Chinaunix首页 | 论坛 | 博客
  • 博客访问: 819863
  • 博文数量: 117
  • 博客积分: 2583
  • 博客等级: 少校
  • 技术积分: 1953
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-06 22:58
个人简介

Coder

文章分类
文章存档

2013年(1)

2012年(10)

2011年(12)

2010年(77)

2009年(13)

2008年(4)

分类: LINUX

2010-07-27 01:11:13

分配超级块对象

许多文件系统对象的get_sb方法都是由单行函数实现的。例如,在Ext3文件系统中该方法实现如下:

---------------------------------------------------------------------

fs/ext3/super.c

3009 static int ext3_get_sb(struct file_system_type *fs_type,

3010   int flags, const char *dev_name, void *data, struct vfsmount *mnt)

3011 {

3012  return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super, mnt);

3013 }

---------------------------------------------------------------------

 

get_sb_bdev() VFS函数分配并初始化一个新的适合于磁盘文件系统的超级块。它接收ext3_fill_super函数的地址作为参数,该函数从Ext3磁盘分区读取磁盘超级块。为了分配适合于特殊文件系统的超级块,VFS也提供get_sb_pseudo()函数(对于没有挂载点的特殊文件系统,例如pipefs sockfsbdevfs等)、get_sb_single()函数(对于具有唯一挂载点的特殊文件系统,例如sysfs)、get_sb_nodev()函数(对于可以挂载多次的特殊文件系统,例如tmpfsramfs等)以及get_sb_ns()()函数。

 

get_sb_bdev()函数定义如下:

---------------------------------------------------------------------

fs/super.c

784 int get_sb_bdev(struct file_system_type *fs_type,

785         int flags, const char *dev_name, void *data,

786         int (*fill_super)(struct super_block *, void *, int),

787         struct vfsmount *mnt)

788 {

789   struct block_device *bdev;

790   struct super_block *s;

791   fmode_t mode = FMODE_READ;

792   int error = 0;

793

794   if (!(flags & MS_RDONLY))

795        mode |= FMODE_WRITE;

796

797   bdev = open_bdev_exclusive(dev_name, mode, fs_type);

798   if (IS_ERR(bdev))

799                 return PTR_ERR(bdev);

800

801   /*

802    * once the super is inserted into the list by sget, s_umount

803    * will protect the lockfs code from trying to start a snapshot

804    * while we are mounting

805    */

806   mutex_lock(&bdev->bd_fsfreeze_mutex);

807   if (bdev->bd_fsfreeze_count > 0) {

808        mutex_unlock(&bdev->bd_fsfreeze_mutex);

809        error = -EBUSY;

810        goto error_bdev;

811   }

812   s = sget(fs_type, test_bdev_super, set_bdev_super, bdev);

813   mutex_unlock(&bdev->bd_fsfreeze_mutex);

814   if (IS_ERR(s))

815        goto error_s;

816

817   if (s->s_root) {

818        if ((flags ^ s->s_flags) & MS_RDONLY) {

819             deactivate_locked_super(s);

820             error = -EBUSY;

821             goto error_bdev;

822        }

823

824        close_bdev_exclusive(bdev, mode);

825   } else {

826        char b[BDEVNAME_SIZE];

827

828        s->s_flags = flags;

829        s->s_mode = mode;

830        strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));

831        sb_set_blocksize(s, block_size(bdev));

832        error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);

833        if (error) {

834             deactivate_locked_super(s);

835             goto error;

836        }

837

838        s->s_flags |= MS_ACTIVE;

839        bdev->bd_super = s;

840   }

841

842   simple_set_mnt(mnt, s);

843   return 0;

844

845 error_s:

846   error = PTR_ERR(s);

847 error_bdev:

848   close_bdev_exclusive(bdev, mode);

849 error:

850   return error;

851 }

---------------------------------------------------------------------

get_sb_bdev()执行的主要操作如下:

1、调用open_bdev_exclusive()打开设备文件名为dev_name的块设备。

 

