本文相对简单得罗列出函数调用层次
start_kernel()
--> vfs_caches_init_early()
--> dcache_init_early()
// 创建目录项hash表,并将hash表每个入口指针均置成NULL
--> inode_init_early()
// 创建文件节点hash表,并将hash表每个入口指针均置成NULL
--> vfs_caches_init(num_physpages)
--> names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL)
// 创建slub高速缓存组names_cache,被格式化成PATH_MAX = 4096,该高缓用指针names_cachep指向的
// struct kmem_cache 结构体描述
--> dcache_init()
--> dentry_cache = KMEM_CACHE(dentry,SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD)
// 创建slub高速缓存组dentry,被格式化成struct dentry,该高缓用指针dentry_cache指向的
// struct kmem_cache 结构体描述
--> register_shrinker(&dcache_shrinker)
// 注册针对dentry高缓的页面回收函数shrink_dcache_memory,由页面回收算法(PFRA)来定期执行
--> inode_init()
--> inode_cachep = kmem_cache_create("inode_cache",
sizeof(struct inode),
0,
(SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD),
init_once);
// 创建slub高速缓存组inode_cache,被格式化成struct inode,该高缓用指针inode_cachep指向的
// struct kmem_cache 结构体描述
--> register_shrinker(&icache_shrinker)
// 注册针对inode_cache高缓的页面回收函数shrink_icache_memory,由页面回收算法(PFRA)来定期执行
--> files_init(mempages)
--> filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
// 创建slub高速缓存组filp,被格式化成struct file,该高缓用指针filp_cachep指向的
// struct kmem_cache 结构体描述
--> files_stat.max_files = ?
// 设置全局结构体对象的max_files域
--> ..
--> mnt_init() // 非常重要函数
--> mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount),
0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL)
// 创建名为mnt_cache的slab高速缓存,格式化成struct vfsmount,由指针mnt_cache指向的结构体描述
--> 必须分配到一页物理内存作为mount_hashtable数组的空间,同时将该hash表每个入口项的指针next、prev
初始化成NULL
--> sysfs_init() // sys文件系统初始化,注册,挂载
--> sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
sizeof(struct sysfs_dirent),
0, 0, NULL);
--> sysfs_inode_init()
--> register_filesystem(&sysfs_fs_type)
// 注册,将sysfs的描述结构体sysfs_fs_type挂接到全局链表file_system中
--> kern_mount(&sysfs_fs_type)
// 挂载sysfs,该函数后面再rootfs时也会用,所以在后面分析它
--> kobject_create_and_add("fs", NULL)
// 在sysfs目录下创建fs目录,主要是创建名为fs的kobject及相关初始化
--> init_rootfs() // rootfs注册
--> bdi_init(&ramfs_backing_dev_info)
--> register_filesystem(&rootfs_fs_type)
// 注册roofs,将rootfs的描述结构体rootfs_fs_type挂接到全局链表file_system中
--> init_mount_tree() // mnt_init调用的重要函数
// 挂载rootfs文件系统
--> struct vfsmount *mnt // 描述文件系统挂载的结构体对象指针
struct mnt_namespace *ns // 名字空间
struct path root // root.mnt 和root.dentry
--> mnt = do_kern_mount("rootfs", 0, "rootfs", NULL)
// /* 重要函数 挂载前面已经注册进内核的rootfs文件系统*/
--> struct file_system_type *type = get_fs_type(fstype) // 找到file_system链表中对应名字
// 的file_system_type结构体地址
struct vfsmount *mnt; // 描述文件系统挂载的结构体对象指针
--> mnt = vfs_kern_mount(type, flags, name, data)
// flags = 0 , data = NULL , name = "rootfs"
--> struct vfsmount *mnt
--> mnt = alloc_vfsmnt(name)
// 在slub高速缓存组mnt_cache中分配一个vfsmount对象,并对其进行初始化,name = rootfs
// 引用计数 = 1
--> data = NULL ,没有数据需要处理
--> error = type->get_sb(type, flags, name, data, mnt)// type->get_sb = rootfs_get_sb
<==> error = rootfs_get_sb(type, flags, name, data, mnt)
--> get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super, mnt)
--> struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL)
--> struct super_block *s = NULL
--> s = alloc_super(type)
// 直接利用kmalloc来分配内存,并做相应初始化
--> err = set(s, data) // set = set_anon_super
<==> set_anon_super(s, data)
--> s->s_type = type // = &rootfs_fs_type
--> strlcpy(s->s_id, type->name, sizeof(s->s_id)) // name copy "rootfs"
--> list_add_tail(&s->s_list, &super_blocks)
// 将该超级块添加到全局超级块链表super_blocks中去
--> list_add(&s->s_instances, &type->fs_supers)
// 将该超级块添加到该文件系统描述结构体中的本文件系统超级块链表中
--> get_filesystem(type) // 这里该函数什么都没做
--> s->s_flags = flags // = MS_NOUSER
--> error = fill_super(s, data, flags & MS_SILENT ? 1 : 0) // 超级块填充函数
<==> error = ramfs_fill_super(s, data, 1)
--> struct inode * inode // 文件节点
struct dentry * root // 目录项root
--> sb->s_maxbytes = MAX_LFS_FILESIZE;/* 文件的最大值 */
sb->s_blocksize = PAGE_CACHE_SIZE;/* 以字节为单位的块的大小 */
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;/* 以位为单位的块的大小 */
sb->s_magic = RAMFS_MAGIC; /* 文件系统的魔数 */
sb->s_op = &ramfs_ops; /* 超级块的方法 ,在处理inode的时候会有用 */
sb->s_time_gran = 1;
--> inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0);
/* 建立根目录索引节点 */
--> struct inode * inode = new_inode(sb)
/* 在索引节点高速缓存inode_cachep中创建一个inode,
并初始化话相应的域*/
--> inode = alloc_inode(sb)
--> inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL)
--> inode_init_always(sb, inode)
--> inode->i_sb = sb
// 其余初始化项省略
--> inode->i_mode = mode;/* 文件的类型 */
inode->i_blocks = 0;//文件的块数
再通过一个switch语句判断是什么文件类型,初始化相应的操作方法
其余省略
--> root = d_alloc_root(inode);/* 建立根目录目录对象,并关联上inode */
--> static const struct qstr name = { .name = "/", .len = 1 }
// 看到根目录的符号了吧!呵呵
--> res = d_alloc(NULL, &name)
// 从slub高缓dentry_cache中分配一个目录对象的内存,并做相应初始化
--> res->d_sb = root_inode->i_sb; //指向该文件系统的超级块
res->d_parent = res; //根目录的父亲当然是它自己了
--> d_instantiate(res, root_inode)//将dentry 和 inode关联上
--> sb->s_root = root; /* 超级块的s_root指向刚建立的根目录对象 */
--> s->s_flags |= MS_ACTIVE
--> simple_set_mnt(mnt, s)
/* 超级块和文件系统挂载结构体简单关联 */
--> mnt->mnt_sb = sb
mnt->mnt_root = dget(sb->s_root)
--> security_sb_kern_mount(mnt->mnt_sb, flags, secdata)
--> mnt->mnt_mountpoint = mnt->mnt_root
//指明挂载点,其实就是刚才建立的”/”目录
--> mnt->mnt_parent = mnt
//父对象是自己
--> return mnt
--> put_filesystem(type) // wake_up_process()
--> return mnt
--> ns = kmalloc(sizeof(*ns), GFP_KERNEL)
// 分配名字空间结构体的内存
--> atomic_set(&ns->count, 1) // 设置ns的引用计数
--> INIT_LIST_HEAD(&ns->list) // 连接体初始化
--> init_waitqueue_head(&ns->poll) // 初始化等待队列头
--> list_add(&mnt->mnt_list, &ns->list)
// 将该vfsmount结构体挂接到namespace结构体的链表中
--> ns->root = mnt
// 该命名空间结构体的root域指向刚刚建立的vfsmount结构体
--> mnt->mnt_ns = ns
// 该vfsmount结构体的命名空间域指向ns
--> init_task.nsproxy->mnt_ns = ns
--> root.mnt = ns->root;
root.dentry = ns->root->mnt_root;
set_fs_pwd(current->fs, &root);
set_fs_root(current->fs, &root);
// 最后这几行通过中间变量root,将 do_kern_mount() 函数中建立的 mnt 和 dentry
// 信息记录在了当前进程的fs结构中
--> bdev_cache_init()
--> chrdev_init()
***vfs_caches_init() end.
至此,sysfs和rootfs文件系统初始化挂载完成。