概述

 
        本篇博客主要描述ext2文件系统中的各种典型元数据结构,其中包括文件系统级别的元数据,如超级块,块组描述符等,也包括文件级的元数据,如文件目录项,文件inode等。
 

ext2超级块

 
      这里的超级块指的是ext2文件系统存储在磁盘上的超级块结构,之所以这么说是因为每个文件系统除了存储在磁盘上的超级块外,还在内存中也存储了一个超级块结构,基本上内存中的超级块是在磁盘超级块的基础上增加了一些额外的管理信息而成,因此,在这里我们主要关注的是ext2存储在磁盘上的超级块的数据结构。
ext2磁盘超级块的定义如下:
 
 /*
* Structure of the super block
*/
struct ext2_super_block {
__le32 s_inodes_count; /* Inodes count 索引节点总数*/
__le32 s_blocks_count; /* Blocks count 块大小,即文件系统以块为单位的大小*/
__le32 s_r_blocks_count; /* Reserved blocks count */
__le32 s_free_blocks_count; /* Free blocks count */
__le32 s_free_inodes_count; /* Free inodes count */
__le32 s_first_data_block; /* First Data Block */
__le32 s_log_block_size; /* Block size */
__le32 s_log_frag_size; /* Fragment size */
__le32 s_blocks_per_group; /* # Blocks per group 每个块组中的块数*/
__le32 s_frags_per_group; /* # Fragments per group */
__le32 s_inodes_per_group; /* # Inodes per group 每个块组中的索引节点个数*/
     __le32    s_mtime;        /* Mount time */
__le32 s_wtime; /* Write time */
__le16 s_mnt_count; /* Mount count */
__le16 s_max_mnt_count; /* Maximal mount count */
__le16 s_magic; /* Magic signature */
__le16 s_state; /* File system state */
__le16 s_errors; /* Behaviour when detecting errors */
__le16 s_minor_rev_level; /* minor revision level */
__le32 s_lastcheck; /* time of last check */
__le32 s_checkinterval; /* max. time between checks */
__le32 s_creator_os; /* OS */
__le32 s_rev_level; /* Revision level */
__le16 s_def_resuid; /* Default uid for reserved blocks */
__le16 s_def_resgid; /* Default gid for reserved blocks */
/*
* These fields are for EXT2_DYNAMIC_REV superblocks only.
*
* Note: the difference between the compatible feature set and
* the incompatible feature set is that if there is a bit set
* in the incompatible feature set that the kernel doesn't
* know about, it should refuse to mount the filesystem.
*
* e2fsck's requirements are more strict; if it doesn't know
* about a feature in either the compatible or incompatible
* feature set, it must abort and not try to meddle with
* things it doesn't understand...
*/
__le32 s_first_ino; /* First non-reserved inode */
__le16 s_inode_size; /* size of inode structure */
__le16 s_block_group_nr; /* block group # of this superblock */
__le32 s_feature_compat; /* compatible feature set */
__le32 s_feature_incompat; /* incompatible feature set */
__le32 s_feature_ro_compat; /* readonly-compatible feature set */
__u8 s_uuid[]; /* 128-bit uuid for volume */
char s_volume_name[]; /* volume name */
char s_last_mounted[]; /* directory where last mounted */
__le32 s_algorithm_usage_bitmap; /* For compression */
/*
* Performance hints. Directory preallocation should only
* happen if the EXT2_COMPAT_PREALLOC flag is on.
*/
__u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
__u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
__u16 s_padding1;
/*
* Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
*/
__u8 s_journal_uuid[]; /* uuid of journal superblock */
__u32 s_journal_inum; /* inode number of journal file */
__u32 s_journal_dev; /* device number of journal file */
__u32 s_last_orphan; /* start of list of inodes to delete */
__u32 s_hash_seed[]; /* HTREE hash seed */
__u8 s_def_hash_version; /* Default hash version to use */
__u8 s_reserved_char_pad;
__u16 s_reserved_word_pad;
__le32 s_default_mount_opts;
__le32 s_first_meta_bg; /* First metablock block group */
__u32 s_reserved[]; /* Padding to the end of the block */
};

