xref: /linux/fs/nfsd/nfssvc.c (revision a01c9fe32378636ae65bec8047b5de3fdb2ba5c8)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Central processing for nfsd.
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Authors:	Olaf Kirch (okir@monad.swb.de)
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
103f07c014SIngo Molnar #include <linux/sched/signal.h>
1183144186SRafael J. Wysocki #include <linux/freezer.h>
12143cb494SPaul Gortmaker #include <linux/module.h>
131da177e4SLinus Torvalds #include <linux/fs_struct.h>
14c3d06f9cSAndy Adamson #include <linux/swap.h>
1591d2e9b5SChuck Lever #include <linux/siphash.h>
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds #include <linux/sunrpc/stats.h>
181da177e4SLinus Torvalds #include <linux/sunrpc/svcsock.h>
1936684996SScott Mayhew #include <linux/sunrpc/svc_xprt.h>
201da177e4SLinus Torvalds #include <linux/lockd/bind.h>
21a257cdd0SAndreas Gruenbacher #include <linux/nfsacl.h>
22ed2d8aedSRyusei Yamaguchi #include <linux/nfslocalio.h>
2336684996SScott Mayhew #include <linux/seq_file.h>
2436684996SScott Mayhew #include <linux/inetdevice.h>
2536684996SScott Mayhew #include <net/addrconf.h>
26fc5d00b0SPavel Emelyanov #include <net/ipv6.h>
279a74af21SBoaz Harrosh #include <net/net_namespace.h>
289a74af21SBoaz Harrosh #include "nfsd.h"
290a3adadeSJ. Bruce Fields #include "cache.h"
302c2fe290SStanislav Kinsbursky #include "vfs.h"
3165294c1fSJeff Layton #include "netns.h"
321da177e4SLinus Torvalds #include "filecache.h"
330dfdad1cSChuck Lever 
340dfdad1cSChuck Lever #include "trace.h"
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #define NFSDDBG_FACILITY	NFSDDBG_SVC
37e41ee44cSJosef Bacik 
381da177e4SLinus Torvalds atomic_t			nfsd_th_cnt = ATOMIC_INIT(0);
399867d76cSJeff Layton static int			nfsd(void *vrqstp);
40029be5d0STrond Myklebust #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
41029be5d0STrond Myklebust static int			nfsd_acl_rpcbind_set(struct net *,
42029be5d0STrond Myklebust 						     const struct svc_program *,
43029be5d0STrond Myklebust 						     u32, int,
44029be5d0STrond Myklebust 						     unsigned short,
45029be5d0STrond Myklebust 						     unsigned short);
46e333f3bbSTrond Myklebust static __be32			nfsd_acl_init_request(struct svc_rqst *,
47e333f3bbSTrond Myklebust 						const struct svc_program *,
48e333f3bbSTrond Myklebust 						struct svc_process_info *);
49029be5d0STrond Myklebust #endif
50029be5d0STrond Myklebust static int			nfsd_rpcbind_set(struct net *,
51029be5d0STrond Myklebust 						 const struct svc_program *,
52029be5d0STrond Myklebust 						 u32, int,
53029be5d0STrond Myklebust 						 unsigned short,
54029be5d0STrond Myklebust 						 unsigned short);
55e333f3bbSTrond Myklebust static __be32			nfsd_init_request(struct svc_rqst *,
56e333f3bbSTrond Myklebust 						const struct svc_program *,
57e333f3bbSTrond Myklebust 						struct svc_process_info *);
581da177e4SLinus Torvalds 
59bedbdd8bSNeil Brown /*
602a36395fSNeilBrown  * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and some members
612a36395fSNeilBrown  * of the svc_serv struct such as ->sv_temp_socks and ->sv_permsocks.
62bedbdd8bSNeil Brown  *
633dd98a3bSJeff Layton  * Finally, the nfsd_mutex also protects some of the global variables that are
643dd98a3bSJeff Layton  * accessed when nfsd starts and that are settable via the write_* routines in
653dd98a3bSJeff Layton  * nfsctl.c. In particular:
663dd98a3bSJeff Layton  *
673dd98a3bSJeff Layton  *	user_recovery_dirname
683dd98a3bSJeff Layton  *	user_lease_time
693dd98a3bSJeff Layton  *	nfsd_versions
70bedbdd8bSNeil Brown  */
71bedbdd8bSNeil Brown DEFINE_MUTEX(nfsd_mutex);
72bedbdd8bSNeil Brown 
734bd9b0f4SAndy Adamson #if IS_ENABLED(CONFIG_NFS_LOCALIO)
744bd9b0f4SAndy Adamson static const struct svc_version *localio_versions[] = {
754bd9b0f4SAndy Adamson 	[1] = &localio_version1,
764bd9b0f4SAndy Adamson };
774bd9b0f4SAndy Adamson 
784bd9b0f4SAndy Adamson #define NFSD_LOCALIO_NRVERS		ARRAY_SIZE(localio_versions)
79b73ac680SGuobin Huang 
80697ce9beSZhang Yanfei #endif /* CONFIG_NFS_LOCALIO */
81697ce9beSZhang Yanfei 
824bd9b0f4SAndy Adamson #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
833fb803a9SAndreas Gruenbacher static const struct svc_version *nfsd_acl_version[] = {
84e9679189SChristoph Hellwig # if defined(CONFIG_NFSD_V2_ACL)
852f3a4b2aSJeff Layton 	[2] = &nfsd_acl_version2,
863fb803a9SAndreas Gruenbacher # endif
872f3a4b2aSJeff Layton # if defined(CONFIG_NFSD_V3_ACL)
882f3a4b2aSJeff Layton 	[3] = &nfsd_acl_version3,
893fb803a9SAndreas Gruenbacher # endif
902f3a4b2aSJeff Layton };
913fb803a9SAndreas Gruenbacher 
923fb803a9SAndreas Gruenbacher #define NFSD_ACL_MINVERS	2
933fb803a9SAndreas Gruenbacher #define NFSD_ACL_NRVERS		ARRAY_SIZE(nfsd_acl_version)
94e8c96f8cSTobias Klauser 
953fb803a9SAndreas Gruenbacher #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
963fb803a9SAndreas Gruenbacher 
973fb803a9SAndreas Gruenbacher static const struct svc_version *nfsd_version[NFSD_MAXVERS+1] = {
983fb803a9SAndreas Gruenbacher #if defined(CONFIG_NFSD_V2)
997c149057SJ. Bruce Fields 	[2] = &nfsd_version2,
1001a8eff6dSNeilBrown #endif
1013fb803a9SAndreas Gruenbacher 	[3] = &nfsd_version3,
1023fb803a9SAndreas Gruenbacher #if defined(CONFIG_NFSD_V4)
103e333f3bbSTrond Myklebust 	[4] = &nfsd_version4,
104029be5d0STrond Myklebust #endif
1053fb803a9SAndreas Gruenbacher };
1063fb803a9SAndreas Gruenbacher 
1073fb803a9SAndreas Gruenbacher struct svc_program		nfsd_programs[] = {
1083fb803a9SAndreas Gruenbacher 	{
109e9679189SChristoph Hellwig 	.pg_prog		= NFS_PROGRAM,		/* program number */
1102f3a4b2aSJeff Layton 	.pg_nvers		= NFSD_MAXVERS+1,	/* nr of entries in nfsd_version */
11170c3b76cSNeilBrown 	.pg_vers		= nfsd_version,		/* version table */
1122f3a4b2aSJeff Layton 	.pg_name		= "nfsd",		/* program name */
11370c3b76cSNeilBrown 	.pg_class		= "nfsd",		/* authentication class */
11470c3b76cSNeilBrown 	.pg_authenticate	= svc_set_client,	/* export authentication */
11570c3b76cSNeilBrown 	.pg_init_request	= nfsd_init_request,
11670c3b76cSNeilBrown 	.pg_rpcbind_set		= nfsd_rpcbind_set,
11770c3b76cSNeilBrown 	},
11870c3b76cSNeilBrown #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
11970c3b76cSNeilBrown 	{
120e8c96f8cSTobias Klauser 	.pg_prog		= NFS_ACL_PROGRAM,
12170c3b76cSNeilBrown 	.pg_nvers		= NFSD_ACL_NRVERS,
12270c3b76cSNeilBrown 	.pg_vers		= nfsd_acl_version,
1233fb803a9SAndreas Gruenbacher 	.pg_name		= "nfsacl",
1243fb803a9SAndreas Gruenbacher 	.pg_class		= "nfsd",
1253fb803a9SAndreas Gruenbacher 	.pg_authenticate	= svc_set_client,
12670c3b76cSNeilBrown 	.pg_init_request	= nfsd_acl_init_request,
12770c3b76cSNeilBrown 	.pg_rpcbind_set		= nfsd_acl_rpcbind_set,
128e333f3bbSTrond Myklebust 	},
12970c3b76cSNeilBrown #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
13070c3b76cSNeilBrown #if IS_ENABLED(CONFIG_NFS_LOCALIO)
13170c3b76cSNeilBrown 	{
132e333f3bbSTrond Myklebust 	.pg_prog		= NFS_LOCALIO_PROGRAM,
133029be5d0STrond Myklebust 	.pg_nvers		= NFSD_LOCALIO_NRVERS,
13470c3b76cSNeilBrown 	.pg_vers		= localio_versions,
13570c3b76cSNeilBrown 	.pg_name		= "nfslocalio",
136e333f3bbSTrond Myklebust 	.pg_class		= "nfsd",
137e333f3bbSTrond Myklebust 	.pg_authenticate	= svc_set_client,
138e333f3bbSTrond Myklebust 	.pg_init_request	= svc_generic_init_request,
139e333f3bbSTrond Myklebust 	.pg_rpcbind_set		= svc_generic_rpcbind_set,
140e333f3bbSTrond Myklebust 	}
141e333f3bbSTrond Myklebust #endif /* CONFIG_NFS_LOCALIO */
142e333f3bbSTrond Myklebust };
1438daf220aSBenny Halevy 
nfsd_support_version(int vers)144e333f3bbSTrond Myklebust bool nfsd_support_version(int vers)
145e333f3bbSTrond Myklebust {
146e333f3bbSTrond Myklebust 	if (vers >= NFSD_MINVERS && vers <= NFSD_MAXVERS)
147e333f3bbSTrond Myklebust 		return nfsd_version[vers] != NULL;
148e333f3bbSTrond Myklebust 	return false;
149e333f3bbSTrond Myklebust }
150e333f3bbSTrond Myklebust 
nfsd_vers(struct nfsd_net * nn,int vers,enum vers_op change)151e333f3bbSTrond Myklebust int nfsd_vers(struct nfsd_net *nn, int vers, enum vers_op change)
152e333f3bbSTrond Myklebust {
153e333f3bbSTrond Myklebust 	if (vers < NFSD_MINVERS || vers > NFSD_MAXVERS)
154e333f3bbSTrond Myklebust 		return 0;
155e333f3bbSTrond Myklebust 	switch(change) {
156e333f3bbSTrond Myklebust 	case NFSD_SET:
157e333f3bbSTrond Myklebust 		nn->nfsd_versions[vers] = nfsd_support_version(vers);
158e333f3bbSTrond Myklebust 		break;
159e333f3bbSTrond Myklebust 	case NFSD_CLEAR:
160e333f3bbSTrond Myklebust 		nn->nfsd_versions[vers] = false;
161e333f3bbSTrond Myklebust 		break;
162e333f3bbSTrond Myklebust 	case NFSD_TEST:
163e333f3bbSTrond Myklebust 		return nn->nfsd_versions[vers];
164e333f3bbSTrond Myklebust 	case NFSD_AVAIL:
165e333f3bbSTrond Myklebust 		return nfsd_support_version(vers);
166e333f3bbSTrond Myklebust 	}
167e333f3bbSTrond Myklebust 	return 0;
168e333f3bbSTrond Myklebust }
169e333f3bbSTrond Myklebust 
170e333f3bbSTrond Myklebust static void
nfsd_adjust_nfsd_versions4(struct nfsd_net * nn)171e333f3bbSTrond Myklebust nfsd_adjust_nfsd_versions4(struct nfsd_net *nn)
172e333f3bbSTrond Myklebust {
173e333f3bbSTrond Myklebust 	unsigned i;
174e333f3bbSTrond Myklebust 
175e333f3bbSTrond Myklebust 	for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++) {
176e333f3bbSTrond Myklebust 		if (nn->nfsd4_minorversions[i])
177e333f3bbSTrond Myklebust 			return;
178e333f3bbSTrond Myklebust 	}
179e333f3bbSTrond Myklebust 	nfsd_vers(nn, 4, NFSD_CLEAR);
180e333f3bbSTrond Myklebust }
181e333f3bbSTrond Myklebust 
nfsd_minorversion(struct nfsd_net * nn,u32 minorversion,enum vers_op change)182e333f3bbSTrond Myklebust int nfsd_minorversion(struct nfsd_net *nn, u32 minorversion, enum vers_op change)
183e333f3bbSTrond Myklebust {
184e333f3bbSTrond Myklebust 	if (minorversion > NFSD_SUPPORTED_MINOR_VERSION &&
185e333f3bbSTrond Myklebust 	    change != NFSD_AVAIL)
186e333f3bbSTrond Myklebust 		return -1;
187e333f3bbSTrond Myklebust 
188e333f3bbSTrond Myklebust 	switch(change) {
189e333f3bbSTrond Myklebust 	case NFSD_SET:
190e333f3bbSTrond Myklebust 		nfsd_vers(nn, 4, NFSD_SET);
191e333f3bbSTrond Myklebust 		nn->nfsd4_minorversions[minorversion] =
192e333f3bbSTrond Myklebust 			nfsd_vers(nn, 4, NFSD_TEST);
193e333f3bbSTrond Myklebust 		break;
1946658d3a7SNeilBrown 	case NFSD_CLEAR:
1956658d3a7SNeilBrown 		nn->nfsd4_minorversions[minorversion] = false;
19615ddb4aeSPavel Emelyanov 		nfsd_adjust_nfsd_versions4(nn);
1976658d3a7SNeilBrown 		break;
1986658d3a7SNeilBrown 	case NFSD_TEST:
199e333f3bbSTrond Myklebust 		return nn->nfsd4_minorversions[minorversion];
200e333f3bbSTrond Myklebust 	case NFSD_AVAIL:
2011a8eff6dSNeilBrown 		return minorversion <= NFSD_SUPPORTED_MINOR_VERSION &&
2026658d3a7SNeilBrown 			nfsd_vers(nn, 4, NFSD_AVAIL);
203e333f3bbSTrond Myklebust 	}
204e333f3bbSTrond Myklebust 	return 0;
205e333f3bbSTrond Myklebust }
2066658d3a7SNeilBrown 
nfsd_net_try_get(struct net * net)2076658d3a7SNeilBrown bool nfsd_net_try_get(struct net *net) __must_hold(rcu)
208e333f3bbSTrond Myklebust {
209e333f3bbSTrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
210df561f66SGustavo A. R. Silva 
2116658d3a7SNeilBrown 	return (nn && percpu_ref_tryget_live(&nn->nfsd_net_ref));
212e333f3bbSTrond Myklebust }
2136658d3a7SNeilBrown 
nfsd_net_put(struct net * net)2146658d3a7SNeilBrown void nfsd_net_put(struct net *net) __must_hold(rcu)
2156658d3a7SNeilBrown {
2168daf220aSBenny Halevy 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
217d3635ff0STrond Myklebust 
218e333f3bbSTrond Myklebust 	percpu_ref_put(&nn->nfsd_net_ref);
219d3635ff0STrond Myklebust }
220d3635ff0STrond Myklebust 
nfsd_net_done(struct percpu_ref * ref)221d3635ff0STrond Myklebust static void nfsd_net_done(struct percpu_ref *ref)
222d3635ff0STrond Myklebust {
223e333f3bbSTrond Myklebust 	struct nfsd_net *nn = container_of(ref, struct nfsd_net, nfsd_net_ref);
224d3635ff0STrond Myklebust 
225d3635ff0STrond Myklebust 	complete(&nn->nfsd_net_confirm_done);
226e333f3bbSTrond Myklebust }
227d3635ff0STrond Myklebust 
nfsd_net_free(struct percpu_ref * ref)228d3635ff0STrond Myklebust static void nfsd_net_free(struct percpu_ref *ref)
229e333f3bbSTrond Myklebust {
2308daf220aSBenny Halevy 	struct nfsd_net *nn = container_of(ref, struct nfsd_net, nfsd_net_ref);
231928c6fb3SNeilBrown 
232928c6fb3SNeilBrown 	complete(&nn->nfsd_net_free_done);
2338daf220aSBenny Halevy }
234e333f3bbSTrond Myklebust 
2358daf220aSBenny Halevy /*
2368daf220aSBenny Halevy  * Maximum number of nfsd processes
237e333f3bbSTrond Myklebust  */
238e333f3bbSTrond Myklebust #define	NFSD_MAXSERVS		8192
239e333f3bbSTrond Myklebust 
nfsd_nrthreads(struct net * net)240e333f3bbSTrond Myklebust int nfsd_nrthreads(struct net *net)
241e333f3bbSTrond Myklebust {
2428daf220aSBenny Halevy 	int rv = 0;
2438daf220aSBenny Halevy 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
244e333f3bbSTrond Myklebust 
245e333f3bbSTrond Myklebust 	mutex_lock(&nfsd_mutex);
246e333f3bbSTrond Myklebust 	if (nn->nfsd_serv)
247e333f3bbSTrond Myklebust 		rv = nn->nfsd_serv->sv_nrthreads;
248e333f3bbSTrond Myklebust 	mutex_unlock(&nfsd_mutex);
2498daf220aSBenny Halevy 	return rv;
2508daf220aSBenny Halevy }
251e333f3bbSTrond Myklebust 
nfsd_init_socks(struct net * net,const struct cred * cred)252e333f3bbSTrond Myklebust static int nfsd_init_socks(struct net *net, const struct cred *cred)
253e333f3bbSTrond Myklebust {
2548daf220aSBenny Halevy 	int error;
255e333f3bbSTrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
256e333f3bbSTrond Myklebust 
2578daf220aSBenny Halevy 	if (!list_empty(&nn->nfsd_serv->sv_permsocks))
2588daf220aSBenny Halevy 		return 0;
2598daf220aSBenny Halevy 
2608daf220aSBenny Halevy 	error = svc_xprt_create(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT,
2611da177e4SLinus Torvalds 				SVC_SOCK_DEFAULTS, cred);
2621da177e4SLinus Torvalds 	if (error < 0)
2631da177e4SLinus Torvalds 		return error;
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds 	error = svc_xprt_create(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT,
2669dd9845fSStanislav Kinsbursky 				SVC_SOCK_DEFAULTS, cred);
2671da177e4SLinus Torvalds 	if (error < 0)
268c7d106c9SNeil Brown 		return error;
2699dd9845fSStanislav Kinsbursky 
2709dd9845fSStanislav Kinsbursky 	return 0;
271c7d106c9SNeil Brown }
2729dd9845fSStanislav Kinsbursky 
2739dd9845fSStanislav Kinsbursky static int nfsd_users = 0;
274c7d106c9SNeil Brown 
nfsd_startup_generic(void)275c7d106c9SNeil Brown static int nfsd_startup_generic(void)
2761da177e4SLinus Torvalds {
2771da177e4SLinus Torvalds 	int ret;
2784df493a2STrond Myklebust 
27959db4a0cSJ. Bruce Fields 	if (nfsd_users++)
28059db4a0cSJ. Bruce Fields 		return 0;
2819dd9845fSStanislav Kinsbursky 
2829dd9845fSStanislav Kinsbursky 	ret = nfsd_file_cache_init();
2839dd9845fSStanislav Kinsbursky 	if (ret)
28459db4a0cSJ. Bruce Fields 		goto dec_users;
28559db4a0cSJ. Bruce Fields 
286352ad314SChuck Lever 	ret = nfs4_state_start();
2874df493a2STrond Myklebust 	if (ret)
28859db4a0cSJ. Bruce Fields 		goto out_file_cache;
28959db4a0cSJ. Bruce Fields 	return 0;
29059db4a0cSJ. Bruce Fields 
291352ad314SChuck Lever out_file_cache:
2924df493a2STrond Myklebust 	nfsd_file_cache_shutdown();
29359db4a0cSJ. Bruce Fields dec_users:
29459db4a0cSJ. Bruce Fields 	nfsd_users--;
29559db4a0cSJ. Bruce Fields 	return ret;
29659db4a0cSJ. Bruce Fields }
29759db4a0cSJ. Bruce Fields 
nfsd_shutdown_generic(void)29859db4a0cSJ. Bruce Fields static void nfsd_shutdown_generic(void)
2994539f149SStanislav Kinsbursky {
3004ad9a344SJeff Layton 	if (--nfsd_users)
30170c53075SVasily Averin 		return;
302bda9cac1SStanislav Kinsbursky 
303bda9cac1SStanislav Kinsbursky 	nfs4_state_shutdown();
304bda9cac1SStanislav Kinsbursky 	nfsd_file_cache_shutdown();
3054539f149SStanislav Kinsbursky }
306bda9cac1SStanislav Kinsbursky 
nfsd_needs_lockd(struct nfsd_net * nn)307bda9cac1SStanislav Kinsbursky static bool nfsd_needs_lockd(struct nfsd_net *nn)
30865294c1fSJeff Layton {
30965294c1fSJeff Layton 	return nfsd_vers(nn, 2, NFSD_TEST) || nfsd_vers(nn, 3, NFSD_TEST);
31065294c1fSJeff Layton }
311d9499a95SKinglong Mee 
312bda9cac1SStanislav Kinsbursky /**
313bda9cac1SStanislav Kinsbursky  * nfsd_copy_write_verifier - Atomically copy a write verifier
314501cb184SJeff Layton  * @verf: buffer in which to receive the verifier cookie
315bda9cac1SStanislav Kinsbursky  * @nn: NFS net namespace
316bda9cac1SStanislav Kinsbursky  *
31765294c1fSJeff Layton  * This function provides a wait-free mechanism for copying the
31865294c1fSJeff Layton  * namespace's write verifier without tearing it.
319d9499a95SKinglong Mee  */
nfsd_copy_write_verifier(__be32 verf[2],struct nfsd_net * nn)320d9499a95SKinglong Mee void nfsd_copy_write_verifier(__be32 verf[2], struct nfsd_net *nn)
321bda9cac1SStanislav Kinsbursky {
322bda9cac1SStanislav Kinsbursky 	unsigned int seq;
323bda9cac1SStanislav Kinsbursky 
324bda9cac1SStanislav Kinsbursky 	do {
325bda9cac1SStanislav Kinsbursky 		seq = read_seqbegin(&nn->writeverf_lock);
3264539f149SStanislav Kinsbursky 		memcpy(verf, nn->writeverf, sizeof(nn->writeverf));
3274539f149SStanislav Kinsbursky 	} while (read_seqretry(&nn->writeverf_lock, seq));
3284539f149SStanislav Kinsbursky }
329bda9cac1SStanislav Kinsbursky 
nfsd_reset_write_verifier_locked(struct nfsd_net * nn)33065294c1fSJeff Layton static void nfsd_reset_write_verifier_locked(struct nfsd_net *nn)
331bda9cac1SStanislav Kinsbursky {
332bda9cac1SStanislav Kinsbursky 	struct timespec64 now;
333e333f3bbSTrond Myklebust 	u64 verf;
3348ef66714SKinglong Mee 
335e333f3bbSTrond Myklebust 	/*
3368ef66714SKinglong Mee 	 * Because the time value is hashed, y2038 time_t overflow
3378ef66714SKinglong Mee 	 * is irrelevant in this usage.
33891d2e9b5SChuck Lever 	 */
3393988a578SChuck Lever 	ktime_get_raw_ts64(&now);
34091d2e9b5SChuck Lever 	verf = siphash_2u64(now.tv_sec, now.tv_nsec, &nn->siphash_key);
34191d2e9b5SChuck Lever 	memcpy(nn->writeverf, &verf, sizeof(nn->writeverf));
34291d2e9b5SChuck Lever }
34391d2e9b5SChuck Lever 
3443988a578SChuck Lever /**
34591d2e9b5SChuck Lever  * nfsd_reset_write_verifier - Generate a new write verifier
3463988a578SChuck Lever  * @nn: NFS net namespace
34727c438f5STrond Myklebust  *
348f3734cc4SOleg Nesterov  * This function updates the ->writeverf field of @nn. This field
34927c438f5STrond Myklebust  * contains an opaque cookie that, according to Section 18.32.3 of
35027c438f5STrond Myklebust  * RFC 8881, "the client can use to determine whether a server has
351f3734cc4SOleg Nesterov  * changed instance state (e.g., server restart) between a call to
35290d21755SChuck Lever  * WRITE and a subsequent call to either WRITE or COMMIT.  This
353f3734cc4SOleg Nesterov  * cookie MUST be unchanged during a single instance of the NFSv4.1
35427c438f5STrond Myklebust  * server and MUST be unique between instances of the NFSv4.1
35527c438f5STrond Myklebust  * server."
3563988a578SChuck Lever  */
nfsd_reset_write_verifier(struct nfsd_net * nn)35727c438f5STrond Myklebust void nfsd_reset_write_verifier(struct nfsd_net *nn)
35891d2e9b5SChuck Lever {
35991d2e9b5SChuck Lever 	write_seqlock(&nn->writeverf_lock);
36091d2e9b5SChuck Lever 	nfsd_reset_write_verifier_locked(nn);
36191d2e9b5SChuck Lever 	write_sequnlock(&nn->writeverf_lock);
36291d2e9b5SChuck Lever }
36391d2e9b5SChuck Lever 
36491d2e9b5SChuck Lever /*
36591d2e9b5SChuck Lever  * Crank up a set of per-namespace resources for a new NFSD instance,
36691d2e9b5SChuck Lever  * including lockd, a duplicate reply cache, an open file cache
36791d2e9b5SChuck Lever  * instance, and a cache of NFSv4 state objects.
36827c438f5STrond Myklebust  */
nfsd_startup_net(struct net * net,const struct cred * cred)36927c438f5STrond Myklebust static int nfsd_startup_net(struct net *net, const struct cred *cred)
37091d2e9b5SChuck Lever {
3713988a578SChuck Lever 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
37291d2e9b5SChuck Lever 	int ret;
37391d2e9b5SChuck Lever 
37491d2e9b5SChuck Lever 	if (nn->nfsd_net_up)
37591d2e9b5SChuck Lever 		return 0;
37691d2e9b5SChuck Lever 
37791d2e9b5SChuck Lever 	ret = nfsd_startup_generic();
37891d2e9b5SChuck Lever 	if (ret)
37991d2e9b5SChuck Lever 		return ret;
38091d2e9b5SChuck Lever 	ret = nfsd_init_socks(net, cred);
38191d2e9b5SChuck Lever 	if (ret)
38291d2e9b5SChuck Lever 		goto out_socks;
3833988a578SChuck Lever 
38427c438f5STrond Myklebust 	if (nfsd_needs_lockd(nn) && !nn->lockd_up) {
38591d2e9b5SChuck Lever 		ret = lockd_up(net, cred);
3863988a578SChuck Lever 		if (ret)
38791d2e9b5SChuck Lever 			goto out_socks;
38827c438f5STrond Myklebust 		nn->lockd_up = true;
38927c438f5STrond Myklebust 	}
3905e092be7SChuck Lever 
3915e092be7SChuck Lever 	ret = nfsd_file_cache_start_net(net);
3925e092be7SChuck Lever 	if (ret)
3935e092be7SChuck Lever 		goto out_lockd;
3945e092be7SChuck Lever 
39570c53075SVasily Averin 	ret = nfsd_reply_cache_init(nn);
3966ff50b3dSStanislav Kinsbursky 	if (ret)
3972c2fe290SStanislav Kinsbursky 		goto out_filecache;
3986ff50b3dSStanislav Kinsbursky 
3996ff50b3dSStanislav Kinsbursky #ifdef CONFIG_NFSD_V4_2_INTER_SSC
4002c2fe290SStanislav Kinsbursky 	nfsd4_ssc_init_umount_work(nn);
4012c2fe290SStanislav Kinsbursky #endif
4022c2fe290SStanislav Kinsbursky 	ret = nfs4_state_start_net(net);
40370c53075SVasily Averin 	if (ret)
404903d9bf0SStanislav Kinsbursky 		goto out_reply_cache;
405903d9bf0SStanislav Kinsbursky 
4064df493a2STrond Myklebust 	nn->nfsd_net_up = true;
4076ff50b3dSStanislav Kinsbursky 	return 0;
408903d9bf0SStanislav Kinsbursky 
4098ef66714SKinglong Mee out_reply_cache:
410e333f3bbSTrond Myklebust 	nfsd_reply_cache_shutdown(nn);
41140373b12STrond Myklebust out_filecache:
4126ff50b3dSStanislav Kinsbursky 	nfsd_file_cache_shutdown_net(net);
413903d9bf0SStanislav Kinsbursky out_lockd:
414e44b4bf2Szhengbin 	if (nn->lockd_up) {
4158ef66714SKinglong Mee 		lockd_down(net);
4168ef66714SKinglong Mee 		nn->lockd_up = false;
4179542e6a6STrond Myklebust 	}
4186ff50b3dSStanislav Kinsbursky out_socks:
4196ff50b3dSStanislav Kinsbursky 	nfsd_shutdown_generic();
420f5f9d4a3SJeff Layton 	return ret;
421f5f9d4a3SJeff Layton }
4229542e6a6STrond Myklebust 
nfsd_shutdown_net(struct net * net)4239542e6a6STrond Myklebust static void nfsd_shutdown_net(struct net *net)
4246ff50b3dSStanislav Kinsbursky {
425f5f9d4a3SJeff Layton 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
426f5f9d4a3SJeff Layton 
427f5f9d4a3SJeff Layton 	if (!nn->nfsd_net_up)
428f5f9d4a3SJeff Layton 		return;
429f4e44b39SDai Ngo 
430f4e44b39SDai Ngo 	percpu_ref_kill_and_confirm(&nn->nfsd_net_ref, nfsd_net_done);
431f4e44b39SDai Ngo 	wait_for_completion(&nn->nfsd_net_confirm_done);
4322c2fe290SStanislav Kinsbursky 
4336ff50b3dSStanislav Kinsbursky 	nfsd_export_flush(net);
4346ff50b3dSStanislav Kinsbursky 	nfs4_state_shutdown_net(net);
435f5f9d4a3SJeff Layton 	nfsd_reply_cache_shutdown(nn);
436f5f9d4a3SJeff Layton 	nfsd_file_cache_shutdown_net(net);
4379542e6a6STrond Myklebust 	if (nn->lockd_up) {
4389542e6a6STrond Myklebust 		lockd_down(net);
4396ff50b3dSStanislav Kinsbursky 		nn->lockd_up = false;
4408ef66714SKinglong Mee 	}
4416ff50b3dSStanislav Kinsbursky 
442e44b4bf2Szhengbin 	wait_for_completion(&nn->nfsd_net_free_done);
4438ef66714SKinglong Mee 	percpu_ref_exit(&nn->nfsd_net_ref);
444903d9bf0SStanislav Kinsbursky 
445bda9cac1SStanislav Kinsbursky 	nn->nfsd_net_up = false;
4464ad9a344SJeff Layton 	nfsd_shutdown_generic();
4474ad9a344SJeff Layton }
4484ad9a344SJeff Layton 
4496ff50b3dSStanislav Kinsbursky static DEFINE_SPINLOCK(nfsd_notifier_lock);
nfsd_inetaddr_event(struct notifier_block * this,unsigned long event,void * ptr)4506ff50b3dSStanislav Kinsbursky static int nfsd_inetaddr_event(struct notifier_block *this, unsigned long event,
4512c2fe290SStanislav Kinsbursky 	void *ptr)
4522c2fe290SStanislav Kinsbursky {
4536ff50b3dSStanislav Kinsbursky 	struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
454f5f9d4a3SJeff Layton 	struct net_device *dev = ifa->ifa_dev->dev;
455789e1e10SJeff Layton 	struct net *net = dev_net(dev);
4568ef66714SKinglong Mee 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
4576ff50b3dSStanislav Kinsbursky 	struct sockaddr_in sin;
458e44b4bf2Szhengbin 
4598ef66714SKinglong Mee 	if (event != NETDEV_DOWN || !nn->nfsd_serv)
4602c2fe290SStanislav Kinsbursky 		goto out;
461903d9bf0SStanislav Kinsbursky 
4626ff50b3dSStanislav Kinsbursky 	spin_lock(&nfsd_notifier_lock);
4636ff50b3dSStanislav Kinsbursky 	if (nn->nfsd_serv) {
464d057cfecSNeilBrown 		dprintk("nfsd_inetaddr_event: removed %pI4\n", &ifa->ifa_local);
46536684996SScott Mayhew 		sin.sin_family = AF_INET;
46636684996SScott Mayhew 		sin.sin_addr.s_addr = ifa->ifa_local;
46736684996SScott Mayhew 		svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin);
46836684996SScott Mayhew 	}
46936684996SScott Mayhew 	spin_unlock(&nfsd_notifier_lock);
47036684996SScott Mayhew 
47136684996SScott Mayhew out:
47236684996SScott Mayhew 	return NOTIFY_DONE;
47336684996SScott Mayhew }
474d057cfecSNeilBrown 
47536684996SScott Mayhew static struct notifier_block nfsd_inetaddr_notifier = {
47636684996SScott Mayhew 	.notifier_call = nfsd_inetaddr_event,
477d057cfecSNeilBrown };
47836684996SScott Mayhew 
47936684996SScott Mayhew #if IS_ENABLED(CONFIG_IPV6)
nfsd_inet6addr_event(struct notifier_block * this,unsigned long event,void * ptr)48036684996SScott Mayhew static int nfsd_inet6addr_event(struct notifier_block *this,
48136684996SScott Mayhew 	unsigned long event, void *ptr)
48236684996SScott Mayhew {
48336684996SScott Mayhew 	struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
484d057cfecSNeilBrown 	struct net_device *dev = ifa->idev->dev;
48536684996SScott Mayhew 	struct net *net = dev_net(dev);
48636684996SScott Mayhew 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
48736684996SScott Mayhew 	struct sockaddr_in6 sin6;
48836684996SScott Mayhew 
48936684996SScott Mayhew 	if (event != NETDEV_DOWN || !nn->nfsd_serv)
49036684996SScott Mayhew 		goto out;
49136684996SScott Mayhew 
49236684996SScott Mayhew 	spin_lock(&nfsd_notifier_lock);
49336684996SScott Mayhew 	if (nn->nfsd_serv) {
49436684996SScott Mayhew 		dprintk("nfsd_inet6addr_event: removed %pI6\n", &ifa->addr);
49536684996SScott Mayhew 		sin6.sin6_family = AF_INET6;
49636684996SScott Mayhew 		sin6.sin6_addr = ifa->addr;
49736684996SScott Mayhew 		if (ipv6_addr_type(&sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
49836684996SScott Mayhew 			sin6.sin6_scope_id = ifa->idev->dev->ifindex;
49936684996SScott Mayhew 		svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin6);
50036684996SScott Mayhew 	}
50136684996SScott Mayhew 	spin_unlock(&nfsd_notifier_lock);
50236684996SScott Mayhew 
50336684996SScott Mayhew out:
504d057cfecSNeilBrown 	return NOTIFY_DONE;
50536684996SScott Mayhew }
50636684996SScott Mayhew 
507d057cfecSNeilBrown static struct notifier_block nfsd_inet6addr_notifier = {
50836684996SScott Mayhew 	.notifier_call = nfsd_inet6addr_event,
50936684996SScott Mayhew };
51036684996SScott Mayhew #endif
51136684996SScott Mayhew 
5127b19824dSScott Mayhew /* Only used under nfsd_mutex, so this atomic may be overkill: */
5137b19824dSScott Mayhew static atomic_t nfsd_notifier_refcount = ATOMIC_INIT(0);
51436684996SScott Mayhew 
51536684996SScott Mayhew /**
516d057cfecSNeilBrown  * nfsd_destroy_serv - tear down NFSD's svc_serv for a namespace
517d057cfecSNeilBrown  * @net: network namespace the NFS service is associated with
51836684996SScott Mayhew  */
nfsd_destroy_serv(struct net * net)51936684996SScott Mayhew void nfsd_destroy_serv(struct net *net)
52036684996SScott Mayhew {
52136684996SScott Mayhew 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
52236684996SScott Mayhew 	struct svc_serv *serv = nn->nfsd_serv;
52336684996SScott Mayhew 
52436684996SScott Mayhew 	lockdep_assert_held(&nfsd_mutex);
52536684996SScott Mayhew 
52636684996SScott Mayhew 	spin_lock(&nfsd_notifier_lock);
5271eca45f8SVasily Averin 	nn->nfsd_serv = NULL;
5281eca45f8SVasily Averin 	spin_unlock(&nfsd_notifier_lock);
5291eca45f8SVasily Averin 
53017419aefSNeilBrown 	/* check if the notifier still has clients */
53117419aefSNeilBrown 	if (atomic_dec_return(&nfsd_notifier_refcount) == 0) {
53217419aefSNeilBrown 		unregister_inetaddr_notifier(&nfsd_inetaddr_notifier);
53317419aefSNeilBrown #if IS_ENABLED(CONFIG_IPV6)
53417419aefSNeilBrown 		unregister_inet6addr_notifier(&nfsd_inet6addr_notifier);
5354ad9a344SJeff Layton #endif
536903d9bf0SStanislav Kinsbursky 	}
5379f28a971SNeilBrown 
5389f28a971SNeilBrown 	/*
5399f28a971SNeilBrown 	 * write_ports can create the server without actually starting
5409f28a971SNeilBrown 	 * any threads.  If we get shut down before any threads are
5419f28a971SNeilBrown 	 * started, then nfsd_destroy_serv will be run before any of this
542903d9bf0SStanislav Kinsbursky 	 * other initialization has been done except the rpcb information.
5431eca45f8SVasily Averin 	 */
5441eca45f8SVasily Averin 	svc_xprt_destroy_all(serv, net, true);
54536684996SScott Mayhew 	nfsd_shutdown_net(net);
54636684996SScott Mayhew 	svc_destroy(&serv);
54736684996SScott Mayhew }
54836684996SScott Mayhew 
nfsd_reset_versions(struct nfsd_net * nn)5491eca45f8SVasily Averin void nfsd_reset_versions(struct nfsd_net *nn)
5501eca45f8SVasily Averin {
5519f28a971SNeilBrown 	int i;
5529f28a971SNeilBrown 
5534ad9a344SJeff Layton 	for (i = 0; i <= NFSD_MAXVERS; i++)
5544ad9a344SJeff Layton 		if (nfsd_vers(nn, i, NFSD_TEST))
5554ad9a344SJeff Layton 			return;
55617419aefSNeilBrown 
557691412b4SKinglong Mee 	for (i = 0; i <= NFSD_MAXVERS; i++)
5584ad9a344SJeff Layton 		if (i != 4)
559691412b4SKinglong Mee 			nfsd_vers(nn, i, NFSD_SET);
560903d9bf0SStanislav Kinsbursky 		else {
5614ad9a344SJeff Layton 			int minor = 0;
562691412b4SKinglong Mee 			while (nfsd_minorversion(nn, minor, NFSD_SET) >= 0)
5636ff50b3dSStanislav Kinsbursky 				minor++;
564b3853e0eSStanislav Kinsbursky 		}
5651e3577a4SNeilBrown }
566bc591ccfSNeilBrown 
nfsd_get_default_max_blksize(void)5676658d3a7SNeilBrown static int nfsd_get_default_max_blksize(void)
568e333f3bbSTrond Myklebust {
5696658d3a7SNeilBrown 	struct sysinfo i;
5706658d3a7SNeilBrown 	unsigned long long target;
5716658d3a7SNeilBrown 	unsigned long ret;
572800a938fSNeilBrown 
573e333f3bbSTrond Myklebust 	si_meminfo(&i);
574800a938fSNeilBrown 	target = (i.totalram - i.totalhigh) << PAGE_SHIFT;
5756658d3a7SNeilBrown 	/*
576800a938fSNeilBrown 	 * Aim for 1/4096 of memory per thread This gives 1MB on 4Gig
577800a938fSNeilBrown 	 * machines, but only uses 32K on 128M machines.  Bottom out at
578e333f3bbSTrond Myklebust 	 * 8K on 32M and smaller.  Of course, this is only a default.
579800a938fSNeilBrown 	 */
580800a938fSNeilBrown 	target >>= 12;
581e333f3bbSTrond Myklebust 
582800a938fSNeilBrown 	ret = NFSSVC_DEFBLKSIZE;
5836658d3a7SNeilBrown 	while (ret > target && ret >= 8*1024*2)
5846658d3a7SNeilBrown 		ret /= 2;
5856658d3a7SNeilBrown 	return ret;
586c3d06f9cSAndy Adamson }
587c3d06f9cSAndy Adamson 
nfsd_shutdown_threads(struct net * net)588c3d06f9cSAndy Adamson void nfsd_shutdown_threads(struct net *net)
589c3d06f9cSAndy Adamson {
590c3d06f9cSAndy Adamson 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
591c3d06f9cSAndy Adamson 	struct svc_serv *serv;
592c3d06f9cSAndy Adamson 
593c3d06f9cSAndy Adamson 	mutex_lock(&nfsd_mutex);
594c3d06f9cSAndy Adamson 	serv = nn->nfsd_serv;
595c3d06f9cSAndy Adamson 	if (serv == NULL) {
596c3d06f9cSAndy Adamson 		mutex_unlock(&nfsd_mutex);
597c3d06f9cSAndy Adamson 		return;
598c3d06f9cSAndy Adamson 	}
599c3d06f9cSAndy Adamson 
60044d8660dSJ. Bruce Fields 	/* Kill outstanding nfsd threads */
6010c193054SAndy Adamson 	svc_set_num_threads(serv, NULL, 0);
6020c193054SAndy Adamson 	nfsd_destroy_serv(net);
6030c193054SAndy Adamson 	mutex_unlock(&nfsd_mutex);
604697ce9beSZhang Yanfei }
605c3d06f9cSAndy Adamson 
nfsd_current_rqst(void)606bedbdd8bSNeil Brown struct svc_rqst *nfsd_current_rqst(void)
60787b0fc7dSJ. Bruce Fields {
60887b0fc7dSJ. Bruce Fields 	if (kthread_func(current) == nfsd)
60987b0fc7dSJ. Bruce Fields 		return kthread_data(current);
61087b0fc7dSJ. Bruce Fields 	return NULL;
61187b0fc7dSJ. Bruce Fields }
61287b0fc7dSJ. Bruce Fields 
nfsd_create_serv(struct net * net)61387b0fc7dSJ. Bruce Fields int nfsd_create_serv(struct net *net)
614508f9227SJ. Bruce Fields {
61587b0fc7dSJ. Bruce Fields 	int error;
61687b0fc7dSJ. Bruce Fields 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
61787b0fc7dSJ. Bruce Fields 	struct svc_serv *serv;
61887b0fc7dSJ. Bruce Fields 
61987b0fc7dSJ. Bruce Fields 	WARN_ON(!mutex_is_locked(&nfsd_mutex));
62087b0fc7dSJ. Bruce Fields 	if (nn->nfsd_serv)
62187b0fc7dSJ. Bruce Fields 		return 0;
62287b0fc7dSJ. Bruce Fields 
62387b0fc7dSJ. Bruce Fields 	error = percpu_ref_init(&nn->nfsd_net_ref, nfsd_net_free,
62487b0fc7dSJ. Bruce Fields 				0, GFP_KERNEL);
62587b0fc7dSJ. Bruce Fields 	if (error)
62687b0fc7dSJ. Bruce Fields 		return error;
62787b0fc7dSJ. Bruce Fields 	init_completion(&nn->nfsd_net_free_done);
628c6c7f2a8STrond Myklebust 	init_completion(&nn->nfsd_net_confirm_done);
629c6c7f2a8STrond Myklebust 
630c6c7f2a8STrond Myklebust 	if (nfsd_max_blksize == 0)
631c6c7f2a8STrond Myklebust 		nfsd_max_blksize = nfsd_get_default_max_blksize();
632c6c7f2a8STrond Myklebust 	nfsd_reset_versions(nn);
633c6c7f2a8STrond Myklebust 	serv = svc_create_pooled(nfsd_programs, ARRAY_SIZE(nfsd_programs),
634c6c7f2a8STrond Myklebust 				 &nn->nfsd_svcstats,
635c6c7f2a8STrond Myklebust 				 nfsd_max_blksize, nfsd);
636c6c7f2a8STrond Myklebust 	if (serv == NULL)
637c6c7f2a8STrond Myklebust 		return -ENOMEM;
638c6c7f2a8STrond Myklebust 
639c6c7f2a8STrond Myklebust 	error = svc_bind(serv, net);
640c6c7f2a8STrond Myklebust 	if (error < 0) {
6413ebdbe52SNeilBrown 		svc_destroy(&serv);
64217419aefSNeilBrown 		return error;
643c6c7f2a8STrond Myklebust 	}
644c6c7f2a8STrond Myklebust 	spin_lock(&nfsd_notifier_lock);
645c6c7f2a8STrond Myklebust 	nn->nfsd_serv = serv;
64644fb26c6SMa Feng 	spin_unlock(&nfsd_notifier_lock);
64728df3d15SJ. Bruce Fields 
64828df3d15SJ. Bruce Fields 	/* check if the notifier is already set */
64928df3d15SJ. Bruce Fields 	if (atomic_inc_return(&nfsd_notifier_refcount) == 1) {
65028df3d15SJ. Bruce Fields 		register_inetaddr_notifier(&nfsd_inetaddr_notifier);
6516777436bSStanislav Kinsbursky #if IS_ENABLED(CONFIG_IPV6)
65202a375f0SNeilBrown 		register_inet6addr_notifier(&nfsd_inet6addr_notifier);
6539793f7c8SStanislav Kinsbursky #endif
654b9c0ef85SStanislav Kinsbursky 	}
655d057cfecSNeilBrown 	nfsd_reset_write_verifier(nn);
6569793f7c8SStanislav Kinsbursky 	return 0;
657bedbdd8bSNeil Brown }
6581e3577a4SNeilBrown 
nfsd_nrpools(struct net * net)65902a375f0SNeilBrown int nfsd_nrpools(struct net *net)
6601e3577a4SNeilBrown {
66187b0fc7dSJ. Bruce Fields 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
66287b0fc7dSJ. Bruce Fields 
663e333f3bbSTrond Myklebust 	if (nn->nfsd_serv == NULL)
664*16fb9808SJosef Bacik 		return 0;
665f0943238SJosef Bacik 	else
666d057cfecSNeilBrown 		return nn->nfsd_serv->sv_nrpools;
667628b3687SJeff Layton }
668bedbdd8bSNeil Brown 
nfsd_get_nrthreads(int n,int * nthreads,struct net * net)669d057cfecSNeilBrown int nfsd_get_nrthreads(int n, int *nthreads, struct net *net)
670d057cfecSNeilBrown {
6719793f7c8SStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
6721e3577a4SNeilBrown 	struct svc_serv *serv = nn->nfsd_serv;
6739793f7c8SStanislav Kinsbursky 	int i;
6749793f7c8SStanislav Kinsbursky 
675d057cfecSNeilBrown 	if (serv)
6767b207ccdSNeilBrown 		for (i = 0; i < serv->sv_nrpools && i < n; i++)
677d057cfecSNeilBrown 			nthreads[i] = serv->sv_pools[i].sp_nrthreads;
678d057cfecSNeilBrown 	return 0;
6799793f7c8SStanislav Kinsbursky }
680628b3687SJeff Layton 
6811eca45f8SVasily Averin /**
6821eca45f8SVasily Averin  * nfsd_set_nrthreads - set the number of running threads in the net's service
68336684996SScott Mayhew  * @n: number of array members in @nthreads
68436684996SScott Mayhew  * @nthreads: array of thread counts for each pool
68536684996SScott Mayhew  * @net: network namespace to operate within
68636684996SScott Mayhew  *
6871eca45f8SVasily Averin  * This function alters the number of running threads for the given network
6883988a578SChuck Lever  * namespace in each pool. If passed an array longer then the number of pools
68987b0fc7dSJ. Bruce Fields  * the extra pool settings are ignored. If passed an array shorter than the
69002a375f0SNeilBrown  * number of pools, the missing values are interpreted as 0's.
69102a375f0SNeilBrown  *
6929dd9845fSStanislav Kinsbursky  * Returns 0 on success or a negative errno on error.
693eed2965aSGreg Banks  */
nfsd_set_nrthreads(int n,int * nthreads,struct net * net)6949dd9845fSStanislav Kinsbursky int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
6959dd9845fSStanislav Kinsbursky {
6969dd9845fSStanislav Kinsbursky 	int i = 0;
697eed2965aSGreg Banks 	int tot = 0;
698eed2965aSGreg Banks 	int err = 0;
6999dd9845fSStanislav Kinsbursky 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
700eed2965aSGreg Banks 
701eed2965aSGreg Banks 	lockdep_assert_held(&nfsd_mutex);
7029dd9845fSStanislav Kinsbursky 
703eed2965aSGreg Banks 	if (nn->nfsd_serv == NULL || n <= 0)
7049dd9845fSStanislav Kinsbursky 		return 0;
7052e8fc923SNeilBrown 
7062e8fc923SNeilBrown 	/*
707eed2965aSGreg Banks 	 * Special case: When n == 1, pass in NULL for the pool, so that the
7082e8fc923SNeilBrown 	 * change is distributed equally among them.
7092e8fc923SNeilBrown 	 */
7102e8fc923SNeilBrown 	if (n == 1)
711eed2965aSGreg Banks 		return svc_set_num_threads(nn->nfsd_serv, NULL, nthreads[0]);
712eed2965aSGreg Banks 
713eed2965aSGreg Banks 	if (n > nn->nfsd_serv->sv_nrpools)
7143938a0d5SStanislav Kinsbursky 		n = nn->nfsd_serv->sv_nrpools;
715eed2965aSGreg Banks 
716eed2965aSGreg Banks 	/* enforce a global maximum number of threads */
717eed2965aSGreg Banks 	tot = 0;
718eed2965aSGreg Banks 	for (i = 0; i < n; i++) {
7199dd9845fSStanislav Kinsbursky 		nthreads[i] = min(nthreads[i], NFSD_MAXSERVS);
720eed2965aSGreg Banks 		tot += nthreads[i];
721bedbdd8bSNeil Brown 	}
722bedbdd8bSNeil Brown 	if (tot > NFSD_MAXSERVS) {
7239dd9845fSStanislav Kinsbursky 		/* total too large: scale down requested numbers */
724eed2965aSGreg Banks 		for (i = 0; i < n && tot > 0; i++) {
725eed2965aSGreg Banks 			int new = nthreads[i] * NFSD_MAXSERVS / tot;
7269dd9845fSStanislav Kinsbursky 			tot -= (nthreads[i] - new);
7279dd9845fSStanislav Kinsbursky 			nthreads[i] = new;
728eed2965aSGreg Banks 		}
729eed2965aSGreg Banks 		for (i = 0; i < n && tot > 0; i++) {
730eed2965aSGreg Banks 			nthreads[i]--;
731eed2965aSGreg Banks 			tot--;
7323c7aa15dSKinglong Mee 		}
733eed2965aSGreg Banks 	}
734eed2965aSGreg Banks 
735eed2965aSGreg Banks 	/* apply the new numbers */
736eed2965aSGreg Banks 	for (i = 0; i < n; i++) {
737eed2965aSGreg Banks 		err = svc_set_num_threads(nn->nfsd_serv,
738eed2965aSGreg Banks 					  &nn->nfsd_serv->sv_pools[i],
739eed2965aSGreg Banks 					  nthreads[i]);
740eed2965aSGreg Banks 		if (err)
741eed2965aSGreg Banks 			goto out;
742eed2965aSGreg Banks 	}
743eed2965aSGreg Banks 
744eed2965aSGreg Banks 	/* Anything undefined in array is considered to be 0 */
745eed2965aSGreg Banks 	for (i = n; i < nn->nfsd_serv->sv_nrpools; ++i) {
746eed2965aSGreg Banks 		err = svc_set_num_threads(nn->nfsd_serv,
747eed2965aSGreg Banks 					  &nn->nfsd_serv->sv_pools[i],
748eed2965aSGreg Banks 					  0);
749eed2965aSGreg Banks 		if (err)
750eed2965aSGreg Banks 			goto out;
751eed2965aSGreg Banks 	}
752eed2965aSGreg Banks out:
753eed2965aSGreg Banks 	return err;
754eed2965aSGreg Banks }
755eed2965aSGreg Banks 
756eed2965aSGreg Banks /**
7573ebdbe52SNeilBrown  * nfsd_svc: start up or shut down the nfsd server
7583ebdbe52SNeilBrown  * @n: number of array members in @nthreads
7593ebdbe52SNeilBrown  * @nthreads: array of thread counts for each pool
760eed2965aSGreg Banks  * @net: network namespace to operate within
761eed2965aSGreg Banks  * @cred: credentials to use for xprt creation
762eed2965aSGreg Banks  * @scope: server scope value (defaults to nodename)
763eed2965aSGreg Banks  *
764eed2965aSGreg Banks  * Adjust the number of threads in each pool and return the new
765eed2965aSGreg Banks  * total number of threads in the service.
766ac77efbeSJeff Layton  */
767ac77efbeSJeff Layton int
nfsd_svc(int n,int * nthreads,struct net * net,const struct cred * cred,const char * scope)768ac77efbeSJeff Layton nfsd_svc(int n, int *nthreads, struct net *net, const struct cred *cred, const char *scope)
769ac77efbeSJeff Layton {
770ac77efbeSJeff Layton 	int	error;
7711da177e4SLinus Torvalds 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
7724df493a2STrond Myklebust 	struct svc_serv *serv;
7731da177e4SLinus Torvalds 
7741da177e4SLinus Torvalds 	lockdep_assert_held(&nfsd_mutex);
7759dd9845fSStanislav Kinsbursky 
7769f28a971SNeilBrown 	dprintk("nfsd: creating service\n");
7771da177e4SLinus Torvalds 
778bedbdd8bSNeil Brown 	strscpy(nn->nfsd_name, scope ? scope : utsname()->nodename,
7796658d3a7SNeilBrown 		sizeof(nn->nfsd_name));
7803c7aa15dSKinglong Mee 
7813c7aa15dSKinglong Mee 	error = nfsd_create_serv(net);
7823c7aa15dSKinglong Mee 	if (error)
783671e1fcfSNeilBrown 		goto out;
7843c7aa15dSKinglong Mee 	serv = nn->nfsd_serv;
7859dd9845fSStanislav Kinsbursky 
786671e1fcfSNeilBrown 	error = nfsd_startup_net(net, cred);
7871da177e4SLinus Torvalds 	if (error)
78872f78ae0SWolfram Sang 		goto out_put;
7897627d7dcSScott Mayhew 	error = nfsd_set_nrthreads(n, nthreads, net);
7907627d7dcSScott Mayhew 	if (error)
7916777436bSStanislav Kinsbursky 		goto out_put;
79202a375f0SNeilBrown 	error = serv->sv_nrthreads;
793774f8bbdSJ. Bruce Fields out_put:
7949f28a971SNeilBrown 	if (serv->sv_nrthreads == 0)
795774f8bbdSJ. Bruce Fields 		nfsd_destroy_serv(net);
79670c53075SVasily Averin out:
797af4718f3SJ. Bruce Fields 	return error;
7988c62d127SNeilBrown }
7999f28a971SNeilBrown 
800774f8bbdSJ. Bruce Fields #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
801bf320752SNeilBrown static bool
nfsd_support_acl_version(int vers)8029f28a971SNeilBrown nfsd_support_acl_version(int vers)
8038c62d127SNeilBrown {
804bf320752SNeilBrown 	if (vers >= NFSD_ACL_MINVERS && vers < NFSD_ACL_NRVERS)
80517419aefSNeilBrown 		return nfsd_acl_version[vers] != NULL;
8061da177e4SLinus Torvalds 	return false;
807bedbdd8bSNeil Brown }
8081da177e4SLinus Torvalds 
8091da177e4SLinus Torvalds static int
nfsd_acl_rpcbind_set(struct net * net,const struct svc_program * progp,u32 version,int family,unsigned short proto,unsigned short port)8101da177e4SLinus Torvalds nfsd_acl_rpcbind_set(struct net *net, const struct svc_program *progp,
811029be5d0STrond Myklebust 		     u32 version, int family, unsigned short proto,
812029be5d0STrond Myklebust 		     unsigned short port)
813029be5d0STrond Myklebust {
814029be5d0STrond Myklebust 	if (!nfsd_support_acl_version(version) ||
815029be5d0STrond Myklebust 	    !nfsd_vers(net_generic(net, nfsd_net_id), version, NFSD_TEST))
816029be5d0STrond Myklebust 		return 0;
817029be5d0STrond Myklebust 	return svc_generic_rpcbind_set(net, progp, version, family,
818029be5d0STrond Myklebust 			proto, port);
819029be5d0STrond Myklebust }
820029be5d0STrond Myklebust 
821029be5d0STrond Myklebust static __be32
nfsd_acl_init_request(struct svc_rqst * rqstp,const struct svc_program * progp,struct svc_process_info * ret)822029be5d0STrond Myklebust nfsd_acl_init_request(struct svc_rqst *rqstp,
823029be5d0STrond Myklebust 		      const struct svc_program *progp,
824029be5d0STrond Myklebust 		      struct svc_process_info *ret)
825029be5d0STrond Myklebust {
826e333f3bbSTrond Myklebust 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
827029be5d0STrond Myklebust 	int i;
828029be5d0STrond Myklebust 
829029be5d0STrond Myklebust 	if (likely(nfsd_support_acl_version(rqstp->rq_vers) &&
830029be5d0STrond Myklebust 	    nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST)))
831e333f3bbSTrond Myklebust 		return svc_generic_init_request(rqstp, progp, ret);
832e333f3bbSTrond Myklebust 
833e333f3bbSTrond Myklebust 	ret->mismatch.lovers = NFSD_ACL_NRVERS;
834e333f3bbSTrond Myklebust 	for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) {
835e333f3bbSTrond Myklebust 		if (nfsd_support_acl_version(rqstp->rq_vers) &&
836e333f3bbSTrond Myklebust 		    nfsd_vers(nn, i, NFSD_TEST)) {
837e333f3bbSTrond Myklebust 			ret->mismatch.lovers = i;
838e333f3bbSTrond Myklebust 			break;
839e333f3bbSTrond Myklebust 		}
840e333f3bbSTrond Myklebust 	}
841e333f3bbSTrond Myklebust 	if (ret->mismatch.lovers == NFSD_ACL_NRVERS)
842e333f3bbSTrond Myklebust 		return rpc_prog_unavail;
843e333f3bbSTrond Myklebust 	ret->mismatch.hivers = NFSD_ACL_MINVERS;
844e333f3bbSTrond Myklebust 	for (i = NFSD_ACL_NRVERS - 1; i >= NFSD_ACL_MINVERS; i--) {
845e333f3bbSTrond Myklebust 		if (nfsd_support_acl_version(rqstp->rq_vers) &&
846e333f3bbSTrond Myklebust 		    nfsd_vers(nn, i, NFSD_TEST)) {
847e333f3bbSTrond Myklebust 			ret->mismatch.hivers = i;
848e333f3bbSTrond Myklebust 			break;
849e333f3bbSTrond Myklebust 		}
850e333f3bbSTrond Myklebust 	}
851e333f3bbSTrond Myklebust 	return rpc_prog_mismatch;
852e333f3bbSTrond Myklebust }
853e333f3bbSTrond Myklebust #endif
854e333f3bbSTrond Myklebust 
855e333f3bbSTrond Myklebust static int
nfsd_rpcbind_set(struct net * net,const struct svc_program * progp,u32 version,int family,unsigned short proto,unsigned short port)856e333f3bbSTrond Myklebust nfsd_rpcbind_set(struct net *net, const struct svc_program *progp,
857e333f3bbSTrond Myklebust 		 u32 version, int family, unsigned short proto,
858e333f3bbSTrond Myklebust 		 unsigned short port)
859e333f3bbSTrond Myklebust {
860e333f3bbSTrond Myklebust 	if (!nfsd_vers(net_generic(net, nfsd_net_id), version, NFSD_TEST))
861e333f3bbSTrond Myklebust 		return 0;
862e333f3bbSTrond Myklebust 	return svc_generic_rpcbind_set(net, progp, version, family,
863e333f3bbSTrond Myklebust 			proto, port);
864029be5d0STrond Myklebust }
865029be5d0STrond Myklebust 
866029be5d0STrond Myklebust static __be32
nfsd_init_request(struct svc_rqst * rqstp,const struct svc_program * progp,struct svc_process_info * ret)867029be5d0STrond Myklebust nfsd_init_request(struct svc_rqst *rqstp,
868029be5d0STrond Myklebust 		  const struct svc_program *progp,
869029be5d0STrond Myklebust 		  struct svc_process_info *ret)
870029be5d0STrond Myklebust {
871e333f3bbSTrond Myklebust 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
872029be5d0STrond Myklebust 	int i;
873029be5d0STrond Myklebust 
874029be5d0STrond Myklebust 	if (likely(nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST)))
875029be5d0STrond Myklebust 		return svc_generic_init_request(rqstp, progp, ret);
8761da177e4SLinus Torvalds 
877e333f3bbSTrond Myklebust 	ret->mismatch.lovers = NFSD_MAXVERS + 1;
878e333f3bbSTrond Myklebust 	for (i = NFSD_MINVERS; i <= NFSD_MAXVERS; i++) {
879e333f3bbSTrond Myklebust 		if (nfsd_vers(nn, i, NFSD_TEST)) {
880e333f3bbSTrond Myklebust 			ret->mismatch.lovers = i;
881e333f3bbSTrond Myklebust 			break;
882e333f3bbSTrond Myklebust 		}
883e333f3bbSTrond Myklebust 	}
884e333f3bbSTrond Myklebust 	if (ret->mismatch.lovers > NFSD_MAXVERS)
885e333f3bbSTrond Myklebust 		return rpc_prog_unavail;
886e333f3bbSTrond Myklebust 	ret->mismatch.hivers = NFSD_MINVERS;
887e333f3bbSTrond Myklebust 	for (i = NFSD_MAXVERS; i >= NFSD_MINVERS; i--) {
888e333f3bbSTrond Myklebust 		if (nfsd_vers(nn, i, NFSD_TEST)) {
889e333f3bbSTrond Myklebust 			ret->mismatch.hivers = i;
890e333f3bbSTrond Myklebust 			break;
891e333f3bbSTrond Myklebust 		}
892e333f3bbSTrond Myklebust 	}
893e333f3bbSTrond Myklebust 	return rpc_prog_mismatch;
894e333f3bbSTrond Myklebust }
895e333f3bbSTrond Myklebust 
896e333f3bbSTrond Myklebust /*
897e333f3bbSTrond Myklebust  * This is the NFS server kernel thread
898e333f3bbSTrond Myklebust  */
899e333f3bbSTrond Myklebust static int
nfsd(void * vrqstp)900e333f3bbSTrond Myklebust nfsd(void *vrqstp)
901e333f3bbSTrond Myklebust {
902e333f3bbSTrond Myklebust 	struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
903e333f3bbSTrond Myklebust 	struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list);
904e333f3bbSTrond Myklebust 	struct net *net = perm_sock->xpt_net;
905e333f3bbSTrond Myklebust 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
906e333f3bbSTrond Myklebust 
9071da177e4SLinus Torvalds 	/* At this point, the thread shares current->fs
9081da177e4SLinus Torvalds 	 * with the init process. We need to create files with the
9091da177e4SLinus Torvalds 	 * umask as defined by the client instead of init's umask.
9109867d76cSJeff Layton 	 */
9119867d76cSJeff Layton 	svc_thread_init_status(rqstp, unshare_fs_struct());
9121da177e4SLinus Torvalds 
9139867d76cSJeff Layton 	current->fs->umask = 0;
91488c47666SStanislav Kinsbursky 
91588c47666SStanislav Kinsbursky 	atomic_inc(&nfsd_th_cnt);
9165b8db00bSJeff Layton 
9171da177e4SLinus Torvalds 	set_freezable();
9189867d76cSJeff Layton 
91947057abdSAndreas Gruenbacher 	/*
92047057abdSAndreas Gruenbacher 	 * The main request loop
9213e93cd67SAl Viro 	 */
9221da177e4SLinus Torvalds 	while (!svc_thread_should_stop(rqstp)) {
9231da177e4SLinus Torvalds 		svc_recv(rqstp);
9241da177e4SLinus Torvalds 		nfsd_file_net_dispose(nn);
9253e93cd67SAl Viro 	}
9261da177e4SLinus Torvalds 
9271da177e4SLinus Torvalds 	atomic_dec(&nfsd_th_cnt);
928e41ee44cSJosef Bacik 
929bedbdd8bSNeil Brown 	/* Release the thread */
93083144186SRafael J. Wysocki 	svc_exit_thread(rqstp);
9311da177e4SLinus Torvalds 	return 0;
9321da177e4SLinus Torvalds }
9331da177e4SLinus Torvalds 
9341da177e4SLinus Torvalds /**
935fa341560SNeilBrown  * nfsd_dispatch - Process an NFS or NFSACL or LOCALIO Request
9365b8db00bSJeff Layton  * @rqstp: incoming request
9375b8db00bSJeff Layton  *
9385b8db00bSJeff Layton  * This RPC dispatcher integrates the NFS server's duplicate reply cache.
939c743b425SNeilBrown  *
940ffb40259SNeilBrown  * Return values:
941ffb40259SNeilBrown  *  %0: Processing complete; do not send a Reply
9421da177e4SLinus Torvalds  *  %1: Processing complete; send Reply in rqstp->rq_res
9431da177e4SLinus Torvalds  */
nfsd_dispatch(struct svc_rqst * rqstp)944e41ee44cSJosef Bacik int nfsd_dispatch(struct svc_rqst *rqstp)
9451da177e4SLinus Torvalds {
9461da177e4SLinus Torvalds 	const struct svc_procedure *proc = rqstp->rq_procinfo;
9471da177e4SLinus Torvalds 	__be32 *statp = rqstp->rq_accept_statp;
9481da177e4SLinus Torvalds 	struct nfsd_cacherep *rp;
9499867d76cSJeff Layton 	unsigned int start, len;
9501da177e4SLinus Torvalds 	__be32 *nfs_reply;
9511da177e4SLinus Torvalds 
952383c440dSChuck Lever 	/*
953383c440dSChuck Lever 	 * Give the xdr decoder a chance to change this if it wants
954383c440dSChuck Lever 	 * (necessary in the NFSv4.0 compound case)
955383c440dSChuck Lever 	 */
956383c440dSChuck Lever 	rqstp->rq_cachetype = proc->pc_cachetype;
957383c440dSChuck Lever 
958383c440dSChuck Lever 	/*
959383c440dSChuck Lever 	 * ->pc_decode advances the argument stream past the NFS
960383c440dSChuck Lever 	 * Call header, so grab the header's starting location and
961383c440dSChuck Lever 	 * size now for the call to nfsd_cache_lookup().
962cee4db19SChuck Lever 	 */
9631da177e4SLinus Torvalds 	start = xdr_stream_pos(&rqstp->rq_arg_stream);
9644c96cb56SChuck Lever 	len = xdr_stream_remaining(&rqstp->rq_arg_stream);
965cee4db19SChuck Lever 	if (!proc->pc_decode(rqstp, &rqstp->rq_arg_stream))
966e7421ce7SChuck Lever 		goto out_decode_err;
967bf51c52aSChuck Lever 
9681caf5f61SChuck Lever 	/*
9691da177e4SLinus Torvalds 	 * Release rq_status_counter setting it to an odd value after the rpc
9701091006cSJ. Bruce Fields 	 * request has been properly parsed. rq_status_counter is used to
9711091006cSJ. Bruce Fields 	 * notify the consumers if the rqstp fields are stable
9721091006cSJ. Bruce Fields 	 * (rq_status_counter is odd) or not meaningful (rq_status_counter
9731091006cSJ. Bruce Fields 	 * is even).
9741091006cSJ. Bruce Fields 	 */
9755191955dSChuck Lever 	smp_store_release(&rqstp->rq_status_counter, rqstp->rq_status_counter | 1);
976bf51c52aSChuck Lever 
977bf51c52aSChuck Lever 	rp = NULL;
978bf51c52aSChuck Lever 	switch (nfsd_cache_lookup(rqstp, start, len, &rp)) {
979bf51c52aSChuck Lever 	case RC_DOIT:
980bf51c52aSChuck Lever 		break;
981bf51c52aSChuck Lever 	case RC_REPLY:
982bf51c52aSChuck Lever 		goto out_cached_reply;
98316c66364SChuck Lever 	case RC_DROPIT:
98485085aacSChuck Lever 		goto out_dropit;
9851091006cSJ. Bruce Fields 	}
986bd9d6a3eSLorenzo Bianconi 
987bd9d6a3eSLorenzo Bianconi 	nfs_reply = xdr_inline_decode(&rqstp->rq_res_stream, 0);
988bd9d6a3eSLorenzo Bianconi 	*statp = proc->pc_func(rqstp);
989bd9d6a3eSLorenzo Bianconi 	if (test_bit(RQ_DROPME, &rqstp->rq_flags))
990bd9d6a3eSLorenzo Bianconi 		goto out_update_drop;
991bd9d6a3eSLorenzo Bianconi 
992bd9d6a3eSLorenzo Bianconi 	if (!proc->pc_encode(rqstp, &rqstp->rq_res_stream))
993bd9d6a3eSLorenzo Bianconi 		goto out_encode_err;
994bd9d6a3eSLorenzo Bianconi 
995cb18eca4SChuck Lever 	/*
996bf51c52aSChuck Lever 	 * Release rq_status_counter setting it to an even value after the rpc
99784c138e7SChuck Lever 	 * request has been properly processed.
99884c138e7SChuck Lever 	 */
9991da177e4SLinus Torvalds 	smp_store_release(&rqstp->rq_status_counter, rqstp->rq_status_counter + 1);
100085085aacSChuck Lever 
100184c138e7SChuck Lever 	nfsd_cache_update(rqstp, rp, rqstp->rq_cachetype, nfs_reply);
100285085aacSChuck Lever out_cached_reply:
10031da177e4SLinus Torvalds 	return 1;
10041da177e4SLinus Torvalds 
10051caf5f61SChuck Lever out_decode_err:
1006cc028a10SChuck Lever 	trace_nfsd_garbage_args_err(rqstp);
100793155647SChuck Lever 	*statp = rpc_garbage_args;
100885085aacSChuck Lever 	return 1;
10091da177e4SLinus Torvalds 
1010fda49441SChuck Lever out_update_drop:
101185085aacSChuck Lever 	nfsd_cache_update(rqstp, rp, RC_NOCACHE, NULL);
101285085aacSChuck Lever out_dropit:
1013bd9d6a3eSLorenzo Bianconi 	return 0;
1014bd9d6a3eSLorenzo Bianconi 
1015bd9d6a3eSLorenzo Bianconi out_encode_err:
1016bd9d6a3eSLorenzo Bianconi 	trace_nfsd_cant_encode_err(rqstp);
1017bd9d6a3eSLorenzo Bianconi 	nfsd_cache_update(rqstp, rp, RC_NOCACHE, NULL);
1018bd9d6a3eSLorenzo Bianconi 	*statp = rpc_system_err;
10191caf5f61SChuck Lever 	return 1;
102085085aacSChuck Lever }
102185085aacSChuck Lever 
102285085aacSChuck Lever /**
102385085aacSChuck Lever  * nfssvc_decode_voidarg - Decode void arguments
10240dfdad1cSChuck Lever  * @rqstp: Server RPC transaction context
102585085aacSChuck Lever  * @xdr: XDR stream positioned at arguments to decode
102685085aacSChuck Lever  *
102785085aacSChuck Lever  * Return values:
102885085aacSChuck Lever  *   %false: Arguments were not valid
1029cb18eca4SChuck Lever  *   %true: Decoding was successful
103085085aacSChuck Lever  */
nfssvc_decode_voidarg(struct svc_rqst * rqstp,struct xdr_stream * xdr)103185085aacSChuck Lever bool nfssvc_decode_voidarg(struct svc_rqst *rqstp, struct xdr_stream *xdr)
103285085aacSChuck Lever {
103385085aacSChuck Lever 	return true;
10340dfdad1cSChuck Lever }
1035cb18eca4SChuck Lever 
10361da177e4SLinus Torvalds /**
10371da177e4SLinus Torvalds  * nfssvc_encode_voidres - Encode void results
10381da177e4SLinus Torvalds  * @rqstp: Server RPC transaction context
103903cf6c9fSGreg Banks  * @xdr: XDR stream into which to encode results
1040788f7183SChuck Lever  *
1041788f7183SChuck Lever  * Return values:
1042788f7183SChuck Lever  *   %false: Local error while encoding
104316c66364SChuck Lever  *   %true: Encoding was successful
1044788f7183SChuck Lever  */
nfssvc_encode_voidres(struct svc_rqst * rqstp,struct xdr_stream * xdr)1045788f7183SChuck Lever bool nfssvc_encode_voidres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
1046c44b31c2SChuck Lever {
1047c44b31c2SChuck Lever 	return true;
1048788f7183SChuck Lever }
1049c44b31c2SChuck Lever