9.2.2  Ext2的超级块

Ext2超级块是用来描述Ext2文件系统整体信息的数据结构,是Ext2的核心所在。它是一个ext2_super_block数据结构(在include/Linux/ext2_fs.h中定义),其各个域及含义如下。

struct ext2_super_block

 { __u32   s_inodes_count;    /* 文件系统中索引节点总数 */

   __u32   s_blocks_count;    /*文件系统中总块数 */

   __u32   s_r_blocks_count;           /* 为超级用户保留的块数 */

   __u32   s_free_blocks_count;   /*文件系统中空闲块总数 */

   __u32   s_free_inodes_count;   /*文件系统中空闲索引节点总数*/

   __u32   s_first_data_block;              /* 文件系统中第一个数据块 */

   __u32   s_log_block_size;              /* 用于计算逻辑块大小 */

   __s32   s_log_frag_size;              /* 用于计算片大小 */

   __u32   s_blocks_per_group; /* 每组中块数 */

   __u32   s_frags_per_group;              /* 每组中片数 */

   __u32   s_inodes_per_group; /* 每组中索引节点数 */

   __u32   s_mtime;                      /*最后一次安装操作的时间 */

   __u32   s_wtime;             /*最后一次对该超级块进行写操作的时间 */

   __u16   s_mnt_count;       /* 安装计数 */

   __s16   s_max_mnt_count;                 /* 最大可安装计数 */

   __u16   s_magic;                    /* 用于确定文件系统版本的标志 */

   __u16   s_state;                      /* 文件系统的状态*/

   __u16   s_errors;                     /* 当检测到有错误时如何处理 */

   __u16   s_minor_rev_level;  /* 次版本号 */

   __u32   s_lastcheck;       /* 最后一次检测文件系统状态的时间 */

   __u32   s_checkinterval; /* 两次对文件系统状态进行检测的间隔时间 */

   __u32   s_rev_level;       /* 版本号 */

   __u16   s_def_resuid;      /* 保留块的默认用户标识号 */

   __u16   s_def_resgid;      /* 保留块的默认用户组标识号*/ 

  

 /*

  * 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...

  */

__u32   s_first_ino;            /* 第一个非保留的索引节点 */

__u16   s_inode_size;           /* 索引节点的大小 */

  __u16   s_block_group_nr;       /* 该超级块的块组号 */

  __u32   s_feature_compat;       /* 兼容特点的位图*/

  __u32   s_feature_incompat;     /* 非兼容特点的位图 */

  __u32   s_feature_ro_compat;    /* 只读兼容特点的位图*/

  __u8    s_uuid[16];             /* 128位的文件系统标识号*/

  char    s_volume_name[16];      /* 卷名 */

  char    s_last_mounted[64];     /* 最后一个安装点的路径名 */

  __u32   s_algorithm_usage_bitmap; /* 用于压缩*/

   /*

   * Performance hints.  Directory preallocation should only

   * happen if the EXT2_COMPAT_PREALLOC flag is on.

   */

  __u8    s_prealloc_blocks;      /* 预分配的块数*/

  __u8    s_prealloc_dir_blocks;  /* 给目录预分配的块数 */

  __u16   s_padding1;         

  __u32   s_reserved[204];        /* null填充块的末尾 */

 };

 

从中我们可以看出,这个数据结构描述了整个文件系统的信息,下面对其中一些域作一些解释。

1)文件系统中并非所有的块普通用户都可以使用,有一些块是保留给超级用户专用的,这些块的数目就是在s_r_blocks_count中定义的。一旦空闲块总数等于保留块数,普通用户无法再申请到块了。如果保留块也被使用,则系统就可能无法启动了。有了保留块,我们就可以确保一个最小的空间用于引导系统。      

2)逻辑块是从0开始编号的,对块大小为1K的文件系统,s_first_data_block1,对其它文件系统,则为0                           

3s_log_block_size是一个整数,以2次方表示块的大小, 用1024字节作为单位。因此,0表示1024字节的块,1表示2048字节的块,如此等等。