可以看到,ext2磁盘超级块结构中大部分是描述整个文件系统的信息,如文件系统中块组的数量,inode数量,磁盘块的数量等等,不一而足,基本上从代码的注释我们就能比较清楚各个成员的含义,而且在后续的文章中我们或多或少地也会遇到这些成员,另外ext2超级块的最后一部分成员是为了兼容ext3而设计的,可能是为了更方便地从ext2升级至ext3吧,当然这只是我的猜测而已。

ext2块组描述符

 
        前面的描述中我们知道,ext2文件系统将磁盘(分区)划分成大小相等的块组,以提高文件存取的连续性。而且块组中存在inode表,inode位图,数据块位图中众多信息,因此,有必要对每个块组生成一个描述符来管理块组,在ext2中,该数据结构如下定义:
 
/*
* Structure of a blocks group descriptor
*/
struct ext2_group_desc
{
__le32 bg_block_bitmap; /* Blocks bitmap block */
__le32 bg_inode_bitmap; /* Inodes bitmap block */
__le32 bg_inode_table; /* Inodes table block */
__le16 bg_free_blocks_count; /* Free blocks count */
__le16 bg_free_inodes_count; /* Free inodes count */
__le16 bg_used_dirs_count; /* Directories count */
__le16 bg_pad;
__le32 bg_reserved[];
};
相对来说,块组描述符简单得多了,记录了块组中数据块位图和inode位图的块号这些块号是相对于块组而言的,而非绝对块号,另外还记录了该块组中创建的目录数量,之所以记录这个是在后来创建目录时会将其作为考虑的参数,之所以这样做的目的是将目录分散在文件系统的所有块组中,避免某些块组过满而另外一些较为空闲的情况,当然这只是一种很简单的策略,效果也不见得多好。
 

ext2文件目录项

 
     熟悉文件系统的朋友都知道,在linux文件系统中是通过目录一级一级索引直至找到最终的文件。文件是被组织在目录下的,要先找到文件我们必须先定位其所在目录,而且在linux中,一切皆文件,目录也是一个文件,也有数据块,其数据块中保存的是该目录下所有文件和子目录的文件目录项,因此,linux下文件查找的过程便是读出目录的数据块,在其中查找感兴趣的文件的文件目录项,进而访问文件更详细的信息
     因此,对于ext2文件来说,每个文件的首先的元数据信息便是文件目录项,而且它是存储在磁盘上的,只不过它是存储在父目录的数据块中,但这并不影响其重要性,ext2文件系统的文件目录项结构如下:
struct ext2_dir_entry_2 {
__le32 inode; /* Inode number inode编号 */
__le16 rec_len; /* Directory entry length */
__u8 name_len; /* Name length */
__u8 file_type;
char name[EXT2_NAME_LEN]; /* File name */
};
 
文件目录项主要是存储文件名至文件inode的映射关系,这样,根据文件名在父目录数据块中查找感兴趣文件就能获取该文件的inode号,进而可以得到该文件的所有信息

在该结构中,inode代表该文件inode编号,rec_len表示本文件目录项的大小,为什么需要这个rec_len呢,结构体定义好了整个长度不也就确认了嘛?非也,这是因为该结构体的最后一个成员name并不是固定长度的,其最大可以支持256字节,因此必须要有一个长度域来保存当前目录项长度,name_len指的是文件名长度,既然已经有了rec_len,为什么还需要文件名长呢,岂不多此一举?这是考虑到存在文件名填充的问题。从效率上来考虑,每个struct ext2_dir_entry_2最终都会被填充成4字节整数倍,对于目录项不是4字节整数倍的,需要在最后name文件名后面填充若干个0,因此name_len中记录的便是name[]域中有效文件名长度(即不包含0)。考虑下图所示事例:

1. “.”和“..”文件名后都填充了‘\0’以使文件目录项总长度为4的整数倍;

2. music和src文件/目录均也填充了‘\0’以使文件目录项总长度为4的整数倍;

3. test.txt因为其文件目录项已经是16个字节,无需填充。

