nfs_srvkrpc.c revision 190971
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: head/sys/nfsserver/nfs_srvkrpc.c 190971 2009-04-12 19:04:27Z rmacklem $");
37184588Sdfr
38184588Sdfr#include "opt_inet6.h"
39184588Sdfr#include "opt_kgssapi.h"
40184588Sdfr
41184588Sdfr#include <sys/param.h>
42184588Sdfr#include <sys/systm.h>
43184588Sdfr#include <sys/sysproto.h>
44184588Sdfr#include <sys/kernel.h>
45184588Sdfr#include <sys/sysctl.h>
46184588Sdfr#include <sys/file.h>
47184588Sdfr#include <sys/filedesc.h>
48184588Sdfr#include <sys/vnode.h>
49184588Sdfr#include <sys/malloc.h>
50184588Sdfr#include <sys/mount.h>
51184588Sdfr#include <sys/priv.h>
52184588Sdfr#include <sys/proc.h>
53184588Sdfr#include <sys/bio.h>
54184588Sdfr#include <sys/buf.h>
55184588Sdfr#include <sys/mbuf.h>
56184588Sdfr#include <sys/socket.h>
57184588Sdfr#include <sys/socketvar.h>
58184588Sdfr#include <sys/domain.h>
59184588Sdfr#include <sys/protosw.h>
60184588Sdfr#include <sys/namei.h>
61184588Sdfr#include <sys/fcntl.h>
62184588Sdfr#include <sys/lockf.h>
63184643Sdfr#include <sys/eventhandler.h>
64184588Sdfr
65184588Sdfr#include <netinet/in.h>
66184588Sdfr#include <netinet/tcp.h>
67184588Sdfr#ifdef INET6
68184588Sdfr#include <net/if.h>
69184588Sdfr#include <netinet6/in6_var.h>
70184588Sdfr#endif
71184588Sdfr
72184588Sdfr#include <rpc/rpc.h>
73184588Sdfr#include <rpc/rpcsec_gss.h>
74184588Sdfr#include <rpc/replay.h>
75184588Sdfr
76184588Sdfr#include <nfs/xdr_subs.h>
77184588Sdfr#include <nfs/rpcv2.h>
78184588Sdfr#include <nfs/nfsproto.h>
79184588Sdfr#include <nfsserver/nfs.h>
80184588Sdfr#include <nfsserver/nfsm_subs.h>
81184588Sdfr#include <nfsserver/nfsrvcache.h>
82184588Sdfr#include <nfsserver/nfs_fha.h>
83184588Sdfr
84184588Sdfr#ifndef NFS_LEGACYRPC
85184588Sdfr
86184588Sdfrstatic MALLOC_DEFINE(M_NFSSVC, "nfss_srvsock", "Nfs server structure");
87184588Sdfr
88184588SdfrMALLOC_DEFINE(M_NFSRVDESC, "nfss_srvdesc", "NFS server socket descriptor");
89184588SdfrMALLOC_DEFINE(M_NFSD, "nfss_daemon", "Nfs server daemon structure");
90184588Sdfr
91184588Sdfr#define	TRUE	1
92184588Sdfr#define	FALSE	0
93184588Sdfr
94184588SdfrSYSCTL_DECL(_vfs_nfsrv);
95184588Sdfr
96184588SdfrSVCPOOL		*nfsrv_pool;
97184588Sdfrint		nfsd_waiting = 0;
98184588Sdfrint		nfsrv_numnfsd = 0;
99184588Sdfrstatic int	nfs_realign_test;
100184588Sdfrstatic int	nfs_realign_count;
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");
114184588SdfrSYSCTL_INT(_vfs_nfsrv, OID_AUTO, realign_test, CTLFLAG_RW,
115184588Sdfr	    &nfs_realign_test, 0, "");
116184588SdfrSYSCTL_INT(_vfs_nfsrv, OID_AUTO, realign_count, CTLFLAG_RW,
117184588Sdfr	    &nfs_realign_count, 0, "");
118184588Sdfr
119184588Sdfrstatic int	nfssvc_addsock(struct file *, struct thread *);
120184588Sdfrstatic int	nfssvc_nfsd(struct thread *, struct nfsd_nfsd_args *);
121184588Sdfr
122184588Sdfrextern u_long sb_max_adj;
123184588Sdfr
124184588Sdfrint32_t (*nfsrv3_procs[NFS_NPROCS])(struct nfsrv_descript *nd,
125184588Sdfr    struct nfssvc_sock *slp, struct mbuf **mreqp) = {
126184588Sdfr	nfsrv_null,
127184588Sdfr	nfsrv_getattr,
128184588Sdfr	nfsrv_setattr,
129184588Sdfr	nfsrv_lookup,
130184588Sdfr	nfsrv3_access,
131184588Sdfr	nfsrv_readlink,
132184588Sdfr	nfsrv_read,
133184588Sdfr	nfsrv_write,
134184588Sdfr	nfsrv_create,
135184588Sdfr	nfsrv_mkdir,
136184588Sdfr	nfsrv_symlink,
137184588Sdfr	nfsrv_mknod,
138184588Sdfr	nfsrv_remove,
139184588Sdfr	nfsrv_rmdir,
140184588Sdfr	nfsrv_rename,
141184588Sdfr	nfsrv_link,
142184588Sdfr	nfsrv_readdir,
143184588Sdfr	nfsrv_readdirplus,
144184588Sdfr	nfsrv_statfs,
145184588Sdfr	nfsrv_fsinfo,
146184588Sdfr	nfsrv_pathconf,
147184588Sdfr	nfsrv_commit,
148184588Sdfr	nfsrv_noop
149184588Sdfr};
150184588Sdfr
151184588Sdfr/*
152184588Sdfr * NFS server system calls
153184588Sdfr */
154190971Srmacklem/*
155190971Srmacklem * This is now called from nfssvc() in nfs/nfs_nfssvc.c.
156190971Srmacklem */
157184588Sdfr
158184588Sdfr/*
159184588Sdfr * Nfs server psuedo system call for the nfsd's
160184588Sdfr * Based on the flag value it either:
161184588Sdfr * - adds a socket to the selection list
162184588Sdfr * - remains in the kernel as an nfsd
163184588Sdfr * - remains in the kernel as an nfsiod
164184588Sdfr * For INET6 we suppose that nfsd provides only IN6P_IPV6_V6ONLY sockets
165184588Sdfr * and that mountd provides
166184588Sdfr *  - sockaddr with no IPv4-mapped addresses
167184588Sdfr *  - mask for both INET and INET6 families if there is IPv4-mapped overlap
168184588Sdfr */
169184588Sdfrint
170190971Srmacklemnfssvc_nfsserver(struct thread *td, struct nfssvc_args *uap)
171184588Sdfr{
172184588Sdfr	struct file *fp;
173184588Sdfr	struct nfsd_addsock_args addsockarg;
174184588Sdfr	struct nfsd_nfsd_args nfsdarg;
175184588Sdfr	int error;
176184588Sdfr
177184588Sdfr	if (uap->flag & NFSSVC_ADDSOCK) {
178184588Sdfr		error = copyin(uap->argp, (caddr_t)&addsockarg,
179184588Sdfr		    sizeof(addsockarg));
180184588Sdfr		if (error)
181184588Sdfr			return (error);
182184588Sdfr		if ((error = fget(td, addsockarg.sock, &fp)) != 0)
183184588Sdfr			return (error);
184184588Sdfr		if (fp->f_type != DTYPE_SOCKET) {
185184588Sdfr			fdrop(fp, td);
186184588Sdfr			return (error);	/* XXXRW: Should be EINVAL? */
187184588Sdfr		}
188184588Sdfr		error = nfssvc_addsock(fp, td);
189184588Sdfr		fdrop(fp, td);
190184588Sdfr	} else if (uap->flag & NFSSVC_OLDNFSD) {
191184588Sdfr		error = nfssvc_nfsd(td, NULL);
192184588Sdfr	} else if (uap->flag & NFSSVC_NFSD) {
193184588Sdfr		if (!uap->argp)
194184588Sdfr			return (EINVAL);
195184588Sdfr		error = copyin(uap->argp, (caddr_t)&nfsdarg,
196184588Sdfr		    sizeof(nfsdarg));
197184588Sdfr		if (error)
198184588Sdfr			return (error);
199184588Sdfr		error = nfssvc_nfsd(td, &nfsdarg);
200184588Sdfr	} else {
201184588Sdfr		error = ENXIO;
202184588Sdfr	}
203184588Sdfr	return (error);
204184588Sdfr}
205184588Sdfr
206184588Sdfr/*
207184588Sdfr * Generate the rpc reply header
208184588Sdfr * siz arg. is used to decide if adding a cluster is worthwhile
209184588Sdfr */
210184588Sdfrstruct mbuf *
211184588Sdfrnfs_rephead(int siz, struct nfsrv_descript *nd, int err,
212184588Sdfr    struct mbuf **mbp, caddr_t *bposp)
213184588Sdfr{
214184588Sdfr	u_int32_t *tl;
215184588Sdfr	struct mbuf *mreq;
216184588Sdfr	caddr_t bpos;
217184588Sdfr	struct mbuf *mb;
218184588Sdfr
219184588Sdfr	if (err == EBADRPC)
220184588Sdfr		return (NULL);
221184588Sdfr
222184588Sdfr	nd->nd_repstat = err;
223184588Sdfr	if (err && (nd->nd_flag & ND_NFSV3) == 0)	/* XXX recheck */
224184588Sdfr		siz = 0;
225184588Sdfr
226184588Sdfr	MGET(mreq, M_WAIT, MT_DATA);
227184588Sdfr
228184588Sdfr	/*
229184588Sdfr	 * If this is a big reply, use a cluster
230184588Sdfr	 */
231184588Sdfr	mreq->m_len = 0;
232184588Sdfr	if (siz >= MINCLSIZE) {
233184588Sdfr		MCLGET(mreq, M_WAIT);
234184588Sdfr	}
235184588Sdfr	mb = mreq;
236184588Sdfr	bpos = mtod(mb, caddr_t);
237184588Sdfr
238184588Sdfr	if (err != NFSERR_RETVOID) {
239184588Sdfr		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
240184588Sdfr		if (err)
241184588Sdfr			*tl = txdr_unsigned(nfsrv_errmap(nd, err));
242184588Sdfr		else
243184588Sdfr			*tl = 0;
244184588Sdfr	}
245184588Sdfr
246184588Sdfr	*mbp = mb;
247184588Sdfr	*bposp = bpos;
248184588Sdfr	if (err != 0 && err != NFSERR_RETVOID)
249184588Sdfr		nfsrvstats.srvrpc_errs++;
250184588Sdfr
251184588Sdfr	return (mreq);
252184588Sdfr}
253184588Sdfr
254184588Sdfr/*
255184588Sdfr *	nfs_realign:
256184588Sdfr *
257184588Sdfr *	Check for badly aligned mbuf data and realign by copying the unaligned
258184588Sdfr *	portion of the data into a new mbuf chain and freeing the portions
259184588Sdfr *	of the old chain that were replaced.
260184588Sdfr *
261184588Sdfr *	We cannot simply realign the data within the existing mbuf chain
262184588Sdfr *	because the underlying buffers may contain other rpc commands and
263184588Sdfr *	we cannot afford to overwrite them.
264184588Sdfr *
265184588Sdfr *	We would prefer to avoid this situation entirely.  The situation does
266184588Sdfr *	not occur with NFS/UDP and is supposed to only occassionally occur
267184588Sdfr *	with TCP.  Use vfs.nfs.realign_count and realign_test to check this.
268184588Sdfr */
269184588Sdfrstatic void
270184588Sdfrnfs_realign(struct mbuf **pm)	/* XXX COMMON */
271184588Sdfr{
272184588Sdfr	struct mbuf *m;
273184588Sdfr	struct mbuf *n = NULL;
274184588Sdfr	int off = 0;
275184588Sdfr
276184588Sdfr	++nfs_realign_test;
277184588Sdfr	while ((m = *pm) != NULL) {
278184588Sdfr		if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) {
279184588Sdfr			MGET(n, M_WAIT, MT_DATA);
280184588Sdfr			if (m->m_len >= MINCLSIZE) {
281184588Sdfr				MCLGET(n, M_WAIT);
282184588Sdfr			}
283184588Sdfr			n->m_len = 0;
284184588Sdfr			break;
285184588Sdfr		}
286184588Sdfr		pm = &m->m_next;
287184588Sdfr	}
288184588Sdfr
289184588Sdfr	/*
290184588Sdfr	 * If n is non-NULL, loop on m copying data, then replace the
291184588Sdfr	 * portion of the chain that had to be realigned.
292184588Sdfr	 */
293184588Sdfr	if (n != NULL) {
294184588Sdfr		++nfs_realign_count;
295184588Sdfr		while (m) {
296184588Sdfr			m_copyback(n, off, m->m_len, mtod(m, caddr_t));
297184588Sdfr			off += m->m_len;
298184588Sdfr			m = m->m_next;
299184588Sdfr		}
300184588Sdfr		m_freem(*pm);
301184588Sdfr		*pm = n;
302184588Sdfr	}
303184588Sdfr}
304184588Sdfr
305184588Sdfrstatic void
306184588Sdfrnfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
307184588Sdfr{
308184588Sdfr	rpcproc_t procnum;
309184588Sdfr	int32_t (*proc)(struct nfsrv_descript *nd, struct nfssvc_sock *slp,
310184588Sdfr	    struct mbuf **mreqp);
311184588Sdfr	int flag;
312184588Sdfr	struct nfsrv_descript nd;
313184588Sdfr	struct mbuf *mreq, *mrep;
314184588Sdfr	int error;
315184588Sdfr
316184588Sdfr	if (rqst->rq_vers == NFS_VER2) {
317184588Sdfr		if (rqst->rq_proc > NFSV2PROC_STATFS) {
318184588Sdfr			svcerr_noproc(rqst);
319184588Sdfr			svc_freereq(rqst);
320184588Sdfr			return;
321184588Sdfr		}
322184588Sdfr		procnum = nfsrv_nfsv3_procid[rqst->rq_proc];
323184588Sdfr		flag = 0;
324184588Sdfr	} else {
325184588Sdfr		if (rqst->rq_proc >= NFS_NPROCS) {
326184588Sdfr			svcerr_noproc(rqst);
327184588Sdfr			svc_freereq(rqst);
328184588Sdfr			return;
329184588Sdfr		}
330184588Sdfr		procnum = rqst->rq_proc;
331184588Sdfr		flag = ND_NFSV3;
332184588Sdfr	}
333184588Sdfr	proc = nfsrv3_procs[procnum];
334184588Sdfr
335184588Sdfr	mreq = mrep = NULL;
336184588Sdfr	mreq = rqst->rq_args;
337184588Sdfr	rqst->rq_args = NULL;
338184588Sdfr	nfs_realign(&mreq);
339184588Sdfr
340184588Sdfr	/*
341184921Sdfr	 * Note: we want rq_addr, not svc_getrpccaller for nd_nam2 -
342184588Sdfr	 * NFS_SRVMAXDATA uses a NULL value for nd_nam2 to detect TCP
343184588Sdfr	 * mounts.
344184588Sdfr	 */
345184588Sdfr	memset(&nd, 0, sizeof(nd));
346184588Sdfr	nd.nd_md = nd.nd_mrep = mreq;
347184588Sdfr	nd.nd_dpos = mtod(mreq, caddr_t);
348184921Sdfr	nd.nd_nam = svc_getrpccaller(rqst);
349184588Sdfr	nd.nd_nam2 = rqst->rq_addr;
350184588Sdfr	nd.nd_procnum = procnum;
351184588Sdfr	nd.nd_cr = NULL;
352184588Sdfr	nd.nd_flag = flag;
353184588Sdfr
354184921Sdfr	if (nfs_privport) {
355184921Sdfr		/* Check if source port is privileged */
356184921Sdfr		u_short port;
357184921Sdfr		struct sockaddr *nam = nd.nd_nam;
358184921Sdfr		struct sockaddr_in *sin;
359184921Sdfr
360184921Sdfr		sin = (struct sockaddr_in *)nam;
361184921Sdfr		/*
362184921Sdfr		 * INET/INET6 - same code:
363184921Sdfr		 *    sin_port and sin6_port are at same offset
364184921Sdfr		 */
365184921Sdfr		port = ntohs(sin->sin_port);
366184921Sdfr		if (port >= IPPORT_RESERVED &&
367184921Sdfr		    nd.nd_procnum != NFSPROC_NULL) {
368184921Sdfr#ifdef INET6
369184921Sdfr			char b6[INET6_ADDRSTRLEN];
370184921Sdfr#if defined(KLD_MODULE)
371184921Sdfr			/* Do not use ip6_sprintf: the nfs module should work without INET6. */
372184921Sdfr#define ip6_sprintf(buf, a)						\
373184921Sdfr			(sprintf((buf), "%x:%x:%x:%x:%x:%x:%x:%x",	\
374184921Sdfr			    (a)->s6_addr16[0], (a)->s6_addr16[1],	\
375184921Sdfr			    (a)->s6_addr16[2], (a)->s6_addr16[3],	\
376184921Sdfr			    (a)->s6_addr16[4], (a)->s6_addr16[5],	\
377184921Sdfr			    (a)->s6_addr16[6], (a)->s6_addr16[7]),	\
378184921Sdfr			    (buf))
379184921Sdfr#endif
380184921Sdfr#endif
381184921Sdfr			printf("NFS request from unprivileged port (%s:%d)\n",
382184921Sdfr#ifdef INET6
383184921Sdfr			    sin->sin_family == AF_INET6 ?
384184921Sdfr			    ip6_sprintf(b6, &satosin6(sin)->sin6_addr) :
385184921Sdfr#if defined(KLD_MODULE)
386184921Sdfr#undef ip6_sprintf
387184921Sdfr#endif
388184921Sdfr#endif
389184921Sdfr			    inet_ntoa(sin->sin_addr), port);
390190053Sdfr			m_freem(mreq);
391184921Sdfr			svcerr_weakauth(rqst);
392184921Sdfr			svc_freereq(rqst);
393184921Sdfr			return;
394184921Sdfr		}
395184921Sdfr	}
396184921Sdfr
397184588Sdfr	if (proc != nfsrv_null) {
398184588Sdfr		if (!svc_getcred(rqst, &nd.nd_cr, &nd.nd_credflavor)) {
399190053Sdfr			m_freem(mreq);
400184588Sdfr			svcerr_weakauth(rqst);
401184588Sdfr			svc_freereq(rqst);
402184588Sdfr			return;
403184588Sdfr		}
404184588Sdfr#ifdef MAC
405184588Sdfr		mac_cred_associate_nfsd(nd.nd_cr);
406184588Sdfr#endif
407184588Sdfr	}
408184588Sdfr	nfsrvstats.srvrpccnt[nd.nd_procnum]++;
409184588Sdfr
410184588Sdfr	error = proc(&nd, NULL, &mrep);
411184588Sdfr
412184588Sdfr	if (nd.nd_cr)
413184588Sdfr		crfree(nd.nd_cr);
414184588Sdfr
415184588Sdfr	if (mrep == NULL) {
416184588Sdfr		svcerr_decode(rqst);
417184588Sdfr		svc_freereq(rqst);
418184588Sdfr		return;
419184588Sdfr	}
420184588Sdfr	if (error && error != NFSERR_RETVOID) {
421184588Sdfr		svcerr_systemerr(rqst);
422184588Sdfr		svc_freereq(rqst);
423184588Sdfr		return;
424184588Sdfr	}
425184869Sdfr	if (nd.nd_repstat & NFSERR_AUTHERR) {
426184869Sdfr		svcerr_auth(rqst, nd.nd_repstat & ~NFSERR_AUTHERR);
427184869Sdfr		m_freem(mrep);
428184869Sdfr	} else {
429184869Sdfr		if (!svc_sendreply_mbuf(rqst, mrep))
430184869Sdfr			svcerr_systemerr(rqst);
431184869Sdfr	}
432184588Sdfr	svc_freereq(rqst);
433184588Sdfr}
434184588Sdfr
435184588Sdfr/*
436184588Sdfr * Adds a socket to the list for servicing by nfsds.
437184588Sdfr */
438184588Sdfrstatic int
439184588Sdfrnfssvc_addsock(struct file *fp, struct thread *td)
440184588Sdfr{
441184588Sdfr	int siz;
442184588Sdfr	struct socket *so;
443184588Sdfr	int error;
444184588Sdfr	SVCXPRT *xprt;
445184588Sdfr
446184588Sdfr	so = fp->f_data;
447184588Sdfr
448184588Sdfr	siz = sb_max_adj;
449184588Sdfr	error = soreserve(so, siz, siz);
450184588Sdfr	if (error) {
451184588Sdfr		return (error);
452184588Sdfr	}
453184588Sdfr
454184588Sdfr	/*
455184588Sdfr	 * Steal the socket from userland so that it doesn't close
456184588Sdfr	 * unexpectedly.
457184588Sdfr	 */
458184588Sdfr	if (so->so_type == SOCK_DGRAM)
459184588Sdfr		xprt = svc_dg_create(nfsrv_pool, so, 0, 0);
460184588Sdfr	else
461184588Sdfr		xprt = svc_vc_create(nfsrv_pool, so, 0, 0);
462184588Sdfr	if (xprt) {
463184588Sdfr		fp->f_ops = &badfileops;
464184588Sdfr		fp->f_data = NULL;
465184588Sdfr		svc_reg(xprt, NFS_PROG, NFS_VER2, nfssvc_program, NULL);
466184588Sdfr		svc_reg(xprt, NFS_PROG, NFS_VER3, nfssvc_program, NULL);
467184588Sdfr	}
468184588Sdfr
469184588Sdfr	return (0);
470184588Sdfr}
471184588Sdfr
472184588Sdfr/*
473184588Sdfr * Called by nfssvc() for nfsds. Just loops around servicing rpc requests
474184588Sdfr * until it is killed by a signal.
475184588Sdfr */
476184588Sdfrstatic int
477184588Sdfrnfssvc_nfsd(struct thread *td, struct nfsd_nfsd_args *args)
478184588Sdfr{
479184588Sdfr#ifdef KGSSAPI
480184588Sdfr	char principal[128];
481184588Sdfr	int error;
482184588Sdfr#endif
483184588Sdfr
484184588Sdfr#ifdef KGSSAPI
485184588Sdfr	if (args) {
486184588Sdfr		error = copyinstr(args->principal, principal,
487184588Sdfr		    sizeof(principal), NULL);
488184588Sdfr		if (error)
489184588Sdfr			return (error);
490184588Sdfr	} else {
491184588Sdfr		snprintf(principal, sizeof(principal), "nfs@%s", hostname);
492184588Sdfr	}
493184588Sdfr#endif
494184588Sdfr
495184588Sdfr	/*
496184588Sdfr	 * Only the first nfsd actually does any work. The RPC code
497184588Sdfr	 * adds threads to it as needed. Any extra processes offered
498184588Sdfr	 * by nfsd just exit. If nfsd is new enough, it will call us
499184588Sdfr	 * once with a structure that specifies how many threads to
500184588Sdfr	 * use.
501184588Sdfr	 */
502184588Sdfr	NFSD_LOCK();
503184588Sdfr	if (nfsrv_numnfsd == 0) {
504184588Sdfr		nfsrv_numnfsd++;
505184588Sdfr
506184588Sdfr		NFSD_UNLOCK();
507184588Sdfr
508184588Sdfr#ifdef KGSSAPI
509184588Sdfr		rpc_gss_set_svc_name(principal, "kerberosv5",
510184588Sdfr		    GSS_C_INDEFINITE, NFS_PROG, NFS_VER2);
511184588Sdfr		rpc_gss_set_svc_name(principal, "kerberosv5",
512184588Sdfr		    GSS_C_INDEFINITE, NFS_PROG, NFS_VER3);
513184588Sdfr#endif
514184588Sdfr
515184588Sdfr		if (args) {
516184588Sdfr			nfsrv_pool->sp_minthreads = args->minthreads;
517184588Sdfr			nfsrv_pool->sp_maxthreads = args->maxthreads;
518184588Sdfr		} else {
519184588Sdfr			nfsrv_pool->sp_minthreads = 4;
520184588Sdfr			nfsrv_pool->sp_maxthreads = 4;
521184588Sdfr		}
522184588Sdfr
523184588Sdfr		svc_run(nfsrv_pool);
524184588Sdfr
525184588Sdfr#ifdef KGSSAPI
526184588Sdfr		rpc_gss_clear_svc_name(NFS_PROG, NFS_VER2);
527184588Sdfr		rpc_gss_clear_svc_name(NFS_PROG, NFS_VER3);
528184588Sdfr#endif
529184588Sdfr
530184588Sdfr		NFSD_LOCK();
531184588Sdfr		nfsrv_numnfsd--;
532184588Sdfr		nfsrv_init(TRUE);
533184588Sdfr	}
534184588Sdfr	NFSD_UNLOCK();
535184588Sdfr
536184588Sdfr	return (0);
537184588Sdfr}
538184588Sdfr
539184588Sdfr/*
540184588Sdfr * Size the NFS server's duplicate request cache at 1/2 the
541184588Sdfr * nmbclusters, floating within a (64, 2048) range. This is to
542184588Sdfr * prevent all mbuf clusters being tied up in the NFS dupreq
543184588Sdfr * cache for small values of nmbclusters.
544184588Sdfr */
545184588Sdfrstatic size_t
546184588Sdfrnfsrv_replay_size(void)
547184588Sdfr{
548184588Sdfr	size_t replaysiz;
549184588Sdfr
550184588Sdfr	replaysiz = nmbclusters / 2;
551184588Sdfr	if (replaysiz > NFSRVCACHE_MAX_SIZE)
552184588Sdfr		replaysiz = NFSRVCACHE_MAX_SIZE;
553184588Sdfr	if (replaysiz < NFSRVCACHE_MIN_SIZE)
554184588Sdfr		replaysiz = NFSRVCACHE_MIN_SIZE;
555184588Sdfr	replaysiz *= MCLBYTES;
556184588Sdfr
557184588Sdfr	return (replaysiz);
558184588Sdfr}
559184588Sdfr
560184588Sdfr/*
561184588Sdfr * Called when nmbclusters changes - we resize the replay cache
562184588Sdfr * accordingly.
563184588Sdfr */
564184588Sdfrstatic void
565184588Sdfrnfsrv_nmbclusters_change(void *tag)
566184588Sdfr{
567184588Sdfr
568184588Sdfr	if (nfsrv_pool)
569184588Sdfr		replay_setsize(nfsrv_pool->sp_rcache, nfsrv_replay_size());
570184588Sdfr}
571184588Sdfr
572184588Sdfr/*
573184588Sdfr * Initialize the data structures for the server.
574184588Sdfr * Handshake with any new nfsds starting up to avoid any chance of
575184588Sdfr * corruption.
576184588Sdfr */
577184588Sdfrvoid
578184588Sdfrnfsrv_init(int terminating)
579184588Sdfr{
580184588Sdfr
581184588Sdfr	NFSD_LOCK_ASSERT();
582184588Sdfr
583184588Sdfr	if (terminating) {
584184588Sdfr		NFSD_UNLOCK();
585184588Sdfr		EVENTHANDLER_DEREGISTER(nmbclusters_change,
586184588Sdfr		    nfsrv_nmbclusters_tag);
587184588Sdfr		svcpool_destroy(nfsrv_pool);
588184588Sdfr		nfsrv_pool = NULL;
589184588Sdfr		NFSD_LOCK();
590184588Sdfr	} else
591184588Sdfr		nfs_pub.np_valid = 0;
592184588Sdfr
593184588Sdfr	NFSD_UNLOCK();
594184588Sdfr
595184588Sdfr	nfsrv_pool = svcpool_create("nfsd", SYSCTL_STATIC_CHILDREN(_vfs_nfsrv));
596184588Sdfr	nfsrv_pool->sp_rcache = replay_newcache(nfsrv_replay_size());
597184588Sdfr	nfsrv_pool->sp_assign = fha_assign;
598184588Sdfr	nfsrv_pool->sp_done = fha_nd_complete;
599184588Sdfr	nfsrv_nmbclusters_tag = EVENTHANDLER_REGISTER(nmbclusters_change,
600184588Sdfr	    nfsrv_nmbclusters_change, NULL, EVENTHANDLER_PRI_FIRST);
601184588Sdfr
602184588Sdfr	NFSD_LOCK();
603184588Sdfr}
604184588Sdfr
605184588Sdfr#endif /* !NFS_LEGACYRPC */
606