Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ab508822 authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

ovl: improve mount helpers



Move common checks into ovl_mount_dir() helper.

Create helper for looking up lower directories.

Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
parent 3b7a9a24
Loading
Loading
Loading
Loading
+73 −52
Original line number Diff line number Diff line
@@ -669,24 +669,6 @@ static void ovl_unescape(char *s)
	}
}

static int ovl_mount_dir(const char *name, struct path *path)
{
	int err;
	char *tmp = kstrdup(name, GFP_KERNEL);

	if (!tmp)
		return -ENOMEM;

	ovl_unescape(tmp);
	err = kern_path(tmp, LOOKUP_FOLLOW, path);
	if (err) {
		pr_err("overlayfs: failed to resolve '%s': %i\n", tmp, err);
		err = -EINVAL;
	}
	kfree(tmp);
	return err;
}

static bool ovl_is_allowed_fs_type(struct dentry *root)
{
	const struct dentry_operations *dop = root->d_op;
@@ -706,6 +688,71 @@ static bool ovl_is_allowed_fs_type(struct dentry *root)
	return true;
}

static int ovl_mount_dir_noesc(const char *name, struct path *path)
{
	int err;

	err = kern_path(name, LOOKUP_FOLLOW, path);
	if (err) {
		pr_err("overlayfs: failed to resolve '%s': %i\n", name, err);
		goto out;
	}
	err = -EINVAL;
	if (!ovl_is_allowed_fs_type(path->dentry)) {
		pr_err("overlayfs: filesystem on '%s' not supported\n", name);
		goto out_put;
	}
	if (!S_ISDIR(path->dentry->d_inode->i_mode)) {
		pr_err("overlayfs: '%s' not a directory\n", name);
		goto out_put;
	}
	return 0;

out_put:
	path_put(path);
out:
	return err;
}

static int ovl_mount_dir(const char *name, struct path *path)
{
	int err = -ENOMEM;
	char *tmp = kstrdup(name, GFP_KERNEL);

	if (tmp) {
		ovl_unescape(tmp);
		err = ovl_mount_dir_noesc(tmp, path);
		kfree(tmp);
	}
	return err;
}

static int ovl_lower_dir(const char *name, struct path *path, long *namelen,
			 int *stack_depth)
{
	int err;
	struct kstatfs statfs;

	err = ovl_mount_dir(name, path);
	if (err)
		goto out;

	err = vfs_statfs(path, &statfs);
	if (err) {
		pr_err("overlayfs: statfs failed on '%s'\n", name);
		goto out_put;
	}
	*namelen = max(*namelen, statfs.f_namelen);
	*stack_depth = max(*stack_depth, path->mnt->mnt_sb->s_stack_depth);

	return 0;

out_put:
	path_put(path);
out:
	return err;
}

/* Workdir should not be subdir of upperdir and vice versa */
static bool ovl_workdir_ok(struct dentry *workdir, struct dentry *upperdir)
{
@@ -726,7 +773,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
	struct dentry *root_dentry;
	struct ovl_entry *oe;
	struct ovl_fs *ufs;
	struct kstatfs statfs;
	struct vfsmount *mnt;
	unsigned int i;
	int err;
@@ -756,48 +802,23 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
	if (err)
		goto out_put_upperpath;

	err = ovl_mount_dir(ufs->config.lowerdir, &lowerpath);
	if (err)
		goto out_put_workpath;

	err = -EINVAL;
	if (!S_ISDIR(upperpath.dentry->d_inode->i_mode) ||
	    !S_ISDIR(lowerpath.dentry->d_inode->i_mode) ||
	    !S_ISDIR(workpath.dentry->d_inode->i_mode)) {
		pr_err("overlayfs: upperdir or lowerdir or workdir not a directory\n");
		goto out_put_lowerpath;
	}

	if (upperpath.mnt != workpath.mnt) {
		pr_err("overlayfs: workdir and upperdir must reside under the same mount\n");
		goto out_put_lowerpath;
		goto out_put_workpath;
	}
	if (!ovl_workdir_ok(workpath.dentry, upperpath.dentry)) {
		pr_err("overlayfs: workdir and upperdir must be separate subtrees\n");
		goto out_put_lowerpath;
	}

	if (!ovl_is_allowed_fs_type(upperpath.dentry)) {
		pr_err("overlayfs: filesystem of upperdir is not supported\n");
		goto out_put_lowerpath;
	}

	if (!ovl_is_allowed_fs_type(lowerpath.dentry)) {
		pr_err("overlayfs: filesystem of lowerdir is not supported\n");
		goto out_put_lowerpath;
	}

	err = vfs_statfs(&lowerpath, &statfs);
	if (err) {
		pr_err("overlayfs: statfs failed on lowerpath\n");
		goto out_put_lowerpath;
		goto out_put_workpath;
	}
	ufs->lower_namelen = statfs.f_namelen;
	sb->s_stack_depth = upperpath.mnt->mnt_sb->s_stack_depth;

	sb->s_stack_depth = max(upperpath.mnt->mnt_sb->s_stack_depth,
				lowerpath.mnt->mnt_sb->s_stack_depth) + 1;
	err = ovl_lower_dir(ufs->config.lowerdir, &lowerpath,
			    &ufs->lower_namelen, &sb->s_stack_depth);
	if (err)
		goto out_put_workpath;

	err = -EINVAL;
	sb->s_stack_depth++;
	if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) {
		pr_err("overlayfs: maximum fs stacking depth exceeded\n");
		goto out_put_lowerpath;