Python 官方文档:入门教程 => 点击学习
Ext3 mount原理 本质上,Ext3 mount的过程实际上是inode被替代的过程。例如,/dev/sdb块设备被mount到/mnt/alan目录。那么mount这个过程所需要解决的问题就是将/mnt/alan的dentry目
Ext3 mount原理
当用户输入”mount /dev/sdb /mnt/alan”命令后,Linux会解析/mnt/alan字符串,并且从Dentry Hash表中获取相关的dentry目录项,然后将该目录项标识成DCACHE_MOUNTED。一旦该dentry被标识成DCACHE_MOUNTED,也就意味着在访问路径上对其进行了屏蔽。
- struct vfsmount {
- struct list_head mnt_hash;
- struct vfsmount *mnt_parent;
- struct dentry *mnt_mountpoint;
- struct dentry *mnt_root;
- struct super_block *mnt_sb;
- #ifdef CONFIG_SMP
- struct mnt_pcp __percpu *mnt_pcp;
- atomic_t mnt_longterm;
- #else
- int mnt_count;
- int mnt_writers;
- #endif
- struct list_head mnt_mounts;
- struct list_head mnt_child;
- int mnt_flags;
-
- #ifdef CONFIG_FSNOTIFY
- __u32 mnt_fsnotify_mask;
- struct hlist_head mnt_fsnotify_marks;
- #endif
- const char *mnt_devname;
- struct list_head mnt_list;
- struct list_head mnt_expire;
- struct list_head mnt_share;
- struct list_head mnt_slave_list;
- struct list_head mnt_slave;
- struct vfsmount *mnt_master;
- struct mnt_namespace *mnt_ns;
- int mnt_id;
- int mnt_group_id;
- int mnt_expiry_mark;
- int mnt_pinned;
- int mnt_ghosts;
- };
- struct super_block {
- struct list_head s_list;
- dev_t s_dev;
- unsigned char s_dirt;
- unsigned char s_blocksize_bits;
- unsigned long s_blocksize;
- loff_t s_maxbytes;
- struct file_system_type *s_type;
- const struct super_operations *s_op;
- const struct dquot_operations *dq_op;
- const struct quotactl_ops *s_qcop;
- const struct export_operations *s_export_op;
- unsigned long s_flags;
- unsigned long s_magic;
- struct dentry *s_root;
- struct rw_semaphore s_umount;
- struct mutex s_lock;
- int s_count;
- atomic_t s_active;
- #ifdef CONFIG_SECURITY
- void *s_security;
- #endif
- const struct xattr_handler **s_xattr;
-
- struct list_head s_inodes;
- struct hlist_bl_head s_anon;
- #ifdef CONFIG_SMP
- struct list_head __percpu *s_files;
- #else
- struct list_head s_files;
- #endif
-
- struct list_head s_dentry_lru;
- int s_nr_dentry_unused;
-
-
- spinlock_t s_inode_lru_lock ____cacheline_aligned_in_smp;
- struct list_head s_inode_lru;
- int s_nr_inodes_unused;
-
- struct block_device *s_bdev;
- struct backing_dev_info *s_bdi;
- struct mtd_info *s_mtd;
- struct list_head s_instances;
- struct quota_info s_dquot;
-
- int s_frozen;
- wait_queue_head_t s_wait_unfrozen;
-
- char s_id[32];
- u8 s_uuid[16];
-
- void *s_fs_info;
- fmode_t s_mode;
-
-
- u32 s_time_gran;
-
-
- struct mutex s_vfs_rename_mutex;
-
-
- char *s_subtype;
-
-
- char __rcu *s_options;
- const struct dentry_operations *s_d_op;
-
-
- int cleancache_poolid;
-
- struct shrinker s_shrink;
- };
代码流程分析
- 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_dir;
- char *kernel_dev;
- unsigned long data_page;
-
- ret = copy_mount_string(type, &kernel_type);
- if (ret < 0)
- Goto out_type;
-
- kernel_dir = getname(dir_name);
- if (IS_ERR(kernel_dir)) {
- ret = PTR_ERR(kernel_dir);
- goto out_dir;
- }
-
- ret = copy_mount_string(dev_name, &kernel_dev);
- if (ret < 0)
- goto out_dev;
-
- ret = copy_mount_options(data, &data_page);
- if (ret < 0)
- goto out_data;
-
- ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags,
- (void *) data_page);
-
- free_page(data_page);
- out_data:
- kfree(kernel_dev);
- out_dev:
- putname(kernel_dir);
- out_dir:
- kfree(kernel_type);
- out_type:
- return ret;
- }
do_mount()函数是mount操作过程中的核心函数,在该函数中,通过mount的目录字符串找到对应的dentry目录项,然后通过do_new_mount()函数完成具体的mount操作。do_mount()函数分析如下:
- long do_mount(char *dev_name, char *dir_name, char *type_page,
- unsigned long flags, void *data_page)
- {
- struct path path;
- int retval = 0;
- int mnt_flags = 0;
-
- 。。。
-
-
- retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
- if (retval)
- return retval;
-
- 。。。
-
-
- if (flags & MS_NOSUID)
- mnt_flags |= MNT_NOSUID;
- if (flags & MS_NODEV)
- mnt_flags |= MNT_NODEV;
- if (flags & MS_NOEXEC)
- mnt_flags |= MNT_NOEXEC;
- if (flags & MS_NOATIME)
- mnt_flags |= MNT_NOATIME;
- if (flags & MS_NODIRATIME)
- mnt_flags |= MNT_NODIRATIME;
- if (flags & MS_STRICTATIME)
- mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
- if (flags & MS_RDONLY)
- mnt_flags |= MNT_READONLY;
-
- flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN |
- MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
- MS_STRICTATIME);
-
-
- if (flags & MS_REMOUNT)
- retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
- data_page);
- else if (flags & MS_BIND)
- retval = do_loopback(&path, dev_name, flags & MS_REC);
- else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
- retval = do_change_type(&path, flags);
- else if (flags & MS_MOVE)
- retval = do_move_mount(&path, dev_name);
- else
-
- retval = do_new_mount(&path, type_page, flags, mnt_flags,
- dev_name, data_page);
- dput_out:
- path_put(&path);
- return retval;
- }
do_new_mount()函数主要分成两大部分:第一部分建立vfsmount对象和superblock对象,必要时从设备上获取文件系统元数据;第二部分将vfsmount对象加入到mount树和Hash Table中,并且将原来的dentry对象无效掉。do_new_mount函数说明如下:
- static int do_new_mount(struct path *path, char *type, int flags,
- int mnt_flags, char *name, void *data)
- {
- struct vfsmount *mnt;
- int err;
-
- 。。。
-
-
- mnt = do_kern_mount(type, flags, name, data);
- if (IS_ERR(mnt))
- return PTR_ERR(mnt);
-
- err = do_add_mount(mnt, path, mnt_flags);
- if (err)
- mntput(mnt);
- return err;
- }
do_new_mount()中的第一步调用do_kern_mount()函数,该函数的主干调用路径如下:
- static struct file_system_type ext3_fs_type = {
- .owner = THIS_MODULE,
- .name = "ext3",
- .mount = ext3_mount,
- .kill_sb = kill_block_super,
- .fs_flags = FS_REQUIRES_DEV,
- };
Ext3 mount函数主干调用路径为:ext3_mount--> mount_bdev。Mount_bdev()函数主要完成superblock对象的内存初始化,并且加入到全局superblock链表中。该函数说明如下:
- struct dentry *mount_bdev(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data,
- int (*fill_super)(struct super_block *, void *, int))
- {
- struct block_device *bdev;
- struct super_block *s;
- fmode_t mode = FMODE_READ | FMODE_EXCL;
- int error = 0;
-
- if (!(flags & MS_RDONLY))
- mode |= FMODE_WRITE;
-
- bdev = blkdev_get_by_path(dev_name, mode, fs_type);
- if (IS_ERR(bdev))
- return ERR_CAST(bdev);
-
-
- mutex_lock(&bdev->bd_fsfreeze_mutex);
- if (bdev->bd_fsfreeze_count > 0) {
- mutex_unlock(&bdev->bd_fsfreeze_mutex);
- error = -EBUSY;
- goto error_bdev;
- }
-
- s = sget(fs_type, test_bdev_super, set_bdev_super, bdev);
- mutex_unlock(&bdev->bd_fsfreeze_mutex);
- if (IS_ERR(s))
- goto error_s;
-
- if (s->s_root) {
-
- if ((flags ^ s->s_flags) & MS_RDONLY) {
- deactivate_locked_super(s);
- error = -EBUSY;
- goto error_bdev;
- }
-
-
- up_write(&s->s_umount);
- blkdev_put(bdev, mode);
- down_write(&s->s_umount);
- } else {
-
- char b[BDEVNAME_SIZE];
-
- s->s_flags = flags | MS_NOSEC;
- s->s_mode = mode;
- strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
- sb_set_blocksize(s, block_size(bdev));
-
- error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
- if (error) {
- deactivate_locked_super(s);
- goto error;
- }
-
- s->s_flags |= MS_ACTIVE;
- bdev->bd_super = s;
- }
-
- return dget(s->s_root);
-
- error_s:
- error = PTR_ERR(s);
- error_bdev:
- blkdev_put(bdev, mode);
- error:
- return ERR_PTR(error);
- }
do_new_mount()函数的第二步是将创建的vfsmount对象加入到mount树和VFSMOUNT Hash Table中,并且将老的dentry目录项无效掉。该过程主干函数调用过程如下所示:
--结束END--
本文标题: Ext3 mount过程分析
本文链接: https://lsjlt.com/news/190901.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0