Chinaunix首页 | 论坛 | 博客
  • 博客访问: 458758
  • 博文数量: 285
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 629
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-14 17:53
个人简介

相信自己,快乐每一天

文章分类

全部博文(285)

分类: LINUX

2014-02-19 10:26:43

原文地址:sysfs文件系统的初始化 作者:tq08g2z

首先,我们从文件系统的角度来看sysfs文件系统,看它的文件系统注册,文件系统的挂载,各个虚拟文件系统对象实例的建立等。

mnt_init()函数中,在建立了vfsmount对象缓冲,为vfsmount哈希表分配空间并初始化哈希表之后,紧接着就调用了sysfs_init()函数来初始化了sysfs文件系统。此时此刻,根文件系统可都还没有挂载呢。sysfs_init()定义为:

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

fs/sysfs/mount.c

87 int __init sysfs_init(void)

 88 {

 89         int err = -ENOMEM;

 90

 91         sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",

 92                                    sizeof(struct sysfs_dirent),

 93                                               0, 0, NULL);

 94         if (!sysfs_dir_cachep)

 95                 goto out;

 96

 97         err = sysfs_inode_init();

 98         if (err)

 99                 goto out_err;

100

101         err = register_filesystem(&sysfs_fs_type);

102         if (!err) {

103                 sysfs_mount = kern_mount(&sysfs_fs_type);

104                 if (IS_ERR(sysfs_mount)) {

105                         printk(KERN_ERR "sysfs: could not mount!\n");

106                         err = PTR_ERR(sysfs_mount);

107                         sysfs_mount = NULL;

108                         unregister_filesystem(&sysfs_fs_type);

109                         goto out_err;

110                 }

111         } else

112                 goto out_err;

113 out:

114         return err;

115 out_err:

116         kmem_cache_destroy(sysfs_dir_cachep);

117         sysfs_dir_cachep = NULL;

118         goto out;

119 }

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

这个函数也在继续着建立各种slab缓存的过程。

1、调用kmem_cache_create()来建立sysfs_dirent结构的缓存,由全局变量sysfs_dir_cachep指向这个缓存。至于说这个结构到底是干什么用的,待我们稍后再说。

2、调用sysfs_inode_init()

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

fs/sysfs/inode.c

47 int __init sysfs_inode_init(void)

48 {

49         return bdi_init(&sysfs_backing_dev_info);

50 }

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

3、调用register_filesystem(&sysfs_fs_type)来注册sysfs文件系统。这个没什么好说的,无非就是将file_system_type对象sysfs_fs_type添加进file_systems指向的file_system_type对象链表中而已。这好像还是系统中注册的第一个文件系统呢。

4、调用kern_mount(&sysfs_fs_type)来挂载sysfs文件系统。kern_mount()是一个宏。其定义如下:

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

iclude/linux/fs.h

1796 #define kern_mount(type) kern_mount_data(type, NULL)

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

这就是一个函数调用的别名而已。再来看kern_mount_data()函数定义:

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

fs/super.c

1032 struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)

1033 {

1034         return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);

1035 }

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

它只是根据传递进来的参数,选择适当的参数来调用vfs_kern_mount()。当是复习好了,我们再来仔仔细细的看下这个vfs_kern_mount()。它的定义为:

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

fs/super.c

927 struct vfsmount *

928 vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)

929 {

930         struct vfsmount *mnt;

931         char *secdata = NULL;

932         int error;

933

934         if (!type)

935                 return ERR_PTR(-ENODEV);

936

937         error = -ENOMEM;

938         mnt = alloc_vfsmnt(name);

939         if (!mnt)

940                 goto out;

941

942         if (flags & MS_KERNMOUNT)

943                 mnt->mnt_flags = MNT_INTERNAL;

944

945         if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {

946                 secdata = alloc_secdata();

947                 if (!secdata)

948                         goto out_mnt;

949

950                 error = security_sb_copy_data(data, secdata);

951                 if (error)

952                         goto out_free_secdata;

953         }

954

955         error = type->get_sb(type, flags, name, data, mnt);

956         if (error < 0)

957                 goto out_free_secdata;

958         BUG_ON(!mnt->mnt_sb);

959         WARN_ON(!mnt->mnt_sb->s_bdi);

960

961         error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);

