当内核被编译时,就已经确定了可以支持哪些文件系统,这些文件系统在系统引导时,在 VFS 中进行注册。如果文件系统是作为内核可装载的模块,则在实际安装时进行注册,并在模块卸载时注销。每个文件系统都有一个初始化例程,它的作用就是在 VFS 中进行注册,即填写一个叫做 file_system_type的数据结构,该结构包含了文件系统的名称以及一个指向对应的 VFS 超级块读取例程的地址,所有已注册的文件系统的file_system_type结构形成一个链表,为区别后面将要说到的已安装的文件系统形成的另一个链表,我们把这个链表称为注册链表。图8.7所示就是内核中的
file_system_type 链表,链表头由 file_systems 变量指定。
图8.7 已注册的文件系统形成的链表
图8.7 仅示意性地说明系统中已安装的三个文件系统Ext2、proc、iso9660其file_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,这些文件系统如Ext2、Minix、ufs等。
(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:这个域是Linux
搞清楚这个数据结构的各个域以后,就很容易理解下面的注册函数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;
}