在第五章,网络故障诊断和第六章,诊断和纠正防火墙问题,我们使用了相当多的工具来解决网络连接问题由于配置错误的路线和防火墙。 与网络相关的问题非常常见,两个示例问题也是常见的场景。 在本章中,我们将关注与硬件相关的问题,并从诊断文件系统错误开始。
*就像其他章节一样,我们将从发现的错误开始,并排除问题,直到找到原因和解决方案。 在此过程中,我们将发现诊断文件系统问题所需的许多不同命令和日志。
不像前面的章节中终端用户向我们报告问题,这一次我们为自己发现了一个问题。 当我们在数据库服务器上执行一些日常任务时,我们试图创建一个数据库备份,并收到以下错误:
[db]# mysqldump wordpress > /data/backups/wordpress.sql
-bash: /data/backups/wordpress.sql: Read-only file system
这个错误很有趣,因为它不一定来自mysqldump
命令,而是来自写入/data/backups/wordpress.sql
文件的 bash 重定向。
如果我们查看这个错误,它是非常特定的,我们试图将备份写到的文件系统是Read-only
。 Read-only
是什么意思?
在 Linux 上定义和挂载文件系统时,您有许多选项,但有两个选项最能定义文件系统的可访问性。 两个选项是:rw
用于读写,ro用于只读。 当使用读写选项挂载文件系统时,这意味着可以读取文件系统的内容,具有适当权限的用户可以将新的文件/目录写入文件系统。
当文件系统以只读模式挂载时,这意味着虽然用户可以读取文件系统,但新的写请求将被拒绝。
由于我们接收到的错误明确地说明文件系统是只读的,所以我们的下一个逻辑步骤是查看挂载在这个服务器上的文件系统。 为此,我们将使用mount
命令:
[db]# mount
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel)
devtmpfs on /dev type devtmpfs (rw,nosuid,seclabel,size=228500k,nr_inodes=57125,mode=755)
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,seclabel)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=000)
tmpfs on /run type tmpfs (rw,nosuid,nodev,seclabel,mode=755)
tmpfs on /sys/fs/cgroup type tmpfs (rw,nosuid,nodev,noexec,seclabel,mode=755)
selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime)
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=33,pgrp=1,timeout=300,minproto=5,maxproto=5,direct)
mqueue on /dev/mqueue type mqueue (rw,relatime,seclabel)
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime,seclabel)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw,relatime)
nfsd on /proc/fs/nfsd type nfsd (rw,relatime)
/dev/sda1 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
192.168.33.13:/nfs on /data type nfs4 (rw,relatime,vers=4.0,rsize=65536,wsize=65536,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=192.168.33.12,local_lock=none,addr=192.168.33.13)
在处理文件系统时,mount
命令非常有用。 它不仅可以用于显示已挂载的文件系统(如上面的命令所示),还可以用于附加(或挂载)和取消附加(卸载)文件系统。
将文件系统称为挂载的文件系统是一种表示文件系统连接到服务器的常用方法。 对于文件系统,它们通常有两种状态,要么是附加的(挂载的)并且用户可以访问内容,要么是未附加的(卸载的)并且用户无法访问内容。 在本章后面,我们将介绍使用mount
命令挂载和卸载文件系统。
mount
命令并不是查看哪些文件系统已挂载或未挂载的唯一方法。 另一种方法是简单地读取/proc/mounts
文件:
[db]# cat /proc/mounts
rootfs / rootfs rw 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0
devtmpfs /dev devtmpfs rw,seclabel,nosuid,size=228500k,nr_inodes=57125,mode=755 0 0
securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0
tmpfs /dev/shm tmpfs rw,seclabel,nosuid,nodev 0 0
devpts /dev/pts devpts rw,seclabel,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
tmpfs /run tmpfs rw,seclabel,nosuid,nodev,mode=755 0 0
tmpfs /sys/fs/cgroup tmpfs rw,seclabel,nosuid,nodev,noexec,mode=755 0 0
selinuxfs /sys/fs/selinux selinuxfs rw,relatime 0 0
systemd-1 /proc/sys/fs/binfmt_misc autofs rw,relatime,fd=33,pgrp=1,timeout=300,minproto=5,maxproto=5,direct 0 0
mqueue /dev/mqueue mqueue rw,seclabel,relatime 0 0
hugetlbfs /dev/hugepages hugetlbfs rw,seclabel,relatime 0 0
debugfs /sys/kernel/debug debugfs rw,relatime 0 0
sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs rw,relatime 0 0
nfsd /proc/fs/nfsd nfsd rw,relatime 0 0
/dev/sda1 /boot xfs rw,seclabel,relatime,attr2,inode64,noquota 0 0
192.168.33.13:/nfs /data nfs4 rw,relatime,vers=4.0,rsize=65536,wsize=65536,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=192.168.33.12,local_lock=none,addr=192.168.33.13 0 0
事实上,/proc/mounts
文件的内容非常接近mount
命令的输出,主要区别在于每行末尾有两个编号的列。 为了更好地理解这个文件和mount
命令的输出,让我们更好地看看/proc/mounts
中的/boot
文件系统的条目:
/dev/sda1 /boot xfs rw,seclabel,relatime,attr2,inode64,noquota 0 0
/proc/mounts
文件数据在六列——设备、挂载点,文件系统类型、选择【显示】,和两个未使用的列存在向后兼容性。 为了更好地理解这些值,让我们更好地理解这些列的。
第一列device
指定文件系统使用的设备。 在上述示例中,/boot
文件系统所在的设备为/dev/sda1
。
从设备(sda1
)的名称,我们可以识别出一条关键信息。 这个设备是另一个设备的一个分区,我们可以通过设备名称末尾有一个数字来识别它。
设备,从名称上看似乎是一个物理驱动器(假设它是一个硬盘驱动器),并被命名为/dev/sda
; 该驱动器至少有一个分区,该分区的设备名称为/dev/sda1
。 每当一个驱动器上有分区时,这些分区被创建为它们自己的设备,每个设备被分配一个数字; 在本例中是 1,这意味着它是第一个分区。
我们可以通过查看正在使用fdisk
命令的/dev/sda
设备来验证这一点:
[db]# fdisk -l /dev/sda
Disk /dev/sda: 42.9 GB, 42949672960 bytes, 83886080 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x0009c844
Device Boot Start End Blocks Id System
/dev/sda1 * 2048 1026047 512000 83 Linux
/dev/sda2 1026048 83886079 41430016 8e Linux LVM
fdisk
命令可能比较熟悉,因为它是一个用于创建磁盘分区的跨平台命令。 但是,它也可以用于列出分区。
在前面的命令中,我们使用–l
(list)标志列出分区,后面跟着我们想要查看的设备—/dev/sda
。 然而,fdisk
命令向我们显示的远不止这个驱动器上可用的分区。 它还显示了磁盘的大小:
Disk /dev/sda: 42.9 GB, 42949672960 bytes, 83886080 sectors
我们可以在从fdisk
命令打印的第一行中看到这一点,根据这一行,我们的设备/dev/sda
的大小为42.9 GB
。 如果我们往输出的底部看,我们还可以看到在这个磁盘上创建的分区:
Device Boot Start End Blocks Id System
/dev/sda1 * 2048 1026047 512000 83 Linux
/dev/sda2 1026048 83886079 41430016 8e Linux LVM
从上面的列表中可以看出,/dev/sda
有两个分区/dev/sda1
和/dev/sda2
。 使用fdisk
,我们已经能够确定关于这个文件系统物理设备的相当多的细节。 如果我们继续看/proc/mounts
的细节,我们应该能够找出一些其他非常有用的信息,如下:
/dev/sda1 /boot xfs rw,seclabel,relatime,attr2,inode64,noquota 0 0
上一行中的第二列挂载点表示这个文件系统被挂载到的路径。 在本例中,路径为/boot
; /boot
本身不过是/
(根)文件系统上的一个目录。 但是,一旦设备/dev/sda1
上存在的文件系统被装入/boot
,现在它就是自己的文件系统了。
为了更好地理解这个概念,我们将使用mount
和umount
命令来附加和分离/boot
文件系统:
[db]# ls /boot/
config-3.10.0-123.el7.x86_64
grub
grub2
initramfs-0-rescue-dee83c8c69394b688b9c2a55de9e29e4.img
initramfs-3.10.0-123.el7.x86_64.img
initramfs-3.10.0-123.el7.x86_64kdump.img
initrd-plymouth.img
symvers-3.10.0-123.el7.x86_64.gz
System.map-3.10.0-123.el7.x86_64
vmlinuz-0-rescue-dee83c8c69394b688b9c2a55de9e29e4
vmlinuz-3.10.0-123.el7.x86_64
如果我们在/boot
路径上执行一个简单的ls
命令,我们可以在这个目录中看到相当多的文件。 从/proc/mounts
文件和mount
命令中,我们知道有一个文件系统附加到/boot
:
[db]# mount | grep /boot
/dev/sda1 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
为了卸载或卸载这个文件系统,我们可以使用umount
命令:
[db]# umount /boot
[db]# mount | grep /boot
umount
命令有一个非常简单的任务,它卸载挂载的文件系统。
上述命令是卸载文件系统的示例,说明卸载文件系统可能是危险的。 通常,在卸载文件系统之前,您应该首先验证文件系统没有被积极地访问。
既然现在已经卸载了/boot
文件系统,那么当我们执行ls
命令时会发生什么呢?
# ls /boot
路径/boot
仍然有效。 然而,它现在只是一个空目录。 这是由于/dev/sda1
上的文件系统没有安装; 因此,该文件系统上存在的任何文件目前都不能在这个系统上访问。
如果我们使用mount
命令重新挂载文件系统,我们将看到文件重新出现:
[db]# mount /boot
[db]# ls /boot
config-3.10.0-123.el7.x86_64
grub
grub2
initramfs-0-rescue-dee83c8c69394b688b9c2a55de9e29e4.img
initramfs-3.10.0-123.el7.x86_64.img
initramfs-3.10.0-123.el7.x86_64kdump.img
initrd-plymouth.img
symvers-3.10.0-123.el7.x86_64.gz
System.map-3.10.0-123.el7.x86_64
vmlinuz-0-rescue-dee83c8c69394b688b9c2a55de9e29e4
vmlinuz-3.10.0-123.el7.x86_64
正如我们所看到的,当给mount
命令一个 path 参数时,该命令将尝试mount
该文件系统。 但是,当没有指定参数时,mount
命令将只显示当前挂载的文件系统。
在本章的后面,我们将探索使用mount
以及它如何理解应该在哪里以及如何安装文件系统; 现在,让我们看看/proc/mounts
输出中的下一列:
/dev/sda1 /boot xfs rw,seclabel,relatime,attr2,inode64,noquota 0 0
第三列文件系统类型表示所使用的文件系统类型。 在许多操作系统中,尤其是 Linux,通常可以使用不止一种类型的文件系统。 在前面的例子中,我们的引导文件系统被设置为xfs
,这在 Red Hat Enterprise Linux 7 中是新的默认文件系统。
在xfs
之前,旧版本的 Red Hat 默认使用ext3
或ext4
文件系统。 Red Hat 仍然支持ext3/4
文件系统和其他文件系统,因此/proc/mounts
文件中可能列出了许多不同的文件系统类型。
对于/boot
文件系统,知道文件系统类型并不是立即有用的; 然而,知道如何查找底层的文件系统类型可能是我们深入研究这个问题:
/dev/sda1 /boot xfs rw,seclabel,relatime,attr2,inode64,noquota 0 0
第四列选项显示文件系统所使用的选项。
当挂载一个文件系统时,可以为该文件系统提供特定的选项,以便更改文件系统的默认行为。 在前面的例子中,提供了相当多的选项; 让我们分解这个列表,以便更好地理解指定的内容:
- rw:以读写方式挂载文件系统
- seclabel:这个选项是由 SELinux 添加的,以表明该文件系统支持标签的额外属性
- relative:这个告诉文件系统,如果访问时间比文件/目录的修改或更改时间值早,那么只修改访问时间
- attr2:这个支持改进内联扩展属性在磁盘上的存储方式
- inode64:这个允许文件系统创建长度大于 32 位的 inode 编号
- noquota:此禁用该文件系统的磁盘配额和强制执行
正如我们从描述中看到的,这些选项可以极大地改变文件系统的行为方式。 在诊断任何文件系统问题时,它们也非常重要:
/dev/sda1 /boot xfs rw,seclabel,relatime,attr2,inode64,noquota 0 0
输出/proc/mounts
的最后两列表示为0 0
,实际上在/proc/mounts
中没有使用。 这些列实际上只是为/etc/mtab
的向后功能而添加的,这是一个类似的文件,但是不像/proc/mounts
那样被认为是最新的。
这两个文件的不同之处在于它们的用法。 /etc/mtab
文件是为用户或应用设计的,以便在/proc/mounts
文件由内核本身使用的地方读取和利用它。 因此,/proc/mounts
文件被认为是最权威的版本。
如果我们回到手头的问题,我们在将备份写到/data/backups
目录时收到了一个错误。 使用mount
命令,我们可以确定该目录存在于哪个文件系统上:
# mount | grep "data"
192.168.33.13:/nfs on /data type nfs4 (rw,relatime,vers=4.0,rsize=65536,wsize=65536,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=192.168.33.12,local_lock=none,addr=192.168.33.13)
现在我们更好地理解了mount
命令的格式,我们可以从前面的命令行中识别一些关键信息。 我们可以看到,这个文件系统的设备设置为192.168.33.13:/nfs
,mount
点(path
把)设置为(/data
),文件系统的类型是(nfs4
),和文件系统有相当多的选项集。
查看/data
文件系统,我们可以看到文件系统类型被设置为nfs4
。 这种文件系统类型意味着该文件系统是一个网络文件系统(NFS)。
NFS 是一种允许服务器与其他远程服务器共享导出目录的服务。 文件系统类型是一种特殊的文件系统,它允许远程服务器像访问标准文件系统一样访问该服务。
文件系统类型中的4
表示要使用的版本,这意味着远程服务器将使用 NFS 协议的 version 4。
目前,最流行的 NFS 版本是版本 3 和版本 4,其中 4 是 Red Hat Enterprise Linux 6 和 7 的默认版本。 版本 3 和版本 4 之间有很多不同之处; 然而,这些差异并不足以对我们的故障排除方法产生影响。 如果您发现自己在使用 NFS 版本 3 时遇到了问题,那么您很可能会遵循与本章相同的步骤类型。
现在我们已经确定了文件系统是一个 NFS 文件系统,让我们看看它被挂载的选项:
192.168.33.13:/nfs on /data type nfs4 (rw,relatime,vers=4.0,rsize=65536,wsize=65536,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=192.168.33.12,local_lock=none,addr=192.168.33.13)
从我们收到的错误来看,文件系统似乎是Read-Only
,但是如果我们查看选项,列出的第一个选项是rw
。 这意味着 NFS 文件系统本身已经被挂载为Read-Write
; 这应该允许对这个文件系统进行写操作。
要测试问题是出在路径/data/backups
还是挂载的文件系统/data
,我们可以使用touch
命令来测试在这个文件系统中创建一个文件:
# touch /data/file.txt
touch: cannot touch '/data/file.txt': Read-only file system
即使是touch
命令也不能在这个文件系统上创建一个新文件。 这清楚地表明文件系统有问题; 唯一的问题是什么导致了这个问题。
如果我们看一下这个文件系统所使用的选项,没有什么会导致文件系统成为Read-Only
; 这意味着问题很可能不在于如何安装文件系统,而在于其他方面。
由于这个问题似乎与 NFS 文件系统的挂载方式无关,而且该文件系统是基于网络的,因此下一步应该检查到 NFS 服务器的网络连接。
与网络故障排除一样,我们的第一个测试将是 pingNFS 服务器,看看是否得到响应; 但问题是:我们应该 ping 哪个服务器?
答案在文件系统所使用的设备名称中(192.168.33.13:/nfs
)。 挂载 NFS 文件系统时,设备的格式为<nfs server>:<shared directory>
。 对于我们的示例,这意味着我们的/data
文件系统正在从服务器192.168.33.13
挂载/nfs
目录。 为了测试连接性,我们可以简单地ping
IP192.168.33.13
:
[db]# ping 192.168.33.13
PING 192.168.33.13 (192.168.33.13) 56(84) bytes of data.
64 bytes from 192.168.33.13: icmp_seq=1 ttl=64 time=0.495 ms
64 bytes from 192.168.33.13: icmp_seq=2 ttl=64 time=0.372 ms
64 bytes from 192.168.33.13: icmp_seq=3 ttl=64 time=0.364 ms
64 bytes from 192.168.33.13: icmp_seq=4 ttl=64 time=0.337 ms
^C
--- 192.168.33.13 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
rtt min/avg/max/mdev = 0.337/0.392/0.495/0.060 ms
从ping
的结果来看,NFS 服务器已经启动; 但是 NFS 服务呢? 我们可以通过对 NFS 端口使用curl
命令telnet
来验证到 NFS 服务的连接。 但是,首先,我们需要确定应该连接到哪个端口。
在前面的章节中,在对数据库连接进行故障诊断时,我们主要使用知名的端口; 因为 NFS 使用几个端口,这些端口不太常见; 我们需要确定连接到哪个端口:
最简单的方法是在/etc/services
文件中搜索端口:
[db]# grep nfs /etc/services
nfs 2049/tcp nfsd shilp # Network File System
nfs 2049/udp nfsd shilp # Network File System
nfs 2049/sctp nfsd shilp # Network File System
netconfsoaphttp 832/tcp # NETCONF for SOAP over HTTPS
netconfsoaphttp 832/udp # NETCONF for SOAP over HTTPS
netconfsoapbeep 833/tcp # NETCONF for SOAP over BEEP
netconfsoapbeep 833/udp # NETCONF for SOAP over BEEP
nfsd-keepalive 1110/udp # Client status info
picknfs 1598/tcp # picknfs
picknfs 1598/udp # picknfs
shiva_confsrvr 1651/tcp shiva-confsrvr # shiva_confsrvr
shiva_confsrvr 1651/udp shiva-confsrvr # shiva_confsrvr
3d-nfsd 2323/tcp # 3d-nfsd
3d-nfsd 2323/udp # 3d-nfsd
mediacntrlnfsd 2363/tcp # Media Central NFSD
mediacntrlnfsd 2363/udp # Media Central NFSD
winfs 5009/tcp # Microsoft Windows Filesystem
winfs 5009/udp # Microsoft Windows Filesystem
enfs 5233/tcp # Etinnae Network File Service
nfsrdma 20049/tcp # Network File System (NFS) over RDMA
nfsrdma 20049/udp # Network File System (NFS) over RDMA
nfsrdma 20049/sctp # Network File System (NFS) over RDMA
/etc/services
文件是一个静态文件,包含在许多 Linux 发行版中。 它被用作查找将网络端口映射到一个简单的人类可读的名称。 从前面的输出可以看到,名称nfs
被映射到 TCP 端口2049
; 这是 NFS 服务的默认端口。 我们可以利用这个端口来测试连通性,如下所示:
[db]# curl -vk telnet://192.168.33.13:2049
* About to connect() to 192.168.33.13 port 2049 (#0)
* Trying 192.168.33.13...
* Connected to 192.168.33.13 (192.168.33.13) port 2049 (#0)
我们的telnet
似乎成功了; 我们可以使用命令netstat
进一步验证它:
[db]# netstat -na | grep 192.168.33.13
tcp 0 0 192.168.33.12:756 192.168.33.13:2049 ESTABLISHED
似乎连接不是问题,如果我们的问题与连接无关,那么可能是关于 NFS 共享的配置方式。
实际上,我们可以通过一个命令——showmount
来验证 NFS 共享的设置和网络连接。
showmount
命令可以用来显示通过-e
(显示 exports)标志导出的目录。 该命令通过查询指定主机上的 NFS 服务来实现。
对于我们的问题,我们将在192.168.33.13
查询 NFS 服务:
[db]# showmount -e 192.168.33.13
Export list for 192.168.33.13:
/nfs 192.168.33.0/24
showmount
命令的格式有两列。 第一列是共享目录。 第二个是共享目录的网络或主机名。
在前面的示例中,我们可以看到从这个主机共享的目录是/nfs
目录。 这也与设备名称192.168.33.13:/nfs
中列出的目录相匹配。
目录与/nfs
共享的网络是192.166.33.0/24
网络,正如我们在网络连接一章中了解到的,它是192.168.33.0
到192.168.33.255
的简称。 从以前的故障排除中,我们已经知道我们所在的数据库服务器在该网络中。
我们还可以看到,自从之前执行netstat
命令以来,这一点没有改变:
[db]# netstat -na | grep 192.168.33.13
tcp 0 0 192.168.33.12:756 192.168.33.13:2049 ESTABLISHED
netstat
命令的第四列显示ESTABLISHED
TCP 连接使用的本端 IP 地址。 通过前面的输出,我们可以看到192.168.33.12
地址是数据库服务器的 IP(如前面章节所示)。
到目前为止,关于这个 NFS 共享的所有内容看起来都是正确的,从这里开始,我们需要登录到 NFS 服务器来继续进行故障排除。
登录到 NFS 服务器后,首先要检查的是 NFS 服务是否在运行:
[db]# systemctl status nfs
nfs-server.service - NFS server and services
Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled)
Active: active (exited) since Sat 2015-04-25 14:01:13 MST; 17h ago
Process: 2226 ExecStart=/usr/sbin/rpc.nfsd $RPCNFSDARGS (code=exited, status=0/SUCCESS)
Process: 2225 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS)
Main PID: 2226 (code=exited, status=0/SUCCESS)
CGroup: /system.slice/nfs-server.service
使用systemctl
,我们可以简单地查看服务状态; 从前面的输出来看是正常的。 这是意料之中的事,因为我们既可以通过telnet
访问 NFS 服务,又可以使用showmount
命令查询它。
由于 NFS 服务正在运行且健康,因此下一步是检查定义导出哪些目录以及如何导出目录的配置; /etc/exports
文件:
[nfs]# ls -la /etc/exports
-rw-r--r--. 1 root root 40 Apr 26 08:28 /etc/exports
[nfs]# cat /etc/exports
/nfs 192.168.33.0/24(rw,no_root_squash)
该文件的格式实际上类似于showmount
命令的输出。
第一列是要共享的目录,第二列是要共享它的网络。 但是,在这个文件中,在网络定义之后还有一些附加信息。
网络/子网列后面是一组括号,其中包含各种NFS
选项。 这些选项的工作原理与我们在/proc/mounts
文件中看到的挂载选项非常相似。
这些选项可能是我们的Read-Only
文件系统的根本原因吗? 很有可能。 让我们分解这两种选择,以便更好地理解:
rw
:允许对共享目录进行读写操作no_root_squash
:禁用root_squash
;root_squash
是一个将根用户映射为匿名用户的系统
不幸的是,这些选项中的都不会强制文件系统处于Read-Only
模式。 事实上,根据这些选项的描述,他们似乎建议这个 NFS 共享应该处于Read-Write
模式。
在对/etc/exports
文件执行ls
时出现了一个有趣的事实:
[nfs]# ls -la /etc/exports
-rw-r--r--. 1 root root 40 Apr 26 08:28 /etc/exports
/etc/exports
文件最近被修改。 可能我们共享的文件系统实际上是作为Read-Only
共享的,但是最近有人更改了/etc/exports
文件,将文件系统导出为Read-Write
。
这种情况是完全可能的,而且实际上是 NFS 的一个常见问题。 NFS 服务不会不断读取/etc/exports
文件以寻找更改。 事实上,这个文件只在服务启动时被读取。
对/etc/exports
文件的任何修改都将在重新加载服务或使用exportfs
命令刷新导出的文件系统后才生效。
一个非常常见的场景是,有人对该文件进行了更改,但却忘记运行命令来刷新导出的文件系统。 我们可以通过使用exportfs
命令来确定是否为这种情况:
[nfs]# exportfs -s
/nfs 192.168.33.0/24(rw,wdelay,no_root_squash,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
当给出–s
(显示当前导出)标志时,exportfs
命令将简单地列出现有的共享目录,包括共享这些目录的选项。
查看前面的输出,我们可以看到这个文件系统与许多选项共享,这些选项在/etc/exports
中没有列出。 这是因为通过 NFS 共享的所有目录都有一个默认选项列表,这些选项管理如何共享目录。 在/etc/exports
中指定的选项实际上用于覆盖默认设置。
为了更好地理解这些选项,让我们将它们进行分解:
rw
:允许对共享目录进行读写操作。wdelay
:这将导致 NFS 在怀疑有另一个客户端写入请求时保持一个写请求。 这是为了减少连接多个客户端时的写冲突。no_root_squash
:禁用root_squash
,这是一个将根用户映射到匿名用户的系统。no_subtree_check
:禁用subtree
检查; 子树检查本质上确保对导出子目录的目录的请求将遵循子目录更严格的策略。sec=sys
:这告诉 NFS 使用用户 ID 和组 ID 值进行文件访问的权限和授权。secure
:这确保 NFS 只处理客户端端口小于 1024 的请求,本质上要求它来自特权 NFS 挂载。no_all_squash
:禁用all_squash
,该功能用于强制将所有权限映射到匿名用户和组。
似乎这些选项也不能解释Read-Only
文件系统。 这个问题似乎很难解决,尤其是在 NFS 服务配置正确的情况下。
因为 NFS 服务器的配置看起来是正确的,而且客户机(数据库服务器)也看起来是正确的,所以我们需要缩小问题是在客户机端还是在服务器端。
一种方法是将文件系统挂载到另一个客户机上,并尝试相同的写请求。 从配置来看,似乎我们只需要在192.168.33.0/24
网络中另一台服务器来执行此测试。 也许我们前面章节提到的博客服务器是一个很好的客户端?
在某些环境中,这个问题的答案可能是no
,因为 web 服务器通常被认为不如数据库服务器安全。 然而,因为这只是本书的一个测试环境,所以它是可以的。
一旦我们登录到博客服务器,我们就可以使用showmount
命令来测试是否可以看到挂载:
[blog]# showmount -e 192.168.33.13
Export list for 192.168.33.13:
/nfs 192.168.33.0/24
这回答了两个问题。 第一个是是否安装了 NFS 客户端软件; 因为存在showmount
命令,所以答案可能是yes
。
第二个问题是是否可以从博客服务器访问 NFS 服务,答案也是 yes。
要测试挂载,我们只需使用mount
命令:
[blog]# mount -t nfs 192.168.33.13:/nfs /mnt
使用mount
命令挂载文件系统,语法为:mount –t <filesystem type> <device> <mount point>
。 在上面的示例中,我们简单地将192.168.33.13:/nfs
设备挂载到/mnt
目录,文件系统类型为nfs
。
在运行命令时,我们没有收到任何错误,但是为了确保文件系统被正确挂载,我们可以像之前那样使用mount
命令:
[blog]# mount | grep /mnt
192.168.33.13:/nfs on /mnt type nfs4 (rw,relatime,vers=4.0,rsize=65536,wsize=65536,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=192.168.33.11,local_lock=none,addr=192.168.33.13)
从mount
命令的输出来看,mount
请求已经成功,并且处于Read-Write
模式,这意味着mount
选项与数据库服务器上使用的选项类似。
现在我们可以通过尝试使用touch
命令创建一个文件来测试文件系统:
# touch /mnt/testfile.txt
touch: cannot touch '/mnt/testfile.txt': Read-only file system
看起来问题不在于客户机的配置,因为即使是我们的新客户机也有写这个文件系统的问题。
作为提示,在前面的示例中,我将/nfs
共享挂载到/mnt
。 /mnt
目录被用作通用的挂载点,通常认为可以使用。 然而,最好的做法是确保不事先安装其他内容到/mnt
。
目前,即使我们使用mount
命令挂载 NFS 共享,这个挂载的文件系统也不被认为是持久的。 下次系统重新引导时,将不会重新挂载 NFS 挂载。
这是因为在系统引导时,引导过程的一部分是读取/etc/fstab
文件和mount
文件中定义的任何文件系统。
为了更好地理解它是如何工作的,让我们看看数据库服务器上的/etc/fstab
文件:
[db]# cat /etc/fstab
#
# /etc/fstab
# Created by anaconda on Mon Jul 21 23:35:56 2014
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/os-root / xfs defaults 1 1
UUID=be76ec1d-686d-44a0-9411-b36931ee239b /boot xfs defaults 1 2
/dev/mapper/os-swap swap swap defaults 0 0
192.168.33.13:/nfs /data nfs defaults 0 0
/etc/fstab
文件的内容实际上与/proc/mounts
文件的内容非常相似。 第一列的/etc/fstab
文件用于指定设备安装,第二列是path
或mount
指山,第三列是文件系统类型,第四列是mount
的选项文件系统。
然而,在/etc/fstab
文件中,最后两列是这些文件的不同之处。 最后两列实际上是有意义的。 在fstab
文件中,dump
命令使用第五列。
dump
命令是一个简单的备份实用程序,它读取/etc/fstab
以确定要备份哪些文件系统。 当执行转储实用程序时,任何设置了0
值的文件系统都不在备份范围内。
虽然目前这个实用程序的使用并不多,但是维护/etc/fstab
文件中的这个专栏是为了提供向后功能。
/etc/fstab
文件中的第六列也是最后一列与当今的系统非常相关。 这个列用来表示引导过程(通常是在失败之后)中执行文件系统检查或fsck
的顺序。
文件系统检查(简称fsck
)是一个定期运行的进程,它检查文件系统中是否存在错误并试图纠正它们。 这是一个过程,我们将在本章进一步介绍。
因为我们不想让 NFS 共享文件系统挂载在博客服务器的/mnt
路径上,所以我们需要卸载该文件系统。
我们可以使用与前面处理/boot
文件系统相同的方法来完成此操作; 使用umount
命令:
[blog]# umount /mnt
[blog]# mount | grep /mnt
在博客服务器上,我们简单地使用umount
,然后使用/mnt
的mount
点到unmount
客户机的 NFSmount
点。 现在,我们可以回到 NFS 服务器继续进行故障排除。
由于我们确定了,即使是新客户端也不能写入/nfs
共享,因此我们现在已经将问题范围缩小到服务器端,而不是客户端。
前面,在对 NFS 服务器进行故障诊断时,我们几乎检查了关于 NFS 的所有检查。 我们验证了服务实际上正在运行,客户机可以访问该服务,并且验证了/etc/exports
中的数据是正确的,并且当前导出的目录与/etc/exports
中的目录匹配。 此时,只剩下一个地方需要检查:log
文件。
默认情况下,NFS 服务不像 Apache 或 MariaDB 那样拥有自己的日志文件。 相反,RHEL 系统上的这项服务使用了syslog
设施; 这意味着我们的日志将在/var/log/messages
内。
messages
日志是 Red Hat Enterprise Linux 发行版中非常常用的日志文件。 事实上,默认情况下,在 cron 作业和身份验证之外,信息日志级别以上的所有 syslog 消息都被发送到基于 RHEL 的系统上的/var/log/messages
。
由于 NFS 服务将其日志消息发送到本地syslog
服务,因此其消息也包含在messages
日志中。
如果我们不知道 NFS 日志被发送到/var/log/messages
日志文件会怎样? 有一个相当简单的技巧可以识别哪个日志文件包含 NFS 日志消息。
通常,在 Linux 系统上,所有系统服务的日志文件都位于/var/log
中。 由于我们知道大多数日志在系统上的默认位置,我们可以简单地快速查看这些文件,以确定哪些文件可能具有 NFS 日志消息:
[nfs]# cd /var/log
[nfs]# grep -rc nfs ./*
./anaconda/anaconda.log:14
./anaconda/syslog:44
./anaconda/anaconda.xlog:0
./anaconda/anaconda.program.log:7
./anaconda/anaconda.packaging.log:16
./anaconda/anaconda.storage.log:56
./anaconda/anaconda.ifcfg.log:0
./anaconda/ks-script-Sr69bV.log:0
./anaconda/ks-script-lfU6U2.log:0
./audit/audit.log:60
./boot.log:4
./btmp:0
./cron:470
./cron-20150420:662
./dmesg:26
./dmesg.old:26
./grubby:0
./lastlog:0
./maillog:112386
./maillog-20150420:17
./messages:3253
./messages-20150420:11804
./sa/sa15:1
./sa/sar15:1
./sa/sa16:1
./sa/sar16:1
./sa/sa17:1
./sa/sa19:1
./sa/sar19:1
./sa/sa20:1
./sa/sa25:1
./sa/sa26:1
./secure:14
./secure-20150420:63
./spooler:0
./tallylog:0
./tuned/tuned.log:0
./wtmp:0
./yum.log:0
grep
命令递归地(-r
)在每个文件中搜索字符串“nfs
”,并输出文件名以及找到该字符串的行数的计数(-c
)。
在前面的输出中,有两个日志文件包含最多的字符串“nfs
”实例。 第一个是maillog
,它是电子邮件消息的系统日志; 这可能与 NFS 服务无关。
第二个是messages
日志文件,如我们所知,它是系统默认的日志文件。
即使事先不了解特定系统的日志记录方法,如果您像前面的示例一样熟悉 Linux 的一般情况和技巧,通常也可以找到哪些日志包含所需的数据。
现在我们知道了要查找的日志文件,让我们看一下/var/log/messages
日志。
由于这个log
文件可能非常大,我们将使用带有-100
标志的tail
命令,这将导致尾部只显示指定文件的最后100
行。 通过限制输出为100
行,我们应该只看到最相关的数据:
[nfs]# tail -100 /var/log/messages
Apr 26 10:25:44 nfs kernel: md/raid1:md127: Disk failure on sdb1, disabling device.
md/raid1:md127: Operation continuing on 1 devices.
Apr 26 10:25:55 nfs kernel: md: unbind<sdb1>
Apr 26 10:25:55 nfs kernel: md: export_rdev(sdb1)
Apr 26 10:27:20 nfs kernel: md: bind<sdb1>
Apr 26 10:27:20 nfs kernel: md: recovery of RAID array md127
Apr 26 10:27:20 nfs kernel: md: minimum _guaranteed_ speed: 1000 KB/sec/disk.
Apr 26 10:27:20 nfs kernel: md: using maximum available idle IO bandwidth (but not more than 200000 KB/sec) for recovery.
Apr 26 10:27:20 nfs kernel: md: using 128k window, over a total of 511936k.
Apr 26 10:27:20 nfs kernel: md: md127: recovery done.
Apr 26 10:27:41 nfs nfsdcltrack[4373]: sqlite_remove_client: unexpected return code from delete: 8
Apr 26 10:27:59 nfs nfsdcltrack[4375]: sqlite_remove_client: unexpected return code from delete: 8
Apr 26 10:55:06 nfs dhclient[3528]: can't create /var/lib/NetworkManager/dhclient-05be239d-0ec7-4f2e-a68d-b64eec03fcb2-enp0s3.lease: Read-only file system
Apr 26 11:03:43 nfs chronyd[744]: Could not open temporary driftfile /var/lib/chrony/drift.tmp for writing
Apr 26 11:55:03 nfs rpc.mountd[4552]: could not open /var/lib/nfs/.xtab.lock for locking: errno 30 (Read-only file system)
Apr 26 11:55:03 nfs rpc.mountd[4552]: can't lock /var/lib/nfs/xtab for writing
因为即使是100
行也可能相当繁琐,所以我将输出截断为只处理相关的行。 这显示了相当多的带有字符串“nfs
”的消息; 然而,并非所有这些都是来自 NFS 服务的消息。 因为我们的 NFS 服务器的主机名被设置为nfs
,所以这个系统的每个日志条目都有字符串“nfs
”。
然而,即使这样,我们仍然可以看到一些与NFS
服务相关的消息,特别是以下几行:
Apr 26 10:27:41 nfs nfsdcltrack[4373]: sqlite_remove_client: unexpected return code from delete: 8
Apr 26 10:27:59 nfs nfsdcltrack[4375]: sqlite_remove_client: unexpected return code from delete: 8
Apr 26 11:55:03 nfs rpc.mountd[4552]: could not open /var/lib/nfs/.xtab.lock for locking: errno 30 (Read-only file system)
Apr 26 11:55:03 nfs rpc.mountd[4552]: can't lock /var/lib/nfs/xtab for writing
关于这些日志条目的有趣的事情是其中一个特别声明了服务rpc.mountd
不能打开一个文件,因为文件系统是Read-only
。 但是,它试图打开的文件/var/lib/nfs/.xtab.lock
不是我们的 NFS 共享的一部分。
由于这个文件系统不是我们的 NFS 的一部分,让我们快速查看一下这个服务器上挂载的文件系统。 我们可以再次这样做,使用mount
命令:
[nfs]# mount
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel)
devtmpfs on /dev type devtmpfs (rw,nosuid,seclabel,size=241112k,nr_inodes=60278,mode=755)
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime)
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=33,pgrp=1,timeout=300,minproto=5,maxproto=5,direct)
mqueue on /dev/mqueue type mqueue (rw,relatime,seclabel)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime,seclabel)
sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw,relatime)
nfsd on /proc/fs/nfsd type nfsd (rw,relatime)
/dev/mapper/md0-root on / type xfs (ro,relatime,seclabel,attr2,inode64,noquota)
/dev/md127 on /boot type xfs (ro,relatime,seclabel,attr2,inode64,noquota)
/dev/mapper/md0-nfs on /nfs type xfs (ro,relatime,seclabel,attr2,inode64,noquota)
和其他服务器一样,这里有很多已安装的文件系统,但是我们对它们并不感兴趣; 只有一小部分。
/dev/mapper/md0-root on / type xfs (ro,relatime,seclabel,attr2,inode64,noquota)
/dev/md127 on /boot type xfs (ro,relatime,seclabel,attr2,inode64,noquota)
/dev/mapper/md0-nfs on /nfs type xfs (ro,relatime,seclabel,attr2,inode64,noquota)
前面三行是我们应该感兴趣的。 这三个挂载的文件系统是为我们的系统定义的持久文件系统。 如果我们看一下这三个持久文件系统,我们可以发现一些有趣的信息。
设备/dev/mapper/md0-root
上存在/
或根文件系统。 这个文件系统实际上对我们的系统非常重要,因为似乎这个服务器被配置为将整个操作系统安装在根文件系统(/
)下,这是一种比较常见的设置。 这个文件系统包括所讨论的文件/var/lib/nfs/.xtab.lock
文件。
/boot
文件系统存在于/dev/md127
设备上,从名称上判断,该设备很可能是使用 Linux 的软件 raid 系统的突袭设备。 /boot
文件系统与根文件系统一样重要,因为/boot
包含服务器启动所需的所有文件。 如果没有/boot
文件系统,这个系统很可能不会重新启动,而只是在下一次系统重新启动时出现内核恐慌。
最后一个文件系统/nfs
使用/dev/mapper/md0-nfs
设备。 根据前面的故障诊断,我们将这个文件系统标识为通过 NFS 服务导出的文件系统。
如果我们回顾一下错误和mount
的输出,我们将开始发现这个系统中一些有趣的错误:
Apr 26 11:55:03 nfs rpc.mountd[4552]: could not open /var/lib/nfs/.xtab.lock for locking: errno 30 (Read-only file system)
该错误报告文件系统在。 xtab.lock
文件位于Read-Only
:
/dev/mapper/md0-root on / type xfs (ro,relatime,seclabel,attr2,inode64,noquota)
通过mount
命令,我们可以看到所讨论的文件系统就是/
文件系统。 在查看了/
或根文件系统的选项之后,我们可以看到这个文件系统实际上是用ro
选项安装的。
事实上,如果我们看一下这三个文件系统的选项,我们可以看到/
、/boot
和/nfs
都用ro
选项挂载。 其中rw
将文件系统挂载为Read-Write
,ro
选项将文件系统挂载为Read-Only
。 这意味着目前,这些文件系统不能被任何用户写入。
对于以Read-Only
模式挂载的所有三个已定义的文件系统来说,这是一种非常不寻常的配置。 要查看这是否是所需的配置,我们可以检查/etc/fstab
文件,它与前面用于标识持久文件系统的文件相同:
[nfs]# cat /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Apr 15 09:39:23 2015
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/md0-root / xfs defaults 0 0
UUID=7873e886-78d5-46cc-b4d9-0c385995d915 /boot xfs defaults 0 0
/dev/mapper/md0-nfs /nfs xfs defaults 0 0
/dev/mapper/md0-swap swap swap defaults 0 0
从/etc/fstab
文件的内容来看,这些文件系统似乎没有被配置为以Read-Only
模式挂载。 相反,这些文件系统是用“默认”选项挂载的。
在 Linux 上,xfs
文件系统的“默认”选项以Read-Write
模式而不是Read-Only
模式挂载文件系统。 如果我们查看数据库服务器上的/etc/fstab
文件,就可以验证这种行为:
[db]# cat /etc/fstab
#
# /etc/fstab
# Created by anaconda on Mon Jul 21 23:35:56 2014
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/os-root / xfs defaults 1 1
UUID=be76ec1d-686d-44a0-9411-b36931ee239b /boot xfs defaults 1 2
/dev/mapper/os-swap swap swap defaults 0 0
192.168.33.13:/nfs /data nfs defaults 0 0
在数据库服务器上,我们可以看到/
或根文件系统也将文件系统选项设置为“defaults”。 然而,当我们使用mount
命令查看文件系统选项时,我们可以看到rw
选项以及其他一些默认选项正在被应用:
[db]# mount | grep root
/dev/mapper/os-root on / type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
这确认了三个持久文件系统的Read-Only
状态不是所需的配置。
如果指定/etc/fstab
文件系统为,以Read-Write
方式挂载文件系统,且mount
命令显示以Read-Only
方式挂载文件系统。 这清楚地表明,有问题的文件系统可能在它们最初作为引导过程的一部分被装载之后被重新装载。
如前所述,当 Linux 系统引导时,它读取/etc/fstab
文件并挂载所有定义的文件系统。 但是,安装文件系统的过程到此为止。 没有进程持续监视/etc/fstab
文件的更改,并挂载或卸载修改的文件系统,至少在默认情况下不是这样。
事实上,经常会看到新创建的文件系统没有挂载,而是在/etc/fstab
文件中指定,因为有人在编辑/etc/fstab
文件后忘记使用mount
命令对其进行mount
操作。
然而,看到文件系统被挂载为Read-Only
,但是fstab
随后被更改的情况并不常见。
事实上,在我们的场景中,这并不容易实现,因为/
文件系统是Read-Only
,所以/etc/fstab
是不可访问的:
[nfs]# touch /etc/fstab
touch: cannot touch '/etc/fstab': Read-only file system
这意味着我们的文件系统是Read-Only
,是在这些文件系统最初安装之后执行的。
这种状态的罪魁祸首实际上在我们之前查看的日志消息中:
Apr 26 10:25:44 nfs kernel: md/raid1:md127: Disk failure on sdb1, disabling device.
md/raid1:md127: Operation continuing on 1 devices.
Apr 26 10:25:55 nfs kernel: md: unbind<sdb1>
Apr 26 10:25:55 nfs kernel: md: export_rdev(sdb1)
Apr 26 10:27:20 nfs kernel: md: bind<sdb1>
Apr 26 10:27:20 nfs kernel: md: recovery of RAID array md127
Apr 26 10:27:20 nfs kernel: md: minimum _guaranteed_ speed: 1000 KB/sec/disk.
Apr 26 10:27:20 nfs kernel: md: using maximum available idle IO bandwidth (but not more than 200000 KB/sec) for recovery.
Apr 26 10:27:20 nfs kernel: md: using 128k window, over a total of 511936k.
Apr 26 10:27:20 nfs kernel: md: md127: recovery done.
从/var/log/messages
日志文件中,我们可以看到,在某个时刻,软件 raid(md
)出现了一个问题,该问题将磁盘/dev/sdb1
标记为失败。
默认情况下,在 Linux 中,如果一个物理磁盘驱动器失败或内核无法使用,Linux 内核将以Read-Only
模式重新挂载该物理磁盘上的文件系统。 与前面的错误消息一样,似乎是sdb1
物理磁盘和md127
raid 设备的故障是导致文件系统为Read-Only
的根本原因。
由于软件 raid 和硬件问题是下一章的主题,我们将在第 8 章、硬件故障中推迟 raid 和磁盘问题的故障排除。
既然我们知道了为什么文件系统处于Read-Only
模式,我们就可以解决这个问题了。 强迫文件系统从Read-Only
转到Read-Write
实际上非常简单。 但是,因为我们不知道导致文件系统进入Read-Only
模式的失败的所有情况,所以我们必须小心。
从文件系统错误中恢复可能非常棘手; 如果处理不当,我们很容易发现自己处于这样一种情况:我们损坏了文件系统,或者以其他方式导致部分甚至全部数据丢失。
因为我们有多个文件系统处于Read-Only
模式,所以我们首先从/boot
文件系统开始。 我们从/boot
文件系统开始的原因是,从技术上讲,这是最容易发生数据丢失的文件系统。 由于/boot
文件系统只在服务器引导过程中使用,所以我们可以简单地确保在/boot
文件系统可以恢复之前不重新引导该服务器。
无论何时,在采取任何行动之前,最好先备份数据。 在接下来的步骤中,我们将假定/boot
文件系统定期进行备份。
为了恢复这个文件系统,我们将执行三个步骤。 在第一步中,我们将卸载/boot
文件系统。 通过在采取任何额外步骤之前卸载文件系统,我们将确保文件系统没有被积极地写入。 这一步骤将大大减少恢复过程中文件系统损坏的机会。
然而,在卸载文件系统之前,我们需要确保没有应用或服务试图写入我们试图恢复的文件系统。
为了确保这一点,我们可以使用lsof
命令。 lsof
命令用于列出打开的文件; 我们可以通过这个列表来确定/boot
文件系统中是否有任何文件是打开的。
如果我们只是运行不带选项的lsof
,它将打印所有当前打开的文件:
[nfs]# lsof
COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root cwd DIR 253,1 4096 128 /
通过向lsof
添加–r
(repeat)标志,我们告诉它以重复模式运行。 然后我们可以将这个输出通过管道传递到grep
命令,在那里我们可以过滤出在/boot
文件系统上打开的文件:
[nfs]# lsof -r | grep /boot
如果前面的命令在一段时间内没有产生任何输出,那么继续卸载文件系统是安全的。 如果该命令打印任何打开的文件,最好找到适当的进程读写文件系统,并在卸载文件系统之前停止它们。
由于我们的示例在/boot
文件系统上没有打开的文件,我们可以继续卸载/boot
文件系统。 为此,我们将使用umount
命令:
[nfs]# umount /boot
幸运的是,umount
命令没有出错。 如果文件正在积极写入,那么卸载时可能会收到错误。 通常,此错误包含一条消息,声明设备正忙。 为了验证文件系统是否被成功卸载,我们可以再次使用mount
命令:
[nfs]# mount | grep /boot
现在已经卸载了/boot
文件系统,我们可以在恢复过程中执行第二步。 我们现在可以检查和修复文件系统。
Linux 有一个非常有用的文件系统检查命令,可以用来检查和修复文件系统。 这个命令称为fsck
。
然而,fsck
命令实际上并不是一个命令。 每种文件系统类型都有自己的检查一致性和修复问题的方法。 fsck
命令只是一个包装器,它为所讨论的文件系统调用适当的命令。
例如,当fsck
命令在ext4
文件系统上运行时,正在执行的命令实际上是e2fsck
。 e2fsck
命令用于ext2
到ext4
的文件系统类型。
我们可以通过两种方式调用e2fsck
,要么直接调用fsck
,要么间接调用fsck
。 在本例中,我们将使用fsck
方法,因为它可以用于 Linux 支持的几乎所有文件系统。
要使用fsck
命令简单地检查文件系统的一致性,我们可以在不带标志的情况下运行它,并指定要检查的磁盘设备:
[nfs]# fsck /dev/sda1
fsck from util-linux 2.20.1
e2fsck 1.42.9 (4-Feb-2014)
cloudimg-rootfs: clean, 85858/2621440 files, 1976768/10485504 blocks
在前面的示例中,我们可以看到文件系统没有识别任何错误。 如果有,就会有人问我们是否需要e2fsck
实用程序来纠正这些错误。
如果需要,我们可以通过将–y
(yes)标志传递给fsck
来自动修复发现的问题:
[nfs]# fsck -y /dev/sda1
fsck from util-linux 2.20.1
e2fsck 1.42 (29-Nov-2011)
/dev/sda1 contains a file system with errors, check forced.
Pass 1: Checking inodes, blocks, and sizes
Inode 2051351 is a unknown file type with mode 0137642 but it looks
like it is really a directory.
Fix? yes
Pass 2: Checking directory structure
Entry 'test' in / (2) has deleted/unused inode 49159\. Clear? yes
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/sda1: ***** FILE SYSTEM WAS MODIFIED *****
/dev/sda1: 96/2240224 files (7.3% non-contiguous), 3793508/4476416 blocks
此时,e2fsck
命令将尝试来纠正它发现的任何错误。 幸运的是,在我们的例子中,错误能够被纠正; 然而,在某些情况下,情况并非如此。
当fsck
命令为时,在文件系统上运行xfs
; 结果却截然不同:
[nfs]# fsck /dev/md127
fsck from util-linux 2.23.2
If you wish to check the consistency of an XFS filesystem or
repair a damaged filesystem, see xfs_repair(8).
xfs
文件系统不同于ext2/3/4
系列文件系统,因为每次挂载文件系统时都会执行一致性检查。 这并不意味着您不能手动检查和修复文件系统。 要检查一个xfs
文件系统,我们可以使用xfs_repair
实用程序:
[nfs]# xfs_repair -n /dev/md127
Phase 1 - find and verify superblock...
Phase 2 - using internal log
- scan filesystem freespace and inode maps...
- found root inode chunk
Phase 3 - for each AG...
- scan (but don't clear) agi unlinked lists...
- process known inodes and perform inode discovery...
- agno = 0
- agno = 1
- agno = 2
- agno = 3
- process newly discovered inodes...
Phase 4 - check for duplicate blocks...
- setting up duplicate extent list...
- check for inodes claiming duplicate blocks...
- agno = 0
- agno = 1
- agno = 2
- agno = 3
No modify flag set, skipping phase 5
Phase 6 - check inode connectivity...
- traversing filesystem ...
- traversal finished ...
- moving disconnected inodes to lost+found ...
Phase 7 - verify link counts...
No modify flag set, skipping filesystem flush and exiting.
当使用–n
(不修改)标志执行,后面跟着要检查的设备时,xfs_repair
实用程序只会验证文件系统的一致性。 在此模式下运行时,它不会尝试修复文件系统。
要在修复文件系统的模式下运行xfs_repair
,只需省略–n
标志,如下所示:
[nfs]# xfs_repair /dev/md127
Phase 1 - find and verify superblock...
Phase 2 - using internal log
- zero log...
- scan filesystem freespace and inode maps...
- found root inode chunk
Phase 3 - for each AG...
- scan and clear agi unlinked lists...
- process known inodes and perform inode discovery...
- agno = 0
- agno = 1
- agno = 2
- agno = 3
- process newly discovered inodes...
Phase 4 - check for duplicate blocks...
- setting up duplicate extent list...
- check for inodes claiming duplicate blocks...
- agno = 0
- agno = 1
- agno = 2
- agno = 3
Phase 5 - rebuild AG headers and trees...
- reset superblock...
Phase 6 - check inode connectivity...
- resetting contents of realtime bitmap and summary inodes
- traversing filesystem ...
- traversal finished ...
- moving disconnected inodes to lost+found ...
Phase 7 - verify and correct link counts...
Done
从前面的xfs_repair
命令的输出来看,我们的/boot
文件系统似乎不需要任何修复进程。
您可能认为用fsck
和xfs_repair
这样的工具来修复这个文件系统是相当容易的。 原因很简单,就是因为文件系统的设计,比如xfs
和ext2/3/4
。 xfs
和ext2/3/4
系列都是日志文件系统; 这意味着这些类型的文件系统将保存对文件系统对象(如文件、目录等)所做更改的日志。
这些更改将保存在此日志中,直到将更改提交到主文件系统。 xfs_repair
实用程序只是查看这个日志,并回放未提交到主文件系统的最后更改。 这些文件系统日志允许文件系统在意外断电或系统重新启动等情况下非常有弹性。
不幸的是,有时候文件系统的日志和工具(如xfs_repair
)不足以纠正这种情况。
在这种情况下,还有更多的选择,比如以强制模式运行修复。 然而,这些选项应该一直保留到最后一搏,因为它们本身有时会导致文件系统损坏。
如果您发现自己的文件系统已损坏且无法修复,那么最好的办法可能就是重新创建文件系统并恢复备份,如果您有备份的话……
现在已经检查并修复了/boot
文件系统,我们可以简单地重新安装它,以验证数据是否正确。 为此,我们可以简单地运行mount
命令,然后运行/boot
:
[nfs]# mount /boot
[nfs]# mount | grep /boot
/dev/md127 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
当在/etc/fstab
文件中定义文件系统时,只需使用mount
点就可以调用mount
和umount
命令。 这将使这两个命令根据文件/etc/fstab
中的定义进入文件系统mount
或unmount
。
从mount
的输出来看,我们的/boot
文件系统现在是Read-Write
而不是Read-Only
。 如果我们执行一个ls
命令,我们仍然可以看到我们的原始数据:
[nfs]# ls /boot
config-3.10.0-229.1.2.el7.x86_64 initrd-plymouth.img
config-3.10.0-229.el7.x86_64 symvers-3.10.0-229.1.2.el7.x86_64.gz
grub symvers-3.10.0-229.el7.x86_64.gz
grub2 System.map-3.10.0-229.1.2.el7.x86_64
initramfs-0-rescue-3f370097c831473a8cfec737ff1d6c55.img System.map-3.10.0-229.el7.x86_64
initramfs-3.10.0-229.1.2.el7.x86_64.img vmlinuz-0-rescue-3f370097c831473a8cfec737ff1d6c55
initramfs-3.10.0-229.1.2.el7.x86_64kdump.img vmlinuz-3.10.0-229.1.2.el7.x86_64
initramfs-3.10.0-229.el7.x86_64.img vmlinuz-3.10.0-229.el7.x86_64
initramfs-3.10.0-229.el7.x86_64kdump.img
看来我们的恢复措施是成功的! 现在我们已经用/boot
文件系统对它们进行了测试,现在我们可以开始修复/nfs
文件系统。
修复/nfs
文件系统的步骤实际上与/boot
文件系统相同,只有一个主要的区别,如下:
[nfs]# lsof -r | grep /nfs
rpc.statd 1075 rpcuser cwd DIR 253,1 40 592302 /var/lib/nfs/statd
rpc.mount 2282 root cwd DIR 253,1 4096 9125499 /var/lib/nfs
rpc.mount 2282 root 4u REG 0,3 0 4026532125 /proc/2280/net/rpc/nfd.export/channel
rpc.mount 2282 root 5u REG 0,3 0 4026532129 /proc/2280/net/rpc/nfd.fh/channel
当使用lsof
检查/nfs
文件系统上打开的文件时,我们可能看不到 NFS 服务进程。 但是,在lsof
命令停止后,NFS 服务很可能会尝试访问这个共享文件系统中的文件。 为了防止这种情况,在对共享文件系统执行任何更改时,最好(尽可能)停止 NFS 服务:
[nfs]# systemctl stop nfs
一旦 NFS 服务停止,其余的步骤是相同的:
[nfs]# umount /nfs
[nfs]# xfs_repair /dev/md0/nfs
Phase 1 - find and verify superblock...
Phase 2 - using internal log
- zero log...
- scan filesystem freespace and inode maps...
- found root inode chunk
Phase 3 - for each AG...
- scan and clear agi unlinked lists...
- process known inodes and perform inode discovery...
- agno = 0
- agno = 1
- agno = 2
- agno = 3
- process newly discovered inodes...
Phase 4 - check for duplicate blocks...
- setting up duplicate extent list...
- check for inodes claiming duplicate blocks...
- agno = 0
- agno = 1
- agno = 2
- agno = 3
Phase 5 - rebuild AG headers and trees...
- reset superblock...
Phase 6 - check inode connectivity...
- resetting contents of realtime bitmap and summary inodes
- traversing filesystem ...
- traversal finished ...
- moving disconnected inodes to lost+found ...
Phase 7 - verify and correct link counts...
done
一旦文件系统被修复,我们可以简单地重新挂载它,如下所示:
[nfs]# mount /nfs
[nfs]# mount | grep /nfs
nfsd on /proc/fs/nfsd type nfsd (rw,relatime)
/dev/mapper/md0-nfs on /nfs type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
在重新安装/nfs
文件系统之后,我们可以看到选项显示rw
,这意味着它是Read-Writable
。
文件系统/
或root
有一点不同。 它之所以不同,是因为顶层文件系统包含了大多数 Linux 包、二进制文件和命令。 这意味着我们不能简单地卸载这个文件系统而不丢失重新安装它所需的工具。
由于这个原因,我们实际上会使用mount
命令重新挂载/
文件系统,而不需要先卸载它:
[nfs]# mount -o remount /
为了告诉mount
命令卸载然后重新安装文件系统,我们只需要传递–o
(选项)标志,然后传递选项remount
。 –o
标志允许您从命令行传递文件系统选项,如rw
或ro
。 当我们重新挂载/文件系统时,我们只是简单地传递了 remount 文件系统选项:
# mount | grep root
/dev/mapper/md0-root on / type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
如果使用mount
命令显示已挂载的文件系统,则可以验证/
文件系统是否已使用Read-Write
访问权限重新挂载。 由于文件系统类型是xfs
,重新挂载应该导致文件系统执行一致性检查和修复。 如果我们对/
文件系统的完整性有任何怀疑,我们的下一步应该是简单地重新启动 NFS 服务器。
如果服务器无法挂载/
文件系统,则将自动调用xfs_repair
实用程序。
此时,我们可以看到 NFS 服务器的文件系统问题已经恢复。 现在我们应该验证我们的 NFS 客户机是否能够写入 NFS 共享。 但是在我们这样做之前,我们还应该首先重新启动我们之前停止的 NFS 服务:
[nfs]# systemctl start nfs
[nfs]# systemctl status nfs
nfs-server.service - NFS server and services
Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled)
Active: active (exited) since Mon 2015-04-27 22:20:46 MST; 6s ago
Process: 2278 ExecStopPost=/usr/sbin/exportfs -f (code=exited, status=0/SUCCESS)
Process: 3098 ExecStopPost=/usr/sbin/exportfs -au (code=exited, status=1/FAILURE)
Process: 3095 ExecStop=/usr/sbin/rpc.nfsd 0 (code=exited, status=0/SUCCESS)
Process: 3265 ExecStart=/usr/sbin/rpc.nfsd $RPCNFSDARGS (code=exited, status=0/SUCCESS)
Process: 3264 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS)
Main PID: 3265 (code=exited, status=0/SUCCESS)
CGroup: /system.slice/nfs-server.service
一旦 NFS 服务启动,我们就可以在客户端使用touch
命令进行测试:
[db]# touch /data/testfile.txt
[db]# ls -la /data/testfile.txt
-rw-r--r--. 1 root root 0 Apr 28 05:24 /data/testfile.txt
看来我们已经成功地解决了这个问题。
作为边注,如果我们注意到对 NFS 共享的请求花费了很长时间,那么可能需要在客户端卸载并挂载 NFS 共享。 如果 NFS 客户端没有识别 NFS 服务器已经重新启动,这是一个常见问题。
在本章中,我们深入探讨了如何挂载文件系统、如何配置 NFS 以及在文件系统进入Read-Only
模式时应该做什么。 我们甚至更进一步,手动修复物理磁盘设备有问题的文件系统。
在下一章中,我们将通过排除硬件故障进一步讨论这个问题。 这意味着查看硬件消息的日志,对硬盘驱动器 RAID 集进行故障排除,以及许多其他与硬件相关的故障排除步骤。*