From a948b1142cae66785521a389cab2cce74069b547 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:55:17 -0400 Subject: [PATCH 01/69] NFSD: Fix TP_printk() format specifier in nfsd_clid_class Since commit 9a6944fee68e ("tracing: Add a verifier to check string pointers for trace events"), which was merged in v5.13-rc1, TP_printk() no longer tacitly supports the "%.*s" format specifier. These are low value tracepoints, so just remove them. Reported-by: David Wysochanski Fixes: dd5e3fbc1f47 ("NFSD: Add tracepoints to the NFSD state management code") Signed-off-by: Chuck Lever Cc: Steven Rostedt Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 3 --- fs/nfsd/trace.h | 29 ----------------------------- 2 files changed, 32 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b517a8794400..6abe48dee6ed 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -7229,7 +7229,6 @@ nfs4_client_to_reclaim(struct xdr_netobj name, struct xdr_netobj princhash, unsigned int strhashval; struct nfs4_client_reclaim *crp; - trace_nfsd_clid_reclaim(nn, name.len, name.data); crp = alloc_reclaim(); if (crp) { strhashval = clientstr_hashval(name); @@ -7279,8 +7278,6 @@ nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn) unsigned int strhashval; struct nfs4_client_reclaim *crp = NULL; - trace_nfsd_clid_find(nn, name.len, name.data); - strhashval = clientstr_hashval(name); list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { if (compare_blob(&crp->cr_name, &name) == 0) { diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 27a93ebd1d80..42ad2a02f953 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -536,35 +536,6 @@ DEFINE_EVENT(nfsd_net_class, nfsd_##name, \ DEFINE_NET_EVENT(grace_start); DEFINE_NET_EVENT(grace_complete); -DECLARE_EVENT_CLASS(nfsd_clid_class, - TP_PROTO(const struct nfsd_net *nn, - unsigned int namelen, - const unsigned char *namedata), - TP_ARGS(nn, namelen, namedata), - TP_STRUCT__entry( - __field(unsigned long long, boot_time) - __field(unsigned int, namelen) - __dynamic_array(unsigned char, name, namelen) - ), - TP_fast_assign( - __entry->boot_time = nn->boot_time; - __entry->namelen = namelen; - memcpy(__get_dynamic_array(name), namedata, namelen); - ), - TP_printk("boot_time=%16llx nfs4_clientid=%.*s", - __entry->boot_time, __entry->namelen, __get_str(name)) -) - -#define DEFINE_CLID_EVENT(name) \ -DEFINE_EVENT(nfsd_clid_class, nfsd_clid_##name, \ - TP_PROTO(const struct nfsd_net *nn, \ - unsigned int namelen, \ - const unsigned char *namedata), \ - TP_ARGS(nn, namelen, namedata)) - -DEFINE_CLID_EVENT(find); -DEFINE_CLID_EVENT(reclaim); - TRACE_EVENT(nfsd_clid_inuse_err, TP_PROTO(const struct nfs4_client *clp), TP_ARGS(clp), From 87b2394d60c32c158ebb96ace4abee883baf1239 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:55:23 -0400 Subject: [PATCH 02/69] NFSD: Add an RPC authflavor tracepoint display helper To be used in subsequent patches. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/trace.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 42ad2a02f953..1b50640cdf96 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -841,6 +841,22 @@ DEFINE_NFSD_CB_EVENT(setup); DEFINE_NFSD_CB_EVENT(state); DEFINE_NFSD_CB_EVENT(shutdown); +TRACE_DEFINE_ENUM(RPC_AUTH_NULL); +TRACE_DEFINE_ENUM(RPC_AUTH_UNIX); +TRACE_DEFINE_ENUM(RPC_AUTH_GSS); +TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5); +TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5I); +TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5P); + +#define show_nfsd_authflavor(val) \ + __print_symbolic(val, \ + { RPC_AUTH_NULL, "none" }, \ + { RPC_AUTH_UNIX, "sys" }, \ + { RPC_AUTH_GSS, "gss" }, \ + { RPC_AUTH_GSS_KRB5, "krb5" }, \ + { RPC_AUTH_GSS_KRB5I, "krb5i" }, \ + { RPC_AUTH_GSS_KRB5P, "krb5p" }) + TRACE_EVENT(nfsd_cb_setup_err, TP_PROTO( const struct nfs4_client *clp, From 27787733ef44332fce749aa853f2749d141982b0 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:55:29 -0400 Subject: [PATCH 03/69] NFSD: Add nfsd_clid_cred_mismatch tracepoint Record when a client tries to establish a lease record but uses an unexpected credential. This is often a sign of a configuration problem. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 14 ++++++++++---- fs/nfsd/trace.h | 28 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6abe48dee6ed..84c4021b3826 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3181,6 +3181,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (!creds_match) { /* case 3 */ if (client_has_state(conf)) { status = nfserr_clid_inuse; + trace_nfsd_clid_cred_mismatch(conf, rqstp); goto out; } goto out_new; @@ -3425,9 +3426,10 @@ nfsd4_create_session(struct svc_rqst *rqstp, goto out_free_conn; } } else if (unconf) { + status = nfserr_clid_inuse; if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { - status = nfserr_clid_inuse; + trace_nfsd_clid_cred_mismatch(unconf, rqstp); goto out_free_conn; } status = nfserr_wrong_cred; @@ -3976,7 +3978,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (clp_used_exchangeid(conf)) goto out; if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { - trace_nfsd_clid_inuse_err(conf); + trace_nfsd_clid_cred_mismatch(conf, rqstp); goto out; } } @@ -4034,10 +4036,14 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, * Nevertheless, RFC 7530 recommends INUSE for this case: */ status = nfserr_clid_inuse; - if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) + if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { + trace_nfsd_clid_cred_mismatch(unconf, rqstp); goto out; - if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) + } + if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) { + trace_nfsd_clid_cred_mismatch(conf, rqstp); goto out; + } /* cases below refer to rfc 3530 section 14.2.34: */ if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { if (conf && same_verf(&confirm, &conf->cl_confirm)) { diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 1b50640cdf96..820a542e1013 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -536,6 +536,34 @@ DEFINE_EVENT(nfsd_net_class, nfsd_##name, \ DEFINE_NET_EVENT(grace_start); DEFINE_NET_EVENT(grace_complete); +TRACE_EVENT(nfsd_clid_cred_mismatch, + TP_PROTO( + const struct nfs4_client *clp, + const struct svc_rqst *rqstp + ), + TP_ARGS(clp, rqstp), + TP_STRUCT__entry( + __field(u32, cl_boot) + __field(u32, cl_id) + __field(unsigned long, cl_flavor) + __field(unsigned long, new_flavor) + __array(unsigned char, addr, sizeof(struct sockaddr_in6)) + ), + TP_fast_assign( + __entry->cl_boot = clp->cl_clientid.cl_boot; + __entry->cl_id = clp->cl_clientid.cl_id; + __entry->cl_flavor = clp->cl_cred.cr_flavor; + __entry->new_flavor = rqstp->rq_cred.cr_flavor; + memcpy(__entry->addr, &rqstp->rq_xprt->xpt_remote, + sizeof(struct sockaddr_in6)); + ), + TP_printk("client %08x:%08x flavor=%s, conflict=%s from addr=%pISpc", + __entry->cl_boot, __entry->cl_id, + show_nfsd_authflavor(__entry->cl_flavor), + show_nfsd_authflavor(__entry->new_flavor), __entry->addr + ) +) + TRACE_EVENT(nfsd_clid_inuse_err, TP_PROTO(const struct nfs4_client *clp), TP_ARGS(clp), From 744ea54c869cebe41fbad5f53f8a8ca5d93a5c97 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:55:36 -0400 Subject: [PATCH 04/69] NFSD: Add nfsd_clid_verf_mismatch tracepoint Record when a client presents a different boot verifier than the one we know about. Typically this is a sign the client has rebooted, but sometimes it signals a conflicting client ID, which the client's administrator will need to address. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 11 ++++++++--- fs/nfsd/trace.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 84c4021b3826..69405cc9d823 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3191,6 +3191,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out_copy; } /* case 5, client reboot */ + trace_nfsd_clid_verf_mismatch(conf, rqstp, &verf); conf = NULL; goto out_new; } @@ -3986,9 +3987,13 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (unconf) unhash_client_locked(unconf); /* We need to handle only case 1: probable callback update */ - if (conf && same_verf(&conf->cl_verifier, &clverifier)) { - copy_clid(new, conf); - gen_confirm(new, nn); + if (conf) { + if (same_verf(&conf->cl_verifier, &clverifier)) { + copy_clid(new, conf); + gen_confirm(new, nn); + } else + trace_nfsd_clid_verf_mismatch(conf, rqstp, + &clverifier); } new->cl_minorversion = 0; gen_callback(new, setclid, rqstp); diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 820a542e1013..24f54ab20eed 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -564,6 +564,38 @@ TRACE_EVENT(nfsd_clid_cred_mismatch, ) ) +TRACE_EVENT(nfsd_clid_verf_mismatch, + TP_PROTO( + const struct nfs4_client *clp, + const struct svc_rqst *rqstp, + const nfs4_verifier *verf + ), + TP_ARGS(clp, rqstp, verf), + TP_STRUCT__entry( + __field(u32, cl_boot) + __field(u32, cl_id) + __array(unsigned char, cl_verifier, NFS4_VERIFIER_SIZE) + __array(unsigned char, new_verifier, NFS4_VERIFIER_SIZE) + __array(unsigned char, addr, sizeof(struct sockaddr_in6)) + ), + TP_fast_assign( + __entry->cl_boot = clp->cl_clientid.cl_boot; + __entry->cl_id = clp->cl_clientid.cl_id; + memcpy(__entry->cl_verifier, (void *)&clp->cl_verifier, + NFS4_VERIFIER_SIZE); + memcpy(__entry->new_verifier, (void *)verf, + NFS4_VERIFIER_SIZE); + memcpy(__entry->addr, &rqstp->rq_xprt->xpt_remote, + sizeof(struct sockaddr_in6)); + ), + TP_printk("client %08x:%08x verf=0x%s, updated=0x%s from addr=%pISpc", + __entry->cl_boot, __entry->cl_id, + __print_hex_str(__entry->cl_verifier, NFS4_VERIFIER_SIZE), + __print_hex_str(__entry->new_verifier, NFS4_VERIFIER_SIZE), + __entry->addr + ) +); + TRACE_EVENT(nfsd_clid_inuse_err, TP_PROTO(const struct nfs4_client *clp), TP_ARGS(clp), From 0bfaacac57e64aa342f865b8ddcab06ca59a6f83 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:55:42 -0400 Subject: [PATCH 05/69] NFSD: Remove trace_nfsd_clid_inuse_err This tracepoint has been replaced by nfsd_clid_cred_mismatch and nfsd_clid_verf_mismatch, and can simply be removed. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/trace.h | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 24f54ab20eed..1265d6f058ee 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -596,30 +596,6 @@ TRACE_EVENT(nfsd_clid_verf_mismatch, ) ); -TRACE_EVENT(nfsd_clid_inuse_err, - TP_PROTO(const struct nfs4_client *clp), - TP_ARGS(clp), - TP_STRUCT__entry( - __field(u32, cl_boot) - __field(u32, cl_id) - __array(unsigned char, addr, sizeof(struct sockaddr_in6)) - __field(unsigned int, namelen) - __dynamic_array(unsigned char, name, clp->cl_name.len) - ), - TP_fast_assign( - __entry->cl_boot = clp->cl_clientid.cl_boot; - __entry->cl_id = clp->cl_clientid.cl_id; - memcpy(__entry->addr, &clp->cl_addr, - sizeof(struct sockaddr_in6)); - __entry->namelen = clp->cl_name.len; - memcpy(__get_dynamic_array(name), clp->cl_name.data, - clp->cl_name.len); - ), - TP_printk("nfs4_clientid %.*s already in use by %pISpc, client %08x:%08x", - __entry->namelen, __get_str(name), __entry->addr, - __entry->cl_boot, __entry->cl_id) -) - /* * from fs/nfsd/filecache.h */ From 7e3b32ace6094aadfa2e1e54ca4c6bbfd07646af Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:55:48 -0400 Subject: [PATCH 06/69] NFSD: Add nfsd_clid_confirmed tracepoint This replaces a dprintk call site in order to get greater visibility on when client IDs are confirmed or re-used. Simple example: nfsd-995 [000] 126.622975: nfsd_compound: xid=0x3a34e2b1 opcnt=1 nfsd-995 [000] 126.623005: nfsd_cb_args: addr=192.168.2.51:45901 client 60958e3b:9213ef0e prog=1073741824 ident=1 nfsd-995 [000] 126.623007: nfsd_compound_status: op=1/1 OP_SETCLIENTID status=0 nfsd-996 [001] 126.623142: nfsd_compound: xid=0x3b34e2b1 opcnt=1 >>>> nfsd-996 [001] 126.623146: nfsd_clid_confirmed: client 60958e3b:9213ef0e nfsd-996 [001] 126.623148: nfsd_cb_probe: addr=192.168.2.51:45901 client 60958e3b:9213ef0e state=UNKNOWN nfsd-996 [001] 126.623154: nfsd_compound_status: op=1/1 OP_SETCLIENTID_CONFIRM status=0 Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 10 +++++----- fs/nfsd/trace.h | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 69405cc9d823..37cef1f498e1 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2816,14 +2816,14 @@ move_to_confirmed(struct nfs4_client *clp) lockdep_assert_held(&nn->client_lock); - dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); add_clp_to_name_tree(clp, &nn->conf_name_tree); - if (!test_and_set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags) && - clp->cl_nfsd_dentry && - clp->cl_nfsd_info_dentry) - fsnotify_dentry(clp->cl_nfsd_info_dentry, FS_MODIFY); + if (!test_and_set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) { + trace_nfsd_clid_confirmed(&clp->cl_clientid); + if (clp->cl_nfsd_dentry && clp->cl_nfsd_info_dentry) + fsnotify_dentry(clp->cl_nfsd_info_dentry, FS_MODIFY); + } renew_client_locked(clp); } diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 1265d6f058ee..c3d47fd68ff5 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -511,6 +511,7 @@ DEFINE_EVENT(nfsd_clientid_class, nfsd_clid_##name, \ TP_PROTO(const clientid_t *clid), \ TP_ARGS(clid)) +DEFINE_CLIENTID_EVENT(confirmed); DEFINE_CLIENTID_EVENT(expired); DEFINE_CLIENTID_EVENT(purged); DEFINE_CLIENTID_EVENT(renew); From cee8aa074281e5269d8404be2b6388bb29ea8efc Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:55:54 -0400 Subject: [PATCH 07/69] NFSD: Add nfsd_clid_reclaim_complete tracepoint Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 1 + fs/nfsd/trace.h | 1 + 2 files changed, 2 insertions(+) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 37cef1f498e1..03f2770c815f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3949,6 +3949,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, goto out; status = nfs_ok; + trace_nfsd_clid_reclaim_complete(&clp->cl_clientid); nfsd4_client_record_create(clp); inc_reclaim_complete(clp); out: diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index c3d47fd68ff5..18be3fbb96ea 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -511,6 +511,7 @@ DEFINE_EVENT(nfsd_clientid_class, nfsd_clid_##name, \ TP_PROTO(const clientid_t *clid), \ TP_ARGS(clid)) +DEFINE_CLIENTID_EVENT(reclaim_complete); DEFINE_CLIENTID_EVENT(confirmed); DEFINE_CLIENTID_EVENT(expired); DEFINE_CLIENTID_EVENT(purged); From c41a9b7a906fb872f8b2b1a34d2a1d5ef7f94adb Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:56:00 -0400 Subject: [PATCH 08/69] NFSD: Add nfsd_clid_destroyed tracepoint Record client-requested termination of client IDs. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 1 + fs/nfsd/trace.h | 1 + 2 files changed, 2 insertions(+) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 03f2770c815f..08ff643e96fb 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3907,6 +3907,7 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, status = nfserr_wrong_cred; goto out; } + trace_nfsd_clid_destroyed(&clp->cl_clientid); unhash_client_locked(clp); out: spin_unlock(&nn->client_lock); diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 18be3fbb96ea..d6ba6a1a1e63 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -513,6 +513,7 @@ DEFINE_EVENT(nfsd_clientid_class, nfsd_clid_##name, \ DEFINE_CLIENTID_EVENT(reclaim_complete); DEFINE_CLIENTID_EVENT(confirmed); +DEFINE_CLIENTID_EVENT(destroyed); DEFINE_CLIENTID_EVENT(expired); DEFINE_CLIENTID_EVENT(purged); DEFINE_CLIENTID_EVENT(renew); From 2958d2ee71021b6c44212ec6c2a39cc71d9cd4a9 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:56:06 -0400 Subject: [PATCH 09/69] NFSD: Add a couple more nfsd_clid_expired call sites Improve observation of NFSv4 lease expiry. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 9 ++++++--- fs/nfsd/trace.h | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 08ff643e96fb..2e7bbaa92684 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2665,6 +2665,8 @@ static void force_expire_client(struct nfs4_client *clp) struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); bool already_expired; + trace_nfsd_clid_admin_expired(&clp->cl_clientid); + spin_lock(&clp->cl_lock); clp->cl_time = 0; spin_unlock(&clp->cl_lock); @@ -3211,6 +3213,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = mark_client_expired_locked(conf); if (status) goto out; + trace_nfsd_clid_replaced(&conf->cl_clientid); } new->cl_minorversion = cstate->minorversion; new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0]; @@ -3450,6 +3453,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, old = NULL; goto out_free_conn; } + trace_nfsd_clid_replaced(&old->cl_clientid); } move_to_confirmed(unconf); conf = unconf; @@ -4078,6 +4082,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, old = NULL; goto out; } + trace_nfsd_clid_replaced(&old->cl_clientid); } move_to_confirmed(unconf); conf = unconf; @@ -5508,10 +5513,8 @@ nfs4_laundromat(struct nfsd_net *nn) clp = list_entry(pos, struct nfs4_client, cl_lru); if (!state_expired(<, clp->cl_time)) break; - if (mark_client_expired_locked(clp)) { - trace_nfsd_clid_expired(&clp->cl_clientid); + if (mark_client_expired_locked(clp)) continue; - } list_add(&clp->cl_lru, &reaplist); } spin_unlock(&nn->client_lock); diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index d6ba6a1a1e63..ac96416b4b33 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -514,7 +514,8 @@ DEFINE_EVENT(nfsd_clientid_class, nfsd_clid_##name, \ DEFINE_CLIENTID_EVENT(reclaim_complete); DEFINE_CLIENTID_EVENT(confirmed); DEFINE_CLIENTID_EVENT(destroyed); -DEFINE_CLIENTID_EVENT(expired); +DEFINE_CLIENTID_EVENT(admin_expired); +DEFINE_CLIENTID_EVENT(replaced); DEFINE_CLIENTID_EVENT(purged); DEFINE_CLIENTID_EVENT(renew); DEFINE_CLIENTID_EVENT(stale); From 237f91c85acef206a33bc02f3c4e856128fd7994 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:56:13 -0400 Subject: [PATCH 10/69] NFSD: Add tracepoints for SETCLIENTID edge cases Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 19 ++++++++----------- fs/nfsd/trace.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 2e7bbaa92684..b6da4abd42a0 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3976,11 +3976,9 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, new = create_client(clname, rqstp, &clverifier); if (new == NULL) return nfserr_jukebox; - /* Cases below refer to rfc 3530 section 14.2.33: */ spin_lock(&nn->client_lock); conf = find_confirmed_client_by_name(&clname, nn); if (conf && client_has_state(conf)) { - /* case 0: */ status = nfserr_clid_inuse; if (clp_used_exchangeid(conf)) goto out; @@ -3992,7 +3990,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, unconf = find_unconfirmed_client_by_name(&clname, nn); if (unconf) unhash_client_locked(unconf); - /* We need to handle only case 1: probable callback update */ if (conf) { if (same_verf(&conf->cl_verifier, &clverifier)) { copy_clid(new, conf); @@ -4000,7 +3997,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, } else trace_nfsd_clid_verf_mismatch(conf, rqstp, &clverifier); - } + } else + trace_nfsd_clid_fresh(new); new->cl_minorversion = 0; gen_callback(new, setclid, rqstp); add_to_unconfirmed(new); @@ -4013,12 +4011,13 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, spin_unlock(&nn->client_lock); if (new) free_client(new); - if (unconf) + if (unconf) { + trace_nfsd_clid_expire_unconf(&unconf->cl_clientid); expire_client(unconf); + } return status; } - __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, @@ -4055,21 +4054,19 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, trace_nfsd_clid_cred_mismatch(conf, rqstp); goto out; } - /* cases below refer to rfc 3530 section 14.2.34: */ if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { if (conf && same_verf(&confirm, &conf->cl_confirm)) { - /* case 2: probable retransmit */ status = nfs_ok; - } else /* case 4: client hasn't noticed we rebooted yet? */ + } else status = nfserr_stale_clientid; goto out; } status = nfs_ok; - if (conf) { /* case 1: callback update */ + if (conf) { old = unconf; unhash_client_locked(old); nfsd4_change_callback(conf, &unconf->cl_cb_conn); - } else { /* case 3: normal case; new or rebooted client */ + } else { old = find_confirmed_client_by_name(&unconf->cl_name, nn); if (old) { status = nfserr_clid_inuse; diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index ac96416b4b33..33fba6dbdc4a 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -511,6 +511,7 @@ DEFINE_EVENT(nfsd_clientid_class, nfsd_clid_##name, \ TP_PROTO(const clientid_t *clid), \ TP_ARGS(clid)) +DEFINE_CLIENTID_EVENT(expire_unconf); DEFINE_CLIENTID_EVENT(reclaim_complete); DEFINE_CLIENTID_EVENT(confirmed); DEFINE_CLIENTID_EVENT(destroyed); @@ -600,6 +601,42 @@ TRACE_EVENT(nfsd_clid_verf_mismatch, ) ); +DECLARE_EVENT_CLASS(nfsd_clid_class, + TP_PROTO(const struct nfs4_client *clp), + TP_ARGS(clp), + TP_STRUCT__entry( + __field(u32, cl_boot) + __field(u32, cl_id) + __array(unsigned char, addr, sizeof(struct sockaddr_in6)) + __field(unsigned long, flavor) + __array(unsigned char, verifier, NFS4_VERIFIER_SIZE) + __dynamic_array(char, name, clp->cl_name.len + 1) + ), + TP_fast_assign( + __entry->cl_boot = clp->cl_clientid.cl_boot; + __entry->cl_id = clp->cl_clientid.cl_id; + memcpy(__entry->addr, &clp->cl_addr, + sizeof(struct sockaddr_in6)); + __entry->flavor = clp->cl_cred.cr_flavor; + memcpy(__entry->verifier, (void *)&clp->cl_verifier, + NFS4_VERIFIER_SIZE); + memcpy(__get_str(name), clp->cl_name.data, clp->cl_name.len); + __get_str(name)[clp->cl_name.len] = '\0'; + ), + TP_printk("addr=%pISpc name='%s' verifier=0x%s flavor=%s client=%08x:%08x", + __entry->addr, __get_str(name), + __print_hex_str(__entry->verifier, NFS4_VERIFIER_SIZE), + show_nfsd_authflavor(__entry->flavor), + __entry->cl_boot, __entry->cl_id) +); + +#define DEFINE_CLID_EVENT(name) \ +DEFINE_EVENT(nfsd_clid_class, nfsd_clid_##name, \ + TP_PROTO(const struct nfs4_client *clp), \ + TP_ARGS(clp)) + +DEFINE_CLID_EVENT(fresh); + /* * from fs/nfsd/filecache.h */ From e8f80c5545ec5794644b48537449e48b009d608d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:56:19 -0400 Subject: [PATCH 11/69] NFSD: Add tracepoints for EXCHANGEID edge cases Some of the most common cases are traced. Enough infrastructure is now in place that more can be added later, as needed. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 12 +++++++++--- fs/nfsd/trace.h | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b6da4abd42a0..aa645aeee7b6 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3178,6 +3178,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, } /* case 6 */ exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; + trace_nfsd_clid_confirmed_r(conf); goto out_copy; } if (!creds_match) { /* case 3 */ @@ -3190,6 +3191,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, } if (verfs_match) { /* case 2 */ conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; + trace_nfsd_clid_confirmed_r(conf); goto out_copy; } /* case 5, client reboot */ @@ -3203,11 +3205,13 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; } - unconf = find_unconfirmed_client_by_name(&exid->clname, nn); + unconf = find_unconfirmed_client_by_name(&exid->clname, nn); if (unconf) /* case 4, possible retry or client restart */ unhash_client_locked(unconf); - /* case 1 (normal case) */ + /* case 1, new owner ID */ + trace_nfsd_clid_fresh(new); + out_new: if (conf) { status = mark_client_expired_locked(conf); @@ -3237,8 +3241,10 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, out_nolock: if (new) expire_client(new); - if (unconf) + if (unconf) { + trace_nfsd_clid_expire_unconf(&unconf->cl_clientid); expire_client(unconf); + } return status; } diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 33fba6dbdc4a..39b7caea4664 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -636,6 +636,7 @@ DEFINE_EVENT(nfsd_clid_class, nfsd_clid_##name, \ TP_ARGS(clp)) DEFINE_CLID_EVENT(fresh); +DEFINE_CLID_EVENT(confirmed_r); /* * from fs/nfsd/filecache.h From 1736aec82a15cb5d4b3bbe0b2fbae0ede66b1a1a Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:56:25 -0400 Subject: [PATCH 12/69] NFSD: Constify @fh argument of knfsd_fh_hash() Enable knfsd_fh_hash() to be invoked in functions where the filehandle pointer is a const. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsfh.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index aff2cda5c6c3..6106697adc04 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -225,15 +225,12 @@ static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) * returns a crc32 hash for the filehandle that is compatible with * the one displayed by "wireshark". */ - -static inline u32 -knfsd_fh_hash(struct knfsd_fh *fh) +static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) { return ~crc32_le(0xFFFFFFFF, (unsigned char *)&fh->fh_base, fh->fh_size); } #else -static inline u32 -knfsd_fh_hash(struct knfsd_fh *fh) +static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) { return 0; } From 8476c69a7fa0f1f9705ec0caa4e97c08b5045779 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:56:31 -0400 Subject: [PATCH 13/69] NFSD: Capture every CB state transition We were missing one. As a clean-up, add a helper that sets the new CB state and fires a tracepoint. The tracepoint fires only when the state changes, to help reduce trace log noise. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 7325592b456e..b6cc51a9f37c 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -945,20 +945,26 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c return 0; } +static void nfsd4_mark_cb_state(struct nfs4_client *clp, int newstate) +{ + if (clp->cl_cb_state != newstate) { + clp->cl_cb_state = newstate; + trace_nfsd_cb_state(clp); + } +} + static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason) { if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags)) return; - clp->cl_cb_state = NFSD4_CB_DOWN; - trace_nfsd_cb_state(clp); + nfsd4_mark_cb_state(clp, NFSD4_CB_DOWN); } static void nfsd4_mark_cb_fault(struct nfs4_client *clp, int reason) { if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags)) return; - clp->cl_cb_state = NFSD4_CB_FAULT; - trace_nfsd_cb_state(clp); + nfsd4_mark_cb_state(clp, NFSD4_CB_FAULT); } static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) @@ -968,10 +974,8 @@ static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) trace_nfsd_cb_done(clp, task->tk_status); if (task->tk_status) nfsd4_mark_cb_down(clp, task->tk_status); - else { - clp->cl_cb_state = NFSD4_CB_UP; - trace_nfsd_cb_state(clp); - } + else + nfsd4_mark_cb_state(clp, NFSD4_CB_UP); } static void nfsd4_cb_probe_release(void *calldata) @@ -995,8 +999,7 @@ static const struct rpc_call_ops nfsd4_cb_probe_ops = { */ void nfsd4_probe_callback(struct nfs4_client *clp) { - clp->cl_cb_state = NFSD4_CB_UNKNOWN; - trace_nfsd_cb_state(clp); + nfsd4_mark_cb_state(clp, NFSD4_CB_UNKNOWN); set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags); nfsd4_run_cb(&clp->cl_cb_null); } @@ -1009,11 +1012,10 @@ void nfsd4_probe_callback_sync(struct nfs4_client *clp) void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn) { - clp->cl_cb_state = NFSD4_CB_UNKNOWN; + nfsd4_mark_cb_state(clp, NFSD4_CB_UNKNOWN); spin_lock(&clp->cl_lock); memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn)); spin_unlock(&clp->cl_lock); - trace_nfsd_cb_state(clp); } /* @@ -1345,7 +1347,7 @@ nfsd4_run_cb_work(struct work_struct *work) * Don't send probe messages for 4.1 or later. */ if (!cb->cb_ops && clp->cl_minorversion) { - clp->cl_cb_state = NFSD4_CB_UP; + nfsd4_mark_cb_state(clp, NFSD4_CB_UP); nfsd41_destroy_cb(cb); return; } From 167145cc64ce4b4b177e636829909a6b14004f9e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:56:37 -0400 Subject: [PATCH 14/69] NFSD: Drop TRACE_DEFINE_ENUM for NFSD4_CB_ macros TRACE_DEFINE_ENUM() is necessary for enum {} but not for C macros. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/trace.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 39b7caea4664..1c43e6647d1e 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -877,11 +877,6 @@ TRACE_EVENT(nfsd_cb_nodelegs, TP_printk("client %08x:%08x", __entry->cl_boot, __entry->cl_id) ) -TRACE_DEFINE_ENUM(NFSD4_CB_UP); -TRACE_DEFINE_ENUM(NFSD4_CB_UNKNOWN); -TRACE_DEFINE_ENUM(NFSD4_CB_DOWN); -TRACE_DEFINE_ENUM(NFSD4_CB_FAULT); - #define show_cb_state(val) \ __print_symbolic(val, \ { NFSD4_CB_UP, "UP" }, \ From 806d65b617d89be887fe68bfa051f78143669cd7 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:56:43 -0400 Subject: [PATCH 15/69] NFSD: Add cb_lost tracepoint Provide more clarity about when the callback channel is in trouble. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 2 ++ fs/nfsd/trace.h | 1 + 2 files changed, 3 insertions(+) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index aa645aeee7b6..377ec4a6a771 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1745,6 +1745,8 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u) struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); struct nfs4_client *clp = c->cn_session->se_client; + trace_nfsd_cb_lost(clp); + spin_lock(&clp->cl_lock); if (!list_empty(&c->cn_persession)) { list_del(&c->cn_persession); diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 1c43e6647d1e..336dc4c45416 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -912,6 +912,7 @@ DEFINE_EVENT(nfsd_cb_class, nfsd_cb_##name, \ DEFINE_NFSD_CB_EVENT(setup); DEFINE_NFSD_CB_EVENT(state); +DEFINE_NFSD_CB_EVENT(lost); DEFINE_NFSD_CB_EVENT(shutdown); TRACE_DEFINE_ENUM(RPC_AUTH_NULL); From b200f0e35338b052976b6c5759e4f77a3013e6f6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:56:49 -0400 Subject: [PATCH 16/69] NFSD: Adjust cb_shutdown tracepoint Show when the upper layer requested a shutdown. RPC tracepoints can already show when rpc_shutdown_client() is called. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index b6cc51a9f37c..ab1836381e22 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -1233,6 +1233,9 @@ void nfsd4_destroy_callback_queue(void) /* must be called under the state lock */ void nfsd4_shutdown_callback(struct nfs4_client *clp) { + if (clp->cl_cb_state != NFSD4_CB_UNKNOWN) + trace_nfsd_cb_shutdown(clp); + set_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags); /* * Note this won't actually result in a null callback; @@ -1278,7 +1281,6 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) * kill the old client: */ if (clp->cl_cb_client) { - trace_nfsd_cb_shutdown(clp); rpc_shutdown_client(clp->cl_cb_client); clp->cl_cb_client = NULL; put_cred(clp->cl_cb_cred); From 9f57c6062bf3ce2c6ab9ba60040b34e8134ef259 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:56:56 -0400 Subject: [PATCH 17/69] NFSD: Remove spurious cb_setup_err tracepoint This path is not really an error path, so the tracepoint I added there is just noise. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index ab1836381e22..15ba16c54793 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -915,10 +915,8 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c args.authflavor = clp->cl_cred.cr_flavor; clp->cl_cb_ident = conn->cb_ident; } else { - if (!conn->cb_xprt) { - trace_nfsd_cb_setup_err(clp, -EINVAL); + if (!conn->cb_xprt) return -EINVAL; - } clp->cl_cb_conn.cb_xprt = conn->cb_xprt; clp->cl_cb_session = ses; args.bc_xprt = conn->cb_xprt; From 3c92fba557c622a53fc166b76dede92863354da1 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:57:02 -0400 Subject: [PATCH 18/69] NFSD: Enhance the nfsd_cb_setup tracepoint Display the transport protocol and authentication flavor so admins can see what they might be getting wrong. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 3 ++- fs/nfsd/trace.h | 27 ++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 15ba16c54793..c2a2a58b3581 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -939,7 +939,8 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c } clp->cl_cb_client = client; clp->cl_cb_cred = cred; - trace_nfsd_cb_setup(clp); + trace_nfsd_cb_setup(clp, rpc_peeraddr2str(client, RPC_DISPLAY_NETID), + args.authflavor); return 0; } diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 336dc4c45416..fc80879d6077 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -910,7 +910,6 @@ DEFINE_EVENT(nfsd_cb_class, nfsd_cb_##name, \ TP_PROTO(const struct nfs4_client *clp), \ TP_ARGS(clp)) -DEFINE_NFSD_CB_EVENT(setup); DEFINE_NFSD_CB_EVENT(state); DEFINE_NFSD_CB_EVENT(lost); DEFINE_NFSD_CB_EVENT(shutdown); @@ -931,6 +930,32 @@ TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5P); { RPC_AUTH_GSS_KRB5I, "krb5i" }, \ { RPC_AUTH_GSS_KRB5P, "krb5p" }) +TRACE_EVENT(nfsd_cb_setup, + TP_PROTO(const struct nfs4_client *clp, + const char *netid, + rpc_authflavor_t authflavor + ), + TP_ARGS(clp, netid, authflavor), + TP_STRUCT__entry( + __field(u32, cl_boot) + __field(u32, cl_id) + __field(unsigned long, authflavor) + __array(unsigned char, addr, sizeof(struct sockaddr_in6)) + __array(unsigned char, netid, 8) + ), + TP_fast_assign( + __entry->cl_boot = clp->cl_clientid.cl_boot; + __entry->cl_id = clp->cl_clientid.cl_id; + strlcpy(__entry->netid, netid, sizeof(__entry->netid)); + __entry->authflavor = authflavor; + memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, + sizeof(struct sockaddr_in6)); + ), + TP_printk("addr=%pISpc client %08x:%08x proto=%s flavor=%s", + __entry->addr, __entry->cl_boot, __entry->cl_id, + __entry->netid, show_nfsd_authflavor(__entry->authflavor)) +); + TRACE_EVENT(nfsd_cb_setup_err, TP_PROTO( const struct nfs4_client *clp, From 2cde7f8118f0fea29ad73ddcf28817f95adeffd5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:57:08 -0400 Subject: [PATCH 19/69] NFSD: Add an nfsd_cb_lm_notify tracepoint When the server kicks off a CB_LM_NOTIFY callback, record its arguments so we can better observe asynchronous locking behavior. For example: nfsd-998 [002] 1471.705873: nfsd_cb_notify_lock: addr=192.168.2.51:0 client 6092a47c:35a43fc1 fh_hash=0x8950b23a Signed-off-by: Chuck Lever Cc: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 4 +++- fs/nfsd/trace.h | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 377ec4a6a771..d4eee8a47ff3 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -6451,8 +6451,10 @@ nfsd4_lm_notify(struct file_lock *fl) } spin_unlock(&nn->blocked_locks_lock); - if (queue) + if (queue) { + trace_nfsd_cb_notify_lock(lo, nbl); nfsd4_run_cb(&nbl->nbl_cb); + } } static const struct lock_manager_operations nfsd_posix_mng_ops = { diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index fc80879d6077..921323f88322 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -1027,6 +1027,32 @@ TRACE_EVENT(nfsd_cb_done, __entry->status) ); +TRACE_EVENT(nfsd_cb_notify_lock, + TP_PROTO( + const struct nfs4_lockowner *lo, + const struct nfsd4_blocked_lock *nbl + ), + TP_ARGS(lo, nbl), + TP_STRUCT__entry( + __field(u32, cl_boot) + __field(u32, cl_id) + __field(u32, fh_hash) + __array(unsigned char, addr, sizeof(struct sockaddr_in6)) + ), + TP_fast_assign( + const struct nfs4_client *clp = lo->lo_owner.so_client; + + __entry->cl_boot = clp->cl_clientid.cl_boot; + __entry->cl_id = clp->cl_clientid.cl_id; + __entry->fh_hash = knfsd_fh_hash(&nbl->nbl_fh); + memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, + sizeof(struct sockaddr_in6)); + ), + TP_printk("addr=%pISpc client %08x:%08x fh_hash=0x%08x", + __entry->addr, __entry->cl_boot, __entry->cl_id, + __entry->fh_hash) +); + #endif /* _NFSD_TRACE_H */ #undef TRACE_INCLUDE_PATH From 87512386e951ee28ba2e7ef32b843ac97621d371 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:57:14 -0400 Subject: [PATCH 20/69] NFSD: Add an nfsd_cb_offload tracepoint Record the arguments of CB_OFFLOAD callbacks so we can better observe asynchronous copy-offload behavior. For example: nfsd-995 [008] 7721.934222: nfsd_cb_offload: addr=192.168.2.51:0 client 6092a47c:35a43fc1 fh_hash=0x8739113a count=116528 status=0 Signed-off-by: Chuck Lever Cc: Olga Kornievskaia Cc: Dai Ngo Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 2 ++ fs/nfsd/trace.h | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index f4ce93d7f26e..426b232ca9fd 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1497,6 +1497,8 @@ static int nfsd4_do_async_copy(void *data) memcpy(&cb_copy->fh, ©->fh, sizeof(copy->fh)); nfsd4_init_cb(&cb_copy->cp_cb, cb_copy->cp_clp, &nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD); + trace_nfsd_cb_offload(copy->cp_clp, ©->cp_res.cb_stateid, + ©->fh, copy->cp_count, copy->nfserr); nfsd4_run_cb(&cb_copy->cp_cb); out: if (!copy->cp_intra) diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 921323f88322..1fb56433043d 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -1053,6 +1053,42 @@ TRACE_EVENT(nfsd_cb_notify_lock, __entry->fh_hash) ); +TRACE_EVENT(nfsd_cb_offload, + TP_PROTO( + const struct nfs4_client *clp, + const stateid_t *stp, + const struct knfsd_fh *fh, + u64 count, + __be32 status + ), + TP_ARGS(clp, stp, fh, count, status), + TP_STRUCT__entry( + __field(u32, cl_boot) + __field(u32, cl_id) + __field(u32, si_id) + __field(u32, si_generation) + __field(u32, fh_hash) + __field(int, status) + __field(u64, count) + __array(unsigned char, addr, sizeof(struct sockaddr_in6)) + ), + TP_fast_assign( + __entry->cl_boot = stp->si_opaque.so_clid.cl_boot; + __entry->cl_id = stp->si_opaque.so_clid.cl_id; + __entry->si_id = stp->si_opaque.so_id; + __entry->si_generation = stp->si_generation; + __entry->fh_hash = knfsd_fh_hash(fh); + __entry->status = be32_to_cpu(status); + __entry->count = count; + memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, + sizeof(struct sockaddr_in6)); + ), + TP_printk("addr=%pISpc client %08x:%08x stateid %08x:%08x fh_hash=0x%08x count=%llu status=%d", + __entry->addr, __entry->cl_boot, __entry->cl_id, + __entry->si_id, __entry->si_generation, + __entry->fh_hash, __entry->count, __entry->status) +); + #endif /* _NFSD_TRACE_H */ #undef TRACE_INCLUDE_PATH From 17d76ddf76e4972411402743eea7243d9a46f4f9 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:57:20 -0400 Subject: [PATCH 21/69] NFSD: Replace the nfsd_deleg_break tracepoint Renamed so it can be enabled as a set with the other nfsd_cb_ tracepoints. And, consistent with those tracepoints, report the address of the client, the client ID the server has given it, and the state ID being recalled. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 2 +- fs/nfsd/trace.h | 32 +++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index d4eee8a47ff3..b2573d3ecd3c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4641,7 +4641,7 @@ nfsd_break_deleg_cb(struct file_lock *fl) struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; struct nfs4_file *fp = dp->dl_stid.sc_file; - trace_nfsd_deleg_break(&dp->dl_stid.sc_stateid); + trace_nfsd_cb_recall(&dp->dl_stid); /* * We don't want the locks code to timeout the lease for us; diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 1fb56433043d..b7ede12f0ab1 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -459,7 +459,6 @@ DEFINE_STATEID_EVENT(layout_recall_release); DEFINE_STATEID_EVENT(open); DEFINE_STATEID_EVENT(deleg_read); -DEFINE_STATEID_EVENT(deleg_break); DEFINE_STATEID_EVENT(deleg_recall); DECLARE_EVENT_CLASS(nfsd_stateseqid_class, @@ -1027,6 +1026,37 @@ TRACE_EVENT(nfsd_cb_done, __entry->status) ); +TRACE_EVENT(nfsd_cb_recall, + TP_PROTO( + const struct nfs4_stid *stid + ), + TP_ARGS(stid), + TP_STRUCT__entry( + __field(u32, cl_boot) + __field(u32, cl_id) + __field(u32, si_id) + __field(u32, si_generation) + __array(unsigned char, addr, sizeof(struct sockaddr_in6)) + ), + TP_fast_assign( + const stateid_t *stp = &stid->sc_stateid; + const struct nfs4_client *clp = stid->sc_client; + + __entry->cl_boot = stp->si_opaque.so_clid.cl_boot; + __entry->cl_id = stp->si_opaque.so_clid.cl_id; + __entry->si_id = stp->si_opaque.so_id; + __entry->si_generation = stp->si_generation; + if (clp) + memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, + sizeof(struct sockaddr_in6)); + else + memset(__entry->addr, 0, sizeof(struct sockaddr_in6)); + ), + TP_printk("addr=%pISpc client %08x:%08x stateid %08x:%08x", + __entry->addr, __entry->cl_boot, __entry->cl_id, + __entry->si_id, __entry->si_generation) +); + TRACE_EVENT(nfsd_cb_notify_lock, TP_PROTO( const struct nfs4_lockowner *lo, From 4ade892ae1c35527584decb7fa026553d53cd03f Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:57:26 -0400 Subject: [PATCH 22/69] NFSD: Add an nfsd_cb_probe tracepoint Record a tracepoint event when the server performs a callback probe. This event can be enabled as a group with other nfsd_cb tracepoints. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 1 + fs/nfsd/trace.h | 1 + 2 files changed, 2 insertions(+) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index c2a2a58b3581..ddab969d7865 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -998,6 +998,7 @@ static const struct rpc_call_ops nfsd4_cb_probe_ops = { */ void nfsd4_probe_callback(struct nfs4_client *clp) { + trace_nfsd_cb_probe(clp); nfsd4_mark_cb_state(clp, NFSD4_CB_UNKNOWN); set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags); nfsd4_run_cb(&clp->cl_cb_null); diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index b7ede12f0ab1..2cdcf53a2c41 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -910,6 +910,7 @@ DEFINE_EVENT(nfsd_cb_class, nfsd_cb_##name, \ TP_ARGS(clp)) DEFINE_NFSD_CB_EVENT(state); +DEFINE_NFSD_CB_EVENT(probe); DEFINE_NFSD_CB_EVENT(lost); DEFINE_NFSD_CB_EVENT(shutdown); From 1d2bf65983a137121c165a7e69b2885572954915 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:57:32 -0400 Subject: [PATCH 23/69] NFSD: Remove the nfsd_cb_work and nfsd_cb_done tracepoints Clean up: These are noise in properly working systems. If you really need to observe the operation of the callback mechanism, use the sunrpc:rpc\* tracepoints along with the workqueue tracepoints. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 5 ----- fs/nfsd/trace.h | 48 ------------------------------------------ 2 files changed, 53 deletions(-) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index ddab969d7865..84401ca04705 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -970,7 +970,6 @@ static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) { struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null); - trace_nfsd_cb_done(clp, task->tk_status); if (task->tk_status) nfsd4_mark_cb_down(clp, task->tk_status); else @@ -1172,8 +1171,6 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) struct nfsd4_callback *cb = calldata; struct nfs4_client *clp = cb->cb_clp; - trace_nfsd_cb_done(clp, task->tk_status); - if (!nfsd4_cb_sequence_done(task, cb)) return; @@ -1326,8 +1323,6 @@ nfsd4_run_cb_work(struct work_struct *work) struct rpc_clnt *clnt; int flags; - trace_nfsd_cb_work(clp, cb->cb_msg.rpc_proc->p_name); - if (cb->cb_need_restart) { cb->cb_need_restart = false; } else { diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 2cdcf53a2c41..daadcb54886d 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -979,54 +979,6 @@ TRACE_EVENT(nfsd_cb_setup_err, __entry->addr, __entry->cl_boot, __entry->cl_id, __entry->error) ); -TRACE_EVENT(nfsd_cb_work, - TP_PROTO( - const struct nfs4_client *clp, - const char *procedure - ), - TP_ARGS(clp, procedure), - TP_STRUCT__entry( - __field(u32, cl_boot) - __field(u32, cl_id) - __string(procedure, procedure) - __array(unsigned char, addr, sizeof(struct sockaddr_in6)) - ), - TP_fast_assign( - __entry->cl_boot = clp->cl_clientid.cl_boot; - __entry->cl_id = clp->cl_clientid.cl_id; - __assign_str(procedure, procedure) - memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, - sizeof(struct sockaddr_in6)); - ), - TP_printk("addr=%pISpc client %08x:%08x procedure=%s", - __entry->addr, __entry->cl_boot, __entry->cl_id, - __get_str(procedure)) -); - -TRACE_EVENT(nfsd_cb_done, - TP_PROTO( - const struct nfs4_client *clp, - int status - ), - TP_ARGS(clp, status), - TP_STRUCT__entry( - __field(u32, cl_boot) - __field(u32, cl_id) - __field(int, status) - __array(unsigned char, addr, sizeof(struct sockaddr_in6)) - ), - TP_fast_assign( - __entry->cl_boot = clp->cl_clientid.cl_boot; - __entry->cl_id = clp->cl_clientid.cl_id; - __entry->status = status; - memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, - sizeof(struct sockaddr_in6)); - ), - TP_printk("addr=%pISpc client %08x:%08x status=%d", - __entry->addr, __entry->cl_boot, __entry->cl_id, - __entry->status) -); - TRACE_EVENT(nfsd_cb_recall, TP_PROTO( const struct nfs4_stid *stid From d6cbe98ff32aef795462a309ef048cfb89d1a11d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 14 May 2021 15:57:39 -0400 Subject: [PATCH 24/69] NFSD: Update nfsd_cb_args tracepoint Clean-up: Re-order the display of IP address and client ID to be consistent with other _cb_ tracepoints. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/trace.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index daadcb54886d..10cc3aaf1089 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -857,9 +857,9 @@ TRACE_EVENT(nfsd_cb_args, memcpy(__entry->addr, &conn->cb_addr, sizeof(struct sockaddr_in6)); ), - TP_printk("client %08x:%08x callback addr=%pISpc prog=%u ident=%u", - __entry->cl_boot, __entry->cl_id, - __entry->addr, __entry->prog, __entry->ident) + TP_printk("addr=%pISpc client %08x:%08x prog=%u ident=%u", + __entry->addr, __entry->cl_boot, __entry->cl_id, + __entry->prog, __entry->ident) ); TRACE_EVENT(nfsd_cb_nodelegs, From e5d74a2d0ee67ae00edad43c3d7811016e4d2e21 Mon Sep 17 00:00:00 2001 From: Yu Hsiang Huang Date: Fri, 14 May 2021 11:58:29 +0800 Subject: [PATCH 25/69] nfsd: Prevent truncation of an unlinked inode from blocking access to its directory Truncation of an unlinked inode may take a long time for I/O waiting, and it doesn't have to prevent access to the directory. Thus, let truncation occur outside the directory's mutex, just like do_unlinkat() does. Signed-off-by: Yu Hsiang Huang Signed-off-by: Bing Jing Chang Signed-off-by: Robbie Ko Signed-off-by: J. Bruce Fields --- fs/nfsd/vfs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 15adf1f6ab21..39948f130712 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1859,6 +1859,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, { struct dentry *dentry, *rdentry; struct inode *dirp; + struct inode *rinode; __be32 err; int host_err; @@ -1887,6 +1888,8 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, host_err = -ENOENT; goto out_drop_write; } + rinode = d_inode(rdentry); + ihold(rinode); if (!type) type = d_inode(rdentry)->i_mode & S_IFMT; @@ -1902,6 +1905,8 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, if (!host_err) host_err = commit_metadata(fhp); dput(rdentry); + fh_unlock(fhp); + iput(rinode); /* truncate the inode here */ out_drop_write: fh_drop_write(fhp); From eeeadbb9bd5652c47bb9b31aa9ad8b4f1b4aa8b3 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 14 May 2021 18:21:37 -0400 Subject: [PATCH 26/69] nfsd: move some commit_metadata()s outside the inode lock The commit may be time-consuming and there's no need to hold the lock for it. More of these are possible, these were just some easy ones. Signed-off-by: J. Bruce Fields --- fs/nfsd/vfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 39948f130712..d73d3c9126fc 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1613,9 +1613,9 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, host_err = vfs_symlink(&init_user_ns, d_inode(dentry), dnew, path); err = nfserrno(host_err); + fh_unlock(fhp); if (!err) err = nfserrno(commit_metadata(fhp)); - fh_unlock(fhp); fh_drop_write(fhp); @@ -1680,6 +1680,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, if (d_really_is_negative(dold)) goto out_dput; host_err = vfs_link(dold, &init_user_ns, dirp, dnew, NULL); + fh_unlock(ffhp); if (!host_err) { err = nfserrno(commit_metadata(ffhp)); if (!err) @@ -1902,10 +1903,10 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, host_err = vfs_rmdir(&init_user_ns, dirp, rdentry); } + fh_unlock(fhp); if (!host_err) host_err = commit_metadata(fhp); dput(rdentry); - fh_unlock(fhp); iput(rinode); /* truncate the inode here */ out_drop_write: From eac0b17a77fbd763d305a5eaa4fd1119e5a0fe0d Mon Sep 17 00:00:00 2001 From: Olga Kornievskaia Date: Wed, 19 May 2021 14:48:27 -0400 Subject: [PATCH 27/69] NFSD add vfs_fsync after async copy is done Currently, the server does all copies as NFS_UNSTABLE. For synchronous copies linux client will append a COMMIT to the COPY compound but for async copies it does not (because COMMIT needs to be done after all bytes are copied and not as a reply to the COPY operation). However, in order to save the client doing a COMMIT as a separate rpc, the server can reply back with NFS_FILE_SYNC copy. This patch proposed to add vfs_fsync() call at the end of the async copy. Signed-off-by: Olga Kornievskaia Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 14 +++++++++++++- fs/nfsd/xdr4.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 426b232ca9fd..48c0992cb65c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1375,7 +1375,8 @@ static const struct nfsd4_callback_ops nfsd4_cb_offload_ops = { static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync) { - copy->cp_res.wr_stable_how = NFS_UNSTABLE; + copy->cp_res.wr_stable_how = + copy->committed ? NFS_FILE_SYNC : NFS_UNSTABLE; copy->cp_synchronous = sync; gen_boot_verifier(©->cp_res.wr_verifier, copy->cp_clp->net); } @@ -1386,6 +1387,7 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) u64 bytes_total = copy->cp_count; u64 src_pos = copy->cp_src_pos; u64 dst_pos = copy->cp_dst_pos; + __be32 status; /* See RFC 7862 p.67: */ if (bytes_total == 0) @@ -1403,6 +1405,16 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) src_pos += bytes_copied; dst_pos += bytes_copied; } while (bytes_total > 0 && !copy->cp_synchronous); + /* for a non-zero asynchronous copy do a commit of data */ + if (!copy->cp_synchronous && copy->cp_res.wr_bytes_written > 0) { + down_write(©->nf_dst->nf_rwsem); + status = vfs_fsync_range(copy->nf_dst->nf_file, + copy->cp_dst_pos, + copy->cp_res.wr_bytes_written, 0); + up_write(©->nf_dst->nf_rwsem); + if (!status) + copy->committed = true; + } return bytes_copied; } diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index a7c425254fee..3e4052e3bd50 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -567,6 +567,7 @@ struct nfsd4_copy { struct vfsmount *ss_mnt; struct nfs_fh c_fh; nfs4_stateid stateid; + bool committed; }; struct nfsd4_seek { From f4e44b393389c77958f7c58bf4415032b4cda15b Mon Sep 17 00:00:00 2001 From: Dai Ngo Date: Fri, 21 May 2021 15:09:37 -0400 Subject: [PATCH 28/69] NFSD: delay unmount source's export after inter-server copy completed. Currently the source's export is mounted and unmounted on every inter-server copy operation. This patch is an enhancement to delay the unmount of the source export for a certain period of time to eliminate the mount and unmount overhead on subsequent copy operations. After a copy operation completes, a work entry is added to the delayed unmount list with an expiration time. This list is serviced by the laundromat thread to unmount the export of the expired entries. Each time the export is being used again, its expiration time is extended and the entry is re-inserted to the tail of the list. The unmount task and the mount operation of the copy request are synced to make sure the export is not unmounted while it's being used. Signed-off-by: Dai Ngo Signed-off-by: J. Bruce Fields --- fs/nfsd/netns.h | 6 ++ fs/nfsd/nfs4proc.c | 135 ++++++++++++++++++++++++++++++++++++++-- fs/nfsd/nfs4state.c | 71 +++++++++++++++++++++ fs/nfsd/nfsd.h | 4 ++ fs/nfsd/nfssvc.c | 3 + include/linux/nfs_ssc.h | 14 +++++ 6 files changed, 229 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index a75abeb1e698..935c1028c217 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -176,6 +176,12 @@ struct nfsd_net { unsigned int longest_chain_cachesize; struct shrinker nfsd_reply_cache_shrinker; + + /* tracking server-to-server copy mounts */ + spinlock_t nfsd_ssc_lock; + struct list_head nfsd_ssc_mount_list; + wait_queue_head_t nfsd_ssc_waitq; + /* utsname taken from the process that starts the server */ char nfsd_name[UNX_MAXNODENAME+1]; }; diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 48c0992cb65c..0bd71c6da81d 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -55,6 +55,13 @@ module_param(inter_copy_offload_enable, bool, 0644); MODULE_PARM_DESC(inter_copy_offload_enable, "Enable inter server to server copy offload. Default: false"); +#ifdef CONFIG_NFSD_V4_2_INTER_SSC +static int nfsd4_ssc_umount_timeout = 900000; /* default to 15 mins */ +module_param(nfsd4_ssc_umount_timeout, int, 0644); +MODULE_PARM_DESC(nfsd4_ssc_umount_timeout, + "idle msecs before unmount export from source server"); +#endif + #ifdef CONFIG_NFSD_V4_SECURITY_LABEL #include @@ -1165,6 +1172,81 @@ extern void nfs_sb_deactive(struct super_block *sb); #define NFSD42_INTERSSC_MOUNTOPS "vers=4.2,addr=%s,sec=sys" +/* + * setup a work entry in the ssc delayed unmount list. + */ +static int nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, + struct nfsd4_ssc_umount_item **retwork, struct vfsmount **ss_mnt) +{ + struct nfsd4_ssc_umount_item *ni = 0; + struct nfsd4_ssc_umount_item *work = NULL; + struct nfsd4_ssc_umount_item *tmp; + DEFINE_WAIT(wait); + + *ss_mnt = NULL; + *retwork = NULL; + work = kzalloc(sizeof(*work), GFP_KERNEL); +try_again: + spin_lock(&nn->nfsd_ssc_lock); + list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { + if (strncmp(ni->nsui_ipaddr, ipaddr, sizeof(ni->nsui_ipaddr))) + continue; + /* found a match */ + if (ni->nsui_busy) { + /* wait - and try again */ + prepare_to_wait(&nn->nfsd_ssc_waitq, &wait, + TASK_INTERRUPTIBLE); + spin_unlock(&nn->nfsd_ssc_lock); + + /* allow 20secs for mount/unmount for now - revisit */ + if (signal_pending(current) || + (schedule_timeout(20*HZ) == 0)) { + kfree(work); + return nfserr_eagain; + } + finish_wait(&nn->nfsd_ssc_waitq, &wait); + goto try_again; + } + *ss_mnt = ni->nsui_vfsmount; + refcount_inc(&ni->nsui_refcnt); + spin_unlock(&nn->nfsd_ssc_lock); + kfree(work); + + /* return vfsmount in ss_mnt */ + return 0; + } + if (work) { + strncpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr)); + refcount_set(&work->nsui_refcnt, 2); + work->nsui_busy = true; + list_add_tail(&work->nsui_list, &nn->nfsd_ssc_mount_list); + *retwork = work; + } + spin_unlock(&nn->nfsd_ssc_lock); + return 0; +} + +static void nfsd4_ssc_update_dul_work(struct nfsd_net *nn, + struct nfsd4_ssc_umount_item *work, struct vfsmount *ss_mnt) +{ + /* set nsui_vfsmount, clear busy flag and wakeup waiters */ + spin_lock(&nn->nfsd_ssc_lock); + work->nsui_vfsmount = ss_mnt; + work->nsui_busy = false; + wake_up_all(&nn->nfsd_ssc_waitq); + spin_unlock(&nn->nfsd_ssc_lock); +} + +static void nfsd4_ssc_cancel_dul_work(struct nfsd_net *nn, + struct nfsd4_ssc_umount_item *work) +{ + spin_lock(&nn->nfsd_ssc_lock); + list_del(&work->nsui_list); + wake_up_all(&nn->nfsd_ssc_waitq); + spin_unlock(&nn->nfsd_ssc_lock); + kfree(work); +} + /* * Support one copy source server for now. */ @@ -1181,6 +1263,8 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, char *ipaddr, *dev_name, *raw_data; int len, raw_len; __be32 status = nfserr_inval; + struct nfsd4_ssc_umount_item *work = NULL; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); naddr = &nss->u.nl4_addr; tmp_addrlen = rpc_uaddr2sockaddr(SVC_NET(rqstp), naddr->addr, @@ -1229,12 +1313,23 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, goto out_free_rawdata; snprintf(dev_name, len + 5, "%s%s%s:/", startsep, ipaddr, endsep); + status = nfsd4_ssc_setup_dul(nn, ipaddr, &work, &ss_mnt); + if (status) + goto out_free_devname; + if (ss_mnt) + goto out_done; + /* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */ ss_mnt = vfs_kern_mount(type, SB_KERNMOUNT, dev_name, raw_data); module_put(type->owner); - if (IS_ERR(ss_mnt)) + if (IS_ERR(ss_mnt)) { + if (work) + nfsd4_ssc_cancel_dul_work(nn, work); goto out_free_devname; - + } + if (work) + nfsd4_ssc_update_dul_work(nn, work, ss_mnt); +out_done: status = 0; *mount = ss_mnt; @@ -1301,10 +1396,42 @@ static void nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src, struct nfsd_file *dst) { + bool found = false; + long timeout; + struct nfsd4_ssc_umount_item *tmp; + struct nfsd4_ssc_umount_item *ni = 0; + struct nfsd_net *nn = net_generic(dst->nf_net, nfsd_net_id); + nfs42_ssc_close(src->nf_file); - fput(src->nf_file); nfsd_file_put(dst); - mntput(ss_mnt); + fput(src->nf_file); + + if (!nn) { + mntput(ss_mnt); + return; + } + spin_lock(&nn->nfsd_ssc_lock); + timeout = msecs_to_jiffies(nfsd4_ssc_umount_timeout); + list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { + if (ni->nsui_vfsmount->mnt_sb == ss_mnt->mnt_sb) { + list_del(&ni->nsui_list); + /* + * vfsmount can be shared by multiple exports, + * decrement refcnt. If the count drops to 1 it + * will be unmounted when nsui_expire expires. + */ + refcount_dec(&ni->nsui_refcnt); + ni->nsui_expire = jiffies + timeout; + list_add_tail(&ni->nsui_list, &nn->nfsd_ssc_mount_list); + found = true; + break; + } + } + spin_unlock(&nn->nfsd_ssc_lock); + if (!found) { + mntput(ss_mnt); + return; + } } #else /* CONFIG_NFSD_V4_2_INTER_SSC */ diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b2573d3ecd3c..99dfc668f605 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "xdr4.h" #include "xdr4cb.h" #include "vfs.h" @@ -5480,6 +5481,69 @@ static bool state_expired(struct laundry_time *lt, time64_t last_refresh) return false; } +#ifdef CONFIG_NFSD_V4_2_INTER_SSC +void nfsd4_ssc_init_umount_work(struct nfsd_net *nn) +{ + spin_lock_init(&nn->nfsd_ssc_lock); + INIT_LIST_HEAD(&nn->nfsd_ssc_mount_list); + init_waitqueue_head(&nn->nfsd_ssc_waitq); +} +EXPORT_SYMBOL_GPL(nfsd4_ssc_init_umount_work); + +/* + * This is called when nfsd is being shutdown, after all inter_ssc + * cleanup were done, to destroy the ssc delayed unmount list. + */ +static void nfsd4_ssc_shutdown_umount(struct nfsd_net *nn) +{ + struct nfsd4_ssc_umount_item *ni = 0; + struct nfsd4_ssc_umount_item *tmp; + + spin_lock(&nn->nfsd_ssc_lock); + list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { + list_del(&ni->nsui_list); + spin_unlock(&nn->nfsd_ssc_lock); + mntput(ni->nsui_vfsmount); + kfree(ni); + spin_lock(&nn->nfsd_ssc_lock); + } + spin_unlock(&nn->nfsd_ssc_lock); +} + +static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) +{ + bool do_wakeup = false; + struct nfsd4_ssc_umount_item *ni = 0; + struct nfsd4_ssc_umount_item *tmp; + + spin_lock(&nn->nfsd_ssc_lock); + list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { + if (time_after(jiffies, ni->nsui_expire)) { + if (refcount_read(&ni->nsui_refcnt) > 1) + continue; + + /* mark being unmount */ + ni->nsui_busy = true; + spin_unlock(&nn->nfsd_ssc_lock); + mntput(ni->nsui_vfsmount); + spin_lock(&nn->nfsd_ssc_lock); + + /* waiters need to start from begin of list */ + list_del(&ni->nsui_list); + kfree(ni); + + /* wakeup ssc_connect waiters */ + do_wakeup = true; + continue; + } + break; + } + if (do_wakeup) + wake_up_all(&nn->nfsd_ssc_waitq); + spin_unlock(&nn->nfsd_ssc_lock); +} +#endif + static time64_t nfs4_laundromat(struct nfsd_net *nn) { @@ -5589,6 +5653,10 @@ nfs4_laundromat(struct nfsd_net *nn) list_del_init(&nbl->nbl_lru); free_blocked_lock(nbl); } +#ifdef CONFIG_NFSD_V4_2_INTER_SSC + /* service the server-to-server copy delayed unmount list */ + nfsd4_ssc_expire_umount(nn); +#endif out: return max_t(time64_t, lt.new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); } @@ -7506,6 +7574,9 @@ nfs4_state_shutdown_net(struct net *net) nfsd4_client_tracking_exit(net); nfs4_state_destroy_net(net); +#ifdef CONFIG_NFSD_V4_2_INTER_SSC + nfsd4_ssc_shutdown_umount(nn); +#endif } void diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 14dbfa75059d..9664303afdaf 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -484,6 +484,10 @@ static inline bool nfsd_attrs_supported(u32 minorversion, const u32 *bmval) extern int nfsd4_is_junction(struct dentry *dentry); extern int register_cld_notifier(void); extern void unregister_cld_notifier(void); +#ifdef CONFIG_NFSD_V4_2_INTER_SSC +extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn); +#endif + #else /* CONFIG_NFSD_V4 */ static inline int nfsd4_is_junction(struct dentry *dentry) { diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index dd5d69921676..ccb59e91011b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -403,6 +403,9 @@ static int nfsd_startup_net(struct net *net, const struct cred *cred) if (ret) goto out_filecache; +#ifdef CONFIG_NFSD_V4_2_INTER_SSC + nfsd4_ssc_init_umount_work(nn); +#endif nn->nfsd_net_up = true; return 0; diff --git a/include/linux/nfs_ssc.h b/include/linux/nfs_ssc.h index f5ba0fbff72f..222ae8883e85 100644 --- a/include/linux/nfs_ssc.h +++ b/include/linux/nfs_ssc.h @@ -8,6 +8,7 @@ */ #include +#include extern struct nfs_ssc_client_ops_tbl nfs_ssc_client_tbl; @@ -52,6 +53,19 @@ static inline void nfs42_ssc_close(struct file *filep) if (nfs_ssc_client_tbl.ssc_nfs4_ops) (*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_close)(filep); } + +struct nfsd4_ssc_umount_item { + struct list_head nsui_list; + bool nsui_busy; + /* + * nsui_refcnt inited to 2, 1 on list and 1 for consumer. Entry + * is removed when refcnt drops to 1 and nsui_expire expires. + */ + refcount_t nsui_refcnt; + unsigned long nsui_expire; + struct vfsmount *nsui_vfsmount; + char nsui_ipaddr[RPC_MAX_ADDRBUFLEN]; +}; #endif /* From 934bd07fae7e55232845f909f78873ab8678ca74 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 25 May 2021 14:53:44 -0400 Subject: [PATCH 29/69] nfsd: move fsnotify on client creation outside spinlock This was causing a "sleeping function called from invalid context" warning. I don't think we need the set_and_test_bit() here; clients move from unconfirmed to confirmed only once, under the client_lock. The (conf == unconf) is a way to check whether we're in that confirming case, hopefully that's not too obscure. Fixes: 472d155a0631 "nfsd: report client confirmation status in "info" file" Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 99dfc668f605..c01ecb7b3fd3 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2824,11 +2824,8 @@ move_to_confirmed(struct nfs4_client *clp) list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); add_clp_to_name_tree(clp, &nn->conf_name_tree); - if (!test_and_set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) { - trace_nfsd_clid_confirmed(&clp->cl_clientid); - if (clp->cl_nfsd_dentry && clp->cl_nfsd_info_dentry) - fsnotify_dentry(clp->cl_nfsd_info_dentry, FS_MODIFY); - } + set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); + trace_nfsd_clid_confirmed(&clp->cl_clientid); renew_client_locked(clp); } @@ -3487,6 +3484,8 @@ nfsd4_create_session(struct svc_rqst *rqstp, /* cache solo and embedded create sessions under the client_lock */ nfsd4_cache_create_session(cr_ses, cs_slot, status); spin_unlock(&nn->client_lock); + if (conf == unconf) + fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY); /* init connection and backchannel */ nfsd4_init_conn(rqstp, conn, new); nfsd4_put_session(new); @@ -4095,6 +4094,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, } get_client_locked(conf); spin_unlock(&nn->client_lock); + if (conf == unconf) + fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY); nfsd4_probe_callback(conf); spin_lock(&nn->client_lock); put_client_renew_locked(conf); From d50295255e787a142a1329d53c7c410227ceaac2 Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Mon, 31 May 2021 14:36:40 +0800 Subject: [PATCH 30/69] xprtrdma: Fix spelling mistakes Fix some spelling mistakes in comments: succes ==> success Signed-off-by: Zheng Yongjun Signed-off-by: J. Bruce Fields --- net/sunrpc/xprtrdma/svc_rdma_rw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c index 5238bc829235..1e651447dc4e 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c @@ -483,7 +483,7 @@ svc_rdma_build_writes(struct svc_rdma_write_info *info, * @iov: kvec to write * * Returns: - * On succes, returns zero + * On success, returns zero * %-E2BIG if the client-provided Write chunk is too small * %-ENOMEM if a resource has been exhausted * %-EIO if an rdma-rw error occurred @@ -504,7 +504,7 @@ static int svc_rdma_iov_write(struct svc_rdma_write_info *info, * @length: number of bytes to write * * Returns: - * On succes, returns zero + * On success, returns zero * %-E2BIG if the client-provided Write chunk is too small * %-ENOMEM if a resource has been exhausted * %-EIO if an rdma-rw error occurred @@ -526,7 +526,7 @@ static int svc_rdma_pages_write(struct svc_rdma_write_info *info, * @data: pointer to write arguments * * Returns: - * On succes, returns zero + * On success, returns zero * %-E2BIG if the client-provided Write chunk is too small * %-ENOMEM if a resource has been exhausted * %-EIO if an rdma-rw error occurred From 3518c8666f15cdd5d38878005dab1d589add1c19 Mon Sep 17 00:00:00 2001 From: Dave Wysochanski Date: Wed, 2 Jun 2021 13:51:39 -0400 Subject: [PATCH 31/69] nfsd4: Expose the callback address and state of each NFS4 client In addition to the client's address, display the callback channel state and address in the 'info' file. Signed-off-by: Dave Wysochanski Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index c01ecb7b3fd3..6c64ce93510f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2358,6 +2358,21 @@ static void seq_quote_mem(struct seq_file *m, char *data, int len) seq_printf(m, "\""); } +static const char *cb_state2str(int state) +{ + switch (state) { + case NFSD4_CB_UP: + return "UP"; + case NFSD4_CB_UNKNOWN: + return "UNKNOWN"; + case NFSD4_CB_DOWN: + return "DOWN"; + case NFSD4_CB_FAULT: + return "FAULT"; + } + return "UNDEFINED"; +} + static int client_info_show(struct seq_file *m, void *v) { struct inode *inode = m->private; @@ -2386,6 +2401,8 @@ static int client_info_show(struct seq_file *m, void *v) seq_printf(m, "\nImplementation time: [%lld, %ld]\n", clp->cl_nii_time.tv_sec, clp->cl_nii_time.tv_nsec); } + seq_printf(m, "callback state: %s\n", cb_state2str(clp->cl_cb_state)); + seq_printf(m, "callback address: %pISpc\n", &clp->cl_cb_conn.cb_addr); drop_client(clp); return 0; From f47dc2d3013c65631bf8903becc7d88dc9d9966e Mon Sep 17 00:00:00 2001 From: Dai Ngo Date: Thu, 3 Jun 2021 20:02:26 -0400 Subject: [PATCH 32/69] nfsd: fix kernel test robot warning in SSC code Fix by initializing pointer nfsd4_ssc_umount_item with NULL instead of 0. Replace return value of nfsd4_ssc_setup_dul with __be32 instead of int. Reported-by: kernel test robot Signed-off-by: Dai Ngo Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 4 ++-- fs/nfsd/nfs4state.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 0bd71c6da81d..af48fc8a601f 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1175,7 +1175,7 @@ extern void nfs_sb_deactive(struct super_block *sb); /* * setup a work entry in the ssc delayed unmount list. */ -static int nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, +static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, struct nfsd4_ssc_umount_item **retwork, struct vfsmount **ss_mnt) { struct nfsd4_ssc_umount_item *ni = 0; @@ -1399,7 +1399,7 @@ nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src, bool found = false; long timeout; struct nfsd4_ssc_umount_item *tmp; - struct nfsd4_ssc_umount_item *ni = 0; + struct nfsd4_ssc_umount_item *ni = NULL; struct nfsd_net *nn = net_generic(dst->nf_net, nfsd_net_id); nfs42_ssc_close(src->nf_file); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6c64ce93510f..980bd8903f84 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5514,7 +5514,7 @@ EXPORT_SYMBOL_GPL(nfsd4_ssc_init_umount_work); */ static void nfsd4_ssc_shutdown_umount(struct nfsd_net *nn) { - struct nfsd4_ssc_umount_item *ni = 0; + struct nfsd4_ssc_umount_item *ni = NULL; struct nfsd4_ssc_umount_item *tmp; spin_lock(&nn->nfsd_ssc_lock); From 54185267e1fe476875e649bb18e1c4254c123305 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 4 Jun 2021 10:12:37 +0000 Subject: [PATCH 33/69] NFSD: Fix error return code in nfsd4_interssc_connect() 'status' has been overwritten to 0 after nfsd4_ssc_setup_dul(), this cause 0 will be return in vfs_kern_mount() error case. Fix to return nfserr_nodev in this error. Fixes: f4e44b393389 ("NFSD: delay unmount source's export after inter-server copy completed.") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index af48fc8a601f..a0d67ba5ed59 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1323,6 +1323,7 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, ss_mnt = vfs_kern_mount(type, SB_KERNMOUNT, dev_name, raw_data); module_put(type->owner); if (IS_ERR(ss_mnt)) { + status = nfserr_nodev; if (work) nfsd4_ssc_cancel_dul_work(nn, work); goto out_free_devname; From 5823e40055166cdf959a77e7b5fe75998b0b9b1f Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Mon, 7 Jun 2021 14:28:23 +0800 Subject: [PATCH 34/69] nfs_common: fix doc warning Fix gcc W=1 warning: fs/nfs_common/grace.c:91: warning: Function parameter or member 'net' not described in 'locks_in_grace' Signed-off-by: ChenXiaoSong Signed-off-by: J. Bruce Fields --- fs/nfs_common/grace.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nfs_common/grace.c b/fs/nfs_common/grace.c index 26f2a50eceac..edec45831585 100644 --- a/fs/nfs_common/grace.c +++ b/fs/nfs_common/grace.c @@ -82,6 +82,7 @@ __state_in_grace(struct net *net, bool open) /** * locks_in_grace + * @net: network namespace * * Lock managers call this function to determine when it is OK for them * to answer ordinary lock requests, and when they should accept only From f6260b98ec1493b214f13bb9d0545779ffe87748 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 13 Jun 2021 15:06:52 +0100 Subject: [PATCH 35/69] rpc: remove redundant initialization of variable status The variable status is being initialized with a value that is never read, the assignment is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: J. Bruce Fields --- net/sunrpc/auth_gss/svcauth_gss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 6dff64374bfe..a81be45f40d9 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -1275,7 +1275,7 @@ static int gss_proxy_save_rsc(struct cache_detail *cd, long long ctxh; struct gss_api_mech *gm = NULL; time64_t expiry; - int status = -EINVAL; + int status; memset(&rsci, 0, sizeof(rsci)); /* context handle */ From 05570a2b01117209b500e1989ce8f1b0524c489f Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 14 Jun 2021 11:20:49 -0400 Subject: [PATCH 36/69] nfsd: rpc_peeraddr2str needs rcu lock I'm not even sure cl_xprt can change here, but we're getting "suspicious RCU usage" warnings, and other rpc_peeraddr2str callers are taking the rcu lock. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 84401ca04705..0f8b10f363e7 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -939,8 +939,10 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c } clp->cl_cb_client = client; clp->cl_cb_cred = cred; + rcu_read_lock(); trace_nfsd_cb_setup(clp, rpc_peeraddr2str(client, RPC_DISPLAY_NETID), args.authflavor); + rcu_read_unlock(); return 0; } From 99cdf57b33e68df7afc876739c93a11f0b1ba807 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:50:40 -0400 Subject: [PATCH 37/69] lockd: Remove stale comments Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- include/linux/lockd/xdr.h | 6 ------ include/linux/lockd/xdr4.h | 7 +------ 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h index 7ab9f264313f..a98309c0121c 100644 --- a/include/linux/lockd/xdr.h +++ b/include/linux/lockd/xdr.h @@ -109,11 +109,5 @@ int nlmsvc_decode_shareargs(struct svc_rqst *, __be32 *); int nlmsvc_encode_shareres(struct svc_rqst *, __be32 *); int nlmsvc_decode_notify(struct svc_rqst *, __be32 *); int nlmsvc_decode_reboot(struct svc_rqst *, __be32 *); -/* -int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *); -int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); -int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *); -int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *); - */ #endif /* LOCKD_XDR_H */ diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h index e709fe5924f2..5ae766f26e04 100644 --- a/include/linux/lockd/xdr4.h +++ b/include/linux/lockd/xdr4.h @@ -37,12 +37,7 @@ int nlm4svc_decode_shareargs(struct svc_rqst *, __be32 *); int nlm4svc_encode_shareres(struct svc_rqst *, __be32 *); int nlm4svc_decode_notify(struct svc_rqst *, __be32 *); int nlm4svc_decode_reboot(struct svc_rqst *, __be32 *); -/* -int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *); -int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); -int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *); -int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *); - */ + extern const struct rpc_version nlm_version4; #endif /* LOCKD_XDR4_H */ From a9ad1a8090f58b2ed1774dd0f4c7cdb8210a3793 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:50:46 -0400 Subject: [PATCH 38/69] lockd: Create a simplified .vs_dispatch method for NLM requests To enable xdr_stream-based encoding and decoding, create a bespoke RPC dispatch function for the lockd service. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/svc.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 1a639e34847d..2de048f80eb8 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -766,6 +766,46 @@ static void __exit exit_nlm(void) module_init(init_nlm); module_exit(exit_nlm); +/** + * nlmsvc_dispatch - Process an NLM Request + * @rqstp: incoming request + * @statp: pointer to location of accept_stat field in RPC Reply buffer + * + * Return values: + * %0: Processing complete; do not send a Reply + * %1: Processing complete; send Reply in rqstp->rq_res + */ +static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp) +{ + const struct svc_procedure *procp = rqstp->rq_procinfo; + struct kvec *argv = rqstp->rq_arg.head; + struct kvec *resv = rqstp->rq_res.head; + + svcxdr_init_decode(rqstp); + if (!procp->pc_decode(rqstp, argv->iov_base)) + goto out_decode_err; + + *statp = procp->pc_func(rqstp); + if (*statp == rpc_drop_reply) + return 0; + if (*statp != rpc_success) + return 1; + + svcxdr_init_encode(rqstp); + if (!procp->pc_encode(rqstp, resv->iov_base + resv->iov_len)) + goto out_encode_err; + + return 1; + +out_decode_err: + *statp = rpc_garbage_args; + return 1; + +out_encode_err: + *statp = rpc_system_err; + return 1; +} + /* * Define NLM program and procedures */ @@ -775,6 +815,7 @@ static const struct svc_version nlmsvc_version1 = { .vs_nproc = 17, .vs_proc = nlmsvc_procedures, .vs_count = nlmsvc_version1_count, + .vs_dispatch = nlmsvc_dispatch, .vs_xdrsize = NLMSVC_XDRSIZE, }; static unsigned int nlmsvc_version3_count[24]; @@ -783,6 +824,7 @@ static const struct svc_version nlmsvc_version3 = { .vs_nproc = 24, .vs_proc = nlmsvc_procedures, .vs_count = nlmsvc_version3_count, + .vs_dispatch = nlmsvc_dispatch, .vs_xdrsize = NLMSVC_XDRSIZE, }; #ifdef CONFIG_LOCKD_V4 @@ -792,6 +834,7 @@ static const struct svc_version nlmsvc_version4 = { .vs_nproc = 24, .vs_proc = nlmsvc_procedures4, .vs_count = nlmsvc_version4_count, + .vs_dispatch = nlmsvc_dispatch, .vs_xdrsize = NLMSVC_XDRSIZE, }; #endif From a6a63ca5652ea05637ecfe349f9e895031529556 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:50:52 -0400 Subject: [PATCH 39/69] lockd: Common NLM XDR helpers Add a .h file containing xdr_stream-based XDR helpers common to both NLMv3 and NLMv4. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/svcxdr.h | 151 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 fs/lockd/svcxdr.h diff --git a/fs/lockd/svcxdr.h b/fs/lockd/svcxdr.h new file mode 100644 index 000000000000..c69a0bb76c94 --- /dev/null +++ b/fs/lockd/svcxdr.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Encode/decode NLM basic data types + * + * Basic NLMv3 XDR data types are not defined in an IETF standards + * document. X/Open has a description of these data types that + * is useful. See Chapter 10 of "Protocols for Interworking: + * XNFS, Version 3W". + * + * Basic NLMv4 XDR data types are defined in Appendix II.1.4 of + * RFC 1813: "NFS Version 3 Protocol Specification". + * + * Author: Chuck Lever + * + * Copyright (c) 2020, Oracle and/or its affiliates. + */ + +#ifndef _LOCKD_SVCXDR_H_ +#define _LOCKD_SVCXDR_H_ + +static inline bool +svcxdr_decode_stats(struct xdr_stream *xdr, __be32 *status) +{ + __be32 *p; + + p = xdr_inline_decode(xdr, XDR_UNIT); + if (!p) + return false; + *status = *p; + + return true; +} + +static inline bool +svcxdr_encode_stats(struct xdr_stream *xdr, __be32 status) +{ + __be32 *p; + + p = xdr_reserve_space(xdr, XDR_UNIT); + if (!p) + return false; + *p = status; + + return true; +} + +static inline bool +svcxdr_decode_string(struct xdr_stream *xdr, char **data, unsigned int *data_len) +{ + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > NLM_MAXSTRLEN) + return false; + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + *data_len = len; + *data = (char *)p; + + return true; +} + +/* + * NLM cookies are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation + * limits their length to 32 bytes, and treats zero-length cookies + * specially. + */ +static inline bool +svcxdr_decode_cookie(struct xdr_stream *xdr, struct nlm_cookie *cookie) +{ + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > NLM_MAXCOOKIELEN) + return false; + if (!len) + goto out_hpux; + + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + cookie->len = len; + memcpy(cookie->data, p, len); + + return true; + + /* apparently HPUX can return empty cookies */ +out_hpux: + cookie->len = 4; + memset(cookie->data, 0, 4); + return true; +} + +static inline bool +svcxdr_encode_cookie(struct xdr_stream *xdr, const struct nlm_cookie *cookie) +{ + __be32 *p; + + if (xdr_stream_encode_u32(xdr, cookie->len) < 0) + return false; + p = xdr_reserve_space(xdr, cookie->len); + if (!p) + return false; + memcpy(p, cookie->data, cookie->len); + + return true; +} + +static inline bool +svcxdr_decode_owner(struct xdr_stream *xdr, struct xdr_netobj *obj) +{ + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > XDR_MAX_NETOBJ) + return false; + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + obj->len = len; + obj->data = (u8 *)p; + + return true; +} + +static inline bool +svcxdr_encode_owner(struct xdr_stream *xdr, const struct xdr_netobj *obj) +{ + unsigned int quadlen = XDR_QUADLEN(obj->len); + __be32 *p; + + if (xdr_stream_encode_u32(xdr, obj->len) < 0) + return false; + p = xdr_reserve_space(xdr, obj->len); + if (!p) + return false; + p[quadlen - 1] = 0; /* XDR pad */ + memcpy(p, obj->data, obj->len); + + return true; +} + +#endif /* _LOCKD_SVCXDR_H_ */ From cc1029b51273da5b342683e9ae14ab4eeaa15997 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:50:58 -0400 Subject: [PATCH 40/69] lockd: Update the NLMv1 void argument decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 982629f7b120..8be42a23679e 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -19,6 +19,8 @@ #include +#include "svcxdr.h" + #define NLMDBG_FACILITY NLMDBG_XDR @@ -178,8 +180,15 @@ nlm_encode_testres(__be32 *p, struct nlm_res *resp) /* - * First, the server side XDR functions + * Decode Call arguments */ + +int +nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p) +{ + return 1; +} + int nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) { @@ -339,12 +348,6 @@ nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p) return xdr_argsize_check(rqstp, p); } -int -nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p) -{ - return xdr_argsize_check(rqstp, p); -} - int nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) { From 2fd0c67aabcf0f8821450b00ee511faa0b7761bf Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:51:04 -0400 Subject: [PATCH 41/69] lockd: Update the NLMv1 TEST arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr.c | 72 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 8be42a23679e..56982edd4766 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -98,6 +98,33 @@ nlm_decode_fh(__be32 *p, struct nfs_fh *f) return p + XDR_QUADLEN(NFS2_FHSIZE); } +/* + * NLM file handles are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation + * constrains their length to exactly the length of an NFSv2 file + * handle. + */ +static bool +svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) +{ + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len != NFS2_FHSIZE) + return false; + + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + fh->size = NFS2_FHSIZE; + memcpy(fh->data, p, len); + memset(fh->data + NFS2_FHSIZE, 0, sizeof(fh->data) - NFS2_FHSIZE); + + return true; +} + /* * Encode and decode owner handle */ @@ -143,6 +170,38 @@ nlm_decode_lock(__be32 *p, struct nlm_lock *lock) return p; } +static bool +svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) +{ + struct file_lock *fl = &lock->fl; + s32 start, len, end; + + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return false; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) + return false; + if (!svcxdr_decode_owner(xdr, &lock->oh)) + return false; + if (xdr_stream_decode_u32(xdr, &lock->svid) < 0) + return false; + if (xdr_stream_decode_u32(xdr, &start) < 0) + return false; + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + + locks_init_lock(fl); + fl->fl_flags = FL_POSIX; + fl->fl_type = F_RDLCK; + end = start + len - 1; + fl->fl_start = s32_to_loff_t(start); + if (len == 0 || end < 0) + fl->fl_end = OFFSET_MAX; + else + fl->fl_end = s32_to_loff_t(end); + + return true; +} + /* * Encode result of a TEST/TEST_MSG call */ @@ -192,19 +251,20 @@ nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p) int nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; + u32 exclusive; - if (!(p = nlm_decode_cookie(p, &argp->cookie))) + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) return 0; - - exclusive = ntohl(*p++); - if (!(p = nlm_decode_lock(p, &argp->lock))) + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) return 0; if (exclusive) argp->lock.fl.fl_type = F_WRLCK; - return xdr_argsize_check(rqstp, p); + return 1; } int From c1adb8c672ca2b085c400695ef064547d77eda29 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:51:10 -0400 Subject: [PATCH 42/69] lockd: Update the NLMv1 LOCK arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr.c | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 56982edd4766..8a9f02e45df2 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -267,6 +267,32 @@ nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) + return 0; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return 0; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) + return 0; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return 0; + argp->monitor = 1; /* monitor client by default */ + + return 1; +} + int nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -277,27 +303,6 @@ nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) return xdr_ressize_check(rqstp, p); } -int -nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; - - if (!(p = nlm_decode_cookie(p, &argp->cookie))) - return 0; - argp->block = ntohl(*p++); - exclusive = ntohl(*p++); - if (!(p = nlm_decode_lock(p, &argp->lock))) - return 0; - if (exclusive) - argp->lock.fl.fl_type = F_WRLCK; - argp->reclaim = ntohl(*p++); - argp->state = ntohl(*p++); - argp->monitor = 1; /* monitor client by default */ - - return xdr_argsize_check(rqstp, p); -} - int nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) { From f4e08f3ac8c4945ea54a740e3afcf44b34e7cf44 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:51:16 -0400 Subject: [PATCH 43/69] lockd: Update the NLMv1 CANCEL arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 8a9f02e45df2..ef38f07d1224 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -293,6 +293,27 @@ nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) + return 0; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return 0; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + + return 1; +} + int nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -303,23 +324,6 @@ nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) return xdr_ressize_check(rqstp, p); } -int -nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; - - if (!(p = nlm_decode_cookie(p, &argp->cookie))) - return 0; - argp->block = ntohl(*p++); - exclusive = ntohl(*p++); - if (!(p = nlm_decode_lock(p, &argp->lock))) - return 0; - if (exclusive) - argp->lock.fl.fl_type = F_WRLCK; - return xdr_argsize_check(rqstp, p); -} - int nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) { From c27045d302b022ed11d24a2653bceb6af56c6327 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:51:22 -0400 Subject: [PATCH 44/69] lockd: Update the NLMv1 UNLOCK arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr.c | 57 +++++++++++++------------------------------------- 1 file changed, 15 insertions(+), 42 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index ef38f07d1224..b59e02b4417c 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -140,36 +140,6 @@ nlm_encode_oh(__be32 *p, struct xdr_netobj *oh) return xdr_encode_netobj(p, oh); } -static __be32 * -nlm_decode_lock(__be32 *p, struct nlm_lock *lock) -{ - struct file_lock *fl = &lock->fl; - s32 start, len, end; - - if (!(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, - NLM_MAXSTRLEN)) - || !(p = nlm_decode_fh(p, &lock->fh)) - || !(p = nlm_decode_oh(p, &lock->oh))) - return NULL; - lock->svid = ntohl(*p++); - - locks_init_lock(fl); - fl->fl_flags = FL_POSIX; - fl->fl_type = F_RDLCK; /* as good as anything else */ - start = ntohl(*p++); - len = ntohl(*p++); - end = start + len - 1; - - fl->fl_start = s32_to_loff_t(start); - - if (len == 0 || end < 0) - fl->fl_end = OFFSET_MAX; - else - fl->fl_end = s32_to_loff_t(end); - return p; -} - static bool svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) { @@ -314,6 +284,21 @@ nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return 0; + argp->lock.fl.fl_type = F_UNLCK; + + return 1; +} + int nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -324,18 +309,6 @@ nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) return xdr_ressize_check(rqstp, p); } -int -nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - - if (!(p = nlm_decode_cookie(p, &argp->cookie)) - || !(p = nlm_decode_lock(p, &argp->lock))) - return 0; - argp->lock.fl.fl_type = F_UNLCK; - return xdr_argsize_check(rqstp, p); -} - int nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) { From 16ddcabe6240c4fb01c97f6fce6c35ddf8626ad5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:51:28 -0400 Subject: [PATCH 45/69] lockd: Update the NLMv1 nlm_res arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index b59e02b4417c..911b6377a6da 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -299,6 +299,20 @@ nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_res *resp = rqstp->rq_argp; + + if (!svcxdr_decode_cookie(xdr, &resp->cookie)) + return 0; + if (!svcxdr_decode_stats(xdr, &resp->status)) + return 0; + + return 1; +} + int nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -379,17 +393,6 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) return xdr_argsize_check(rqstp, p); } -int -nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_res *resp = rqstp->rq_argp; - - if (!(p = nlm_decode_cookie(p, &resp->cookie))) - return 0; - resp->status = *p++; - return xdr_argsize_check(rqstp, p); -} - int nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) { From 137e05e2f735f696e117553f7fa5ef8fb09953e1 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:51:34 -0400 Subject: [PATCH 46/69] lockd: Update the NLMv1 SM_NOTIFY arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 911b6377a6da..421613170e5f 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -313,6 +313,32 @@ nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_reboot *argp = rqstp->rq_argp; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return 0; + if (len > SM_MAXSTRLEN) + return 0; + p = xdr_inline_decode(xdr, len); + if (!p) + return 0; + argp->len = len; + argp->mon = (char *)p; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return 0; + p = xdr_inline_decode(xdr, SM_PRIV_SIZE); + if (!p) + return 0; + memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); + + return 1; +} + int nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -380,19 +406,6 @@ nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p) return xdr_argsize_check(rqstp, p); } -int -nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_reboot *argp = rqstp->rq_argp; - - if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) - return 0; - argp->state = ntohl(*p++); - memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); - p += XDR_QUADLEN(SM_PRIV_SIZE); - return xdr_argsize_check(rqstp, p); -} - int nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) { From 890939e1266b9adf3b0acd5e0385b39813cb8f11 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:51:40 -0400 Subject: [PATCH 47/69] lockd: Update the NLMv1 SHARE arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr.c | 100 ++++++++++++++----------------------------------- 1 file changed, 28 insertions(+), 72 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 421613170e5f..c496f18eff06 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -21,8 +21,6 @@ #include "svcxdr.h" -#define NLMDBG_FACILITY NLMDBG_XDR - static inline loff_t s32_to_loff_t(__s32 offset) @@ -46,33 +44,6 @@ loff_t_to_s32(loff_t offset) /* * XDR functions for basic NLM types */ -static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c) -{ - unsigned int len; - - len = ntohl(*p++); - - if(len==0) - { - c->len=4; - memset(c->data, 0, 4); /* hockeypux brain damage */ - } - else if(len<=NLM_MAXCOOKIELEN) - { - c->len=len; - memcpy(c->data, p, len); - p+=XDR_QUADLEN(len); - } - else - { - dprintk("lockd: bad cookie size %d (only cookies under " - "%d bytes are supported.)\n", - len, NLM_MAXCOOKIELEN); - return NULL; - } - return p; -} - static inline __be32 * nlm_encode_cookie(__be32 *p, struct nlm_cookie *c) { @@ -82,22 +53,6 @@ nlm_encode_cookie(__be32 *p, struct nlm_cookie *c) return p; } -static __be32 * -nlm_decode_fh(__be32 *p, struct nfs_fh *f) -{ - unsigned int len; - - if ((len = ntohl(*p++)) != NFS2_FHSIZE) { - dprintk("lockd: bad fhandle size %d (should be %d)\n", - len, NFS2_FHSIZE); - return NULL; - } - f->size = NFS2_FHSIZE; - memset(f->data, 0, sizeof(f->data)); - memcpy(f->data, p, NFS2_FHSIZE); - return p + XDR_QUADLEN(NFS2_FHSIZE); -} - /* * NLM file handles are defined by specification to be a variable-length * XDR opaque no longer than 1024 bytes. However, this implementation @@ -128,12 +83,6 @@ svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) /* * Encode and decode owner handle */ -static inline __be32 * -nlm_decode_oh(__be32 *p, struct xdr_netobj *oh) -{ - return xdr_decode_netobj(p, oh); -} - static inline __be32 * nlm_encode_oh(__be32 *p, struct xdr_netobj *oh) { @@ -339,6 +288,34 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + + memset(lock, 0, sizeof(*lock)); + locks_init_lock(&lock->fl); + lock->svid = ~(u32)0; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return 0; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) + return 0; + if (!svcxdr_decode_owner(xdr, &lock->oh)) + return 0; + /* XXX: Range checks are missing in the original code */ + if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) + return 0; + if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) + return 0; + + return 1; +} + int nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -349,27 +326,6 @@ nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) return xdr_ressize_check(rqstp, p); } -int -nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_lock *lock = &argp->lock; - - memset(lock, 0, sizeof(*lock)); - locks_init_lock(&lock->fl); - lock->svid = ~(u32) 0; - - if (!(p = nlm_decode_cookie(p, &argp->cookie)) - || !(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN)) - || !(p = nlm_decode_fh(p, &lock->fh)) - || !(p = nlm_decode_oh(p, &lock->oh))) - return 0; - argp->fsm_mode = ntohl(*p++); - argp->fsm_access = ntohl(*p++); - return xdr_argsize_check(rqstp, p); -} - int nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) { From 14e105256b9dcdf50a003e2e9a0da77e06770a4b Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:51:46 -0400 Subject: [PATCH 48/69] lockd: Update the NLMv1 FREE_ALL arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index c496f18eff06..091c8c463ab4 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -316,6 +316,21 @@ nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return 0; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return 0; + + return 1; +} + int nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -349,19 +364,6 @@ nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) return xdr_ressize_check(rqstp, p); } -int -nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_lock *lock = &argp->lock; - - if (!(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN))) - return 0; - argp->state = ntohl(*p++); - return xdr_argsize_check(rqstp, p); -} - int nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) { From e26ec898b68b2ab64f379ba0fc0a615b2ad41f40 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:51:52 -0400 Subject: [PATCH 49/69] lockd: Update the NLMv1 void results encoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 091c8c463ab4..840fa8ff8426 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -331,6 +331,17 @@ nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p) return 1; } + +/* + * Encode Reply results + */ + +int +nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) +{ + return 1; +} + int nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -363,9 +374,3 @@ nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) *p++ = resp->status; return xdr_ressize_check(rqstp, p); } - -int -nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) -{ - return xdr_ressize_check(rqstp, p); -} From adf98a4850b9ede9fc174c78a885845fb08499a5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:51:58 -0400 Subject: [PATCH 50/69] lockd: Update the NLMv1 TEST results encoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr.c | 74 ++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 840fa8ff8426..daf3524040d6 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -80,15 +80,6 @@ svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) return true; } -/* - * Encode and decode owner handle - */ -static inline __be32 * -nlm_encode_oh(__be32 *p, struct xdr_netobj *oh) -{ - return xdr_encode_netobj(p, oh); -} - static bool svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) { @@ -121,39 +112,44 @@ svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) return true; } -/* - * Encode result of a TEST/TEST_MSG call - */ -static __be32 * -nlm_encode_testres(__be32 *p, struct nlm_res *resp) +static bool +svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock) { - s32 start, len; + const struct file_lock *fl = &lock->fl; + s32 start, len; - if (!(p = nlm_encode_cookie(p, &resp->cookie))) - return NULL; - *p++ = resp->status; + /* exclusive */ + if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0) + return false; + if (xdr_stream_encode_u32(xdr, lock->svid) < 0) + return false; + if (!svcxdr_encode_owner(xdr, &lock->oh)) + return false; + start = loff_t_to_s32(fl->fl_start); + if (fl->fl_end == OFFSET_MAX) + len = 0; + else + len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); + if (xdr_stream_encode_u32(xdr, start) < 0) + return false; + if (xdr_stream_encode_u32(xdr, len) < 0) + return false; - if (resp->status == nlm_lck_denied) { - struct file_lock *fl = &resp->lock.fl; + return true; +} - *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one; - *p++ = htonl(resp->lock.svid); - - /* Encode owner handle. */ - if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) - return NULL; - - start = loff_t_to_s32(fl->fl_start); - if (fl->fl_end == OFFSET_MAX) - len = 0; - else - len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); - - *p++ = htonl(start); - *p++ = htonl(len); +static bool +svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) +{ + if (!svcxdr_encode_stats(xdr, resp->status)) + return false; + switch (resp->status) { + case nlm_lck_denied: + if (!svcxdr_encode_holder(xdr, &resp->lock)) + return false; } - return p; + return true; } @@ -345,11 +341,11 @@ nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) int nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nlm_res *resp = rqstp->rq_resp; - if (!(p = nlm_encode_testres(p, resp))) - return 0; - return xdr_ressize_check(rqstp, p); + return svcxdr_encode_cookie(xdr, &resp->cookie) && + svcxdr_encode_testrply(xdr, resp); } int From e96735a6980574ecbdb24c760b8d294095e47074 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:52:04 -0400 Subject: [PATCH 51/69] lockd: Update the NLMv1 nlm_res results encoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index daf3524040d6..4fb6090bc915 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -348,6 +348,16 @@ nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) svcxdr_encode_testrply(xdr, resp); } +int +nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + return svcxdr_encode_cookie(xdr, &resp->cookie) && + svcxdr_encode_stats(xdr, resp->status); +} + int nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) { @@ -359,14 +369,3 @@ nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) *p++ = xdr_zero; /* sequence argument */ return xdr_ressize_check(rqstp, p); } - -int -nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_res *resp = rqstp->rq_resp; - - if (!(p = nlm_encode_cookie(p, &resp->cookie))) - return 0; - *p++ = resp->status; - return xdr_ressize_check(rqstp, p); -} From 529ca3a116e8978575fec061a71fa6865a344891 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:52:10 -0400 Subject: [PATCH 52/69] lockd: Update the NLMv1 SHARE results encoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 4fb6090bc915..9235e60b1769 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -41,18 +41,6 @@ loff_t_to_s32(loff_t offset) return res; } -/* - * XDR functions for basic NLM types - */ -static inline __be32 * -nlm_encode_cookie(__be32 *p, struct nlm_cookie *c) -{ - *p++ = htonl(c->len); - memcpy(p, c->data, c->len); - p+=XDR_QUADLEN(c->len); - return p; -} - /* * NLM file handles are defined by specification to be a variable-length * XDR opaque no longer than 1024 bytes. However, this implementation @@ -361,11 +349,16 @@ nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) int nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nlm_res *resp = rqstp->rq_resp; - if (!(p = nlm_encode_cookie(p, &resp->cookie))) + if (!svcxdr_encode_cookie(xdr, &resp->cookie)) return 0; - *p++ = resp->status; - *p++ = xdr_zero; /* sequence argument */ - return xdr_ressize_check(rqstp, p); + if (!svcxdr_encode_stats(xdr, resp->status)) + return 0; + /* sequence */ + if (xdr_stream_encode_u32(xdr, 0) < 0) + return 0; + + return 1; } From 7956521aac58e434a05cf3c68c1b66c1312e5649 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:52:16 -0400 Subject: [PATCH 53/69] lockd: Update the NLMv4 void arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr4.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 5fa9f48a9dba..d0960a8551f8 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -18,6 +18,8 @@ #include #include +#include "svcxdr.h" + #define NLMDBG_FACILITY NLMDBG_XDR static inline loff_t @@ -175,8 +177,15 @@ nlm4_encode_testres(__be32 *p, struct nlm_res *resp) /* - * First, the server side XDR functions + * Decode Call arguments */ + +int +nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p) +{ + return 1; +} + int nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) { @@ -336,12 +345,6 @@ nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p) return xdr_argsize_check(rqstp, p); } -int -nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p) -{ - return xdr_argsize_check(rqstp, p); -} - int nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) { From 345b4159a075b15dc4ae70f1db90fa8abf85d2e7 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:52:22 -0400 Subject: [PATCH 54/69] lockd: Update the NLMv4 TEST arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr4.c | 72 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index d0960a8551f8..cf64794fdc1f 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -96,6 +96,32 @@ nlm4_decode_fh(__be32 *p, struct nfs_fh *f) return p + XDR_QUADLEN(f->size); } +/* + * NLM file handles are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation + * limits their length to the size of an NFSv3 file handle. + */ +static bool +svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) +{ + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > NFS_MAXFHSIZE) + return false; + + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + fh->size = len; + memcpy(fh->data, p, len); + memset(fh->data + len, 0, sizeof(fh->data) - len); + + return true; +} + /* * Encode and decode owner handle */ @@ -135,6 +161,39 @@ nlm4_decode_lock(__be32 *p, struct nlm_lock *lock) return p; } +static bool +svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) +{ + struct file_lock *fl = &lock->fl; + u64 len, start; + s64 end; + + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return false; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) + return false; + if (!svcxdr_decode_owner(xdr, &lock->oh)) + return false; + if (xdr_stream_decode_u32(xdr, &lock->svid) < 0) + return false; + if (xdr_stream_decode_u64(xdr, &start) < 0) + return false; + if (xdr_stream_decode_u64(xdr, &len) < 0) + return false; + + locks_init_lock(fl); + fl->fl_flags = FL_POSIX; + fl->fl_type = F_RDLCK; + end = start + len - 1; + fl->fl_start = s64_to_loff_t(start); + if (len == 0 || end < 0) + fl->fl_end = OFFSET_MAX; + else + fl->fl_end = s64_to_loff_t(end); + + return true; +} + /* * Encode result of a TEST/TEST_MSG call */ @@ -189,19 +248,20 @@ nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p) int nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_arg_stream; struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; + u32 exclusive; - if (!(p = nlm4_decode_cookie(p, &argp->cookie))) + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) return 0; - - exclusive = ntohl(*p++); - if (!(p = nlm4_decode_lock(p, &argp->lock))) + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) return 0; if (exclusive) argp->lock.fl.fl_type = F_WRLCK; - return xdr_argsize_check(rqstp, p); + return 1; } int From 0e5977af4fdc277984fca7d8c2e0c880935775a0 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:52:28 -0400 Subject: [PATCH 55/69] lockd: Update the NLMv4 LOCK arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr4.c | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index cf64794fdc1f..1d3e780c25fd 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -264,6 +264,32 @@ nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) + return 0; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return 0; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) + return 0; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return 0; + argp->monitor = 1; /* monitor client by default */ + + return 1; +} + int nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -274,27 +300,6 @@ nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) return xdr_ressize_check(rqstp, p); } -int -nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; - - if (!(p = nlm4_decode_cookie(p, &argp->cookie))) - return 0; - argp->block = ntohl(*p++); - exclusive = ntohl(*p++); - if (!(p = nlm4_decode_lock(p, &argp->lock))) - return 0; - if (exclusive) - argp->lock.fl.fl_type = F_WRLCK; - argp->reclaim = ntohl(*p++); - argp->state = ntohl(*p++); - argp->monitor = 1; /* monitor client by default */ - - return xdr_argsize_check(rqstp, p); -} - int nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) { From 1e1f38dcf3c031715191e1fd26f70a0affca4dbd Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:52:34 -0400 Subject: [PATCH 56/69] lockd: Update the NLMv4 CANCEL arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr4.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 1d3e780c25fd..37d45f1d7199 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -290,6 +290,26 @@ nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) + return 0; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return 0; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + return 1; +} + int nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -300,23 +320,6 @@ nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) return xdr_ressize_check(rqstp, p); } -int -nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; - - if (!(p = nlm4_decode_cookie(p, &argp->cookie))) - return 0; - argp->block = ntohl(*p++); - exclusive = ntohl(*p++); - if (!(p = nlm4_decode_lock(p, &argp->lock))) - return 0; - if (exclusive) - argp->lock.fl.fl_type = F_WRLCK; - return xdr_argsize_check(rqstp, p); -} - int nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) { From d76d8c25cea794f65615f3a2324052afa4b5f900 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:52:40 -0400 Subject: [PATCH 57/69] lockd: Update the NLMv4 UNLOCK arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr4.c | 57 +++++++++++++------------------------------------ 1 file changed, 15 insertions(+), 42 deletions(-) diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 37d45f1d7199..47a87ea4a99b 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -131,36 +131,6 @@ nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh) return xdr_decode_netobj(p, oh); } -static __be32 * -nlm4_decode_lock(__be32 *p, struct nlm_lock *lock) -{ - struct file_lock *fl = &lock->fl; - __u64 len, start; - __s64 end; - - if (!(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN)) - || !(p = nlm4_decode_fh(p, &lock->fh)) - || !(p = nlm4_decode_oh(p, &lock->oh))) - return NULL; - lock->svid = ntohl(*p++); - - locks_init_lock(fl); - fl->fl_flags = FL_POSIX; - fl->fl_type = F_RDLCK; /* as good as anything else */ - p = xdr_decode_hyper(p, &start); - p = xdr_decode_hyper(p, &len); - end = start + len - 1; - - fl->fl_start = s64_to_loff_t(start); - - if (len == 0 || end < 0) - fl->fl_end = OFFSET_MAX; - else - fl->fl_end = s64_to_loff_t(end); - return p; -} - static bool svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) { @@ -310,6 +280,21 @@ nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return 0; + argp->lock.fl.fl_type = F_UNLCK; + + return 1; +} + int nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -320,18 +305,6 @@ nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) return xdr_ressize_check(rqstp, p); } -int -nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - - if (!(p = nlm4_decode_cookie(p, &argp->cookie)) - || !(p = nlm4_decode_lock(p, &argp->lock))) - return 0; - argp->lock.fl.fl_type = F_UNLCK; - return xdr_argsize_check(rqstp, p); -} - int nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) { From b4c24b5a41da63e5f3a9b6ea56cbe2a1efe49579 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:52:46 -0400 Subject: [PATCH 58/69] lockd: Update the NLMv4 nlm_res arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr4.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 47a87ea4a99b..6bd3bfb69ed7 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -295,6 +295,20 @@ nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_res *resp = rqstp->rq_argp; + + if (!svcxdr_decode_cookie(xdr, &resp->cookie)) + return 0; + if (!svcxdr_decode_stats(xdr, &resp->status)) + return 0; + + return 1; +} + int nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -375,17 +389,6 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) return xdr_argsize_check(rqstp, p); } -int -nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_res *resp = rqstp->rq_argp; - - if (!(p = nlm4_decode_cookie(p, &resp->cookie))) - return 0; - resp->status = *p++; - return xdr_argsize_check(rqstp, p); -} - int nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) { From bc3665fd718b325cfff3abd383b00d1a87e028dc Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:52:52 -0400 Subject: [PATCH 59/69] lockd: Update the NLMv4 SM_NOTIFY arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr4.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 6bd3bfb69ed7..2dbf82c2726b 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -309,6 +309,32 @@ nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_reboot *argp = rqstp->rq_argp; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return 0; + if (len > SM_MAXSTRLEN) + return 0; + p = xdr_inline_decode(xdr, len); + if (!p) + return 0; + argp->len = len; + argp->mon = (char *)p; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return 0; + p = xdr_inline_decode(xdr, SM_PRIV_SIZE); + if (!p) + return 0; + memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); + + return 1; +} + int nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -376,19 +402,6 @@ nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p) return xdr_argsize_check(rqstp, p); } -int -nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_reboot *argp = rqstp->rq_argp; - - if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) - return 0; - argp->state = ntohl(*p++); - memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); - p += XDR_QUADLEN(SM_PRIV_SIZE); - return xdr_argsize_check(rqstp, p); -} - int nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) { From 7cf96b6d0104b12aa30961901879e428884b1695 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:52:58 -0400 Subject: [PATCH 60/69] lockd: Update the NLMv4 SHARE arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr4.c | 103 +++++++++++++----------------------------------- 1 file changed, 28 insertions(+), 75 deletions(-) diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 2dbf82c2726b..e6bab1d1e41f 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -42,37 +42,6 @@ loff_t_to_s64(loff_t offset) return res; } -/* - * XDR functions for basic NLM types - */ -static __be32 * -nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c) -{ - unsigned int len; - - len = ntohl(*p++); - - if(len==0) - { - c->len=4; - memset(c->data, 0, 4); /* hockeypux brain damage */ - } - else if(len<=NLM_MAXCOOKIELEN) - { - c->len=len; - memcpy(c->data, p, len); - p+=XDR_QUADLEN(len); - } - else - { - dprintk("lockd: bad cookie size %d (only cookies under " - "%d bytes are supported.)\n", - len, NLM_MAXCOOKIELEN); - return NULL; - } - return p; -} - static __be32 * nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c) { @@ -82,20 +51,6 @@ nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c) return p; } -static __be32 * -nlm4_decode_fh(__be32 *p, struct nfs_fh *f) -{ - memset(f->data, 0, sizeof(f->data)); - f->size = ntohl(*p++); - if (f->size > NFS_MAXFHSIZE) { - dprintk("lockd: bad fhandle size %d (should be <=%d)\n", - f->size, NFS_MAXFHSIZE); - return NULL; - } - memcpy(f->data, p, f->size); - return p + XDR_QUADLEN(f->size); -} - /* * NLM file handles are defined by specification to be a variable-length * XDR opaque no longer than 1024 bytes. However, this implementation @@ -122,15 +77,6 @@ svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) return true; } -/* - * Encode and decode owner handle - */ -static __be32 * -nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh) -{ - return xdr_decode_netobj(p, oh); -} - static bool svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) { @@ -335,6 +281,34 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + + memset(lock, 0, sizeof(*lock)); + locks_init_lock(&lock->fl); + lock->svid = ~(u32)0; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return 0; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) + return 0; + if (!svcxdr_decode_owner(xdr, &lock->oh)) + return 0; + /* XXX: Range checks are missing in the original code */ + if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) + return 0; + if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) + return 0; + + return 1; +} + int nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -345,27 +319,6 @@ nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) return xdr_ressize_check(rqstp, p); } -int -nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_lock *lock = &argp->lock; - - memset(lock, 0, sizeof(*lock)); - locks_init_lock(&lock->fl); - lock->svid = ~(u32) 0; - - if (!(p = nlm4_decode_cookie(p, &argp->cookie)) - || !(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN)) - || !(p = nlm4_decode_fh(p, &lock->fh)) - || !(p = nlm4_decode_oh(p, &lock->oh))) - return 0; - argp->fsm_mode = ntohl(*p++); - argp->fsm_access = ntohl(*p++); - return xdr_argsize_check(rqstp, p); -} - int nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) { From 3049e974a7c7cfa0c15fb807f4a3e75b2ab8517a Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:53:04 -0400 Subject: [PATCH 61/69] lockd: Update the NLMv4 FREE_ALL arguments decoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr4.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index e6bab1d1e41f..6c5383bef2bf 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -309,6 +309,21 @@ nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) return 1; } +int +nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return 0; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return 0; + + return 1; +} + int nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -342,19 +357,6 @@ nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) return xdr_ressize_check(rqstp, p); } -int -nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_lock *lock = &argp->lock; - - if (!(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN))) - return 0; - argp->state = ntohl(*p++); - return xdr_argsize_check(rqstp, p); -} - int nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) { From ec757e423b4fcd6e5ea4405d1e8243c040458d78 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:53:11 -0400 Subject: [PATCH 62/69] lockd: Update the NLMv4 void results encoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr4.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 6c5383bef2bf..0db142e203d2 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -324,6 +324,17 @@ nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p) return 1; } + +/* + * Encode Reply results + */ + +int +nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) +{ + return 1; +} + int nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { @@ -356,9 +367,3 @@ nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) *p++ = resp->status; return xdr_ressize_check(rqstp, p); } - -int -nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) -{ - return xdr_ressize_check(rqstp, p); -} From 1beef1473ccaa70a2d54f9e76fba5f534931ea23 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:53:17 -0400 Subject: [PATCH 63/69] lockd: Update the NLMv4 TEST results encoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr4.c | 72 ++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 0db142e203d2..9b8a7afb935c 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -20,8 +20,6 @@ #include "svcxdr.h" -#define NLMDBG_FACILITY NLMDBG_XDR - static inline loff_t s64_to_loff_t(__s64 offset) { @@ -110,44 +108,44 @@ svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) return true; } -/* - * Encode result of a TEST/TEST_MSG call - */ -static __be32 * -nlm4_encode_testres(__be32 *p, struct nlm_res *resp) +static bool +svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock) { - s64 start, len; + const struct file_lock *fl = &lock->fl; + s64 start, len; - dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp); - if (!(p = nlm4_encode_cookie(p, &resp->cookie))) - return NULL; - *p++ = resp->status; + /* exclusive */ + if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0) + return false; + if (xdr_stream_encode_u32(xdr, lock->svid) < 0) + return false; + if (!svcxdr_encode_owner(xdr, &lock->oh)) + return false; + start = loff_t_to_s64(fl->fl_start); + if (fl->fl_end == OFFSET_MAX) + len = 0; + else + len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); + if (xdr_stream_encode_u64(xdr, start) < 0) + return false; + if (xdr_stream_encode_u64(xdr, len) < 0) + return false; - if (resp->status == nlm_lck_denied) { - struct file_lock *fl = &resp->lock.fl; + return true; +} - *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one; - *p++ = htonl(resp->lock.svid); - - /* Encode owner handle. */ - if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) - return NULL; - - start = loff_t_to_s64(fl->fl_start); - if (fl->fl_end == OFFSET_MAX) - len = 0; - else - len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); - - p = xdr_encode_hyper(p, start); - p = xdr_encode_hyper(p, len); - dprintk("xdr: encode_testres (status %u pid %d type %d start %Ld end %Ld)\n", - resp->status, (int)resp->lock.svid, fl->fl_type, - (long long)fl->fl_start, (long long)fl->fl_end); +static bool +svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) +{ + if (!svcxdr_encode_stats(xdr, resp->status)) + return false; + switch (resp->status) { + case nlm_lck_denied: + if (!svcxdr_encode_holder(xdr, &resp->lock)) + return false; } - dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp); - return p; + return true; } @@ -338,11 +336,11 @@ nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) int nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nlm_res *resp = rqstp->rq_resp; - if (!(p = nlm4_encode_testres(p, resp))) - return 0; - return xdr_ressize_check(rqstp, p); + return svcxdr_encode_cookie(xdr, &resp->cookie) && + svcxdr_encode_testrply(xdr, resp); } int From 447c14d48968d0d4c2733c3f8052cb63aa1deb38 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:53:23 -0400 Subject: [PATCH 64/69] lockd: Update the NLMv4 nlm_res results encoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr4.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 9b8a7afb935c..efdede71b951 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -343,6 +343,16 @@ nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) svcxdr_encode_testrply(xdr, resp); } +int +nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) +{ + struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + return svcxdr_encode_cookie(xdr, &resp->cookie) && + svcxdr_encode_stats(xdr, resp->status); +} + int nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) { @@ -354,14 +364,3 @@ nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) *p++ = xdr_zero; /* sequence argument */ return xdr_ressize_check(rqstp, p); } - -int -nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_res *resp = rqstp->rq_resp; - - if (!(p = nlm4_encode_cookie(p, &resp->cookie))) - return 0; - *p++ = resp->status; - return xdr_ressize_check(rqstp, p); -} From 0ff5b50ab1f7f39862d0cdf6803978d31b27f25e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 3 Jun 2021 16:53:29 -0400 Subject: [PATCH 65/69] lockd: Update the NLMv4 SHARE results encoder to use struct xdr_stream Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/xdr4.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index efdede71b951..98e957e4566c 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -40,15 +40,6 @@ loff_t_to_s64(loff_t offset) return res; } -static __be32 * -nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c) -{ - *p++ = htonl(c->len); - memcpy(p, c->data, c->len); - p+=XDR_QUADLEN(c->len); - return p; -} - /* * NLM file handles are defined by specification to be a variable-length * XDR opaque no longer than 1024 bytes. However, this implementation @@ -356,11 +347,16 @@ nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) int nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) { + struct xdr_stream *xdr = &rqstp->rq_res_stream; struct nlm_res *resp = rqstp->rq_resp; - if (!(p = nlm4_encode_cookie(p, &resp->cookie))) + if (!svcxdr_encode_cookie(xdr, &resp->cookie)) return 0; - *p++ = resp->status; - *p++ = xdr_zero; /* sequence argument */ - return xdr_ressize_check(rqstp, p); + if (!svcxdr_encode_stats(xdr, resp->status)) + return 0; + /* sequence */ + if (xdr_stream_encode_u32(xdr, 0) < 0) + return 0; + + return 1; } From 474bc334698df98ce07c890f1898c7e7f389b0c7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 17 Jun 2021 19:26:52 -0400 Subject: [PATCH 66/69] nfsd: Reduce contention for the nfsd_file nf_rwsem When flushing out the unstable file writes as part of a COMMIT call, try to perform most of of the data writes and waits outside the semaphore. This means that if the client is sending the COMMIT as part of a memory reclaim operation, then it can continue performing I/O, with contention for the lock occurring only once the data sync is finished. Fixes: 5011af4c698a ("nfsd: Fix stable writes") Signed-off-by: Trond Myklebust Tested-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/vfs.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index d73d3c9126fc..a224a5e23cc1 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1123,6 +1123,19 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, } #ifdef CONFIG_NFSD_V3 +static int +nfsd_filemap_write_and_wait_range(struct nfsd_file *nf, loff_t offset, + loff_t end) +{ + struct address_space *mapping = nf->nf_file->f_mapping; + int ret = filemap_fdatawrite_range(mapping, offset, end); + + if (ret) + return ret; + filemap_fdatawait_range_keep_errors(mapping, offset, end); + return 0; +} + /* * Commit all pending writes to stable storage. * @@ -1153,10 +1166,11 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, if (err) goto out; if (EX_ISSYNC(fhp->fh_export)) { - int err2; + int err2 = nfsd_filemap_write_and_wait_range(nf, offset, end); down_write(&nf->nf_rwsem); - err2 = vfs_fsync_range(nf->nf_file, offset, end, 0); + if (!err2) + err2 = vfs_fsync_range(nf->nf_file, offset, end, 0); switch (err2) { case 0: nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net, From e34c0ce9136a0fe96f0f547898d14c44f3c9f147 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 13 May 2021 16:16:39 +0100 Subject: [PATCH 67/69] nfsd: remove redundant assignment to pointer 'this' The pointer 'this' is being initialized with a value that is never read and it is being updated later with a new value. The initialization is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index a0d67ba5ed59..486c5dba4b65 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -3374,7 +3374,7 @@ bool nfsd4_spo_must_allow(struct svc_rqst *rqstp) { struct nfsd4_compoundres *resp = rqstp->rq_resp; struct nfsd4_compoundargs *argp = rqstp->rq_argp; - struct nfsd4_op *this = &argp->ops[resp->opcnt - 1]; + struct nfsd4_op *this; struct nfsd4_compound_state *cstate = &resp->cstate; struct nfs4_op_map *allow = &cstate->clp->cl_spo_must_allow; u32 opiter; From 7b08cf62b1239a4322427d677ea9363f0ab677c6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 25 Jun 2021 11:12:49 -0400 Subject: [PATCH 68/69] NFSD: Prevent a possible oops in the nfs_dirent() tracepoint The double copy of the string is a mistake, plus __assign_str() uses strlen(), which is wrong to do on a string that isn't guaranteed to be NUL-terminated. Fixes: 6019ce0742ca ("NFSD: Add a tracepoint to record directory entry encoding") Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/trace.h | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 10cc3aaf1089..adaec43548d1 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -408,7 +408,6 @@ TRACE_EVENT(nfsd_dirent, __entry->ino = ino; __entry->len = namlen; memcpy(__get_str(name), name, namlen); - __assign_str(name, name); ), TP_printk("fh_hash=0x%08x ino=%llu name=%.*s", __entry->fh_hash, __entry->ino, From ab1016d39cc052064e32f25ad18ef8767a0ee3b8 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 1 Jul 2021 20:06:56 -0400 Subject: [PATCH 69/69] nfsd: fix NULL dereference in nfs3svc_encode_getaclres In error cases the dentry may be NULL. Before 20798dfe249a, the encoder also checked dentry and d_really_is_positive(dentry), but that looks like overkill to me--zero status should be enough to guarantee a positive dentry. This isn't the first time we've seen an error-case NULL dereference hidden in the initialization of a local variable in an xdr encoder. But I went back through the other recent rewrites and didn't spot any similar bugs. Reported-by: JianHong Yin Reviewed-by: Chuck Lever III Fixes: 20798dfe249a ("NFSD: Update the NFSv3 GETACL result encoder...") Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs3acl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index a1591feeea22..5dfe7644a517 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -172,7 +172,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) struct nfsd3_getaclres *resp = rqstp->rq_resp; struct dentry *dentry = resp->fh.fh_dentry; struct kvec *head = rqstp->rq_res.head; - struct inode *inode = d_inode(dentry); + struct inode *inode; unsigned int base; int n; int w; @@ -181,6 +181,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) return 0; switch (resp->status) { case nfs_ok: + inode = d_inode(dentry); if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) return 0; if (xdr_stream_encode_u32(xdr, resp->mask) < 0)