aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-04-23 16:40:55 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-04-23 16:40:55 -0400
commit12a54b150fb5b6c2f3da932dc0e665355f8a5a48 (patch)
treefa5d6becf0392244d4a44cc6afdbc93e363689d1
parentd286e13d53f54b00bcd7443eedd067cd432cf547 (diff)
parentf456458e4d25a8962d0946891617c76cc3ff5fb9 (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.c17
-rw-r--r--fs/nfsd/nfs3xdr.c11
-rw-r--r--fs/nfsd/nfs4callback.c8
-rw-r--r--fs/nfsd/nfs4state.c12
-rw-r--r--fs/nfsd/state.h1
-rw-r--r--net/sunrpc/cache.c3
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
573nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) 573nfs3svc_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
1288void nfsd4_run_cb(struct nfsd4_callback *cb) 1294void 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,
265static void 265static void
266free_blocked_lock(struct nfsd4_blocked_lock *nbl) 266free_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
301static void
302nfsd4_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
301static int 309static int
302nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task) 310nfsd4_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
327static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = { 335static 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 }
4869out: 4877out:
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
75struct nfsd4_callback_ops { 76struct 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
57static inline int cache_is_valid(struct cache_head *h);
57static void cache_fresh_locked(struct cache_head *head, time_t expiry, 58static void cache_fresh_locked(struct cache_head *head, time_t expiry,
58 struct cache_detail *detail); 59 struct cache_detail *detail);
59static void cache_fresh_unlocked(struct cache_head *head, 60static 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;