Linux: 关于 mount 的一些细节
文章目录
- 1. 前言
- 2. mount 的主要细节
1. 前言
限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。
2. mount 的主要细节
mount
从系统调用 sys_mount()
发起,如 mount -t tmpfs cgroup /sys/fs/cgroup
:
sys_mount() /* fs/namespace.c */do_mount()do_new_mount()struct vfsmount *mnt;...type = get_fs_type(fstype); /* 查找 @fstype 字串对应的文件系统类型 */...mnt = vfs_kern_mount(type, sb_flags, name, data);struct mount *mnt;struct dentry *root; /* @type 文件系统 的 根目录 */...mnt = alloc_vfsmnt(name);...root = mount_fs(type, flags, name, data);struct dentry *root; /* @type 文件系统 的 根目录 */struct super_block *sb; /* @type 文件系统 super block */...root = type->mount(type, flags, name, data);shmem_mount() /* tmpfs 的 挂载接口 */...sb = root->d_sb;.../* mm/shmem.c */
static struct dentry *shmem_mount(struct file_system_type *fs_type,int flags, const char *dev_name, void *data)
{return mount_nodev(fs_type, flags, data, shmem_fill_super);
}struct dentry *mount_nodev(struct file_system_type *fs_type,int flags, void *data,int (*fill_super)(struct super_block *, void *, int))
{.../* 分配 super block 对象 */struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL);...error = fill_super(s, data, flags & SB_SILENT ? 1 : 0); /* shmem_fill_super(), ... */...
}int shmem_fill_super(struct super_block *sb, void *data, int silent)
{struct inode *inode; /* tmpfs 根目录的 inode */struct shmem_sb_info *sbinfo; /* 特定于 tmpfs 的 super block 信息 */.../* Round up to L1_CACHE_BYTES to resist false sharing */sbinfo = kzalloc(max((int)sizeof(struct shmem_sb_info),L1_CACHE_BYTES), GFP_KERNEL);...sb->s_fs_info = sbinfo;...sb->s_magic = TMPFS_MAGIC;sb->s_op = &shmem_ops;.../* 创建 tmpfs 根目录的 inode */inode = shmem_get_inode(sb, NULL, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);if (!inode)goto failed;inode->i_uid = sbinfo->uid;inode->i_gid = sbinfo->gid;/* 创建 tmpfs 根目录对象 */sb->s_root = d_make_root(inode);...
}static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir,umode_t mode, dev_t dev, unsigned long flags)
{struct inode *inode;...inode = new_inode(sb);if (inode) {inode->i_ino = get_next_ino(); /* 分配 inode 编号 */...inode->i_blocks = 0;inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);inode->i_generation = get_seconds();.../* 根据 inode 的类型,设置对应的接口 */switch (mode & S_IFMT) {...case S_IFDIR: /* 这里的上下文是为 tmpfs 建立的 根目录 的 inode */inc_nlink(inode);/* Some things misbehave if size == 0 on a directory */inode->i_size = 2 * BOGO_DIRENT_SIZE;inode->i_op = &shmem_dir_inode_operations;inode->i_fop = &simple_dir_operations;break;...}} else...return inode;
}
看下来,mount
的重点工作是:
1. 建立文件系统的 super block 。
2. 建立根目录,同时绑定根目录的接口。在例子中的上下文,是绑定 shmem_dir_inode_operations、simple_dir_operations 接口。
建立文件系统 super block
,以及文件系统根目录和其接口设定,自然都是为了管理文件系统。super block
包含文件系统的很多信息,譬如关联的设备,最大 block 尺寸,等等,这里不详细展开。而文件系统根目录,首先是建立了文件系统起始路径
,再就是根目录接口的设定
,其主要目的是用来创建目录和文件
。先看文件创建
的过程:
sys_open()do_sys_open()do_filp_open()path_openat()struct file *file;...file = get_empty_filp(); /* 新建 file 对象 */...do_last(nd, file, op, &opened).../* 创建文件 inode,设置文件 file 对象 */lookup_open(nd, &path, file, op, got_write, opened).../* Negative dentry, just create the file */if (!dentry->d_inode && (open_flag & O_CREAT)) {error = dir_inode->i_op->create(dir_inode, dentry, mode, open_flag & O_EXCL);shmem_create() /* 创建文件 inode 和 接口 */}...vfs_open(&nd->path, file, current_cred());do_dentry_open(file, d_backing_inode(dentry), NULL, cred)...f->f_inode = inode; /* 绑定文件 file 的 inode */.../* 绑定文件 file 对象的接口 &simple_dir_operations */f->f_op = fops_get(inode->i_fop); ... static int shmem_create(struct inode *dir, struct dentry *dentry, umode_t mode,bool excl)
{return shmem_mknod(dir, dentry, mode | S_IFREG, 0);
}static int
shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
{struct inode *inode;...inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE);if (inode) {...d_instantiate(dentry, inode);...}return error;...
}static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir,umode_t mode, dev_t dev, unsigned long flags)
{struct inode *inode;...inode = new_inode(sb);if (inode) {inode->i_ino = get_next_ino(); /* 分配 inode 编号 */...switch (mode & S_IFMT) {...case S_IFREG: /* 文件类型 inode 接口设定 */inode->i_mapping->a_ops = &shmem_aops;inode->i_op = &shmem_inode_operations;inode->i_fop = &shmem_file_operations;mpol_shared_policy_init(&info->policy,shmem_get_sbmpol(sbinfo));break;...}}...
}
再看目录创建
的过程:
sys_mkdir()sys_mkdirat()vfs_mkdir(path.dentry->d_inode, dentry, mode)dir->i_op->mkdir(dir, dentry, mode)shmem_mkdir()shmem_mknod(dir, dentry, mode | S_IFDIR, 0)struct inode *inode;.../* 创建 目录 的 inode ,过程参考前面 tmpfs 的 挂载过程 */inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE);if (inode) {...dir->i_size += BOGO_DIRENT_SIZE;dir->i_ctime = dir->i_mtime = current_time(dir);d_instantiate(dentry, inode);dget(dentry); /* Extra count - pin the dentry in core */}
到此,mount
的主要过程及相关细节已经分析完毕。
简单小结一下,mount
的主要目的就是 建立 super block
和 根目录
,然后绑定的根目录接口又可以进行目录和文件的创建和接口绑定,目录下的目录的接口又可以创建目录和文件,如此层层递推。