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

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