vfsrootfs挂载
start_kernel–》vfs_caches_init,内核初始化时,调用vfs_caches_init初始虚拟文件系统相关结构,包括目录项,inode,操作方法,命名空间,file,mnt等
void __init vfs_caches_init(unsigned long mempages)
{
unsigned long reserve;
/* Base hash sizes on available memory, with a reserve equal to
150% of current kernel size */
reserve = min((mempages - nr_free_pages()) * 3/2, mempages - 1);
mempages -= reserve;
names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
dcache_init();初始化dentry_cache
inode_init();初始化inode_cache
files_init(mempages);初始化dentry_cache
mnt_init();初始化filp_cachep,mnt_cache
bdev_cache_init();
chrdev_init();
}
mnt_init
void __init mnt_init(void)
{
unsigned u;
int err;
init_rwsem(&namespace_sem);
mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount),
0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
初始化mount管理hash表
mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);
mountpoint_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);
for (u = 0; u < HASH_SIZE; u++)
INIT_LIST_HEAD(&mount_hashtable[u]);
for (u = 0; u < HASH_SIZE; u++)
INIT_LIST_HEAD(&mountpoint_hashtable[u]);
br_lock_init(&vfsmount_lock);
err = sysfs_init();先创建sysfs文件系统
fs_kobj = kobject_create_and_add("fs", NULL);
init_rootfs();
init_mount_tree();
}
创建sysfs文件系统
sysfs用来记录和展示linux驱动模型
sysfs_init
static struct file_system_type sysfs_fs_type = {
.name = "sysfs",
.mount = sysfs_mount,
.kill_sb = sysfs_kill_sb,
.fs_flags = FS_USERNS_MOUNT,
};
sysfs_init–》register_filesystem(&sysfs_fs_type); 注册sysfs_fs_type到系统全局file_systems中
sysfs_init–》kern_mount–》vfs_kern_mount–》vfs_kern_mount–>sysfs_mount 回调sysfs_mount
主要分配struct vfsmount, struct mount , struct super_block超级块,初始化超级块操作函数
创建根目录’’,每个文件系统本身都有一个根目录,用于在上面创建各种文件,目录等,也提供给其他文件系统挂载,构成树状结构。
sysfs_mount–》sysfs_fill_super sys文件系统类型的超级块填充,主要是操作函数
static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
struct dentry *root;
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = SYSFS_MAGIC;
sb->s_op = &sysfs_ops;//操作函数,文件系统中文件操作方法
sb->s_time_gran = 1;
/* get root inode, initialize and unlock it */
mutex_lock(&sysfs_mutex);
inode = sysfs_get_inode(sb, &sysfs_root);
mutex_unlock(&sysfs_mutex);
/* instantiate and link root dentry */
root = d_make_root(inode); 创建根目录'\'
root->d_fsdata = &sysfs_root;
sb->s_root = root;
sb->s_d_op = &sysfs_dentry_ops;//操作函数,文件系统中目录操作方法
return 0;
}
struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
struct mount *mnt;
struct dentry *root;
if (!type)
return ERR_PTR(-ENODEV);
mnt = alloc_vfsmnt(name);
if (!mnt)
return ERR_PTR(-ENOMEM);
if (flags & MS_KERNMOUNT)
mnt->mnt.mnt_flags = MNT_INTERNAL;
root = mount_fs(type, flags, name, data);
mnt->mnt.mnt_root = root; //根目录
mnt->mnt.mnt_sb = root->d_sb;
mnt->mnt_mountpoint = mnt->mnt.mnt_root;//根目录设置为mnt_mountpoint
mnt->mnt_parent = mnt;
br_write_lock(&vfsmount_lock);
list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);
br_write_unlock(&vfsmount_lock);
return &mnt->mnt;
}
rootfs
kernel启动时先创建虚拟根文件系统管理结构,rootfs是基于内存的文件系统,所有操作都在内存中完成;也没有实际的存储设备,所以不需要设备驱动程序的参与,所以开始并没有挂载到真实磁盘中文件系统,真实文件系统可能在sd,硬盘,flash等等,这些必须等到驱动初始化完成,才能挂载。而虚拟文件系统只需要内存就可以挂载。
init_rootfs
首先把rootfs_fs_type 注册到系统中
static struct file_system_type rootfs_fs_type = {
.name = "rootfs",
.mount = rootfs_mount,
.kill_sb = kill_litter_super,
};
init_rootfs-》register_filesystem(&rootfs_fs_type);
init_mount_tree
挂载rootfs文件系统,
static void __init init_mount_tree(void)
{
struct vfsmount *mnt;
struct mnt_namespace *ns;
struct path root;
struct file_system_type *type;
type = get_fs_type("rootfs");
mnt = vfs_kern_mount(type, 0, "rootfs", NULL); 挂载文件系统,创建根目录,超级块,并初始化参数
put_filesystem(type);
ns = create_mnt_ns(mnt);
init_task.nsproxy->mnt_ns = ns; 设置init进程命名空间为rootfs命名空间
get_mnt_ns(ns);
root.mnt = mnt;
root.dentry = mnt->mnt_root;
set_fs_pwd(current->fs, &root); 设置当前进程工作目录为根目录
set_fs_root(current->fs, &root);设置当前进程根目目录为根目录
}
设置了设置init进程命名空间为rootfs命名空间,设置当前进程工作目录为rootfs系统下的根目录,设置当前进程根目目录为rootfs系统下的根目录,所以用户实际使用的是rootfs文件系统。rootfs为VFS提供了’/'根目录,后续文件操作将在rootfs系统下的根目录。
sysfs文件系统进行了初始化,并注册到了系统中,但并没有挂载到rootfs系统下的目录下。后续init进程启动后,会挂载sysfs到rootfs系统下。
rootfs_mount
虚拟rootfs mount
static struct dentry *rootfs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return mount_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super);这里看到rootfs超级块类型为ramfs,内存中。
}
超级块初始化
int ramfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct ramfs_fs_info *fsi;
struct inode *inode;
int err;
save_mount_options(sb, data);
fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL);
sb->s_fs_info = fsi;
if (!fsi)
return -ENOMEM;
err = ramfs_parse_options(data, &fsi->mount_opts);
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; 设置超级块中操作方法为ramfs_ops
sb->s_time_gran = 1;
inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0);
sb->s_root = d_make_root(inode); //创建了根目录
if (!sb->s_root)
return -ENOMEM;
return 0;
}
至此,初始化完成了虚拟文件系统,创建了sysfs文件系统,创建了跟文件系统,并设置了init进程工作空间为rootfs文件系统。也创建了rootfs的根目录’’,但rootfs中没有其它文件和目录,后续需要加载InitRamfs文件系统。
总结
start_kernel(void)
vfs_caches_init_early();
dcache_init_early();
inode_init_early();
--> vfs_caches_init(num_physpages);
dcache_init();
inode_init();
files_init(mempages);
--> mnt_init();
--> init_rootfs();
--> init_mount_tree();
InitRamfs挂载
InitRamdisk实际属于真实文件系统,只不过不在磁盘,而在内存,这是有结构决定的,而不是介质。
下面主要讲InitRamfs挂载,为cpio结构,挂载方式实际为解析文件结构,把文件重复在前面创建的rootfs根目录下进行创建或复制。比如在InitRamfs有一个data目录,那么就在rootfs根目录下创建一个data目录,实际就是模拟创建。
start_kernel--》rest_init--》kernel_init--》kernel_init_freeable--》do_basic_setup--》driver_init--》devices_init
在sysfs文件系统下面创建device,相关目录,后续用于设备初始化时再对应目录下创建设备;前面已经创建了sysfs文件系统。
int __init devices_init(void)
{
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
dev_kobj = kobject_create_and_add("dev", NULL);
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
return 0;
}
start_kernel--》rest_init--》kernel_init--》kernel_init_freeable--》do_basic_setup--》do_initcalls--》do_one_initcall
do_one_initcall会调用各种初始化,主要是driver初始化,也包括rootfs。
这里只关注rootfs,\init\initramfs.c 文件中rootfs_initcall(populate_rootfs);
populate_rootfs释放uboot传递过来的initram到rootfs根目录下
static int __init populate_rootfs(void)
{
char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
if (initrd_start) {
#ifdef CONFIG_BLK_DEV_RAM
int fd;
printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n");
err = unpack_to_rootfs((char *)initrd_start,
initrd_end - initrd_start);
if (!err) {
free_initrd();
goto done;
} else {
clean_rootfs();
unpack_to_rootfs(__initramfs_start, __initramfs_size);
}
printk(KERN_INFO "rootfs image is not initramfs (%s)"
"; looks like an initrd\n", err);
fd = sys_open("/initrd.image",
O_WRONLY|O_CREAT, 0700);
if (fd >= 0) {
sys_write(fd, (char *)initrd_start,
initrd_end - initrd_start);
sys_close(fd);
free_initrd();
}
done:
#else
printk(KERN_INFO "Unpacking initramfs...\n");
err = unpack_to_rootfs((char *)initrd_start, //CONFIG_BLK_DEV_RAM没有定义时,initrd_start,initrd_end 为uboot通过dtb中bootargs参数传递过来
initrd_end - initrd_start);
if (err)
printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);
free_initrd();
#endif
/*
* Try loading default modules from initramfs. This gives
* us a chance to load before device_initcalls.
*/
load_default_modules();
}
return 0;
}
不同类型initram压缩文件,解压函数
static const struct compress_format compressed_formats[] __initconst = {
{ {037, 0213}, "gzip", gunzip },
{ {037, 0236}, "gzip", gunzip },
{ {0x42, 0x5a}, "bzip2", bunzip2 },
{ {0x5d, 0x00}, "lzma", unlzma },
{ {0xfd, 0x37}, "xz", unxz },
{ {0x89, 0x4c}, "lzo", unlzo },
{ {0, 0}, NULL, NULL }
};
static char * __init unpack_to_rootfs(char *buf, unsigned len)
{
int written, res;
decompress_fn decompress;
const char *compress_name;
static __initdata char msg_buf[64];
header_buf = kmalloc(110, GFP_KERNEL);
symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL);
name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL);
if (!header_buf || !symlink_buf || !name_buf)
panic("can't allocate buffers");
state = Start;
this_header = 0;
message = NULL;
while (!message && len) {
loff_t saved_offset = this_header;
if (*buf == '0' && !(this_header & 3)) {
state = Start;状态
written = write_buffer(buf, len); //调用write_buffer 解析initramfs
buf += written;
len -= written;
continue;
}
if (!*buf) {
buf++;
len--;
this_header++;
continue;
}
this_header = 0;
decompress = decompress_method(buf, len, &compress_name); //这里获取解压initramfs函数,根据initramfs类型,cpio为gzip
if (decompress) {
res = decompress(buf, len, NULL, flush_buffer, NULL,
&my_inptr, error);
if (res)
error("decompressor failed");
} else if (compress_name) {
if (!message) {
snprintf(msg_buf, sizeof msg_buf,
"compression method %s not configured",
compress_name);
message = msg_buf;
}
} else
error("junk in compressed archive");
if (state != Reset)
error("junk in compressed archive");
this_header = saved_offset + my_inptr;
buf += my_inptr;
len -= my_inptr;
}
dir_utime();
kfree(name_buf);
kfree(symlink_buf);
kfree(header_buf);
return message;
}
static __initdata int (*actions[])(void) = {
[Start] = do_start,
[Collect] = do_collect,
[GotHeader] = do_header,
[SkipIt] = do_skip,
[GotName] = do_name,
[CopyFile] = do_copy,
[GotSymlink] = do_symlink,
[Reset] = do_reset,
};
static int __init write_buffer(char *buf, unsigned len)
{
count = len;
victim = buf;设置要处理的词
while (!actions[state]()) 根据state状态,调用不同函数处理
;
return len - count;
}
总体上,unpack_to_rootfs函数就是解压initramfs内存,然后按照文件组织格式,在rootfs中再创建相同的目录和文件。
至此,虚拟根文件系统创建完成。