首页 > *nix技术, 文件系统 > Xfs文件系统磁盘布局之十一:inode节点结构

Xfs文件系统磁盘布局之十一:inode节点结构

2012年1月5日 发表评论 阅读评论 3,014 次浏览

Linux下一切皆文件,所以文件的类型有很多,比如普通文件、目录文件、软链接文件、设备文件等等,ls -l命令显示的文件列表的第一个字符表示该文件的类型:b:块设备、c:字符设备、d:目录、p:命名管道、f:普通文件、l:软连接、s:socket,可以利用find的命令查找系统上指定类型的文件:

[root@localhost xfsprogs]# ls -l
total 1736
-rw-r--r-- 1 root root 231387 Jan  5 14:09 aclocal.m4
drwxr-xr-x 2 root root   4096 Jan  5 14:09 autom4te.cache
-rwxr-xr-x 1 root root  42037 Jan  5 14:09 config.guess
...
[root@localhost xfsprogs]# ls -l /dev/ttyS0
crw-rw---- 1 root uucp 4, 64 Jan  5 10:10 /dev/ttyS0
[root@localhost xfsprogs]# ls -l /dev/sda1 
brw-r----- 1 root disk 8, 1 Jan  5 10:11 /dev/sda1
[root@localhost xfsprogs]# ls -l /dev/ramdisk 
lrwxrwxrwx 1 root root 4 Jan  5 10:11 /dev/ramdisk -> ram0
[root@localhost xfsprogs]# ls /dev/initctl  -l
prw------- 1 root root 0 Jan  5 10:11 /dev/initctl
[root@localhost xfsprogs]# find / -type s
/tmp/.font-unix/fs7100
/dev/gpmctl
/dev/log
^C
[root@localhost xfsprogs]# ls /dev/log -l
srw-rw-rw- 1 root root 0 Jan  5 10:12 /dev/log

Linux任何一个文件,除了本身的固定属性(比如文件类型、访问权限、所有者、最后访问时间、最后修改时间等),还有文件数据(后面特称之为文件内容)与其它扩展属性(比如用户自定义的属性),与此一一对应,inode结构也就被分成了三部分,即inode核心数据、文件内容、扩展属性(文件内容和扩展属性之间为什么是虚线后面会讲到,另外为了后续文章的叙述清楚,下图中的inode核心数据、文件内容和扩展属性分别所占的磁盘空间就分别以inode core、data fork、attribute fork代称,即一说到inode core,那就是指图中斜网格填充的这一块磁盘空间区域,其它类此。):

其中inode核心数据由结构体xfs_dinode描述,有几个字段比较重要,它们决定了后面数据的安放。第一个重要字段是di_mode,这个字段记录该文件的类型和权限,而不同类型的文件存放的据内容和格式很明显是不一样的,比如目录文件和普通文件。第二个重要字段是di_format,这个字段决定了文件内容的存放方式。这个字段的取值定义在枚举体xfs_dinode_fmt内,其中“uuid”目前尚未用到,“dev”表示本inode关联的是一个字符或块设备,“local”表示文件内容直接存放在本inode所在的这个block块内,“extents”表示文件内容存放在其他block块内,而这些block的块号被以数组的形式组织起来存放在本inode所在的block块内,“btree”表示文件内容存放在其他block块内,而这些block的块号被以B+tree的形式组织,并且该B+tree的根节点存放在本inode所在的block块内。可以看到“local”->“extents”->“btree”的形式可以存放由少到多的文件内容。
文件内容(根据前面几句话的描述,文件内容不一定就是文件的实际数据,也可能是其他存放实际文件内容的block块号或B+tree根节点等,这里统一认为是文件内容,当然,标准说法为Data Fork)存放的起始地址紧跟在inode核心数据之后,由于结构体xfs_dinode占100个字节,所以文件内容存放的起始地址也就是100。
看实际数据验证我们的分析:

[root@localhost loop]# ls
xfs  xfs.256  xfs.256.new  xfs.img  xfs.img.256  xfs.img.256.new
[root@localhost loop]# dd if=/dev/zero of=inode.256.img bs=512 count=524288
524288+0 records in
524288+0 records out
268435456 bytes (268 MB) copied, 9.77917 s, 27.4 MB/s
[root@localhost loop]# losetup -d /dev/loop0
[root@localhost loop]# losetup /dev/loop0 inode.256.img 
[root@localhost loop]# mkfs.xfs /dev/loop0
meta-data=/dev/loop0             isize=256    agcount=4, agsize=16384 blks
         =                       sectsz=512   attr=2, projid32bit=0
