8.4.1  文件系统的注册

当内核被编译时,就已经确定了可以支持哪些文件系统,这些文件系统在系统引导时,在 VFS 中进行注册。如果文件系统是作为内核可装载的模块,则在实际安装时进行注册,并在模块卸载时注销。每个文件系统都有一个初始化例程,它的作用就是在 VFS 中进行注册,即填写一个叫做 file_system_type的数据结构,该结构包含了文件系统的名称以及一个指向对应的 VFS 超级块读取例程的地址,所有已注册的文件系统的file_system_type结构形成一个链表,为区别后面将要说到的已安装的文件系统形成的另一个链表,我们把这个链表称为注册链表。图8.7示就是内核中的 file_system_type 链表,链表头由 file_systems 变量指定。


8.7   已注册的文件系统形成的链表

8.7 仅示意性地说明系统中已安装的三个文件系统Ext2prociso9660file_system_type结构所形成的链表。当然,系统中实际安装的文件系统要更多。

file_system_type的数据结构在fs.h中定义如下:

struct file_system_type {

         const char *name;

         int fs_flags;

         struct super_block *(*read_super) (struct super_block *, void *, int);

         struct module *owner;

         struct file_system_type * next;

         struct list_head fs_supers;

};

对其中几个域的说明如下:

·      name:文件系统的类型名,以字符串的形式出现。

·      fs_flags:指明具体文件系统的一些特性,有关标志定义于fs.h中:

     /* public flags for file_system_type */

        #define FS_REQUIRES_DEV 1

#define FS_NO_DCACHE    2 /* Only dcache the necessary things. */

    #define FS_NO_PRELIM    4 /* prevent preloading of dentries, even if

                            * FS_NO_DCACHE is not set.

                           */

#define FS_SINGLE       8 /* Filesystem that can have only one superblock */

#define FS_NOMOUNT      16 /* Never mount from userland */

#define FS_LITTER       32 /* Keeps the tree in dcache */

#define FS_ODD_RENAME   32768   /* Temporary stuff; will go away as soon

                                  * as nfs_rename() will be cleaned up

                                   */

     对某些常用标志的说明如下:

(1)     有些虚拟的文件系统,如pipe、共享内存等,根本不允许由用户进程通过系统调用mount()来安装。这样的文件系统其fs_flags中的FS_NOMOUNT标志位为1

(2)     一般的文件系统类型要求有物理的设备作为其物质基础,其fs_flags中的FS_REQUIRES_DEV标志位为1,这些文件系统如Ext2Minixufs等。

(3)     有些虚拟文件系统在安装了同类型中的第一个“设备”,从而创建了其超级块的super_block数据结构,在安装同一类型中的其他设备时就共享已存在的super_block结构,而不再有自己的超级块结构。此时fs_flags中的FS_SINGLE标志位为1,表示整个文件系统只有一个超级块,而不像一般的文件系统类型那样,每个具体的设备上都有一个超级块。

·      read_super:这是各种文件系统读入其超级块的函数指针。因为不同的文件系统其超级块不同,因此其读入函数也不同。

·      owner:如果file_system_type所代表的文件系统是通过可安装模块实现的,则该指针指向代表着具体模块的module结构。如果文件系统是静态地链接到内核,则这个域为NULL。实际上,你只需要把这个域置为THIS_MODLUE (这是个一个宏),它就能自动地完成上述工作。

·      next:把所有的file_system_type结构链接成单项链表的链接指针,变量file_systems指向这个链表。这个链表是一个临界资源,受file_systems_lock自旋读写锁的保护。

·      fs_supers:这个域是Linux2.4.10以后的内核版本中新增加的,这是一个双向链表。链表中的元素是超级块结构。如前说述,每个文件系统都有一个超级块,但有些文件系统可能被安装在不同的设备上,而且每个具体的设备都有一个超级块,这些超级块就形成一个双向链表。

 搞清楚这个数据结构的各个域以后,就很容易理解下面的注册函数register_filesystem(),该函数定义于fs/super.c

      **

      *      register_filesystem - register a new filesystem

      *      @fs: the file system structure

*

*      Adds the file system passed to the list of file systems the kernel

*      is aware of for mount and other syscalls. Returns 0 on success,

*      or a negative errno code on an error.

*

*      The &struct file_system_type that is passed is linked into the kernel

*      structures and must not be freed until the file system has been

*      unregistered.

 */

   

int register_filesystem(struct file_system_type * fs)

{

        int res = 0;

         struct file_system_type ** p;

 

         if (!fs)

                 return -EINVAL;

         if (fs->next)

                return -EBUSY;

         INIT_LIST_HEAD(&fs->fs_supers);

        write_lock(&file_systems_lock);

         p = find_filesystem(fs->name);

         if (*p)

                res = -EBUSY;

         else

                *p = fs;

         write_unlock(&file_systems_lock);

        return res;

}

find_filesystem()函数在同一个文件中定义如下:

  static struct file_system_type **find_filesystem(const char *name)

{

         struct file_system_type **p;

        for (p=&file_systems; *p; p=&(*p)->next)

                 if (strcmp((*p)->name,name) == 0)

                         break;

        return p;

}

注意,对注册链表的操作必须互斥地进行,因此,对该链表的查找加了写锁write_lock

 

文件系统注册后,还可以撤消这个注册,即从注册链表中删除一个file_system_type 结构,此后系统不再支持该种文件系统。fs/super.c中的unregister_filesystem()函数就是起这个作用的,它在执行成功后返回0,如果注册链表中本来就没有指定的要删除的结构,则返回-1,其代码如下:

/**

*      unregister_filesystem - unregister a file system

*      @fs: filesystem to unregister

*

*      Remove a file system that was previously successfully registered

*      with the kernel. An error is returned if the file system is not found.

*      Zero is returned on a success.

*     

*      Once this function has returned the &struct file_system_type structure

*      may be freed or reused.

*/

 

int unregister_filesystem(struct file_system_type * fs)

{

        struct file_system_type ** tmp;

 

         write_lock(&file_systems_lock);

         tmp = &file_systems;

         while (*tmp) {

                if (fs == *tmp) {

                        *tmp = fs->next;

                        fs->next = NULL;

                         write_unlock(&file_systems_lock);

                        return 0;

                 }

                tmp = &(*tmp)->next;

         }

         write_unlock(&file_systems_lock);

         return -EINVAL;

  }