Linux虚拟文件系统(安装根文件系统)
安装根文件系统分为两个阶段:
1,内核安装特殊rootfs文件系统,该文件系统仅提供一个作为初始安装点的空目录
start_kernel()->vfs_caches_init()->mnt_init()->init_rootfs()
1. /*初始化根文件系统*/
2. int __init init_rootfs(void)
3. {
4. int err;
5. /*初始化ramfs_backing_dev_info*/
6. err = bdi_init(&ramfs_backing_dev_info);
7. if (err)
8. return err;
9. /*注册rootfs_fs_type文件类型*/
10. err = register_filesystem(&rootfs_fs_type);
11. if (err)/*如果出错,销毁上面初始化的*/
12. bdi_destroy(&ramfs_backing_dev_info);
13.
14. return err;
15. } 1. static struct backing_dev_info ramfs_backing_dev_info = {
2. .name = "ramfs",
3. .ra_pages = 0, /* No readahead */
4. .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK |
5. BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY |
6. BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,
7. }; 1. /**
2. * register_filesystem - register a new filesystem
3. * @fs: the file system structure
4. *
5. * Adds the file system passed to the list of file systems the kernel
6. * is aware of for mount and other syscalls. Returns 0 on success,
7. * or a negative errno code on an error.
8. *
9. * The &struct file_system_type that is passed is linked into the kernel
10. * structures and must not be freed until the file system has been
11. * unregistered.
12. */
13. /*注册一个新的文件系统*/
14. int register_filesystem(struct file_system_type * fs)
15. {
16. int res = 0;
17. struct file_system_type ** p;
18.
19. BUG_ON(strchr(fs->name, '.'));
20. if (fs->next)
21. return -EBUSY;
22. INIT_LIST_HEAD(&fs->fs_supers);
23. write_lock(&file_systems_lock);
24. /*从system_type链表中查找指定名称的file_system_type*/
25. p = find_filesystem(fs->name, strlen(fs->name));
26. if (*p)
27. res = -EBUSY;
28. else
29. *p = fs;
30. write_unlock(&file_systems_lock);
31. return res;
32. } 根文件系统定义如下
1. static struct file_system_type rootfs_fs_type = {
2. .name = "rootfs",
3. .get_sb = rootfs_get_sb,
4. .kill_sb = kill_litter_super,
5. }; 下面看看他的两个函数
1. /*获得根目录的sb*/
2. static int rootfs_get_sb(struct file_system_type *fs_type,
3. int flags, const char *dev_name, void *data, struct vfsmount *mnt)
4. {
5. return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super,
6. mnt);
7. } 1. int get_sb_nodev(struct file_system_type *fs_type,
2. int flags, void *data,
3. int (*fill_super)(struct super_block *, void *, int),
4. struct vfsmount *mnt)
5. {
6. int error;
7. /*获得sb结构*/
8. struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
9.
10. if (IS_ERR(s))
11. return PTR_ERR(s);
12.
13. s->s_flags = flags;
14. /*这里实际调用ramfs_fill_super,对sb结构的属性进行设置*/
15. error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
16. if (error) {
17. deactivate_locked_super(s);
18. return error;
19. }
20. s->s_flags |= MS_ACTIVE;
21. simple_set_mnt(mnt, s);/*设置mnt和sb关联*/
22. return 0;
23. } 1. /**
2. * sget - find or create a superblock
3. * @type: filesystem type superblock should belong to
4. * @test: comparison callback
5. * @set: setup callback
6. * @data: argument to each of them
7. */
8. /*查找或创建一个sb结构*/
9. struct super_block *sget(struct file_system_type *type,
10. int (*test)(struct super_block *,void *),
11. int (*set)(struct super_block *,void *),
12. void *data)
13. {
14. struct super_block *s = NULL;
15. struct super_block *old;
16. int err;
17.
18. retry:
19. spin_lock(&sb_lock);
20. if (test) {
21. list_for_each_entry(old, &type->fs_supers, s_instances) {
22. if (!test(old, data))
23. continue;
24. if (!grab_super(old))
25. goto retry;
26. if (s) {
27. up_write(&s->s_umount);
28. destroy_super(s);
29. }
30. return old;
31. }
32. }
33. if (!s) {/*如果找不到sb,从内存中申请一个*/
34. spin_unlock(&sb_lock);
35. s = alloc_super(type);
36. if (!s)
37. return ERR_PTR(-ENOMEM);
38. goto retry;
39. }
40.
41. err = set(s, data);
42. if (err) {
43. spin_unlock(&sb_lock);
44. up_write(&s->s_umount);
45. destroy_super(s);
46. return ERR_PTR(err);
47. }
48. /*初始化得到的sb结构*/
49. s->s_type = type;
50. strlcpy(s->s_id, type->name, sizeof(s->s_id));
51. /*加入链表尾*/
52. list_add_tail(&s->s_list, &super_blocks);
53. list_add(&s->s_instances, &type->fs_supers);
54. spin_unlock(&sb_lock);
55. get_filesystem(type);
56. return s;
57. } 1. /*所有超级块对象都以双向循环链表的形式链接在一起,量表中第一个
2. 元素用super_blocks变量表示,而超级块对象的s_list字段存放指向链表
3. 相邻元素的指针*/
4. LIST_HEAD(super_blocks); 1. /**
2. * alloc_super - create new superblock
3. * @type: filesystem type superblock should belong to
4. *
5. * Allocates and initializes a new &struct super_block. alloc_super()
6. * returns a pointer new superblock or %NULL if allocation had failed.
7. */
8. static struct super_block *alloc_super(struct file_system_type *type)
9. {
10. /*从内存中申请sb*/
11. struct super_block *s = kzalloc(sizeof(struct super_block), GFP_USER);
12. static const struct super_operations default_op;
13.
14. if (s) {
15. if (security_sb_alloc(s)) {
16. kfree(s);
17. s = NULL;
18. goto out;
19. }
20. /*初始化*/
21. INIT_LIST_HEAD(&s->s_files);
22. INIT_LIST_HEAD(&s->s_instances);
23. INIT_HLIST_HEAD(&s->s_anon);
24. INIT_LIST_HEAD(&s->s_inodes);
25. INIT_LIST_HEAD(&s->s_dentry_lru);
26. init_rwsem(&s->s_umount);
27. mutex_init(&s->s_lock);
28. lockdep_set_class(&s->s_umount, &type->s_umount_key);
29. /*
30. * The locking rules for s_lock are up to the
31. * filesystem. For example ext3fs has different
32. * lock ordering than usbfs:
33. */
34. lockdep_set_class(&s->s_lock, &type->s_lock_key);
35. /*
36. * sget() can have s_umount recursion.
37. *
38. * When it cannot find a suitable sb, it allocates a new
39. * one (this one), and tries again to find a suitable old
40. * one.
41. *
42. * In case that succeeds, it will acquire the s_umount
43. * lock of the old one. Since these are clearly distrinct
44. * locks, and this object isn't exposed yet, there's no
45. * risk of deadlocks.
46. *
47. * Annotate this by putting this lock in a different
48. * subclass.
49. */
50. down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
51. s->s_count = S_BIAS;
52. atomic_set(&s->s_active, 1);
53. mutex_init(&s->s_vfs_rename_mutex);
54. mutex_init(&s->s_dquot.dqio_mutex);
55. mutex_init(&s->s_dquot.dqonoff_mutex);
56. init_rwsem(&s->s_dquot.dqptr_sem);
57. init_waitqueue_head(&s->s_wait_unfrozen);
58. s->s_maxbytes = MAX_NON_LFS;
59. s->dq_op = sb_dquot_ops;
60. s->s_qcop = sb_quotactl_ops;
61. s->s_op = &default_op;
62. s->s_time_gran = 1000000000;
63. }
64. out:
65. return s;
66. } kill_litter_super的过程相反,这里不再写了。
构造根目录是由init_mount_tree()函数实现的,该函数在前面已经介绍过了。
2,安装实际根文件系统
关于__setup宏
__setup宏来注册关键字及相关联的处理函数,__setup宏在include/linux/init.h中定义,其原型如下:
__setup(string, _handler);
其中:string是关键字,_handler是关联处理函数。__setup只是告诉内核在启动时输入串中含有string时,内核要去
执行_handler。String必须以“=”符结束以使parse_args更方便解析。紧随“=”后的任何文本都会作为输入传给
_handler。下面的例子来自于init/do_mounts.c,其中root_dev_setup作为处理程序被注册给“root=”关键字:
__setup("root=", root_dev_setup);
比如我们在启动向参数终有
noinitrd root=/dev/mtdblock2 console=/linuxrc
setup_arch解释时会发现root=/dev/mtdblock2,然后它就会调用root_dev_setup
1. static int __init root_dev_setup(char *line)
2. {
3. strlcpy(saved_root_name, line, sizeof(saved_root_name));
4. return 1;
5. }
6.
7. __setup("root=", root_dev_setup); Start_kernel->rest_init->init-> prepare_namespace->
1. /*
2. * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
3. */
4. void __init prepare_namespace(void)
5. {
6. int is_floppy;
7.
8. if (root_delay) {
9. printk(KERN_INFO "Waiting %dsec before mounting root device...\n",
10. root_delay);
11. ssleep(root_delay);
12. }
13.
14. /*
15. * wait for the known devices to complete their probing
16. *
17. * Note: this is a potential source of long boot delays.
18. * For example, it is not atypical to wait 5 seconds here
19. * for the touchpad of a laptop to initialize.
20. */
21. wait_for_device_probe();
22. /*创建/dev/ram0,必须得,因为initrd要放到/dev/ram0里*/
23. md_run_setup();
24.
25. if (saved_root_name[0]) {/*saved_root_name为从启动参数"root"中获取的设备文件名*/
26. root_device_name = saved_root_name;
27. if (!strncmp(root_device_name, "mtd", 3) ||
28. !strncmp(root_device_name, "ubi", 3)) {/*如果设备名开头为这两个*/
29. mount_block_root(root_device_name, root_mountflags);
30. goto out;
31. }
32. /*主设备号和次设备号*/
33. ROOT_DEV = name_to_dev_t(root_device_name);
34. if (strncmp(root_device_name, "/dev/", 5) == 0)
35. root_device_name += 5;/*滤掉'/dev/'字符*/
36. }
37.
38. if (initrd_load())
39. goto out;
40.
41. /* wait for any asynchronous scanning to complete */
42. if ((ROOT_DEV == 0) && root_wait) {
43. printk(KERN_INFO "Waiting for root device %s...\n",
44. saved_root_name);
45. while (driver_probe_done() != 0 ||
46. (ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)
47. msleep(100);
48. async_synchronize_full();
49. }
50.
51. is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
52.
53. if (is_floppy && rd_doload && rd_load_disk(0))
54. ROOT_DEV = Root_RAM0;
55. /*实际操作*/
56. mount_root();
57. out:
58. devtmpfs_mount("dev");/*devfs从虚拟的根文件系统的/dev umount*/
59. sys_mount(".", "/", NULL, MS_MOVE, NULL);/*将挂载点从当前目录【/root】(在mount_root函数中设置的)移到根目录*/
60. /*当前目录即【/root】(真正文件系统挂载的目录)做为系统根目录*/
61. sys_chroot(".");
62. } mount_root操作
1. void __init mount_root(void)
2. {
3. #ifdef CONFIG_ROOT_NFS
4. if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
5. if (mount_nfs_root())
6. return;
7.
8. printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
9. ROOT_DEV = Root_FD0;
10. }
11. #endif
12. #ifdef CONFIG_BLK_DEV_FD
13. if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
14. /* rd_doload is 2 for a dual initrd/ramload setup */
15. if (rd_doload==2) {
16. if (rd_load_disk(1)) {
17. ROOT_DEV = Root_RAM1;
18. root_device_name = NULL;
19. }
20. } else
21. change_floppy("root floppy");
22. }
23. #endif
24. #ifdef CONFIG_BLOCK/*这里是一般流程*/
25. create_dev("/dev/root", ROOT_DEV);/*用系统调用创建"/dev/root"*/
26. mount_block_root("/dev/root", root_mountflags);
27. #endif
28. } 1. void __init mount_block_root(char *name, int flags)
2. {
3. /*从cache中分配空间*/
4. char *fs_names = __getname_gfp(GFP_KERNEL
5. | __GFP_NOTRACK_FALSE_POSITIVE);
6. char *p;
7. #ifdef CONFIG_BLOCK
8. char b[BDEVNAME_SIZE];
9. #else
10. const char *b = name;
11. #endif
12. /*获得文件系统类型,如果在bootoption里有,
13. 则就为这个文件系统类型,如果没有指定,
14. 则返回ilesytem链上所有类型,下面再对每个进行尝试.*/
15. get_fs_names(fs_names);
16. retry:
17. for (p = fs_names; *p; p += strlen(p)+1) {
18. /*实际的安装工作,这里调用了mount系统调用
19. 将文件系统挂到/root目录,p为文件系统类型,由get_fs_names得到
20. */
21. int err = do_mount_root(name, p, flags, root_mount_data);
22. switch (err) {
23. case 0:
24. goto out;
25. case -EACCES:
26. flags |= MS_RDONLY;
27. goto retry;
28. case -EINVAL:
29. continue;
30. }
31. /*
32. * Allow the user to distinguish between failed sys_open
33. * and bad superblock on root device.
34. * and give them a list of the available devices
35. */
36. #ifdef CONFIG_BLOCK
37. __bdevname(ROOT_DEV, b);
38. #endif
39. printk("VFS: Cannot open root device \"%s\" or %s\n",
40. root_device_name, b);
41. printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
42.
43. printk_all_partitions();
44. #ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT
45. printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify "
46. "explicit textual name for \"root=\" boot option.\n");
47. #endif
48. panic("VFS: Unable to mount root fs on %s", b);
49. }
50.
51. printk("List of all partitions:\n");
52. printk_all_partitions();
53. printk("No filesystem could mount root, tried: ");
54. for (p = fs_names; *p; p += strlen(p)+1)
55. printk(" %s", p);
56. printk("\n");
57. #ifdef CONFIG_BLOCK
58. __bdevname(ROOT_DEV, b);
59. #endif
60. panic("VFS: Unable to mount root fs on %s", b);
61. out:
62. putname(fs_names);
63. }
64. 1. static int __init do_mount_root(char *name, char *fs, int flags, void *data)
2. {
3. /*mount系统调用来做实际的安装文件系统工作*/
4. int err = sys_mount(name, "/root", fs, flags, data);
5. if (err)
6. return err;
7. /*改变当前路径到根目录*/
8. sys_chdir("/root");
9. ROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev;
10. printk("VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",
11. current->fs->pwd.mnt->mnt_sb->s_type->name,
12. current->fs->pwd.mnt->mnt_sb->s_flags & MS_RDONLY ?
13. " readonly" : "", MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
14. return 0;
15. } 到此,根文件系统的安装过程算是完成了,中间关于mount等系统调用将在后面分析。可以看出总的步骤主要有:
1,创建一个rootfs,这个是虚拟的rootfs,是内存文件系统(和ramfs),后面还会指向具体的根文件系统;
2,从系统启动参数中获取设备文件名以及设备号;
3,调用系统调用创建符号链接,并调用mount系统调用进程实际的安装操作;
4,改变进程当前目录;
5,移动rootfs文件系统根目录上得已经安装文件系统的安装点;
rootfs特殊文件系统没有被卸载,他只是隐藏在基于磁盘的根文件系统下了。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)