History

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

Pull overlayfs fixes from Miklos Szeredi: "Fix a regression in 4.14 and one in 4.13. The latter is a case when Docker is doing something it really shouldn't and gets away with it. We now print a warning instead of erroring out. There are also fixes to several error paths" * 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: fix regression caused by exclusive upper/work dir protection ovl: fix missing unlock_rename() in ovl_do_copy_up() ovl: fix dentry leak in ovl_indexdir_cleanup() ovl: fix dput() of ERR_PTR in ovl_cleanup_index() ovl: fix error value printed in ovl_lookup_index() ovl: fix may_write_real() for overlayfs directories

Linus Torvalds committed 9 years ago

Commit 8d4ef4e2 parents 1249b57 85fdee110 files · +60 −37Browse files

Unified · Split

10 files
  1. Documentation/filesystems/overlayfs.txt +4 −1
  2. fs/namespace.c +3 −1
  3. fs/overlayfs/copy_up.c +2 −4
  4. fs/overlayfs/dir.c +0 −20
  5. fs/overlayfs/namei.c +1 −0
  6. fs/overlayfs/overlayfs.h +1 −0
  7. fs/overlayfs/ovl_entry.h +3 −0
  8. fs/overlayfs/readdir.c +4 −2
  9. fs/overlayfs/super.c +19 −8
  10. fs/overlayfs/util.c +23 −1
