您的位置:首页 > 其它

文件系统注册注销,模块输出file_systems链表文件系统类型

2015-12-13 13:21 435 查看

一、文件系统注册

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



在Linux中,系统有一个file_system_type类型的全局变量file_systems,用来保存所有已经注册到系统中的文件系统。在mount文件系统时,会判断系统是否是已注册的文件系统:

static struct file_system_type *file_systems;


file_system_type结构体

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;
};


name:文件系统的名字,这个名字唯一的标识一种文件系统

get_sb:这个函数非常重要,它是VFS能够和底层文件系统交互的起始点,该函数是不能放在super_block结构中的,因为super_block是在get_sb执行之后才能建立的。get_sb从底层文件系统获取super_block的信息,是和底层文件系统相关的;在安装文件系统时,调用指针所指向的函数在磁盘中获取super_block

kill_sb:卸载文件系统时,调用此指针所指函数进行一些清理工作;

owner是指向module的指针,仅当文件系统类型是以模块方式注册时,owner才有效。

next:系统所有已经注册的文件系统形成一个链表,头指针为全局变量file_systems,这个字段指向链表中下一个文件系统类型指针。

fs_supers:对于每一个mount的文件系统,系统都会为它创建一个super_block数据结构,该结构保存文件系统本身以及挂载点相关的信息。由于可以同时挂载多个同一文件系统类型的文件系统(比如/ 和/home都挂载了ext3文件系统),因此同一个文件系统类型会对应多个super block,fs_supers就把同一个文件系统类型对应的所有super block链接起来,形成一个双链表。

新的文件系统注册到内核时,将扫描该链表,直至到达链表尾部或找到所需的文件系统。如果在链表中找到所需文件系统,会返回一个适当的错误信息,这是因为一个文件系统不能注册两次;否则将描述新文件系统的对象置于链表末尾,这样就完成了文件系统的注册;

Linux文件系统中,文件系统注册都是已register_filesystem()函数开始:

/**
*   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;
BUG_ON(strchr(fs->name, '.'));
if (fs->next)   //fs存在next,则指向的是已被注册的文件系统,那么返回错误信息
return -EBUSY;
INIT_LIST_HEAD(&fs->fs_supers);  // 初始化指向相同文件系统类型super_block的链表
write_lock(&file_systems_lock);  //文件系统链表操作须互斥进行,需要先进行加锁工作

p = find_filesystem(fs->name, strlen(fs->name));    //在file_systems(已注册)链表中查找是否存在fs文件系统类型

// p不为空,那么说明该文件系统已经存在,那么直接返回;
//为空,说明find_filesystem函数已经搜索到链表的最后,
//那么就要在此添加一个新的节点,内容就是要挂载的fs的信息
if (*p)
res = -EBUSY;
else
*p = fs;
write_unlock(&file_systems_lock);
return res;
}


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)    //遍历file_systems链表

if (strlen((*p)->name) == len &&strncmp((*p)->name, name, len) == 0)
break;
return p;
}


二、文件系统注销

/* 注销file_systems链表中fs指向的文件系统 */
int unregister_filesystem(struct file_system_type * fs)
{
struct file_system_type ** tmp;        //申请一个类型为struct file_system*的指针tmp
write_lock(&file_systems_lock);    //获得保护单链表的锁

tmp = &file_systems;        //给指针tmp赋值为指向单链表头那个指针变量的地址

while (*tmp) {            // 判断tmp是否为空

if (fs == *tmp) {        //判断tmp中的内容是否等于要注销的文件系统描述结构体首地址;若相等,则将该fs指向的结构体从单链表中摘除,并返回成功
*tmp = fs->next;        //tmp中存放fs指向的结构体的next地址,即就是将fs的下一个结构体地址存放在tmp,以在链表中去掉fs
fs->next = NULL;
write_unlock(&file_systems_lock);
return 0;
}
tmp = &(*tmp)->next;        //将tmp赋值为指向下一个结构体的指针next的地址
}
write_unlock(&file_systems_lock);        //释放锁
return -EINVAL;

}


整个函数的操作就是:查找文件系统链表,若找到需要注销的文件系统描述结构就将该结构从链表上摘除。在整个操作单链表的过程中它只使用了一个临时指针变量,申请的临时指针变量不是直接指向单链表中的结构体的,而是指向的“指向结构体的指针”(二级指针),二级指针一般用在需要修改函数外部指针的情况。因为函数外部的指针变量,只有通过二级指针解引用得到外部指针变量在内存单元的地址,修改这个地址所指向的内容即可。

对于二级指针的认识,可以参看文章http://www.fenesky.com/blog/2014/07/03/pointers-to-pointers.html

三、打印file_systems链表中文件系统类型

获取file_systems和file_systems_lock的地址

[root@ty ~]# cat /proc/kallsyms | grep file_system
ffffffff81ad2b28 d file_systems_lock
ffffffff81fcb968 b file_systems


注意在使用该地址时,需要在前边加上0x标志,否则会出错

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/init.h>

#define FILE_SYSTEMS_LOCK 0xffffffff81ad2b28
#define FILE_SYSTEMS      0xffffffff81fcb968

static int __init fs_init(void)
{
struct file_system_type **tmp;

read_lock((rwlock_t *)FILE_SYSTEMS_LOCK);    //读file_systems链表时需要加读锁
tmp = (struct file_system_type **)FILE_SYSTEMS;    //tmp指向链表头
printk("input fs_type from kernel\n");
while(*tmp){
printk("fs_name: %s\n",(*tmp)->name);  //"(*tmp)->name"为指向字符串的指针类型,用%s打印出name指向的字符串值
tmp = &(*tmp)->next;
}
read_unlock((rwlock_t *)FILE_SYSTEMS_LOCK);
return 0;
}

static void __exit fs_exit(void)
{
printk("fs exit...\n");
}

module_init(fs_init);
module_exit(fs_exit);
MODULE_LICENSE("GPL");


编译插入模块,查看dmesg

input fs_type from kernel
fs_name: sysfs
fs_name: rootfs
fs_name: bdev
fs_name: proc
fs_name: cgroup
fs_name: cpuset
fs_name: tmpfs
fs_name: devtmpfs
fs_name: binfmt_misc
fs_name: debugfs
fs_name: securityfs
...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  文件系统 内核