Commit 2cac0c00 authored by Amir Goldstein's avatar Amir Goldstein Committed by Miklos Szeredi

ovl: get exclusive ownership on upper/work dirs

Bad things can happen if several concurrent overlay mounts try to
use the same upperdir/workdir path.

Try to get the 'inuse' advisory lock on upperdir and workdir.
Fail mount if another overlay mount instance or another user
holds the 'inuse' lock on these directories.

Note that this provides no protection for concurrent overlay
mount that use overlapping (i.e. descendant) upper/work dirs.
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent ad0af710
...@@ -21,6 +21,9 @@ struct ovl_fs { ...@@ -21,6 +21,9 @@ struct ovl_fs {
struct vfsmount *upper_mnt; struct vfsmount *upper_mnt;
unsigned numlower; unsigned numlower;
struct vfsmount **lower_mnt; struct vfsmount **lower_mnt;
/* workbasedir is the path at workdir= mount option */
struct dentry *workbasedir;
/* workdir is the 'work' directory under workbasedir */
struct dentry *workdir; struct dentry *workdir;
long namelen; long namelen;
/* pathnames of lower and upper dirs, for show_options */ /* pathnames of lower and upper dirs, for show_options */
......
...@@ -204,6 +204,10 @@ static void ovl_put_super(struct super_block *sb) ...@@ -204,6 +204,10 @@ static void ovl_put_super(struct super_block *sb)
unsigned i; unsigned i;
dput(ufs->workdir); dput(ufs->workdir);
ovl_inuse_unlock(ufs->workbasedir);
dput(ufs->workbasedir);
if (ufs->upper_mnt)
ovl_inuse_unlock(ufs->upper_mnt->mnt_root);
mntput(ufs->upper_mnt); mntput(ufs->upper_mnt);
for (i = 0; i < ufs->numlower; i++) for (i = 0; i < ufs->numlower; i++)
mntput(ufs->lower_mnt[i]); mntput(ufs->lower_mnt[i]);
...@@ -821,9 +825,15 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -821,9 +825,15 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
if (err) if (err)
goto out_put_upperpath; goto out_put_upperpath;
err = -EBUSY;
if (!ovl_inuse_trylock(upperpath.dentry)) {
pr_err("overlayfs: upperdir is in-use by another mount\n");
goto out_put_upperpath;
}
err = ovl_mount_dir(ufs->config.workdir, &workpath); err = ovl_mount_dir(ufs->config.workdir, &workpath);
if (err) if (err)
goto out_put_upperpath; goto out_unlock_upperdentry;
err = -EINVAL; err = -EINVAL;
if (upperpath.mnt != workpath.mnt) { if (upperpath.mnt != workpath.mnt) {
...@@ -834,12 +844,20 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -834,12 +844,20 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
pr_err("overlayfs: workdir and upperdir must be separate subtrees\n"); pr_err("overlayfs: workdir and upperdir must be separate subtrees\n");
goto out_put_workpath; goto out_put_workpath;
} }
err = -EBUSY;
if (!ovl_inuse_trylock(workpath.dentry)) {
pr_err("overlayfs: workdir is in-use by another mount\n");
goto out_put_workpath;
}
ufs->workbasedir = workpath.dentry;
sb->s_stack_depth = upperpath.mnt->mnt_sb->s_stack_depth; sb->s_stack_depth = upperpath.mnt->mnt_sb->s_stack_depth;
} }
err = -ENOMEM; err = -ENOMEM;
lowertmp = kstrdup(ufs->config.lowerdir, GFP_KERNEL); lowertmp = kstrdup(ufs->config.lowerdir, GFP_KERNEL);
if (!lowertmp) if (!lowertmp)
goto out_put_workpath; goto out_unlock_workdentry;
err = -EINVAL; err = -EINVAL;
stacklen = ovl_split_lowerdirs(lowertmp); stacklen = ovl_split_lowerdirs(lowertmp);
...@@ -882,6 +900,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -882,6 +900,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
pr_err("overlayfs: failed to clone upperpath\n"); pr_err("overlayfs: failed to clone upperpath\n");
goto out_put_lowerpath; goto out_put_lowerpath;
} }
/* Don't inherit atime flags */ /* Don't inherit atime flags */
ufs->upper_mnt->mnt_flags &= ~(MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME); ufs->upper_mnt->mnt_flags &= ~(MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME);
...@@ -1004,7 +1023,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1004,7 +1023,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
mntput(upperpath.mnt); mntput(upperpath.mnt);
for (i = 0; i < numlower; i++) for (i = 0; i < numlower; i++)
mntput(stack[i].mnt); mntput(stack[i].mnt);
path_put(&workpath); mntput(workpath.mnt);
kfree(lowertmp); kfree(lowertmp);
if (upperpath.dentry) { if (upperpath.dentry) {
...@@ -1043,8 +1062,12 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1043,8 +1062,12 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
kfree(stack); kfree(stack);
out_free_lowertmp: out_free_lowertmp:
kfree(lowertmp); kfree(lowertmp);
out_unlock_workdentry:
ovl_inuse_unlock(workpath.dentry);
out_put_workpath: out_put_workpath:
path_put(&workpath); path_put(&workpath);
out_unlock_upperdentry:
ovl_inuse_unlock(upperpath.dentry);
out_put_upperpath: out_put_upperpath:
path_put(&upperpath); path_put(&upperpath);
out_free_config: out_free_config:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment