linux文件系统

一.了解文件系统

        分区很复杂,但是为了好理解不妨先简化介绍。首先来看下图,记住这是一个分区。

linux文件系统_第1张图片

        当对一个分区格式化时,分区被分成两部分。

        (1)右侧部分被划分成很多小格子,每个小格子称为block,默认大小为4KB。

        (2)左侧部分为inode,用于记录文件的属性,每个文件都会占用一个 inode。每个block中只能存储一个文件,假设一个文件aa只有1KB存放在2号block中,则2号block还剩余3KB的空间,但是这3KB的空间也不会存储其他数据了。所以,此文件大小为1KB,占用空间为4KB

        如果一个文件的值大于4KB,一个block存放不下,则会占用多个 block。例如,某文件大小为9KB,则需要占用3个block。

        当要读取某个文件时,如果系统不知道此文件在哪个block中,则要读取所有的block(这个过程称为“遍历”),这样效率是极其低下的。所以,每个文件的属性都有对应的inode条目来记录,例如,上图中的aa文件由10号inode记录,在inode中记录了aa文件的属性,如大小、权限等,以及此文件占用了哪些block,inode相当于书的目录。当需要读取文件时。在inode中可以快速找到此文件,从而快速定位此文件所在的block。

        总之,创建文件系统的过程就理解为创建上图中小格子的过程。不同的内核所使用的文件系统不一样,例如,Windows 中常见的文件系统包括FAT、NTFS等,Linux中常见的文件系统包括EXT3、EXT4、XFS等。这些不同的文件系统具有不同的功能,包括所支持的单个文件最大能有多大,整个文件系统最大能有多大,RHEL8/CentOS8中默认的文件系统是XFS。

二.了解硬链接

        前面讲了inode记录的是某文件的属性信息,如图

linux文件系统_第2张图片

        10号 inode记录了aa文件的属性,包括aa文件的名称、大小、权限等,及其所在的block,可以在10号inode中给aa文件再起一个名称bb,如图

linux文件系统_第3张图片

        此时对10号inode来说,用两个名称aa和 bb来记录2号block中的文件,所以 aa和 bb对应的是同一个文件,那么aa和 bb就是硬链接关系。

        练习:先拷贝一个测试文件,例"/etc/hosts"文件

[root@jiayi ~]# cp /etc/hosts aa

        查看aa的属性

[root@jiayi ~]# ls -lh aa
-rw-r--r-- 1 root root 158 12月  3 22:06 aa

        此处的加粗字1,指的是aa文件只有一个硬链接,即存储在 block中的文件只有一个名称aa。下面对aa做硬链接

[root@jiayi ~]# ln aa bb

        查看aa和bb的属性

[root@jiayi ~]# ls -lh aa bb
-rw-r--r-- 2 root root 158 12月  3 22:06 aa
-rw-r--r-- 2 root root 158 12月  3 22:06 bb

        硬链接数显示为2,说明存储在 block中的那个文件有两个名称aa和 bb。aa和 bb是在同一个inode上记录的两个名称,通过ls -i可以查看aa和 bb分别是在哪个inode上记录的

[root@jiayi ~]# ls -i aa ; ls -i bb
202296827 aa
202296827 bb

        可以看到, inode值是--样的。即在同-个inode上用两个名称来记录 block中的那个文件。换言之就是aa和bb对应的是同一个文件,修改aa之后会发现.bb的内容也做了相同的修改,修改协之后会发现aa也做了相应的修改。

        因为block中的文件现在有两个名称,所以删除任意一个之后,block中的数据是不会跟着删除的。所以,删除aa是不会影响bb的,或者删除bb也不会影响aa。但是aa和bb两个同时删除,则block中的文件就没有名称了,则此文件会从 block中删除。

        block中的文件只要还有一个名称,那么数据就不会删除。如果所有名称都没有了,则此数据会从 block中删除。

        同一个分区的inode只能记录同一个分区 block中的数据,不能在第二个分区中产生一个inode来记录第一个分区中的文件,所以硬链接不能跨分区。

3.创建文件系统

        再看看前面已经在/dev/sdb 上创建过的分区

[root@jiayi ~]# fdisk -l /dev/nvme0n2
Disk /dev/nvme0n2:20 GiB,21474836480 字节,41943040 个扇区
单元:扇区 / 1 * 512 = 512 字节
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0xc783fdac

