linux中ext3/4文件系统探索

来源:互联网 发布:阿里云技术架构 编辑:程序博客网 时间:2024/05/22 06:54

前言

       前段时间做linux虚拟化相关的项目,需要实现一个功能,通过linuxExt3\4文件系统中文件的inode号,计算出该文件在linux文件系统的磁盘块号(blocks)以及扇区号(sectors),基本上算是对linux的EXT文件系统有了较深的理解。这样的一个工作,花费了我很长的时间,网上只是关于文件系统的资料比较多,但牵扯到具体的计算,基本上没有资料。因此,我想在这里,把自己前一段时间的工作成果分享出来,或许能给以后在这方面研究的朋友们一些帮助。

文件inode号

       在介绍EXT文件系统之前,我想先对文件的inode号进行一下说明。

       文件存储在硬盘上,硬盘的最小存储单位叫做扇区(sector)。每个扇区的大小不一,常见512KB。操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个"块"(block)。这种由多个扇区组成的"块",是文件存取的最小单位。"块"的大小,最常见的是4KB,即连续八个 sector组成一个 block。文件数据就存放在磁盘块中,inode作为文件的元信息,存储则文件创建者,创建日期,大小,读写权限等。每个文件对应一个唯一inode号。

       每个inode节点的大小,一般是128字节或256字节。inode节点的总数,在格式化时就给定,一般是每1KB或每2KB就设置一个inode。假定在一块1GB的硬盘中,每个inode节点的大小为128字节,每1KB就设置一个inode,那么inode table的大小就会达到128MB,占整块硬盘的12.8%。

EXT文件系统结构

       EXT文件系统的结构如上图所示,首先第一块是启动块——Boot Block,这个里面基本上为0值。
接下来就是一个紧挨着另外一个的块组——Block group(上文提到的块,多个块组成的块组)。每个块组都是相互独立的存储着信息。从图中可以看出,每个块组都会包含下列信息(EXT4稍微有改动,稍后提及)。

  • 一个文件系统超级块的拷贝(占用1块)
  • 一个文件系统组描述符的拷贝(占用n块)
  • 一个数据块位图(占用1块)
  • 一个索引节点位图(占用1块)
  • 一个索引节表(占用n块)
  • 一个大数据块(占用n块)

       由上可知,超级块以及块组描述符内容一样,且只有块组0中所包含的超级块和组描述符才有内核使用,即使这样也会拷贝到所有的块组中,如果出现数据损坏,并且0块组的主超级块和主描述符变为无效,那么系统管理员就可以命令e2fsck引用存放在摸个块组(除了第一个块组)中的超级块和组描述符的旧拷贝(ext4 考虑到在每个块组中都备份有点多余,尤其是组描述符表所以就仅在块号以 3 , 5 , 7 为幂的块组上进行备份。)。那么有多少块组呢?这将取决于文件系统分区的大小和块的大小。

文件系统信息查看

       在深入到文件系统的数据结构之前,我想先介绍文件系统的查看工具dumpe2fs。

