分区很复杂,但是为了好理解不妨先简化介绍。首先来看下图,记住这是一个分区。
当对一个分区格式化时,分区被分成两部分。
(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记录的是某文件的属性信息,如图
10号 inode记录了aa文件的属性,包括aa文件的名称、大小、权限等,及其所在的block,可以在10号inode中给aa文件再起一个名称bb,如图
此时对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来记录第一个分区中的文件,所以硬链接不能跨分区。
再看看前面已经在/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 了
分区格式化好了之后是不可以直接访问的,要想访问此分区,必须把它挂载到某个目录上才行,如同在 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 上,如下图所示
例如,有一个碗把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
可以看到,已经可以正常拷贝过去了
前面使用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命令可以自动挂载
有时我们需要在系统中查找一些文件,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替代