深入理解ext4

来源:互联网 发布:java this.getclass 编辑:程序博客网 时间:2024/05/16 05:37

 文件系统是操作系统的一个重要组成部分,也有着举足轻重的地位。本系列文章主要讲述了linux ext4文件系统的一些实现原理。笔者参考了2.6.32.60的内核源代码。在写这篇的文章时,最新的内核已经去到了3.7.9。

ext4是替代ext2/3Linux文件系统。从2.6.28版本开始,被正式认定进入稳定(stable)。本文主要介绍ext4文件系统在硬盘层面上的存储结构及原理。

 

读者对象:对Linux有一定基础,希望了解ext4底层原理,和它与ext2/3系统区别。

 

关键词汇

先回顾几个基本的概念,如果不是特别清楚下面几个概念的话,可以去google一下。

inode:索引节点

superblock:超级块

block:文件系统块

block group:文件系统块组

disk block:磁盘块(512字节)

block device:块设备

VFS:虚拟文件系统

EXT4存储结构

假如把整个超级块比如一本书,那么文件系统的工作就是把要记录的内容,按页码,行段记录在这本书里。这当然也包括书的目录了。我们使用dumpe2fs工具输出:

 

Reserved GDT blocks:      609

Blocks per group:         32768

Fragments per group:      32768

Inodes per group:         8128

Inode blocks per group:   508

Flex block group size:    16

Filesystem created:       Mon May 14 13:30:51 2012

Last mount time:          Sun Jan  6 18:51:16 2013

Last write time:          Sun Jan  6 18:51:16 2013

Mount count:              282

Maximum mount count:      -1

Last checked:             Mon May 14 13:30:51 2012

Check interval:           0 (<none>)

Lifetime writes:          20 GB

Reserved blocks uid:      0 (user root)

Reserved blocks gid:      0 (group root)

First inode:              11

Inode size:               256

Required extra isize:     28

Desired extra isize:      28

Journal inode:            8

 

首先,映入眼帘的是该超级块的相关重要参数,比如inode大小,块组含块数,块组inode数目等等。这些数据是存在ext4_super_blockext4_sb_info这两个结构体中,定义在ext4.h头文件里,它们不是本篇重要讨论的内容。我们只需要知道它们是存放一些超级块信息的结构体即可。

接下来,可以看到ext4硬盘上的存储结构:

Group 0: (Blocks 0-32767) [ITABLE_ZEROED]

  Checksum 0x7cf3, unused inodes 0

  Primary superblock at 0, Group descriptors at 1-2

  Reserved GDT blocks at 3-611

  Block bitmap at 612 (+612), Inode bitmap at 628 (+628)

  Inode table at 644-1151 (+644)

  2720 free blocks, 0 free inodes, 1383 directories

  Free blocks: 8888-8959, 9068, 9071-9135, 9144-9175, 9200-9207, 9213-9214, 9279, 9700-10120, 11823-11964, 12213-12870, 12879-13043, 13139-13254, 18432-19021, 22748-22975, 32549-32767

  Free inodes:

 

这是块组0的情况,它表明块组0由块号为0-3276732768个块组成,超级块基本信息存在块0,块组描述符在块1-2,预留的块组描述符表在块3-611,块位图在块612中,inode位图在块628中,Inode表在块644-1151中,空闲的块有很多,空闲的inode没了。

接下来,我们将重点分析这句废话中每个词的含义

        超级块基本信息:

                  我们在前面已经讲过了。顾名思义,不多解释。

         块组描述符

                  在内核中就是结构体ext4_group_desc,它包括的内容为:块位图块号,inode位图块号,inode表块号,空闲块计数,自由块计数等等。

         预留的块组描述符表

                  为以后要使用所留下来的空间。

         块位图

                  这个就是一个块使用情况记录表。记录哪些块使用,哪些块未使用。它的原理就是对整个块组中0-32767这总共32768个块中作一个映射。根据一个bytes8个位00000000,一个块有4096bytes也就是有4096*8=32768个位,这32768个位刚好对应了块组中32768的块。如果第N个块被使用了则标记第N位为1,否则为0

         inode位图

                  和上面的块位图一样,这个是inode的使用情况记录表。由超级块基本信息可以看到每个块组有8128inode,这里对inode的映射原理和块位图也是一样,只不过         没有用满一个块。

         inode

                  inode表就是具体存放inode信息的地方。在ext4中,inode的大小为256字节(ext2/3中仅有它的一半,128字节),一个块可以存放16inode,由于一个块组有8128          inode,总共需要8128/16=508个块存放inode表。这个值可以在超级块基本信息中的Inode blocks per group中看到。

