Commit 3cfd4ba7 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'overlayfs-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs

Pull two overlayfs fixes from Miklos Szeredi:
 "Overlayfs rmdir() failed to check for emptiness in one case; this was
  introduced in 4.0.  The other bug was there since day one: failure to
  mount if upper fs is full, which bit some OpenWRT folks"

* 'overlayfs-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ovl: mount read-only if workdir can't be created
  ovl: don't remove non-empty opaque directory
parents 1b887bf3 cc6f67bc
...@@ -299,6 +299,9 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, ...@@ -299,6 +299,9 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
struct cred *override_cred; struct cred *override_cred;
char *link = NULL; char *link = NULL;
if (WARN_ON(!workdir))
return -EROFS;
ovl_path_upper(parent, &parentpath); ovl_path_upper(parent, &parentpath);
upperdir = parentpath.dentry; upperdir = parentpath.dentry;
......
...@@ -222,6 +222,9 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry, ...@@ -222,6 +222,9 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
struct kstat stat; struct kstat stat;
int err; int err;
if (WARN_ON(!workdir))
return ERR_PTR(-EROFS);
err = ovl_lock_rename_workdir(workdir, upperdir); err = ovl_lock_rename_workdir(workdir, upperdir);
if (err) if (err)
goto out; goto out;
...@@ -322,6 +325,9 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, ...@@ -322,6 +325,9 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
struct dentry *newdentry; struct dentry *newdentry;
int err; int err;
if (WARN_ON(!workdir))
return -EROFS;
err = ovl_lock_rename_workdir(workdir, upperdir); err = ovl_lock_rename_workdir(workdir, upperdir);
if (err) if (err)
goto out; goto out;
...@@ -506,11 +512,28 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir) ...@@ -506,11 +512,28 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
struct dentry *opaquedir = NULL; struct dentry *opaquedir = NULL;
int err; int err;
if (is_dir && OVL_TYPE_MERGE_OR_LOWER(ovl_path_type(dentry))) { if (WARN_ON(!workdir))
opaquedir = ovl_check_empty_and_clear(dentry); return -EROFS;
err = PTR_ERR(opaquedir);
if (IS_ERR(opaquedir)) if (is_dir) {
goto out; if (OVL_TYPE_MERGE_OR_LOWER(ovl_path_type(dentry))) {
opaquedir = ovl_check_empty_and_clear(dentry);
err = PTR_ERR(opaquedir);
if (IS_ERR(opaquedir))
goto out;
} else {
LIST_HEAD(list);
/*
* When removing an empty opaque directory, then it
* makes no sense to replace it with an exact replica of
* itself. But emptiness still needs to be checked.
*/
err = ovl_check_empty_dir(dentry, &list);
ovl_cache_free(&list);
if (err)
goto out;
}
} }
err = ovl_lock_rename_workdir(workdir, upperdir); err = ovl_lock_rename_workdir(workdir, upperdir);
......
...@@ -529,7 +529,7 @@ static int ovl_remount(struct super_block *sb, int *flags, char *data) ...@@ -529,7 +529,7 @@ static int ovl_remount(struct super_block *sb, int *flags, char *data)
{ {
struct ovl_fs *ufs = sb->s_fs_info; struct ovl_fs *ufs = sb->s_fs_info;
if (!(*flags & MS_RDONLY) && !ufs->upper_mnt) if (!(*flags & MS_RDONLY) && (!ufs->upper_mnt || !ufs->workdir))
return -EROFS; return -EROFS;
return 0; return 0;
...@@ -925,9 +925,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -925,9 +925,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry);
err = PTR_ERR(ufs->workdir); err = PTR_ERR(ufs->workdir);
if (IS_ERR(ufs->workdir)) { if (IS_ERR(ufs->workdir)) {
pr_err("overlayfs: failed to create directory %s/%s\n", pr_warn("overlayfs: failed to create directory %s/%s (errno: %i); mounting read-only\n",
ufs->config.workdir, OVL_WORKDIR_NAME); ufs->config.workdir, OVL_WORKDIR_NAME, -err);
goto out_put_upper_mnt; sb->s_flags |= MS_RDONLY;
ufs->workdir = NULL;
} }
} }
...@@ -997,7 +998,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -997,7 +998,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
kfree(ufs->lower_mnt); kfree(ufs->lower_mnt);
out_put_workdir: out_put_workdir:
dput(ufs->workdir); dput(ufs->workdir);
out_put_upper_mnt:
mntput(ufs->upper_mnt); mntput(ufs->upper_mnt);
out_put_lowerpath: out_put_lowerpath:
for (i = 0; i < numlower; i++) for (i = 0; i < numlower; i++)
......
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