962         if (error)

963                 goto out_sb;

964

965         /*

966          * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE

967          * but s_maxbytes was an unsigned long long for many releases. Throw

968          * this warning for a little while to try and catch filesystems that

969          * violate this rule. This warning should be either removed or

970          * converted to a BUG() in 2.6.34.

971          */

972         WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "

973                 "negative value (%lld)\n", type->name, mnt->mnt_sb->s_maxbytes);

974

975         mnt->mnt_mountpoint = mnt->mnt_root;

976         mnt->mnt_parent = mnt;

977         up_write(&mnt->mnt_sb->s_umount);

978         free_secdata(secdata);

979         return mnt;

980 out_sb:

981         dput(mnt->mnt_root);

982         deactivate_locked_super(mnt->mnt_sb);

983 out_free_secdata:

984         free_secdata(secdata);

985 out_mnt:

986         free_vfsmnt(mnt);

987 out:

988         return ERR_PTR(error);

989 }

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

vfs_kern_mount()的四个参数分别是文件系统类型,挂载标志,设备名和文件系统私有数据。在挂载sysfs中,这四个参数的实例分别为sysfs_fs_typeMS_KERNMOUNT"sysfs"NULL。没有挂载目录,可见这个函数完成的都是与vfsmountsuper_block有关的工作。来看下在我们挂载sysfs文件系统的过程中vfs_kern_mount()的操作:

a.调用alloc_vfsmnt(name)vfsmount缓冲mnt_cache中分配vfsmount对象,分配内核缓冲区,将设备名复制到该内核缓冲区,并使vfsmount对象的mnt_devname字段指向这个缓冲区,然后初始化它的部分其他字段,并将其地址保存在局部变量mnt中。

b.设置mnt的挂载标志字段mnt->mnt_flagsMNT_INTERNAL

c.调用sysfs_fs_typeget_sb()方法来分配并初始化一个超级块结构,一个sysfs的超级块结构。这才是让我们牵肠挂肚的那条语句啊。在这里我们也来看一下sysfs_fs_type的定义:

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

fs/sysfs/mount.c

75 static int sysfs_get_sb(struct file_system_type *fs_type,

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

77 {

78   return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);

79 }

 

81 static struct file_system_type sysfs_fs_type = {

82         .name           = "sysfs",

83         .get_sb         = sysfs_get_sb,

84         .kill_sb        = kill_anon_super,

85 };

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

上面的那个get_sb()方法也即是sysfs_get_sb()函数。sysfs_get_sb()函数也是以传递进来的参数为依据,来形成适当的参数调用get_sb_single()而已。get_sb_single()的几个参数分别为sysfs_fs_typeMS_KERNMOUNTNULLsysfs_fill_super和刚刚获得的mnt

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

fs/super.c

899 int get_sb_single(struct file_system_type *fs_type,

900         int flags, void *data,

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

902         struct vfsmount *mnt)

903 {

904         struct super_block *s;

905         int error;

906

907         s = sget(fs_type, compare_single, set_anon_super, NULL);

908         if (IS_ERR(s))

909                 return PTR_ERR(s);

910         if (!s->s_root) {

911                 s->s_flags = flags;

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

913                 if (error) {

914                         deactivate_locked_super(s);

915                         return error;

916                 }

917                 s->s_flags |= MS_ACTIVE;

918         } else {

919                 do_remount_sb(s, flags, data, 0);

920         }

921         simple_set_mnt(mnt, s);

922         return 0;

923 }

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

(1).调用sget()函数分配新的super_block对象,传递set_anon_super函数的地址作为参数。sget()函数会调用alloc_super(type)来分配一个super_block对象,alloc_super()如下处理新分配的super_block对象的各个字段:

INIT_LIST_HEAD(&s->s_files);

INIT_LIST_HEAD(&s->s_instances);

INIT_HLIST_HEAD(&s->s_anon);

INIT_LIST_HEAD(&s->s_inodes);

INIT_LIST_HEAD(&s->s_dentry_lru);

init_rwsem(&s->s_umount);

