diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-11-04 23:12:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-11-04 23:12:10 -0400 |
commit | fb415f222c26d0d1fa19615af1d102bf5f5b3ca2 (patch) | |
tree | c2cc2ca5e597b6da803d63252fefbc2be6aba65a /fs | |
parent | 46d7cbb2c49ac93246aad9ac76b39ef2ac7bc41b (diff) | |
parent | f46c445b79906a9da55c13e0a6f6b6a006b892fe (diff) |
Merge tag 'nfsd-4.9-1' of git://linux-nfs.org/~bfields/linux
Pull nfsd bugfixes from Bruce Fields:
"Fixes for some recent regressions including fallout from the vmalloc'd
stack change (after which we can no longer encrypt stuff on the
stack)"
* tag 'nfsd-4.9-1' of git://linux-nfs.org/~bfields/linux:
nfsd: Fix general protection fault in release_lock_stateid()
svcrdma: backchannel cannot share a page for send and rcv buffers
sunrpc: fix some missing rq_rbuffer assignments
sunrpc: don't pass on-stack memory to sg_set_buf
nfsd: move blocked lock handling under a dedicated spinlock
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/netns.h | 5 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 38 |
2 files changed, 24 insertions, 19 deletions
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index b10d557f9c9e..ee36efd5aece 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h | |||
@@ -84,6 +84,8 @@ struct nfsd_net { | |||
84 | struct list_head client_lru; | 84 | struct list_head client_lru; |
85 | struct list_head close_lru; | 85 | struct list_head close_lru; |
86 | struct list_head del_recall_lru; | 86 | struct list_head del_recall_lru; |
87 | |||
88 | /* protected by blocked_locks_lock */ | ||
87 | struct list_head blocked_locks_lru; | 89 | struct list_head blocked_locks_lru; |
88 | 90 | ||
89 | struct delayed_work laundromat_work; | 91 | struct delayed_work laundromat_work; |
@@ -91,6 +93,9 @@ struct nfsd_net { | |||
91 | /* client_lock protects the client lru list and session hash table */ | 93 | /* client_lock protects the client lru list and session hash table */ |
92 | spinlock_t client_lock; | 94 | spinlock_t client_lock; |
93 | 95 | ||
96 | /* protects blocked_locks_lru */ | ||
97 | spinlock_t blocked_locks_lock; | ||
98 | |||
94 | struct file *rec_file; | 99 | struct file *rec_file; |
95 | bool in_grace; | 100 | bool in_grace; |
96 | const struct nfsd4_client_tracking_ops *client_tracking_ops; | 101 | const struct nfsd4_client_tracking_ops *client_tracking_ops; |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 9752beb78659..4b4beaaa4eaa 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -217,7 +217,7 @@ find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh, | |||
217 | { | 217 | { |
218 | struct nfsd4_blocked_lock *cur, *found = NULL; | 218 | struct nfsd4_blocked_lock *cur, *found = NULL; |
219 | 219 | ||
220 | spin_lock(&nn->client_lock); | 220 | spin_lock(&nn->blocked_locks_lock); |
221 | list_for_each_entry(cur, &lo->lo_blocked, nbl_list) { | 221 | list_for_each_entry(cur, &lo->lo_blocked, nbl_list) { |
222 | if (fh_match(fh, &cur->nbl_fh)) { | 222 | if (fh_match(fh, &cur->nbl_fh)) { |
223 | list_del_init(&cur->nbl_list); | 223 | list_del_init(&cur->nbl_list); |
@@ -226,7 +226,7 @@ find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh, | |||
226 | break; | 226 | break; |
227 | } | 227 | } |
228 | } | 228 | } |
229 | spin_unlock(&nn->client_lock); | 229 | spin_unlock(&nn->blocked_locks_lock); |
230 | if (found) | 230 | if (found) |
231 | posix_unblock_lock(&found->nbl_lock); | 231 | posix_unblock_lock(&found->nbl_lock); |
232 | return found; | 232 | return found; |
@@ -1227,9 +1227,7 @@ static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, | |||
1227 | 1227 | ||
1228 | static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) | 1228 | static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) |
1229 | { | 1229 | { |
1230 | struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner); | 1230 | lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); |
1231 | |||
1232 | lockdep_assert_held(&oo->oo_owner.so_client->cl_lock); | ||
1233 | 1231 | ||
1234 | list_del_init(&stp->st_locks); | 1232 | list_del_init(&stp->st_locks); |
1235 | nfs4_unhash_stid(&stp->st_stid); | 1233 | nfs4_unhash_stid(&stp->st_stid); |
@@ -1238,12 +1236,12 @@ static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) | |||
1238 | 1236 | ||
1239 | static void release_lock_stateid(struct nfs4_ol_stateid *stp) | 1237 | static void release_lock_stateid(struct nfs4_ol_stateid *stp) |
1240 | { | 1238 | { |
1241 | struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner); | 1239 | struct nfs4_client *clp = stp->st_stid.sc_client; |
1242 | bool unhashed; | 1240 | bool unhashed; |
1243 | 1241 | ||
1244 | spin_lock(&oo->oo_owner.so_client->cl_lock); | 1242 | spin_lock(&clp->cl_lock); |
1245 | unhashed = unhash_lock_stateid(stp); | 1243 | unhashed = unhash_lock_stateid(stp); |
1246 | spin_unlock(&oo->oo_owner.so_client->cl_lock); | 1244 | spin_unlock(&clp->cl_lock); |
1247 | if (unhashed) | 1245 | if (unhashed) |
1248 | nfs4_put_stid(&stp->st_stid); | 1246 | nfs4_put_stid(&stp->st_stid); |
1249 | } | 1247 | } |
@@ -4665,7 +4663,7 @@ nfs4_laundromat(struct nfsd_net *nn) | |||
4665 | * indefinitely once the lock does become free. | 4663 | * indefinitely once the lock does become free. |
4666 | */ | 4664 | */ |
4667 | BUG_ON(!list_empty(&reaplist)); | 4665 | BUG_ON(!list_empty(&reaplist)); |
4668 | spin_lock(&nn->client_lock); | 4666 | spin_lock(&nn->blocked_locks_lock); |
4669 | while (!list_empty(&nn->blocked_locks_lru)) { | 4667 | while (!list_empty(&nn->blocked_locks_lru)) { |
4670 | nbl = list_first_entry(&nn->blocked_locks_lru, | 4668 | nbl = list_first_entry(&nn->blocked_locks_lru, |
4671 | struct nfsd4_blocked_lock, nbl_lru); | 4669 | struct nfsd4_blocked_lock, nbl_lru); |
@@ -4678,7 +4676,7 @@ nfs4_laundromat(struct nfsd_net *nn) | |||
4678 | list_move(&nbl->nbl_lru, &reaplist); | 4676 | list_move(&nbl->nbl_lru, &reaplist); |
4679 | list_del_init(&nbl->nbl_list); | 4677 | list_del_init(&nbl->nbl_list); |
4680 | } | 4678 | } |
4681 | spin_unlock(&nn->client_lock); | 4679 | spin_unlock(&nn->blocked_locks_lock); |
4682 | 4680 | ||
4683 | while (!list_empty(&reaplist)) { | 4681 | while (!list_empty(&reaplist)) { |
4684 | nbl = list_first_entry(&nn->blocked_locks_lru, | 4682 | nbl = list_first_entry(&nn->blocked_locks_lru, |
@@ -5439,13 +5437,13 @@ nfsd4_lm_notify(struct file_lock *fl) | |||
5439 | bool queue = false; | 5437 | bool queue = false; |
5440 | 5438 | ||
5441 | /* An empty list means that something else is going to be using it */ | 5439 | /* An empty list means that something else is going to be using it */ |
5442 | spin_lock(&nn->client_lock); | 5440 | spin_lock(&nn->blocked_locks_lock); |
5443 | if (!list_empty(&nbl->nbl_list)) { | 5441 | if (!list_empty(&nbl->nbl_list)) { |
5444 | list_del_init(&nbl->nbl_list); | 5442 | list_del_init(&nbl->nbl_list); |
5445 | list_del_init(&nbl->nbl_lru); | 5443 | list_del_init(&nbl->nbl_lru); |
5446 | queue = true; | 5444 | queue = true; |
5447 | } | 5445 | } |
5448 | spin_unlock(&nn->client_lock); | 5446 | spin_unlock(&nn->blocked_locks_lock); |
5449 | 5447 | ||
5450 | if (queue) | 5448 | if (queue) |
5451 | nfsd4_run_cb(&nbl->nbl_cb); | 5449 | nfsd4_run_cb(&nbl->nbl_cb); |
@@ -5868,10 +5866,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5868 | 5866 | ||
5869 | if (fl_flags & FL_SLEEP) { | 5867 | if (fl_flags & FL_SLEEP) { |
5870 | nbl->nbl_time = jiffies; | 5868 | nbl->nbl_time = jiffies; |
5871 | spin_lock(&nn->client_lock); | 5869 | spin_lock(&nn->blocked_locks_lock); |
5872 | list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked); | 5870 | list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked); |
5873 | list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru); | 5871 | list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru); |
5874 | spin_unlock(&nn->client_lock); | 5872 | spin_unlock(&nn->blocked_locks_lock); |
5875 | } | 5873 | } |
5876 | 5874 | ||
5877 | err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); | 5875 | err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); |
@@ -5900,10 +5898,10 @@ out: | |||
5900 | if (nbl) { | 5898 | if (nbl) { |
5901 | /* dequeue it if we queued it before */ | 5899 | /* dequeue it if we queued it before */ |
5902 | if (fl_flags & FL_SLEEP) { | 5900 | if (fl_flags & FL_SLEEP) { |
5903 | spin_lock(&nn->client_lock); | 5901 | spin_lock(&nn->blocked_locks_lock); |
5904 | list_del_init(&nbl->nbl_list); | 5902 | list_del_init(&nbl->nbl_list); |
5905 | list_del_init(&nbl->nbl_lru); | 5903 | list_del_init(&nbl->nbl_lru); |
5906 | spin_unlock(&nn->client_lock); | 5904 | spin_unlock(&nn->blocked_locks_lock); |
5907 | } | 5905 | } |
5908 | free_blocked_lock(nbl); | 5906 | free_blocked_lock(nbl); |
5909 | } | 5907 | } |
@@ -6943,9 +6941,11 @@ static int nfs4_state_create_net(struct net *net) | |||
6943 | INIT_LIST_HEAD(&nn->client_lru); | 6941 | INIT_LIST_HEAD(&nn->client_lru); |
6944 | INIT_LIST_HEAD(&nn->close_lru); | 6942 | INIT_LIST_HEAD(&nn->close_lru); |
6945 | INIT_LIST_HEAD(&nn->del_recall_lru); | 6943 | INIT_LIST_HEAD(&nn->del_recall_lru); |
6946 | INIT_LIST_HEAD(&nn->blocked_locks_lru); | ||
6947 | spin_lock_init(&nn->client_lock); | 6944 | spin_lock_init(&nn->client_lock); |
6948 | 6945 | ||
6946 | spin_lock_init(&nn->blocked_locks_lock); | ||
6947 | INIT_LIST_HEAD(&nn->blocked_locks_lru); | ||
6948 | |||
6949 | INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); | 6949 | INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); |
6950 | get_net(net); | 6950 | get_net(net); |
6951 | 6951 | ||
@@ -7063,14 +7063,14 @@ nfs4_state_shutdown_net(struct net *net) | |||
7063 | } | 7063 | } |
7064 | 7064 | ||
7065 | BUG_ON(!list_empty(&reaplist)); | 7065 | BUG_ON(!list_empty(&reaplist)); |
7066 | spin_lock(&nn->client_lock); | 7066 | spin_lock(&nn->blocked_locks_lock); |
7067 | while (!list_empty(&nn->blocked_locks_lru)) { | 7067 | while (!list_empty(&nn->blocked_locks_lru)) { |
7068 | nbl = list_first_entry(&nn->blocked_locks_lru, | 7068 | nbl = list_first_entry(&nn->blocked_locks_lru, |
7069 | struct nfsd4_blocked_lock, nbl_lru); | 7069 | struct nfsd4_blocked_lock, nbl_lru); |
7070 | list_move(&nbl->nbl_lru, &reaplist); | 7070 | list_move(&nbl->nbl_lru, &reaplist); |
7071 | list_del_init(&nbl->nbl_list); | 7071 | list_del_init(&nbl->nbl_list); |
7072 | } | 7072 | } |
7073 | spin_unlock(&nn->client_lock); | 7073 | spin_unlock(&nn->blocked_locks_lock); |
7074 | 7074 | ||
7075 | while (!list_empty(&reaplist)) { | 7075 | while (!list_empty(&reaplist)) { |
7076 | nbl = list_first_entry(&nn->blocked_locks_lru, | 7076 | nbl = list_first_entry(&nn->blocked_locks_lru, |