很多具体文件系统中都有超级块结构,超级块是这些文件系统中最重要的数据结构,它是来描述整个文件系统信息的,可以说是一个全局的数据结构。Minix、Ext2等有超级块,VFS也有超级块,为了避免与后面介绍的Ext2超级块发生混淆,这里用VFS超级块来表示。VFS超级块是各种具体文件系统在安装时建立的,并在这些文件系统卸载时自动删除,可见,VFS超级块确实只存在于内存中,同时提到VFS超级块也应该说成是哪个具体文件系统的VFS超级块。VFS超级块在inculde/fs/fs.h中定义,即数据结构super_block,该结构及其主要域的含义如下:
struct super_block
{
/************描述具体文件系统的整体信息的域*****************
kdev_t
s_dev;
/* 包含该具体文件系统的块设备标识符。
例如,对于 /dev/hda1,其设备标识符为 0x301*/
unsigned
long s_blocksize; /*该具体文件系统中数据块的大小,
以字节为单位 */
unsigned
char s_blocksize_bits; /*块大小的值占用的位数,例如,
如果块大小为1024字节,则该值为10*/
unsigned long long s_maxbytes; /* 文件的最大长度 */
unsigned
long s_flags;
/* 安装标志*/
unsigned
long s_magic;
/*魔数,即该具体文件系统区别于其它
文系统的一个标志*/
/**************用于管理超级块的域******************/
struct list_head s_list; /*指向超级块链表的指针*/
struct semaphore s_lock /*锁标志位,若置该位,则其它进程
不能对该超级块操作*/
struct rw_semaphore s_umount /*对超级块读写时进行同步*/
unsigned char s_dirt; /*脏位,若置该位,表明该超级块已被修改*/
struct dentry *s_root; /*指向该具体文件系统安装目录的目录项。*/
int
s_count; /*对超级块的使用计数*/
atomic_t
s_active;
struct list_head
s_dirty; /*已修改的索引节点形成的链表 */
struct list_head
s_locked_inodes;/* 要进行同步的索引节点形成的链表*/
struct list_head s_files
/***********和具体文件系统相联系的域*************************/
struct
file_system_type *s_type;
/*指向文件系统的
file_system_type 数据结构的指针
*/
struct
super_operations *s_op;
/*指向某个特定的具体文件系统的用
于超级块操作的函数集合 */
struct dquot_operations *dq_op;
/* 指向某个特定的具体文件系统
用于限额操作的函数集合 */
u;
/*一个共用体,其成员是各种文件系统
的 fsname_sb_info数据结构 */
};
所有超级块对象(每个已安装的文件系统都有一个超级块)以双向环形链表的形式链接在一起。链表中第一个元素和最后一个元素的地址分别存放在super_blocks变量的s_list域的 next 和 prev域中。s_list域的数据类型为struct list_head,在超级块的s_dirty域以及内核的其他很多地方都可以找到这样的数据类型;这种数据类型仅仅包括指向链表中的前一个元素和后一个元素的指针。因此,超级块对象的s_list域包含指向链表中两个相邻超级块对象的指针。图8.2说明了list_head 元素、next 和 prev是如何嵌入到超级块对象中的。
super_blocks next prev
超级块 超级块 超级块
图8.2 超级块链表
超级块最后一个u 联合体域包括属于具体文件系统的超级块信息:
union {
struct Minix_sb_info Minix_sb;
struct Ext2_sb_info Ext2_sb;
struct ext3_sb_info ext3_sb;
struct hpfs_sb_info hpfs_sb;
struct ntfs_sb_info ntfs_sb;
struct msdos_sb_info msdos_sb;
struct isofs_sb_info isofs_sb;
struct nfs_sb_info nfs_sb;
struct sysv_sb_info sysv_sb;
struct affs_sb_info affs_sb;
struct ufs_sb_info ufs_sb;
struct efs_sb_info efs_sb;
struct shmem_sb_info shmem_sb;
struct romfs_sb_info romfs_sb;
struct smb_sb_info smbfs_sb;
struct hfs_sb_info hfs_sb;
struct adfs_sb_info adfs_sb;
struct qnx4_sb_info qnx4_sb;
struct reiserfs_sb_info reiserfs_sb;
struct bfs_sb_info bfs_sb;
struct udf_sb_info udf_sb;
struct ncp_sb_info ncpfs_sb;
struct usbdev_sb_info usbdevfs_sb;
struct jffs2_sb_info jffs2_sb;
struct cramfs_sb_info cramfs_sb;
void *generic_sbp;
} u;
通常,为了效率起见u域的数据被复制到内存。任何基于磁盘的文件系统都需要访问和更改自己的磁盘分配位示图,以便分配和释放磁盘块。VFS允许这些文件系统直接对内存超级块的u联合体域进行操作,无需访问磁盘。
但是,这种方法带来一个新问题:有可能VFS超级块最终不再与磁盘上相应的超级块同步。因此,有必要引入一个s_dirt标志,来表示该超级块是否是脏的,也就是说,磁盘上的数据是否必须要更新。缺乏同步还导致我们熟悉的一个问题:当一台机器的电源突然断开而用户来不及正常关闭系统时,就会出现文件系统崩溃。Linux是通过周期性地将所有“脏”的超级块写回磁盘来减少该问题带来的危害。
与超级块关联的方法就是所谓的超级块操作。这些操作是由数据结构super_operations来描述的,该结构的起始地址存放在超级块的s_op域中,稍后将与其他对象的操作一块介绍。