summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--fs/9p/fid.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 73ca55042cb0..616abaf1c6cd 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -41,10 +41,15 @@
  *
  */
 
+static inline void __add_fid(struct dentry *dentry, struct p9_fid *fid)
+{
+	hlist_add_head(&fid->dlist, (struct hlist_head *)&dentry->d_fsdata);
+}
+
 void v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
 {
 	spin_lock(&dentry->d_lock);
-	hlist_add_head(&fid->dlist, (struct hlist_head *)&dentry->d_fsdata);
+	__add_fid(dentry, fid);
 	spin_unlock(&dentry->d_lock);
 }
 
@@ -198,8 +203,17 @@ static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry,
 	}
 	kfree(wnames);
 fid_out:
-	if (!IS_ERR(fid))
-		v9fs_fid_add(dentry, fid);
+	if (!IS_ERR(fid)) {
+		spin_lock(&dentry->d_lock);
+		if (d_unhashed(dentry)) {
+			spin_unlock(&dentry->d_lock);
+			p9_client_clunk(fid);
+			fid = ERR_PTR(-ENOENT);
+		} else {
+			__add_fid(dentry, fid);
+			spin_unlock(&dentry->d_lock);
+		}
+	}
 err_out:
 	up_read(&v9ses->rename_sem);
 	return fid;