linux启动--文件系统初始化
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux启动--vfs相关初始化
内核在启动时对文件系统的初始化,主要完成的工作是为vfs中各种数据结构申请缓存,初始化散列表,并加载rootfs作为当前进程的根文件系统。
1、start_kernel( )中与文件系统相关的初始化
start_kernel( )
{
...
vfs_caches_init_early(); //fs/dcache.c完成dentry,inode散列表的初始化。
....
vfs_caches_init(); //fs/dcache.c
....
proc_root_init();
nsfs_init();
...
}
本节对上面函数逐一进行分析。
2、vfs_caches_init_early( )
// fs/dcache.c
void __init vfs_caches_init_early(void)
{
dcache_init_early();
inode_init_early();
}
dcache_init_early()在fs/dcache.c中主要完成目录结构dentry的散列表初始化。
inode_init_early()在fs/inode.c中主要完成inode结构散列表的初始化。
3 、vfs_caches_init( )
此函数在fs/dcache.c是文件系统初始化的主要函数。
void __init vfs_caches_init(void)
{
names_cachep = kmem_cache_create("names_cache", P ATH_MAX, 0,
SLAB_HWCACHE_ALIGN|SLAB_P ANIC, NULL);
dcache_init(); //fs/dcache.c
inode_init(); //fs/inode.c
files_init(); //fs/file_table.c
files_maxfiles_init(); //fs/file_table.c
mnt_init(); // fs/namespace.c
bdev_cache_init();
chrdev_init();
}
3.1、vfs_caches_init( ) →dcache_init()
dcache_init()在fs/dcache.c中,主要完成dentry结构缓存的申请和初始化。
3.2、vfs_caches_init( ) → inode_init()
inode_init()在fs/inode.c中主要完成inode结构缓存的申请和初始化。
3.3、vfs_caches_init( ) → files_init()
files_init()在fs/file_table.c中主要也是完成file结构缓存的申请和初始化。
3.4 vfs_caches_init( ) → files_maxfiles_init()
files_maxfiles_init()也在fs/file_table.c中,设置打开最大文件数。
以上几个函数都比较简短,功能也比较简单,基本上就是完成vfs中用到的inode,dentry,file等结构体内存缓存的申请和散列表的初始化。
3.3、vfs_caches_init( ) → mnt_init( ): // fs/namespace.c
mnt_init()是与vfs相关初始化的主要函数,位于fs/namespace.c中:
void __init mnt_init(void)
{
...
kernfs_init(); //fs/kernfs/inode.c
...
err = sysfs_init(); //fs/sysfs/mount.c注册并挂载sysfs。
...
init_rootfs(); //init/do_mount.c
init_mount_tree(); //fs/namespace.c
}
此函数完成,mount结构及散列表的初始化,内核文件系统及sys文件系统初始化。这里我们先关注最后两个函数。
init_rootfs()完成ramfs文件在内核的注册,由于内核启动前期无法访问外部块设备内的文件系统,所以启动时期必须先加载内存文件系统ramfs或叫rootfs。加载它的目的是用于系统初始化和加载块设备驱动程序,以便在启动后期加载块设备上的文件系统。
重点来看init_mount_tree(void),位于fs/namespace.c:
static void __init init_mount_tree(void)
{
struct path root;
...
type = get_fs_type("rootfs");
...
mnt = vfs_kern_mount(type, 0, "rootfs", NULL); /*在本文件内*/
root.mnt = mnt;
root.dentry = mnt->mnt_root;
mnt->mnt_flags |= MNT_LOCKED;
set_fs_pwd(current->fs, &root); //设置当前进程的当前目录。
set_fs_root(current->fs, &root); //设置当前进程的根目录,即加载当前目录为根目录。
}
浏览源代码可看出,此函数的任务就是加载rootfs文件系统,并将当前进程的当前目录和根目录设为rootfs的挂载点。
rootfs也就是ramfs,由于它是存在于内存中的文件系统,所以内核在加载时就得将文件系统一并加载。如果配置时启用了initramfs,则需在构建前将该文件系统的内容设置好,在配置时一并将路径加入配置选项中,内核在构建时就会将文件系统的内容压缩链接入内核中的一个段中,在内核启动时再解压释放到内存中,从而就可以访问文件系统内了。
解压函数在init/initramfs.c中:
static int __init populate_rootfs(void)
{
char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
....
}
rootfs_initcall(populate_rootfs);
由最后一个宏定义可知,此函数会在启动时期调用。关于根文件系统的加载和制作在下一篇文章中再做介绍。
4、vfs_caches_init( ) →bdev_cache_init()
此函数位于fs/block_dev.c:
void __init bdev_cache_init(void)
{
int err;
static struct vfsmount *bd_mnt;
bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode),
0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD|SLAB_P ANIC),
init_once);