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 @@ int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index) 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; }