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