1.文件系统
从以下三个角度去学习:
1.目录和文件;
2.系统数据文件和信息;
3.进程环境.
2.查看内核注册的文件系统
cat /proc/filesystems
3.文件系统及ext2文件系统
文件系统,file system(fs).
windows上是ntfs,fat32等
Linux上的文件系统:ext2,ext3,ext4,xfs等
4.ext2文件系统
学习文件系统有什么用呢?
如果您学习了文件系统并且对其有比较好的了解,您可以做数据恢复噢.
磁盘是被一些文件系统的逻辑关系组织起来.
当您拿到一个磁盘的时候,您可以当做磁盘是一个一个bit位的存储,
磁盘中有很多扇区,一般来说物理磁盘中的一个扇区是512个字节,磁盘中充满了扇区.
当您想要存储一个文件到磁盘中的时候,是如何存储进去的呢?
当您想要通过文件名读或者打开文件的时候,操作系统又是如何找到这个文件呢?
如果这些512字节都是来存储数据的,您会如何设计这个文件系统呢?
假设您有一个名字叫做hello的文件要存到磁盘中去.
假设我们在磁盘的最后找一块存储空间,写成键值对的形式,
我们需要知道文件名,文件起始位置,文件大小,这样我们就简单地设计出一个文件系统.
但是这样会有一个问题,比如我们的hello这个文件中本来有100byte,之后我们想要在
hello文件后面追加120个字节,这个简单的格式就不太合适了,我们可能需要预留一些位置
给文件扩展使用,但这个预留大小我们是不知道的,所以我们还需要一种更加灵活的文件系统.
文件系统存在的意义就是组织和管理文件在磁盘中的存储.
Linux在设计文件系统时,首先将磁盘分成若干block(块),每个block可以指定大小,
可以是4096bytes或8192bytes或1024bytes,但这个每一块的大小都要是扇区大小的
整数倍,将几个扇区合成一个块,可以更好的方便我们的管理.
如果一个block是4096bytes,一个扇区是512bytes,那么我们可以知道这个块有8个扇区.
可以用以下换算:
1block = 4096 bytes = 32768 bits
1block = 8个磁盘扇区
1个磁盘扇区 = 512 bytes = 4096 bits
也可以设置
1block = 1024bytes = 8192bits
为了方便管理,在整个磁盘分区的有一个比较特殊的blcok,也是第一个block,称作boot block,
(mbi-12:48)
boot block中记录了磁盘分了几个区,每个区的开始位置是什么以及这个区上的操作系统是什么,
比如说C盘装的windows,D盘装的linux,这件事情就会被存储在boot block中.
这个boot block多大呢?pc联盟规定,这个boot block的大小是1k.不管您的系统是window的
还是linux的,都是符合这个标准的,整个磁盘的第一块都是用来存放这些信息的.
在linux系统中,boot block后面的块由ext2(假如您的fs是ext2)开始接管,
ext2中一个Block Group的组成部分:
1.Super Block
2.GDT
3.Block Bitmap
4.Inode Bitmap
5.Inode Table
6.Data Blocks
一个Block Group有多大是谁限制的呢?一个group里有多少块是谁限制的?
这个与block有多大有关系,如果这里设置的一块是1024bytes,
那么就是会有8192个bit位,可以描述8192个块的使用情况.
Group0和Group1里面的块是统一编号的,假设两个Group里面都是8192个块,
那么Group0里面的块的编号是0-8191,Group1里面的块的编号是8192-16383.
一次类推.
ext2在管理这些block的时候,引入了组的概念,会将block分成一个一个组来进行管理,一个组中
有若干个block.
1.Super Block
一个组中的第一块叫做超级块,
2.GDT
超级块后面的几个块会设计成GDT(块组描述符表,Group Descriptor Table).
描述当前的Group是从第几个块开始是Block Bitmap,第几块开始是Inode Bitmap,
第几块开始是Inode Table以及当前Block Group里面块的使用情况(当前的空闲块
有多少).df命令能够快速统计出磁盘的使用情况就是利用了GDT中的信息.
【为什么用 df命令统计整个磁盘的已用空间非常快呢?因为只需要查看每个块组的块位图即可,而不需要搜遍整个分区.
相反,用du命令查看一个较大目录的已用空间就非常慢,因为不可避免地要搜遍整个目录的所有文件.】--摘自博友,待验证.
3.Block Bitmap
GDT后面就是Block Bitmap(块位图,用bit位来表示块的使用情况),块位图可以决定这个Block Group
里面有多少个块.
如果这里设置的一块是1024bytes,
那么就是会有8192个bit位,可以描述8192个块的使用情况,使用了的话比特位翻转成1,没有使用的话
就是0,之前的超级块和GDT所占的块是已经被使用的块,如果是有Block Bitmap占用8192个比特位,
那么说明这个Block Group最多能有8192个块,这样能够用Block Bitmap标识Block Group中每个块
的使用情况.
如果这里设置的一块是4096bytes,
那么就是会有32768个bit位,可以描述8192个块的使用情况,使用了的话比特位翻转成1,没有使用的话
就是0,之前的超级块和GDT所占的块是已经被使用的块,如果是有Block Bitmap占用32768个比特位,
那么说明这个Block Group最多能有32768个块,这样能够用Block Bitmap标识Block Group中每个块
的使用情况.
4.Inode Bitmap
Block Bitmap后面就是Inode位图,标识的是Inode是否用了.记录的是Inode Table中的一个个
Inode的使用状况.
5.Inode Table
Inode Bitmap后面就是Inode Table.
Inode Table(Inode表)是由若干个Inode组成,每个Inode占固定128个字节,如果一个块的大小是
1024bytes,那么一个块里面可以放8个Inode.一个Block Group里面会拿出若干个block来存放Inode.
每个文件都需要一个Inode,每个文件都有一个Inode编号,Inode为什么需要占128个字节呢?因为
Inode需要记录文件的很多信息,比如说文件的大小,文件的块信息,文件的IO块信息,文件的类型,
设备,Inode编号,硬链接计数,文件的权限,文件的Uid,Gid,最近访问,最近修改,最近改动,创
建时间等等信息.Inode与文件内容是没有关系的,文件是由两部分组成,一部分就是属性(由Inode记录),
一部分就是内容,两者是分开的.
Inode的组成:
(1)文件属性;
(2)数据指针组,在128个字节的Inode里面,数据指针组占用60bytes,如果指针是4bytes,那么一个Inode
中会有15个指针,
InodeArray[0] --指向数据块
InodeArray[1] --指向数据块
InodeArray[2] --指向数据块
InodeArray[3] --指向数据块
InodeArray[4] --指向数据块
InodeArray[5] --指向数据块
InodeArray[6] --指向数据块
InodeArray[7] --指向数据块
InodeArray[8] --指向数据块
InodeArray[9] --指向数据块
InodeArray[10] --指向数据块
InodeArray[11] --指向数据块
InodeArray[12] --一级间接寻址指针
InodeArray[13] --二级间接寻址指针
InodeArray[14] --三级间接寻址指针
6.Data Blocks
一个一个block,单位就是block.
了解了以上知识,我们可以看下,如果我们想在Group0中存一个hello文件,我们是如何存进去的.
首先需要申请一个Inode,要想申请一个Inode必须先知道Bitmap在什么位置,会跳过boot block和
超级块去GDT里面检索Inode Bitmap在什么位置并跳转到那里,然后可以通过Inode Bitmap查看哪个
Inode是空闲的,然后计算空闲的Inode在什么位置可以找到空闲的Inode并成功申请,然后在这个Inode
里面存放这个文件的属性文件的权限,文件的Uid,Gid,创建时间等等信息,此时文件的大小还是没有
在Inode中确定下的,下一步需要对文件写内容(此时去开辟数据块,数据块指针指向所申请的数据块,
此时BlockBitmap中相应的标志位也要翻转成1表示此数据块已经被使用了),
假设数据块的大小是1024bytes,假设以上的15个指针都指向一个块,那么当文件大小超过15*1024bytes的
时候如何处理呢?此时linux系统做了一个这样的设计,它的前12个指向的数据块,后面三个指针分别是一级
间接寻址指针,二级间接寻址指针,三级间接寻址指针.
InodeArray[12]里面不存内容,只存指针,1024bytes共有256个指针(256kb+12k)=268KB
InodeArray[13](256*256+12)KB=65548KB=64.011718M
InodeArray[14](256*256*256+12)KB=16777216KB+12KB=16777228KB=16.000011444GB
不用担心心存储不了超过16GB的数据,我们这里只是假定一个block的大小是1KB,一般来说
是4KB,也可以设置成8K,而且在ext4文件系统中,我们的Inode的大小是256字节,可以拥有更多的指针,
思考一下,就会有好的解决方案.
rm是如何工作的?
rm需要释放Inode,释放Inode之前需要释放Inode里面的数据块.
数据块是如何删除的呢?将数据块对应的BlockBitmap中对应的位置设置成0.
然后将Inode中的数据指针组清零或者不清零都行(这个对吗?需要思考一下,为什么都可以呢?)
最主要的是数据块对应的BlockBitmap中相应的位置设置成0,
之后再将Inode对应的bitmap对应的位设置成0,
这样就完成了删除.
所以拷贝1G电影的时候非常费时间,但是删除的时候非常快.(思考window和Linux下创造大文件的问题).
删除的时候只需要将Inode Bitmap和Block Bitmap中的状态为变一下就可以了.
如果需要做数据恢复的话,rm之后数据还是在磁盘中没有丢失,往简单了说,就是要找到文件的Block Bitmap
和Inode Bitmap,将其状态变为1即可,当然其中还是有比较复杂的操作,但思路和原理是这样的.删数据的时候,数据还在真正的数据块中,只是把Block Bitmap和Inode Bitmap对应的位置置为0了.
5.ext2文件系统中用stat查看文件信息
文件系统相关的linux命令:
stat filename 查看一个文件的情况
mke2fs 设置块的大小
6.ext2文件系统的文件名存在哪里?
根据上面的描述我们发现文件名并没有存在Inode里面,那么它究竟存在哪里呢?
让我们揭开它神秘的面纱.
首先我们来看看与之相关的目录.
一个目录一般情况下是多大?一般是4096bytes.
当您创建目录的时候,首先会给这个目录一个Inode,然后通过Inode数据块指针
申请到一个块(操作系统会默认给一个块),目录的数据块里面存储的都是记录
项,记录项里面描述了【当前目录下有什么文件(即文件名)】,【文件对应的
Inode编号】,【记录长度】,【文件类型】,目录下的每一个子文件都对应着
一个目录项.
当我们vim打开一个文件目录的时候,里面显示的是这个目录下的文件名.
强调文件记录项包括的内容:
1.文件名
2.Inode编号
3.记录长度
4.文件类型
注意:每个文件的记录项没有一定要等长(文件名有长有短),有记录长度这个标签来记录这个记录项的长度,
记录项中的Inode编号是等长的.
假设/home目录下有一个hello文件,那么vim 打开hello的一个寻址过程是怎样的?
1.找到home数据块;
2.拿hello这个文件名与home目录对应的Inode数据块里面的每一条记录项做比对,
找到Inode编号;
3.在InodeTable中根据Inode编号找到对应的Inode,从而完成对应的寻址.
假设有一个文件hello的绝对路径是/home/muten/hello,又是如何找到的呢?
再问,/home目录怎么找到?
有一个规定,根目录/必须放在inode为2的inode上,这是一个规定.
**********
(我的x86-64咋不是2??但是我的Federo是2,应该和文件所选择的文件系统有关系,需要研究一下).
7.ext2文件系统的场景缺陷
1.假设有一个100G的硬盘,格式化成ext2,然后100G里存了一部电影是99.9G,
数据块几乎被占满了,这样会造成inode节点的浪费,这些inode也没法申请
数据块;
2.假设有很多很小的文件,一个文件也就百十来个字节,很快,inode被耗没了,
然后剩下大量的数据块.
所以您在装盘的时候,到底想要数据块多一点还是inode多一些呢,有一个平衡
的算法(这个是什么算法呢?)
如果您在工作中需要设计文件系统,那么您就需要考虑到底该如何分配数据块和
inode.