Coder
分类: LINUX
2010-07-25 09:43:00
文件系统类型
特殊文件系统
为系统程序员和管理员提供一种容易的方式来操作内核的数据结构并实现系统的特殊特征。
特殊文件系统不限于物理设备。然而,内核给每个安装的特殊文件系统分配一个虚拟的块设备让其主设备号是0,而此设备号具有任意值(每个特定文件系统具有不同的值)。set_anon_super()函数用于初始化特殊文件系统的超级块;该函数本质上获得一个未使用的此设备号dev,然后用主设备号0和次设备号dev设置新超级块的s_dev字段。而另一个kill_anon_super()函数移走特殊文件系统的超级块。unnamed_dev_ida变量(fs/super.c, static
DEFINE_IDA(unnamed_dev_ida);)包含一个辅助结构(记录当前在用的次设备号)的指针。
文件系统类型注册
VFS必须对那些代码已经在内核中的所有文件系统的类型进行跟踪。这就是通过进行文件系统类型注册来实现的。每个注册的文件系统类型为file_system_type的对象来描述。其定义如下:
---------------------------------------------------------------------
include/linux/fs.h
struct file_system_type {
const char *name;
int fs_flags;
int (*get_sb) (struct
file_system_type *, int,
const char *, void *, struct vfsmount
*);
void (*kill_sb) (struct
super_block *);
struct module *owner;
struct file_system_type
* next;
struct list_head
fs_supers;
struct lock_class_key
s_lock_key;
struct lock_class_key
s_umount_key;
struct lock_class_key
i_lock_key;
struct lock_class_key
i_mutex_key;
struct lock_class_key
i_mutex_dir_key;
struct lock_class_key
i_alloc_sem_key;
};
---------------------------------------------------------------------
所有文件系统类型的对象都插入到一个单向链表中。由全局变量file_systems指向链表的第一个元素,而结构中的next字段则指向链表的下一个元素。file_systems_lock读/写自旋锁保护整个链表免受同时访问:
---------------------------------------------------------------------
fs/filesystems.c
static struct file_system_type *file_systems;
static DEFINE_RWLOCK(file_systems_lock);
--------------------------------------------------------------------- name: 文件系统类型的名字, 比如
"ext2", "iso9660", "msdos"
等等
fs_flags: 各种标志 (i.e. FS_REQUIRES_DEV, FS_NO_DCACHE,
etc.)
get_sb: 当有一个该文件系统的新的实例被挂载的时候调用的方法,该字段依赖于文件系统类型,该函数分配并初始化一个超级快对象并初始化它。
kill_sb: 当该文件系统的一个实例被卸载的时候调用的方法。
owner: 给VFS内部使用: 在大多数情况下你应该将它初始化为THIS_MODULE。
next: 给VFS内部使用: 你应该将它初始化为NULL
s_lock_key, s_umount_key: lockdep-specific
fs_supers:表示给定类型已安装文件系统所对应的超级快链表的头,链表元素的向后和向前链接存放在超级块对象的s_instances字段中。
get_sb()
方法有下列参数:
struct file_system_type *fs_type: 描述文件系统, 被特定文件系统代码部分的初始化
int flags: 挂载标志
const char *dev_name: 我们挂载的设备的设备名
void *data: 任意的挂载选项, 通常是一个ASCII字符串
struct vfsmount *mnt: 一个挂载点的vfs内部的表示
get_sb()方法必须判断用dev_name和fs_type指定的特定设备是否包含一个该方法支持的文件系统类型。如果它成功的打开了用名字指定的块设备,则为块设备包含的文件系统初始化一个struct super_block描述符。出错时它返回错误。
get_sb()方法最多的是填充超级块结构的成员"s_op"。这是一个指向一个"struct super_operations"的指针,而"struct
super_operations"则描述了文件系统实现的下一个层次。
通常一个文件系统使用某个通用的get_sb()实现并提供fill_super()方法来代替。通用的方法有:
get_sb_bdev: 挂载一个位于一个块设备上的文件系
get_sb_nodev: 挂载一个没有被一个设备支持的文件系统
get_sb_single: 挂载一个mount a filesystem which shares the
instance between all mounts
一个fill_super()方法实现具有如下的参数:
struct super_block *sb: 超级块结构。fill_super()方法必须适当的初始化它。
void *data: 任意的挂载选项,通常是一个ASCII字符串(参考 "挂载选项"
部分)
在系统初始化期间,调用register_filesystem()函数来注册一个文件系统,这个函数定义如下:
---------------------------------------------------------------------
fs/filesystems.c
int register_filesystem(struct file_system_type * fs)
{
int res = 0;
struct file_system_type
** p;
BUG_ON(strchr(fs->name,
'.'));
if (fs->next)
return -EBUSY;
INIT_LIST_HEAD(&fs->fs_supers);
write_lock(&file_systems_lock);
p =
find_filesystem(fs->name, strlen(fs->name));
if (*p)
res = -EBUSY;
else
*p = fs;
write_unlock(&file_systems_lock);
return res;
}
---------------------------------------------------------------------
这个函数初始化fs的fs_supers,也就是连接同类型文件系统的super_block的字段。然后调用find_filesystem()函数来在文件系统类型链表中查找适当的位置,将file_system_type对象插入链表。在注册之前file_system_type需要被适当初始化。
---------------------------------------------------------------------
fs/filesystems.c
static struct file_system_type **find_filesystem(const char
*name, unsigned len)
{
struct file_system_type
**p;
for
(p=&file_systems; *p; p=&(*p)->next)
if
(strlen((*p)->name) == len &&
strncmp((*p)->name, name, len) == 0)
break;
return p;
}
---------------------------------------------------------------------
根据文件系统类型的名字,在文件系统类型链表file_systems中查找。如果找到,则返回连接该file_system_type的file_system_type的next字段的地址,否则返回链表尾file_system_type的next字段的地址
当实现了文件系统的模块被装入时,也要调用register_filesystem()函数。在这种情况下,当该模块卸载时,对应的文件系统可以通过调用unregister_filesystem()函数来注销。unregister_filesystem()函数定义:
---------------------------------------------------------------------
fs/filesystems.c
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;
}
---------------------------------------------------------------------
它完成和register_filesystem()函数相反的工作。
get_fs_type()函数(接收文件系统名作为它的参数)扫描已注册的文件系统链表以查找文件系统类型的name字段,并返回指向相应的file_system_type对象(如果存在)的指针。其定义如下:
---------------------------------------------------------------------
fs/filesystems.c
static struct file_system_type *__get_fs_type(const char *name,
int len)
{
struct file_system_type
*fs;
read_lock(&file_systems_lock);
fs =
*(find_filesystem(name, len));
if (fs &&
!try_module_get(fs->owner))
fs = NULL;
read_unlock(&file_systems_lock);
return fs;
}
struct file_system_type *get_fs_type(const char *name)
{
struct file_system_type
*fs;
const char *dot =
strchr(name, '.');
int len = dot ? dot - name
: strlen(name);
fs =
__get_fs_type(name, len);
if (!fs &&
(request_module("%.*s", len, name) == 0))
fs =
__get_fs_type(name, len);
if (dot && fs
&& !(fs->fs_flags & FS_HAS_SUBTYPE)) {
put_filesystem(fs);
fs = NULL;
}
return fs;
}
---------------------------------------------------------------------
get_fs_type()函数先调用__get_fs_type()函数在已注册文件系统链表中查找,若找到,则递增file_system_type结构中指针owner指向的module结构中的共享计数。如果没找到,则通过request_module装入所需文件系统的可安装模块,然后在扫描队列。