设备           启动    起点     末尾     扇区 大小 Id 类型
/dev/nvme0n2p1         2048  4196351  4194304   2G 83 Linux
/dev/nvme0n2p2      4196352  8390655  4194304   2G 83 Linux
/dev/nvme0n2p4      8390656 41943039 33552384  16G 83 Linux

        下面对分区进行格式化,格式化的语法如下

mkfs ‐f 文件系统 ‐选项 /dev/分区
或
mkfs.文件系统 ‐选项 /dev/分区

        把/dev/nvme0n2p1格式化为XFS文件系统

[root@jiayi ~]# mkfs.xfs /dev/nvme0n2p1
meta-data=/dev/nvme0n2p1         isize=512    agcount=4, agsize=131072 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=1
data     =                       bsize=4096   blocks=524288, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

        从上面的 bsize=4096可以看到,block的大小默认设置为了4KB,如果指定为1KB,需要加上-b size=1024选项

[root@jiayi ~]# mkfs.xfs -b size=1024 /dev/nvme0n2p1
mkfs.xfs: /dev/nvme0n2p1 appears to contain an existing filesystem (xfs).
mkfs.xfs: Use the -f option to force overwrite.

        再次格式化时,因为/dev/nvme0n2p1已经存在文件系统了,所以再次格式化失败,需要加上-f选项表示强制格式化

[root@jiayi ~]# mkfs.xfs -f -b size=1024 /dev/nvme0n2p1
meta-data=/dev/nvme0n2p1         isize=512    agcount=4, agsize=524288 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=1
data     =                       bsize=1024   blocks=2097152, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=1024   blocks=10240, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

        可以看到,现在bsize即 block size的大小已经是1024了。这里输出的属性是刚格式化后输出的,如果过了一段时间之后想再次查看/dev/sdb1文件系统的属性,可以通过xfs_info来查看

[root@jiayi ~]# xfs_info /dev/nvme0n2p1
meta-data=/dev/nvme0n2p1         isize=512    agcount=4, agsize=524288 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=1
data     =                       bsize=1024   blocks=2097152, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=1024   blocks=10240, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

        记住,block size的大小只能在格式化时指定,不可以后期修改。

        每个文件系统都会有唯一的一个UUID来记录,查看系统中所有的UUID,可以通过如下命今

[root@jiayi ~]# blkid
/dev/nvme0n1: PTUUID="53d73aeb" PTTYPE="dos"
/dev/nvme0n1p1: UUID="8e7bc5eb-a396-4e03-b741-37b8162a3725" BLOCK_SIZE="512" TYPE="xfs" PARTUUID="53d73aeb-01"
/dev/nvme0n1p2: UUID="KrMlRb-krfi-T43c-mJHd-ns6H-z3IF-5lweYU" TYPE="LVM2_member" PARTUUID="53d73aeb-02"
/dev/nvme0n2: PTUUID="c783fdac" PTTYPE="dos"
/dev/nvme0n2p1: UUID="25116cf4-20ba-428e-a395-a9580c2c9ef6" BLOCK_SIZE="512" TYPE="xfs" PARTUUID="c783fdac-01"
/dev/nvme0n2p2: PARTUUID="c783fdac-02"
/dev/nvme0n2p4: PARTUUID="c783fdac-04"
/dev/sr0: BLOCK_SIZE="2048" UUID="2021-10-13-03-57-25-00" LABEL="RHEL-8-5-0-BaseOS-x86_64" TYPE="iso9660" PTUUID="4d694e6c" PTTYPE="dos"
/dev/mapper/rhel_jiayi-root: UUID="85f1fb7a-3234-440c-b315-fd171f0adad7" BLOCK_SIZE="512" TYPE="xfs"
/dev/mapper/rhel_jiayi-swap: UUID="c7b9aa1a-de8c-4c80-9545-f6de5ce5e671" TYPE="swap"
/dev/mapper/rhel_jiayi-home: UUID="2697e301-3f85-4667-bf3b-43aca64b1d22" BLOCK_SIZE="512" TYPE="xfs"

        如果想单独查看某个XFS格式的文件系统的UUID,可以通过“xfs admin -u分区名”来查看

[root@jiayi ~]# xfs_admin -u /dev/nvme0n2p1
UUID = 25116cf4-20ba-428e-a395-a9580c2c9ef6

        可以看到,/dev/nvme0n2p1文件系统的UUID是 25116cf4-20ba-428e-a395-a9580c2c9ef6。这个UUID也是可以切换成其他值的

        通过uuidgen命令手动生成一个新的UUID

