1184588Sdfr/*-
2184588Sdfr * Copyright (c) 1989, 1993
3184588Sdfr *	The Regents of the University of California.  All rights reserved.
4184588Sdfr *
5184588Sdfr * This code is derived from software contributed to Berkeley by
6184588Sdfr * Rick Macklem at The University of Guelph.
7184588Sdfr *
8184588Sdfr * Redistribution and use in source and binary forms, with or without
9184588Sdfr * modification, are permitted provided that the following conditions
10184588Sdfr * are met:
11184588Sdfr * 1. Redistributions of source code must retain the above copyright
12184588Sdfr *    notice, this list of conditions and the following disclaimer.
13184588Sdfr * 2. Redistributions in binary form must reproduce the above copyright
14184588Sdfr *    notice, this list of conditions and the following disclaimer in the
15184588Sdfr *    documentation and/or other materials provided with the distribution.
16184588Sdfr * 4. Neither the name of the University nor the names of its contributors
17184588Sdfr *    may be used to endorse or promote products derived from this software
18184588Sdfr *    without specific prior written permission.
19184588Sdfr *
20184588Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21184588Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22184588Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23184588Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24184588Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25184588Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26184588Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27184588Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28184588Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29184588Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30184588Sdfr * SUCH DAMAGE.
31184588Sdfr *
32184588Sdfr *	@(#)nfs_syscalls.c	8.5 (Berkeley) 3/30/95
33184588Sdfr */
34184588Sdfr
35184588Sdfr#include <sys/cdefs.h>
36184588Sdfr__FBSDID("$FreeBSD$");
37184588Sdfr
38184588Sdfr#include "opt_inet6.h"
39184588Sdfr#include "opt_kgssapi.h"
40184588Sdfr
41184588Sdfr#include <sys/param.h>
42224778Srwatson#include <sys/capability.h>
43184588Sdfr#include <sys/systm.h>
44184588Sdfr#include <sys/sysproto.h>
45184588Sdfr#include <sys/kernel.h>
46184588Sdfr#include <sys/sysctl.h>
47184588Sdfr#include <sys/file.h>
48184588Sdfr#include <sys/filedesc.h>
49194073Srmacklem#include <sys/jail.h>
50184588Sdfr#include <sys/vnode.h>
51184588Sdfr#include <sys/malloc.h>
52184588Sdfr#include <sys/mount.h>
53184588Sdfr#include <sys/priv.h>
54184588Sdfr#include <sys/proc.h>
55184588Sdfr#include <sys/bio.h>
56184588Sdfr#include <sys/buf.h>
57184588Sdfr#include <sys/mbuf.h>
58184588Sdfr#include <sys/socket.h>
59184588Sdfr#include <sys/socketvar.h>
60184588Sdfr#include <sys/domain.h>
61184588Sdfr#include <sys/protosw.h>
62184588Sdfr#include <sys/namei.h>
63184588Sdfr#include <sys/fcntl.h>
64184588Sdfr#include <sys/lockf.h>
65184643Sdfr#include <sys/eventhandler.h>
66184588Sdfr
67184588Sdfr#include <netinet/in.h>
68184588Sdfr#include <netinet/tcp.h>
69184588Sdfr#ifdef INET6
70184588Sdfr#include <net/if.h>
71184588Sdfr#include <netinet6/in6_var.h>
72184588Sdfr#endif
73184588Sdfr
74184588Sdfr#include <rpc/rpc.h>
75184588Sdfr#include <rpc/rpcsec_gss.h>
76184588Sdfr#include <rpc/replay.h>
77184588Sdfr
78184588Sdfr#include <nfs/xdr_subs.h>
79184588Sdfr#include <nfs/nfsproto.h>
80249596Sken#include <nfs/nfs_fha.h>
81184588Sdfr#include <nfsserver/nfs.h>
82184588Sdfr#include <nfsserver/nfsm_subs.h>
83184588Sdfr#include <nfsserver/nfsrvcache.h>
84249592Sken#include <nfsserver/nfs_fha_old.h>
85184588Sdfr
86193511Srwatson#include <security/mac/mac_framework.h>
87193511Srwatson
88184588Sdfrstatic MALLOC_DEFINE(M_NFSSVC, "nfss_srvsock", "Nfs server structure");
89184588Sdfr
90184588SdfrMALLOC_DEFINE(M_NFSRVDESC, "nfss_srvdesc", "NFS server socket descriptor");
91184588SdfrMALLOC_DEFINE(M_NFSD, "nfss_daemon", "Nfs server daemon structure");
92184588Sdfr
93184588Sdfr#define	TRUE	1
94184588Sdfr#define	FALSE	0
95184588Sdfr
96184588SdfrSYSCTL_DECL(_vfs_nfsrv);
97184588Sdfr
98184588SdfrSVCPOOL		*nfsrv_pool;
99184588Sdfrint		nfsd_waiting = 0;
100184588Sdfrint		nfsrv_numnfsd = 0;
101184588Sdfrstruct callout	nfsrv_callout;
102184588Sdfrstatic eventhandler_tag nfsrv_nmbclusters_tag;
103184588Sdfr
104184588Sdfrstatic int	nfs_privport = 0;
105184588SdfrSYSCTL_INT(_vfs_nfsrv, NFS_NFSPRIVPORT, nfs_privport, CTLFLAG_RW,
106184588Sdfr    &nfs_privport, 0,
107184588Sdfr    "Only allow clients using a privileged port");
108184588SdfrSYSCTL_INT(_vfs_nfsrv, OID_AUTO, gatherdelay, CTLFLAG_RW,
109184588Sdfr    &nfsrvw_procrastinate, 0,
110184588Sdfr    "Delay value for write gathering");
111184588SdfrSYSCTL_INT(_vfs_nfsrv, OID_AUTO, gatherdelay_v3, CTLFLAG_RW,
112184588Sdfr    &nfsrvw_procrastinate_v3, 0,
113184588Sdfr    "Delay in seconds for NFSv3 write gathering");
114184588Sdfr
115184588Sdfrstatic int	nfssvc_addsock(struct file *, struct thread *);
116184588Sdfrstatic int	nfssvc_nfsd(struct thread *, struct nfsd_nfsd_args *);
117184588Sdfr
118184588Sdfrextern u_long sb_max_adj;
119184588Sdfr
120184588Sdfrint32_t (*nfsrv3_procs[NFS_NPROCS])(struct nfsrv_descript *nd,
121184588Sdfr    struct nfssvc_sock *slp, struct mbuf **mreqp) = {
122184588Sdfr	nfsrv_null,
123184588Sdfr	nfsrv_getattr,
124184588Sdfr	nfsrv_setattr,
125184588Sdfr	nfsrv_lookup,
126184588Sdfr	nfsrv3_access,
127184588Sdfr	nfsrv_readlink,
128184588Sdfr	nfsrv_read,
129184588Sdfr	nfsrv_write,
130184588Sdfr	nfsrv_create,
131184588Sdfr	nfsrv_mkdir,
132184588Sdfr	nfsrv_symlink,
133184588Sdfr	nfsrv_mknod,
134184588Sdfr	nfsrv_remove,
135184588Sdfr	nfsrv_rmdir,
136184588Sdfr	nfsrv_rename,
137184588Sdfr	nfsrv_link,
138184588Sdfr	nfsrv_readdir,
139184588Sdfr	nfsrv_readdirplus,
140184588Sdfr	nfsrv_statfs,
141184588Sdfr	nfsrv_fsinfo,
142184588Sdfr	nfsrv_pathconf,
143184588Sdfr	nfsrv_commit,
144184588Sdfr	nfsrv_noop
145184588Sdfr};
146184588Sdfr
147184588Sdfr/*
148184588Sdfr * NFS server system calls
149184588Sdfr */
150190971Srmacklem/*
151190971Srmacklem * This is now called from nfssvc() in nfs/nfs_nfssvc.c.
152190971Srmacklem */
153184588Sdfr
154184588Sdfr/*
155184588Sdfr * Nfs server psuedo system call for the nfsd's
156184588Sdfr * Based on the flag value it either:
157184588Sdfr * - adds a socket to the selection list
158184588Sdfr * - remains in the kernel as an nfsd
159184588Sdfr * - remains in the kernel as an nfsiod
160184588Sdfr * For INET6 we suppose that nfsd provides only IN6P_IPV6_V6ONLY sockets
161184588Sdfr * and that mountd provides
162184588Sdfr *  - sockaddr with no IPv4-mapped addresses
163184588Sdfr *  - mask for both INET and INET6 families if there is IPv4-mapped overlap
164184588Sdfr */
165184588Sdfrint
166190971Srmacklemnfssvc_nfsserver(struct thread *td, struct nfssvc_args *uap)
167184588Sdfr{
168184588Sdfr	struct file *fp;
169184588Sdfr	struct nfsd_addsock_args addsockarg;
170184588Sdfr	struct nfsd_nfsd_args nfsdarg;
171255219Spjd	cap_rights_t rights;
172184588Sdfr	int error;
173184588Sdfr
174184588Sdfr	if (uap->flag & NFSSVC_ADDSOCK) {
175184588Sdfr		error = copyin(uap->argp, (caddr_t)&addsockarg,
176184588Sdfr		    sizeof(addsockarg));
177184588Sdfr		if (error)
178184588Sdfr			return (error);
179255219Spjd		error = fget(td, addsockarg.sock,
180255219Spjd		    cap_rights_init(&rights, CAP_SOCK_SERVER), &fp);
181247602Spjd		if (error)
182184588Sdfr			return (error);
183184588Sdfr		if (fp->f_type != DTYPE_SOCKET) {
184184588Sdfr			fdrop(fp, td);
185184588Sdfr			return (error);	/* XXXRW: Should be EINVAL? */
186184588Sdfr		}
187184588Sdfr		error = nfssvc_addsock(fp, td);
188184588Sdfr		fdrop(fp, td);
189201899Smarius	} else if (uap->flag & NFSSVC_OLDNFSD)
190184588Sdfr		error = nfssvc_nfsd(td, NULL);
191201899Smarius	else if (uap->flag & NFSSVC_NFSD) {
192201899Smarius		if (!uap->argp)
193184588Sdfr			return (EINVAL);
194184588Sdfr		error = copyin(uap->argp, (caddr_t)&nfsdarg,
195184588Sdfr		    sizeof(nfsdarg));
196184588Sdfr		if (error)
197184588Sdfr			return (error);
198184588Sdfr		error = nfssvc_nfsd(td, &nfsdarg);
199201899Smarius	} else
200184588Sdfr		error = ENXIO;
201184588Sdfr	return (error);
202184588Sdfr}
203184588Sdfr
204184588Sdfr/*
205184588Sdfr * Generate the rpc reply header
206184588Sdfr * siz arg. is used to decide if adding a cluster is worthwhile
207184588Sdfr */
208184588Sdfrstruct mbuf *
209184588Sdfrnfs_rephead(int siz, struct nfsrv_descript *nd, int err,
210184588Sdfr    struct mbuf **mbp, caddr_t *bposp)
211184588Sdfr{
212184588Sdfr	u_int32_t *tl;
213184588Sdfr	struct mbuf *mreq;
214184588Sdfr	caddr_t bpos;
215184588Sdfr	struct mbuf *mb;
216184588Sdfr
217184588Sdfr	if (err == EBADRPC)
218184588Sdfr		return (NULL);
219184588Sdfr
220184588Sdfr	nd->nd_repstat = err;
221184588Sdfr	if (err && (nd->nd_flag & ND_NFSV3) == 0)	/* XXX recheck */
222184588Sdfr		siz = 0;
223184588Sdfr
224243882Sglebius	MGET(mreq, M_WAITOK, MT_DATA);
225184588Sdfr
226184588Sdfr	/*
227184588Sdfr	 * If this is a big reply, use a cluster
228184588Sdfr	 */
229184588Sdfr	mreq->m_len = 0;
230184588Sdfr	if (siz >= MINCLSIZE) {
231243882Sglebius		MCLGET(mreq, M_WAITOK);
232184588Sdfr	}
233184588Sdfr	mb = mreq;
234184588Sdfr	bpos = mtod(mb, caddr_t);
235184588Sdfr
236184588Sdfr	if (err != NFSERR_RETVOID) {
237184588Sdfr		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
238184588Sdfr		if (err)
239184588Sdfr			*tl = txdr_unsigned(nfsrv_errmap(nd, err));
240184588Sdfr		else
241184588Sdfr			*tl = 0;
242184588Sdfr	}
243184588Sdfr
244184588Sdfr	*mbp = mb;
245184588Sdfr	*bposp = bpos;
246184588Sdfr	if (err != 0 && err != NFSERR_RETVOID)
247184588Sdfr		nfsrvstats.srvrpc_errs++;
248184588Sdfr
249184588Sdfr	return (mreq);
250184588Sdfr}
251184588Sdfr
252184588Sdfrstatic void
253184588Sdfrnfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
254184588Sdfr{
255184588Sdfr	rpcproc_t procnum;
256184588Sdfr	int32_t (*proc)(struct nfsrv_descript *nd, struct nfssvc_sock *slp,
257184588Sdfr	    struct mbuf **mreqp);
258184588Sdfr	int flag;
259184588Sdfr	struct nfsrv_descript nd;
260184588Sdfr	struct mbuf *mreq, *mrep;
261184588Sdfr	int error;
262184588Sdfr
263184588Sdfr	if (rqst->rq_vers == NFS_VER2) {
264184588Sdfr		if (rqst->rq_proc > NFSV2PROC_STATFS) {
265184588Sdfr			svcerr_noproc(rqst);
266184588Sdfr			svc_freereq(rqst);
267184588Sdfr			return;
268184588Sdfr		}
269184588Sdfr		procnum = nfsrv_nfsv3_procid[rqst->rq_proc];
270184588Sdfr		flag = 0;
271184588Sdfr	} else {
272184588Sdfr		if (rqst->rq_proc >= NFS_NPROCS) {
273184588Sdfr			svcerr_noproc(rqst);
274184588Sdfr			svc_freereq(rqst);
275184588Sdfr			return;
276184588Sdfr		}
277184588Sdfr		procnum = rqst->rq_proc;
278184588Sdfr		flag = ND_NFSV3;
279184588Sdfr	}
280184588Sdfr	proc = nfsrv3_procs[procnum];
281184588Sdfr
282184588Sdfr	mreq = mrep = NULL;
283184588Sdfr	mreq = rqst->rq_args;
284184588Sdfr	rqst->rq_args = NULL;
285243882Sglebius	(void)nfs_realign(&mreq, M_WAITOK);
286184588Sdfr
287184588Sdfr	/*
288184921Sdfr	 * Note: we want rq_addr, not svc_getrpccaller for nd_nam2 -
289184588Sdfr	 * NFS_SRVMAXDATA uses a NULL value for nd_nam2 to detect TCP
290184588Sdfr	 * mounts.
291184588Sdfr	 */
292184588Sdfr	memset(&nd, 0, sizeof(nd));
293184588Sdfr	nd.nd_md = nd.nd_mrep = mreq;
294184588Sdfr	nd.nd_dpos = mtod(mreq, caddr_t);
295184921Sdfr	nd.nd_nam = svc_getrpccaller(rqst);
296184588Sdfr	nd.nd_nam2 = rqst->rq_addr;
297184588Sdfr	nd.nd_procnum = procnum;
298184588Sdfr	nd.nd_cr = NULL;
299184588Sdfr	nd.nd_flag = flag;
300184588Sdfr
301184921Sdfr	if (nfs_privport) {
302184921Sdfr		/* Check if source port is privileged */
303184921Sdfr		u_short port;
304184921Sdfr		struct sockaddr *nam = nd.nd_nam;
305184921Sdfr		struct sockaddr_in *sin;
306184921Sdfr
307184921Sdfr		sin = (struct sockaddr_in *)nam;
308184921Sdfr		/*
309184921Sdfr		 * INET/INET6 - same code:
310184921Sdfr		 *    sin_port and sin6_port are at same offset
311184921Sdfr		 */
312184921Sdfr		port = ntohs(sin->sin_port);
313184921Sdfr		if (port >= IPPORT_RESERVED &&
314184921Sdfr		    nd.nd_procnum != NFSPROC_NULL) {
315184921Sdfr#ifdef INET6
316184921Sdfr			char b6[INET6_ADDRSTRLEN];
317184921Sdfr#if defined(KLD_MODULE)
318184921Sdfr			/* Do not use ip6_sprintf: the nfs module should work without INET6. */
319184921Sdfr#define ip6_sprintf(buf, a)						\
320184921Sdfr			(sprintf((buf), "%x:%x:%x:%x:%x:%x:%x:%x",	\
321184921Sdfr			    (a)->s6_addr16[0], (a)->s6_addr16[1],	\
322184921Sdfr			    (a)->s6_addr16[2], (a)->s6_addr16[3],	\
323184921Sdfr			    (a)->s6_addr16[4], (a)->s6_addr16[5],	\
324184921Sdfr			    (a)->s6_addr16[6], (a)->s6_addr16[7]),	\
325184921Sdfr			    (buf))
326184921Sdfr#endif
327184921Sdfr#endif
328184921Sdfr			printf("NFS request from unprivileged port (%s:%d)\n",
329184921Sdfr#ifdef INET6
330184921Sdfr			    sin->sin_family == AF_INET6 ?
331184921Sdfr			    ip6_sprintf(b6, &satosin6(sin)->sin6_addr) :
332184921Sdfr#if defined(KLD_MODULE)
333184921Sdfr#undef ip6_sprintf
334184921Sdfr#endif
335184921Sdfr#endif
336184921Sdfr			    inet_ntoa(sin->sin_addr), port);
337190053Sdfr			m_freem(mreq);
338184921Sdfr			svcerr_weakauth(rqst);
339184921Sdfr			svc_freereq(rqst);
340184921Sdfr			return;
341184921Sdfr		}
342184921Sdfr	}
343184921Sdfr
344184588Sdfr	if (proc != nfsrv_null) {
345184588Sdfr		if (!svc_getcred(rqst, &nd.nd_cr, &nd.nd_credflavor)) {
346190053Sdfr			m_freem(mreq);
347184588Sdfr			svcerr_weakauth(rqst);
348184588Sdfr			svc_freereq(rqst);
349184588Sdfr			return;
350184588Sdfr		}
351184588Sdfr#ifdef MAC
352184588Sdfr		mac_cred_associate_nfsd(nd.nd_cr);
353184588Sdfr#endif
354184588Sdfr	}
355184588Sdfr	nfsrvstats.srvrpccnt[nd.nd_procnum]++;
356184588Sdfr
357184588Sdfr	error = proc(&nd, NULL, &mrep);
358184588Sdfr
359184588Sdfr	if (nd.nd_cr)
360184588Sdfr		crfree(nd.nd_cr);
361184588Sdfr
362184588Sdfr	if (mrep == NULL) {
363184588Sdfr		svcerr_decode(rqst);
364184588Sdfr		svc_freereq(rqst);
365184588Sdfr		return;
366184588Sdfr	}
367184588Sdfr	if (error && error != NFSERR_RETVOID) {
368184588Sdfr		svcerr_systemerr(rqst);
369184588Sdfr		svc_freereq(rqst);
370184588Sdfr		return;
371184588Sdfr	}
372184869Sdfr	if (nd.nd_repstat & NFSERR_AUTHERR) {
373184869Sdfr		svcerr_auth(rqst, nd.nd_repstat & ~NFSERR_AUTHERR);
374184869Sdfr		m_freem(mrep);
375184869Sdfr	} else {
376184869Sdfr		if (!svc_sendreply_mbuf(rqst, mrep))
377184869Sdfr			svcerr_systemerr(rqst);
378184869Sdfr	}
379184588Sdfr	svc_freereq(rqst);
380184588Sdfr}
381184588Sdfr
382184588Sdfr/*
383184588Sdfr * Adds a socket to the list for servicing by nfsds.
384184588Sdfr */
385184588Sdfrstatic int
386184588Sdfrnfssvc_addsock(struct file *fp, struct thread *td)
387184588Sdfr{
388184588Sdfr	int siz;
389184588Sdfr	struct socket *so;
390184588Sdfr	int error;
391184588Sdfr	SVCXPRT *xprt;
392184588Sdfr
393184588Sdfr	so = fp->f_data;
394184588Sdfr
395184588Sdfr	siz = sb_max_adj;
396184588Sdfr	error = soreserve(so, siz, siz);
397201899Smarius	if (error)
398184588Sdfr		return (error);
399184588Sdfr
400184588Sdfr	/*
401184588Sdfr	 * Steal the socket from userland so that it doesn't close
402184588Sdfr	 * unexpectedly.
403184588Sdfr	 */
404184588Sdfr	if (so->so_type == SOCK_DGRAM)
405184588Sdfr		xprt = svc_dg_create(nfsrv_pool, so, 0, 0);
406184588Sdfr	else
407184588Sdfr		xprt = svc_vc_create(nfsrv_pool, so, 0, 0);
408184588Sdfr	if (xprt) {
409184588Sdfr		fp->f_ops = &badfileops;
410184588Sdfr		fp->f_data = NULL;
411184588Sdfr		svc_reg(xprt, NFS_PROG, NFS_VER2, nfssvc_program, NULL);
412184588Sdfr		svc_reg(xprt, NFS_PROG, NFS_VER3, nfssvc_program, NULL);
413194407Srmacklem		SVC_RELEASE(xprt);
414184588Sdfr	}
415184588Sdfr
416184588Sdfr	return (0);
417184588Sdfr}
418184588Sdfr
419184588Sdfr/*
420201899Smarius * Called by nfssvc() for nfsds.  Just loops around servicing rpc requests
421184588Sdfr * until it is killed by a signal.
422184588Sdfr */
423184588Sdfrstatic int
424184588Sdfrnfssvc_nfsd(struct thread *td, struct nfsd_nfsd_args *args)
425184588Sdfr{
426184588Sdfr	char principal[128];
427184588Sdfr	int error;
428184588Sdfr
429184588Sdfr	if (args) {
430184588Sdfr		error = copyinstr(args->principal, principal,
431184588Sdfr		    sizeof(principal), NULL);
432184588Sdfr		if (error)
433184588Sdfr			return (error);
434184588Sdfr	} else {
435193066Sjamie		memcpy(principal, "nfs@", 4);
436193066Sjamie		getcredhostname(td->td_ucred, principal + 4,
437193066Sjamie		    sizeof(principal) - 4);
438184588Sdfr	}
439184588Sdfr
440184588Sdfr	/*
441201899Smarius	 * Only the first nfsd actually does any work.  The RPC code
442201899Smarius	 * adds threads to it as needed.  Any extra processes offered
443201899Smarius	 * by nfsd just exit.  If nfsd is new enough, it will call us
444184588Sdfr	 * once with a structure that specifies how many threads to
445184588Sdfr	 * use.
446184588Sdfr	 */
447184588Sdfr	NFSD_LOCK();
448184588Sdfr	if (nfsrv_numnfsd == 0) {
449184588Sdfr		nfsrv_numnfsd++;
450184588Sdfr
451184588Sdfr		NFSD_UNLOCK();
452184588Sdfr
453223309Srmacklem		rpc_gss_set_svc_name_call(principal, "kerberosv5",
454184588Sdfr		    GSS_C_INDEFINITE, NFS_PROG, NFS_VER2);
455223309Srmacklem		rpc_gss_set_svc_name_call(principal, "kerberosv5",
456184588Sdfr		    GSS_C_INDEFINITE, NFS_PROG, NFS_VER3);
457184588Sdfr
458184588Sdfr		if (args) {
459184588Sdfr			nfsrv_pool->sp_minthreads = args->minthreads;
460184588Sdfr			nfsrv_pool->sp_maxthreads = args->maxthreads;
461184588Sdfr		} else {
462184588Sdfr			nfsrv_pool->sp_minthreads = 4;
463184588Sdfr			nfsrv_pool->sp_maxthreads = 4;
464184588Sdfr		}
465201899Smarius
466184588Sdfr		svc_run(nfsrv_pool);
467184588Sdfr
468223309Srmacklem		rpc_gss_clear_svc_name_call(NFS_PROG, NFS_VER2);
469223309Srmacklem		rpc_gss_clear_svc_name_call(NFS_PROG, NFS_VER3);
470184588Sdfr
471184588Sdfr		NFSD_LOCK();
472184588Sdfr		nfsrv_numnfsd--;
473184588Sdfr		nfsrv_init(TRUE);
474184588Sdfr	}
475184588Sdfr	NFSD_UNLOCK();
476184588Sdfr
477184588Sdfr	return (0);
478184588Sdfr}
479184588Sdfr
480184588Sdfr/*
481184588Sdfr * Size the NFS server's duplicate request cache at 1/2 the
482201899Smarius * nmbclusters, floating within a (64, 2048) range.  This is to
483184588Sdfr * prevent all mbuf clusters being tied up in the NFS dupreq
484184588Sdfr * cache for small values of nmbclusters.
485184588Sdfr */
486184588Sdfrstatic size_t
487184588Sdfrnfsrv_replay_size(void)
488184588Sdfr{
489184588Sdfr	size_t replaysiz;
490184588Sdfr
491184588Sdfr	replaysiz = nmbclusters / 2;
492184588Sdfr	if (replaysiz > NFSRVCACHE_MAX_SIZE)
493184588Sdfr		replaysiz = NFSRVCACHE_MAX_SIZE;
494184588Sdfr	if (replaysiz < NFSRVCACHE_MIN_SIZE)
495184588Sdfr		replaysiz = NFSRVCACHE_MIN_SIZE;
496184588Sdfr	replaysiz *= MCLBYTES;
497184588Sdfr
498184588Sdfr	return (replaysiz);
499184588Sdfr}
500184588Sdfr
501184588Sdfr/*
502184588Sdfr * Called when nmbclusters changes - we resize the replay cache
503184588Sdfr * accordingly.
504184588Sdfr */
505184588Sdfrstatic void
506184588Sdfrnfsrv_nmbclusters_change(void *tag)
507184588Sdfr{
508184588Sdfr
509184588Sdfr	if (nfsrv_pool)
510184588Sdfr		replay_setsize(nfsrv_pool->sp_rcache, nfsrv_replay_size());
511184588Sdfr}
512184588Sdfr
513184588Sdfr/*
514184588Sdfr * Initialize the data structures for the server.
515184588Sdfr * Handshake with any new nfsds starting up to avoid any chance of
516184588Sdfr * corruption.
517184588Sdfr */
518184588Sdfrvoid
519184588Sdfrnfsrv_init(int terminating)
520184588Sdfr{
521184588Sdfr
522184588Sdfr	NFSD_LOCK_ASSERT();
523184588Sdfr
524184588Sdfr	if (terminating) {
525184588Sdfr		NFSD_UNLOCK();
526184588Sdfr		EVENTHANDLER_DEREGISTER(nmbclusters_change,
527184588Sdfr		    nfsrv_nmbclusters_tag);
528184588Sdfr		svcpool_destroy(nfsrv_pool);
529184588Sdfr		nfsrv_pool = NULL;
530184588Sdfr		NFSD_LOCK();
531184588Sdfr	} else
532184588Sdfr		nfs_pub.np_valid = 0;
533184588Sdfr
534184588Sdfr	NFSD_UNLOCK();
535184588Sdfr
536184588Sdfr	nfsrv_pool = svcpool_create("nfsd", SYSCTL_STATIC_CHILDREN(_vfs_nfsrv));
537184588Sdfr	nfsrv_pool->sp_rcache = replay_newcache(nfsrv_replay_size());
538249592Sken	nfsrv_pool->sp_assign = fhaold_assign;
539184588Sdfr	nfsrv_pool->sp_done = fha_nd_complete;
540184588Sdfr	nfsrv_nmbclusters_tag = EVENTHANDLER_REGISTER(nmbclusters_change,
541184588Sdfr	    nfsrv_nmbclusters_change, NULL, EVENTHANDLER_PRI_FIRST);
542184588Sdfr
543184588Sdfr	NFSD_LOCK();
544184588Sdfr}
545