安装根文件系统分为两个阶段:
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);
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. }
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特殊文件系统没有被卸载,他只是隐藏在基于磁盘的根文件系统下了。