linux VFS 之二:超级块superblock

来源:互联网 发布:开关电源软件破解 编辑:程序博客网 时间:2024/04/28 16:09

进程与vfs对象之间的关系很重要:




superblock作用及重要成员

sb作用:
在文件系统安装时,VFS根据实际文件系统存放在块设备上的管理信息,在内存中建立一个VFS超级块。
VFS超级块用来描述已安装的文件系统的信息,是一个全局的数据结构: struct list_head super_blocks;
VFS超级块存在于内存中,它在文件系统安装时建立,并且在文件系统卸载时自动删除 。
注意:分清楚VFS超级块和各实际文件系统,如EXT4的超级块
对每个具体的文件系统来说,都有各自的超级块, 如EXT4超级块,它们存放于磁盘

/kernel/fs/super.c
LIST_HEAD(super_blocks);

superblock 的重要成员:
struct super_block {
struct list_head s_list;/* Keep this first */   指向超级块链表的指针
dev_t s_dev;/* search index; _not_ kdev_t */  设备标识符
unsigned char s_dirt;     脏标识
unsigned long s_blocksize;  字节为单位的块大小
loff_t s_maxbytes; /* Max file size */ 文件的最大长度
struct file_system_type*s_type;   文件系统类型
const struct super_operations*s_op;  超级块方法
struct dentry*s_root;     文件系统根目录的目录项对象

struct list_head s_inodes;/* all inodes */
  ......................................................................

struct block_device*s_bdev;  块设备驱动程序描述符指针
 
        ....................................................................
void *s_fs_info;/* Filesystem private info */ 特定文件系统超级块指针
  ....................................................................

};

superblock创建函数:sget


extern struct list_head super_blocks; //所有超级块以双向链表形式链接在一起。链表中第一个元素
用super_blocks全局变量表示。 sget()用于查找、或创建superblock。
/**
 * sget - find or create a superblock
 * @type: filesystem type superblock should belong to
 * @test: comparison callback
 * @set: setup callback
 * @data: argument to each of them
 */
struct super_block *sget(struct file_system_type *type,
int (*test)(struct super_block *,void *),
int (*set)(struct super_block *,void *),
void *data)
{
struct super_block *s = NULL;
struct hlist_node *node;
struct super_block *old;
int err;
retry:
spin_lock(&sb_lock);

if (!s) {
spin_unlock(&sb_lock);
s = alloc_super(type);
if (!s)
return ERR_PTR(-ENOMEM);
goto retry;
}

err = set(s, data);         //通常用于初始化superblock的块设备驱动程序描述符指针:s_bdev;  
if (err) {
spin_unlock(&sb_lock);
up_write(&s->s_umount);
destroy_super(s);
return ERR_PTR(err);
}
s->s_type = type;
strlcpy(s->s_id, type->name, sizeof(s->s_id));
list_add_tail(&s->s_list, &super_blocks);  //新创建的superblock链接到全局链表super_blocks尾巴
hlist_add_head(&s->s_instances, &type->fs_supers);
spin_unlock(&sb_lock);
get_filesystem(type);
register_shrinker(&s->s_shrink);
return s;
}

特定文件系统mount过程中创建VFS superblock过程:

参考代码一:块设备文件系统块设备mount_bdev


struct dentry *mount_bdev(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data,
int (*fill_super)(struct super_block *, void *, int))
{
struct block_device *bdev;
struct super_block *s;
fmode_t mode = FMODE_READ | FMODE_EXCL;
int error = 0;

if (!(flags & MS_RDONLY))
mode |= FMODE_WRITE;

bdev = blkdev_get_by_path(dev_name, mode, fs_type);   //通过路径名获取块设备指针
           
s = sget(fs_type, test_bdev_super,set_bdev_super, bdev);   //创建vfs superblock, set_bdev_super初始化块设备指针:s_bdev
mutex_unlock(&bdev->bd_fsfreeze_mutex);

..........................................................
   //初始化 vfs superblock
s->s_flags = flags | MS_NOSEC;
s->s_mode = mode;
strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
sb_set_blocksize(s, block_size(bdev));
error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);      //创建特定文件系统的superblock,存放在:s_fs_info
if (error) {
xlog_printk(ANDROID_LOG_DEBUG, "MNT_TAG", "mount_bdev, fill_super error:%d\n", error);
deactivate_locked_super(s);
goto error;
}


s->s_flags |= MS_ACTIVE;
bdev->bd_super = s;
}

return dget(s->s_root);

error_s:
error = PTR_ERR(s);
error_bdev:
blkdev_put(bdev, mode);
error:
return ERR_PTR(error);
}

下面例举磁盘文件系统ext4的mount函数:
static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags,
      const char *dev_name, void *data)
{
return mount_bdev(fs_type, flags, dev_name, data, ext4_fill_super);
}

参考代码二:非块设备特殊文件系统的mount_nodev

struct dentry *mount_nodev(struct file_system_type *fs_type,
int flags, void *data,
int (*fill_super)(struct super_block *, void *, int))
{
int error;
struct super_block *s = sget(fs_type, NULL, set_anon_super,NULL);


if (IS_ERR(s))
return ERR_CAST(s);


s->s_flags = flags;


error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
if (error) {
deactivate_locked_super(s);
return ERR_PTR(error);
}
s->s_flags |= MS_ACTIVE;
return dget(s->s_root);
}
下面例举两个特殊文件系统的mount函数:
//fuse文件系统的mount
static struct dentry *fuse_mount(struct file_system_type *fs_type,
      int flags, const char *dev_name,
      void *raw_data)
{
return mount_nodev(fs_type, flags, raw_data, fuse_fill_super);
}
//ramfs文件系统的mount
struct dentry *ramfs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return mount_nodev(fs_type, flags, data, ramfs_fill_super);
}

superblock超级块方法重要成员

struct super_operations {
    struct inode *(*alloc_inode)(struct super_block *sb);   //为索引节点对象inode分配空间,包括具体文件系统的数据所需空间
void (*destroy_inode)(struct inode *);   //撤销alloc_inode分配的空间

    void (*dirty_inode) (struct inode *, int flags);      //当索引节点标记为dirty时调用,像ext4用它更新磁盘上的日志。
int (*write_inode) (struct inode *, struct writeback_control *wbc); 
int (*drop_inode) (struct inode *);       
void (*evict_inode) (struct inode *);
void (*put_super) (struct super_block *);      //umount文件系统时,释放超级块对象
void (*write_super) (struct super_block *);    //更新超级块
int (*sync_fs)(struct super_block *sb, int wait);  //同步超级块对象对到磁盘,ext4等日志文件系统使用。

int (*statfs) (struct dentry *, struct kstatfs *);   //获取文件系统信息
int (*remount_fs) (struct super_block *, int *, char *);
void (*umount_begin) (struct super_block *);


int (*show_options)(struct seq_file *, struct dentry *);
int (*show_devname)(struct seq_file *, struct dentry *);
int (*show_path)(struct seq_file *, struct dentry *);
int (*show_stats)(struct seq_file *, struct dentry *);


};

举例sdcardfs super_operations
sdcardfs在mount时,会调用函数:sdcardfs_read_super(),该函数有语句sb->s_op = &sdcardfs_sops;  
sdcardfs superblock操作方法,如下全局结构体变量:
const struct super_operations sdcardfs_sops = {
.put_super = sdcardfs_put_super,
.statfs = sdcardfs_statfs,
.remount_fs = sdcardfs_remount_fs,
.evict_inode = sdcardfs_evict_inode,
.umount_begin = sdcardfs_umount_begin,
.show_options = sdcardfs_show_options,
.alloc_inode = sdcardfs_alloc_inode,
.destroy_inode= sdcardfs_destroy_inode,
.drop_inode = generic_delete_inode,
};  

下面举例分析sdcardfs中alloc_inode成员的,来说明文件系统获取inode的过程,其它方法不再一一分析。

static struct inode *sdcardfs_iget(struct super_block *sb,
struct inode *lower_inode)
{
struct sdcardfs_inode_info *info;
struct inode *inode; /* the new inode to return */
int err;


/* in order for FAT emulation */
//struct sdcardfs_sb_info *sb_info = sb->s_fs_info;


inode = iget5_locked(sb, /* our superblock */
    /*
     * hashval: we use inode number, but we can
     * also use "(unsigned long)lower_inode"
     * instead.
     */
    lower_inode->i_ino, /* hashval */
    sdcardfs_inode_test,/* inode comparison function */
    sdcardfs_inode_set, /* inode init function */
    lower_inode); /* data passed to test+set fxns */  
      核心就在这里,继续往下看它是怎样实现的!
  。。。。。。。。。。。。。。。。

struct inode *iget5_locked(struct super_block *sb, unsigned long hashval,
int (*test)(struct inode *, void *),
int (*set)(struct inode *, void *), void *data)
{
struct hlist_head *head = inode_hashtable + hash(sb, hashval);
struct inode *inode;
       /

spin_lock(&inode_hash_lock);
inode = find_inode(sb, head, test, data);  /如果 inode 在内存中(全局hash表:inode_hashtable已经存在,则直接返回;
spin_unlock(&inode_hash_lock);


if (inode) {
wait_on_inode(inode);
return inode;
}


inode = alloc_inode(sb);   //否则调用sb->s_op->alloc_inode(sb);创建一个新的 inode
if (inode) {

      。。。。。。。。。。。。
  return inode;
}

static struct inode *alloc_inode(struct super_block *sb)
{
struct inode *inode;


if (sb->s_op->alloc_inode)
inode = sb->s_op->alloc_inode(sb);   //哈哈,到这边就真正调用到特定文件系统的supblock的alloc_inode方法了。 
//比如sdcardfs的supblock的alloc_inode方法:sdcardfs_alloc_inode
else
inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL);

。。。。。。。。

return inode;
}

/* sdcardfs inode data in memory */
struct sdcardfs_inode_info {
perm_t perm;
    userid_t userid;
struct inode *lower_inode;
struct inode vfs_inode;
};

//到这边获取sdcardfs的inode就结束了!
static struct inode *sdcardfs_alloc_inode(struct super_block *sb)
{
struct sdcardfs_inode_info *i;


i = kmem_cache_alloc(sdcardfs_inode_cachep, GFP_KERNEL);   //申请inode内存,但不仅仅inode内存,还申请了sdcardf专有数据空间。
if (!i)
return NULL;


/* memset everything up to the inode to 0 */
memset(i, 0, offsetof(struct sdcardfs_inode_info, vfs_inode));    //这边并没有初始化sdcardfs inode,


i->vfs_inode.i_version = 1;
    //printk(KERN_INFO "sdcardfs: %s(%d)-> i_mode=%o \n", __FUNCTION__, __LINE__, i->vfs_inode.i_mode);
return &i->vfs_inode;   //返回sdcardfs inode
}




0 0
原创粉丝点击