initrd 挂载根文件系统

挂载并初始化根文件系统rootfs的简单函数调用关系如下:

init/main.c 

    start_kernel --> vfs_cache_init-->mnt_init-->init_rootfs 

                                                                         init_mount_tree-->vfs_kern_mount

                                                                        挂载并初始化根文件系统rootfs,

1.内核启动调用start_kernel函数进行初始化。

asmlinkage void __init start_kernel(void) //init\Main.c:528
{
    buffer_init();
    key_init();
    security_init();
     vfs_caches_init(totalram_pages); // 678行,vfs初始化
    signals_init();
}

2.start_kernel调用vfs_caches_init对vfs进行初始化。

//fs\Dcach.c:2354行
void __init vfs_caches_init(unsigned long mempages)
{
    .......
    dcache_init();
    inode_init();
    files_init(mempages);
     mnt_init();  // mnt初始化
    bdev_cache_init();
    chrdev_init();
}


3.在vfs_caches_init调用fs\namespace.c 2321行的mnt_init函数

void __init mnt_init(void)
{
    
     init_rootfs();     // 初始化rootfs文件系统
    init_mount_tree();  // 初始化加载树
}

4. fs\ramfs第308行的init_rootfs函数初始化rootfs文件系统

int __init init_rootfs(void)
{
    int err;

    err = bdi_init(&ramfs_backing_dev_info);
    if (err)
        return err;

     err  =  register_filesystem( & rootfs_fs_type); // 注册rootfs文件系统
    if (err)
        bdi_destroy(&ramfs_backing_dev_info);

    return err;
}

rootfs文件系统信息fs/ramfs/inode.c

static struct file_system_type rootfs_fs_type = {
    .name        = "rootfs",
     .get_sb         =  rootfs_get_sb,(init_mount_tree会通过调用该函数对rootfs进行初始化)
    .kill_sb    = kill_litter_super,
};

5. 

static void __init init_mount_tree(void)
2286{
2287        struct vfsmount *mnt;
2288        struct mnt_namespace *ns;
2289        struct path root;
2290
2291        mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
2292        if (IS_ERR(mnt))
2293                panic("Can't create rootfs");
2294        ns = create_mnt_ns(mnt);
2295        if (IS_ERR(ns))
2296                panic("Can't allocate initial namespace");
2297
2298        init_task.nsproxy->mnt_ns = ns;
2299        get_mnt_ns(ns);
2300
2301        root.mnt = ns->root;
2302        root.dentry = ns->root->mnt_root;
2303
2304        set_fs_pwd(current->fs, &root);
2305        set_fs_root(current->fs, &root);
2306}


1058struct vfsmount *
1059do_kern_mount(const char *fstype, int flags, const char *name, void *data)
1060{
1061        struct file_system_type *type = get_fs_type(fstype);
1062        struct vfsmount *mnt;
1063        if (!type)
1064                return ERR_PTR(-ENODEV);
1065        mnt = vfs_kern_mount(type, flags, name, data);
1066        if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
1067            !mnt->mnt_sb->s_subtype)
1068                mnt = fs_set_subtype(mnt, fstype);
1069        put_filesystem(type);
1070        return mnt;
1071} 

 879struct vfsmount *
 880vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
 881{
 882        struct vfsmount *mnt;
 883        char *secdata = NULL;
 884        int error;
 885
 886        if (!type)
 887                return ERR_PTR(-ENODEV);
 888
 889        error = -ENOMEM;
 890        mnt = alloc_vfsmnt(name);
 891        if (!mnt)
 892                goto out;
 893
 894        if (flags & MS_KERNMOUNT)
 895                mnt->mnt_flags = MNT_INTERNAL;
 896
 897        if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
 898                secdata = alloc_secdata();
 899                if (!secdata)
 900                        goto out_mnt;
 901
 902                error = security_sb_copy_data(data, secdata);
 903                if (error)
 904                        goto out_free_secdata;
 905        }
 906
 907        error = type->get_sb(type, flags, name, data, mnt);(调用了rootfs的get_sb即rootfs_get_sb)

               *********

  }

 263static int rootfs_get_sb(struct file_system_type *fs_type,
 264        int flags, const char *dev_name, void *data, struct vfsmount *mnt)
 265{
 266        return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super,
 267                            mnt);
 268}

 821int get_sb_nodev(struct file_system_type *fs_type,
 822        int flags, void *data,
 823        int (*fill_super)(struct super_block *, void *, int),
 824        struct vfsmount *mnt)
 825{
 826        int error;
 827        struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
 828
 829        if (IS_ERR(s))
 830                return PTR_ERR(s);
 831
 832        s->s_flags = flags;
 833
 834        error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
 835        if (error) {
 836                deactivate_locked_super(s);
 837                return error;
 838        }
 839        s->s_flags |= MS_ACTIVE;
 840        simple_set_mnt(mnt, s);
 841        return 0;
 842}

fill_super-->simple_fill_super-->new_inode()

                                               d_alloc_root()这里终于看到熟悉的“/"根目录;


回到start_kernel函数,最后一行调用rest_init

rest_init创建内核线程kernel_init,调用do_basic_setup将 initrd的内容压到rootfs文件系统下

接着调用init_post执行initrd下的的init脚本(注意,确实是个脚本,参见initrd解压


rest_init-->kernel_init-->do_basic_setup-->do_init_calls

                                -->init_post

static void __init do_initcalls(void)
{
 initcall_t *call;
 int count = preempt_count();

 for (call = __initcall_start; call < __initcall_end; call++) {
                ··················
                (*call)();     //调用一系列初始化函数
               ···················
}
---------------------------
      __initcall_start和__initcall_end界定了存放初始化函数指针区域的起始地址,即从__initcall_start开始到__initcall_end结束的区域中存放了指向各个初始化函数的函数指针。 由 (*call)()完成各个部分的初始化工作,且便于扩充。


其中有init/initramfs.c rootfs_initcall(populate_rootfs);

#define rootfs_initcall(fn)             __define_initcall("rootfs",fn,rootfs)

populate_rootfs 将 initrd的内容解压到rootfs文件系统下;


821 static noinline int init_post(void)

822     __releases(kernel_lock)

823 {

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

825     async_synchronize_full();

826     free_initmem();

827     mark_rodata_ro();

828     system_state = SYSTEM_RUNNING;

829     numa_default_policy();

830 

831 

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

833 

 //ramdisk_execute_command在kernel_init函数中被初始话为/init,init脚本详解见附录


834     if (ramdisk_execute_command) {   

835         run_init_process(ramdisk_execute_command);

              //带有initrd的内核不会执行以下代码; run_init_process函数不会返回;

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

837                 ramdisk_execute_command);

838     }

839 


840     /*

841      * We try each of these until one succeeds.

842      *

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

844      * trying to recover a really broken machine.

845      */

846     if (execute_command) {

847         run_init_process(execute_command);

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

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

850     }

//带有initrd的内核不会执行以下代码,不带的应该会执行到这里;

851     run_init_process("/sbin/init");

852     run_init_process("/etc/init");

853     run_init_process("/bin/init");

854     run_init_process("/bin/sh");

855 

856     panic("No init found.  Try passing init= option to kernel. "

857           "See Linux Documentation/init.txt for guidance.");

858 }


【1】 init脚本详解参考:http://unixboy.iteye.com/blog/157717

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值