超级块对象

from:超级块对象


每个VFS对象都存放在一个适当的数据结构中,其中包括对象的属性和指向对象的方法的指针,内核可以动态地修改对象的方法,因此可以为对象建立专用的行为。

内核中有多重对象,超级块对象是一种常用的对象。超级块对象由super_block结构组成。代码如下:

<include/linux/fs.h>

struct super_block {
    struct list_head    s_list;
    dev_t               s_dev;
    unsigned long       s_blocksize;
    unsigned char       s_blocksize_bits;
    unsigned char       s_dirt;
    loff_t              s_maxbytes;
    struct file_system_type         *s_type;
    const struct super_operations   *s_op;
    const struct dquot_operations   *dq_op;
    const struct quotactl_ops       *s_qcop;
    const struct export_operations  *s_export_op;
    unsigned long       s_flags;
    unsigned long       s_magic;
    struct dentry       *s_root;
    struct rw_semaphore s_umount;
    struct mutex        s_lock;
    int         s_count;
    int         s_need_sync;
    atomic_t        s_active;
#ifdef CONFIG_SECURITY    void                *s_security;
#endif    struct xattr_handler  **s_xattr;

    struct list_head    s_inodes;
    struct hlist_head   s_anon;
    struct list_head    s_files;
    struct list_head    s_dentry_lru;
    int                 s_nr_dentry_unused; 

    struct block_device *s_bdev;
    struct backing_dev_info *s_bdi;
    struct mtd_info     *s_mtd;
    struct list_head    s_instances;
    struct quota_info   s_dquot;

    int                 s_frozen;
    wait_queue_head_t   s_wait_unfrozen;

    char s_id[32];

    void                *s_fs_info;
    fmode_t             s_mode;

    struct mutex s_vfs_rename_mutex;

    u32    s_time_gran;

    char *s_subtype;
    char *s_options;
};
字段名说明
s_list指向超级块链表的指针
s_dev设备标识符
s_blocksize以字节为单位的块大小
s_old_blocksize基本块设备驱动程序中提到的以字节为单位的块大小
s_blocksize_bits以位为单位的块大小
s_dirt修改(脏)标志
s_maxbytes文件的最长长度
s_type文件系统类型
s_op超级块方法
dp_op磁盘限额处理方法
s_qcop磁盘限额管理方法
s_export_op网络文件系统使用的输出操作
s_flags安装标志
s_magic文件系统的magic words
s_root文件系统根目录的目录项对象
s_unmount卸载所用的信号量
s_lock超级块信号量
s_count引用计数器
s_syncing表示对超级块的索引节点进行同步的标志
s_need_sync_fs对超级块的已安装文件系统进行同步的标志
s_active次级引用计数器
s_security指向超级块安全数据结构的指针
s_xattr指向超级块扩展属性结构的指针
s_inodes所有索引节点的链表
s_dirty改进型索引节点的链表
s_io等待被写入磁盘的索引节点的链表
s_anon用于处理远程网络文件系统的你们目录项的链表
s_files文件对象的链表
s_bdev指向块设备驱动程序描述符的指针
s_instances用于给定文件系统类型的超级块对象链表的指针
s_dquot磁盘限额的描述符
s_frozen冻结文件系统时使用的标志
s_wait_unforzen进程挂起的等待队列,直到文件系统被解冻
s_id包含超级块的块设备名称
s_fs_info指向特定文件系统的超级块信息的指针
s_vfs_rename_sem当VFS通过目录重命名文件时使用的信号量
s_time_gran纳秒级的时间戳的粒度

所有超级块对象都以双向链表的形式链接在一起,链表中的第一个元素用super_blocks变量来表示,而超级块多想的s_list字段存放指向链表相邻元素的指针,sb_lock自旋锁保护链表受多处理器系统上的同时访问。

s_fs_info字段指向属于具体文件系统的超级块信息,例如,加入超级块对象指向的时Ext文件系统,该字段就指向extx_sb_info数据结构,该结构包括磁盘分配位掩码和其他与VFS的通用文件模型无关的数据。

通常,为了效率期间,由s_fs_info字段所指向的数据结构被复制到内存。任何基于磁盘文件系统都需要访问和更改自己的磁盘分配位图,以便分配或释放磁盘块,VFS允许这些文件系统直接对内存超级块s_fs_info字段进行操作,而无需访问磁盘。

但是这种方法会带来一个新问题,有可能VFS超级块最终不再与磁盘上相应的超级块同步。因此,有必要引入一个s_dirty标志来表示该超级块是否时脏的—由此可以推断磁盘上的数据是否有必要更新。缺乏同步还会导致产生一个问题,就是当一台机器的电源突然断开而用户来不及正常关闭系统时,就会出现文件系统崩溃,Linux时他哦难过周期性地将所有『脏』超级块写回磁盘来减少该问题带来的危害。