2、调用sget()搜索文件系统的超级块对象链表(type->fs_supersfile_system_typefs_supers字段将同文件系统类型的不同实例的超级块对象连接起来),我们看到传递的参数为fs_typetest_bdev_superset_bdev_superbdev。如果找到一个与打开的块设备相匹配的超级块,则返回它的地址。也就是同一个设备无论在多少个挂载点挂载多少次,系统中对应于该设备,实际上都只有一个super_block对象,由此保证了数据的同步。否则,分配并初始化一个新的超级块对象,把它插入到以文件系统的fs_supers字段为链表头的双向链表中,并返回其地址。我们来看sget()的定义:

---------------------------------------------------------------------

fs/super.c

339 struct super_block *sget(struct file_system_type *type,

340                         int (*test)(struct super_block *,void *),

341                         int (*set)(struct super_block *,void *),

342                         void *data)

343 {

344   struct super_block *s = NULL;

345   struct super_block *old;

346   int err;

347

348 retry:

349   spin_lock(&sb_lock);

350   if (test) {

351        list_for_each_entry(old, &type->fs_supers, s_instances) {

352             if (!test(old, data))

353                  continue;

354             if (!grab_super(old))

355                  goto retry;

356             if (s) {

357                  up_write(&s->s_umount);

358                  destroy_super(s);

359             }

360             return old;

361        }

362   }

363   if (!s) {

364        spin_unlock(&sb_lock);

365        s = alloc_super(type);

366        if (!s)

367             return ERR_PTR(-ENOMEM);

368        goto retry;

369   }

370               

371   err = set(s, data);

372   if (err) {

373        spin_unlock(&sb_lock);

374        up_write(&s->s_umount);

375        destroy_super(s);

376        return ERR_PTR(err);

377   }

378   s->s_type = type;

379   strlcpy(s->s_id, type->name, sizeof(s->s_id));

380   list_add_tail(&s->s_list, &super_blocks);

381   list_add(&s->s_instances, &type->fs_supers);

382   spin_unlock(&sb_lock);

383   get_filesystem(type);

384   return s;

385 }

---------------------------------------------------------------------

sget()函数首先通过一个循环,使用传递进来的test方法,逐个地检查文件系统类型的fs_supers链表中的元素,查看test_bdev_super()的定义,即检查超级块的s_bdev字段值是否与打开的块设备相同,若是,则将相应的超级块返回。

 

在文件系统类型的fs_supers链表中没有找到超级块,则调用alloc_super(type)来分配并初始化超级块。

 

调用传递进来的set(s, data)方法,查看set_bdev_super()函数的定义,则主要是设置超级块的s_bdev字段指向块设备结构,设置超级块的s_dev,即设备号字段为块设备的设备号。

 

设置超级块的s_type指向文件系统类型对象,设置超级块的s->s_id值为文件系统类型名。将超级块对象添加进系统的超级块对象链表,将超级块对象添加进文件系统类型的fs_supers链表。增加文件系统类型的引用计数。

 

3、如果不是新的超级块(通过sget()函数返回的super_block对象的s_root字段,即s->s_root是否为空来判断的),则首先检查flags s->s_flags是否仅有一个设置了MS_RDONLY。若是,则调用close_bdev_exclusive(bdev, mode)关闭块设备并返回-EBUSY;否则,仅仅调用close_bdev_exclusive(bdev, mode)关闭块设备。

 

4、超级块是新创建的,把参数flags中的值拷贝到超级块的s_flags字段,把mode中的值拷贝到超级块的s_mode字段,并将s_ids_blocksize字段设置为块设备的合适值(s_id为由block_device所属的gendisk的设备名及分区号组成的字符串,s_blocksizebdev->bd_block_size)。调用特定文件系统的超级块填充函数(例子中是ext3_fill_super函数),这个函数访问磁盘上的超级块信息,并填充新超级块对象的其他字段。设置超级块标志字段s->s_flagsMS_ACTIVE,以表示超级快可用。同时设置bdev->bd_super为超级块的地址

 

5、调用simple_set_mnt()简单设置mnt参数,即将vfsmount对象的mnt_sb字段设置为获得的super_block,增加super_block字段s_root所指向的dentry的引用计数,并将s_root字段值赋给mntmnt_root字段。

 

在这里,我们看到,在fill_super()方法返回的时候,其超级块对象的s_root,也就是文件系统的根目录目录项已经为有效值了。

 

6、返回0
阅读(3178) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

ziyanghgd2015-10-13 21:33:58

不错,简洁明了