aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2017-06-21 06:46:12 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2017-07-04 16:03:19 -0400
commitcaf70cb2ba5dff85ea90f494a30075af92df13b0 (patch)
treed93982b090f4ff5f56a733e8aec083959f4a567a
parent5f8415d6b87ecb4ebf1bbd02c538694ebb7fb57c (diff)
ovl: cleanup orphan index entries
index entry should live only as long as there are upper or lower hardlinks. Cleanup orphan index entries on mount and when dropping the last overlay inode nlink. When about to cleanup or link up to orphan index and the index inode nlink > 1, admit that something went wrong and adjust overlay nlink to index inode nlink - 1 to prevent it from dropping below zero. This could happen when adding lower hardlinks underneath a mounted overlay and then trying to unlink them. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/inode.c6
-rw-r--r--fs/overlayfs/namei.c5
-rw-r--r--fs/overlayfs/overlayfs.h3
-rw-r--r--fs/overlayfs/super.c2
-rw-r--r--fs/overlayfs/util.c66
5 files changed, 77 insertions, 5 deletions
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 196a4e5450c0..69f4fc26ee39 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -510,9 +510,9 @@ int ovl_set_nlink_lower(struct dentry *dentry)
510 return ovl_set_nlink_common(dentry, ovl_dentry_lower(dentry), "L%+i"); 510 return ovl_set_nlink_common(dentry, ovl_dentry_lower(dentry), "L%+i");
511} 511}
512 512
513static unsigned int ovl_get_nlink(struct dentry *lowerdentry, 513unsigned int ovl_get_nlink(struct dentry *lowerdentry,
514 struct dentry *upperdentry, 514 struct dentry *upperdentry,
515 unsigned int fallback) 515 unsigned int fallback)
516{ 516{
517 int nlink_diff; 517 int nlink_diff;
518 int nlink; 518 int nlink;
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 2d8b6292fe21..9bc0e580a5b3 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -425,6 +425,11 @@ int ovl_verify_index(struct dentry *index, struct path *lowerstack,
425 if (err) 425 if (err)
426 goto fail; 426 goto fail;
427 427
428 /* Check if index is orphan and don't warn before cleaning it */
429 if (d_inode(index)->i_nlink == 1 &&
430 ovl_get_nlink(index, origin.dentry, 0) == 0)
431 err = -ENOENT;
432
428 dput(origin.dentry); 433 dput(origin.dentry);
429out: 434out:
430 kfree(fh); 435 kfree(fh);
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index c1321ab38224..60d26605e039 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -263,6 +263,9 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
263/* inode.c */ 263/* inode.c */
264int ovl_set_nlink_upper(struct dentry *dentry); 264int ovl_set_nlink_upper(struct dentry *dentry);
265int ovl_set_nlink_lower(struct dentry *dentry); 265int ovl_set_nlink_lower(struct dentry *dentry);
266unsigned int ovl_get_nlink(struct dentry *lowerdentry,
267 struct dentry *upperdentry,
268 unsigned int fallback);
266int ovl_setattr(struct dentry *dentry, struct iattr *attr); 269int ovl_setattr(struct dentry *dentry, struct iattr *attr);
267int ovl_getattr(const struct path *path, struct kstat *stat, 270int ovl_getattr(const struct path *path, struct kstat *stat,
268 u32 request_mask, unsigned int flags); 271 u32 request_mask, unsigned int flags);
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index f29ee08cf99f..44dc2d6ffe0f 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1069,7 +1069,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
1069 if (err) 1069 if (err)
1070 pr_err("overlayfs: failed to verify index dir origin\n"); 1070 pr_err("overlayfs: failed to verify index dir origin\n");
1071 1071
1072 /* Cleanup bad/stale index entries */ 1072 /* Cleanup bad/stale/orphan index entries */
1073 if (!err) 1073 if (!err)
1074 err = ovl_indexdir_cleanup(ufs->indexdir, 1074 err = ovl_indexdir_cleanup(ufs->indexdir,
1075 ufs->upper_mnt, 1075 ufs->upper_mnt,
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 04d5018e728e..c492ba75c659 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -14,6 +14,8 @@
14#include <linux/xattr.h> 14#include <linux/xattr.h>
15#include <linux/exportfs.h> 15#include <linux/exportfs.h>
16#include <linux/uuid.h> 16#include <linux/uuid.h>
17#include <linux/namei.h>
18#include <linux/ratelimit.h>
17#include "overlayfs.h" 19#include "overlayfs.h"
18#include "ovl_entry.h" 20#include "ovl_entry.h"
19 21
@@ -411,6 +413,58 @@ void ovl_inuse_unlock(struct dentry *dentry)
411 } 413 }
412} 414}
413 415
416/* Called must hold OVL_I(inode)->oi_lock */
417static void ovl_cleanup_index(struct dentry *dentry)
418{
419 struct inode *dir = ovl_indexdir(dentry->d_sb)->d_inode;
420 struct dentry *lowerdentry = ovl_dentry_lower(dentry);
421 struct dentry *upperdentry = ovl_dentry_upper(dentry);
422 struct dentry *index = NULL;
423 struct inode *inode;
424 struct qstr name;
425 int err;
426
427 err = ovl_get_index_name(lowerdentry, &name);
428 if (err)
429 goto fail;
430
431 inode = d_inode(upperdentry);
432 if (inode->i_nlink != 1) {
433 pr_warn_ratelimited("overlayfs: cleanup linked index (%pd2, ino=%lu, nlink=%u)\n",
434 upperdentry, inode->i_ino, inode->i_nlink);
435 /*
436 * We either have a bug with persistent union nlink or a lower
437 * hardlink was added while overlay is mounted. Adding a lower
438 * hardlink and then unlinking all overlay hardlinks would drop
439 * overlay nlink to zero before all upper inodes are unlinked.
440 * As a safety measure, when that situation is detected, set
441 * the overlay nlink to the index inode nlink minus one for the
442 * index entry itself.
443 */
444 set_nlink(d_inode(dentry), inode->i_nlink - 1);
445 ovl_set_nlink_upper(dentry);
446 goto out;
447 }
448
449 inode_lock_nested(dir, I_MUTEX_PARENT);
450 /* TODO: whiteout instead of cleanup to block future open by handle */
451 index = lookup_one_len(name.name, ovl_indexdir(dentry->d_sb), name.len);
452 err = PTR_ERR(index);
453 if (!IS_ERR(index))
454 err = ovl_cleanup(dir, index);
455 inode_unlock(dir);
456 if (err)
457 goto fail;
458
459out:
460 dput(index);
461 return;
462
463fail:
464 pr_err("overlayfs: cleanup index of '%pd2' failed (%i)\n", dentry, err);
465 goto out;
466}
467
414/* 468/*
415 * Operations that change overlay inode and upper inode nlink need to be 469 * Operations that change overlay inode and upper inode nlink need to be
416 * synchronized with copy up for persistent nlink accounting. 470 * synchronized with copy up for persistent nlink accounting.
@@ -473,6 +527,16 @@ out:
473 527
474void ovl_nlink_end(struct dentry *dentry, bool locked) 528void ovl_nlink_end(struct dentry *dentry, bool locked)
475{ 529{
476 if (locked) 530 if (locked) {
531 if (ovl_test_flag(OVL_INDEX, d_inode(dentry)) &&
532 d_inode(dentry)->i_nlink == 0) {
533 const struct cred *old_cred;
534
535 old_cred = ovl_override_creds(dentry->d_sb);
536 ovl_cleanup_index(dentry);
537 revert_creds(old_cred);
538 }
539
477 mutex_unlock(&OVL_I(d_inode(dentry))->lock); 540 mutex_unlock(&OVL_I(d_inode(dentry))->lock);
541 }
478} 542}