Commit d76829889ac4250a18cfcc1a606bb256bb9c570c
Committed by
J. Bruce Fields
1 parent
07cd4909a6
Exists in
master
and in
39 other branches
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>
Showing 3 changed files with 27 additions and 4 deletions Side-by-side Diff
fs/nfsd/nfs4state.c
... | ... | @@ -701,6 +701,22 @@ |
701 | 701 | kfree(clp); |
702 | 702 | } |
703 | 703 | |
704 | +void | |
705 | +release_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 | 720 | /* must be called under the client_lock */ |
705 | 721 | static inline void |
706 | 722 | unhash_client_locked(struct nfs4_client *clp) |
... | ... | @@ -1476,8 +1492,7 @@ |
1476 | 1492 | /* Hold a session reference until done processing the compound. */ |
1477 | 1493 | if (cstate->session) { |
1478 | 1494 | nfsd4_get_session(cstate->session); |
1479 | - /* Renew the clientid on success and on replay */ | |
1480 | - renew_client_locked(session->se_client); | |
1495 | + atomic_inc(&session->se_client->cl_refcount); | |
1481 | 1496 | } |
1482 | 1497 | spin_unlock(&client_lock); |
1483 | 1498 | dprintk("%s: return %d\n", __func__, ntohl(status)); |
... | ... | @@ -2598,7 +2613,13 @@ |
2598 | 2613 | clientid_val = t; |
2599 | 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 | 2624 | spin_unlock(&client_lock); |
2604 | 2625 | list_for_each_safe(pos, next, &reaplist) { |
fs/nfsd/nfs4xdr.c
... | ... | @@ -3313,7 +3313,8 @@ |
3313 | 3313 | dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__); |
3314 | 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 | 3319 | return 1; |
3319 | 3320 | } |
fs/nfsd/state.h
... | ... | @@ -420,6 +420,7 @@ |
420 | 420 | extern void nfsd4_recdir_purge_old(void); |
421 | 421 | extern int nfsd4_create_clid_dir(struct nfs4_client *clp); |
422 | 422 | extern void nfsd4_remove_clid_dir(struct nfs4_client *clp); |
423 | +extern void release_session_client(struct nfsd4_session *); | |
423 | 424 | |
424 | 425 | static inline void |
425 | 426 | nfs4_put_stateowner(struct nfs4_stateowner *so) |