[root@jiayi ~]# uuidgen
6f3da2e8-3bce-4b47-8f94-653191b2ec95

        把/dev/nvme0n2p1的UUID切换成新生成的UUID

[root@jiayi ~]# xfs_admin -U 6f3da2e8-3bce-4b47-8f94-653191b2ec95 /dev/nvme0n2p1
Clearing log and setting UUID
writing all SBs
new UUID = 6f3da2e8-3bce-4b47-8f94-653191b2ec95

        再次查看/dev/sdb1的UUID

[root@jiayi ~]# xfs_admin -u /dev/nvme0n2p1
UUID = 6f3da2e8-3bce-4b47-8f94-653191b2ec95

        可以看到,现在已经是新的UUID 了

4.挂载文件系统

        分区格式化好了之后是不可以直接访问的,要想访问此分区,必须把它挂载到某个目录上才行,如同在 Windows中创建一个分区,必须给它一个盘符或装在某个NTFS文件夹中。

        要查看哪些分区已经挂载及分区的使用情况,可以使用df命令

[root@jiayi ~]# df
文件系统                       1K-块    已用     可用 已用% 挂载点
devtmpfs                      968968       0   968968    0% /dev
tmpfs                         998536       0   998536    0% /dev/shm
tmpfs                         998536    9580   988956    1% /run
tmpfs                         998536       0   998536    0% /sys/fs/cgroup
/dev/mapper/rhel_jiayi-root 68283828 5771980 62511848    9% /
/dev/mapper/rhel_jiayi-home 33341536  265672 33075864    1% /home
/dev/nvme0n1p1               1038336  232248   806088   23% /boot
tmpfs                         199704      12   199692    1% /run/user/42
tmpfs                         199704       0   199704    0% /run/user/0

        这里文件系统为tmpfs的是临时文件系统,可以忽略不管,上面结果中的分区大小都是以K为单位,看起来不方便,可以加上-hT选项,-h会以合适的单位显示,-T会显示文件系统

[root@jiayi ~]# df -Th | grep -v tmpfs
文件系统                    类型      容量  已用  可用 已用% 挂载点

/dev/nvme0n1p1              xfs      1014M  227M  788M   23% /boot

        挂载语法的命令如下

mount ‐o optl,opt2,... /dev/设备/目录

        首先创建一个目录jiayi,并拷贝进去几个测试文件

[root@jiayi ~]# mkdir jiayi
[root@jiayi ~]# cp /etc/hosts /etc/services jiayi/
[root@jiayi ~]# ls jiayi/
hosts  services

        下面把/dev/nvme0n2p1挂载到jiayi上,注意jiayi中内容的变化

[root@jiayi ~]# mount /dev/nvme0n2p1 jiayi/
[root@jiayi ~]# ls jiayi/
[root@jiayi ~]# 

        以后访问jiayi就是访问/dev/nvme0n2p1中的内容了,现在查看jiayi中的内容

        此时发现jiayi中的内容看不到了,原因是如果某个目录挂载了一个分区,则这个目录中原有的内容就会被隐藏。为了更好地理解,可以参考下图。

        此时是没有挂载的情况,jiayi中有自己的文件,然后把/dev/nvme0n2p1挂载到jiayi 上,如下图所示

linux文件系统_第4张图片linux文件系统_第5张图片

        例如,有一个碗把jiayi中原有的内容盖住了,现在看到的是上层碗中的内容,即/dev/nvme0n2p1中的内容。只有卸载掉才能再次看到,卸载的命令是umount,用法如下。

umount /挂载点
或
umount /dev/设备

        现在把/dev/nvme0n2p1卸载掉,然后查看jiayi中的内容

[root@jiayi ~]# umount /dev/nvme0n2p1
[root@jiayi ~]# ls jiayi/
hosts  services

        卸载后又能看到jiayi中的内容了,就相当于又把盖在jiayi上面的那个“碗”拿掉了,所以能看到jiayi中的内容了。

        这里需要注意两个问题,第一个问题是假设在/xx没有挂载之前,往里面写了一个200GB的文件file,然后又把/dev/nvme0n2p1挂载到/xx上,这时的file会被隐藏。有一天发现少了200GB的空间,然后到每个目录中找jiayi,怎么都找不到这200GB。此时要想到哪些目录是挂载点,这些目录在挂载分区之前,里面是不是存在文件

        第二个问题是有时卸载时可能无法正常卸载,类似于在 Windows中卸载U盘时,提示进程正在占用。先模拟一下这个文件,再次把/dev/nvme0n2p1挂载到jiayi上