讲完了这些词的含义,我们对group 0有了初步的了解。那么group 1呢?

Group 1: (Blocks 32768-65535) [ITABLE_ZEROED]

  Checksum 0xbb99, unused inodes 0

  Backup superblock at 32768, Group descriptors at 32769-32770

  Reserved GDT blocks at 32771-33379

  Block bitmap at 613 (+4294935141), Inode bitmap at 629 (+4294935157)

  Inode table at 1152-1659 (+4294935680)

  598 free blocks, 0 free inodes, 648 directories

  Free blocks: 33424-33439, 33442-33443, 33564-33627, 33644-33647, 33652-33663, 33725-33871, 33878-33931, 33934-33973, 33976-33983, 34046-34047, 34176-34303, 36008, 36015, 36019, 36412, 40299-40415

  Free inodes:

 

我们看到group 1 中,primary superblock 变为了backup superblock,由于超级块基本信息对于文件系统至关重要,为了系统的健壮性,ext文件系统在每个块组中都进行了备份。ext4考虑到在每个块组中都备份有点多余,尤其是组描述符表所以就仅在块号以357为幂的块组上进行备份。

用个表格表示超级块中块组的结构:

ext4 超级块

块组描述符

Reserved GDT Blocks

数据块位图

Inode位图

inode 表

数据块

1 block

若干blocks

若干 blocks

1 block

1 block

若干

好多好多块

                                                                                                                                                    

inode

Purpose

0

Doesn't exist; there is no inode 0.

1

List of defective blocks.

2

Root directory.

3

ACL index.

4

ACL data.

5

Boot loader.

6

Undelete directory.

7

Reserved group descriptors inode.

8

Journal inode.

11

First non-reserved inode. Usually this is the lost+found directory.

 

块寻址

ext4的块寻址已经改为48位。这种设计改动是为了支持更大的文件系统大小。EXT4使用了区段(extents)这个概念,取代了过去早期UNIX文件系统中(ext2/3)中低效的非直接块映射机制。区段和NTFS上的cluster有点类似,它们都是选定了一个特定的块地址并把数个块组合一个区间。一个文件如果是碎片化的,那么就意味它着拥有多个区段,ext4会尽它自己的努力保持文件连续。

 

这种新的块寻址策略导致了先前工具的大部分问题。举个列子:

 

