nfsd4: clean up open owners on OPEN failure
authorJ. Bruce Fields <bfields@redhat.com>
Thu, 13 Oct 2011 19:12:59 +0000 (15:12 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Mon, 17 Oct 2011 21:33:57 +0000 (17:33 -0400)
If process_open1() creates a new open owner, but the open later fails,
the current code will leave the open owner around.  It won't be on the
close_lru list, and the client isn't expected to send a CLOSE, so it
will hang around as long as the client does.

Similarly, if process_open1() removes an existing open owner from the
close lru, anticipating that an open owner that previously had no
associated stateid's now will, but the open subsequently fails, then
we'll again be left with the same leak.

Fix both problems.

Reported-by: Bryan Schumaker <bjschuma@netapp.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/state.h
fs/nfsd/xdr4.h

index 5b192a2512b69e4056c9a5f4e97436b091cebad9..10b50d78bdc3b823e00df9022d9463d09f5cd4b3 100644 (file)
@@ -409,6 +409,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
         */
        status = nfsd4_process_open2(rqstp, &cstate->current_fh, open);
 out:
+       nfsd4_cleanup_open_state(open, status);
        if (open->op_openowner)
                cstate->replay_owner = &open->op_openowner->oo_owner;
        else
index 62aa91ae278b2a06e22a50cea7dc1dc7e08aa702..2c9a1a20e0145389bf4ca329fe3b402a3d0ff834 100644 (file)
@@ -2320,7 +2320,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
                return NULL;
        oo->oo_owner.so_is_open_owner = 1;
        oo->oo_owner.so_seqid = open->op_seqid;
-       oo->oo_flags = 0;
+       oo->oo_flags = NFS4_OO_NEW;
        oo->oo_time = 0;
        oo->oo_last_closed_stid = NULL;
        INIT_LIST_HEAD(&oo->oo_close_lru);
@@ -2526,7 +2526,6 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
                open->op_openowner = NULL;
                goto new_owner;
        }
-       list_del_init(&oo->oo_close_lru);
        return nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
 new_owner:
        oo = alloc_init_open_stateowner(strhashval, clp, open);
@@ -2946,6 +2945,23 @@ out:
        return status;
 }
 
+void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
+{
+       if (open->op_openowner) {
+               struct nfs4_openowner *oo = open->op_openowner;
+
+               if (!list_empty(&oo->oo_owner.so_stateids))
+                       list_del_init(&oo->oo_close_lru);
+               if (oo->oo_flags & NFS4_OO_NEW) {
+                       if (status) {
+                               release_openowner(oo);
+                               open->op_openowner = NULL;
+                       } else
+                               oo->oo_flags &= ~NFS4_OO_NEW;
+               }
+       }
+}
+
 __be32
 nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
            clientid_t *clid)
index 87eecfd9b9688a1ba1db83b85b26bc55593c5230..eab9dae23c068ca759853a1d996fbb4df0276418 100644 (file)
@@ -359,6 +359,7 @@ struct nfs4_openowner {
        time_t                  oo_time; /* time of placement on so_close_lru */
 #define NFS4_OO_CONFIRMED   1
 #define NFS4_OO_PURGE_CLOSE 2
+#define NFS4_OO_NEW         4
        unsigned char           oo_flags;
 };
 
index 4c8a7ec3f25d133c11cfc1a52360c330907592a0..32e6fd8d9768552e1d7e511540ebfe5b60465199 100644 (file)
@@ -554,6 +554,7 @@ extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *,
                struct nfsd4_open *open);
 extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp,
                struct svc_fh *current_fh, struct nfsd4_open *open);
+extern void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status);
 extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp,
                struct nfsd4_compound_state *, struct nfsd4_open_confirm *oc);
 extern __be32 nfsd4_close(struct svc_rqst *rqstp,