[root@jiayi ~]# mount /dev/nvme0n2p1 jiayi/

        打开第二个终端执行如下命令

[root@jiayi ~]# cd jiayi/

        这样cd jiayi之后,bash进程会一直占用jiayi。

        再回到第一个终端,卸载jiayi

[root@jiayi ~]# umount /dev/nvme0n2p1 
umount: /root/jiayi: target is busy.

        发现根本卸载不了,说明jiayi现在正在被某个进程占用。那如何查看是哪个进程占用的呢?可以使用fuser命令

[root@jiayi ~]# fuser -mv jiayi/
                     用户     进程号 权限   命令
/root/jiayi:         root     kernel mount /root/jiayi
                     root       2252 ..c.. bash

        可以看到,有一个进程号为2322的进程正在占用,就是第二个终端中运行的cd命令。利用kill命令杀死进程号为2322的进程,然后再次卸载

[root@jiayi ~]# kill -9 2252
[root@jiayi ~]# umount jiayi/
[root@jiayi ~]# 

        此时可以正常卸载了。这里kill -9 2322的意思是强制杀死进程号为2322的进程,-9表示强制的意思

(这其实和谈恋爱一样,如果你和你对象手也牵了、嘴也亲了、会也约了,不过ta就是不愿意和你表清关系将你公布出去,为什么?因为该程序已经被占用,你只有杀死该进程号,才可以查看、更改该程序。上述用的是root用户所以可以杀死该进程号,如果你只是普通用户,你就会发现你无法杀死该进程号甚至连查看该进程号的权限都没有,root用户的权限真的很大,所以我们就应该知道自己无法查看、更改该程序,这个时候我们应该去重新编写一个属于自己的一个程序或者等root用户结束该程序)

        挂载时还可以指定一些选项,先看一下默认的选项

[root@jiayi ~]# mount /dev/nvme0n2p1 jiayi/

[root@jiayi ~]# mount | grep jiayi
/dev/mapper/rhel_jiayi-root on / type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)
/dev/mapper/rhel_jiayi-home on /home type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)
/dev/nvme0n2p1 on /root/jiayi type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)

        通过执行mount命今可以看到所有已经挂裁了的设冬,地可以看到/dev/nvme0n2p1的默认挂载选项。其中rw的意思是可读可写,测试往jiayi中写入内容

[root@jiayi ~]# ls jiayi/
[root@jiayi ~]# cp /etc/services jiayi/
[root@jiayi ~]# ls jiayi/
services

        现在是可以正常写进去的,然后卸载并重新以ro的方式挂载

[root@jiayi ~]# umount jiayi/

[root@jiayi ~]# mount -o ro /dev/nvme0n2p1 jiayi/

        查看挂载选项

[root@jiayi ~]# mount | grep jiayi
/dev/mapper/rhel_jiayi-root on / type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)
/dev/mapper/rhel_jiayi-home on /home type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)
/dev/nvme0n2p1 on /root/jiayi type xfs (ro,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)

        现在是以ro的方式挂载的,测试往jiayi中写入内容

[root@jiayi ~]# cp /etc/issue jiayi/
cp: 无法创建普通文件'jiayi/issue': 只读文件系统

        此时就写不进去了

        如果想换选项也不用每次都卸载然后再挂载,可以用如下命令

mount ‐o remount,新选项/挂载点

        现在把/dev/nvme0n2p1以 rw的方式挂载

[root@jiayi ~]# mount -o remount,rw jiayi/
[root@jiayi ~]# mount | grep jiayi
/dev/mapper/rhel_jiayi-root on / type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)
/dev/mapper/rhel_jiayi-home on /home type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)
/dev/nvme0n2p1 on /root/jiayi type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)

        然后再次拷贝测试文件进去

[root@jiayi ~]# cp /etc/issue jiayi/

[root@jiayi ~]# ls jiayi
issue  services

        可以看到,已经可以正常拷贝过去了

5.设置永久挂载

        前面使用mount挂载设备也只是临时生效,重启系统之后此设备不会自动挂载。如果希望重启之后能自动挂载,需要写入/etc/fstab中,格式如下