dumpe2fs /dev/sda1Filesystem volume name:   &lt;none&gt;Last mounted on:  / Filesystem UUID:  90dcc170-957c-41c6-a0ba-2c3d045fc481Filesystem magic number:  0xEF53Filesystem revision #:1 (dynamic)Filesystem flags: signed_directory_hash Default mount options:user_xattr aclFilesystem state: clean Errors behavior:  ContinueFilesystem OS type:   Linux Inode count:  30334976Block count:  121309952Reserved block count: 6065497Free blocks:  85495976Free inodes:  30080455First block:  0 Block size:   4096  Fragment size:4096  Reserved GDT blocks:  995   Blocks per group: 32768 Fragments per group:  32768 Inodes per group: 8192  Inode blocks per group:   512   Flex block group size:16Filesystem created:   Thu Mar 31 02:34:34 2016Last mount time:  Wed Aug 24 10:24:20 2016Last write time:  Wed Aug 24 10:24:20 2016Mount count:  70Maximum mount count:  -1Last checked: Thu Mar 31 02:34:34 2016Reserved blocks gid:  0 (group root) First inode:  11Inode size:   256Required extra isize: 28Desired extra isize:  28Journal inode:8Journal backup:   inode blocksJournal features: journal_incompat_revokeJournal size: 128MJournal length:   32768Journal sequence: 0x0001117aJournal start:1Group 0: (Blocks 0-32767) [ITABLE_ZEROED]  Checksum 0x9d44, unused inodes 8178  Primary superblock at 0, Group descriptors at 1-29  Reserved GDT blocks at 30-1024  Block bitmap at 1025 (+1025), Inode bitmap at 1041 (+1041)  Inode table at 1057-1568 (+1057)  23485 free blocks, 8179 free inodes, 2 directories, 8178 unused inodes  Free blocks: 9283-32767  Free inodes: 14-8192Group 1: (Blocks 32768-65535) [INODE_UNINIT, ITABLE_ZEROED]  Checksum 0x9df4, unused inodes 8192  Backup superblock at 32768, Group descriptors at 32769-32797  Reserved GDT blocks at 32798-33792  Block bitmap at 1026 (bg #0 + 1026), Inode bitmap at 1042 (bg #0 + 1042)  Inode table at 1569-2080 (bg #0 + 1569)  959 free blocks, 8192 free inodes, 0 directories, 8192 unused inodes  Free blocks: 34762-34783, 34810-34815, 56835-56863, 56881-57023, 57047-57055, 57081-57087, 57259-57343, 62126-62431, 62452-62687, 62705-62719, 62911, 62929-62943, 62961-62975, 63281-63295, 63313-63327, 63345-63359, 63463-63487  Free inodes: 8193-16384`</pre>&#160; &#160; &#160; &#160;以上是使用dumpe2fs对本地磁盘的部分查看结果,会列出所有的块组信息,现在只显示前两个块组。这里有一个小细节,我们查看这些块组信息时每次都要重新使用dumpe2fs工具,而且想要查看后面的块组,还要一点一点翻着看,这时我们就可以借助linux的数据流重定向功能,把这些信息定位到一个文件中去。 <pre>`dumpe2fs /dev/sda1 &gt; dump`</pre>&#160; &#160; &#160; &#160;这样我们的磁盘sda1的基本信息就存储在了dump文件中,可以随时快速查看。  &#160; &#160; &#160; &#160;从上面的信息中可以看出文件inode总数,磁盘块大小(block size),每个块组磁盘块数(block per group),每个块组inode数,inode大小(inode size)。## 超级块&#160; &#160; &#160; &#160;超级块存放在一个ext_super_block的结构中。在内核结构中,使用了__le16、__le32、__be16、__be32的数据类型,前两种类型分别表示字或双字的“小尾”即小端序的排序方式(低阶字节在高位地址),而后两种类型分别表示字或双字的“大尾”即大端序的排序方式(高阶字节在高位地址)。接下来介绍一下超级块的字段,这里我们引用《深入理解linux内核》这本书中的数据结构截图。![](http://i.imgur.com/Q2s4lUR.png) ![](http://i.imgur.com/Y1LRhnm.png)&#160; &#160; &#160; &#160;在我们对超级块的数据结构有些了解之后,我们开始对磁盘进行字节方面的探索,依旧是使用linux的数据流重定向功能,把文件系统的字节信息输入的指定的文件中去,以便之后查看。<pre>`od -tx1 -Ax -N2000 /dev/sda1 &gt; blockinfo

       上述代码的意思就是查看/dev/sda1磁盘块的2000字节的信息,并输出到文件blockinfo中。在这里我的磁盘信息如下图:

       可以看出来,这里的数字全是以16进制进行的。跟我们之前分析的文件系统磁盘结构一样,刚开始有1000字节的空白,代表的是启动块。从第0X400(即第1000字节)开始,就到了第一个块组的范围,第一个块组的头部是超级块,也就是说,从0X400开始,就是第一个超级块。前四个字节是01cee000=30334976(之前说过的小端序),这四个字节代表的是inode count,inode的个数,可以看出来,与刚才在块组信息里面的inode个数一致;接下来四个字节是block count总块数,0X073b0b00=121309952,同样和之前的块组信息里面的总块数一致。这里我只是给大家提供一种方法,如何找到文件系统的数据结构中的各个字段,下面还有很多,朋友们可以自行验证找到所有字段来获取想要得到的信息。需要注意的是各个字段的长度。

块组描述符

       Group Descriptor Tabel 每个块组都有一个专门的数据结构用来描述整个块组的相关信息,即块组描述表,它紧跟在超级块后面的一个块,其每一项称为组描述符,是一个大小为32字节的数据结构。记录组中块位图所在的块号、索引节点位图所在的块号、索引节点表的第一个块号等。

       块组描述符的数据结构如下图:


       还是从之前的块组信息中看到 :Primary superblock at 0, Group descriptors at 1-29,第二块就是快组描述符的位置了。由于每个块大小为4096字节,所以在0x1000开始为第二块,即快组描述符的开始。

       这样我们可以对照数据结构,在这些字节码中,找到需要的信息。

其他结构

       Block Bitmap 即此块组中的块位图,记录此组中的哪些块已经被占用,在分配块时使用。

       Inode Bitmap 即此块组中的索引节点位图,记录本组中的哪些索引节点已经被占用。

       Inode Table 即此块组中的索引节点表,每一项是一个文件的索引,即Inode,记录此文件的相关信息,其中本文最为关心的是地41~100字节,记录着文件所占数据库的信息。

       Data Blocks 即此块组中的数据块,可供分配给各个文件使用。


       在这篇文章中说明了如何查找文件系统中的相关信息的数据结构,接下来探讨如何通过inode计算出文件所在的磁盘块号和扇区号。



0 0