aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorBenny Halevy <bhalevy@panasas.com>2010-05-11 17:13:54 -0400
committerJ. Bruce Fields <bfields@citi.umich.edu>2010-05-13 11:58:54 -0400
commitd76829889ac4250a18cfcc1a606bb256bb9c570c (patch)
tree27a675ed794809b4aa2430aa3a03e4ffb0f11816 /fs/nfsd
parent07cd4909a6c0c275ef42fd27748226975919e336 (diff)
nfsd4: keep a reference count on client while in use
Get a refcount on the client on SEQUENCE, Release the refcount and renew the client when all respective compounds completed. Do not expire the client by the laundromat while in use. If the client was expired via another path, free it when the compounds complete and the refcount reaches 0. Note that unhash_client_locked must call list_del_init on cl_lru as it may be called twice for the same client (once from nfs4_laundromat and then from expire_client) Signed-off-by: Benny Halevy <bhalevy@panasas.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4state.c27
-rw-r--r--fs/nfsd/nfs4xdr.c3
-rw-r--r--fs/nfsd/state.h1
3 files changed, 27 insertions, 4 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 98aa7e8827b9..cc0e9117dd16 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -701,6 +701,22 @@ free_client(struct nfs4_client *clp)
701 kfree(clp); 701 kfree(clp);
702} 702}
703 703
704void
705release_session_client(struct nfsd4_session *session)
706{
707 struct nfs4_client *clp = session->se_client;
708
709 if (!atomic_dec_and_lock(&clp->cl_refcount, &client_lock))
710 return;
711 if (is_client_expired(clp)) {
712 free_client(clp);
713 session->se_client = NULL;
714 } else
715 renew_client_locked(clp);
716 spin_unlock(&client_lock);
717 nfsd4_put_session(session);
718}
719
704/* must be called under the client_lock */ 720/* must be called under the client_lock */
705static inline void 721static inline void
706unhash_client_locked(struct nfs4_client *clp) 722unhash_client_locked(struct nfs4_client *clp)
@@ -1476,8 +1492,7 @@ out:
1476 /* Hold a session reference until done processing the compound. */ 1492 /* Hold a session reference until done processing the compound. */
1477 if (cstate->session) { 1493 if (cstate->session) {
1478 nfsd4_get_session(cstate->session); 1494 nfsd4_get_session(cstate->session);
1479 /* Renew the clientid on success and on replay */ 1495 atomic_inc(&session->se_client->cl_refcount);
1480 renew_client_locked(session->se_client);
1481 } 1496 }
1482 spin_unlock(&client_lock); 1497 spin_unlock(&client_lock);
1483 dprintk("%s: return %d\n", __func__, ntohl(status)); 1498 dprintk("%s: return %d\n", __func__, ntohl(status));
@@ -2598,7 +2613,13 @@ nfs4_laundromat(void)
2598 clientid_val = t; 2613 clientid_val = t;
2599 break; 2614 break;
2600 } 2615 }
2601 list_move(&clp->cl_lru, &reaplist); 2616 if (atomic_read(&clp->cl_refcount)) {
2617 dprintk("NFSD: client in use (clientid %08x)\n",
2618 clp->cl_clientid.cl_id);
2619 continue;
2620 }
2621 unhash_client_locked(clp);
2622 list_add(&clp->cl_lru, &reaplist);
2602 } 2623 }
2603 spin_unlock(&client_lock); 2624 spin_unlock(&client_lock);
2604 list_for_each_safe(pos, next, &reaplist) { 2625 list_for_each_safe(pos, next, &reaplist) {
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 5c2de471329a..126d0caabb3c 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3313,7 +3313,8 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
3313 dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__); 3313 dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__);
3314 cs->slot->sl_inuse = false; 3314 cs->slot->sl_inuse = false;
3315 } 3315 }
3316 nfsd4_put_session(cs->session); 3316 /* Renew the clientid on success and on replay */
3317 release_session_client(cs->session);
3317 } 3318 }
3318 return 1; 3319 return 1;
3319} 3320}
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index cfd743ea4b79..006c84230c7c 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -420,6 +420,7 @@ extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
420extern void nfsd4_recdir_purge_old(void); 420extern void nfsd4_recdir_purge_old(void);
421extern int nfsd4_create_clid_dir(struct nfs4_client *clp); 421extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
422extern void nfsd4_remove_clid_dir(struct nfs4_client *clp); 422extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
423extern void release_session_client(struct nfsd4_session *);
423 424
424static inline void 425static inline void
425nfs4_put_stateowner(struct nfs4_stateowner *so) 426nfs4_put_stateowner(struct nfs4_stateowner *so)