文件系统系列学习笔记(3)
挂载和卸载
1 文件系统启动之初建立“/”,根文件系统的根目录挂载在“/”下,该文件系统所在的设备即是根设备
2 其他文件系统挂载在根文件系统的某些目录下,特定设备文件系统在挂载前以设备文件形式存在于系统上特定目录下如/dev/hda1。设备文件可以确定驱动程序,此时为原始的流设备。可以字节的读写。挂载后以文件系统的形式读写。
3 根据系统不同状态,内核有三个挂载函数:sys_mount(), mount_root(), kern_mount()。下面分别介绍如下:
sys_mount()----系统调用mount的内核实现
//参数:设备路径名,挂载处的目录路径名, 挂载文件系统类型,挂载标志, 挂载数据 **1**asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name, char __user * type, unsigned long flags, void __user * data) { ... retval = do_mount((char*)dev_page, dir_page, (char*)type_page, flags, (void*)data_page); unlock_kernel(); free_page(data_page); ... } //可见主要操作在do_mount()中完成,一起看下: * * Flags is a 32-bit value that allows up to 31 non-fs dependent flags to * be given to the mount() call (ie: read-only, no-dev, no-suid etc). * * data is a (void *) that can point to any structure up to * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent * information (or be NULL). * * Pre-0.97 versions of mount() didn't have a flags word. * When the flags word was introduced its top half was required * to have the magic value 0xC0ED, and this remained so until 2.4.0-test9. * Therefore, if this magic number is present, it carries no information * and must be discarded. */ **2**long do_mount(char * dev_name, char * dir_name, char *type_page, unsigned long flags, void *data_page) { struct nameidata nd; int retval = 0; int mnt_flags = 0; /* Discard magic */ if ((flags & MS_MGC_MSK) == MS_MGC_VAL) flags &= ~MS_MGC_MSK; /* Basic sanity checks */ if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE)) return -EINVAL; if (dev_name && !memchr(dev_name, 0, PAGE_SIZE)) return -EINVAL; if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; /* Separate the per-mountpoint flags */ if (flags & MS_NOSUID) mnt_flags |= MNT_NOSUID; if (flags & MS_NODEV) mnt_flags |= MNT_NODEV; if (flags & MS_NOEXEC) mnt_flags |= MNT_NOEXEC; flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_ACTIVE); /* ... and get the mountpoint */ retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd);//nd中存储挂载目录的dentry信息 if (retval) return retval; //下面做安全检查和挂载操作检查,直接看主流程do_new_moun() retval = security_sb_mount(dev_name, &nd, type_page, flags, data_page); if (retval) goto dput_out; if (flags & MS_REMOUNT) retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags, data_page); else if (flags & MS_BIND) retval = do_loopback(&nd, dev_name, flags & MS_REC); else if (flags & MS_MOVE) retval = do_move_mount(&nd, dev_name); else //挂载主流程 retval = do_new_mount(&nd, type_page, flags, mnt_flags, dev_name, data_page); dput_out: path_release(&nd); return retval; } **3**static int do_new_mount(struct nameidata *nd, char *type, int flags, int mnt_flags, char *name, void *data) { struct vfsmount *mnt; if (!type || !memchr(type, 0, PAGE_SIZE)) return -EINVAL; //一般需要系统管理员权限 /* we need capabilities... */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; mnt = do_kern_mount(type, flags, name, data);//主流程 if (IS_ERR(mnt)) return PTR_ERR(mnt); return do_add_mount(mnt, nd, mnt_flags, NULL);//最后注释************ }
struct vfsmount * do_kern_mount(const char *fstype, int flags, const char *name, void *data) //根据文件系统类型在系统中查找对应的file_system_type信息,该结构中包含有读取超级块的函数指针、VFSmount、具体文件系统flag、module owner、文件系统type名等信息。 { struct file_system_type *type = get_fs_type(fstype); struct super_block *sb = ERR_PTR(-ENOMEM); struct vfsmount *mnt; int error; char *secdata = NULL; if (!type) return ERR_PTR(-ENODEV); mnt = alloc_vfsmnt(name);//According the device path name to allocate vfsmount if (!mnt) goto out; if (data) { secdata = alloc_secdata(); if (!secdata) { sb = ERR_PTR(-ENOMEM); goto out_mnt; } error = security_sb_copy_data(type, data, secdata); if (error) { sb = ERR_PTR(error); goto out_free_secdata; } } sb = type->get_sb(type, flags, name, data);//Use the get_sb() in structure file_system_type to read super block. if (IS_ERR(sb)) goto out_free_secdata; error = security_sb_kern_mount(sb, secdata); if (error) goto out_sb; mnt->mnt_sb = sb;//Super block mnt->mnt_root = dget(sb->s_root);//root dentry mnt->mnt_mountpoint = sb->s_root; mnt->mnt_parent = mnt; mnt->mnt_namespace = current->namespace; up_write(&sb->s_umount); put_filesystem(type); return mnt; out_sb: up_write(&sb->s_umount); deactivate_super(sb); sb = ERR_PTR(error); out_free_secdata: free_secdata(secdata); out_mnt: free_vfsmnt(mnt); out: put_filesystem(type); return (struct vfsmount *)sb; }
最后:
/* * add a mount into a namespace's mount tree * - provide the option of adding the new mount to an expiration list */ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, int mnt_flags, struct list_head *fslist) { int err; down_write(¤t->namespace->sem); /* Something was mounted here while we slept */ while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) ; err = -EINVAL; if (!check_mnt(nd->mnt)) goto unlock; /* Refuse the same filesystem on the same mount point */ err = -EBUSY; if (nd->mnt->mnt_sb == newmnt->mnt_sb && nd->mnt->mnt_root == nd->dentry) goto unlock; err = -EINVAL; if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode)) goto unlock; newmnt->mnt_flags = mnt_flags; err = graft_tree(newmnt, nd); if (err == 0 && fslist) { /* add to the specified expiration list */ spin_lock(&vfsmount_lock); list_add_tail(&newmnt->mnt_fslink, fslist); spin_unlock(&vfsmount_lock); } unlock: up_write(¤t->namespace->sem); mntput(newmnt); return err; }
应用的到的重要数据结构及其意义:
- file_system_type:系统初始化时将内核支持的各种文件系统的file_system_type数据结构用register_filesystem挂到一个队列当中,成为文件系统的注册。有些文件系统支持可安装的模块,在装入这种模块时也会将相应的数据结构挂入该队列中。
- vfsmount:作为挂载待挂载的设备与挂载点的连接器。
struct vfsmount { struct list_head mnt_hash; struct vfsmount *mnt_parent; /* fs we are mounted on */ struct dentry *mnt_mountpoint; /* dentry of mountpoint */ struct dentry *mnt_root; /* root of the mounted tree */ struct super_block *mnt_sb; /* pointer to superblock */ struct list_head mnt_mounts; /* list of children, anchored here */ struct list_head mnt_child; /* and going through their mnt_child */ atomic_t mnt_count; int mnt_flags; int mnt_expiry_mark; /* true if marked for expiry */ char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ struct list_head mnt_list; struct list_head mnt_fslink; /* link in fs-specific expiry list */ struct namespace *mnt_namespace; /* containing namespace */ };优质内容筛选与推荐>>