OverlayFS 注册与挂载

1 篇文章 0 订阅

Overlayfs 注册与挂载

OverlayFs 注册

OverlayFs在内核中以模块的形式存在,在加载模块时,会涉及到两个关键函数:入口函数和出口函数

module_init(ovl_init);
module_exit(ovl_exit);

当使用命令 overlay 加载 overlayfs 模块时,会调用入口函数 ovl_init()

static int __init ovl_init(void) {
    return register_filesystem(&ovl_fs_type);
}

当加载 overlay 模块时,模块入口函数 register_fileststem 函数注册 overlayfs:

#include <linux/fs.h>

extern int register_filesystem(struct file_system_type *);

注册一个文件系统需要用到 struct file_ststem_type,这个结构定义了文件系统的名称,挂载函数等信息:

struct file_system_type {
	const char *name;
	int fs_flags;
    struct dentry *(*mount) (struct file_system_type *, int,
                    const char *, void *);
    void (*kill_sb) (struct super_block *);
    struct module *owner;
    struct file_system_type * next;
    struct list_head fs_supers;
	struct lock_class_key s_lock_key;
	struct lock_class_key s_umount_key;
};

OverlayFs 挂载

在 overlayfs/super.c 中指明了挂载函数:.mount = ovl_mount

static struct file_system_type ovl_fs_type = {
	.owner		= THIS_MODULE,
	.name		= "overlay",
	.mount		= ovl_mount,
	.kill_sb	= kill_anon_super,
};
MODULE_ALIAS_FS("overlay");

ovl_mount 是函数 mount_nodev 的封装:

static struct dentry *ovl_mount(struct file_system_type *fs_type, int flags,
				const char *dev_name, void *raw_data)
{
	return mount_nodev(fs_type, flags, raw_data, ovl_fill_super);
}

struct dentry *mount_nodev(struct file_system_type *fs_type,
	int flags, void *data,
	int (*fill_super)(struct super_block *, void *, int))
{
	...
    // 1.创建一个 superblock ,它已经链接到全局 superblock 链表中
	struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL);

	...
    // 2. 填充 superblock
	error = fill_super(s, data, flags & SB_SILENT ? 1 : 0);
	...
}
EXPORT_SYMBOL(mount_nodev);

OverlayFs挂载信息

结构体 ovl_fs 以及 ovl_config 是 Overlayfs 的特有信息,它记录了 OverlayFs upper 层和 lower 层的文件系统、文件名以及 work 目录的 dentry 这些挂载信息:

/* private information held for overlayfs's superblock */
struct ovl_fs {
	struct vfsmount *upper_mnt;
	unsigned int numlayer;
	/* Number of unique fs among layers including upper fs */
	unsigned int numfs;
	struct ovl_layer *layers;
	struct ovl_sb *fs;
	/* workbasedir is the path at workdir= mount option */
	struct dentry *workbasedir;
	/* workdir is the 'work' directory under workbasedir */
	struct dentry *workdir;
	/* index directory listing overlay inodes by origin file handle */
	struct dentry *indexdir;
	long namelen;
	/* pathnames of lower and upper dirs, for show_options */
	struct ovl_config config;
	/* creds of process who forced instantiation of super block */
	const struct cred *creator_cred;
	bool tmpfile;
	bool noxattr;
	/* Did we take the inuse lock? */
	bool upperdir_locked;
	bool workdir_locked;
	/* Traps in ovl inode cache */
	struct inode *upperdir_trap;
	struct inode *workbasedir_trap;
	struct inode *workdir_trap;
	struct inode *indexdir_trap;
	/* -1: disabled, 0: same fs, 1..32: number of unused ino bits */
	int xino_mode;
	/* For allocation of non-persistent inode numbers */
	atomic_long_t last_ino;
};

struct ovl_config {
	char *lowerdir;
	char *upperdir;
	char *workdir;
	bool default_permissions;
	bool redirect_dir;
	bool redirect_follow;
	const char *redirect_mode;
	bool index;
	bool nfs_export;
	int xino;
	bool metacopy;
};

填充 super_block

填充 super_block 由函数 ovl_file_super 完成,主要包括下列工作:

  1. 分配一个 ovl_fs 结构的 ofs,调用函数 ovl_parse_opt() 对挂载命令进行解析,得到 upper、lower、work 目录的字符串,存入 ofs 的 config 字段:
struct ovl_fs *ofs;	//存储 overlayfs 挂载信息
...
ofs = kzalloc(sizeof(struct ovl_fs), GFP_KERNEL);
...
err = ovl_parse_opt((char *)data, &ofs->config);
...
  1. 对 upper 目录和 worker 目录的字符串进行解析。
if (ofs->config.upperdir) {
		...
		err = ovl_get_upper(sb, ofs, &upperpath);
		...
		err = ovl_get_workdir(sb, ofs, &upperpath);
		...
}

内核通过 ovl_get_upper() 以及 ovl_get_workdir() 来获得 upper 层和 work 目录的路径,最终都会调用 kern_path() 执行路径解析,得到目录,在解析完路径之后,函数内部会对其进行有效性检查,要求 upper 目录与 work 目录必须处在相同文件系统下,同时要求两个目录不能在同一子树中

  1. 函数 ovl_get_lowerstack() 对记录 lower 层的字符串进行解析,分析出 lower 层数,循环调用函数 ovl_lower_dir() 对 lower 层进行解析,该函数最终也会调用到 kern_path() 执行路径解析,得到每个 lower 目录的路径,保存在路径栈 stack 中:
// func ovl_get_lowerstack()
...
// 复制 lower 层的字符串
lowertmp = kstrdup(ofs->config.lowerdir, GFP_KERNEL);
...
// 得到 lower 层数目
stacklen = ovl_split_lowerdirs(lowertmp);
...
// 为路径栈分配空间
stack = kcalloc(stacklen, sizeof(struct path), GFP_KERNEL);
...
// 循环获取每个 lower 层的路径
for (numlower = 0; numlower < stacklen; numlower++) {
    err = ovl_lower_dir(lower, &stack[numlower], ofs,
                        &sb->s_stack_depth, &remote);
	...
}
...
  1. 填充 struct ovl_entry 类型的变量 oe 分配空间(这个变量记录 OverlayFS 根目录的层次信息,由根目录指向)。为 OverlayFS 根目录分配 inode,创建根目录的 dentry。通过前面得到的 upper 层和 lower 层的路径填充 oe,然后设置根目录 dentry 的 d_fsdata 字段指向 oe。

  2. 填充 super_block 的 s_d_op 字段,这个字段是一个 struct dentry_operations 类型的指针,它描述了 OverlayFS 的 dentry 操作,每当在 OverlayFS 中分配一个 dentry 时,会使用 s_d_op 字段赋值 dentry 的 d_op 字段

    // func ovl_get_lowerstack()
    ...
    // 填充 oe
    for (i = 0; i < numlower; i++) {
        oe->lowerstack[i].dentry = dget(stack[i].dentry);
        oe->lowerstack[i].layer = &ofs->layers[i+1];
    }
    // 填充 sb->s_d_op
    if (remote)
        sb->s_d_op = &ovl_reval_dentry_operations;
    else
        sb->s_d_op = &ovl_dentry_operations;
    ...
    
    // func ovl_get_root()
    ...
    // 为根目录分配inode,创建dentry
    root = d_make_root(ovl_new_inode(sb, S_IFDIR, 0));
    ...
    
    
  3. 填充 super_block 的剩余字段

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值