diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-18 14:22:04 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-18 14:22:04 -0500 |
commit | 4dd3c2e5a4225e3df85afc6033e62ce8b09f0ed2 (patch) | |
tree | 3d1dac5206550994b161eaab8ac73828f410228a /fs/nfsd | |
parent | 07c455ee222f3ad219c2835d05a175a326a138fb (diff) | |
parent | 22700f3c6df55387cec2ee27c533a7b23c76dc51 (diff) |
Merge tag 'nfsd-4.15' of git://linux-nfs.org/~bfields/linux
Pull nfsd updates from Bruce Fields:
"Lots of good bugfixes, including:
- fix a number of races in the NFSv4+ state code
- fix some shutdown crashes in multiple-network-namespace cases
- relax our 4.1 session limits; if you've an artificially low limit
to the number of 4.1 clients that can mount simultaneously, try
upgrading"
* tag 'nfsd-4.15' of git://linux-nfs.org/~bfields/linux: (22 commits)
SUNRPC: Improve ordering of transport processing
nfsd: deal with revoked delegations appropriately
svcrdma: Enqueue after setting XPT_CLOSE in completion handlers
nfsd: use nfs->ns.inum as net ID
rpc: remove some BUG()s
svcrdma: Preserve CB send buffer across retransmits
nfds: avoid gettimeofday for nfssvc_boot time
fs, nfsd: convert nfs4_file.fi_ref from atomic_t to refcount_t
fs, nfsd: convert nfs4_cntl_odstate.co_odcount from atomic_t to refcount_t
fs, nfsd: convert nfs4_stid.sc_count from atomic_t to refcount_t
lockd: double unregister of inetaddr notifiers
nfsd4: catch some false session retries
nfsd4: fix cached replies to solo SEQUENCE compounds
sunrcp: make function _svc_create_xprt static
SUNRPC: Fix tracepoint storage issues with svc_recv and svc_rqst_status
nfsd: use ARRAY_SIZE
nfsd: give out fewer session slots as limit approaches
nfsd: increase DRC cache limit
nfsd: remove unnecessary nofilehandle checks
nfs_common: convert int to bool
...
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/fault_inject.c | 5 | ||||
-rw-r--r-- | fs/nfsd/netns.h | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 10 | ||||
-rw-r--r-- | fs/nfsd/nfs4layouts.c | 4 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 19 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 127 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 4 | ||||
-rw-r--r-- | fs/nfsd/state.h | 11 | ||||
-rw-r--r-- | fs/nfsd/xdr4.h | 13 |
9 files changed, 136 insertions, 59 deletions
diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index 6dfede6d172a..84831253203d 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/nsproxy.h> | 12 | #include <linux/nsproxy.h> |
13 | #include <linux/sunrpc/addr.h> | 13 | #include <linux/sunrpc/addr.h> |
14 | #include <linux/uaccess.h> | 14 | #include <linux/uaccess.h> |
15 | #include <linux/kernel.h> | ||
15 | 16 | ||
16 | #include "state.h" | 17 | #include "state.h" |
17 | #include "netns.h" | 18 | #include "netns.h" |
@@ -126,8 +127,6 @@ static struct nfsd_fault_inject_op inject_ops[] = { | |||
126 | }, | 127 | }, |
127 | }; | 128 | }; |
128 | 129 | ||
129 | #define NUM_INJECT_OPS (sizeof(inject_ops)/sizeof(struct nfsd_fault_inject_op)) | ||
130 | |||
131 | int nfsd_fault_inject_init(void) | 130 | int nfsd_fault_inject_init(void) |
132 | { | 131 | { |
133 | unsigned int i; | 132 | unsigned int i; |
@@ -138,7 +137,7 @@ int nfsd_fault_inject_init(void) | |||
138 | if (!debug_dir) | 137 | if (!debug_dir) |
139 | goto fail; | 138 | goto fail; |
140 | 139 | ||
141 | for (i = 0; i < NUM_INJECT_OPS; i++) { | 140 | for (i = 0; i < ARRAY_SIZE(inject_ops); i++) { |
142 | op = &inject_ops[i]; | 141 | op = &inject_ops[i]; |
143 | if (!debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd)) | 142 | if (!debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd)) |
144 | goto fail; | 143 | goto fail; |
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 3714231a9d0f..1c91391f4805 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h | |||
@@ -107,7 +107,7 @@ struct nfsd_net { | |||
107 | bool lockd_up; | 107 | bool lockd_up; |
108 | 108 | ||
109 | /* Time of server startup */ | 109 | /* Time of server startup */ |
110 | struct timeval nfssvc_boot; | 110 | struct timespec64 nfssvc_boot; |
111 | 111 | ||
112 | /* | 112 | /* |
113 | * Max number of connections this nfsd container will allow. Defaults | 113 | * Max number of connections this nfsd container will allow. Defaults |
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index f38acd905441..2758480555fa 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -748,8 +748,9 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) | |||
748 | if (resp->status == 0) { | 748 | if (resp->status == 0) { |
749 | *p++ = htonl(resp->count); | 749 | *p++ = htonl(resp->count); |
750 | *p++ = htonl(resp->committed); | 750 | *p++ = htonl(resp->committed); |
751 | *p++ = htonl(nn->nfssvc_boot.tv_sec); | 751 | /* unique identifier, y2038 overflow can be ignored */ |
752 | *p++ = htonl(nn->nfssvc_boot.tv_usec); | 752 | *p++ = htonl((u32)nn->nfssvc_boot.tv_sec); |
753 | *p++ = htonl(nn->nfssvc_boot.tv_nsec); | ||
753 | } | 754 | } |
754 | return xdr_ressize_check(rqstp, p); | 755 | return xdr_ressize_check(rqstp, p); |
755 | } | 756 | } |
@@ -1119,8 +1120,9 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p) | |||
1119 | p = encode_wcc_data(rqstp, p, &resp->fh); | 1120 | p = encode_wcc_data(rqstp, p, &resp->fh); |
1120 | /* Write verifier */ | 1121 | /* Write verifier */ |
1121 | if (resp->status == 0) { | 1122 | if (resp->status == 0) { |
1122 | *p++ = htonl(nn->nfssvc_boot.tv_sec); | 1123 | /* unique identifier, y2038 overflow can be ignored */ |
1123 | *p++ = htonl(nn->nfssvc_boot.tv_usec); | 1124 | *p++ = htonl((u32)nn->nfssvc_boot.tv_sec); |
1125 | *p++ = htonl(nn->nfssvc_boot.tv_nsec); | ||
1124 | } | 1126 | } |
1125 | return xdr_ressize_check(rqstp, p); | 1127 | return xdr_ressize_check(rqstp, p); |
1126 | } | 1128 | } |
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c index ea45d954e8d7..7d888369f85a 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c | |||
@@ -336,7 +336,7 @@ nfsd4_recall_file_layout(struct nfs4_layout_stateid *ls) | |||
336 | 336 | ||
337 | trace_layout_recall(&ls->ls_stid.sc_stateid); | 337 | trace_layout_recall(&ls->ls_stid.sc_stateid); |
338 | 338 | ||
339 | atomic_inc(&ls->ls_stid.sc_count); | 339 | refcount_inc(&ls->ls_stid.sc_count); |
340 | nfsd4_run_cb(&ls->ls_recall); | 340 | nfsd4_run_cb(&ls->ls_recall); |
341 | 341 | ||
342 | out_unlock: | 342 | out_unlock: |
@@ -441,7 +441,7 @@ nfsd4_insert_layout(struct nfsd4_layoutget *lgp, struct nfs4_layout_stateid *ls) | |||
441 | goto done; | 441 | goto done; |
442 | } | 442 | } |
443 | 443 | ||
444 | atomic_inc(&ls->ls_stid.sc_count); | 444 | refcount_inc(&ls->ls_stid.sc_count); |
445 | list_add_tail(&new->lo_perstate, &ls->ls_layouts); | 445 | list_add_tail(&new->lo_perstate, &ls->ls_layouts); |
446 | new = NULL; | 446 | new = NULL; |
447 | done: | 447 | done: |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 8487486ec496..008ea0b627d0 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -485,9 +485,6 @@ static __be32 | |||
485 | nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 485 | nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
486 | union nfsd4_op_u *u) | 486 | union nfsd4_op_u *u) |
487 | { | 487 | { |
488 | if (!cstate->current_fh.fh_dentry) | ||
489 | return nfserr_nofilehandle; | ||
490 | |||
491 | u->getfh = &cstate->current_fh; | 488 | u->getfh = &cstate->current_fh; |
492 | return nfs_ok; | 489 | return nfs_ok; |
493 | } | 490 | } |
@@ -535,9 +532,6 @@ static __be32 | |||
535 | nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 532 | nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
536 | union nfsd4_op_u *u) | 533 | union nfsd4_op_u *u) |
537 | { | 534 | { |
538 | if (!cstate->current_fh.fh_dentry) | ||
539 | return nfserr_nofilehandle; | ||
540 | |||
541 | fh_dup2(&cstate->save_fh, &cstate->current_fh); | 535 | fh_dup2(&cstate->save_fh, &cstate->current_fh); |
542 | if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG)) { | 536 | if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG)) { |
543 | memcpy(&cstate->save_stateid, &cstate->current_stateid, sizeof(stateid_t)); | 537 | memcpy(&cstate->save_stateid, &cstate->current_stateid, sizeof(stateid_t)); |
@@ -570,10 +564,11 @@ static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net) | |||
570 | 564 | ||
571 | /* | 565 | /* |
572 | * This is opaque to client, so no need to byte-swap. Use | 566 | * This is opaque to client, so no need to byte-swap. Use |
573 | * __force to keep sparse happy | 567 | * __force to keep sparse happy. y2038 time_t overflow is |
568 | * irrelevant in this usage. | ||
574 | */ | 569 | */ |
575 | verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec; | 570 | verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec; |
576 | verf[1] = (__force __be32)nn->nfssvc_boot.tv_usec; | 571 | verf[1] = (__force __be32)nn->nfssvc_boot.tv_nsec; |
577 | memcpy(verifier->data, verf, sizeof(verifier->data)); | 572 | memcpy(verifier->data, verf, sizeof(verifier->data)); |
578 | } | 573 | } |
579 | 574 | ||
@@ -703,10 +698,8 @@ nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
703 | union nfsd4_op_u *u) | 698 | union nfsd4_op_u *u) |
704 | { | 699 | { |
705 | struct nfsd4_link *link = &u->link; | 700 | struct nfsd4_link *link = &u->link; |
706 | __be32 status = nfserr_nofilehandle; | 701 | __be32 status; |
707 | 702 | ||
708 | if (!cstate->save_fh.fh_dentry) | ||
709 | return status; | ||
710 | status = nfsd_link(rqstp, &cstate->current_fh, | 703 | status = nfsd_link(rqstp, &cstate->current_fh, |
711 | link->li_name, link->li_namelen, &cstate->save_fh); | 704 | link->li_name, link->li_namelen, &cstate->save_fh); |
712 | if (!status) | 705 | if (!status) |
@@ -850,10 +843,8 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
850 | union nfsd4_op_u *u) | 843 | union nfsd4_op_u *u) |
851 | { | 844 | { |
852 | struct nfsd4_rename *rename = &u->rename; | 845 | struct nfsd4_rename *rename = &u->rename; |
853 | __be32 status = nfserr_nofilehandle; | 846 | __be32 status; |
854 | 847 | ||
855 | if (!cstate->save_fh.fh_dentry) | ||
856 | return status; | ||
857 | if (opens_in_grace(SVC_NET(rqstp)) && | 848 | if (opens_in_grace(SVC_NET(rqstp)) && |
858 | !(cstate->save_fh.fh_export->ex_flags & NFSEXP_NOSUBTREECHECK)) | 849 | !(cstate->save_fh.fh_export->ex_flags & NFSEXP_NOSUBTREECHECK)) |
859 | return nfserr_grace; | 850 | return nfserr_grace; |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 0c04f81aa63b..b82817767b9d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -359,7 +359,7 @@ put_nfs4_file(struct nfs4_file *fi) | |||
359 | { | 359 | { |
360 | might_lock(&state_lock); | 360 | might_lock(&state_lock); |
361 | 361 | ||
362 | if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) { | 362 | if (refcount_dec_and_lock(&fi->fi_ref, &state_lock)) { |
363 | hlist_del_rcu(&fi->fi_hash); | 363 | hlist_del_rcu(&fi->fi_hash); |
364 | spin_unlock(&state_lock); | 364 | spin_unlock(&state_lock); |
365 | WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate)); | 365 | WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate)); |
@@ -568,7 +568,7 @@ alloc_clnt_odstate(struct nfs4_client *clp) | |||
568 | co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL); | 568 | co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL); |
569 | if (co) { | 569 | if (co) { |
570 | co->co_client = clp; | 570 | co->co_client = clp; |
571 | atomic_set(&co->co_odcount, 1); | 571 | refcount_set(&co->co_odcount, 1); |
572 | } | 572 | } |
573 | return co; | 573 | return co; |
574 | } | 574 | } |
@@ -586,7 +586,7 @@ static inline void | |||
586 | get_clnt_odstate(struct nfs4_clnt_odstate *co) | 586 | get_clnt_odstate(struct nfs4_clnt_odstate *co) |
587 | { | 587 | { |
588 | if (co) | 588 | if (co) |
589 | atomic_inc(&co->co_odcount); | 589 | refcount_inc(&co->co_odcount); |
590 | } | 590 | } |
591 | 591 | ||
592 | static void | 592 | static void |
@@ -598,7 +598,7 @@ put_clnt_odstate(struct nfs4_clnt_odstate *co) | |||
598 | return; | 598 | return; |
599 | 599 | ||
600 | fp = co->co_file; | 600 | fp = co->co_file; |
601 | if (atomic_dec_and_lock(&co->co_odcount, &fp->fi_lock)) { | 601 | if (refcount_dec_and_lock(&co->co_odcount, &fp->fi_lock)) { |
602 | list_del(&co->co_perfile); | 602 | list_del(&co->co_perfile); |
603 | spin_unlock(&fp->fi_lock); | 603 | spin_unlock(&fp->fi_lock); |
604 | 604 | ||
@@ -656,7 +656,7 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *sla | |||
656 | stid->sc_stateid.si_opaque.so_id = new_id; | 656 | stid->sc_stateid.si_opaque.so_id = new_id; |
657 | stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; | 657 | stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; |
658 | /* Will be incremented before return to client: */ | 658 | /* Will be incremented before return to client: */ |
659 | atomic_set(&stid->sc_count, 1); | 659 | refcount_set(&stid->sc_count, 1); |
660 | spin_lock_init(&stid->sc_lock); | 660 | spin_lock_init(&stid->sc_lock); |
661 | 661 | ||
662 | /* | 662 | /* |
@@ -813,7 +813,7 @@ nfs4_put_stid(struct nfs4_stid *s) | |||
813 | 813 | ||
814 | might_lock(&clp->cl_lock); | 814 | might_lock(&clp->cl_lock); |
815 | 815 | ||
816 | if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock)) { | 816 | if (!refcount_dec_and_lock(&s->sc_count, &clp->cl_lock)) { |
817 | wake_up_all(&close_wq); | 817 | wake_up_all(&close_wq); |
818 | return; | 818 | return; |
819 | } | 819 | } |
@@ -913,7 +913,7 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) | |||
913 | if (status) | 913 | if (status) |
914 | return status; | 914 | return status; |
915 | ++fp->fi_delegees; | 915 | ++fp->fi_delegees; |
916 | atomic_inc(&dp->dl_stid.sc_count); | 916 | refcount_inc(&dp->dl_stid.sc_count); |
917 | dp->dl_stid.sc_type = NFS4_DELEG_STID; | 917 | dp->dl_stid.sc_type = NFS4_DELEG_STID; |
918 | list_add(&dp->dl_perfile, &fp->fi_delegations); | 918 | list_add(&dp->dl_perfile, &fp->fi_delegations); |
919 | list_add(&dp->dl_perclnt, &clp->cl_delegations); | 919 | list_add(&dp->dl_perclnt, &clp->cl_delegations); |
@@ -1214,7 +1214,7 @@ static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, | |||
1214 | 1214 | ||
1215 | WARN_ON_ONCE(!list_empty(&stp->st_locks)); | 1215 | WARN_ON_ONCE(!list_empty(&stp->st_locks)); |
1216 | 1216 | ||
1217 | if (!atomic_dec_and_test(&s->sc_count)) { | 1217 | if (!refcount_dec_and_test(&s->sc_count)) { |
1218 | wake_up_all(&close_wq); | 1218 | wake_up_all(&close_wq); |
1219 | return; | 1219 | return; |
1220 | } | 1220 | } |
@@ -1439,8 +1439,10 @@ free_session_slots(struct nfsd4_session *ses) | |||
1439 | { | 1439 | { |
1440 | int i; | 1440 | int i; |
1441 | 1441 | ||
1442 | for (i = 0; i < ses->se_fchannel.maxreqs; i++) | 1442 | for (i = 0; i < ses->se_fchannel.maxreqs; i++) { |
1443 | free_svc_cred(&ses->se_slots[i]->sl_cred); | ||
1443 | kfree(ses->se_slots[i]); | 1444 | kfree(ses->se_slots[i]); |
1445 | } | ||
1444 | } | 1446 | } |
1445 | 1447 | ||
1446 | /* | 1448 | /* |
@@ -1472,6 +1474,11 @@ static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca) | |||
1472 | spin_lock(&nfsd_drc_lock); | 1474 | spin_lock(&nfsd_drc_lock); |
1473 | avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, | 1475 | avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, |
1474 | nfsd_drc_max_mem - nfsd_drc_mem_used); | 1476 | nfsd_drc_max_mem - nfsd_drc_mem_used); |
1477 | /* | ||
1478 | * Never use more than a third of the remaining memory, | ||
1479 | * unless it's the only way to give this client a slot: | ||
1480 | */ | ||
1481 | avail = clamp_t(int, avail, slotsize, avail/3); | ||
1475 | num = min_t(int, num, avail / slotsize); | 1482 | num = min_t(int, num, avail / slotsize); |
1476 | nfsd_drc_mem_used += num * slotsize; | 1483 | nfsd_drc_mem_used += num * slotsize; |
1477 | spin_unlock(&nfsd_drc_lock); | 1484 | spin_unlock(&nfsd_drc_lock); |
@@ -2072,7 +2079,7 @@ find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) | |||
2072 | s = find_stateid_locked(cl, t); | 2079 | s = find_stateid_locked(cl, t); |
2073 | if (s != NULL) { | 2080 | if (s != NULL) { |
2074 | if (typemask & s->sc_type) | 2081 | if (typemask & s->sc_type) |
2075 | atomic_inc(&s->sc_count); | 2082 | refcount_inc(&s->sc_count); |
2076 | else | 2083 | else |
2077 | s = NULL; | 2084 | s = NULL; |
2078 | } | 2085 | } |
@@ -2287,14 +2294,18 @@ nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) | |||
2287 | 2294 | ||
2288 | dprintk("--> %s slot %p\n", __func__, slot); | 2295 | dprintk("--> %s slot %p\n", __func__, slot); |
2289 | 2296 | ||
2297 | slot->sl_flags |= NFSD4_SLOT_INITIALIZED; | ||
2290 | slot->sl_opcnt = resp->opcnt; | 2298 | slot->sl_opcnt = resp->opcnt; |
2291 | slot->sl_status = resp->cstate.status; | 2299 | slot->sl_status = resp->cstate.status; |
2300 | free_svc_cred(&slot->sl_cred); | ||
2301 | copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred); | ||
2292 | 2302 | ||
2293 | slot->sl_flags |= NFSD4_SLOT_INITIALIZED; | 2303 | if (!nfsd4_cache_this(resp)) { |
2294 | if (nfsd4_not_cached(resp)) { | 2304 | slot->sl_flags &= ~NFSD4_SLOT_CACHED; |
2295 | slot->sl_datalen = 0; | ||
2296 | return; | 2305 | return; |
2297 | } | 2306 | } |
2307 | slot->sl_flags |= NFSD4_SLOT_CACHED; | ||
2308 | |||
2298 | base = resp->cstate.data_offset; | 2309 | base = resp->cstate.data_offset; |
2299 | slot->sl_datalen = buf->len - base; | 2310 | slot->sl_datalen = buf->len - base; |
2300 | if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) | 2311 | if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) |
@@ -2321,8 +2332,16 @@ nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, | |||
2321 | op = &args->ops[resp->opcnt - 1]; | 2332 | op = &args->ops[resp->opcnt - 1]; |
2322 | nfsd4_encode_operation(resp, op); | 2333 | nfsd4_encode_operation(resp, op); |
2323 | 2334 | ||
2324 | /* Return nfserr_retry_uncached_rep in next operation. */ | 2335 | if (slot->sl_flags & NFSD4_SLOT_CACHED) |
2325 | if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) { | 2336 | return op->status; |
2337 | if (args->opcnt == 1) { | ||
2338 | /* | ||
2339 | * The original operation wasn't a solo sequence--we | ||
2340 | * always cache those--so this retry must not match the | ||
2341 | * original: | ||
2342 | */ | ||
2343 | op->status = nfserr_seq_false_retry; | ||
2344 | } else { | ||
2326 | op = &args->ops[resp->opcnt++]; | 2345 | op = &args->ops[resp->opcnt++]; |
2327 | op->status = nfserr_retry_uncached_rep; | 2346 | op->status = nfserr_retry_uncached_rep; |
2328 | nfsd4_encode_operation(resp, op); | 2347 | nfsd4_encode_operation(resp, op); |
@@ -2986,6 +3005,34 @@ static bool nfsd4_request_too_big(struct svc_rqst *rqstp, | |||
2986 | return xb->len > session->se_fchannel.maxreq_sz; | 3005 | return xb->len > session->se_fchannel.maxreq_sz; |
2987 | } | 3006 | } |
2988 | 3007 | ||
3008 | static bool replay_matches_cache(struct svc_rqst *rqstp, | ||
3009 | struct nfsd4_sequence *seq, struct nfsd4_slot *slot) | ||
3010 | { | ||
3011 | struct nfsd4_compoundargs *argp = rqstp->rq_argp; | ||
3012 | |||
3013 | if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) != | ||
3014 | (bool)seq->cachethis) | ||
3015 | return false; | ||
3016 | /* | ||
3017 | * If there's an error than the reply can have fewer ops than | ||
3018 | * the call. But if we cached a reply with *more* ops than the | ||
3019 | * call you're sending us now, then this new call is clearly not | ||
3020 | * really a replay of the old one: | ||
3021 | */ | ||
3022 | if (slot->sl_opcnt < argp->opcnt) | ||
3023 | return false; | ||
3024 | /* This is the only check explicitly called by spec: */ | ||
3025 | if (!same_creds(&rqstp->rq_cred, &slot->sl_cred)) | ||
3026 | return false; | ||
3027 | /* | ||
3028 | * There may be more comparisons we could actually do, but the | ||
3029 | * spec doesn't require us to catch every case where the calls | ||
3030 | * don't match (that would require caching the call as well as | ||
3031 | * the reply), so we don't bother. | ||
3032 | */ | ||
3033 | return true; | ||
3034 | } | ||
3035 | |||
2989 | __be32 | 3036 | __be32 |
2990 | nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 3037 | nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
2991 | union nfsd4_op_u *u) | 3038 | union nfsd4_op_u *u) |
@@ -3045,6 +3092,9 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3045 | status = nfserr_seq_misordered; | 3092 | status = nfserr_seq_misordered; |
3046 | if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) | 3093 | if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) |
3047 | goto out_put_session; | 3094 | goto out_put_session; |
3095 | status = nfserr_seq_false_retry; | ||
3096 | if (!replay_matches_cache(rqstp, seq, slot)) | ||
3097 | goto out_put_session; | ||
3048 | cstate->slot = slot; | 3098 | cstate->slot = slot; |
3049 | cstate->session = session; | 3099 | cstate->session = session; |
3050 | cstate->clp = clp; | 3100 | cstate->clp = clp; |
@@ -3351,7 +3401,7 @@ static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, | |||
3351 | { | 3401 | { |
3352 | lockdep_assert_held(&state_lock); | 3402 | lockdep_assert_held(&state_lock); |
3353 | 3403 | ||
3354 | atomic_set(&fp->fi_ref, 1); | 3404 | refcount_set(&fp->fi_ref, 1); |
3355 | spin_lock_init(&fp->fi_lock); | 3405 | spin_lock_init(&fp->fi_lock); |
3356 | INIT_LIST_HEAD(&fp->fi_stateids); | 3406 | INIT_LIST_HEAD(&fp->fi_stateids); |
3357 | INIT_LIST_HEAD(&fp->fi_delegations); | 3407 | INIT_LIST_HEAD(&fp->fi_delegations); |
@@ -3514,7 +3564,7 @@ nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) | |||
3514 | continue; | 3564 | continue; |
3515 | if (local->st_stateowner == &oo->oo_owner) { | 3565 | if (local->st_stateowner == &oo->oo_owner) { |
3516 | ret = local; | 3566 | ret = local; |
3517 | atomic_inc(&ret->st_stid.sc_count); | 3567 | refcount_inc(&ret->st_stid.sc_count); |
3518 | break; | 3568 | break; |
3519 | } | 3569 | } |
3520 | } | 3570 | } |
@@ -3573,7 +3623,7 @@ init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open) | |||
3573 | goto out_unlock; | 3623 | goto out_unlock; |
3574 | 3624 | ||
3575 | open->op_stp = NULL; | 3625 | open->op_stp = NULL; |
3576 | atomic_inc(&stp->st_stid.sc_count); | 3626 | refcount_inc(&stp->st_stid.sc_count); |
3577 | stp->st_stid.sc_type = NFS4_OPEN_STID; | 3627 | stp->st_stid.sc_type = NFS4_OPEN_STID; |
3578 | INIT_LIST_HEAD(&stp->st_locks); | 3628 | INIT_LIST_HEAD(&stp->st_locks); |
3579 | stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); | 3629 | stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); |
@@ -3621,7 +3671,7 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) | |||
3621 | * there should be no danger of the refcount going back up again at | 3671 | * there should be no danger of the refcount going back up again at |
3622 | * this point. | 3672 | * this point. |
3623 | */ | 3673 | */ |
3624 | wait_event(close_wq, atomic_read(&s->st_stid.sc_count) == 2); | 3674 | wait_event(close_wq, refcount_read(&s->st_stid.sc_count) == 2); |
3625 | 3675 | ||
3626 | release_all_access(s); | 3676 | release_all_access(s); |
3627 | if (s->st_stid.sc_file) { | 3677 | if (s->st_stid.sc_file) { |
@@ -3647,7 +3697,7 @@ find_file_locked(struct knfsd_fh *fh, unsigned int hashval) | |||
3647 | 3697 | ||
3648 | hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) { | 3698 | hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash) { |
3649 | if (fh_match(&fp->fi_fhandle, fh)) { | 3699 | if (fh_match(&fp->fi_fhandle, fh)) { |
3650 | if (atomic_inc_not_zero(&fp->fi_ref)) | 3700 | if (refcount_inc_not_zero(&fp->fi_ref)) |
3651 | return fp; | 3701 | return fp; |
3652 | } | 3702 | } |
3653 | } | 3703 | } |
@@ -3783,7 +3833,7 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp) | |||
3783 | * lock) we know the server hasn't removed the lease yet, we know | 3833 | * lock) we know the server hasn't removed the lease yet, we know |
3784 | * it's safe to take a reference. | 3834 | * it's safe to take a reference. |
3785 | */ | 3835 | */ |
3786 | atomic_inc(&dp->dl_stid.sc_count); | 3836 | refcount_inc(&dp->dl_stid.sc_count); |
3787 | nfsd4_run_cb(&dp->dl_recall); | 3837 | nfsd4_run_cb(&dp->dl_recall); |
3788 | } | 3838 | } |
3789 | 3839 | ||
@@ -3966,7 +4016,8 @@ static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, statei | |||
3966 | { | 4016 | { |
3967 | struct nfs4_stid *ret; | 4017 | struct nfs4_stid *ret; |
3968 | 4018 | ||
3969 | ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID); | 4019 | ret = find_stateid_by_type(cl, s, |
4020 | NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID); | ||
3970 | if (!ret) | 4021 | if (!ret) |
3971 | return NULL; | 4022 | return NULL; |
3972 | return delegstateid(ret); | 4023 | return delegstateid(ret); |
@@ -3989,6 +4040,12 @@ nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, | |||
3989 | deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); | 4040 | deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); |
3990 | if (deleg == NULL) | 4041 | if (deleg == NULL) |
3991 | goto out; | 4042 | goto out; |
4043 | if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) { | ||
4044 | nfs4_put_stid(&deleg->dl_stid); | ||
4045 | if (cl->cl_minorversion) | ||
4046 | status = nfserr_deleg_revoked; | ||
4047 | goto out; | ||
4048 | } | ||
3992 | flags = share_access_to_flags(open->op_share_access); | 4049 | flags = share_access_to_flags(open->op_share_access); |
3993 | status = nfs4_check_delegmode(deleg, flags); | 4050 | status = nfs4_check_delegmode(deleg, flags); |
3994 | if (status) { | 4051 | if (status) { |
@@ -4858,6 +4915,16 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, | |||
4858 | struct nfs4_stid **s, struct nfsd_net *nn) | 4915 | struct nfs4_stid **s, struct nfsd_net *nn) |
4859 | { | 4916 | { |
4860 | __be32 status; | 4917 | __be32 status; |
4918 | bool return_revoked = false; | ||
4919 | |||
4920 | /* | ||
4921 | * only return revoked delegations if explicitly asked. | ||
4922 | * otherwise we report revoked or bad_stateid status. | ||
4923 | */ | ||
4924 | if (typemask & NFS4_REVOKED_DELEG_STID) | ||
4925 | return_revoked = true; | ||
4926 | else if (typemask & NFS4_DELEG_STID) | ||
4927 | typemask |= NFS4_REVOKED_DELEG_STID; | ||
4861 | 4928 | ||
4862 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 4929 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
4863 | return nfserr_bad_stateid; | 4930 | return nfserr_bad_stateid; |
@@ -4872,6 +4939,12 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, | |||
4872 | *s = find_stateid_by_type(cstate->clp, stateid, typemask); | 4939 | *s = find_stateid_by_type(cstate->clp, stateid, typemask); |
4873 | if (!*s) | 4940 | if (!*s) |
4874 | return nfserr_bad_stateid; | 4941 | return nfserr_bad_stateid; |
4942 | if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) { | ||
4943 | nfs4_put_stid(*s); | ||
4944 | if (cstate->minorversion) | ||
4945 | return nfserr_deleg_revoked; | ||
4946 | return nfserr_bad_stateid; | ||
4947 | } | ||
4875 | return nfs_ok; | 4948 | return nfs_ok; |
4876 | } | 4949 | } |
4877 | 4950 | ||
@@ -5071,7 +5144,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5071 | ret = nfserr_locks_held; | 5144 | ret = nfserr_locks_held; |
5072 | break; | 5145 | break; |
5073 | case NFS4_LOCK_STID: | 5146 | case NFS4_LOCK_STID: |
5074 | atomic_inc(&s->sc_count); | 5147 | refcount_inc(&s->sc_count); |
5075 | spin_unlock(&cl->cl_lock); | 5148 | spin_unlock(&cl->cl_lock); |
5076 | ret = nfsd4_free_lock_stateid(stateid, s); | 5149 | ret = nfsd4_free_lock_stateid(stateid, s); |
5077 | goto out; | 5150 | goto out; |
@@ -5578,7 +5651,7 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, | |||
5578 | 5651 | ||
5579 | lockdep_assert_held(&clp->cl_lock); | 5652 | lockdep_assert_held(&clp->cl_lock); |
5580 | 5653 | ||
5581 | atomic_inc(&stp->st_stid.sc_count); | 5654 | refcount_inc(&stp->st_stid.sc_count); |
5582 | stp->st_stid.sc_type = NFS4_LOCK_STID; | 5655 | stp->st_stid.sc_type = NFS4_LOCK_STID; |
5583 | stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); | 5656 | stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); |
5584 | get_nfs4_file(fp); | 5657 | get_nfs4_file(fp); |
@@ -5604,7 +5677,7 @@ find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp) | |||
5604 | 5677 | ||
5605 | list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) { | 5678 | list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) { |
5606 | if (lst->st_stid.sc_file == fp) { | 5679 | if (lst->st_stid.sc_file == fp) { |
5607 | atomic_inc(&lst->st_stid.sc_count); | 5680 | refcount_inc(&lst->st_stid.sc_count); |
5608 | return lst; | 5681 | return lst; |
5609 | } | 5682 | } |
5610 | } | 5683 | } |
@@ -7006,8 +7079,8 @@ nfs4_state_start_net(struct net *net) | |||
7006 | nn->nfsd4_manager.block_opens = true; | 7079 | nn->nfsd4_manager.block_opens = true; |
7007 | locks_start_grace(net, &nn->nfsd4_manager); | 7080 | locks_start_grace(net, &nn->nfsd4_manager); |
7008 | nfsd4_client_tracking_init(net); | 7081 | nfsd4_client_tracking_init(net); |
7009 | printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n", | 7082 | printk(KERN_INFO "NFSD: starting %ld-second grace period (net %x)\n", |
7010 | nn->nfsd4_grace, net); | 7083 | nn->nfsd4_grace, net->ns.inum); |
7011 | queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); | 7084 | queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); |
7012 | return 0; | 7085 | return 0; |
7013 | } | 7086 | } |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index e02bd2783124..33117d4ffce0 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -447,7 +447,7 @@ void nfsd_reset_versions(void) | |||
447 | */ | 447 | */ |
448 | static void set_max_drc(void) | 448 | static void set_max_drc(void) |
449 | { | 449 | { |
450 | #define NFSD_DRC_SIZE_SHIFT 10 | 450 | #define NFSD_DRC_SIZE_SHIFT 7 |
451 | nfsd_drc_max_mem = (nr_free_buffer_pages() | 451 | nfsd_drc_max_mem = (nr_free_buffer_pages() |
452 | >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE; | 452 | >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE; |
453 | nfsd_drc_mem_used = 0; | 453 | nfsd_drc_mem_used = 0; |
@@ -517,7 +517,7 @@ int nfsd_create_serv(struct net *net) | |||
517 | register_inet6addr_notifier(&nfsd_inet6addr_notifier); | 517 | register_inet6addr_notifier(&nfsd_inet6addr_notifier); |
518 | #endif | 518 | #endif |
519 | } | 519 | } |
520 | do_gettimeofday(&nn->nfssvc_boot); /* record boot time */ | 520 | ktime_get_real_ts64(&nn->nfssvc_boot); /* record boot time */ |
521 | return 0; | 521 | return 0; |
522 | } | 522 | } |
523 | 523 | ||
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 005c911b34ac..f3772ea8ba0d 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -36,6 +36,7 @@ | |||
36 | #define _NFSD4_STATE_H | 36 | #define _NFSD4_STATE_H |
37 | 37 | ||
38 | #include <linux/idr.h> | 38 | #include <linux/idr.h> |
39 | #include <linux/refcount.h> | ||
39 | #include <linux/sunrpc/svc_xprt.h> | 40 | #include <linux/sunrpc/svc_xprt.h> |
40 | #include "nfsfh.h" | 41 | #include "nfsfh.h" |
41 | 42 | ||
@@ -83,7 +84,7 @@ struct nfsd4_callback_ops { | |||
83 | * fields that are of general use to any stateid. | 84 | * fields that are of general use to any stateid. |
84 | */ | 85 | */ |
85 | struct nfs4_stid { | 86 | struct nfs4_stid { |
86 | atomic_t sc_count; | 87 | refcount_t sc_count; |
87 | #define NFS4_OPEN_STID 1 | 88 | #define NFS4_OPEN_STID 1 |
88 | #define NFS4_LOCK_STID 2 | 89 | #define NFS4_LOCK_STID 2 |
89 | #define NFS4_DELEG_STID 4 | 90 | #define NFS4_DELEG_STID 4 |
@@ -169,11 +170,13 @@ static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s) | |||
169 | struct nfsd4_slot { | 170 | struct nfsd4_slot { |
170 | u32 sl_seqid; | 171 | u32 sl_seqid; |
171 | __be32 sl_status; | 172 | __be32 sl_status; |
173 | struct svc_cred sl_cred; | ||
172 | u32 sl_datalen; | 174 | u32 sl_datalen; |
173 | u16 sl_opcnt; | 175 | u16 sl_opcnt; |
174 | #define NFSD4_SLOT_INUSE (1 << 0) | 176 | #define NFSD4_SLOT_INUSE (1 << 0) |
175 | #define NFSD4_SLOT_CACHETHIS (1 << 1) | 177 | #define NFSD4_SLOT_CACHETHIS (1 << 1) |
176 | #define NFSD4_SLOT_INITIALIZED (1 << 2) | 178 | #define NFSD4_SLOT_INITIALIZED (1 << 2) |
179 | #define NFSD4_SLOT_CACHED (1 << 3) | ||
177 | u8 sl_flags; | 180 | u8 sl_flags; |
178 | char sl_data[]; | 181 | char sl_data[]; |
179 | }; | 182 | }; |
@@ -465,7 +468,7 @@ struct nfs4_clnt_odstate { | |||
465 | struct nfs4_client *co_client; | 468 | struct nfs4_client *co_client; |
466 | struct nfs4_file *co_file; | 469 | struct nfs4_file *co_file; |
467 | struct list_head co_perfile; | 470 | struct list_head co_perfile; |
468 | atomic_t co_odcount; | 471 | refcount_t co_odcount; |
469 | }; | 472 | }; |
470 | 473 | ||
471 | /* | 474 | /* |
@@ -481,7 +484,7 @@ struct nfs4_clnt_odstate { | |||
481 | * the global state_lock spinlock. | 484 | * the global state_lock spinlock. |
482 | */ | 485 | */ |
483 | struct nfs4_file { | 486 | struct nfs4_file { |
484 | atomic_t fi_ref; | 487 | refcount_t fi_ref; |
485 | spinlock_t fi_lock; | 488 | spinlock_t fi_lock; |
486 | struct hlist_node fi_hash; /* hash on fi_fhandle */ | 489 | struct hlist_node fi_hash; /* hash on fi_fhandle */ |
487 | struct list_head fi_stateids; | 490 | struct list_head fi_stateids; |
@@ -634,7 +637,7 @@ struct nfs4_file *find_file(struct knfsd_fh *fh); | |||
634 | void put_nfs4_file(struct nfs4_file *fi); | 637 | void put_nfs4_file(struct nfs4_file *fi); |
635 | static inline void get_nfs4_file(struct nfs4_file *fi) | 638 | static inline void get_nfs4_file(struct nfs4_file *fi) |
636 | { | 639 | { |
637 | atomic_inc(&fi->fi_ref); | 640 | refcount_inc(&fi->fi_ref); |
638 | } | 641 | } |
639 | struct file *find_any_file(struct nfs4_file *f); | 642 | struct file *find_any_file(struct nfs4_file *f); |
640 | 643 | ||
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 1e4edbf70052..bc29511b6405 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -649,9 +649,18 @@ static inline bool nfsd4_is_solo_sequence(struct nfsd4_compoundres *resp) | |||
649 | return resp->opcnt == 1 && args->ops[0].opnum == OP_SEQUENCE; | 649 | return resp->opcnt == 1 && args->ops[0].opnum == OP_SEQUENCE; |
650 | } | 650 | } |
651 | 651 | ||
652 | static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp) | 652 | /* |
653 | * The session reply cache only needs to cache replies that the client | ||
654 | * actually asked us to. But it's almost free for us to cache compounds | ||
655 | * consisting of only a SEQUENCE op, so we may as well cache those too. | ||
656 | * Also, the protocol doesn't give us a convenient response in the case | ||
657 | * of a replay of a solo SEQUENCE op that wasn't cached | ||
658 | * (RETRY_UNCACHED_REP can only be returned in the second op of a | ||
659 | * compound). | ||
660 | */ | ||
661 | static inline bool nfsd4_cache_this(struct nfsd4_compoundres *resp) | ||
653 | { | 662 | { |
654 | return !(resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS) | 663 | return (resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS) |
655 | || nfsd4_is_solo_sequence(resp); | 664 | || nfsd4_is_solo_sequence(resp); |
656 | } | 665 | } |
657 | 666 | ||