根文件系统的挂载过程

当内核启动的时候,会先注册和挂载一个虚拟的根文件系统,也就是rootfs,然后会把做好的initramfs(这个可以自己制作)中的文件解压到rootfs中。然后系统会挂载真的根文件系统;

01void __init vfs_caches_init(unsigned long mempages)

02{

03    unsigned long reserve;

04

05    /* Base hash sizes on available memory, with a reserve equal to

06           150% of current kernel size */

07

08    reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1);

09    mempages -= reserve;

10

11    names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,

12                  SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);

13

14    dcache_init();  //页目录缓存的初始化

15    inode_init();     //索引结点缓存的初始化

16    files_init(mempages);

17    mnt_init();           //  虚拟文件系统挂载的初始化, 主要是挂载节点的初始化化和把目录设置为当前挂载点目录

18    bdev_cache_init();

19    chrdev_init();

20}


根节点创建好了,然后是解压 initramfs。populate_rootfs函数是通过do_initcalls()时被调用执行的

static int __init populate_rootfs(void)

02{

03    char *err = unpack_to_rootfs(__initramfs_start,

04                  __initramfs_end - __initramfs_start);


05    if (err)

06           panic(err);      /* Failed to decompress INTERNAL initramfs */

07    if (initrd_start) {

08#ifdef CONFIG_BLK_DEV_RAM

09           int fd;

10           printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n");

11           err = unpack_to_rootfs((char *)initrd_start,

12                  initrd_end - initrd_start);

13           if (!err) {

14                  free_initrd();

15                  return 0;

16           } else {

17                  clean_rootfs();

18                  unpack_to_rootfs(__initramfs_start,

19                         __initramfs_end - __initramfs_start);

20           }

21           printk(KERN_INFO "rootfs image is not initramfs (%s)"

22                         "; looks like an initrd\n", err);

23           fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);

24           if (fd >= 0) {

25                  sys_write(fd, (char *)initrd_start,

26                                initrd_end - initrd_start);

27                  sys_close(fd);

28                  free_initrd();

29           }

30#else

31           err = unpack_to_rootfs((char *)initrd_start,

32                  initrd_end - initrd_start);

33           if (err)

34                  printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);

35           free_initrd();

36#endif

37    }

38    return 0;

39}



解压完然后是挂载

01void __init prepare_namespace(void)

02{

03    int is_floppy;

04    if (root_delay) {

05           printk(KERN_INFO "Waiting %dsec before mounting root device...\n",

06                  root_delay);

07           ssleep(root_delay);

08    }

09

10    /*

11    * wait for the known devices to complete their probing

12    *

13    * Note: this is a potential source of long boot delays.

14    * For example, it is not atypical to wait 5 seconds here

15    * for the touchpad of a laptop to initialize.

16    */

17    wait_for_device_probe();

18

19    md_run_setup();

20

21    if (saved_root_name[0]) {

22           root_device_name = saved_root_name;

23           if (!strncmp(root_device_name, "mtd", 3) ||

24               !strncmp(root_device_name, "ubi", 3)) {

25                  mount_block_root(root_device_name, root_mountflags);

26                  goto out;

27           }

28           ROOT_DEV = name_to_dev_t(root_device_name);

29           if (strncmp(root_device_name, "/dev/", 5) == 0)

30                  root_device_name += 5;

31}

32

33    if (initrd_load())

34                  goto out;

35

36    /* wait for any asynchronous scanning to complete */

37    if ((ROOT_DEV == 0) && root_wait) {

38           printk(KERN_INFO "Waiting for root device %s...\n",

39                  saved_root_name);

40           while (driver_probe_done() != 0 ||

41                  (ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)

42                  msleep(100);

43           async_synchronize_full();

44    }

45

46    is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;

47

48    if (is_floppy && rd_doload && rd_load_disk(0))

49           ROOT_DEV = Root_RAM0;

50

51    mount_root();

52out:

53    sys_mount(".", "/", NULL, MS_MOVE, NULL);

54    sys_chroot(".");

55}

第21行检查saved_root_name是否为真,这里是有值的。

第22行把它赋给root_device_name,此时为/dev/mtdblock3

第23-27行不执行

第25行挂载根文件系统

第28行名字到设备号的转变,这个设备号是设备的设备号,下面会用到的。我这里是flash的第三个分区

第29行/dev/mtdblock3的前5个字符与/dev/比较,这里是相等的。

第30行root_device_name加5,所以此时root_device_name为mtdblock3.

第37-44行由于设备号不为0,所以这里面没有执行。

第53行移动根文件系统的根目录为/

01void __init mount_block_root(char *name, int flags)

02{

03    char *fs_names = __getname();

04    char *p;

05#ifdef CONFIG_BLOCK

06    char b[BDEVNAME_SIZE];

07#else

08    const char *b = name;

09#endif

10

11    get_fs_names(fs_names);

12retry:

13    for (p = fs_names; *p; p += strlen(p)+1) {

14           int err = do_mount_root(name, p, flags, root_mount_data);

15           switch (err) {

16                  case 0:

17                         goto out;

18                  case -EACCES:

19                         flags |= MS_RDONLY;

20                         goto retry;

21                  case -EINVAL:

22                         continue;

23           }

24            /*

25           * Allow the user to distinguish between failed sys_open

26           * and bad superblock on root device.

27           * and give them a list of the available devices

28           */

29#ifdef CONFIG_BLOCK

30           __bdevname(ROOT_DEV, b);

31#endif

32           printk("VFS: Cannot open root device \"%s\" or %s\n",

33                         root_device_name, b);

34           printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");

35

36           printk_all_partitions();

37#ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT

38           printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify "

39                  "explicit textual name for \"root=\" boot option.\n");

40#endif

41           panic("VFS: Unable to mount root fs on %s", b);

42    }

43

44    printk("List of all partitions:\n");

45    printk_all_partitions();

46    printk("No filesystem could mount root, tried: ");

47    for (p = fs_names; *p; p += strlen(p)+1)

48           printk(" %s", p);

49    printk("\n");

50#ifdef CONFIG_BLOCK

51    __bdevname(ROOT_DEV, b);

52#endif

53    panic("VFS: Unable to mount root fs on %s", b);

54out:

55    putname(fs_names);

56}

