aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2011-10-13 15:12:59 -0400
committerJ. Bruce Fields <bfields@redhat.com>2011-10-17 17:33:57 -0400
commitd29b20cd589128a599e5045d4effc2d7dbc388f5 (patch)
tree48794b614b23f4159f2edeef484b1ff9c93ffbd7 /fs/nfsd
parentbcf130f9dfbaccf91376a44b18f51ed8007840d6 (diff)
nfsd4: clean up open owners on OPEN failure
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>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4proc.c1
-rw-r--r--fs/nfsd/nfs4state.c20
-rw-r--r--fs/nfsd/state.h1
-rw-r--r--fs/nfsd/xdr4.h1
4 files changed, 21 insertions, 2 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 5b192a2512b6..10b50d78bdc3 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -409,6 +409,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
409 */ 409 */
410 status = nfsd4_process_open2(rqstp, &cstate->current_fh, open); 410 status = nfsd4_process_open2(rqstp, &cstate->current_fh, open);
411out: 411out:
412 nfsd4_cleanup_open_state(open, status);
412 if (open->op_openowner) 413 if (open->op_openowner)
413 cstate->replay_owner = &open->op_openowner->oo_owner; 414 cstate->replay_owner = &open->op_openowner->oo_owner;
414 else 415 else
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 62aa91ae278b..2c9a1a20e014 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2320,7 +2320,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
2320 return NULL; 2320 return NULL;
2321 oo->oo_owner.so_is_open_owner = 1; 2321 oo->oo_owner.so_is_open_owner = 1;
2322 oo->oo_owner.so_seqid = open->op_seqid; 2322 oo->oo_owner.so_seqid = open->op_seqid;
2323 oo->oo_flags = 0; 2323 oo->oo_flags = NFS4_OO_NEW;
2324 oo->oo_time = 0; 2324 oo->oo_time = 0;
2325 oo->oo_last_closed_stid = NULL; 2325 oo->oo_last_closed_stid = NULL;
2326 INIT_LIST_HEAD(&oo->oo_close_lru); 2326 INIT_LIST_HEAD(&oo->oo_close_lru);
@@ -2526,7 +2526,6 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
2526 open->op_openowner = NULL; 2526 open->op_openowner = NULL;
2527 goto new_owner; 2527 goto new_owner;
2528 } 2528 }
2529 list_del_init(&oo->oo_close_lru);
2530 return nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 2529 return nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
2531new_owner: 2530new_owner:
2532 oo = alloc_init_open_stateowner(strhashval, clp, open); 2531 oo = alloc_init_open_stateowner(strhashval, clp, open);
@@ -2946,6 +2945,23 @@ out:
2946 return status; 2945 return status;
2947} 2946}
2948 2947
2948void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
2949{
2950 if (open->op_openowner) {
2951 struct nfs4_openowner *oo = open->op_openowner;
2952
2953 if (!list_empty(&oo->oo_owner.so_stateids))
2954 list_del_init(&oo->oo_close_lru);
2955 if (oo->oo_flags & NFS4_OO_NEW) {
2956 if (status) {
2957 release_openowner(oo);
2958 open->op_openowner = NULL;
2959 } else
2960 oo->oo_flags &= ~NFS4_OO_NEW;
2961 }
2962 }
2963}
2964
2949__be32 2965__be32
2950nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 2966nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2951 clientid_t *clid) 2967 clientid_t *clid)
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 87eecfd9b968..eab9dae23c06 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -359,6 +359,7 @@ struct nfs4_openowner {
359 time_t oo_time; /* time of placement on so_close_lru */ 359 time_t oo_time; /* time of placement on so_close_lru */
360#define NFS4_OO_CONFIRMED 1 360#define NFS4_OO_CONFIRMED 1
361#define NFS4_OO_PURGE_CLOSE 2 361#define NFS4_OO_PURGE_CLOSE 2
362#define NFS4_OO_NEW 4
362 unsigned char oo_flags; 363 unsigned char oo_flags;
363}; 364};
364 365
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 4c8a7ec3f25d..32e6fd8d9768 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -554,6 +554,7 @@ extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *,
554 struct nfsd4_open *open); 554 struct nfsd4_open *open);
555extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp, 555extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp,
556 struct svc_fh *current_fh, struct nfsd4_open *open); 556 struct svc_fh *current_fh, struct nfsd4_open *open);
557extern void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status);
557extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp, 558extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp,
558 struct nfsd4_compound_state *, struct nfsd4_open_confirm *oc); 559 struct nfsd4_compound_state *, struct nfsd4_open_confirm *oc);
559extern __be32 nfsd4_close(struct svc_rqst *rqstp, 560extern __be32 nfsd4_close(struct svc_rqst *rqstp,