mutex_init(&s->s_lock);

lockdep_set_class(&s->s_umount, &type->s_umount_key);

/*

* The locking rules for s_lock are up to the

* filesystem. For example ext3fs has different

* lock ordering than usbfs:

*/

lockdep_set_class(&s->s_lock, &type->s_lock_key);

/*

* sget() can have s_umount recursion.

*

* When it cannot find a suitable sb, it allocates a new

* one (this one), and tries again to find a suitable old

* one.

*

* In case that succeeds, it will acquire the s_umount

* lock of the old one. Since these are clearly distrinct

* locks, and this object isn't exposed yet, there's no

* risk of deadlocks.

*

* Annotate this by putting this lock in a different

* subclass.

*/

down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);

s->s_count = S_BIAS;

atomic_set(&s->s_active, 1);

mutex_init(&s->s_vfs_rename_mutex);

mutex_init(&s->s_dquot.dqio_mutex);

mutex_init(&s->s_dquot.dqonoff_mutex);

init_rwsem(&s->s_dquot.dqptr_sem);

init_waitqueue_head(&s->s_wait_unfrozen);

s->s_maxbytes = MAX_NON_LFS;

s->dq_op = sb_dquot_ops;

s->s_qcop = sb_quotactl_ops;

s->s_op = &default_op;

s->s_time_gran = 1000000000;

接下来,sget()函数会调用set_anon_super函数,用合适的方式设置超级块的s_dev字段:主设备号为0,次设备号不同于其他已安装的特殊文件系统。并设置super_block对象的s_bdi字段:

s->s_dev = MKDEV(0, dev & MINORMASK);

s->s_bdi = &noop_backing_dev_info;

随后sget()将设置super_block对象的s_type指向文件系统类型,文件系统名称type->name复制给super_block对象的s_id字段,将超级块对象添加进超级块对象链表super_blocks,将超级块对象添加进文件系统的同文件系统类型超级块链表type->fs_supers中。增加文件系统所在的文件系统的模块的引用计数。

(2).设置超级块的挂载标志字段为传递进来的挂载标志,也就是MS_KERNMOUNT。调用传递进来的方法fill_super()来进一步设置超级块对象,这个方法主要完成创建sysfs文件系统根目录目录项的工作。后面详细说明。

设置超级块挂在标志的MS_ACTIVE位。

(3).调用 simple_set_mnt(mnt, s)来将超级块对象和vfsmount对象mnt联系起来,其本质上是设置mnt->mnt_sb为超级块的地址,设置mnt->mnt_root为指向超级块的文件系统根目录的目录项,并增加该目录项引用计数。这个目录项在特定文件系统的fill_super()中构建。

(4).返回0

d. vfs_kern_mount()中设置mnt->mnt_mountpointmnt->mnt_root,设置mnt->mnt_parent指向mnt

e.返回mnt。在此,总结一下vfsmount对象个字段的值:

alloc_vfsmnt()分配

       atomic_set(&mnt->mnt_count, 1);

       INIT_LIST_HEAD(&mnt->mnt_hash);

       INIT_LIST_HEAD(&mnt->mnt_child);

       INIT_LIST_HEAD(&mnt->mnt_mounts);

       INIT_LIST_HEAD(&mnt->mnt_list);

       INIT_LIST_HEAD(&mnt->mnt_expire);

       INIT_LIST_HEAD(&mnt->mnt_share);

       INIT_LIST_HEAD(&mnt->mnt_slave_list);

       INIT_LIST_HEAD(&mnt->mnt_slave);

#ifdef CONFIG_SMP

       mnt->mnt_writers = alloc_percpu(int);

       if (!mnt->mnt_writers)

           goto out_free_devname;

#else

       mnt->mnt_writers = 0;

 

mnt->mnt_flags = MNT_INTERNAL;

mnt->mnt_sb = sb

mnt->mnt_root = sb->s_root

mnt->mnt_mountpoint = mnt->mnt_root

mnt->mnt_parent = mnt

5sysfs_init()将返回的vfsmount对象地址保存在静态变量sysfs_mount中。sysfsvfsmount对象没有被添加进vfsmount对象哈希表中。
阅读(1074) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~