summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2018-01-11 15:33:51 +0200
committerMiklos Szeredi <mszeredi@redhat.com>2018-01-24 11:25:56 +0100
commit24f0b17203691d22815e842051a014e3bde7c227 (patch)
treeb4a2a55684b6413ee380c1ac645831d2e3185ce3
parente7dd0e71348c1e3bc4b9d767c1ffbcbdee46a726 (diff)
downloadlinux-24f0b17203691d22815e842051a014e3bde7c227.tar.gz
linux-24f0b17203691d22815e842051a014e3bde7c227.tar.bz2
linux-24f0b17203691d22815e842051a014e3bde7c227.zip
ovl: whiteout orphan index entries on mount
Orphan index entries are non-dir index entries whose union nlink count dropped to zero. With index=on, orphan index entries are removed on mount. With NFS export feature enabled, orphan index entries are replaced with white out index entries to block future open by handle from opening the lower file. When dir index has a stale 'upper' xattr, we assume that the upper dir was removed and we treat the dir index as orphan entry that needs to be whited out or removed. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/namei.c19
-rw-r--r--fs/overlayfs/readdir.c25
2 files changed, 40 insertions, 4 deletions
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 7f27ec5999ea..111a64f904c2 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -539,7 +539,15 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index)
upper = ovl_index_upper(ofs, index);
if (IS_ERR_OR_NULL(upper)) {
err = PTR_ERR(upper);
- if (!err)
+ /*
+ * Directory index entries with no 'upper' xattr need to be
+ * removed. When dir index entry has a stale 'upper' xattr,
+ * we assume that upper dir was removed and we treat the dir
+ * index as orphan entry that needs to be whited out.
+ */
+ if (err == -ESTALE)
+ goto orphan;
+ else if (!err)
err = -ESTALE;
goto fail;
}
@@ -556,7 +564,7 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index)
goto fail;
if (ovl_get_nlink(origin.dentry, index, 0) == 0)
- err = -ENOENT;
+ goto orphan;
}
out:
@@ -568,6 +576,13 @@ fail:
pr_warn_ratelimited("overlayfs: failed to verify index (%pd2, ftype=%x, err=%i)\n",
index, d_inode(index)->i_mode & S_IFMT, err);
goto out;
+
+orphan:
+ pr_warn_ratelimited("overlayfs: orphan index entry (%pd2, ftype=%x, nlink=%u)\n",
+ index, d_inode(index)->i_mode & S_IFMT,
+ d_inode(index)->i_nlink);
+ err = -ENOENT;
+ goto out;
}
/*
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 4c660c7085b7..c11f5c0906c3 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -1067,12 +1067,33 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
break;
}
err = ovl_verify_index(ofs, index);
- /* Cleanup stale and orphan index entries */
- if (err && (err == -ESTALE || err == -ENOENT))
+ if (!err) {
+ goto next;
+ } else if (err == -ESTALE) {
+ /* Cleanup stale index entries */
err = ovl_cleanup(dir, index);
+ } else if (err != -ENOENT) {
+ /*
+ * Abort mount to avoid corrupting the index if
+ * an incompatible index entry was found or on out
+ * of memory.
+ */
+ break;
+ } else if (ofs->config.nfs_export) {
+ /*
+ * Whiteout orphan index to block future open by
+ * handle after overlay nlink dropped to zero.
+ */
+ err = ovl_cleanup_and_whiteout(indexdir, dir, index);
+ } else {
+ /* Cleanup orphan index entries */
+ err = ovl_cleanup(dir, index);
+ }
+
if (err)
break;
+next:
dput(index);
index = NULL;
}