同样,片的大小计算方法也是类似的,因为Ext2中还没有实现片,因此,s_log_frag_sizes_log_block_size相等。

4Ext2要定期检查自己的状态,它的状态取下面两个值之一。

#define EXT2_VALID_FS    0x0001

文件系统没有出错。

#define EXT2_ERROR_FS   0x0002

内核检测到错误。

s_lastcheck就是用来记录最近一次检查状态的时间,而s_checkinterval则规定了两次检查状态的最大允许间隔时间。

5)如果检测到文件系统有错误,则对s_errors赋一个错误值。一个好的系统应该能在错误发生时进行正确处理,有关Ext2如何处理错误将在后面介绍。

超级块被读入内存后,主要用于填写VFS的超级块,此外,它还要用来填写另外一个结构,这就是ext2_super_info结构,这一点我们可以从有关Ext2超级块的操作中看出,比如ext2_read_super()。之所以要用到这个结构,是因为VFS的超级块必须兼容各种文件系统的不同的超级块结构,所以对某个文件系统超级块自己的特性必须用另一个结构保存于内存中,以加快对文件的操作,比如对Ext2来说,片就是它特有的,所以不能存储在VFS超级块中。Ext2中的这个结构是ext2_super_info,它其中的信息多是从磁盘上的索引节点计算得来的 。该结构定义于include/Linux/ext2_fs_sb.h,下面是该结构及各个域含义:

struct ext2_sb_info

{

   unsigned long s_frag_size;                  /* 片大小(以字节计) */

   unsigned long s_frags_per_block;              /* 每块中片数 */

   unsigned long s_inodes_per_block;             /* 每块中节点数*/

   unsigned long s_frags_per_group;             /* 每组中片数*/

   unsigned long s_blocks_per_group;            /* 每组中块数 */

   unsigned long s_inodes_per_group;            /*每组中节点数 */

   unsigned long s_itb_per_group;         /* 每组中索引节点表所占块数 */

   unsigned long s_db_per_group;         /* 每组中组描述符所在块数 */

   unsigned long s_desc_per_block;                /* 每块中组描述符数 */

   unsigned long s_groups_count;              /* 文件系统中块组数 */

   struct buffer_head * s_sbh;                 /* 指向包含超级块的缓存 */

   struct buffer_head ** s_group_desc;     /*指向高速缓存中组描述符表块的                                指针数组的一个指针*/

   unsigned short s_loaded_inode_bitmaps;   /* 装入高速缓存中的节点位图块数*/

   unsigned short s_loaded_block_bitmaps;    /*装入高速缓存中的块位图块数*/

   unsigned long s_inode_bitmap_number[Ext2_MAX_GROUP_LOADED];

   struct buffer_head * s_inode_bitmap[Ext2_MAX_GROUP_LOADED];

   unsigned long s_block_bitmap_number[Ext2_MAX_GROUP_LOADED];

   struct buffer_head * s_block_bitmap[Ext2_MAX_GROUP_LOADED];

   int s_rename_lock;                         /*重命名时的锁信号量*/

   struct wait_queue * s_rename_wait;          /*指向重命名时的等待队列*/

   unsigned long  s_mount_opt;                 /*安装选项*/

   unsigned short s_resuid;                     *默认的用户标识号*/

   unsigned short s_resgid;                     /* 默认的用户组标识号*/

   unsigned short s_mount_state;              /*专用于管理员的安装选项*/

   unsigned short s_pad;                       /*填充*/

   int s_inode_size;                        /*节点的大小*/

   int s_first_ino;                       /*第一个节点号*/

};

s_block_bitmap_number[]s_block_bitmap[]s_inode_bitmap_number[]s_inode_bitmap[]是用来管理位图块高速缓存的,在介绍位图时再作说明。

另外,由于每个文件系统的组描述符表可能占多个块,这些块进入缓存后,用一个指针数组分别指向它们在缓存中的地址,而s_group_desc则是用来指向这个数组的,用相对于组描述符表首块的块数作索引,就可以找到指定的组描述符表块!

9.3是三个与超级块相关的数据结构的关系示意图:

 

            

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 9.3种超级块结构的关系示意图