文件系统注册注销,模块输出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 ...
相关文章推荐
- Linux 自检和 SystemTap
- Linux内核链表实现过程
- 文件系统变为raw 无法访问的解决方法
- PHP 文件系统详解
- Powershell实现克隆NTFS文件系统权限
- 深入理解PHP内核(二)之SAPI探究
- C++中Semaphore内核对象用法实例
- 深入理解PHP内核(一)
- 深入php内核之php in array
- php中的filesystem文件系统函数介绍及使用示例
- 用Python编写一个简单的FUSE文件系统的教程
- 【转自中科蓝鲸】集群NAS与集群文件系统的区别
- HBase 系统架构
- 修改内核 内存分配 root、文件系统和内核镜像的位置
- 移植linux-2.6.30.4到S3C2440
- LINUX的EXT2文件系统
- 文件系统的简单操作
- 看《Linux0.11内核完全注释2.01》的方法
- 升级LINUX内核(支持8G内存)的命令
- linux系统查看分区文件系统