summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
}