summaryrefslogtreecommitdiffstats
path: root/kernel/fs/overlayfs/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/fs/overlayfs/dir.c')
-rw-r--r--kernel/fs/overlayfs/dir.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/kernel/fs/overlayfs/dir.c b/kernel/fs/overlayfs/dir.c
index 692ceda3b..a2b1d7ce3 100644
--- a/kernel/fs/overlayfs/dir.c
+++ b/kernel/fs/overlayfs/dir.c
@@ -618,7 +618,8 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
* sole user of this dentry. Too tricky... Just unhash for
* now.
*/
- d_drop(dentry);
+ if (!err)
+ d_drop(dentry);
mutex_unlock(&dir->i_mutex);
return err;
@@ -903,6 +904,13 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
if (!overwrite && new_is_dir && !old_opaque && new_opaque)
ovl_remove_opaque(newdentry);
+ /*
+ * Old dentry now lives in different location. Dentries in
+ * lowerstack are stale. We cannot drop them here because
+ * access to them is lockless. This could be only pure upper
+ * or opaque directory - numlower is zero. Or upper non-dir
+ * entry - its pureness is tracked by flag opaque.
+ */
if (old_opaque != new_opaque) {
ovl_dentry_set_opaque(old, new_opaque);
if (!overwrite)