设备 挂载点 文件系统 挂载选项 dump值 fsck值
或
设备UUID 挂载点 文件系统 挂载选项 dump值 fsck值

        最后两列的意义如下。

        (1)dump值:意思是能否被dump备份命令作用,dump是一个用来作为备份的命令,通常这个参数的值为0或1

        (2)fsck值:是否检验扇区,开机的过程中,系统默认会以fsck检验系统是否完整(clean)。这两列值建议写0,不要写其他值

        现在希望/dev/nvme0n2p1在重启之后能自动挂载到jiayi 上,/etc/fstab的写法如下

[root@jiayi ~]# grep jiayi/ /etc/fstab 
/dev/nvme0n2p1 jiayi/                   xfs        defaults         0 0

        这样开机就会自动挂载,当然这里也可以写/dev/sdb1的 UUID。先获取/dev/nvme0n2p1的UUID

[root@jiayi ~]# xfs_admin -u /dev/nvme0n2p1
UUID = 6f3da2e8-3bce-4b47-8f94-653191b2ec95

        修改/etc/fstab的内容

[root@jiayi ~]# grep jiayi /etc/fstab 

# /dev/nvme0n2p1 jiayi/                   xfs        defaults         0 0
UUID=6f3da2e8-3bce-4b47-8f94-653191b2ec95 jiayi/                   xfs     defaults        0 0

        需要注意的是,UUID后面的“=”两边不要有空格,挂载选项使用默认选项,所以关键字defaults,记住是defaults而不是 default。如果要加上其他选项就用逗号隔开,例如,以ro 的方式挂载

[root@jiayi ~]# grep jiayi/ /etc/fstab 
# /dev/nvme0n2p1 jiayi/                   xfs        defaults         0 0
UUID=6f3da2e8-3bce-4b47-8f94-653191b2ec95 jiayi/                   xfs     defaults,ro        0 0

        选项分隔符逗号两边不要有空格。

        在写人/etc/fstab之后,如果/dev/nvme0n2p1当前没有挂载,执行mouont -a命令可以自动挂载

6.查找文件

        有时我们需要在系统中查找一些文件,Windows 中有一个非常好用的工具Everything

        Everything 可以帮助快速找到想要的文件,Linux中也有这样出较方便的工具,如which、locate、find等

        which一般用于查询可执行的路径,例如,要查询vim所在路径

[root@jiayi ~]# which vim
/usr/bin/vim

        locate用于查询文件名或路径中含有特定关键字的文件

[root@jiayi ~]# locate jiayi
/dev/rhel_jiayi
/dev/disk/by-id/dm-name-rhel_jiayi-home

        这个数据文件默认每天更新一次,所以如果现在创建一个新的文件

[root@jiayi ~]# touch jiayiya
[root@jiayi ~]# locate jiayiya
[root@jiayi ~]# 

        此文件在mlocate.db更新之后创建,也就是文件 jiayiya还没有出现在此数据库文件中,所以查询不到。此时只要更新一下数据库即可

[root@jiayi ~]# updatedb
[root@jiayi ~]# locate jiayiya
/root/jiayiya

        locale命令是用于设置编码的,因为与locate比较像,所以这里提一下。在命令行中直接输入“locale”

[root@jiayi ~]# locale
LANG=zh_CN.UTF-8
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=

        这里显示了当前系统正在使用的编码为zh CN.UTF-8,即显示为中文UTF-8编码

[root@jiayi ~]# ls -l /opt/
总用量 0

        可以看到,这里会以中文显示,如果想设置为英文UTF-8编码

[root@jiayi ~]# LANG=en_US.UTF-8

[root@jiayi ~]# locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
[root@jiayi ~]# ls -l /opt/
total 0

        这种修改编码的方式只是临时生效,重启之后就不再生效了,如果希望能水久生效,需要修改文件

[root@jiayi ~]# cat /etc/locale.conf 
LANG="zh_CN.UTF-8"

        如果只是想执行命令时用指定的编码打开,可以在此命令前加上“LANG-编码”

[root@jiayi ~]# LANG=en_US.UTF-8 ls -l /opt
total 0
[root@jiayi ~]# ls -l /opt
总用量 0

LANG-en_US.UTF-8 可以用LANG-C替代

你可能感兴趣的:(linux)