ext2索引节点

  
      该数据结构可能是一个文件最重要的元数据信息了,因为描述文件的一切属性都保存在这里了(除了文件名),重要性不言而喻,而且索引节点也是持久化存储在磁盘之上,每个块组都有专门的inode表来存储文件索引节点,ext2的索引节点结构如下所描述:
/*
* Structure of an inode on the disk
*/
struct ext2_inode {
__le16 i_mode; /* File mode */
__le16 i_uid; /* Low 16 bits of Owner Uid */
__le32 i_size; /* Size in bytes */
__le32 i_atime; /* Access time */
__le32 i_ctime; /* Creation time */
__le32 i_mtime; /* Modification time */
__le32 i_dtime; /* Deletion Time */
__le16 i_gid; /* Low 16 bits of Group Id */
__le16 i_links_count; /* Links count */
__le32 i_blocks; /* Blocks count */
__le32 i_flags; /* File flags */
union {
struct {
__le32 l_i_reserved1;
} linux1;
struct {
__le32 h_i_translator;
} hurd1;
struct {
__le32 m_i_reserved1;
} masix1;
} osd1; /* OS dependent 1 */
__le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
__le32 i_generation; /* File version (for NFS) */
__le32 i_file_acl; /* File ACL */
__le32 i_dir_acl; /* Directory ACL */
__le32 i_faddr; /* Fragment address */
union {
struct {
__u8 l_i_frag; /* Fragment number */
__u8 l_i_fsize; /* Fragment size */
__u16 i_pad1;
__le16 l_i_uid_high; /* these 2 fields */
__le16 l_i_gid_high; /* were reserved2[0] */
__u32 l_i_reserved2;
} linux2;
struct {
__u8 h_i_frag; /* Fragment number */
__u8 h_i_fsize; /* Fragment size */
__le16 h_i_mode_high;
__le16 h_i_uid_high;
__le16 h_i_gid_high;
__le32 h_i_author;
} hurd2;
struct {
__u8 m_i_frag; /* Fragment number */
__u8 m_i_fsize; /* Fragment size */
__u16 m_pad1;
__u32 m_i_reserved2[];
} masix2;
} osd2; /* OS dependent 2 */
};
索引节点记录了文件的各种属性,如文件大小,文件模式,文件各种时间信息,文件数据块位置信息等。而其中最重要的信息就得数文件数据块位置了。ext2文件系统采用了巧妙的办法来记录文件数据块,兼顾了效率和空间利用率,具体方法如下图所示:
ext2中,将文件的数据块索引组织成数组的形式。在ext2的索引结构中有一个i_block[],该数组共有15项,每项记录的都是物理磁盘块号,其中前12项记录的是一级索引,即该该索引记录的是文件数据块地址,因此,对于小于12个数据块的文件来说,只需要查一次索引即可获得文件数据块位置。i_block[]的第13项是一个二级索引,即其中的块号指向的并不是文件数据块,而是一个存储索引的数据块,该索引数据块中保存了文件数据块的块号,因此,对于大一点的文件,获取数据可能得经历两次索引查询,另外还有三级索引等等,ext2就是采取这种策略来组织文件数据,这种方式在后面的博客中还会有专门的篇幅来阐述,这里点到为止。

