因为Linux支持模块机制,所以我们可以将文件系统编译为模块,所以文件系统系统类型的注册的注册有多种方式:要么已经包含在内核映像中,要么作为一个模块被动态加载。我们关注的重点是rootfs和sysfs,他们其实在系统初始化的时候就注册并安装好了,没有rootfs,linux就没法玩了。以rootfs的注册为例,来分析一下文件系统类型的注册:
在start_kernel-->vfs_caches_init(totalram_pages);
vfs_caches_init函数如下:
- void __init vfs_caches_init(unsigned long mempages)
- {
- unsigned long reserve;
- /* Base hash sizes on available memory, with a reserve equal to
- 150% of current kernel size */
- reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1);
- mempages -= reserve;
- names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
- dcache_init();
- inode_init();
- files_init(mempages);
- mnt_init();
- bdev_cache_init();
- chrdev_init();
- }
inode_init(); //索引节点的缓存
files_init(mempages); //file的缓存
mnt_init();
bdev_cache_init(); //块设备的缓存
chrdev_init(); //字符设备的初始化,在《 linux设备模型之字符设备 》中会看到字符设备文件是如何建立的。
目前我们关注的重点是mnt_init(),其中有这么几行代码:
- err = sysfs_init();
- if (err)
- printk(KERN_WARNING "%s: sysfs_init error: %d\n",
- __func__, err);
- fs_kobj = kobject_create_and_add("fs", NULL);
- if (!fs_kobj)
- printk(KERN_WARNING "%s: kobj create error\n", __func__);
- init_rootfs();
- init_mount_tree();
这一次我们只看init_rootfs():
在fs/ramfs/inode.c中:
- int __init init_rootfs(void)
- {
- int err;
- err = bdi_init(&ramfs_backing_dev_info);
- if (err)
- return err;
- err = register_filesystem(&rootfs_fs_type);
- if (err)
- bdi_destroy(&ramfs_backing_dev_info);
- return err;
- }
- static struct file_system_type rootfs_fs_type = {
- .name = "rootfs",
- .get_sb = rootfs_get_sb,
- .kill_sb = kill_litter_super,
- };
其实这个注册过程很简单,其实就是加入链表的过程:
为了证明链表的存在:还是要给出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;
- };
仔细看一下这个结构体,可以看到貌似有两个链表:struct file_system_type * next;单项链表和struct list_head fs_supers;这个linux内核经典的双向链表。
往后,我们会看到这两个链表各自是怎么串的,串的是什么内容。而在register_filesystem中我们就可以看到struct file_system_type * next;单项链表的形成。
register_filesystem函数如下:
- 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; //1
- INIT_LIST_HEAD(&fs->fs_supers); //2
- write_lock(&file_systems_lock);
- p = find_filesystem(fs->name, strlen(fs->name)); //3
- if (*p)
- res = -EBUSY;
- else
- *p = fs;
- write_unlock(&file_systems_lock);
- return res;
- }
2、初始化fs->fs_supers;
3、将即将注册的文件系统放在链表的尾部:
find_filesystem函数如下:
- 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;
- }
可以清楚的看到:通过二级指针来遍历当前的链表,并将文件系统类型通过next指针挂载链表尾部,链表头为file_systems。
到此,文件系统类型的注册就结束了,简单说:就是将文件类型加入以file_systems为表头的单向链表中。