kernel 文件系統掛載流程分析【轉】


轉自:https://blog.csdn.net/wuu1010/article/details/94332319

 

1. mount系統調用

1.1. sys_mount

sys_mount主要將系統調用的參數dev_name、dir_name、type、flags、data從用戶空間拷貝到內核空間,然后調用do_mount函數

sys_mount
	copy_mount_string
	copy_mount_options
	do_mount
		user_path(dirname, &path) -> path_lookupat ==> 復雜的過程,找到目錄對應的掛載描述符合dentry實例
		do_remount
		do_loopback
		do_change_type
		do_move_mount
		do_new_mount	// 構建虛擬掛載點vsfmount,檢查設置namespace
			get_fs_type // 根據文件系統類型的命長找到file_system_type實例
			vfs_kernel_mount    // 調用具體文件系統的mount,並將返回的root dentry與分配的vfsmount掛接
				alloc_vfsmnt    // 分配掛載描述符
				mount_fs
					type->mount // 調用具體文件系統的mount,返回root dentry
					設置vfsmount結構內容
				把掛載描述符添加到長幾塊的掛載實例鏈表中
		do_add_mount
			graft_tree
				attach_recursive_mnt
					commit_tree
						__attach_mnt
							把掛載描述符加入散列表
							把掛載描述符加入父親的孩子列表

 

mount

SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, char __user *, type, unsigned long, flags, void __user *, data) { int ret; char *kernel_type; char *kernel_dev; void *options; kernel_type = copy_mount_string(type); ret = PTR_ERR(kernel_type); if (IS_ERR(kernel_type)) goto out_type; kernel_dev = copy_mount_string(dev_name); ret = PTR_ERR(kernel_dev); if (IS_ERR(kernel_dev)) goto out_dev; options = copy_mount_options(data); ret = PTR_ERR(options); if (IS_ERR(options)) goto out_data; ret = do_mount(kernel_dev, dir_name, kernel_type, flags, options); kfree(options); out_data: kfree(kernel_dev); out_dev: kfree(kernel_type); out_type: return ret; } 

 

do_mount

1.2. ext4文件系統的mount

mount_fs中通過下邊語句調用特定文件系統的mount函數。

root = type->mount(type, flags, name, data); 
  • 1

ext4_fs_type

static struct file_system_type ext4_fs_type = { .owner = THIS_MODULE, .name = "ext4", .mount = ext4_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

ext4_mount

static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { return mount_bdev(fs_type, flags, dev_name, data, ext4_fill_super); } 
  • 1
  • 2
  • 3
  • 4
  • 5

mount_bdev是針對塊設備掛載時使用的函數,此外還有mount_nodev, mount_single等函數,分別用於不同的掛載情況。
mount_bdev函數的主要邏輯如下:

  1. blkdev_get_by_path根據設備名得到block_device結構
  2. sget得到已經存在或者新分配的super_block結構
  3. 如果是已經存在的sb,就釋放第一步得到的bdev結構
  4. 如果是新的sb,就調用文件系統個別實現的fill_super函數繼續處理新的sb,並創建根inode, dentry
  5. 返回得到的s_root
  6. fill_super函數將完成mount接下來重要的工作

1.4. ext4_fill_super

在磁盤掛載的時候文件系統需要從磁盤中讀取超級塊來填充內存中的結構,EXT4文件系統超級塊的填充是由函數ext4_fill_super()來完成的。在EXT4文件系統中,磁盤上的超級塊結構是與結構體structext4_super_block的定義是一致的,大小是1K,即1024個字節。順便提下,EXT3文件系統超級塊在磁盤上的大小也是1024個字節,EXT4擴展了EXT3的定義,EXT3只是占了1024個字節,有些字節沒有定義,在EXT4中重新定義了,總的大小沒有改變。

在掛載文件系統的時候,讀取磁盤上ext4_super_block結構的值,填充內存中ext4_sb_info的結構。

2. 掛載根文件系統

start_kernel
    vfs_caches_init
        mnt_init
            init_rootfs     // 注冊rootfs文件系統
            init_mount_tree // 掛載rootfs文件系統
  • 1
  • 2
  • 3
  • 4
  • 5

2.1. init_rootfs

init_rootfs注冊rootfs文件系統

static struct file_system_type rootfs_fs_type = { .name = "rootfs", .mount = rootfs_mount, .kill_sb = kill_litter_super, }; int __init init_rootfs(void) { int err = register_filesystem(&rootfs_fs_type); if (err) return err; if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] && (!root_fs_names || strstr(root_fs_names, "tmpfs"))) { err = shmem_init(); is_tmpfs = true; } else { err = init_ramfs_fs(); } if (err) unregister_filesystem(&rootfs_fs_type); return err; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

2.2. init_mount_tree

init_mount_tree

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"); if (!type) panic("Can't find rootfs type"); mnt = vfs_kern_mount(type, 0, "rootfs", NULL); // 掛載rootfs文件系統 put_filesystem(type); if (IS_ERR(mnt)) panic("Can't create rootfs"); ns = create_mnt_ns(mnt); // 創建第一個掛載命名空間 if (IS_ERR(ns)) panic("Can't allocate initial namespace"); init_task.nsproxy->mnt_ns = ns; // 設置0號線程的掛載命名工具 get_mnt_ns(ns); root.mnt = mnt; root.dentry = mnt->mnt_root; mnt->mnt_flags |= MNT_LOCKED; set_fs_pwd(current->fs, &root); // 把0號線程的當前工作目錄設置為rootfs文件系統的根目錄 set_fs_root(current->fs, &root); // 把0號線程的根目錄設置為rootfs文件系統的根目錄 } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

3. 參考資料

  1. Linux內核-文件系統-掛載流程分析
  2. Linux內核深度解析-第6章 文件系統
  3. mount過程分析之五(mount_bdev->fill_super)
  4. EXT4文件系統之ext4_fill_super()
  5. EXT4文件系統筆記之ext4_fill_super


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM