diff options
| author | Benny Halevy <bhalevy@panasas.com> | 2010-05-11 17:13:04 -0400 |
|---|---|---|
| committer | J. Bruce Fields <bfields@citi.umich.edu> | 2010-05-11 21:02:02 -0400 |
| commit | 36acb66bda512dd8159c3e1b40358c5219524868 (patch) | |
| tree | f65fddbb0ad59a93f762010c85b7b533ede4dff8 | |
| parent | 328efbab0f8ae1617448917906a12e5f568553b6 (diff) | |
nfsd4: extend the client_lock to cover cl_lru
To be used later on to hold a reference count on the client while in use by a
nfsv4.1 compound.
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
| -rw-r--r-- | fs/nfsd/nfs4state.c | 41 |
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 */ |
| 254 | static DEFINE_SPINLOCK(client_lock); | 254 | static 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 */ | ||
| 631 | static inline void | 632 | static inline void |
| 632 | renew_client(struct nfs4_client *clp) | 633 | renew_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 | ||
| 645 | static inline void | ||
| 646 | renew_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 */ |
| 645 | static int | 654 | static int |
| 646 | STALE_CLIENTID(clientid_t *clid) | 655 | STALE_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 | ||
| 855 | static void | 863 | static void |
| @@ -1447,15 +1455,12 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
| 1447 | 1455 | ||
| 1448 | out: | 1456 | out: |
| 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); |
