summaryrefslogtreecommitdiffstats
path: root/fs/overlayfs
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2017-06-25 09:37:17 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2017-11-09 04:23:26 -0500
commitb79e05aaa166755fafbf02db275175edb5175df8 (patch)
treeaaa5fcc30c2ffe7c22df0074900846917332c08b /fs/overlayfs
parent4eae06de482bf370144704e31f65cd6dfbcebe94 (diff)
ovl: no direct iteration for dir with origin xattr
If a non-merge dir in an overlay mount has an overlay.origin xattr, it means it was once an upper merge dir, which may contain whiteouts and then the lower dir was removed under it. Do not iterate real dir directly in this case to avoid exposing whiteouts. [SzM] Set OVL_WHITEOUT for all merge directories as well. [amir] A directory that was just copied up does not have the OVL_WHITEOUTS flag. We need to set it to fix merge dir iteration. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/overlayfs')
-rw-r--r--fs/overlayfs/copy_up.c7
-rw-r--r--fs/overlayfs/inode.c10
-rw-r--r--fs/overlayfs/overlayfs.h4
-rw-r--r--fs/overlayfs/readdir.c24
-rw-r--r--fs/overlayfs/super.c2
-rw-r--r--fs/overlayfs/util.c13
6 files changed, 55 insertions, 5 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index c441f9387a1b..d07ad7bbd041 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -486,6 +486,7 @@ static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp)
486static int ovl_copy_up_locked(struct ovl_copy_up_ctx *c) 486static int ovl_copy_up_locked(struct ovl_copy_up_ctx *c)
487{ 487{
488 struct inode *udir = c->destdir->d_inode; 488 struct inode *udir = c->destdir->d_inode;
489 struct inode *inode;
489 struct dentry *newdentry = NULL; 490 struct dentry *newdentry = NULL;
490 struct dentry *temp = NULL; 491 struct dentry *temp = NULL;
491 int err; 492 int err;
@@ -508,7 +509,11 @@ static int ovl_copy_up_locked(struct ovl_copy_up_ctx *c)
508 if (err) 509 if (err)
509 goto out_cleanup; 510 goto out_cleanup;
510 511
511 ovl_inode_update(d_inode(c->dentry), newdentry); 512 inode = d_inode(c->dentry);
513 ovl_inode_update(inode, newdentry);
514 if (S_ISDIR(inode->i_mode))
515 ovl_set_flag(OVL_WHITEOUTS, inode);
516
512out: 517out:
513 dput(temp); 518 dput(temp);
514 return err; 519 return err;
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 03f0ec2b73eb..e5a20fd3cbd4 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -661,6 +661,16 @@ struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry,
661 if (upperdentry && ovl_is_impuredir(upperdentry)) 661 if (upperdentry && ovl_is_impuredir(upperdentry))
662 ovl_set_flag(OVL_IMPURE, inode); 662 ovl_set_flag(OVL_IMPURE, inode);
663 663
664 /* Check for non-merge dir that may have whiteouts */
665 if (S_ISDIR(realinode->i_mode)) {
666 struct ovl_entry *oe = dentry->d_fsdata;
667
668 if (((upperdentry && lowerdentry) || oe->numlower > 1) ||
669 ovl_check_origin_xattr(upperdentry ?: lowerdentry)) {
670 ovl_set_flag(OVL_WHITEOUTS, inode);
671 }
672 }
673
664 if (inode->i_state & I_NEW) 674 if (inode->i_state & I_NEW)
665 unlock_new_inode(inode); 675 unlock_new_inode(inode);
666out: 676out:
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index d9a0edd4e57e..d53157ccf0d7 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -28,7 +28,10 @@ enum ovl_path_type {
28#define OVL_XATTR_NLINK OVL_XATTR_PREFIX "nlink" 28#define OVL_XATTR_NLINK OVL_XATTR_PREFIX "nlink"
29 29
30enum ovl_flag { 30enum ovl_flag {
31 /* Pure upper dir that may contain non pure upper entries */
31 OVL_IMPURE, 32 OVL_IMPURE,
33 /* Non-merge dir that may contain whiteout entries */
34 OVL_WHITEOUTS,
32 OVL_INDEX, 35 OVL_INDEX,
33}; 36};
34 37
@@ -223,6 +226,7 @@ bool ovl_is_whiteout(struct dentry *dentry);
223struct file *ovl_path_open(struct path *path, int flags); 226struct file *ovl_path_open(struct path *path, int flags);
224int ovl_copy_up_start(struct dentry *dentry); 227int ovl_copy_up_start(struct dentry *dentry);
225void ovl_copy_up_end(struct dentry *dentry); 228void ovl_copy_up_end(struct dentry *dentry);
229bool ovl_check_origin_xattr(struct dentry *dentry);
226bool ovl_check_dir_xattr(struct dentry *dentry, const char *name); 230bool ovl_check_dir_xattr(struct dentry *dentry, const char *name);
227int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry, 231int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry,
228 const char *name, const void *value, size_t size, 232 const char *name, const void *value, size_t size,
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 698b74dd750e..95d12755f847 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -316,21 +316,37 @@ static inline int ovl_dir_read(struct path *realpath,
316 return err; 316 return err;
317} 317}
318 318
319/*
320 * Can we iterate real dir directly?
321 *
322 * Non-merge dir may contain whiteouts from a time it was a merge upper, before
323 * lower dir was removed under it and possibly before it was rotated from upper
324 * to lower layer.
325 */
326static bool ovl_dir_is_real(struct dentry *dir)
327{
328 return !ovl_test_flag(OVL_WHITEOUTS, d_inode(dir));
329}
330
319static void ovl_dir_reset(struct file *file) 331static void ovl_dir_reset(struct file *file)
320{ 332{
321 struct ovl_dir_file *od = file->private_data; 333 struct ovl_dir_file *od = file->private_data;
322 struct ovl_dir_cache *cache = od->cache; 334 struct ovl_dir_cache *cache = od->cache;
323 struct dentry *dentry = file->f_path.dentry; 335 struct dentry *dentry = file->f_path.dentry;
324 enum ovl_path_type type = ovl_path_type(dentry); 336 bool is_real;
325 337
326 if (cache && ovl_dentry_version_get(dentry) != cache->version) { 338 if (cache && ovl_dentry_version_get(dentry) != cache->version) {
327 ovl_cache_put(od, dentry); 339 ovl_cache_put(od, dentry);
328 od->cache = NULL; 340 od->cache = NULL;
329 od->cursor = NULL; 341 od->cursor = NULL;
330 } 342 }
331 WARN_ON(!od->is_real && !OVL_TYPE_MERGE(type)); 343 is_real = ovl_dir_is_real(dentry);
332 if (od->is_real && OVL_TYPE_MERGE(type)) 344 if (od->is_real != is_real) {
345 /* is_real can only become false when dir is copied up */
346 if (WARN_ON(is_real))
347 return;
333 od->is_real = false; 348 od->is_real = false;
349 }
334} 350}
335 351
336static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list, 352static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list,
@@ -816,7 +832,7 @@ static int ovl_dir_open(struct inode *inode, struct file *file)
816 return PTR_ERR(realfile); 832 return PTR_ERR(realfile);
817 } 833 }
818 od->realfile = realfile; 834 od->realfile = realfile;
819 od->is_real = !OVL_TYPE_MERGE(type); 835 od->is_real = ovl_dir_is_real(file->f_path.dentry);
820 od->is_upper = OVL_TYPE_UPPER(type); 836 od->is_upper = OVL_TYPE_UPPER(type);
821 file->private_data = od; 837 file->private_data = od;
822 838
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index f5738e96a052..8d82a1cb655f 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1141,6 +1141,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
1141 1141
1142 root_dentry->d_fsdata = oe; 1142 root_dentry->d_fsdata = oe;
1143 1143
1144 /* Root is always merge -> can have whiteouts */
1145 ovl_set_flag(OVL_WHITEOUTS, d_inode(root_dentry));
1144 ovl_inode_init(d_inode(root_dentry), upperpath.dentry, 1146 ovl_inode_init(d_inode(root_dentry), upperpath.dentry,
1145 ovl_dentry_lower(root_dentry)); 1147 ovl_dentry_lower(root_dentry));
1146 1148
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index b9b239fa5cfd..51ca8bd16009 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -329,6 +329,19 @@ void ovl_copy_up_end(struct dentry *dentry)
329 mutex_unlock(&OVL_I(d_inode(dentry))->lock); 329 mutex_unlock(&OVL_I(d_inode(dentry))->lock);
330} 330}
331 331
332bool ovl_check_origin_xattr(struct dentry *dentry)
333{
334 int res;
335
336 res = vfs_getxattr(dentry, OVL_XATTR_ORIGIN, NULL, 0);
337
338 /* Zero size value means "copied up but origin unknown" */
339 if (res >= 0)
340 return true;
341
342 return false;
343}
344
332bool ovl_check_dir_xattr(struct dentry *dentry, const char *name) 345bool ovl_check_dir_xattr(struct dentry *dentry, const char *name)
333{ 346{
334 int res; 347 int res;