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