diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-04-23 16:40:55 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-04-23 16:40:55 -0400 |
| commit | 12a54b150fb5b6c2f3da932dc0e665355f8a5a48 (patch) | |
| tree | fa5d6becf0392244d4a44cc6afdbc93e363689d1 | |
| parent | d286e13d53f54b00bcd7443eedd067cd432cf547 (diff) | |
| parent | f456458e4d25a8962d0946891617c76cc3ff5fb9 (diff) | |
Merge tag 'nfsd-5.1-1' of git://linux-nfs.org/~bfields/linux
Pull nfsd bugfixes from Bruce Fields:
"Fix miscellaneous nfsd bugs, in NFSv4.1 callbacks, NFSv4.1
lock-notification callbacks, NFSv3 readdir encoding, and the
cache/upcall code"
* tag 'nfsd-5.1-1' of git://linux-nfs.org/~bfields/linux:
nfsd: wake blocked file lock waiters before sending callback
nfsd: wake waiters blocked on file_lock before deleting it
nfsd: Don't release the callback slot unless it was actually held
nfsd/nfsd3_proc_readdir: fix buffer count and page pointers
sunrpc: don't mark uninitialised items as VALID.
| -rw-r--r-- | fs/nfsd/nfs3proc.c | 17 | ||||
| -rw-r--r-- | fs/nfsd/nfs3xdr.c | 11 | ||||
| -rw-r--r-- | fs/nfsd/nfs4callback.c | 8 | ||||
| -rw-r--r-- | fs/nfsd/nfs4state.c | 12 | ||||
| -rw-r--r-- | fs/nfsd/state.h | 1 | ||||
| -rw-r--r-- | net/sunrpc/cache.c | 3 |
6 files changed, 45 insertions, 7 deletions
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 8f933e84cec1..9bc32af4e2da 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c | |||
| @@ -442,7 +442,9 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) | |||
| 442 | struct nfsd3_readdirargs *argp = rqstp->rq_argp; | 442 | struct nfsd3_readdirargs *argp = rqstp->rq_argp; |
| 443 | struct nfsd3_readdirres *resp = rqstp->rq_resp; | 443 | struct nfsd3_readdirres *resp = rqstp->rq_resp; |
| 444 | __be32 nfserr; | 444 | __be32 nfserr; |
| 445 | int count; | 445 | int count = 0; |
| 446 | struct page **p; | ||
| 447 | caddr_t page_addr = NULL; | ||
| 446 | 448 | ||
| 447 | dprintk("nfsd: READDIR(3) %s %d bytes at %d\n", | 449 | dprintk("nfsd: READDIR(3) %s %d bytes at %d\n", |
| 448 | SVCFH_fmt(&argp->fh), | 450 | SVCFH_fmt(&argp->fh), |
| @@ -462,7 +464,18 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) | |||
| 462 | nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie, | 464 | nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie, |
| 463 | &resp->common, nfs3svc_encode_entry); | 465 | &resp->common, nfs3svc_encode_entry); |
| 464 | memcpy(resp->verf, argp->verf, 8); | 466 | memcpy(resp->verf, argp->verf, 8); |
| 465 | resp->count = resp->buffer - argp->buffer; | 467 | count = 0; |
| 468 | for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) { | ||
| 469 | page_addr = page_address(*p); | ||
| 470 | |||
| 471 | if (((caddr_t)resp->buffer >= page_addr) && | ||
| 472 | ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) { | ||
| 473 | count += (caddr_t)resp->buffer - page_addr; | ||
| 474 | break; | ||
| 475 | } | ||
| 476 | count += PAGE_SIZE; | ||
| 477 | } | ||
| 478 | resp->count = count >> 2; | ||
| 466 | if (resp->offset) { | 479 | if (resp->offset) { |
| 467 | loff_t offset = argp->cookie; | 480 | loff_t offset = argp->cookie; |
| 468 | 481 | ||
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 93fea246f676..8d789124ed3c 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
| @@ -573,6 +573,7 @@ int | |||
| 573 | nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) | 573 | nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) |
| 574 | { | 574 | { |
| 575 | struct nfsd3_readdirargs *args = rqstp->rq_argp; | 575 | struct nfsd3_readdirargs *args = rqstp->rq_argp; |
| 576 | int len; | ||
| 576 | u32 max_blocksize = svc_max_payload(rqstp); | 577 | u32 max_blocksize = svc_max_payload(rqstp); |
| 577 | 578 | ||
| 578 | p = decode_fh(p, &args->fh); | 579 | p = decode_fh(p, &args->fh); |
| @@ -582,8 +583,14 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) | |||
| 582 | args->verf = p; p += 2; | 583 | args->verf = p; p += 2; |
| 583 | args->dircount = ~0; | 584 | args->dircount = ~0; |
| 584 | args->count = ntohl(*p++); | 585 | args->count = ntohl(*p++); |
| 585 | args->count = min_t(u32, args->count, max_blocksize); | 586 | len = args->count = min_t(u32, args->count, max_blocksize); |
| 586 | args->buffer = page_address(*(rqstp->rq_next_page++)); | 587 | |
| 588 | while (len > 0) { | ||
| 589 | struct page *p = *(rqstp->rq_next_page++); | ||
| 590 | if (!args->buffer) | ||
| 591 | args->buffer = page_address(p); | ||
| 592 | len -= PAGE_SIZE; | ||
| 593 | } | ||
| 587 | 594 | ||
| 588 | return xdr_argsize_check(rqstp, p); | 595 | return xdr_argsize_check(rqstp, p); |
| 589 | } | 596 | } |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index d219159b98af..7caa3801ce72 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
| @@ -1010,8 +1010,9 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata) | |||
| 1010 | cb->cb_seq_status = 1; | 1010 | cb->cb_seq_status = 1; |
| 1011 | cb->cb_status = 0; | 1011 | cb->cb_status = 0; |
| 1012 | if (minorversion) { | 1012 | if (minorversion) { |
| 1013 | if (!nfsd41_cb_get_slot(clp, task)) | 1013 | if (!cb->cb_holds_slot && !nfsd41_cb_get_slot(clp, task)) |
| 1014 | return; | 1014 | return; |
| 1015 | cb->cb_holds_slot = true; | ||
| 1015 | } | 1016 | } |
| 1016 | rpc_call_start(task); | 1017 | rpc_call_start(task); |
| 1017 | } | 1018 | } |
| @@ -1038,6 +1039,9 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback | |||
| 1038 | return true; | 1039 | return true; |
| 1039 | } | 1040 | } |
| 1040 | 1041 | ||
| 1042 | if (!cb->cb_holds_slot) | ||
| 1043 | goto need_restart; | ||
| 1044 | |||
| 1041 | switch (cb->cb_seq_status) { | 1045 | switch (cb->cb_seq_status) { |
| 1042 | case 0: | 1046 | case 0: |
| 1043 | /* | 1047 | /* |
| @@ -1076,6 +1080,7 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback | |||
| 1076 | cb->cb_seq_status); | 1080 | cb->cb_seq_status); |
| 1077 | } | 1081 | } |
| 1078 | 1082 | ||
| 1083 | cb->cb_holds_slot = false; | ||
| 1079 | clear_bit(0, &clp->cl_cb_slot_busy); | 1084 | clear_bit(0, &clp->cl_cb_slot_busy); |
| 1080 | rpc_wake_up_next(&clp->cl_cb_waitq); | 1085 | rpc_wake_up_next(&clp->cl_cb_waitq); |
| 1081 | dprintk("%s: freed slot, new seqid=%d\n", __func__, | 1086 | dprintk("%s: freed slot, new seqid=%d\n", __func__, |
| @@ -1283,6 +1288,7 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, | |||
| 1283 | cb->cb_seq_status = 1; | 1288 | cb->cb_seq_status = 1; |
| 1284 | cb->cb_status = 0; | 1289 | cb->cb_status = 0; |
| 1285 | cb->cb_need_restart = false; | 1290 | cb->cb_need_restart = false; |
| 1291 | cb->cb_holds_slot = false; | ||
| 1286 | } | 1292 | } |
| 1287 | 1293 | ||
| 1288 | void nfsd4_run_cb(struct nfsd4_callback *cb) | 1294 | void nfsd4_run_cb(struct nfsd4_callback *cb) |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6a45fb00c5fc..f056b1d3fecd 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -265,6 +265,7 @@ find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh, | |||
| 265 | static void | 265 | static void |
| 266 | free_blocked_lock(struct nfsd4_blocked_lock *nbl) | 266 | free_blocked_lock(struct nfsd4_blocked_lock *nbl) |
| 267 | { | 267 | { |
| 268 | locks_delete_block(&nbl->nbl_lock); | ||
| 268 | locks_release_private(&nbl->nbl_lock); | 269 | locks_release_private(&nbl->nbl_lock); |
| 269 | kfree(nbl); | 270 | kfree(nbl); |
| 270 | } | 271 | } |
| @@ -293,11 +294,18 @@ remove_blocked_locks(struct nfs4_lockowner *lo) | |||
| 293 | nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock, | 294 | nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock, |
| 294 | nbl_lru); | 295 | nbl_lru); |
| 295 | list_del_init(&nbl->nbl_lru); | 296 | list_del_init(&nbl->nbl_lru); |
| 296 | locks_delete_block(&nbl->nbl_lock); | ||
| 297 | free_blocked_lock(nbl); | 297 | free_blocked_lock(nbl); |
| 298 | } | 298 | } |
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | static void | ||
| 302 | nfsd4_cb_notify_lock_prepare(struct nfsd4_callback *cb) | ||
| 303 | { | ||
| 304 | struct nfsd4_blocked_lock *nbl = container_of(cb, | ||
| 305 | struct nfsd4_blocked_lock, nbl_cb); | ||
| 306 | locks_delete_block(&nbl->nbl_lock); | ||
| 307 | } | ||
| 308 | |||
| 301 | static int | 309 | static int |
| 302 | nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task) | 310 | nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task) |
| 303 | { | 311 | { |
| @@ -325,6 +333,7 @@ nfsd4_cb_notify_lock_release(struct nfsd4_callback *cb) | |||
| 325 | } | 333 | } |
| 326 | 334 | ||
| 327 | static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = { | 335 | static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = { |
| 336 | .prepare = nfsd4_cb_notify_lock_prepare, | ||
| 328 | .done = nfsd4_cb_notify_lock_done, | 337 | .done = nfsd4_cb_notify_lock_done, |
| 329 | .release = nfsd4_cb_notify_lock_release, | 338 | .release = nfsd4_cb_notify_lock_release, |
| 330 | }; | 339 | }; |
| @@ -4863,7 +4872,6 @@ nfs4_laundromat(struct nfsd_net *nn) | |||
| 4863 | nbl = list_first_entry(&reaplist, | 4872 | nbl = list_first_entry(&reaplist, |
| 4864 | struct nfsd4_blocked_lock, nbl_lru); | 4873 | struct nfsd4_blocked_lock, nbl_lru); |
| 4865 | list_del_init(&nbl->nbl_lru); | 4874 | list_del_init(&nbl->nbl_lru); |
| 4866 | locks_delete_block(&nbl->nbl_lock); | ||
| 4867 | free_blocked_lock(nbl); | 4875 | free_blocked_lock(nbl); |
| 4868 | } | 4876 | } |
| 4869 | out: | 4877 | out: |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 396c76755b03..9d6cb246c6c5 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
| @@ -70,6 +70,7 @@ struct nfsd4_callback { | |||
| 70 | int cb_seq_status; | 70 | int cb_seq_status; |
| 71 | int cb_status; | 71 | int cb_status; |
| 72 | bool cb_need_restart; | 72 | bool cb_need_restart; |
| 73 | bool cb_holds_slot; | ||
| 73 | }; | 74 | }; |
| 74 | 75 | ||
| 75 | struct nfsd4_callback_ops { | 76 | struct nfsd4_callback_ops { |
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 12bb23b8e0c5..261131dfa1f1 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
| @@ -54,6 +54,7 @@ static void cache_init(struct cache_head *h, struct cache_detail *detail) | |||
| 54 | h->last_refresh = now; | 54 | h->last_refresh = now; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | static inline int cache_is_valid(struct cache_head *h); | ||
| 57 | static void cache_fresh_locked(struct cache_head *head, time_t expiry, | 58 | static void cache_fresh_locked(struct cache_head *head, time_t expiry, |
| 58 | struct cache_detail *detail); | 59 | struct cache_detail *detail); |
| 59 | static void cache_fresh_unlocked(struct cache_head *head, | 60 | static void cache_fresh_unlocked(struct cache_head *head, |
| @@ -105,6 +106,8 @@ static struct cache_head *sunrpc_cache_add_entry(struct cache_detail *detail, | |||
| 105 | if (cache_is_expired(detail, tmp)) { | 106 | if (cache_is_expired(detail, tmp)) { |
| 106 | hlist_del_init_rcu(&tmp->cache_list); | 107 | hlist_del_init_rcu(&tmp->cache_list); |
| 107 | detail->entries --; | 108 | detail->entries --; |
| 109 | if (cache_is_valid(tmp) == -EAGAIN) | ||
| 110 | set_bit(CACHE_NEGATIVE, &tmp->flags); | ||
| 108 | cache_fresh_locked(tmp, 0, detail); | 111 | cache_fresh_locked(tmp, 0, detail); |
| 109 | freeme = tmp; | 112 | freeme = tmp; |
| 110 | break; | 113 | break; |
