android rootfs根文件系统挂载(二)

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中再创建相同的目录和文件。
至此,虚拟根文件系统创建完成。

在这里插入图片描述

参考:
https://blog.csdn.net/nanaoxue/article/details/32701579
https://www.cnblogs.com/wuchanming/p/3769727.html
https://blog.csdn.net/armmfc/article/details/51314581?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158833707919724848329051%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.57659%2522%257D&request_id=158833707919724848329051&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v25-2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章