第3行申请空间

第11行fs_name指向内核里面编译文件系统的第一个

第13行循环把这些文件系统挂到根目录下,我的内核里面分别有,ext3,ext3,vfat等,这里用到的是yaffs文件系统

第14行调用do_mount_root函数进行挂载

第15行返回的结果0

第17行增加对文件系统的引用

01static int __init do_mount_root(char *name, char *fs, int flags, void *data)

02{

03    int err = sys_mount(name, "/root", fs, flags, data);

04    if (err)

05           return err;

06

07    sys_chdir("/root");

08    ROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev;

09    printk("VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",

10           current->fs->pwd.mnt->mnt_sb->s_type->name,

11           current->fs->pwd.mnt->mnt_sb->s_flags & MS_RDONLY ?

12           " readonly" : "", MAJOR(ROOT_DEV), MINOR(ROOT_DEV));

13    return 0;

14}

第3行挂载文件系统,这里的name为/dev/root,fs为文件的类型,这里是yaffs2,文件类型当然还是ext3,ext2等。

第7行改变到/root目录下

第9行分别显示出挂载出根文件系统和主次设备号,这里是yaffs文件系统,主:次31:3

01void __init mount_root(void)

02{

03#ifdef CONFIG_ROOT_NFS

04    if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {

05           if (mount_nfs_root())

06                  return;

07

08           printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");

09           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);

26    mount_block_root("/dev/root", root_mountflags);

27#endif

28}

这里只执行了CONFI_BLOCK宏开关

第25行创建设备结点,这里我在ubutu上测试了一下,/dev/root是的连接是hda1

第26行挂载根文件系统

第五部分运行真正根目录中的init程序

01static noinline int init_post(void)

02    __releases(kernel_lock)

03{

04    /* need to finish all async __init code before freeing the memory */

05    async_synchronize_full();

06    free_initmem();

07    unlock_kernel();

08    mark_rodata_ro();

09    system_state = SYSTEM_RUNNING;

10    numa_default_policy();

11

12    if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)

13           printk(KERN_WARNING "Warning: unable to open an initial console.\n");

14

15    (void) sys_dup(0);

16    (void) sys_dup(0);

17

18    current->signal->flags |= SIGNAL_UNKILLABLE;

19

20    if (ramdisk_execute_command) {

21           run_init_process(ramdisk_execute_command);

22           printk(KERN_WARNING "Failed to execute %s\n",

23                         ramdisk_execute_command);

24    }

25

26    /*

27    * We try each of these until one succeeds.

28    *

29    * The Bourne shell can be used instead of init if we are

30    * trying to recover a really broken machine.

31    */

32    if (execute_command) {

33           run_init_process(execute_command);

34           printk(KERN_WARNING "Failed to execute %s.  Attempting "

35                                "defaults...\n", execute_command);

36    }

37    run_init_process("/sbin/init");

38    run_init_process("/etc/init");

39    run_init_process("/bin/init");

40    run_init_process("/bin/sh");

41

42    panic("No init found.  Try passing init= option to kernel.");

43}

第12行打开/dev/console设备文件

第15-16行将文件描述符0复制给文件描述符1和2。

第20-24行ramdisk_execute_command变量中如果指定了要运行的程序,就开始运行这个程序,在u-boot的命令行参数中会指定rdinit=…,这个时候ramdisk_execute_command等于这个参数指定的程序。也可能/init程序存在,哪么ramdisk_execute_command就等于/init,或者为空。本程序没有指定,所以这里为空。

第37行执行/sbin/init程序,这个程序存在于根文件系统,如果存在,执行它,系统的控制权交给/sbin/init,不再返回init_post函数


你可能感兴趣的:(linux系统)