与超级块关联的方法就是超级块操作,当VFS需要调用其中一个操作时,比如说read_inode(),它就会执行下列操作:
sb->s_op->read_incode(inode);

这里sb存放所涉及超级块对象的地址。super_operations表的read_inode
字段存放这这个函数的地址,所以可以看作这个函数直接被调用。我们可以通过了解super_operations()函数来了解一下超级块的操作。

代码如下:

<include/linux/fs.h>

struct super_operations {
    struct inode *(*alloc_inode)(struct super_block *sb);
    void (*destroy_inode)(struct inode *);
    void (*dirty_inode) (struct inode *);
    int (*write_inode) (struct inode *, int);
    void (*drop_inode) (struct inode *);
    void (*delete_inode) (struct inode *);
    void (*put_super) (struct super_block *);
    void (*write_super) (struct super_block *);
    int (*sync_fs)(struct super_block *sb, int wait);
    int (*freeze_fs) (struct super_block *);
    int (*unfreeze_fs) (struct super_block *);
    int (*statfs) (struct dentry *, struct kstatfs *);
    int (*remount_fs) (struct super_block *, int *, char *);
    void (*clear_inode) (struct inode *);
    void (*umount_begin) (struct super_block *);
    int (*show_options)(struct seq_file *, struct vfsmount *);
    int (*show_stats)(struct seq_file *, struct vfsmount *);
#ifdef CONFIG_QUOTA    ssize_t (*quota_read)(
        struct super_block *, int, char *, size_t, loff_t);
    ssize_t (*quota_write)(
        struct super_block *, int,
        const char *, size_t, loff_t);
#endif    int (*bdev_try_to_free_page)(
        struct super_block*,
        struct page*,
        gfp_t);
};
函数名说明
alloc_inocde(sb)为索引节点对象分配空间,包括具体文件系统的数据所需的空间
destory_inode(inodes)撤销索引节点对象,包括具体文件系统的数据
read_inode(inode)用磁盘上的数据填充以参数传递过来的索引节点对象的字段,索引节点对象的i_ino字段标识从磁盘上要读取的具体文件系统的索引节点
dirty_inode(inode)当索引节点标记为修改时调用
write_inode(inode, flag)用通过传递参数指定的索引节点对象的内容更新一个文件系统的索引节点,索引节点对象的i_ino字段标识所涉及磁盘上文件系统的索引节点。flag参数表示I/O操作是否应当同步
put_inode(inode)释放索引节点时调用以执行具体文件系统操作
drop_inode(inode)在即将撤销索引节点时调用,也就是说,当最后一个用户释放该索引节点时,实现该方法的文件系统使用generic_drop_inode()函数。该函数从VFS数据结构中移走对索引节点的每一个引用,如果索引节点不再出现在任何目录中,则调用超级块方法delete_inode将它从文件系统中删除
delete_inode(inode)在必须撤销索引节点时调用,删除内存中的VFS索引节点和磁盘上的文件数据及元数据
put_super(super)释放通过传递的参数知道的超级块对象
write_super(super)用指定对象的内容更新文件系统的超级块
sync_fs(sb, wait)在清除文件系统来更新磁盘上的具体文件系统数据结构时调用
write_super_lockfs(super)阻塞对文件系统的修改并用指定对象的内容更新超级块。当文件系统被冻结时调用该方法
unlockfs(super)取消由write_super_lockfs()超级块方法实现的对文件系统更新的阻塞
statfs(super, buf)将文件系统的统计信息返回并填写在buf缓冲中
remount_fs(super, flags, data)用新的选项重新安装文件系统
clear_inode(inode)当撤销磁盘索引节点执行具体文件系统操作时调用
umount_begin(super)中断一个安装操作,因为相应的卸载操作已经开始,此操作只在网络文件系统中使用
show_options(seq_file, vfsmount)用来显式特定文件系统的选项
quota_read(super, type, data, size, offset)限额系统使用该方法从文件中读取数据,该文件详细说明了所在文件系统的限制
quota_write(super, type, data, size, offset)限额系统使用该方法将数据写入文件中,该文件详细说明了所在文件系统的限制1

上表的方法对所有可能的文件系统类型均是可用的,但是只有其中的一个自己应用到每个具体的文件系统,未实现的方法对应的字段设置为NULL。

  1. 限额系统(quota system)为每个用户和(或)组限制了它们在给定文件系统上所能使用的空间大小。