From 5142d04ad6dd0c3b2a2a93571b7e2d4d4d647372 Mon Sep 17 00:00:00 2001
From: bobijam <bobijam>
Date: Wed, 19 Nov 2008 01:39:07 +0000
Subject: [PATCH] Branch b1_6 b=16992 o=johann i=oleg.drokin (green)
 i=zhenyu.xu (bobijam)

During ll_intent_lock(), server looks up parent and child, lock them, between these events parent could be deleted, then vfs_create may_access() fails with -ENOENT.

Then client intent disposition got DISP_OPEN_CREATE | DISP_LOOKUP_NEG | DISP_LOOKUP_EXECD | DISP_IT_EXECD, and the request got double free.

Solution: Clear DISP_ENQ_COMPLETE when we are going to release the intent (request cannot be reused anyway)
---
 lustre/llite/dcache.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/lustre/llite/dcache.c b/lustre/llite/dcache.c
index e1b9445f46..82146baf0e 100644
--- a/lustre/llite/dcache.c
+++ b/lustre/llite/dcache.c
@@ -213,7 +213,7 @@ int ll_drop_dentry(struct dentry *dentry)
                 spin_lock(&dcache_lock);
                 return 1;
         }
-	/* disconected dentry can not be find without lookup, because we 
+	/* disconected dentry can not be find without lookup, because we
 	 * not need his to unhash or mark invalid. */
 	if (dentry->d_flags & DCACHE_DISCONNECTED) {
 		unlock_dentry(dentry);
@@ -239,7 +239,7 @@ int ll_drop_dentry(struct dentry *dentry)
                 if (dentry->d_inode) {
                         /* Put positive dentries to orphan list */
                         list_add(&dentry->d_hash,
-                                 &ll_i2sbi(dentry->d_inode)->ll_orphan_dentry_list);
+                             &ll_i2sbi(dentry->d_inode)->ll_orphan_dentry_list);
                 }
 #endif
 #else
@@ -488,11 +488,14 @@ do_lock:
 revalidate_finish:
         rc = revalidate_it_finish(req, DLM_REPLY_REC_OFF, it, de);
         if (rc != 0) {
+                /* we are going release the intent, so clear DISP_ENQ_COMPLETE
+                 * to prevent a double free of the request */
+                it_clear_disposition(it, DISP_ENQ_COMPLETE);
                 ll_intent_release(it);
                 GOTO(out, rc = 0);
         }
-        if ((it->it_op & IT_OPEN) && de->d_inode && 
-            !S_ISREG(de->d_inode->i_mode) && 
+        if ((it->it_op & IT_OPEN) && de->d_inode &&
+            !S_ISREG(de->d_inode->i_mode) &&
             !S_ISDIR(de->d_inode->i_mode)) {
                 ll_release_openhandle(de, it);
         }
@@ -572,6 +575,9 @@ do_lookup:
                 /* see if we got same inode, if not - return error */
                 if(!memcmp(&fid, &mds_body->fid1, sizeof(struct ll_fid)))
                         goto revalidate_finish;
+                /* we are going release the intent, so clear DISP_ENQ_COMPLETE
+                 * to prevent a double free of the request */
+                it_clear_disposition(it, DISP_ENQ_COMPLETE);
                 ll_intent_release(it);
         }
         GOTO(out, rc = 0);
@@ -703,7 +709,8 @@ int ll_revalidate_nd(struct dentry *dentry, struct nameidata *nd)
                         RETURN(0);
                 if (it->it_op == (IT_OPEN|IT_CREAT))
                         if (nd->intent.open.flags & O_EXCL) {
-                                CDEBUG(D_VFSTRACE, "create O_EXCL, returning 0\n");
+                                CDEBUG(D_VFSTRACE,
+                                       "create O_EXCL, returning 0\n");
                                 rc = 0;
                                 goto out_it;
                         }
@@ -747,7 +754,7 @@ int ll_revalidate_nd(struct dentry *dentry, struct nameidata *nd)
                         ll_d2d(dentry)->lld_it = it;
                         it = NULL; /* avoid freeing */
                 }
-                        
+
 out_it:
                 if (it) {
                         ll_intent_release(it);
-- 
GitLab