运维工程师学习手册
运维工程师学习手册
文件存储结构
介绍文件存储结构前先来看看文件系统如何划分磁盘,创建一个文件、目录、链接的过程。
01
物理磁盘到文件系统
我们知道文件最终是保存在硬盘上的。硬盘最基本的组成部分是由坚硬金属材料制成的涂以磁性介质的盘片,不同容量硬盘的盘片数不等。
每个盘片有两面,都可记录信息。盘片被分成许多扇形的区域,每个区域叫一个扇区,每个扇区可存储128×2的N次方(N=0.1.2.3)字节信息。在DOS中每扇区是128×2的2次方=512字节,盘片表面上以盘片中心为圆心,不同半径的同心圆称为磁道。
硬盘中,不同盘片相同半径的磁道所组成的圆柱称为柱面。磁道与柱面都是表示不同半径的圆,在许多场合,磁道和柱面可以互换使用。我们知道,每个磁盘有两个面,每个面都有一个磁头,习惯用磁头号来区分。扇区、磁道(或柱面)和磁头数构成了硬盘结构的基本参数,帮这些参数可以得到硬盘的容量,基计算公式为:
存储容量=磁头数×磁道(柱面)数×每道扇区数×每扇区字节数
要点:
(1)硬盘有数个盘片,每盘片两个面,每个面一个磁头
(2)盘片被划分为多个扇形区域即扇区
(3)同一盘片不同半径的同心圆为磁道
(4)不同盘片相同半径构成的圆柱面即柱面
(5)公式:存储容量=磁头数×磁道(柱面)数×每道扇区数×每扇区字节数
(6)信息记录可表示为:××磁道(柱面),××磁头,××扇区
那么这些空间又是怎么管理起来的呢?unix / Linux使用了一个简单的方法。
它将磁盘块分为以下三个部分:
1) 超级块。
文件系统中第一个块被称为超级块。这个块存放文件系统本身的结构信息。比如,超级块记录了每个区域的大小,超级块也存放未被使用的磁盘块的信息。
2) I-切点表。
超级块的下一个部分就是i-节点表。每个i-节点就是一个对应一个文件/目录的结构,这个结构它包含了一个文件的长度、创建及修改时间、权限、所属关系、磁盘中的位置等信息。一个文件系统维护了一个索引节点的数组,每个文件或目录都与索引节点数组中的唯一一个元素对应。系统给每个索引节点分配了一个号码,也就是该节点在数组中的索引号,称为索引节点号。
3) 数据区。
文件系统的第3个部分是数据区。文件的内容保存在这个区域。磁盘上所有块的大小都一样。如果文件包含了超过一个块的内容,则文件内容会存放在多个磁盘块中。一个较大的文件很容易分布上千个独产的磁盘块中。
Linux正统的文件系统(如ext2、ext3)一个文件由目录项、inode和数据块组成。
目录项:包括文件名和inode节点号。
Inode:又称文件索引节点,是文件基本信息的存放地和数据块指针存放地。
数据块:文件的具体内容存放地。
Linux正统的文件系统(如ext2、3等)将硬盘分区时会划分出目录块、inode Table区块和data block数据区域。一个文件由一个目录项、inode和数据区域块组成。Inode包含文件的属性(如读写属性、owner等,以及指向数据块的指针),数据区域块则是文件内容。当查看某个文件时,会先从inode table中查出文件属性及数据存放点,再从数据块中读取数据。
文件存储结构大概如下:
其中目录项的结构如下(每个文件的目录项存储在改文件所属目录的文件内容里):
目录项结构 :
其中文件的inode结构如下(inode里所包含的文件信息可以通过stat filename查看得到):
以上只反映大体的结构,linux文件系统本身在不断发展。但是以上概念基本是不变的。且如ext2、ext3、ext4文件系统也存在很大差别,如果要了解可以查看专门的文件系统介绍。
02
创建一个文件的过程
我们从前面可以知道文件的内容和属性是分开存放的,那么又是如何管理它们的呢?现在我们以创建一个文件为例来讲解。
在命令行输入命令:
$ who > userlist
当完成这个命令时。文件系统中增加了一个存放命令who输出内容的新文件userlist,那么这整个过程到底是怎么回事呢?
文件主要有属性、内容以及文件名三项。内核将文件内容存放在数据区,文件属性存放在i-节点,文件名存放在目录中。
创建成功一个文件主要有以下四个步骤:
1) 存储属性
也就是文件属性的存储,内核先找到一块空的i-节点。例如,内核找到i-节点号921130。内核把文件的信息记录其中。如文件的大小、文件所有者、和创建时间等。
2) 存储数据
即文件内容的存储,由于该文件需要3个数据块。因此内核从自由块的列表中找到3个自由块。如600、200、992,内核缓冲区的第一块数据复制到块600,第二和第三分别复制到922和600。
3) 记录分配情况
数据保存到了三个数据块中,所以必须要记录起来,以后再找到正确的数据。分配情况记录在文件的i-节点中的磁盘序号列表里。这3个编号分别放在最开始的3个位置。
4) 添加文件名到目录
新文件的名字是userlist 内核将文件的入口(47,userlist)添加到目录文件里。文件名和i-节点号之间的对应关系将文件名和文件和文件的内容属性连接起来,找到文件名就找到文件的i-节点号,通过i-节点号就能找到文件的属性和内容。
代码具体实现过程参考:
http://blog.csdn.net/kai_ding/article/details/9206057
03
创建一个目录的过程
前面说了创建一个文件的大概过程,也了解文件内容、属性以及入口的保存方式,那么创建一个目录时又是怎么回事呢?
我现在test目录使用命令mkdir 新增一个子目录child:
从用户的角度看,目录child是目录test的一个子目录,那么在系统中这层关系是怎么实现的呢?实际上test目录包含一个指向子目录child的i-节点的链接,原理跟普通文件一样,因为目录也是文件。
目录其实也是文件,只是它的内容比较特殊。所以它的创建过程和文件创建过程一样,只是第二步写的内容不同。
系统找到空闲的i-节点号887220,写入目录的属性
找到空闲的数据块1002来存储目录的内容,只是目录的内容比较特殊,包含文件名字列表,列表一般包含两个部分:i-节点号和文件名,这个列表其实也就是文件的入口,新建的目录至少包含三个目录”.”和”..”其中”.”指向自己,”..”指向上级目录,我们可以通过比较对应的i-节点号来验证,887270对应着上级目录中的child对应的i-节点号。
记录分配情况。这个和创建文件完全一样。
添加目录的入口到父目录,即在父目录中的child入口。
一般都说文件存放在某个目录中,其实目录中存入的只是文件在i-节点表的入口,而文件的内容则存储在数据区。
我们一般会说“文件userlist在目录test中”,其实这意味着目录test中有一个指向i-节点921130的链接,这个链接所附加的文件名为userlist,这也可以这样理解:目录包含的是文件的引用,每个引用被称为链接。文件的内容存储在数据块。文件的属性被记录在一个被称为i-节点的结构中。I-节点的编号和文件名关联起来存在目录中。
注意:其中“.”表示是当前目录。而“..”是当前目录的父目录。但也有特殊情况:如我们查看根目录/的情况,发现“.”和“..”都指向i-节点2。实际上当我们用mkfs创建一个文件系统时,mkfs都会将根目录的父目录指向自己。所以根目录下.和..指向同一个i-节点也不奇怪了。
代码具体实现参考:
http://blog.csdn.net/kai_ding/article/details/9206057
04
理解链接
我们知道文件都有文件名与数据,这在 Linux 上被分成两个部分:用户数据 (user data) 与元数据 (metadata)。
用户数据,即文件数据块 (data block),数据块是记录文件真实内容的地方。
而元数据则是文件的附加属性,如文件大小、创建时间、所有者等信息。
在 Linux 中,元数据中的 inode 号(inode 是文件元数据的一部分但其并不包含文件名,inode 号即索引节点号)才是文件的唯一标识而非文件名。文件名仅是为了方便人们的记忆和使用,系统或程序通过 inode 号寻找正确的文件数据块。图 1.展示了程序通过文件名获取文件内容的过程。
图 1. 通过文件名打开文件
清单 3. 移动或重命名文件
在 Linux 系统中查看 inode 号可使用命令 stat 或 ls -i (若是 AIX 系统,则使用命令 istat)。清单 3.中使用命令 mv 移动并重命名文件 glibc-2.16.0.tar.xz,其结果不影响文件的用户数据及 inode 号,文件移动前后 inode 号均为:2485677。
为解决文件的共享使用,Linux 系统引入了两种链接:硬链接 (hard link) 与软链接(又称符号链接,即 soft link 或 symbolic link)。
具体关系如下:
为 Linux 系统解决了文件的共享使用,还带来了隐藏文件路径、增加权限安全及节省存储等好处。若一个 inode 号对应多个文件名,则称这些文件为硬链接。换言之,硬链接就是同一个文件使用了多个别名。硬链接可由命令 link 或 ln 创建。如下是对文件 oldfile 创建硬链接。
link oldfile newfile
ln oldfile newfile
由于硬链接是有着相同 inode 号仅文件名不同的文件,因此硬链接存在以下几点特性:
文件有相同的 inode 及 data block;
只能对已存在的文件进行创建;
不能交叉文件系统进行硬链接的创建;
不能对目录进行创建,只可对文件创建;
删除一个硬链接文件并不影响其他有相同 inode 号的文件。
创建一个链接的步骤大概如下:
通过原文件的文件名找到文件的i-节点号。
添加文件名关联到目录,新文件的名字是mylink 内核将文件的入口(921130,mylink)添加到目录文件里。
和创建文件的过程比较发现,链接少了写文件内容的步骤,完全相同的是把文件名关联到目录这一步。
现在.i- 节点号921130对应了两个文件名。链接数也会变成2个,文件的内容并不会发生任何变化。前面我们已经讲了:目录包含的是文件的引用,每个引用被称为链接。所以链接文件和原始文件本质上是一样的,因为它们都是指向同一个i-节点。
由于此原因也就可以理解链接的下列特性:你改变其中任何一个文件的内容,别的链接文件也一样是变化;另外如果你删除某一个文件,系统只会在所指向的i-节点上把链接数减1,只有当链接数减为零时才会真正释放i-节点。
硬链接有两个特点:
1)不能跨文件系统
2)不能对目录
清单 4. 硬链接特性展示
# ls -li
total 0
// 只能对已存在的文件创建硬连接
# link old.file hard.link
link: cannot create link `hard.link' to `old.file': No such file or directory
# echo "This is an original file" > old.file
# cat old.file
This is an original file
# stat old.file
File: `old.file'
Size: 25 Blocks: 8 IO Block: 4096 regular file
Device: 807h/2055d Inode: 660650 Links: 2
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
...
// 文件有相同的 inode 号以及 data block
# link old.file hard.link | ls -li
total 8
660650 -rw-r--r-- 2 root root 25 Sep 1 17:44 hard.link
660650 -rw-r--r-- 2 root root 25 Sep 1 17:44 old.file
// 不能交叉文件系统
# ln /dev/input/event5 /root/bfile.txt
ln: failed to create hard link `/root/bfile.txt' => `/dev/input/event5':
Invalid cross-device link
// 不能对目录进行创建硬连接
# mkdir -p old.dir/test
# ln old.dir/ hardlink.dir
ln: `old.dir/': hard link not allowed for directory
# ls -iF
660650 hard.link 657948 old.dir/ 660650 old.file
软链接与硬链接不同,若文件用户数据块中存放的内容是另一文件的路径名的指向,则该文件就是软连接。软链接就是一个普通文件,只是数据块内容有点特殊。软链接有着自己的 inode 号以及用户数据块(见图2.)。因此软链接的创建与使用没有类似硬链接的诸多限制:
软链接有自己的文件属性及权限等;
可对不存在的文件或目录创建软链接;
软链接可交叉文件系统;
软链接可对文件或目录创建;
创建软链接时,链接计数 i_nlink 不会增加;
删除软链接并不影响被指向的文件,但若被指向的原文件被删除,则相关软连接被称为死链接(即 dangling link,若被指向路径文件被重新创建,死链接可恢复为正常的软链接)。
图 2. 软链接的访问
软链接
实际上只是一段文字,里面包含着它所指向的文件的名字,系统看到软链接后自动跳到对应的文件位置处进行处理;相反,硬链接为文件开设一个新的目录项,硬链接与文件原有的名字是平权的,在Linux看来它们是等价的。由于这个原因,硬链接不能连接两个不同文件系统上的文件。
软连接与windows下的快捷方式类似
至于硬连接,举个例子说吧,你把dir1/file1硬连接到dir2/file2, 就是在dir2下建立一个dir1/file1的镜像文件file2,它与file1是占用一样大的空间的,并且改动两者中的一个,另一个也会发生同样的改动。
软连接和硬连接可以这样理解:
硬连接就像一个文件有多个文件名,软连接就是产生一个新文件(这个文件内容,实际上就是记当要链接原文件路径的信息),这个文件指向另一个文件的位置,
硬连接必须在同一文件系统中,而软连接可以跨文件系统。
硬连接 :源文件名和链接文件名都指向相同的物理地址,目录不能够有硬连接,文件在磁盘中只有一个复制,可以节省硬盘空间,由于删除文件要在同一个索引节点属于唯一的连接时才能成功,因此可以防止不必要的误删除软连接(符号连接)用ln -s命令创建文件的符号连接,符号连接是linux特殊文件的一种,作为一个文件,它的资料是它所连接的文件的路径名,类似于硬件方式,可以删除原始文件,而连接文件仍然存在。
# ls -li
total 0
// 可对不存在的文件创建软链接
# ln -s old.file soft.link
# ls -liF
total 0
789467 lrwxrwxrwx 1 root root 8 Sep 1 18:00 soft.link -> old.file
// 由于被指向的文件不存在,此时的软链接 soft.link 就是死链接
# cat soft.link
cat: soft.link: No such file or directory
// 创建被指向的文件 old.file,soft.link 恢复成正常的软链接
# echo "This is an original file_A" >> old.file
# cat soft.link
This is an original file_A
// 对不存在的目录创建软链接
# ln -s old.dir soft.link.dir
# mkdir -p old.dir/test
# tree . -F --inodes
.
├── [ 789497] old.dir/
│ └── [ 789498] test/
├── [ 789495] old.file
├── [ 789495] soft.link -> old.file
└── [ 789497] soft.link.dir -> old.dir/
代码具体实现参考:http://blog.csdn.net/kai_ding/article/details/8942884
文件节点inode
可以看到inode节点好比是文件的大脑,下面就详细介绍一下inode。
01
inode是什么
理解inode,要从文件储存说起。
扇区(sector):硬件(磁盘)上的最小的操作单位,是操作系统和块设备(硬件、磁盘)之间传送数据的单位。
block由一个或多个sector组成,文件系统中最小的操作单位;OS的虚拟文件系统从硬件设备上读取一个block,实际为从硬件设备读取一个或多个sector。对于文件管理来说,每个文件对应的多个block可能是不连续的。
block最终要映射到sector上,所以block的大小一般是sector的整数倍。不同的文件系统block可使用不同的大小,操作系统会在内存中开辟内存,存放block到所谓的block buffer中。
在Ext2中,物理块的大小是可变化的,这取决于在创建文件系统时的选择,之所以不限制大小,也正体现了Ext2的灵活性和可扩充性。通常,Ext2的物理块占一个或几个连续的扇区,显然,物理块的数目是由磁盘容量等硬件因素决定的。
具体文件系统所操作的基本单位是逻辑块,只在需要进行I/O操作时才进行逻辑块到物理块的映射,这显然避免了大量的I/O操作,因而文件系统能够变得高效。逻辑块作为一个抽象的概念,它必然要映射到具体的物理块上去,因此,逻辑块的大小必须是物理块大小的整数倍,一般说来,两者是一样大的。
通常,一个文件占用的多个物理块在磁盘上是不连续存储的,因为如果连续存储,则经过频繁的删除、建立、移动文件等操作,最后磁盘上将形成大量的空洞,很快磁盘上将无空间可供使用。因此,必须提供一种方法将一个文件占用的多个逻辑块映射到对应的非连续存储的物理块上去,Ext2等类文件系统是用索引节点解决这个问题的。
文件数据都储存在“块”中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为"索引节点"。
在Unix/Linux上,一个文件由一个inode 表示。inode在系统管理员看来是每一个文件的唯一标识,在系统里面,inode是一个结构,存储了关于这个文件的大部分信息。
02
inode内容
inode包含文件的元信息,具体来说有以下内容:
文件的字节数。
文件拥有者的UserID*文件的GroupID。
文件的读、写、执行权限。
文件的时间戳,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间。
链接数,即有多少文件名指向这个inode*文件数据block的位置可以用stat命令,查看某个文件的inode信息:statexample.txt。
总之,除了文件名以外的所有文件信息,都存在inode之中。至于为什么没有文件名,下文会有详细解释。
inode中存储了一个文件的以下信息:
03
inode结构
inode就是一个文件的一部分描述,不是全部,在内核中,inode对应了这样一个实际存在的结构。
纵观整个inode的C语言描述,没有发现关于文件名的东西,也就是说文件名不由inode保存,实际上系统是不关心文件名的,对于系统中任何的操作,大部分情况下你都是通过文件名来做的,但系统最终都要通过找到文件对应的inode来操作文件,由inode结构中 *i_op指向的接口来操作。
文件系统如何存取文件的:
根据文件名,通过Directory里的对应关系,找到文件对应的Inodenumber。
再根据Inodenumber读取到文件的Inodetable。
再根据Inodetable中的Pointer读取到相应的Blocks。
这里有一个重要的内容,就是Directory,他不是我们通常说的目录,而是一个列表,记录了一个文件/目录名称对应的Inodenumber。
END
推荐阅读
>>>Linux运维零基础入门第一课 - 云计算是什么,如何定义
>>>Docker容器使用-Linux运维红帽RHCE零基础入门课
>>>Linux运维工程师年薪30w?为什么他可以我不行?行业概述
运维界升职加薪必备的云计算技术,你学了吗?
学完高级运维云计算课程之后,你可以:
跨越90%企业的招聘硬门槛
增加70%就业机会
拿下BAT全国TOP100大厂敲门砖
体系化得到运维技术硬实力
技术大佬年薪可达30w+
资源放送
2021新版Linux运维高级云计算-红帽RHCE实战课程合集,扫描下方二维码即可领取!