diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-05-27 12:47:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-05-27 12:47:57 -0400 |
commit | 3cfd4ba7d37b52eb965ed05209647072932dfd0a (patch) | |
tree | 099660db38046f017104820623e4431dd126b757 /fs | |
parent | 1b887bf31dd6e2f8cef80d205d6e9949a7dd98cc (diff) | |
parent | cc6f67bcafcb6bbbb2d1be1603dcd95125a52800 (diff) |
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
Diffstat (limited to 'fs')
-rw-r--r-- | fs/overlayfs/copy_up.c | 3 | ||||
-rw-r--r-- | fs/overlayfs/dir.c | 33 | ||||
-rw-r--r-- | fs/overlayfs/super.c | 10 |
3 files changed, 36 insertions, 10 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 24f640441bd9..84d693d37428 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c | |||
@@ -299,6 +299,9 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, | |||
299 | struct cred *override_cred; | 299 | struct cred *override_cred; |
300 | char *link = NULL; | 300 | char *link = NULL; |
301 | 301 | ||
302 | if (WARN_ON(!workdir)) | ||
303 | return -EROFS; | ||
304 | |||
302 | ovl_path_upper(parent, &parentpath); | 305 | ovl_path_upper(parent, &parentpath); |
303 | upperdir = parentpath.dentry; | 306 | upperdir = parentpath.dentry; |
304 | 307 | ||
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index d139405d2bfa..692ceda3bc21 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c | |||
@@ -222,6 +222,9 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry, | |||
222 | struct kstat stat; | 222 | struct kstat stat; |
223 | int err; | 223 | int err; |
224 | 224 | ||
225 | if (WARN_ON(!workdir)) | ||
226 | return ERR_PTR(-EROFS); | ||
227 | |||
225 | err = ovl_lock_rename_workdir(workdir, upperdir); | 228 | err = ovl_lock_rename_workdir(workdir, upperdir); |
226 | if (err) | 229 | if (err) |
227 | goto out; | 230 | goto out; |
@@ -322,6 +325,9 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, | |||
322 | struct dentry *newdentry; | 325 | struct dentry *newdentry; |
323 | int err; | 326 | int err; |
324 | 327 | ||
328 | if (WARN_ON(!workdir)) | ||
329 | return -EROFS; | ||
330 | |||
325 | err = ovl_lock_rename_workdir(workdir, upperdir); | 331 | err = ovl_lock_rename_workdir(workdir, upperdir); |
326 | if (err) | 332 | if (err) |
327 | goto out; | 333 | goto out; |
@@ -506,11 +512,28 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir) | |||
506 | struct dentry *opaquedir = NULL; | 512 | struct dentry *opaquedir = NULL; |
507 | int err; | 513 | int err; |
508 | 514 | ||
509 | if (is_dir && OVL_TYPE_MERGE_OR_LOWER(ovl_path_type(dentry))) { | 515 | if (WARN_ON(!workdir)) |
510 | opaquedir = ovl_check_empty_and_clear(dentry); | 516 | return -EROFS; |
511 | err = PTR_ERR(opaquedir); | 517 | |
512 | if (IS_ERR(opaquedir)) | 518 | if (is_dir) { |
513 | goto out; | 519 | if (OVL_TYPE_MERGE_OR_LOWER(ovl_path_type(dentry))) { |
520 | opaquedir = ovl_check_empty_and_clear(dentry); | ||
521 | err = PTR_ERR(opaquedir); | ||
522 | if (IS_ERR(opaquedir)) | ||
523 | goto out; | ||
524 | } else { | ||
525 | LIST_HEAD(list); | ||
526 | |||
527 | /* | ||
528 | * When removing an empty opaque directory, then it | ||
529 | * makes no sense to replace it with an exact replica of | ||
530 | * itself. But emptiness still needs to be checked. | ||
531 | */ | ||
532 | err = ovl_check_empty_dir(dentry, &list); | ||
533 | ovl_cache_free(&list); | ||
534 | if (err) | ||
535 | goto out; | ||
536 | } | ||
514 | } | 537 | } |
515 | 538 | ||
516 | err = ovl_lock_rename_workdir(workdir, upperdir); | 539 | err = ovl_lock_rename_workdir(workdir, upperdir); |
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 5f0d1993e6e3..bf8537c7f455 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
@@ -529,7 +529,7 @@ static int ovl_remount(struct super_block *sb, int *flags, char *data) | |||
529 | { | 529 | { |
530 | struct ovl_fs *ufs = sb->s_fs_info; | 530 | struct ovl_fs *ufs = sb->s_fs_info; |
531 | 531 | ||
532 | if (!(*flags & MS_RDONLY) && !ufs->upper_mnt) | 532 | if (!(*flags & MS_RDONLY) && (!ufs->upper_mnt || !ufs->workdir)) |
533 | return -EROFS; | 533 | return -EROFS; |
534 | 534 | ||
535 | return 0; | 535 | return 0; |
@@ -925,9 +925,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
925 | ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); | 925 | ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); |
926 | err = PTR_ERR(ufs->workdir); | 926 | err = PTR_ERR(ufs->workdir); |
927 | if (IS_ERR(ufs->workdir)) { | 927 | if (IS_ERR(ufs->workdir)) { |
928 | pr_err("overlayfs: failed to create directory %s/%s\n", | 928 | pr_warn("overlayfs: failed to create directory %s/%s (errno: %i); mounting read-only\n", |
929 | ufs->config.workdir, OVL_WORKDIR_NAME); | 929 | ufs->config.workdir, OVL_WORKDIR_NAME, -err); |
930 | goto out_put_upper_mnt; | 930 | sb->s_flags |= MS_RDONLY; |
931 | ufs->workdir = NULL; | ||
931 | } | 932 | } |
932 | } | 933 | } |
933 | 934 | ||
@@ -997,7 +998,6 @@ out_put_lower_mnt: | |||
997 | kfree(ufs->lower_mnt); | 998 | kfree(ufs->lower_mnt); |
998 | out_put_workdir: | 999 | out_put_workdir: |
999 | dput(ufs->workdir); | 1000 | dput(ufs->workdir); |
1000 | out_put_upper_mnt: | ||
1001 | mntput(ufs->upper_mnt); | 1001 | mntput(ufs->upper_mnt); |
1002 | out_put_lowerpath: | 1002 | out_put_lowerpath: |
1003 | for (i = 0; i < numlower; i++) | 1003 | for (i = 0; i < numlower; i++) |