data     =                       bsize=4096   blocks=65536, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0
log      =internal log           bsize=4096   blocks=1200, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
[root@localhost loop]# ls
inode.256.img  xfs  xfs.256  xfs.256.new  xfs.img  xfs.img.256  xfs.img.256.new
[root@localhost loop]# mkdir inode.256
[root@localhost loop]# mount /dev/loop0 inode.256
[root@localhost loop]# cd !$
cd inode.256
[root@localhost inode.256]# echo "123456789" > lenky.xfs
[root@localhost inode.256]# cat lenky.xfs 
123456789
[root@localhost inode.256]# ls -lai
total 8
   128 drwxr-xr-x. 2 root root   22 Dec 31 09:18 .
524142 drwxr-xr-x. 6 root root 4096 Dec 31 09:17 ..
   131 -rw-r--r--. 1 root root   10 Dec 31 09:18 lenky.xfs
[root@localhost inode.256]# cd ..
[root@localhost loop]# umount inode.256
[root@localhost loop]# /home/lenky/xfs/xfsprogs/db/xfs_db /dev/loop0
xfs_db> inode 128
xfs_db> p
core.magic = 0x494e
core.mode = 040755
core.version = 2
core.format = 1 (local)
core.nlinkv2 = 2
core.onlink = 0
core.projid_lo = 0
core.projid_hi = 0
core.uid = 0
core.gid = 0
core.flushiter = 1
core.atime.sec = Sat Dec 31 09:18:03 2011
core.atime.nsec = 812159818
core.mtime.sec = Sat Dec 31 09:18:01 2011
core.mtime.nsec = 473154327
core.ctime.sec = Sat Dec 31 09:18:01 2011
core.ctime.nsec = 473154327
core.size = 22
core.nblocks = 0
core.extsize = 0
core.nextents = 0
core.naextents = 0
core.forkoff = 0
core.aformat = 2 (extents)
core.dmevmask = 0
core.dmstate = 0
core.newrtbm = 0
core.prealloc = 0
core.realtime = 0
core.immutable = 0
core.append = 0
core.sync = 0
core.noatime = 0
core.nodump = 0
core.rtinherit = 0
core.projinherit = 0
core.nosymlinks = 0
core.extsz = 0
core.extszinherit = 0
core.nodefrag = 0
core.filestream = 0
core.gen = 0
next_unlinked = null
u.sfdir2.hdr.count = 1
u.sfdir2.hdr.i8count = 0
u.sfdir2.hdr.parent.i4 = 128
u.sfdir2.list[0].namelen = 9
u.sfdir2.list[0].offset = 0x30
u.sfdir2.list[0].name = "lenky.xfs"
u.sfdir2.list[0].inumber.i4 = 131
xfs_db> inode 131
xfs_db> p
core.magic = 0x494e
core.mode = 0100644
core.version = 2
core.format = 2 (extents)
core.nlinkv2 = 1
core.onlink = 0
core.projid_lo = 0
core.projid_hi = 0
core.uid = 0
core.gid = 0
core.flushiter = 2
core.atime.sec = Sat Dec 31 09:18:04 2011
core.atime.nsec = 300159942
core.mtime.sec = Sat Dec 31 09:18:01 2011
core.mtime.nsec = 474154430
core.ctime.sec = Sat Dec 31 09:18:01 2011
core.ctime.nsec = 474154430
core.size = 10
core.nblocks = 1
core.extsize = 0
core.nextents = 1
core.naextents = 0
core.forkoff = 13
core.aformat = 1 (local)
core.dmevmask = 0
core.dmstate = 0
core.newrtbm = 0
core.prealloc = 0
core.realtime = 0
core.immutable = 0
core.append = 0
core.sync = 0
core.noatime = 0
core.nodump = 0
core.rtinherit = 0
core.projinherit = 0
core.nosymlinks = 0
core.extsz = 0
core.extszinherit = 0
core.nodefrag = 0
core.filestream = 0
core.gen = 0
next_unlinked = null
u.bmx[0] = [startoff,startblock,blockcount,extentflag] 0:[0,12,1,0]
a.sfattr.hdr.totsize = 46
a.sfattr.hdr.count = 1
a.sfattr.list[0].namelen = 7
a.sfattr.list[0].valuelen = 32
a.sfattr.list[0].root = 0
a.sfattr.list[0].secure = 1
a.sfattr.list[0].name = "selinux"
a.sfattr.list[0].value = "unconfined_u:object_r:file_t:s0\000"
xfs_db> 

从命令“ls -lai”里可以看到目录文件“.”对应的inode是128,普通文件lenky.xfs对应的inode是131,128的di_format字段为1(local),表示该文件的内容(因为这是一个目录文件,所以文件内容就是该目录的子文件、子目录等信息)存放在本inode所在的这个block块内,即是100字节的起始位置;另一方面,可以看出131的di_format字段为 2(extents),它的数据存放在其它block内,block号为12;先hexdump验证一下,由于128的inode在第8块block(不清楚的话看前面的文章),所以偏移为32768:

[root@localhost loop]# hexdump -C -s 32768 -n 256 /dev/loop0
00008000  49 4e 41 ed 02 01 00 00  00 00 00 00 00 00 00 00  |INA.............|
00008010  00 00 00 02 00 00 00 00  00 00 00 00 00 00 00 01  |................|
00008020  4e ff 19 9b 30 68 93 4a  4e ff 19 99 1c 33 c3 17  |N...0h.JN....3..|
00008030  4e ff 19 99 1c 33 c3 17  00 00 00 00 00 00 00 16  |N....3..........|
00008040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00008050  00 00 00 02 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00008060  ff ff ff ff 01 00 00 00  00 80 09 00 30 6c 65 6e  |............0len|
00008070  6b 79 2e 78 66 73 00 00  00 83 00 00 00 00 00 00  |ky.xfs..........|
00008080  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00008100
[root@localhost loop]# hexdump -C -s 49152 -n 256 /dev/loop0
0000c000  31 32 33 34 35 36 37 38  39 0a 00 00 00 00 00 00  |123456789.......|
0000c010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
0000c100
[root@localhost loop]# 

再看继续看一下,可以看到随着子文件的增多,信息已经无法在当前inode所在的block块存放了(一个inode一共才256字节的空间),所以由“local”变成了“extents”的。另一方面,对于普通文件,就算只有2个字节,其存放方式也是“extents”(实验结论):