[root@localhost Desktop]# stat math.c

  File: `math.c'

  Size: 1477               Blocks: 8          IO Block: 4096   regular file

Device: fd00h/64768d     Inode:420402      Links: 1

Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)

Access: 2013-01-05 15:07:11.815541582 +0800

Modify: 2012-08-20 13:40:02.496797954 +0800

Change: 2012-12-30 11:28:54.751357610 +0800

 

 

由上面得到文件math.cInode号为420402

[root@localhost Desktop]# istat /dev/mapper/VolGroup-lv_root 420402

inode: 420402

Allocated

Group: 51

Generation Id: 1062005310

uid / gid: 0 / 0

mode: rrw-r--r--

Flags:

size: 1477

num of links: 1

 

Inode Times:

Accessed:         2013-01-05 15:07:11 (CST)

File Modified:   2012-08-20 13:40:02 (CST)

Inode Modified:        2012-12-30 11:28:54 (CST)

 

Direct Blocks:

127754

 

 

由上面的命令结果可以看到,Inode位于节点上块组51上,留意上面命令最下面有Direct Blocks这一行,这一行写着127754。在ext4的文件系统中,由于direct block映射的块寻址机制被取代,而采取的是extent区段树的块寻址。这个地方的值基本上是无效的。127754这个值十六进制表示为0x1f30a,我们在稍后的讨论这个值的来源。

我们知道了math.c这个文件的inode号码为420402,那么怎样知道它数据块是拿一个呢?

由前面的内容我们知道,每个块可以存16inode,那么420402则在第420402/16=26275.125个块中,也就是位于第26275个块的第二个位置。每个块组有508inode块,那么26725/508=51.72可以得知,位于块组51号之中,这个值可以在我们之前istat中可以验证。

那么具体是51块组中的哪个块呢?我们先确定这个inode块是在块组中的第几个块。因为每个块组有508inode块,51块组前面共有51*508=25908个块。第26275inode块在51块组中排在26275-25908=367的位置。查看51块组的描述:

 

Group 51: (Blocks 1671168-1703935) [ITABLE_ZEROED]

  Checksum 0x5ffd, unused inodes 0

  Block bitmap at 1572867 (+4294868995), Inode bitmap at 1572883 (+4294869011)

  Inode table at 1574420-1574927 (+4294870548)

  34 free blocks, 1 free inodes, 541 directories

  Free blocks: 1672899, 1673339, 1673344, 1674035, 1674054, 1674062, 1674077, 16

74334, 1674353-1674354, 1674423, 1675259, 1675754-1675755, 1675763, 1675860-1675

861, 1675867, 1675979, 1676183, 1676287, 1676367, 1676507, 1676526-1676527, 1676

567, 1676711, 1676743, 1676924-1676925, 1676934, 1691649, 1691658, 1691707

  Free inodes: 422608

 

看到inode的起点位于1574420,由此,我们想要找的inode信息的块就存在于1574787inode块中的第二个。

可以使用blkcat查看1574787的内容,我们用vi切换到16进制模式打开如下:

 

0000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000080: 1c00 0000 4430 c1a7 c8f1 733d fc8a 6cb1  ....D0....s=..l.

0000090: 58a8 b04f 04a0 6538 0000 0000 0000 02ea  X..O..e8........

00000a0: 0706 3c00 0000 0000 2200 0000 0000 0000  ..<.....".......

00000b0: 7365 6c69 6e75 7800 0000 0000 0000 0000  selinux.........

00000c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

00000d0: 0000 0000 0000 0000 0000 0000 7379 7374  ............syst

00000e0: 656d 5f75 3a6f 626a 6563 745f 723a 6164  em_u:object_r:ad

00000f0: 6d69 6e5f 686f 6d65 5f74 3a73 3000 0000  min_home_t:s0...

0000100: a481 0000 c505 0000 1fd1 e750 f6b4 df50  ...........P...P

0000110: b2cd 3150 0000 0000 0000 0100 0800 0000  ..1P............

0000120: 0000 0800 0100 0000 0af3 0100 0400 0000  ................

0000130: 0000 0000 0000 0000 0100 0000 d64a 1c00  .............J..

0000140: 0000 0000 0000 0000 0000 0000 0000 0000  ................

 

 我们知道inodesize大小为256字节,那么第二个inode的起始位置也就是256=0x100处。

这个时候,我们看下inode的数据结构:

 

位置

名称

描述

0x0

__le16

i_mode

文件模式

0x2

__le16

i_uid

所有者UID.

0x4

__le32

i_size_lo

文件大小.

0x8

__le32

i_atime

读取时间.

0xC

__le32

i_ctime

Inode修改时间

0x10

__le32

i_mtime

文件修改时间.

0x14

__le32

i_dtime

删除时间

0x18

__le16

i_gid

GID.

0x1A

__le16

i_links_count

硬链接计数.

0x1C

__le32

i_blocks_lo

块计数(512字节)

0x20

__le32

i_flags

文件标识(ext4使用extent需要标记0x80000)

...

0x28

__le32

i_block[EXT4_N_BLOCKS=15]

块映射(ext2/3)或区段树(ext4)

...

 

我们按照表中的结构,对照上面的块码:

 

偏移

大小

名称

描述

0x0

0x81a4

i_mode

文件模式

0x2

0x0000

i_uid

所有者UID.

0x4

0x0000 05c5

i_size_lo

文件大小.

0x8

0x50e7 d11f

i_atime

读取时间.

0xC

0x50df b4f6

i_ctime

Inode修改时间

0x10

0x5031 b2cd

i_mtime

文件修改时间.

0x14

0x0000 0000

i_dtime

删除时间

0x18

0x0000

i_gid

GID.

0x1A

0x0001

i_links_count

硬链接计数.

0x1C

0x0000 0008

i_blocks_lo

块计数(512字节)

0x20

0x0080 0000

i_flags

文件标识(ext4使用extent需要标记0x80000)

...

0x28

 ...

i_block[EXT4_N_BLOCKS=15]

块映射(ext2/3)或区段树(ext4)

...

 

细心的同学会发现大小的顺序是倒过来的,这是因为__lexx类型,lelittle endian小端开始的缩写,意思就是从小到大的顺序。我们看到文件的大小为0x5c5=1477,这说明我们找的正是math.cinode

 

因为ext4 使用区段去代替了块映射去查找文件的内容。从40-9960个字节过去是用作块映射的,如今用作存储extent信息。extent结构体有12字节的大小,反应快的同学马上会说,那么一个inode可以存放最多5extent。然而这是不对的,因为前12个字节(40-51)被段头(extent header)所占据,所以,一个inode中的区段数最多只能是4

 

现在,我们重点开始讲区段树(extent tree)

ext4中,区段树取代了旧式的逻辑块映射。这是因为在老的模式中,分配连续的1000个块需要映射这1000个块的地址。但使用了区段,只需要映射一个区段并把区段的长度标记为1000ee_len=1000)。如果起用了flex_bg的功能,一个区段可以分配一个很大的文件,这降低了元数据的大小,也提高了硬盘的效率。inode必须使用区段标记0x80000开启区段的功能。

区段的结构是树形的。每个树节点的起始为:struct ext4_extent_header(这是一个结构体,我们接下来会给大家描述它的内容)。如果一个节点是树的内部节点(即eh.eh_depth>0),那么eh.eh_entries的指针将指向struct ext4_extent_idx;每个这些索引都指向一个块,块中包含更多的区段树中的节点。如果节点是树的叶子节点(eh.eh_depth=0),那么eh.eh_entries的指针将指向struct ext4_extent;这些结构体中指向文件的数据块。区段树的根节点存在inode.i_block,也就是我们在前面讨论的从40-99的那60个字节里。

 

说了这么多,我们还是赶紧看看extent的结构吧;

 

首先出场的是段头(extent header)

 

偏移

大小

名称

描述

0x0

__le16

eh_magic

幻数magic number, 0xF30A.

0x2

__le16

eh_entries

区段数.

0x4

__le16

eh_max

最大的区段数.

0x6

__le16

eh_depth

段节点在段树中的深度。0则表示为叶子节点,指向数据块;否则指向其它段节点。

0x8

__le32

eh_generation

暂不讨论

 

同样的,对照我们的实际数据看看

 

偏移

大小

名称

描述

0x0

0xf30a

eh_magic

幻数magic number, 0xF30A.

0x2

0x0001

eh_entries

区段数.

0x4

0x0004

eh_max

最大的区段数.

0x6

0x0000

eh_depth

段节点在段树中的深度。0则表示为叶子节点,指向数据块;否则指向其它段节点。

0x8

0x0000 0000

eh_generation

暂不讨论

 

 

接下来我们先看struct ext4_extent_idx,这个结构在前面我们有提到过,用于extent树的内部节点。

 

偏移

大小

名称

描述

0x0

__le32

ei_block

逻辑块号.

0x4

__le32

ei_leaf_lo

区段树中下一层的区段节点块地址(低32位),可以指向叶子节点或者内部节点。

0x8

__le16

ei_leaf_hi

上一栏的高16位地址

0xA

__u16

ei_unused

未使用

 

我们接着看struct ext4_extent,叶子节点的结构体

 

偏移

大小

名称

描述

0x0

__le32

ee_block

此区段的第一个块号,起始块号

0x4

__le16

ee_len

区段内包含的块数.

0x6

__le16

ee_start_hi

此区段所指向的块号(高16位)

0x8

__le32

ee_start_lo

此区段所指向的块号(低32位)

 

对照我们的实际数据看看

 

偏移

大小

名称

描述

0x0

0x0000 0000

ee_block

此区段的第一个块号,起始块号

0x4

0x0001

ee_len

区段内包含的块数.

0x6

0x0000

ee_start_hi

此区段所指向的块号(高16位)

0x8

0x001c 4ad6

ee_start_lo

此区段所指向的块号(低32位)

 

由上表可以看到,因为我们的文件较小,这里作为叶子节点直接指向了文件数据块。数据块号为0x001c4ad6=1854166。我们使用命令查看块中的内容:

[root@localhost Desktop]# blkcat /dev/mapper/VolGroup-lv_root 1854166

#include <stdlib.h>

#include <math.h>

...

 

呵呵,可以看到,这就是我们的math.c文件。

 

思考:

请读者找一个大于4k的文件,看看能不能找到它的数据块。

 

删除文件

执行rm后删除文件,数据块并没有被清除,inode被释放,有下面3项会改变: 1. 文件大小被置为0

    2. 段头中的区段值被设为0

    3. 区段被清空

清空了区段意味着我们会失去文件起始物理块的地址和区段的长度。也就是说,在inode中已经不存在元数据可以帮我们恢复文件。这种行为和ext3回收inode时清除inode中的块指针很相似。这样就意味着我们只能靠传统的file-carving去恢复文件。

还记得在上一章中,我们提到过的结构体struct ext4_extent_idx。这个结构体表示在extent tree中的节点。 我们在前面的章节已经阐述过,ext4使用extent取代了传统的block映射方式。我们的案例中只展示了只有一个extent的情况。本篇文章将介绍多个extent情况下的具体细节。

 

在本文中,我们选取了文件/var/log/messages,它是系统日志的记录文件,由于它的角色特殊,时间长了会造成给很多的碎片。我们还是先看看他的inode,方法和(一)中描述的一致,在此不重复了。

 

 

0000c00: 8081 0000 d036 0000 814b ee50 7f4b ee50  .....6...K.P.K.P

0000c10: 7f4b ee50 0000 0000 0000 0100 2000 0000  .K.P........ ...

0000c20: 0000 0800 0100 00000af30400 0400 0000  ................

0000c30: 0000 0000 0000 0000 0100 0000 58c2 0b00  ............X...

0000c40: 0100 0000 0100 0000 e599 1b00 0200 0000  ................

0000c50: 0100 0000 41e6 2f00 0300 0000 0100 0000  ....A./.........

0000c60: b878 1c00 275f ea72 0000 0000 0000 0000  .x..'_.r........

0000c70: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000c80: 1c00 0000 c018 94d1 c018 94d1 c0e5 ea86  ................

0000c90: 9bea e850 d0a4 fcb4 0000 0000 0000 02ea  ...P............

0000ca0: 0706 4000 0000 0000 1f00 0000 0000 0000  ..@.............

0000cb0: 7365 6c69 6e75 7800 0000 0000 0000 0000  selinux.........

0000cc0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000cd0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000ce0: 7379 7374 656d 5f75 3a6f 626a 6563 745f  system_u:object_

0000cf0: 723a 7661 725f 6c6f 675f 743a 7330 0000  r:var_log_t:s0..

 

 

0x0af3开始,这是extent header起始的标记,我们还是像(一)那样,对照着表看

 

偏移

大小

名称

描述

0x0

0xf30a

eh_magic

幻数magic number, 0xF30A.

0x2

0x0004

eh_entries

区段数.

0x4

0x0004

eh_max

最大的区段数.

0x6

0x0000

eh_depth

段节点在段数中的深度。0则表示为叶子节点,指向数据块;否则指向其它段节点。

0x8

0x0000

eh_generation

暂不讨论

 

因为这里看到depth0,说明extent中指向的是数据块。在extent header中接下来的将extent是我们把接下来的数据对应到它的表中

 

偏移

大小

名称

描述

0x0

0x0000 0000

ee_block

此区段的第一个块号,起始块号

0x4

0x0001

ee_len

区段内包含的块数.

0x6

0x0000

ee_start_hi

此区段所指向的块号(高16位)

0x8

0x000b c258

ee_start_lo

此区段所指向的块号(低32位)

 

接下来的12个字节

 

偏移

大小

名称

描述

0x0

0x0000 0001

ee_block

此区段的第一个块号,起始块号

0x4

0x0001

ee_len

区段内包含的块数.

0x6

0x0000

ee_start_hi

此区段所指向的块号(高16位)

0x8

0x001b 99e5

ee_start_lo

此区段所指向的块号(低32位)

 

再接下来的12个字节

 

偏移

大小

名称

描述

0x0

0x0000 0002

ee_block

此区段的第一个块号,起始块号

0x4

0x0001

ee_len

区段内包含的块数.

0x6

0x0000

ee_start_hi

此区段所指向的块号(高16位)

0x8

0x00f2 e641

ee_start_lo

此区段所指向的块号(低32位)

 

最后的12个字节 

偏移

大小

名称

描述

0x0

0x0000 0003

ee_block

此区段的第一个块号,起始块号

0x4

0x0001

ee_len

区段内包含的块数.

0x6

0x0000

ee_start_hi

此区段所指向的块号(高16位)

0x8

0x001c 78b8

ee_start_lo

此区段所指向的块号(低32位)

 

可以通过使用blkcat看到4个块刚好凑成了messages文件,疑心重的同学可以把4个块拼成一个文件,用md5sum比较一下。这里我们并没有想看到extent中的内部节点情况。没关系,我们系统日志文件时会随着时间增长。正在笔者撰写此文时,messages已经变大了,并且超过了16k的大小,也就是超出了4个块。这时候我们看看messagesinode信息,方法不重复了。

 

0000c00: 8081 0000 4f51 0000 eb84 ef50 ea84 ef50  ....OQ.....P...P

0000c10: ea84 ef50 0000 0000 0000 0100 3800 0000  ...P........8...

0000c20: 0000 0800 0100 00000af3 0100 0400 0100  ................

0000c30: 0000 0000 0000 0000 7c03 1c00 0000 0b00  ........|.......

0000c40: 0100 0000 0100 0000 e599 1b00 0200 0000  ................

0000c50: 0100 0000 41e6 2f00 0300 0000 0100 0000  ....A./.........

0000c60: b878 1c00 275f ea72 0000 0000 0000 0000  .x..'_.r........

0000c70: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000c80: 1c00 0000 c80e c097 c80e c097 accd 3948  ..............9H

0000c90: 9bea e850 d0a4 fcb4 0000 0000 0000 02ea  ...P............

0000ca0: 0706 4000 0000 0000 1f00 0000 0000 0000  ..@.............

0000cb0: 7365 6c69 6e75 7800 0000 0000 0000 0000  selinux.........

0000cc0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000cd0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000ce0: 7379 7374 656d 5f75 3a6f 626a 6563 745f  system_u:object_

0000cf0: 723a 7661 725f 6c6f 675f 743a 7330 0000  r:var_log_t:s0..

 

 

经过一段时间的练习,同学们应该不需要对照表来识辨这些16进制码的含义了,如果不熟练的话,可以回过头多看几遍。我们看到这个inode较之前有了变化。extent的区段数变成了1,区段树的深度变成了1。区段树深度为1,这说明非叶子节点。

 

偏移

大小

名称

描述

0x0

0x0000 0000

ei_block

逻辑块号.

0x4

0x001c 037c

ei_leaf_lo

区段树中下一层的区段节点块地址(低32位),可以指向叶子节点或者内部节点。

0x8

0x0000

ei_leaf_hi

上一栏的高16位地址

0xA

0x000b

ei_unused

未使用

 

使用blkcat查看文件系统块1835900的内容,

 

0000000: 0af3 0e00 5401 0000 0000 0000 0000 0000  ....T...........

0000010: 0100 0000 58c2 0b00 0100 0000 0100 0000  ....X...........

0000020: e599 1b00 0200 0000 0100 0000 41e6 2f00  ............A./.

0000030: 0300 0000 0100 0000 b878 1c00 0400 0000  .........x......

0000040: 0100 0000 2d8b 1b00 0500 0000 0100 0000  ....-...........

0000050: 9a79 1c00 0600 0000 0100 0000 0d82 1b00  .y..............

0000060: 0700 0000 0100 0000 1182 1b00 0800 0000  ................

0000070: 0100 0000 1382 1b00 0900 0000 0100 0000  ................

0000080: 1682 1b00 0a00 0000 0100 0000 1882 1b00  ................

0000090: 0b00 0000 0300 0000 034e 1c00 0e00 0000  .........N......

00000a0: 0200 0000 074e 1c00 1000 0000 0400 0000  .....N..........

00000b0: e082 0c00 0000 0000 0000 0000 0000 0000  ................

 

 

从上面的数据,我们可以看到有0x000e个区段,也就是在extent header后有14extent或者extent ixd的结构体。接着看到extent最大数为0x0154=340,这个数字是怎么来的呢?我们知道在一个inode里面,这个值是4,那是因为('extent space' - 'extent header size') / 'extent size'  (60-12)/12=4,那么在这里也一样,只不过60这里要变为4096,因为我们不在inode中,而是在一个块中,即4096-12=4084,4084/12340.333,最后还剩4个字节浪费了。再接着,是树的深度,也就是0x0000表明是叶子节点。那么我们知道,这个文件由着14block的块组成。有兴趣的同学可以自己把文件dump出来拼一下。呵呵。

0 0