轉自: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
把掛載描述符加入散列表
把掛載描述符加入父親的孩子列表
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; }
1.2. ext4文件系統的mount
在mount_fs中通過下邊語句調用特定文件系統的mount函數。
root = type->mount(type, flags, name, data);
- 1
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
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函數的主要邏輯如下:
- blkdev_get_by_path根據設備名得到block_device結構
- sget得到已經存在或者新分配的super_block結構
- 如果是已經存在的sb,就釋放第一步得到的bdev結構
- 如果是新的sb,就調用文件系統個別實現的fill_super函數繼續處理新的sb,並創建根inode, dentry
- 返回得到的s_root
- 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
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