掛載並初始化根檔案系統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 }