Index: head/sys/nfsserver/nfs.h =================================================================== --- head/sys/nfsserver/nfs.h (revision 201898) +++ head/sys/nfsserver/nfs.h (revision 201899) @@ -1,322 +1,321 @@ /*- * Copyright (c) 1989, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Rick Macklem at The University of Guelph. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)nfs.h 8.4 (Berkeley) 5/1/95 * $FreeBSD$ */ #ifndef _NFSSERVER_NFS_H_ #define _NFSSERVER_NFS_H_ #ifdef _KERNEL #include "opt_nfs.h" #endif #include /* * Tunable constants for nfs */ #define NFS_TICKINTVL 10 /* Desired time for a tick (msec) */ #define NFS_HZ (hz / nfs_ticks) /* Ticks/sec */ #define NFS_TIMEO (1 * NFS_HZ) /* Default timeout = 1 second */ #define NFS_MINTIMEO (1 * NFS_HZ) /* Min timeout to use */ #define NFS_MAXTIMEO (60 * NFS_HZ) /* Max timeout to backoff to */ #define NFS_MINIDEMTIMEO (5 * NFS_HZ) /* Min timeout for non-idempotent ops*/ #define NFS_MAXUIDHASH 64 /* Max. # of hashed uid entries/mp */ #ifndef NFS_GATHERDELAY #define NFS_GATHERDELAY 10 /* Default write gather delay (msec) */ #endif #ifdef _KERNEL #define DIRBLKSIZ 512 /* XXX we used to use ufs's DIRBLKSIZ */ #endif /* * Oddballs */ #define NFS_SRVMAXDATA(n) \ (((n)->nd_flag & ND_NFSV3) ? (((n)->nd_nam2) ? \ NFS_MAXDGRAMDATA : NFS_MAXDATA) : NFS_V2MAXDATA) /* * XXX * The B_INVAFTERWRITE flag should be set to whatever is required by the * buffer cache code to say "Invalidate the block after it is written back". */ #define B_INVAFTERWRITE B_NOCACHE /* * The IO_METASYNC flag should be implemented for local filesystems. * (Until then, it is nothin at all.) */ #ifndef IO_METASYNC #define IO_METASYNC 0 #endif - /* NFS state flags XXX -Wunused */ #define NFSRV_SNDLOCK 0x01000000 /* Send socket lock */ #define NFSRV_WANTSND 0x02000000 /* Want above */ /* - * Structures for the nfssvc(2) syscall. Not that anyone but nfsd and mount_nfs - * should ever try and use it. + * Structures for the nfssvc(2) syscall. Not that anyone but nfsd and + * mount_nfs should ever try and use it. */ /* * Add a socket to monitor for NFS requests. */ struct nfsd_addsock_args { int sock; /* Socket to serve */ caddr_t name; /* Client addr for connection based sockets */ int namelen; /* Length of name */ }; /* * Start processing requests. */ struct nfsd_nfsd_args { const char *principal; /* GSS-API service principal name */ int minthreads; /* minimum service thread count */ int maxthreads; /* maximum service thread count */ }; /* * XXX to allow amd to include nfs.h without nfsproto.h */ #ifdef NFS_NPROCS #include #endif /* * vfs.nfsrv sysctl(3) identifiers */ #define NFS_NFSRVSTATS 1 /* struct: struct nfsrvstats */ #define NFS_NFSPRIVPORT 2 /* int: prohibit nfs to resvports */ #ifdef _KERNEL extern struct mtx nfsd_mtx; #define NFSD_LOCK_ASSERT() mtx_assert(&nfsd_mtx, MA_OWNED) #define NFSD_UNLOCK_ASSERT() mtx_assert(&nfsd_mtx, MA_NOTOWNED) #define NFSD_LOCK_DONTCARE() #define NFSD_LOCK() mtx_lock(&nfsd_mtx) #define NFSD_UNLOCK() mtx_unlock(&nfsd_mtx) #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_NFSRVDESC); MALLOC_DECLARE(M_NFSD); #endif /* Forward declarations */ struct nfssvc_sock; struct nfsrv_descript; struct uio; struct vattr; struct nameidata; extern struct callout nfsrv_callout; extern struct nfsrvstats nfsrvstats; extern int nfsrv_ticks; extern int nfsrvw_procrastinate; extern int nfsrvw_procrastinate_v3; extern int nfsrv_numnfsd; /* Various values converted to XDR form. */ extern u_int32_t nfsrv_nfs_false, nfsrv_nfs_true, nfsrv_nfs_xdrneg1, nfsrv_nfs_prog; extern u_int32_t nfsrv_rpc_reply, nfsrv_rpc_msgdenied, nfsrv_rpc_mismatch, nfsrv_rpc_vers; extern u_int32_t nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted, nfsrv_rpc_call, nfsrv_rpc_autherr; /* Procedure table data */ extern const int nfsrvv2_procid[NFS_NPROCS]; extern const int nfsrv_nfsv3_procid[NFS_NPROCS]; extern int32_t (*nfsrv3_procs[NFS_NPROCS])(struct nfsrv_descript *nd, struct nfssvc_sock *slp, struct mbuf **mreqp); /* * A list of nfssvc_sock structures is maintained with all the sockets * that require service by the nfsd. */ #ifndef NFS_WDELAYHASHSIZ #define NFS_WDELAYHASHSIZ 16 /* and with this */ #endif #define NWDELAYHASH(sock, f) \ (&(sock)->ns_wdelayhashtbl[(*((u_int32_t *)(f))) % NFS_WDELAYHASHSIZ]) /* * This structure is used by the server for describing each request. */ struct nfsrv_descript { struct mbuf *nd_mrep; /* Request mbuf list */ struct mbuf *nd_md; /* Current dissect mbuf */ struct mbuf *nd_mreq; /* Reply mbuf list */ struct sockaddr *nd_nam; /* and socket addr */ struct sockaddr *nd_nam2; /* return socket addr */ caddr_t nd_dpos; /* Current dissect pos */ u_int32_t nd_procnum; /* RPC # */ int nd_stable; /* storage type */ int nd_flag; /* nd_flag */ int nd_repstat; /* Reply status */ fhandle_t nd_fh; /* File handle */ struct ucred *nd_cr; /* Credentials */ int nd_credflavor; /* Security flavor */ }; /* Bits for "nd_flag" */ #define ND_NFSV3 0x08 /* * Defines for WebNFS */ #define WEBNFS_ESC_CHAR '%' #define WEBNFS_SPECCHAR_START 0x80 #define WEBNFS_NATIVE_CHAR 0x80 /* * .. * Possibly more here in the future. */ /* * Macro for converting escape characters in WebNFS pathnames. * Should really be in libkern. */ #define HEXTOC(c) \ ((c) >= 'a' ? ((c) - ('a' - 10)) : \ ((c) >= 'A' ? ((c) - ('A' - 10)) : ((c) - '0'))) #define HEXSTRTOI(p) \ ((HEXTOC(p[0]) << 4) + HEXTOC(p[1])) #ifdef NFS_DEBUG extern int nfs_debug; #define NFS_DEBUG_ASYNCIO 1 /* asynchronous i/o */ #define NFS_DEBUG_WG 2 /* server write gathering */ #define NFS_DEBUG_RC 4 /* server request caching */ #define NFS_DPF(cat, args) \ do { \ if (nfs_debug & NFS_DEBUG_##cat) printf args; \ } while (0) #else #define NFS_DPF(cat, args) #endif void nfs_realign(struct mbuf **); struct mbuf *nfs_rephead(int, struct nfsrv_descript *, int, struct mbuf **, caddr_t *); void nfsm_srvfattr(struct nfsrv_descript *, struct vattr *, struct nfs_fattr *); void nfsm_srvwcc(struct nfsrv_descript *, int, struct vattr *, int, struct vattr *, struct mbuf **, char **); void nfsm_srvpostopattr(struct nfsrv_descript *, int, struct vattr *, struct mbuf **, char **); int nfs_namei(struct nameidata *, struct nfsrv_descript *, fhandle_t *, int, struct nfssvc_sock *, struct sockaddr *, struct mbuf **, caddr_t *, struct vnode **, int, struct vattr *, int *, int); void nfsm_adj(struct mbuf *, int, int); int nfsm_mbuftouio(struct mbuf **, struct uio *, int, caddr_t *); void nfsrv_init(int); int nfsrv_errmap(struct nfsrv_descript *, int); void nfsrvw_sort(gid_t *, int); int nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_fhtovp(fhandle_t *, int, struct vnode **, int *, struct nfsrv_descript *, struct nfssvc_sock *, struct sockaddr *, int *, int); int nfsrv_setpublicfs(struct mount *, struct netexport *, struct export_args *); int nfs_ispublicfh(fhandle_t *); int nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); int nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf **mrq); /* * #ifdef _SYS_SYSPROTO_H_ so that it is only defined when sysproto.h * has been included, so that "struct nfssvc_args" is defined. */ #ifdef _SYS_SYSPROTO_H_ int nfssvc_nfsserver(struct thread *, struct nfssvc_args *); #endif #endif /* _KERNEL */ #endif Index: head/sys/nfsserver/nfs_fha.c =================================================================== --- head/sys/nfsserver/nfs_fha.c (revision 201898) +++ head/sys/nfsserver/nfs_fha.c (revision 201899) @@ -1,601 +1,600 @@ /*- * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static MALLOC_DEFINE(M_NFS_FHA, "NFS FHA", "NFS FHA"); /* Sysctl defaults. */ #define DEF_BIN_SHIFT 18 /* 256k */ #define DEF_MAX_NFSDS_PER_FH 8 #define DEF_MAX_REQS_PER_NFSD 4 struct fha_ctls { u_int32_t bin_shift; u_int32_t max_nfsds_per_fh; u_int32_t max_reqs_per_nfsd; } fha_ctls; struct sysctl_ctx_list fha_clist; SYSCTL_DECL(_vfs_nfsrv); SYSCTL_DECL(_vfs_nfsrv_fha); /* Static sysctl node for the fha from the top-level vfs_nfsrv node. */ SYSCTL_NODE(_vfs_nfsrv, OID_AUTO, fha, CTLFLAG_RD, 0, "fha node"); /* This is the global structure that represents the state of the fha system. */ static struct fha_global { struct fha_hash_entry_list *hashtable; u_long hashmask; } g_fha; -/* - * These are the entries in the filehandle hash. They talk about a specific - * file, requests against which are being handled by one or more nfsds. We keep - * a chain of nfsds against the file. We only have more than one if reads are - * ongoing, and then only if the reads affect disparate regions of the file. +/* + * These are the entries in the filehandle hash. They talk about a specific + * file, requests against which are being handled by one or more nfsds. We + * keep a chain of nfsds against the file. We only have more than one if reads + * are ongoing, and then only if the reads affect disparate regions of the + * file. * - * In general, we want to assign a new request to an existing nfsd if it is - * going to contend with work happening already on that nfsd, or if the - * operation is a read and the nfsd is already handling a proximate read. We - * do this to avoid jumping around in the read stream unnecessarily, and to + * In general, we want to assign a new request to an existing nfsd if it is + * going to contend with work happening already on that nfsd, or if the + * operation is a read and the nfsd is already handling a proximate read. We + * do this to avoid jumping around in the read stream unnecessarily, and to * avoid contention between threads over single files. */ struct fha_hash_entry { LIST_ENTRY(fha_hash_entry) link; u_int64_t fh; u_int16_t num_reads; u_int16_t num_writes; u_int8_t num_threads; struct svcthread_list threads; }; LIST_HEAD(fha_hash_entry_list, fha_hash_entry); /* A structure used for passing around data internally. */ struct fha_info { u_int64_t fh; off_t offset; int locktype; }; static int fhe_stats_sysctl(SYSCTL_HANDLER_ARGS); - + static void nfs_fha_init(void *foo) { /* * A small hash table to map filehandles to fha_hash_entry * structures. */ g_fha.hashtable = hashinit(256, M_NFS_FHA, &g_fha.hashmask); /* * Initialize the sysctl context list for the fha module. */ sysctl_ctx_init(&fha_clist); fha_ctls.bin_shift = DEF_BIN_SHIFT; fha_ctls.max_nfsds_per_fh = DEF_MAX_NFSDS_PER_FH; fha_ctls.max_reqs_per_nfsd = DEF_MAX_REQS_PER_NFSD; SYSCTL_ADD_UINT(&fha_clist, SYSCTL_STATIC_CHILDREN(_vfs_nfsrv_fha), OID_AUTO, "bin_shift", CTLFLAG_RW, &fha_ctls.bin_shift, 0, "For FHA reads, no two requests will " "contend if they're 2^(bin_shift) bytes apart"); SYSCTL_ADD_UINT(&fha_clist, SYSCTL_STATIC_CHILDREN(_vfs_nfsrv_fha), OID_AUTO, "max_nfsds_per_fh", CTLFLAG_RW, &fha_ctls.max_nfsds_per_fh, 0, "Maximum nfsd threads that " "should be working on requests for the same file handle"); SYSCTL_ADD_UINT(&fha_clist, SYSCTL_STATIC_CHILDREN(_vfs_nfsrv_fha), OID_AUTO, "max_reqs_per_nfsd", CTLFLAG_RW, &fha_ctls.max_reqs_per_nfsd, 0, "Maximum requests that " "single nfsd thread should be working on at any time"); - SYSCTL_ADD_OID(&fha_clist, SYSCTL_STATIC_CHILDREN(_vfs_nfsrv_fha), + SYSCTL_ADD_OID(&fha_clist, SYSCTL_STATIC_CHILDREN(_vfs_nfsrv_fha), OID_AUTO, "fhe_stats", CTLTYPE_STRING | CTLFLAG_RD, 0, 0, fhe_stats_sysctl, "A", ""); } static void nfs_fha_uninit(void *foo) { hashdestroy(g_fha.hashtable, M_NFS_FHA, g_fha.hashmask); } SYSINIT(nfs_fha, SI_SUB_ROOT_CONF, SI_ORDER_ANY, nfs_fha_init, NULL); SYSUNINIT(nfs_fha, SI_SUB_ROOT_CONF, SI_ORDER_ANY, nfs_fha_uninit, NULL); -/* +/* * This just specifies that offsets should obey affinity when within * the same 1Mbyte (1<<20) chunk for the file (reads only for now). */ static void fha_extract_info(struct svc_req *req, struct fha_info *i) { struct mbuf *md; nfsfh_t fh; caddr_t dpos; static u_int64_t random_fh = 0; int error; int v3 = (req->rq_vers == 3); u_int32_t *tl; rpcproc_t procnum; - /* - * We start off with a random fh. If we get a reasonable - * procnum, we set the fh. If there's a concept of offset + /* + * We start off with a random fh. If we get a reasonable + * procnum, we set the fh. If there's a concept of offset * that we're interested in, we set that. */ i->fh = ++random_fh; i->offset = 0; i->locktype = LK_EXCLUSIVE; - + /* * Extract the procnum and convert to v3 form if necessary, - * taking care to deal with out-of-range procnums. Caller will + * taking care to deal with out-of-range procnums. Caller will * ensure that rq_vers is either 2 or 3. */ procnum = req->rq_proc; if (!v3) { if (procnum > NFSV2PROC_STATFS) goto out; procnum = nfsrv_nfsv3_procid[procnum]; } - /* - * We do affinity for most. However, we divide a realm of affinity - * by file offset so as to allow for concurrent random access. We - * only do this for reads today, but this may change when IFS supports + /* + * We do affinity for most. However, we divide a realm of affinity + * by file offset so as to allow for concurrent random access. We + * only do this for reads today, but this may change when IFS supports * efficient concurrent writes. */ if (procnum == NFSPROC_FSSTAT || procnum == NFSPROC_FSINFO || procnum == NFSPROC_PATHCONF || - procnum == NFSPROC_NOOP || + procnum == NFSPROC_NOOP || procnum == NFSPROC_NULL) goto out; - + nfs_realign(&req->rq_args); md = req->rq_args; dpos = mtod(md, caddr_t); /* Grab the filehandle. */ error = nfsm_srvmtofh_xx(&fh.fh_generic, v3, &md, &dpos); if (error) goto out; bcopy(fh.fh_generic.fh_fid.fid_data, &i->fh, sizeof(i->fh)); /* Content ourselves with zero offset for all but reads. */ if (procnum != NFSPROC_READ) goto out; if (v3) { tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, &md, &dpos); if (tl == NULL) goto out; i->offset = fxdr_hyper(tl); } else { tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, &md, &dpos); if (tl == NULL) goto out; i->offset = fxdr_unsigned(u_int32_t, *tl); } out: switch (procnum) { case NFSPROC_NULL: case NFSPROC_GETATTR: case NFSPROC_LOOKUP: case NFSPROC_ACCESS: case NFSPROC_READLINK: case NFSPROC_READ: case NFSPROC_READDIR: case NFSPROC_READDIRPLUS: i->locktype = LK_SHARED; break; case NFSPROC_SETATTR: case NFSPROC_WRITE: case NFSPROC_CREATE: case NFSPROC_MKDIR: case NFSPROC_SYMLINK: case NFSPROC_MKNOD: case NFSPROC_REMOVE: case NFSPROC_RMDIR: case NFSPROC_RENAME: case NFSPROC_LINK: case NFSPROC_FSSTAT: case NFSPROC_FSINFO: case NFSPROC_PATHCONF: case NFSPROC_COMMIT: case NFSPROC_NOOP: i->locktype = LK_EXCLUSIVE; break; } } static struct fha_hash_entry * fha_hash_entry_new(u_int64_t fh) { struct fha_hash_entry *e; e = malloc(sizeof(*e), M_NFS_FHA, M_WAITOK); e->fh = fh; e->num_reads = 0; e->num_writes = 0; e->num_threads = 0; LIST_INIT(&e->threads); - - return e; + + return (e); } static void fha_hash_entry_destroy(struct fha_hash_entry *e) { if (e->num_reads + e->num_writes) panic("nonempty fhe"); free(e, M_NFS_FHA); } static void fha_hash_entry_remove(struct fha_hash_entry *e) { LIST_REMOVE(e, link); fha_hash_entry_destroy(e); } static struct fha_hash_entry * fha_hash_entry_lookup(SVCPOOL *pool, u_int64_t fh) { struct fha_hash_entry *fhe, *new_fhe; - LIST_FOREACH(fhe, &g_fha.hashtable[fh % g_fha.hashmask], link) { + LIST_FOREACH(fhe, &g_fha.hashtable[fh % g_fha.hashmask], link) if (fhe->fh == fh) break; - } if (!fhe) { /* Allocate a new entry. */ mtx_unlock(&pool->sp_lock); new_fhe = fha_hash_entry_new(fh); mtx_lock(&pool->sp_lock); /* Double-check to make sure we still need the new entry. */ - LIST_FOREACH(fhe, &g_fha.hashtable[fh % g_fha.hashmask], link) { + LIST_FOREACH(fhe, &g_fha.hashtable[fh % g_fha.hashmask], link) if (fhe->fh == fh) break; - } if (!fhe) { fhe = new_fhe; LIST_INSERT_HEAD(&g_fha.hashtable[fh % g_fha.hashmask], fhe, link); - } else { + } else fha_hash_entry_destroy(new_fhe); - } } - return fhe; + return (fhe); } static void fha_hash_entry_add_thread(struct fha_hash_entry *fhe, SVCTHREAD *thread) { + LIST_INSERT_HEAD(&fhe->threads, thread, st_alink); fhe->num_threads++; } static void fha_hash_entry_remove_thread(struct fha_hash_entry *fhe, SVCTHREAD *thread) { LIST_REMOVE(thread, st_alink); fhe->num_threads--; } -/* +/* * Account for an ongoing operation associated with this file. */ static void fha_hash_entry_add_op(struct fha_hash_entry *fhe, int locktype, int count) { if (LK_EXCLUSIVE == locktype) fhe->num_writes += count; else fhe->num_reads += count; } static SVCTHREAD * get_idle_thread(SVCPOOL *pool) { SVCTHREAD *st; LIST_FOREACH(st, &pool->sp_idlethreads, st_ilink) { if (st->st_xprt == NULL && STAILQ_EMPTY(&st->st_reqs)) return (st); } return (NULL); } -/* +/* * Get the service thread currently associated with the fhe that is * appropriate to handle this operation. */ SVCTHREAD * fha_hash_entry_choose_thread(SVCPOOL *pool, struct fha_hash_entry *fhe, struct fha_info *i, SVCTHREAD *this_thread); SVCTHREAD * fha_hash_entry_choose_thread(SVCPOOL *pool, struct fha_hash_entry *fhe, struct fha_info *i, SVCTHREAD *this_thread) { SVCTHREAD *thread, *min_thread = NULL; int req_count, min_count = 0; off_t offset1, offset2; LIST_FOREACH(thread, &fhe->threads, st_alink) { req_count = thread->st_reqcount; /* If there are any writes in progress, use the first thread. */ if (fhe->num_writes) { #if 0 - ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO, + ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO, "fha: %p(%d)w", thread, req_count); #endif return (thread); } - /* - * Check for read locality, making sure that we won't - * exceed our per-thread load limit in the process. + /* + * Check for read locality, making sure that we won't + * exceed our per-thread load limit in the process. */ offset1 = i->offset >> fha_ctls.bin_shift; offset2 = STAILQ_FIRST(&thread->st_reqs)->rq_p3 >> fha_ctls.bin_shift; if (offset1 == offset2) { if ((fha_ctls.max_reqs_per_nfsd == 0) || (req_count < fha_ctls.max_reqs_per_nfsd)) { #if 0 - ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO, + ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO, "fha: %p(%d)r", thread, req_count); #endif return (thread); } } - /* + /* * We don't have a locality match, so skip this thread, - * but keep track of the most attractive thread in case + * but keep track of the most attractive thread in case * we need to come back to it later. */ #if 0 - ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO, - "fha: %p(%d)s off1 %llu off2 %llu", thread, + ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO, + "fha: %p(%d)s off1 %llu off2 %llu", thread, req_count, offset1, offset2); #endif if ((min_thread == NULL) || (req_count < min_count)) { min_count = req_count; min_thread = thread; } } - /* - * We didn't find a good match yet. See if we can add + /* + * We didn't find a good match yet. See if we can add * a new thread to this file handle entry's thread list. */ - if ((fha_ctls.max_nfsds_per_fh == 0) || + if ((fha_ctls.max_nfsds_per_fh == 0) || (fhe->num_threads < fha_ctls.max_nfsds_per_fh)) { - /* - * We can add a new thread, so try for an idle thread - * first, and fall back to this_thread if none are idle. + /* + * We can add a new thread, so try for an idle thread + * first, and fall back to this_thread if none are idle. */ if (STAILQ_EMPTY(&this_thread->st_reqs)) { thread = this_thread; #if 0 - ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO, + ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO, "fha: %p(%d)t", thread, thread->st_reqcount); #endif } else if ((thread = get_idle_thread(pool))) { #if 0 - ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO, + ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO, "fha: %p(%d)i", thread, thread->st_reqcount); #endif - } else { + } else { thread = this_thread; #if 0 - ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO, + ITRACE_CURPROC(ITRACE_NFS, ITRACE_INFO, "fha: %p(%d)b", thread, thread->st_reqcount); #endif } fha_hash_entry_add_thread(fhe, thread); } else { - /* - * We don't want to use any more threads for this file, so + /* + * We don't want to use any more threads for this file, so * go back to the most attractive nfsd we're already using. */ thread = min_thread; } return (thread); } -/* - * After getting a request, try to assign it to some thread. Usually we +/* + * After getting a request, try to assign it to some thread. Usually we * handle it ourselves. */ SVCTHREAD * fha_assign(SVCTHREAD *this_thread, struct svc_req *req) { SVCPOOL *pool; SVCTHREAD *thread; struct fha_info i; struct fha_hash_entry *fhe; /* * Only do placement if this is an NFS request. */ if (req->rq_prog != NFS_PROG) return (this_thread); if (req->rq_vers != 2 && req->rq_vers != 3) return (this_thread); pool = req->rq_xprt->xp_pool; fha_extract_info(req, &i); - /* - * We save the offset associated with this request for later + /* + * We save the offset associated with this request for later * nfsd matching. */ fhe = fha_hash_entry_lookup(pool, i.fh); req->rq_p1 = fhe; req->rq_p2 = i.locktype; req->rq_p3 = i.offset; - - /* + + /* * Choose a thread, taking into consideration locality, thread load, * and the number of threads already working on this file. */ thread = fha_hash_entry_choose_thread(pool, fhe, &i, this_thread); KASSERT(thread, ("fha_assign: NULL thread!")); fha_hash_entry_add_op(fhe, i.locktype, 1); return (thread); } -/* - * Called when we're done with an operation. The request has already +/* + * Called when we're done with an operation. The request has already * been de-queued. */ void fha_nd_complete(SVCTHREAD *thread, struct svc_req *req) { struct fha_hash_entry *fhe = req->rq_p1; /* * This may be called for reqs that didn't go through * fha_assign (e.g. extra NULL ops used for RPCSEC_GSS. */ if (!fhe) return; fha_hash_entry_add_op(fhe, req->rq_p2, -1); if (thread->st_reqcount == 0) { fha_hash_entry_remove_thread(fhe, thread); if (0 == fhe->num_reads + fhe->num_writes) fha_hash_entry_remove(fhe); } } extern SVCPOOL *nfsrv_pool; static int fhe_stats_sysctl(SYSCTL_HANDLER_ARGS) { int error, count, i; struct sbuf sb; struct fha_hash_entry *fhe; bool_t first = TRUE; SVCTHREAD *thread; sbuf_new(&sb, NULL, 4096, SBUF_FIXEDLEN); if (!nfsrv_pool) { sbuf_printf(&sb, "NFSD not running\n"); goto out; } mtx_lock(&nfsrv_pool->sp_lock); count = 0; for (i = 0; i <= g_fha.hashmask; i++) if (!LIST_EMPTY(&g_fha.hashtable[i])) count++; if (count == 0) { sbuf_printf(&sb, "No file handle entries.\n"); goto out; } for (i = 0; i <= g_fha.hashmask; i++) { LIST_FOREACH(fhe, &g_fha.hashtable[i], link) { sbuf_printf(&sb, "%sfhe %p: {\n", first ? "" : ", ", fhe); sbuf_printf(&sb, " fh: %ju\n", (uintmax_t) fhe->fh); sbuf_printf(&sb, " num_reads: %d\n", fhe->num_reads); sbuf_printf(&sb, " num_writes: %d\n", fhe->num_writes); sbuf_printf(&sb, " num_threads: %d\n", fhe->num_threads); LIST_FOREACH(thread, &fhe->threads, st_alink) { sbuf_printf(&sb, " thread %p (count %d)\n", thread, thread->st_reqcount); } sbuf_printf(&sb, "}"); first = FALSE; /* Limit the output. */ if (++count > 128) { sbuf_printf(&sb, "..."); break; } } } out: if (nfsrv_pool) mtx_unlock(&nfsrv_pool->sp_lock); sbuf_trim(&sb); sbuf_finish(&sb); error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); sbuf_delete(&sb); return (error); } Index: head/sys/nfsserver/nfs_srvkrpc.c =================================================================== --- head/sys/nfsserver/nfs_srvkrpc.c (revision 201898) +++ head/sys/nfsserver/nfs_srvkrpc.c (revision 201899) @@ -1,606 +1,604 @@ /*- * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Rick Macklem at The University of Guelph. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 */ #include __FBSDID("$FreeBSD$"); #include "opt_inet6.h" #include "opt_kgssapi.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET6 #include #include #endif #include #include #include #include #include #include #include #include #include #include static MALLOC_DEFINE(M_NFSSVC, "nfss_srvsock", "Nfs server structure"); MALLOC_DEFINE(M_NFSRVDESC, "nfss_srvdesc", "NFS server socket descriptor"); MALLOC_DEFINE(M_NFSD, "nfss_daemon", "Nfs server daemon structure"); #define TRUE 1 #define FALSE 0 SYSCTL_DECL(_vfs_nfsrv); SVCPOOL *nfsrv_pool; int nfsd_waiting = 0; int nfsrv_numnfsd = 0; static int nfs_realign_test; static int nfs_realign_count; struct callout nfsrv_callout; static eventhandler_tag nfsrv_nmbclusters_tag; static int nfs_privport = 0; SYSCTL_INT(_vfs_nfsrv, NFS_NFSPRIVPORT, nfs_privport, CTLFLAG_RW, &nfs_privport, 0, "Only allow clients using a privileged port"); SYSCTL_INT(_vfs_nfsrv, OID_AUTO, gatherdelay, CTLFLAG_RW, &nfsrvw_procrastinate, 0, "Delay value for write gathering"); SYSCTL_INT(_vfs_nfsrv, OID_AUTO, gatherdelay_v3, CTLFLAG_RW, &nfsrvw_procrastinate_v3, 0, "Delay in seconds for NFSv3 write gathering"); SYSCTL_INT(_vfs_nfsrv, OID_AUTO, realign_test, CTLFLAG_RW, &nfs_realign_test, 0, ""); SYSCTL_INT(_vfs_nfsrv, OID_AUTO, realign_count, CTLFLAG_RW, &nfs_realign_count, 0, ""); static int nfssvc_addsock(struct file *, struct thread *); static int nfssvc_nfsd(struct thread *, struct nfsd_nfsd_args *); extern u_long sb_max_adj; int32_t (*nfsrv3_procs[NFS_NPROCS])(struct nfsrv_descript *nd, struct nfssvc_sock *slp, struct mbuf **mreqp) = { nfsrv_null, nfsrv_getattr, nfsrv_setattr, nfsrv_lookup, nfsrv3_access, nfsrv_readlink, nfsrv_read, nfsrv_write, nfsrv_create, nfsrv_mkdir, nfsrv_symlink, nfsrv_mknod, nfsrv_remove, nfsrv_rmdir, nfsrv_rename, nfsrv_link, nfsrv_readdir, nfsrv_readdirplus, nfsrv_statfs, nfsrv_fsinfo, nfsrv_pathconf, nfsrv_commit, nfsrv_noop }; /* * NFS server system calls */ /* * This is now called from nfssvc() in nfs/nfs_nfssvc.c. */ /* * Nfs server psuedo system call for the nfsd's * Based on the flag value it either: * - adds a socket to the selection list * - remains in the kernel as an nfsd * - remains in the kernel as an nfsiod * For INET6 we suppose that nfsd provides only IN6P_IPV6_V6ONLY sockets * and that mountd provides * - sockaddr with no IPv4-mapped addresses * - mask for both INET and INET6 families if there is IPv4-mapped overlap */ int nfssvc_nfsserver(struct thread *td, struct nfssvc_args *uap) { struct file *fp; struct nfsd_addsock_args addsockarg; struct nfsd_nfsd_args nfsdarg; int error; if (uap->flag & NFSSVC_ADDSOCK) { error = copyin(uap->argp, (caddr_t)&addsockarg, sizeof(addsockarg)); if (error) return (error); if ((error = fget(td, addsockarg.sock, &fp)) != 0) return (error); if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, td); return (error); /* XXXRW: Should be EINVAL? */ } error = nfssvc_addsock(fp, td); fdrop(fp, td); - } else if (uap->flag & NFSSVC_OLDNFSD) { + } else if (uap->flag & NFSSVC_OLDNFSD) error = nfssvc_nfsd(td, NULL); - } else if (uap->flag & NFSSVC_NFSD) { - if (!uap->argp) + else if (uap->flag & NFSSVC_NFSD) { + if (!uap->argp) return (EINVAL); error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg)); if (error) return (error); error = nfssvc_nfsd(td, &nfsdarg); - } else { + } else error = ENXIO; - } return (error); } /* * Generate the rpc reply header * siz arg. is used to decide if adding a cluster is worthwhile */ struct mbuf * nfs_rephead(int siz, struct nfsrv_descript *nd, int err, struct mbuf **mbp, caddr_t *bposp) { u_int32_t *tl; struct mbuf *mreq; caddr_t bpos; struct mbuf *mb; if (err == EBADRPC) return (NULL); nd->nd_repstat = err; if (err && (nd->nd_flag & ND_NFSV3) == 0) /* XXX recheck */ siz = 0; MGET(mreq, M_WAIT, MT_DATA); /* * If this is a big reply, use a cluster */ mreq->m_len = 0; if (siz >= MINCLSIZE) { MCLGET(mreq, M_WAIT); } mb = mreq; bpos = mtod(mb, caddr_t); if (err != NFSERR_RETVOID) { tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); if (err) *tl = txdr_unsigned(nfsrv_errmap(nd, err)); else *tl = 0; } *mbp = mb; *bposp = bpos; if (err != 0 && err != NFSERR_RETVOID) nfsrvstats.srvrpc_errs++; return (mreq); } /* * nfs_realign: * * Check for badly aligned mbuf data and realign by copying the unaligned * portion of the data into a new mbuf chain and freeing the portions * of the old chain that were replaced. * * We cannot simply realign the data within the existing mbuf chain * because the underlying buffers may contain other rpc commands and * we cannot afford to overwrite them. * * We would prefer to avoid this situation entirely. The situation does * not occur with NFS/UDP and is supposed to only occassionally occur * with TCP. Use vfs.nfs.realign_count and realign_test to check this. */ void nfs_realign(struct mbuf **pm) /* XXX COMMON */ { struct mbuf *m; struct mbuf *n = NULL; int off = 0; ++nfs_realign_test; while ((m = *pm) != NULL) { if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) { MGET(n, M_WAIT, MT_DATA); if (m->m_len >= MINCLSIZE) { MCLGET(n, M_WAIT); } n->m_len = 0; break; } pm = &m->m_next; } /* * If n is non-NULL, loop on m copying data, then replace the * portion of the chain that had to be realigned. */ if (n != NULL) { ++nfs_realign_count; while (m) { m_copyback(n, off, m->m_len, mtod(m, caddr_t)); off += m->m_len; m = m->m_next; } m_freem(*pm); *pm = n; } } static void nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt) { rpcproc_t procnum; int32_t (*proc)(struct nfsrv_descript *nd, struct nfssvc_sock *slp, struct mbuf **mreqp); int flag; struct nfsrv_descript nd; struct mbuf *mreq, *mrep; int error; if (rqst->rq_vers == NFS_VER2) { if (rqst->rq_proc > NFSV2PROC_STATFS) { svcerr_noproc(rqst); svc_freereq(rqst); return; } procnum = nfsrv_nfsv3_procid[rqst->rq_proc]; flag = 0; } else { if (rqst->rq_proc >= NFS_NPROCS) { svcerr_noproc(rqst); svc_freereq(rqst); return; } procnum = rqst->rq_proc; flag = ND_NFSV3; } proc = nfsrv3_procs[procnum]; mreq = mrep = NULL; mreq = rqst->rq_args; rqst->rq_args = NULL; nfs_realign(&mreq); /* * Note: we want rq_addr, not svc_getrpccaller for nd_nam2 - * NFS_SRVMAXDATA uses a NULL value for nd_nam2 to detect TCP * mounts. */ memset(&nd, 0, sizeof(nd)); nd.nd_md = nd.nd_mrep = mreq; nd.nd_dpos = mtod(mreq, caddr_t); nd.nd_nam = svc_getrpccaller(rqst); nd.nd_nam2 = rqst->rq_addr; nd.nd_procnum = procnum; nd.nd_cr = NULL; nd.nd_flag = flag; if (nfs_privport) { /* Check if source port is privileged */ u_short port; struct sockaddr *nam = nd.nd_nam; struct sockaddr_in *sin; sin = (struct sockaddr_in *)nam; /* * INET/INET6 - same code: * sin_port and sin6_port are at same offset */ port = ntohs(sin->sin_port); if (port >= IPPORT_RESERVED && nd.nd_procnum != NFSPROC_NULL) { #ifdef INET6 char b6[INET6_ADDRSTRLEN]; #if defined(KLD_MODULE) /* Do not use ip6_sprintf: the nfs module should work without INET6. */ #define ip6_sprintf(buf, a) \ (sprintf((buf), "%x:%x:%x:%x:%x:%x:%x:%x", \ (a)->s6_addr16[0], (a)->s6_addr16[1], \ (a)->s6_addr16[2], (a)->s6_addr16[3], \ (a)->s6_addr16[4], (a)->s6_addr16[5], \ (a)->s6_addr16[6], (a)->s6_addr16[7]), \ (buf)) #endif #endif printf("NFS request from unprivileged port (%s:%d)\n", #ifdef INET6 sin->sin_family == AF_INET6 ? ip6_sprintf(b6, &satosin6(sin)->sin6_addr) : #if defined(KLD_MODULE) #undef ip6_sprintf #endif #endif inet_ntoa(sin->sin_addr), port); m_freem(mreq); svcerr_weakauth(rqst); svc_freereq(rqst); return; } } if (proc != nfsrv_null) { if (!svc_getcred(rqst, &nd.nd_cr, &nd.nd_credflavor)) { m_freem(mreq); svcerr_weakauth(rqst); svc_freereq(rqst); return; } #ifdef MAC mac_cred_associate_nfsd(nd.nd_cr); #endif } nfsrvstats.srvrpccnt[nd.nd_procnum]++; error = proc(&nd, NULL, &mrep); if (nd.nd_cr) crfree(nd.nd_cr); if (mrep == NULL) { svcerr_decode(rqst); svc_freereq(rqst); return; } if (error && error != NFSERR_RETVOID) { svcerr_systemerr(rqst); svc_freereq(rqst); return; } if (nd.nd_repstat & NFSERR_AUTHERR) { svcerr_auth(rqst, nd.nd_repstat & ~NFSERR_AUTHERR); m_freem(mrep); } else { if (!svc_sendreply_mbuf(rqst, mrep)) svcerr_systemerr(rqst); } svc_freereq(rqst); } /* * Adds a socket to the list for servicing by nfsds. */ static int nfssvc_addsock(struct file *fp, struct thread *td) { int siz; struct socket *so; int error; SVCXPRT *xprt; so = fp->f_data; siz = sb_max_adj; error = soreserve(so, siz, siz); - if (error) { + if (error) return (error); - } /* * Steal the socket from userland so that it doesn't close * unexpectedly. */ if (so->so_type == SOCK_DGRAM) xprt = svc_dg_create(nfsrv_pool, so, 0, 0); else xprt = svc_vc_create(nfsrv_pool, so, 0, 0); if (xprt) { fp->f_ops = &badfileops; fp->f_data = NULL; svc_reg(xprt, NFS_PROG, NFS_VER2, nfssvc_program, NULL); svc_reg(xprt, NFS_PROG, NFS_VER3, nfssvc_program, NULL); SVC_RELEASE(xprt); } return (0); } /* - * Called by nfssvc() for nfsds. Just loops around servicing rpc requests + * Called by nfssvc() for nfsds. Just loops around servicing rpc requests * until it is killed by a signal. */ static int nfssvc_nfsd(struct thread *td, struct nfsd_nfsd_args *args) { #ifdef KGSSAPI char principal[128]; int error; #endif #ifdef KGSSAPI if (args) { error = copyinstr(args->principal, principal, sizeof(principal), NULL); if (error) return (error); } else { memcpy(principal, "nfs@", 4); getcredhostname(td->td_ucred, principal + 4, sizeof(principal) - 4); } #endif /* - * Only the first nfsd actually does any work. The RPC code - * adds threads to it as needed. Any extra processes offered - * by nfsd just exit. If nfsd is new enough, it will call us + * Only the first nfsd actually does any work. The RPC code + * adds threads to it as needed. Any extra processes offered + * by nfsd just exit. If nfsd is new enough, it will call us * once with a structure that specifies how many threads to * use. */ NFSD_LOCK(); if (nfsrv_numnfsd == 0) { nfsrv_numnfsd++; NFSD_UNLOCK(); #ifdef KGSSAPI rpc_gss_set_svc_name(principal, "kerberosv5", GSS_C_INDEFINITE, NFS_PROG, NFS_VER2); rpc_gss_set_svc_name(principal, "kerberosv5", GSS_C_INDEFINITE, NFS_PROG, NFS_VER3); #endif if (args) { nfsrv_pool->sp_minthreads = args->minthreads; nfsrv_pool->sp_maxthreads = args->maxthreads; } else { nfsrv_pool->sp_minthreads = 4; nfsrv_pool->sp_maxthreads = 4; } - + svc_run(nfsrv_pool); #ifdef KGSSAPI rpc_gss_clear_svc_name(NFS_PROG, NFS_VER2); rpc_gss_clear_svc_name(NFS_PROG, NFS_VER3); #endif NFSD_LOCK(); nfsrv_numnfsd--; nfsrv_init(TRUE); } NFSD_UNLOCK(); return (0); } /* * Size the NFS server's duplicate request cache at 1/2 the - * nmbclusters, floating within a (64, 2048) range. This is to + * nmbclusters, floating within a (64, 2048) range. This is to * prevent all mbuf clusters being tied up in the NFS dupreq * cache for small values of nmbclusters. */ static size_t nfsrv_replay_size(void) { size_t replaysiz; replaysiz = nmbclusters / 2; if (replaysiz > NFSRVCACHE_MAX_SIZE) replaysiz = NFSRVCACHE_MAX_SIZE; if (replaysiz < NFSRVCACHE_MIN_SIZE) replaysiz = NFSRVCACHE_MIN_SIZE; replaysiz *= MCLBYTES; return (replaysiz); } /* * Called when nmbclusters changes - we resize the replay cache * accordingly. */ static void nfsrv_nmbclusters_change(void *tag) { if (nfsrv_pool) replay_setsize(nfsrv_pool->sp_rcache, nfsrv_replay_size()); } /* * Initialize the data structures for the server. * Handshake with any new nfsds starting up to avoid any chance of * corruption. */ void nfsrv_init(int terminating) { NFSD_LOCK_ASSERT(); if (terminating) { NFSD_UNLOCK(); EVENTHANDLER_DEREGISTER(nmbclusters_change, nfsrv_nmbclusters_tag); svcpool_destroy(nfsrv_pool); nfsrv_pool = NULL; NFSD_LOCK(); } else nfs_pub.np_valid = 0; NFSD_UNLOCK(); nfsrv_pool = svcpool_create("nfsd", SYSCTL_STATIC_CHILDREN(_vfs_nfsrv)); nfsrv_pool->sp_rcache = replay_newcache(nfsrv_replay_size()); nfsrv_pool->sp_assign = fha_assign; nfsrv_pool->sp_done = fha_nd_complete; nfsrv_nmbclusters_tag = EVENTHANDLER_REGISTER(nmbclusters_change, nfsrv_nmbclusters_change, NULL, EVENTHANDLER_PRI_FIRST); NFSD_LOCK(); }