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