[root@localhost loop]# mount /dev/loop0 inode.256
[root@localhost loop]# cd !$
cd inode.256
[root@localhost inode.256]# for((i=1;i<=100;i++)); do touch "lenky.$i"; done
[root@localhost inode.256]# ls
lenky.1    lenky.14  lenky.2   lenky.25  lenky.30  lenky.36  lenky.41  lenky.47  lenky.52  lenky.58  lenky.63  lenky.69  lenky.74  lenky.8   lenky.85  lenky.90  lenky.96
lenky.10   lenky.15  lenky.20  lenky.26  lenky.31  lenky.37  lenky.42  lenky.48  lenky.53  lenky.59  lenky.64  lenky.7   lenky.75  lenky.80  lenky.86  lenky.91  lenky.97
lenky.100  lenky.16  lenky.21  lenky.27  lenky.32  lenky.38  lenky.43  lenky.49  lenky.54  lenky.6   lenky.65  lenky.70  lenky.76  lenky.81  lenky.87  lenky.92  lenky.98
lenky.11   lenky.17  lenky.22  lenky.28  lenky.33  lenky.39  lenky.44  lenky.5   lenky.55  lenky.60  lenky.66  lenky.71  lenky.77  lenky.82  lenky.88  lenky.93  lenky.99
lenky.12   lenky.18  lenky.23  lenky.29  lenky.34  lenky.4   lenky.45  lenky.50  lenky.56  lenky.61  lenky.67  lenky.72  lenky.78  lenky.83  lenky.89  lenky.94  lenky.xfs
lenky.13   lenky.19  lenky.24  lenky.3   lenky.35  lenky.40  lenky.46  lenky.51  lenky.57  lenky.62  lenky.68  lenky.73  lenky.79  lenky.84  lenky.9   lenky.95
[root@localhost inode.256]# cd ..
[root@localhost loop]# umount inode.256
[root@localhost loop]# /home/lenky/xfs/xfsprogs/db/xfs_db /dev/loop0
xfs_db> inode 128
xfs_db> p
core.magic = 0x494e
core.mode = 040755
core.version = 2
core.format = 2 (extents)
core.nlinkv2 = 2
core.onlink = 0
core.projid_lo = 0
core.projid_hi = 0
core.uid = 0
core.gid = 0
core.flushiter = 2
core.atime.sec = Sat Dec 31 09:41:33 2011
core.atime.nsec = 324158002
core.mtime.sec = Sat Dec 31 09:41:31 2011
core.mtime.nsec = 340158002
core.ctime.sec = Sat Dec 31 09:41:31 2011
core.ctime.nsec = 340158002
core.size = 4096
core.nblocks = 1
core.extsize = 0
core.nextents = 1
core.naextents = 0
core.forkoff = 0
core.aformat = 2 (extents)
core.dmevmask = 0
core.dmstate = 0
core.newrtbm = 0
core.prealloc = 0
core.realtime = 0
core.immutable = 0
core.append = 0
core.sync = 0
core.noatime = 0
core.nodump = 0
core.rtinherit = 0
core.projinherit = 0
core.nosymlinks = 0
core.extsz = 0
core.extszinherit = 0
core.nodefrag = 0
core.filestream = 0
core.gen = 0
next_unlinked = null
u.bmx[0] = [startoff,startblock,blockcount,extentflag] 0:[0,13,1,0]
xfs_db> inode 
current inode number is 128
xfs_db> fsblock 3^H
bad fsblock 3
xfs_db> fsblock 13
xfs_db> type text
xfs_db> p
000:  58 44 32 42 09 a8 03 18 00 00 00 00 00 00 00 00  XD2B............
010:  00 00 00 00 00 00 00 80 01 2e 00 00 00 00 00 10  ................
020:  00 00 00 00 00 00 00 80 02 2e 2e 00 00 00 00 20  ................
030:  00 00 00 00 00 00 00 83 09 6c 65 6e 6b 79 2e 78  .........lenky.x
040:  66 73 00 00 00 00 00 30 00 00 00 00 00 00 00 84  fs.....0........
050:  07 6c 65 6e 6b 79 2e 31 00 00 00 00 00 00 00 48  .lenky.1.......H
060:  00 00 00 00 00 00 00 85 07 6c 65 6e 6b 79 2e 32  .........lenky.2
070:  00 00 00 00 00 00 00 60 00 00 00 00 00 00 00 86  ................
080:  07 6c 65 6e 6b 79 2e 33 00 00 00 00 00 00 00 78  .lenky.3.......x
090:  00 00 00 00 00 00 00 87 07 6c 65 6e 6b 79 2e 34  .........lenky.4
0a0:  00 00 00 00 00 00 00 90 00 00 00 00 00 00 00 88  ................
0b0:  07 6c 65 6e 6b 79 2e 35 00 00 00 00 00 00 00 a8  .lenky.5........
0c0:  00 00 00 00 00 00 00 89 07 6c 65 6e 6b 79 2e 36  .........lenky.6
0d0:  00 00 00 00 00 00 00 c0 00 00 00 00 00 00 00 8a  ................
0e0:  07 6c 65 6e 6b 79 2e 37 00 00 00 00 00 00 00 d8  .lenky.7........
*
xfs_db> q
[root@localhost loop]# mount /dev/loop0 inode.256
[root@localhost loop]# cd inode.256
[root@localhost inode.256]# vi lenky.xfs 
[root@localhost inode.256]# hexdump lenky.xfs -C
00000000  31 0a                                             |1.|
00000002
[root@localhost inode.256]# cd ..
[root@localhost loop]# umount inode.256
[root@localhost loop]# /home/lenky/xfs/xfsprogs/db/xfs_db /dev/loop0
xfs_db> inode 131
xfs_db> p
core.magic = 0x494e
core.mode = 0
core.version = 2
core.format = 2 (extents)
core.nlinkv2 = 0
core.onlink = 0
core.projid_lo = 0
core.projid_hi = 0
core.uid = 0
core.gid = 0
core.flushiter = 3
core.atime.sec = Sat Dec 31 09:18:04 2011
core.atime.nsec = 300159942
core.mtime.sec = Sat Dec 31 09:18:01 2011
core.mtime.nsec = 474154430
core.ctime.sec = Sat Dec 31 09:52:11 2011
core.ctime.nsec = 498158007
core.size = 0
core.nblocks = 0
core.extsize = 0
core.nextents = 0
core.naextents = 0
core.forkoff = 0
core.aformat = 2 (extents)
core.dmevmask = 0
core.dmstate = 0
core.newrtbm = 0
core.prealloc = 0
core.realtime = 0
core.immutable = 0
core.append = 0
core.sync = 0
core.noatime = 0
core.nodump = 0
core.rtinherit = 0
core.projinherit = 0
core.nosymlinks = 0
core.extsz = 0
core.extszinherit = 0
core.nodefrag = 0
core.filestream = 0
core.gen = 1
next_unlinked = null
u = (empty)
xfs_db> q
[root@localhost loop]# 