Documentation/filesystems/overlayfs.txt+4−1
@@ -210,8 +210,11 @@ path as another overlay mount and it may use a lower layer path that is · 209 unmodified lines
210beneath or above the path of another overlay lower layer path.210beneath or above the path of another overlay lower layer path.
211 211
212Using an upper layer path and/or a workdir path that are already used by212Using an upper layer path and/or a workdir path that are already used by
213another overlay mount is not allowed and will fail with EBUSY. Using213another overlay mount is not allowed and may fail with EBUSY. Using
214partially overlapping paths is not allowed but will not fail with EBUSY.214partially overlapping paths is not allowed but will not fail with EBUSY.
215If files are accessed from two overlayfs mounts which share or overlap the
216upper layer and/or workdir path the behavior of the overlay is undefined,
217though it will not result in a crash or deadlock.
215 218
216Mounting an overlay using an upper layer path, where the upper layer path219Mounting an overlay using an upper layer path, where the upper layer path
217was previously used by another mounted overlay in combination with a220was previously used by another mounted overlay in combination with a
fs/namespace.c+3−1
@@ -468,7 +468,9 @@ static inline int may_write_real(struct file *file) · 467 unmodified lines
468 468
469 /* File refers to upper, writable layer? */469 /* File refers to upper, writable layer? */
470 upperdentry = d_real(dentry, NULL, 0, D_REAL_UPPER);470 upperdentry = d_real(dentry, NULL, 0, D_REAL_UPPER);
471 if (upperdentry && file_inode(file) == d_inode(upperdentry))471 if (upperdentry &&
472 (file_inode(file) == d_inode(upperdentry) ||
473 file_inode(file) == d_inode(dentry)))
472 return 0;474 return 0;
473 475
474 /* Lower layer: can't write to real file, sorry... */476 /* Lower layer: can't write to real file, sorry... */
fs/overlayfs/copy_up.c+2−4
@@ -561,10 +561,8 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c) · 560 unmodified lines
561 c->tmpfile = true;561 c->tmpfile = true;
562 err = ovl_copy_up_locked(c);562 err = ovl_copy_up_locked(c);
563 } else {563 } else {
564 err = -EIO;564 err = ovl_lock_rename_workdir(c->workdir, c->destdir);
565 if (lock_rename(c->workdir, c->destdir) != NULL) {565 if (!err) {
566 pr_err("overlayfs: failed to lock workdir+upperdir\n");
567 } else {
568 err = ovl_copy_up_locked(c);566 err = ovl_copy_up_locked(c);
569 unlock_rename(c->workdir, c->destdir);567 unlock_rename(c->workdir, c->destdir);
570 }568 }
fs/overlayfs/dir.c+0−20
@@ -216,26 +216,6 @@ out_unlock: · 215 unmodified lines
216 return err;216 return err;
217}217}
218 218
219static int ovl_lock_rename_workdir(struct dentry *workdir,
220 struct dentry *upperdir)
221{
222 /* Workdir should not be the same as upperdir */
223 if (workdir == upperdir)
224 goto err;
225
226 /* Workdir should not be subdir of upperdir and vice versa */
227 if (lock_rename(workdir, upperdir) != NULL)
228 goto err_unlock;
229
230 return 0;
231
232err_unlock:
233 unlock_rename(workdir, upperdir);
234err:
235 pr_err("overlayfs: failed to lock workdir+upperdir\n");
236 return -EIO;
237}
238
239static struct dentry *ovl_clear_empty(struct dentry *dentry,219static struct dentry *ovl_clear_empty(struct dentry *dentry,
240 struct list_head *list)220 struct list_head *list)
241{221{
fs/overlayfs/namei.c+1−0
@@ -506,6 +506,7 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry, · 505 unmodified lines
506 506
507 index = lookup_one_len_unlocked(name.name, ofs->indexdir, name.len);507 index = lookup_one_len_unlocked(name.name, ofs->indexdir, name.len);
508 if (IS_ERR(index)) {508 if (IS_ERR(index)) {
509 err = PTR_ERR(index);
509 pr_warn_ratelimited("overlayfs: failed inode index lookup (ino=%lu, key=%*s, err=%i);\n"510 pr_warn_ratelimited("overlayfs: failed inode index lookup (ino=%lu, key=%*s, err=%i);\n"
510 "overlayfs: mount with '-o index=off' to disable inodes index.\n",511 "overlayfs: mount with '-o index=off' to disable inodes index.\n",
511 d_inode(origin)->i_ino, name.len, name.name,512 d_inode(origin)->i_ino, name.len, name.name,
fs/overlayfs/overlayfs.h+1−0
@@ -235,6 +235,7 @@ bool ovl_inuse_trylock(struct dentry *dentry); · 234 unmodified lines
235void ovl_inuse_unlock(struct dentry *dentry);235void ovl_inuse_unlock(struct dentry *dentry);
236int ovl_nlink_start(struct dentry *dentry, bool *locked);236int ovl_nlink_start(struct dentry *dentry, bool *locked);
237void ovl_nlink_end(struct dentry *dentry, bool locked);237void ovl_nlink_end(struct dentry *dentry, bool locked);
238int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir);
238 239
239static inline bool ovl_is_impuredir(struct dentry *dentry)240static inline bool ovl_is_impuredir(struct dentry *dentry)
240{241{
fs/overlayfs/ovl_entry.h+3−0
@@ -37,6 +37,9 @@ struct ovl_fs { · 36 unmodified lines
37 bool noxattr;37 bool noxattr;
38 /* sb common to all layers */38 /* sb common to all layers */
39 struct super_block *same_sb;39 struct super_block *same_sb;
40 /* Did we take the inuse lock? */
41 bool upperdir_locked;
42 bool workdir_locked;
40};43};
41 44
42/* private information held for every overlayfs dentry */45/* private information held for every overlayfs dentry */
fs/overlayfs/readdir.c+4−2
@@ -988,6 +988,7 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt, · 987 unmodified lines
988 struct path *lowerstack, unsigned int numlower)988 struct path *lowerstack, unsigned int numlower)
989{989{
990 int err;990 int err;
991 struct dentry *index = NULL;
991 struct inode *dir = dentry->d_inode;992 struct inode *dir = dentry->d_inode;
992 struct path path = { .mnt = mnt, .dentry = dentry };993 struct path path = { .mnt = mnt, .dentry = dentry };
993 LIST_HEAD(list);994 LIST_HEAD(list);
@@ -1007,8 +1008,6 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt, · 13 unmodified lines
1007 1008
1008 inode_lock_nested(dir, I_MUTEX_PARENT);1009 inode_lock_nested(dir, I_MUTEX_PARENT);
1009 list_for_each_entry(p, &list, l_node) {1010 list_for_each_entry(p, &list, l_node) {
1010 struct dentry *index;
1011
1012 if (p->name[0] == '.') {1011 if (p->name[0] == '.') {
1013 if (p->len == 1)1012 if (p->len == 1)
1014 continue;1013 continue;
@@ -1018,6 +1017,7 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt, · 3 unmodified lines
1018 index = lookup_one_len(p->name, dentry, p->len);1017 index = lookup_one_len(p->name, dentry, p->len);
1019 if (IS_ERR(index)) {1018 if (IS_ERR(index)) {
1020 err = PTR_ERR(index);1019 err = PTR_ERR(index);
1020 index = NULL;
1021 break;1021 break;
1022 }1022 }
1023 err = ovl_verify_index(index, lowerstack, numlower);1023 err = ovl_verify_index(index, lowerstack, numlower);
@@ -1029,7 +1029,9 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt, · 5 unmodified lines
1029 break;1029 break;
1030 }1030 }
1031 dput(index);1031 dput(index);
1032 index = NULL;
1032 }1033 }
1034 dput(index);
1033 inode_unlock(dir);1035 inode_unlock(dir);
1034out:1036out:
1035 ovl_cache_free(&list);1037 ovl_cache_free(&list);
fs/overlayfs/super.c+19−8
@@ -211,9 +211,10 @@ static void ovl_put_super(struct super_block *sb) · 210 unmodified lines
211 211
212 dput(ufs->indexdir);212 dput(ufs->indexdir);
213 dput(ufs->workdir);213 dput(ufs->workdir);
214 ovl_inuse_unlock(ufs->workbasedir);214 if (ufs->workdir_locked)
215 ovl_inuse_unlock(ufs->workbasedir);
215 dput(ufs->workbasedir);216 dput(ufs->workbasedir);
216 if (ufs->upper_mnt)217 if (ufs->upper_mnt && ufs->upperdir_locked)
217 ovl_inuse_unlock(ufs->upper_mnt->mnt_root);218 ovl_inuse_unlock(ufs->upper_mnt->mnt_root);
218 mntput(ufs->upper_mnt);219 mntput(ufs->upper_mnt);
219 for (i = 0; i < ufs->numlower; i++)220 for (i = 0; i < ufs->numlower; i++)
@@ -881,9 +882,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) · 661 unmodified lines
881 goto out_put_upperpath;882 goto out_put_upperpath;
882 883
883 err = -EBUSY;884 err = -EBUSY;
884 if (!ovl_inuse_trylock(upperpath.dentry)) {885 if (ovl_inuse_trylock(upperpath.dentry)) {
885 pr_err("overlayfs: upperdir is in-use by another mount\n");886 ufs->upperdir_locked = true;
887 } else if (ufs->config.index) {
888 pr_err("overlayfs: upperdir is in-use by another mount, mount with '-o index=off' to override exclusive upperdir protection.\n");
886 goto out_put_upperpath;889 goto out_put_upperpath;
890 } else {
891 pr_warn("overlayfs: upperdir is in-use by another mount, accessing files from both mounts will result in undefined behavior.\n");
887 }892 }
888 893
889 err = ovl_mount_dir(ufs->config.workdir, &workpath);894 err = ovl_mount_dir(ufs->config.workdir, &workpath);
@@ -901,9 +906,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) · 11 unmodified lines
901 }906 }
902 907
903 err = -EBUSY;908 err = -EBUSY;
904 if (!ovl_inuse_trylock(workpath.dentry)) {909 if (ovl_inuse_trylock(workpath.dentry)) {
905 pr_err("overlayfs: workdir is in-use by another mount\n");910 ufs->workdir_locked = true;
911 } else if (ufs->config.index) {
912 pr_err("overlayfs: workdir is in-use by another mount, mount with '-o index=off' to override exclusive workdir protection.\n");
906 goto out_put_workpath;913 goto out_put_workpath;
914 } else {
915 pr_warn("overlayfs: workdir is in-use by another mount, accessing files from both mounts will result in undefined behavior.\n");
907 }916 }
908 917
909 ufs->workbasedir = workpath.dentry;918 ufs->workbasedir = workpath.dentry;
@@ -1156,11 +1165,13 @@ out_put_lowerpath: · 246 unmodified lines
1156out_free_lowertmp:1165out_free_lowertmp:
1157 kfree(lowertmp);1166 kfree(lowertmp);
1158out_unlock_workdentry:1167out_unlock_workdentry:
1159 ovl_inuse_unlock(workpath.dentry);1168 if (ufs->workdir_locked)
1169 ovl_inuse_unlock(workpath.dentry);
1160out_put_workpath:1170out_put_workpath:
1161 path_put(&workpath);1171 path_put(&workpath);
1162out_unlock_upperdentry:1172out_unlock_upperdentry:
1163 ovl_inuse_unlock(upperpath.dentry);1173 if (ufs->upperdir_locked)
1174 ovl_inuse_unlock(upperpath.dentry);
1164out_put_upperpath:1175out_put_upperpath:
1165 path_put(&upperpath);1176 path_put(&upperpath);
1166out_free_config:1177out_free_config:
fs/overlayfs/util.c+23−1
@@ -430,7 +430,7 @@ void ovl_inuse_unlock(struct dentry *dentry) · 429 unmodified lines
430 }430 }
431}431}
432 432
433/* Called must hold OVL_I(inode)->oi_lock */433/* Caller must hold OVL_I(inode)->lock */
434static void ovl_cleanup_index(struct dentry *dentry)434static void ovl_cleanup_index(struct dentry *dentry)
435{435{
436 struct inode *dir = ovl_indexdir(dentry->d_sb)->d_inode;436 struct inode *dir = ovl_indexdir(dentry->d_sb)->d_inode;
@@ -469,6 +469,9 @@ static void ovl_cleanup_index(struct dentry *dentry) · 32 unmodified lines
469 err = PTR_ERR(index);469 err = PTR_ERR(index);
470 if (!IS_ERR(index))470 if (!IS_ERR(index))
471 err = ovl_cleanup(dir, index);471 err = ovl_cleanup(dir, index);
472 else
473 index = NULL;
474
472 inode_unlock(dir);475 inode_unlock(dir);
473 if (err)476 if (err)
474 goto fail;477 goto fail;
@@ -557,3 +560,22 @@ void ovl_nlink_end(struct dentry *dentry, bool locked) · 82 unmodified lines
557 mutex_unlock(&OVL_I(d_inode(dentry))->lock);560 mutex_unlock(&OVL_I(d_inode(dentry))->lock);
558 }561 }
559}562}
563
564int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir)
565{
566 /* Workdir should not be the same as upperdir */
567 if (workdir == upperdir)
568 goto err;
569
570 /* Workdir should not be subdir of upperdir and vice versa */
571 if (lock_rename(workdir, upperdir) != NULL)
572 goto err_unlock;
573
574 return 0;
575
576err_unlock:
577 unlock_rename(workdir, upperdir);
578err:
579 pr_err("overlayfs: failed to lock workdir+upperdir\n");
580 return -EIO;
581}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t