ext2元数据结构的更多相关文章

  1. OAF_MDS系列1_OAF页面元数据结构MDS的解析(概念)

    2014-06-06 Created By BaoXinjian

  2. 一个相对通用的JSON响应结构,其中包含两部分:元数据与返回值

    定义一个相对通用的JSON响应结构,其中包含两部分:元数据与返回值,其中,元数据表示操作是否成功与返回值消息等,返回值对应服务端方法所返回的数据. public class Response { pr ...

  3. ASP.NET MVC Model元数据(四)

    ASP.NET MVC Model元数据(四) 前言 前面的篇幅讲解了Model元数据生成的过程,并没有对Model元数据生成过程的内部和Model元数据结构的详细解释.看完本篇后将会对Model元数 ...

  4. WCF技术剖析之二十六:如何导出WCF服务的元数据(Metadata)[扩展篇]

    原文:WCF技术剖析之二十六:如何导出WCF服务的元数据(Metadata)[扩展篇] 通过<实现篇>对WSDL元素和终结点三要素的之间的匹配关系的介绍,我们知道了WSDL的Binding ...

  5. WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[元数据描述篇]

    原文:WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[元数据描述篇] 在[WS标准篇]中我花了很大的篇幅介绍了WS-MEX以及与它相关的WS规范:WS-Policy.WS-Tra ...

  6. inode结构体成员详解

    概述:inode译成中文就是索引节点,它用来存放档案及目录的基本信息,包含时间.档名.使用者及群组等.inode分为内存中的inode和文件系统中的inode,为了避免混淆,我们称前者为VFS ino ...

  7. 【转】MEF程序设计指南五:迟延(Lazy)加载导出部件(Export Part)与元数据(Metadata)

    MEF中使用导出与导入,实质上就是对一个对象的实例化的过程,通过MEF的特性降低了对象的直接依赖,从而让系统的设计达到一种高灵活.高扩展性的效果.在具体的设计开发中,存在着某些对象是不需要在系统运行或 ...

  8. 我所认识的EXT2(一)

    前言: 本文是笔者自己在学习文件系统中的一些体会,写出来和大家分享一下.本文首先是介绍了下文件系统的一些理论概念,然后分析了ext2文件系统的原理和部分源码. 文件系统是什么: 人们在认识一件陌生事物 ...

  9. Linux磁盘管理——Ext2文件系统

    前言 通常而言,对于一块新磁盘我们不是直接使用,而是先分区,分区完毕后格式化,格式化后OS才能使用这个文件系统.分区可能会涉及到MBR和GPT问题.至于格式化和文件系统又有什么关系? 这里的格式化指的 ...

随机推荐

  1. java 编写hadoop程序中使用第三方libxx.so库

    在使用java编写hadoop处理程序时遇到了,java使用依赖的第三方libxx.so库的情况,找到了一种可行的方法,记录一下,希望对别人也有帮助: 加入需要使用的lib库为libxxx.so 1. ...

  2. poj 3299 Humidex

    直接套公式就可以,可我套公式第一遍都错了,英语差的孩子伤不起(┬_┬) #include <iostream> #include <cmath> #include <io ...

  3. Node.js V0.12 新特性之性能优化

    v0.12悠长的开发周期(已经过去九个月了,并且还在继续,是有史以来最长的一次)让核心团队和贡献者们有充分的机会对性能做一些优化. 本文会介绍其中最值得注意的几个. http://www.infoq. ...

  4. 如何通过Android Studio发布library到jCenter和Maven Central

    http://www.jianshu.com/p/3c63ae866e52# 在Android Studio里,如果你想引入任何library到自己的项目中,只需要很简单的在module的build. ...

  5. U盘分区信息清除

    diskpart select disk 1 clean 清除选中(优U)盘的所有信息;

  6. cocos2dx移植android平台-我的血泪史

    版权声明:本文由( 小塔 )原创,转载请保留文章出处! 本文链接:http://www.zaojiahua.com/android-platform.html 本人这几天一直都没有跟新自己的网站内容, ...

  7. ubuntu 安装ssh-server时出现错误:openssh-server: Depends: openssh-client (= 1:5.3p1-3ubuntu3) but 1:5.3p1-3ubuntu4 is to be installed

    错误如下: tiger@ubuntu:~/Desktop/work$ sudo apt-get install openssh-server [sudo] password for tiger: Re ...

  8. install python module

    [install python module] 参考:http://docs.python.org/2.7/install/index.html

  9. ActiveX控件

    什么是ActiveX控件:一个进程内服务器,支持多种的COM接口.(可以理解为,一个COM接口是一个纯抽象基类,你实现了它,并且它支持自注册,就是一个ActiveX控件了)可以把ActiveX控件看做 ...

  10. LeetCode7:Reverse Integer

    Reverse digits of an integer. Example1: x = 123, return 321Example2: x = -123, return -321 click to ...