下篇分析各种不同类型文件的文件内容的具体结构与组织,附带相关数据结构体的定义:

/*
 * On-disk inode structure.
 *
 * This is just the header or "dinode core", the inode is expanded to fill a
 * variable size the leftover area split into a data and an attribute fork.
 * The format of the data and attribute fork depends on the format of the
 * inode as indicated by di_format and di_aformat.  To access the data and
 * attribute use the XFS_DFORK_PTR, XFS_DFORK_DPTR, and XFS_DFORK_PTR macros
 * below.
 *
 * There is a very similar struct icdinode in xfs_inode which matches the
 * layout of the first 96 bytes of this structure, but is kept in native
 * format instead of big endian.
 */
typedef struct xfs_dinode {
	__be16		di_magic;	/* inode magic # = XFS_DINODE_MAGIC */
	__be16		di_mode;	/* mode and type of file */
	__u8		di_version;	/* inode version */
	__u8		di_format;	/* format of di_c data */
	__be16		di_onlink;	/* old number of links to file */
	__be32		di_uid;		/* owner's user id */
	__be32		di_gid;		/* owner's group id */
	__be32		di_nlink;	/* number of links to file */
	__be16		di_projid_lo;	/* lower part of owner's project id */
	__be16		di_projid_hi;	/* higher part owner's project id */
	__u8		di_pad[6];	/* unused, zeroed space */
	__be16		di_flushiter;	/* incremented on flush */
	xfs_timestamp_t	di_atime;	/* time last accessed */
	xfs_timestamp_t	di_mtime;	/* time last modified */
	xfs_timestamp_t	di_ctime;	/* time created/inode modified */
	__be64		di_size;	/* number of bytes in file */
	__be64		di_nblocks;	/* # of direct & btree blocks used */
	__be32		di_extsize;	/* basic/minimum extent size for file */
	__be32		di_nextents;	/* number of extents in data fork */
	__be16		di_anextents;	/* number of extents in attribute fork*/
	__u8		di_forkoff;	/* attr fork offs, <<3 for 64b align */
	__s8		di_aformat;	/* format of attr fork's data */
	__be32		di_dmevmask;	/* DMIG event mask */
	__be16		di_dmstate;	/* DMIG state info */
	__be16		di_flags;	/* random flags, XFS_DIFLAG_... */
	__be32		di_gen;		/* generation number */

	/* di_next_unlinked is the only non-core field in the old dinode */
	__be32		di_next_unlinked;/* agi unlinked list ptr */
} __attribute__((packed)) xfs_dinode_t;

/*
 * Values for di_format
 */
typedef enum xfs_dinode_fmt {
	XFS_DINODE_FMT_DEV,		/* xfs_dev_t */
	XFS_DINODE_FMT_LOCAL,		/* bulk data */
	XFS_DINODE_FMT_EXTENTS,		/* struct xfs_bmbt_rec */
	XFS_DINODE_FMT_BTREE,		/* struct xfs_bmdr_block */
	XFS_DINODE_FMT_UUID		/* uuid_t */
} xfs_dinode_fmt_t;

转载请保留地址:http://www.lenky.info/archives/2012/01/792http://lenky.info/?p=792


备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以Email或书面等方式告知,本站将及时删除相关内容或链接。

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.