aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/nfs4state.c41
1 files changed, 26 insertions, 15 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index aecafb2e4056..3f572cb3f896 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -250,7 +250,7 @@ unhash_delegation(struct nfs4_delegation *dp)
250 * SETCLIENTID state 250 * SETCLIENTID state
251 */ 251 */
252 252
253/* client_lock protects the session hash table */ 253/* client_lock protects the client lru list and session hash table */
254static DEFINE_SPINLOCK(client_lock); 254static DEFINE_SPINLOCK(client_lock);
255 255
256/* Hash tables for nfs4_clientid state */ 256/* Hash tables for nfs4_clientid state */
@@ -628,8 +628,9 @@ free_session(struct kref *kref)
628 kfree(ses); 628 kfree(ses);
629} 629}
630 630
631/* must be called under the client_lock */
631static inline void 632static inline void
632renew_client(struct nfs4_client *clp) 633renew_client_locked(struct nfs4_client *clp)
633{ 634{
634 /* 635 /*
635 * Move client to the end to the LRU list. 636 * Move client to the end to the LRU list.
@@ -641,6 +642,14 @@ renew_client(struct nfs4_client *clp)
641 clp->cl_time = get_seconds(); 642 clp->cl_time = get_seconds();
642} 643}
643 644
645static inline void
646renew_client(struct nfs4_client *clp)
647{
648 spin_lock(&client_lock);
649 renew_client_locked(clp);
650 spin_unlock(&client_lock);
651}
652
644/* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 653/* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
645static int 654static int
646STALE_CLIENTID(clientid_t *clid) 655STALE_CLIENTID(clientid_t *clid)
@@ -706,14 +715,14 @@ expire_client(struct nfs4_client *clp)
706 list_del_init(&dp->dl_recall_lru); 715 list_del_init(&dp->dl_recall_lru);
707 unhash_delegation(dp); 716 unhash_delegation(dp);
708 } 717 }
709 list_del(&clp->cl_idhash);
710 list_del(&clp->cl_strhash);
711 list_del(&clp->cl_lru);
712 while (!list_empty(&clp->cl_openowners)) { 718 while (!list_empty(&clp->cl_openowners)) {
713 sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); 719 sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient);
714 release_openowner(sop); 720 release_openowner(sop);
715 } 721 }
722 list_del(&clp->cl_idhash);
723 list_del(&clp->cl_strhash);
716 spin_lock(&client_lock); 724 spin_lock(&client_lock);
725 list_del(&clp->cl_lru);
717 while (!list_empty(&clp->cl_sessions)) { 726 while (!list_empty(&clp->cl_sessions)) {
718 struct nfsd4_session *ses; 727 struct nfsd4_session *ses;
719 ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 728 ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
@@ -848,8 +857,7 @@ add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval)
848 list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); 857 list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]);
849 idhashval = clientid_hashval(clp->cl_clientid.cl_id); 858 idhashval = clientid_hashval(clp->cl_clientid.cl_id);
850 list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); 859 list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]);
851 list_add_tail(&clp->cl_lru, &client_lru); 860 renew_client(clp);
852 clp->cl_time = get_seconds();
853} 861}
854 862
855static void 863static void
@@ -1447,15 +1455,12 @@ nfsd4_sequence(struct svc_rqst *rqstp,
1447 1455
1448out: 1456out:
1449 /* Hold a session reference until done processing the compound. */ 1457 /* Hold a session reference until done processing the compound. */
1450 if (cstate->session)
1451 nfsd4_get_session(cstate->session);
1452 spin_unlock(&client_lock);
1453 /* Renew the clientid on success and on replay */
1454 if (cstate->session) { 1458 if (cstate->session) {
1455 nfs4_lock_state(); 1459 nfsd4_get_session(cstate->session);
1456 renew_client(session->se_client); 1460 /* Renew the clientid on success and on replay */
1457 nfs4_unlock_state(); 1461 renew_client_locked(session->se_client);
1458 } 1462 }
1463 spin_unlock(&client_lock);
1459 dprintk("%s: return %d\n", __func__, ntohl(status)); 1464 dprintk("%s: return %d\n", __func__, ntohl(status));
1460 return status; 1465 return status;
1461} 1466}
@@ -2564,6 +2569,8 @@ nfs4_laundromat(void)
2564 dprintk("NFSD: laundromat service - starting\n"); 2569 dprintk("NFSD: laundromat service - starting\n");
2565 if (locks_in_grace()) 2570 if (locks_in_grace())
2566 nfsd4_end_grace(); 2571 nfsd4_end_grace();
2572 INIT_LIST_HEAD(&reaplist);
2573 spin_lock(&client_lock);
2567 list_for_each_safe(pos, next, &client_lru) { 2574 list_for_each_safe(pos, next, &client_lru) {
2568 clp = list_entry(pos, struct nfs4_client, cl_lru); 2575 clp = list_entry(pos, struct nfs4_client, cl_lru);
2569 if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { 2576 if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
@@ -2572,12 +2579,16 @@ nfs4_laundromat(void)
2572 clientid_val = t; 2579 clientid_val = t;
2573 break; 2580 break;
2574 } 2581 }
2582 list_move(&clp->cl_lru, &reaplist);
2583 }
2584 spin_unlock(&client_lock);
2585 list_for_each_safe(pos, next, &reaplist) {
2586 clp = list_entry(pos, struct nfs4_client, cl_lru);
2575 dprintk("NFSD: purging unused client (clientid %08x)\n", 2587 dprintk("NFSD: purging unused client (clientid %08x)\n",
2576 clp->cl_clientid.cl_id); 2588 clp->cl_clientid.cl_id);
2577 nfsd4_remove_clid_dir(clp); 2589 nfsd4_remove_clid_dir(clp);
2578 expire_client(clp); 2590 expire_client(clp);
2579 } 2591 }
2580 INIT_LIST_HEAD(&reaplist);
2581 spin_lock(&recall_lock); 2592 spin_lock(&recall_lock);
2582 list_for_each_safe(pos, next, &del_recall_lru) { 2593 list_for_each_safe(pos, next, &del_recall_lru) {
2583 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 2594 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);