nfs_commonport.c revision 268115
160484Sobrien/*- 2218822Sdim * Copyright (c) 1989, 1993 3218822Sdim * The Regents of the University of California. All rights reserved. 460484Sobrien * 560484Sobrien * This code is derived from software contributed to Berkeley by 660484Sobrien * Rick Macklem at The University of Guelph. 760484Sobrien * 860484Sobrien * Redistribution and use in source and binary forms, with or without 960484Sobrien * modification, are permitted provided that the following conditions 1060484Sobrien * are met: 1160484Sobrien * 1. Redistributions of source code must retain the above copyright 1260484Sobrien * notice, this list of conditions and the following disclaimer. 1360484Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1460484Sobrien * notice, this list of conditions and the following disclaimer in the 1560484Sobrien * documentation and/or other materials provided with the distribution. 1660484Sobrien * 4. Neither the name of the University nor the names of its contributors 1760484Sobrien * may be used to endorse or promote products derived from this software 1860484Sobrien * without specific prior written permission. 1960484Sobrien * 20218822Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2160484Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2260484Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2360484Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2460484Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2560484Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2660484Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2760484Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2860484Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2960484Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3060484Sobrien * SUCH DAMAGE. 3160484Sobrien * 3260484Sobrien */ 3360484Sobrien 3460484Sobrien#include <sys/cdefs.h> 35218822Sdim__FBSDID("$FreeBSD: head/sys/fs/nfs/nfs_commonport.c 268115 2014-07-01 20:47:16Z rmacklem $"); 3689857Sobrien 3760484Sobrien/* 3860484Sobrien * Functions that need to be different for different versions of BSD 3960484Sobrien * kernel should be kept here, along with any global storage specific 4060484Sobrien * to this BSD variant. 4160484Sobrien */ 4260484Sobrien#include <fs/nfs/nfsport.h> 4360484Sobrien#include <sys/sysctl.h> 4460484Sobrien#include <vm/vm.h> 4560484Sobrien#include <vm/vm_object.h> 4660484Sobrien#include <vm/vm_page.h> 4760484Sobrien#include <vm/vm_param.h> 4860484Sobrien#include <vm/vm_map.h> 4960484Sobrien#include <vm/vm_kern.h> 5060484Sobrien#include <vm/vm_extern.h> 5160484Sobrien#include <vm/uma.h> 5260484Sobrien 5360484Sobrienextern int nfscl_ticks; 5460484Sobrienextern int nfsrv_nfsuserd; 5560484Sobrienextern struct nfssockreq nfsrv_nfsuserdsock; 5660484Sobrienextern void (*nfsd_call_recall)(struct vnode *, int, struct ucred *, 5760484Sobrien struct thread *); 5860484Sobrienextern int nfsrv_useacl; 5960484Sobrienstruct mount nfsv4root_mnt; 6060484Sobrienint newnfs_numnfsd = 0; 6160484Sobrienstruct nfsstats newnfsstats; 6260484Sobrienint nfs_numnfscbd = 0; 6360484Sobrienint nfscl_debuglevel = 0; 6460484Sobrienchar nfsv4_callbackaddr[INET6_ADDRSTRLEN]; 6560484Sobrienstruct callout newnfsd_callout; 6660484Sobrienvoid (*nfsd_call_servertimer)(void) = NULL; 6761843Sobrienvoid (*ncl_call_invalcaches)(struct vnode *) = NULL; 6861843Sobrien 6961843Sobrienstatic int nfs_realign_test; 7061843Sobrienstatic int nfs_realign_count; 7161843Sobrien 7260484SobrienSYSCTL_NODE(_vfs, OID_AUTO, nfs, CTLFLAG_RW, 0, "New NFS filesystem"); 7360484SobrienSYSCTL_INT(_vfs_nfs, OID_AUTO, realign_test, CTLFLAG_RW, &nfs_realign_test, 7460484Sobrien 0, "Number of realign tests done"); 7560484SobrienSYSCTL_INT(_vfs_nfs, OID_AUTO, realign_count, CTLFLAG_RW, &nfs_realign_count, 7660484Sobrien 0, "Number of mbuf realignments done"); 7760484SobrienSYSCTL_STRING(_vfs_nfs, OID_AUTO, callback_addr, CTLFLAG_RW, 7860484Sobrien nfsv4_callbackaddr, sizeof(nfsv4_callbackaddr), 7960484Sobrien "NFSv4 callback addr for server to use"); 8060484SobrienSYSCTL_INT(_vfs_nfs, OID_AUTO, debuglevel, CTLFLAG_RW, &nfscl_debuglevel, 8160484Sobrien 0, "Debug level for new nfs client"); 8260484Sobrien 8360484Sobrien/* 8460484Sobrien * Defines for malloc 8560484Sobrien * (Here for FreeBSD, since they allocate storage.) 8660484Sobrien */ 8760484SobrienMALLOC_DEFINE(M_NEWNFSRVCACHE, "NFSD srvcache", "NFSD Server Request Cache"); 8860484SobrienMALLOC_DEFINE(M_NEWNFSDCLIENT, "NFSD V4client", "NFSD V4 Client Id"); 8960484SobrienMALLOC_DEFINE(M_NEWNFSDSTATE, "NFSD V4state", 90130561Sobrien "NFSD V4 State (Openowner, Open, Lockowner, Delegation"); 9160484SobrienMALLOC_DEFINE(M_NEWNFSDLOCK, "NFSD V4lock", "NFSD V4 byte range lock"); 92130561SobrienMALLOC_DEFINE(M_NEWNFSDLOCKFILE, "NFSD lckfile", "NFSD Open/Lock file"); 9360484SobrienMALLOC_DEFINE(M_NEWNFSSTRING, "NFSD string", "NFSD V4 long string"); 94130561SobrienMALLOC_DEFINE(M_NEWNFSUSERGROUP, "NFSD usrgroup", "NFSD V4 User/group map"); 9560484SobrienMALLOC_DEFINE(M_NEWNFSDREQ, "NFS req", "NFS request header"); 9660484SobrienMALLOC_DEFINE(M_NEWNFSFH, "NFS fh", "NFS file handle"); 9760484SobrienMALLOC_DEFINE(M_NEWNFSCLOWNER, "NFSCL owner", "NFSCL Open Owner"); 98130561SobrienMALLOC_DEFINE(M_NEWNFSCLOPEN, "NFSCL open", "NFSCL Open"); 9960484SobrienMALLOC_DEFINE(M_NEWNFSCLDELEG, "NFSCL deleg", "NFSCL Delegation"); 100130561SobrienMALLOC_DEFINE(M_NEWNFSCLCLIENT, "NFSCL client", "NFSCL Client"); 101130561SobrienMALLOC_DEFINE(M_NEWNFSCLLOCKOWNER, "NFSCL lckown", "NFSCL Lock Owner"); 102130561SobrienMALLOC_DEFINE(M_NEWNFSCLLOCK, "NFSCL lck", "NFSCL Lock"); 10360484SobrienMALLOC_DEFINE(M_NEWNFSV4NODE, "NEWNFSnode", "New nfs vnode"); 10460484SobrienMALLOC_DEFINE(M_NEWNFSDIRECTIO, "NEWdirectio", "New nfs Direct IO buffer"); 10560484SobrienMALLOC_DEFINE(M_NEWNFSDIROFF, "NFSCL diroffdiroff", 10660484Sobrien "New NFS directory offset data"); 10760484SobrienMALLOC_DEFINE(M_NEWNFSDROLLBACK, "NFSD rollback", 10860484Sobrien "New NFS local lock rollback"); 109130561SobrienMALLOC_DEFINE(M_NEWNFSLAYOUT, "NFSCL layout", "NFSv4.1 Layout"); 11060484SobrienMALLOC_DEFINE(M_NEWNFSFLAYOUT, "NFSCL flayout", "NFSv4.1 File Layout"); 11160484SobrienMALLOC_DEFINE(M_NEWNFSDEVINFO, "NFSCL devinfo", "NFSv4.1 Device Info"); 11260484SobrienMALLOC_DEFINE(M_NEWNFSSOCKREQ, "NFSCL sockreq", "NFS Sock Req"); 11360484SobrienMALLOC_DEFINE(M_NEWNFSCLDS, "NFSCL session", "NFSv4.1 Session"); 11489857SobrienMALLOC_DEFINE(M_NEWNFSLAYRECALL, "NFSCL layrecall", "NFSv4.1 Layout Recall"); 11589857SobrienMALLOC_DEFINE(M_NEWNFSDSESSION, "NFSD session", "NFSD Session for a client"); 11689857Sobrien 11789857Sobrien/* 11860484Sobrien * Definition of mutex locks. 119130561Sobrien * newnfsd_mtx is used in nfsrvd_nfsd() to protect the nfs socket list 12060484Sobrien * and assorted other nfsd structures. 12160484Sobrien */ 12260484Sobrienstruct mtx newnfsd_mtx; 12360484Sobrienstruct mtx nfs_sockl_mutex; 124130561Sobrienstruct mtx nfs_state_mutex; 12560484Sobrienstruct mtx nfs_nameid_mutex; 12660484Sobrienstruct mtx nfs_req_mutex; 12760484Sobrienstruct mtx nfs_slock_mutex; 12860484Sobrien 12960484Sobrien/* local functions */ 13060484Sobrienstatic int nfssvc_call(struct thread *, struct nfssvc_args *, struct ucred *); 13160484Sobrien 13260484Sobrien#ifdef __NO_STRICT_ALIGNMENT 13360484Sobrien/* 134130561Sobrien * These architectures don't need re-alignment, so just return. 13560484Sobrien */ 13660484Sobrienint 13760484Sobriennewnfs_realign(struct mbuf **pm, int how) 13860484Sobrien{ 13960484Sobrien 14060484Sobrien return (0); 14160484Sobrien} 14260484Sobrien#else /* !__NO_STRICT_ALIGNMENT */ 14360484Sobrien/* 14460484Sobrien * newnfs_realign: 14560484Sobrien * 14660484Sobrien * Check for badly aligned mbuf data and realign by copying the unaligned 14760484Sobrien * portion of the data into a new mbuf chain and freeing the portions 14860484Sobrien * of the old chain that were replaced. 14960484Sobrien * 15060484Sobrien * We cannot simply realign the data within the existing mbuf chain 15160484Sobrien * because the underlying buffers may contain other rpc commands and 15260484Sobrien * we cannot afford to overwrite them. 153218822Sdim * 15460484Sobrien * We would prefer to avoid this situation entirely. The situation does 15560484Sobrien * not occur with NFS/UDP and is supposed to only occassionally occur 15660484Sobrien * with TCP. Use vfs.nfs.realign_count and realign_test to check this. 15760484Sobrien * 15860484Sobrien */ 15960484Sobrienint 16060484Sobriennewnfs_realign(struct mbuf **pm, int how) 16160484Sobrien{ 16260484Sobrien struct mbuf *m, *n; 16360484Sobrien int off, space; 16460484Sobrien 16560484Sobrien ++nfs_realign_test; 16660484Sobrien while ((m = *pm) != NULL) { 16760484Sobrien if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) { 16860484Sobrien /* 16960484Sobrien * NB: we can't depend on m_pkthdr.len to help us 17060484Sobrien * decide what to do here. May not be worth doing 17160484Sobrien * the m_length calculation as m_copyback will 17260484Sobrien * expand the mbuf chain below as needed. 17360484Sobrien */ 17460484Sobrien space = m_length(m, NULL); 17560484Sobrien if (space >= MINCLSIZE) { 17689857Sobrien /* NB: m_copyback handles space > MCLBYTES */ 17789857Sobrien n = m_getcl(how, MT_DATA, 0); 17860484Sobrien } else 17960484Sobrien n = m_get(how, MT_DATA); 18060484Sobrien if (n == NULL) 18160484Sobrien return (ENOMEM); 18260484Sobrien /* 18360484Sobrien * Align the remainder of the mbuf chain. 18460484Sobrien */ 18560484Sobrien n->m_len = 0; 18660484Sobrien off = 0; 18760484Sobrien while (m != NULL) { 18860484Sobrien m_copyback(n, off, m->m_len, mtod(m, caddr_t)); 18960484Sobrien off += m->m_len; 19060484Sobrien m = m->m_next; 19160484Sobrien } 19260484Sobrien m_freem(*pm); 19360484Sobrien *pm = n; 19460484Sobrien ++nfs_realign_count; 19560484Sobrien break; 19660484Sobrien } 19760484Sobrien pm = &m->m_next; 19860484Sobrien } 19960484Sobrien 20060484Sobrien return (0); 20160484Sobrien} 20260484Sobrien#endif /* __NO_STRICT_ALIGNMENT */ 20360484Sobrien 20460484Sobrien#ifdef notdef 20560484Sobrienstatic void 20660484Sobriennfsrv_object_create(struct vnode *vp, struct thread *td) 20760484Sobrien{ 208218822Sdim 209218822Sdim if (vp == NULL || vp->v_type != VREG) 21060484Sobrien return; 21160484Sobrien (void) vfs_object_create(vp, td, td->td_ucred); 21260484Sobrien} 213218822Sdim#endif 21460484Sobrien 21560484Sobrien/* 21660484Sobrien * Look up a file name. Basically just initialize stuff and call namei(). 21760484Sobrien */ 21860484Sobrienint 21960484Sobriennfsrv_lookupfilename(struct nameidata *ndp, char *fname, NFSPROC_T *p) 22060484Sobrien{ 22189857Sobrien int error; 22260484Sobrien 22360484Sobrien NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, fname, 22460484Sobrien p); 22560484Sobrien error = namei(ndp); 22660484Sobrien if (!error) { 22760484Sobrien NDFREE(ndp, NDF_ONLY_PNBUF); 22860484Sobrien } 22960484Sobrien return (error); 23060484Sobrien} 23160484Sobrien 232130561Sobrien/* 23360484Sobrien * Copy NFS uid, gids to the cred structure. 23460484Sobrien */ 23560484Sobrienvoid 23660484Sobriennewnfs_copycred(struct nfscred *nfscr, struct ucred *cr) 23760484Sobrien{ 23860484Sobrien 23960484Sobrien KASSERT(nfscr->nfsc_ngroups >= 0, 24089857Sobrien ("newnfs_copycred: negative nfsc_ngroups")); 24189857Sobrien cr->cr_uid = nfscr->nfsc_uid; 242130561Sobrien crsetgroups(cr, nfscr->nfsc_ngroups, nfscr->nfsc_groups); 243130561Sobrien} 24460484Sobrien 24560484Sobrien/* 24660484Sobrien * Map args from nfsmsleep() to msleep(). 24760484Sobrien */ 24860484Sobrienint 24960484Sobriennfsmsleep(void *chan, void *mutex, int prio, const char *wmesg, 25060484Sobrien struct timespec *ts) 25160484Sobrien{ 25260484Sobrien u_int64_t nsecval; 25360484Sobrien int error, timeo; 25460484Sobrien 25560484Sobrien if (ts) { 25660484Sobrien timeo = hz * ts->tv_sec; 25760484Sobrien nsecval = (u_int64_t)ts->tv_nsec; 25860484Sobrien nsecval = ((nsecval * ((u_int64_t)hz)) + 500000000) / 25960484Sobrien 1000000000; 26060484Sobrien timeo += (int)nsecval; 26160484Sobrien } else { 26260484Sobrien timeo = 0; 26360484Sobrien } 26489857Sobrien error = msleep(chan, (struct mtx *)mutex, prio, wmesg, timeo); 26560484Sobrien return (error); 26660484Sobrien} 26760484Sobrien 26860484Sobrien/* 26960484Sobrien * Get the file system info for the server. For now, just assume FFS. 27060484Sobrien */ 27160484Sobrienvoid 27260484Sobriennfsvno_getfs(struct nfsfsinfo *sip, int isdgram) 27360484Sobrien{ 27460484Sobrien int pref; 27560484Sobrien 27660484Sobrien /* 27760484Sobrien * XXX 27860484Sobrien * There should be file system VFS OP(s) to get this information. 27960484Sobrien * For now, assume ufs. 28089857Sobrien */ 28160484Sobrien if (isdgram) 28260484Sobrien pref = NFS_MAXDGRAMDATA; 28360484Sobrien else 28460484Sobrien pref = NFS_MAXDATA; 28560484Sobrien sip->fs_rtmax = NFS_MAXDATA; 28660484Sobrien sip->fs_rtpref = pref; 28760484Sobrien sip->fs_rtmult = NFS_FABLKSIZE; 28860484Sobrien sip->fs_wtmax = NFS_MAXDATA; 28960484Sobrien sip->fs_wtpref = pref; 290130561Sobrien sip->fs_wtmult = NFS_FABLKSIZE; 29160484Sobrien sip->fs_dtpref = pref; 29260484Sobrien sip->fs_maxfilesize = 0xffffffffffffffffull; 29360484Sobrien sip->fs_timedelta.tv_sec = 0; 29460484Sobrien sip->fs_timedelta.tv_nsec = 1; 29560484Sobrien sip->fs_properties = (NFSV3FSINFO_LINK | 29660484Sobrien NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | 29789857Sobrien NFSV3FSINFO_CANSETTIME); 29860484Sobrien} 29989857Sobrien 30060484Sobrien/* 301130561Sobrien * Do the pathconf vnode op. 30260484Sobrien */ 30360484Sobrienint 30460484Sobriennfsvno_pathconf(struct vnode *vp, int flag, register_t *retf, 30560484Sobrien struct ucred *cred, struct thread *p) 30660484Sobrien{ 30760484Sobrien int error; 30860484Sobrien 30960484Sobrien error = VOP_PATHCONF(vp, flag, retf); 31060484Sobrien if (error == EOPNOTSUPP || error == EINVAL) { 31160484Sobrien /* 31260484Sobrien * Some file systems return EINVAL for name arguments not 31360484Sobrien * supported and some return EOPNOTSUPP for this case. 314218822Sdim * So the NFSv3 Pathconf RPC doesn't fail for these cases, 31560484Sobrien * just fake them. 31660484Sobrien */ 31760484Sobrien switch (flag) { 31860484Sobrien case _PC_LINK_MAX: 31960484Sobrien *retf = LINK_MAX; 32060484Sobrien break; 32160484Sobrien case _PC_NAME_MAX: 322218822Sdim *retf = NAME_MAX; 32360484Sobrien break; 32460484Sobrien case _PC_CHOWN_RESTRICTED: 32560484Sobrien *retf = 1; 32660484Sobrien break; 32760484Sobrien case _PC_NO_TRUNC: 32860484Sobrien *retf = 1; 32960484Sobrien break; 33060484Sobrien default: 33160484Sobrien /* 33260484Sobrien * Only happens if a _PC_xxx is added to the server, 33360484Sobrien * but this isn't updated. 33489857Sobrien */ 33560484Sobrien *retf = 0; 33660484Sobrien printf("nfsrvd pathconf flag=%d not supp\n", flag); 33760484Sobrien }; 33860484Sobrien error = 0; 33960484Sobrien } 34060484Sobrien NFSEXITCODE(error); 34160484Sobrien return (error); 34260484Sobrien} 34360484Sobrien 34460484Sobrien/* Fake nfsrv_atroot. Just return 0 */ 34560484Sobrienint 34660484Sobriennfsrv_atroot(struct vnode *vp, long *retp) 34760484Sobrien{ 348218822Sdim 349218822Sdim return (0); 35060484Sobrien} 35160484Sobrien 35260484Sobrien/* 353218822Sdim * Set the credentials to refer to root. 35460484Sobrien * If only the various BSDen could agree on whether cr_gid is a separate 35560484Sobrien * field or cr_groups[0]... 35660484Sobrien */ 35760484Sobrienvoid 35860484Sobriennewnfs_setroot(struct ucred *cred) 35960484Sobrien{ 360130561Sobrien 36160484Sobrien cred->cr_uid = 0; 36260484Sobrien cred->cr_groups[0] = 0; 36360484Sobrien cred->cr_ngroups = 1; 364130561Sobrien} 36560484Sobrien 36660484Sobrien/* 36760484Sobrien * Get the client credential. Used for Renew and recovery. 36860484Sobrien */ 36960484Sobrienstruct ucred * 37060484Sobriennewnfs_getcred(void) 37160484Sobrien{ 37260484Sobrien struct ucred *cred; 37360484Sobrien struct thread *td = curthread; 37460484Sobrien 37560484Sobrien cred = crdup(td->td_ucred); 37660484Sobrien newnfs_setroot(cred); 37760484Sobrien return (cred); 37860484Sobrien} 37960484Sobrien 38060484Sobrien/* 38160484Sobrien * Nfs timer routine 38260484Sobrien * Call the nfsd's timer function once/sec. 38360484Sobrien */ 384130561Sobrienvoid 38560484Sobriennewnfs_timer(void *arg) 38660484Sobrien{ 38760484Sobrien static time_t lasttime = 0; 38860484Sobrien /* 38960484Sobrien * Call the server timer, if set up. 39060484Sobrien * The argument indicates if it is the next second and therefore 39160484Sobrien * leases should be checked. 392218822Sdim */ 393218822Sdim if (lasttime != NFSD_MONOSEC) { 39460484Sobrien lasttime = NFSD_MONOSEC; 39560484Sobrien if (nfsd_call_servertimer != NULL) 39660484Sobrien (*nfsd_call_servertimer)(); 39760484Sobrien } 39860484Sobrien callout_reset(&newnfsd_callout, nfscl_ticks, newnfs_timer, NULL); 39960484Sobrien} 40060484Sobrien 401130561Sobrien 40260484Sobrien/* 40360484Sobrien * Sleep for a short period of time unless errval == NFSERR_GRACE, where 40460484Sobrien * the sleep should be for 5 seconds. 40560484Sobrien * Since lbolt doesn't exist in FreeBSD-CURRENT, just use a timeout on 40660484Sobrien * an event that never gets a wakeup. Only return EINTR or 0. 40760484Sobrien */ 40860484Sobrienint 40960484Sobriennfs_catnap(int prio, int errval, const char *wmesg) 41060484Sobrien{ 41160484Sobrien static int non_event; 41260484Sobrien int ret; 41360484Sobrien 41460484Sobrien if (errval == NFSERR_GRACE) 41560484Sobrien ret = tsleep(&non_event, prio, wmesg, 5 * hz); 41660484Sobrien else 41760484Sobrien ret = tsleep(&non_event, prio, wmesg, 1); 41860484Sobrien if (ret != EINTR) 41960484Sobrien ret = 0; 42060484Sobrien return (ret); 42160484Sobrien} 42260484Sobrien 42360484Sobrien/* 42460484Sobrien * Get referral. For now, just fail. 42560484Sobrien */ 42660484Sobrienstruct nfsreferral * 42760484Sobriennfsv4root_getreferral(struct vnode *vp, struct vnode *dvp, u_int32_t fileno) 42860484Sobrien{ 42960484Sobrien 43060484Sobrien return (NULL); 43160484Sobrien} 43260484Sobrien 43360484Sobrienstatic int 43460484Sobriennfssvc_nfscommon(struct thread *td, struct nfssvc_args *uap) 43560484Sobrien{ 43660484Sobrien int error; 43760484Sobrien 43860484Sobrien error = nfssvc_call(td, uap, td->td_ucred); 43960484Sobrien NFSEXITCODE(error); 44060484Sobrien return (error); 44160484Sobrien} 44260484Sobrien 44360484Sobrienstatic int 44460484Sobriennfssvc_call(struct thread *p, struct nfssvc_args *uap, struct ucred *cred) 44560484Sobrien{ 44660484Sobrien int error = EINVAL; 44760484Sobrien struct nfsd_idargs nid; 44860484Sobrien 44960484Sobrien if (uap->flag & NFSSVC_IDNAME) { 45060484Sobrien error = copyin(uap->argp, (caddr_t)&nid, sizeof (nid)); 45160484Sobrien if (error) 45260484Sobrien goto out; 45360484Sobrien error = nfssvc_idname(&nid); 45460484Sobrien goto out; 45560484Sobrien } else if (uap->flag & NFSSVC_GETSTATS) { 45660484Sobrien error = copyout(&newnfsstats, 45760484Sobrien CAST_USER_ADDR_T(uap->argp), sizeof (newnfsstats)); 45860484Sobrien if (error == 0) { 459130561Sobrien if ((uap->flag & NFSSVC_ZEROCLTSTATS) != 0) { 46060484Sobrien newnfsstats.attrcache_hits = 0; 46160484Sobrien newnfsstats.attrcache_misses = 0; 46260484Sobrien newnfsstats.lookupcache_hits = 0; 46360484Sobrien newnfsstats.lookupcache_misses = 0; 46460484Sobrien newnfsstats.direofcache_hits = 0; 46560484Sobrien newnfsstats.direofcache_misses = 0; 46660484Sobrien newnfsstats.accesscache_hits = 0; 46789857Sobrien newnfsstats.accesscache_misses = 0; 468218822Sdim newnfsstats.biocache_reads = 0; 469104834Sobrien newnfsstats.read_bios = 0; 470218822Sdim newnfsstats.read_physios = 0; 471218822Sdim newnfsstats.biocache_writes = 0; 47260484Sobrien newnfsstats.write_bios = 0; 473104834Sobrien newnfsstats.write_physios = 0; 47460484Sobrien newnfsstats.biocache_readlinks = 0; 475104834Sobrien newnfsstats.readlink_bios = 0; 47660484Sobrien newnfsstats.biocache_readdirs = 0; 47760484Sobrien newnfsstats.readdir_bios = 0; 47860484Sobrien newnfsstats.rpcretries = 0; 47960484Sobrien newnfsstats.rpcrequests = 0; 48060484Sobrien newnfsstats.rpctimeouts = 0; 48160484Sobrien newnfsstats.rpcunexpected = 0; 48260484Sobrien newnfsstats.rpcinvalid = 0; 48360484Sobrien bzero(newnfsstats.rpccnt, 48460484Sobrien sizeof(newnfsstats.rpccnt)); 485218822Sdim } 48660484Sobrien if ((uap->flag & NFSSVC_ZEROSRVSTATS) != 0) { 48760484Sobrien newnfsstats.srvrpc_errs = 0; 48860484Sobrien newnfsstats.srv_errs = 0; 48960484Sobrien newnfsstats.srvcache_inproghits = 0; 49060484Sobrien newnfsstats.srvcache_idemdonehits = 0; 49160484Sobrien newnfsstats.srvcache_nonidemdonehits = 0; 49260484Sobrien newnfsstats.srvcache_misses = 0; 49360484Sobrien newnfsstats.srvcache_tcppeak = 0; 49460484Sobrien newnfsstats.srvclients = 0; 49560484Sobrien newnfsstats.srvopenowners = 0; 49660484Sobrien newnfsstats.srvopens = 0; 49760484Sobrien newnfsstats.srvlockowners = 0; 49860484Sobrien newnfsstats.srvlocks = 0; 49960484Sobrien newnfsstats.srvdelegates = 0; 50060484Sobrien newnfsstats.clopenowners = 0; 50160484Sobrien newnfsstats.clopens = 0; 50260484Sobrien newnfsstats.cllockowners = 0; 50360484Sobrien newnfsstats.cllocks = 0; 50460484Sobrien newnfsstats.cldelegates = 0; 50560484Sobrien newnfsstats.cllocalopenowners = 0; 50660484Sobrien newnfsstats.cllocalopens = 0; 50760484Sobrien newnfsstats.cllocallockowners = 0; 50860484Sobrien newnfsstats.cllocallocks = 0; 50960484Sobrien bzero(newnfsstats.srvrpccnt, 51060484Sobrien sizeof(newnfsstats.srvrpccnt)); 51160484Sobrien bzero(newnfsstats.cbrpccnt, 51260484Sobrien sizeof(newnfsstats.cbrpccnt)); 51360484Sobrien } 51460484Sobrien } 51560484Sobrien goto out; 51660484Sobrien } else if (uap->flag & NFSSVC_NFSUSERDPORT) { 51760484Sobrien u_short sockport; 51860484Sobrien 51960484Sobrien error = copyin(uap->argp, (caddr_t)&sockport, 52060484Sobrien sizeof (u_short)); 52160484Sobrien if (!error) 52260484Sobrien error = nfsrv_nfsuserdport(sockport, p); 52360484Sobrien } else if (uap->flag & NFSSVC_NFSUSERDDELPORT) { 52460484Sobrien nfsrv_nfsuserddelport(); 52560484Sobrien error = 0; 52660484Sobrien } 52760484Sobrien 52860484Sobrienout: 52960484Sobrien NFSEXITCODE(error); 53060484Sobrien return (error); 531218822Sdim} 53260484Sobrien 53360484Sobrien/* 53460484Sobrien * called by all three modevent routines, so that it gets things 53560484Sobrien * initialized soon enough. 53660484Sobrien */ 53777298Sobrienvoid 53860484Sobriennewnfs_portinit(void) 53960484Sobrien{ 540 static int inited = 0; 541 542 if (inited) 543 return; 544 inited = 1; 545 /* Initialize SMP locks used by both client and server. */ 546 mtx_init(&newnfsd_mtx, "newnfsd_mtx", NULL, MTX_DEF); 547 mtx_init(&nfs_state_mutex, "nfs_state_mutex", NULL, MTX_DEF); 548} 549 550/* 551 * Determine if the file system supports NFSv4 ACLs. 552 * Return 1 if it does, 0 otherwise. 553 */ 554int 555nfs_supportsnfsv4acls(struct vnode *vp) 556{ 557 int error; 558 register_t retval; 559 560 ASSERT_VOP_LOCKED(vp, "nfs supports nfsv4acls"); 561 562 if (nfsrv_useacl == 0) 563 return (0); 564 error = VOP_PATHCONF(vp, _PC_ACL_NFS4, &retval); 565 if (error == 0 && retval != 0) 566 return (1); 567 return (0); 568} 569 570extern int (*nfsd_call_nfscommon)(struct thread *, struct nfssvc_args *); 571 572/* 573 * Called once to initialize data structures... 574 */ 575static int 576nfscommon_modevent(module_t mod, int type, void *data) 577{ 578 int error = 0; 579 static int loaded = 0; 580 581 switch (type) { 582 case MOD_LOAD: 583 if (loaded) 584 goto out; 585 newnfs_portinit(); 586 mtx_init(&nfs_nameid_mutex, "nfs_nameid_mutex", NULL, MTX_DEF); 587 mtx_init(&nfs_sockl_mutex, "nfs_sockl_mutex", NULL, MTX_DEF); 588 mtx_init(&nfs_slock_mutex, "nfs_slock_mutex", NULL, MTX_DEF); 589 mtx_init(&nfs_req_mutex, "nfs_req_mutex", NULL, MTX_DEF); 590 mtx_init(&nfsrv_nfsuserdsock.nr_mtx, "nfsuserd", NULL, 591 MTX_DEF); 592 callout_init(&newnfsd_callout, CALLOUT_MPSAFE); 593 newnfs_init(); 594 nfsd_call_nfscommon = nfssvc_nfscommon; 595 loaded = 1; 596 break; 597 598 case MOD_UNLOAD: 599 if (newnfs_numnfsd != 0 || nfsrv_nfsuserd != 0 || 600 nfs_numnfscbd != 0) { 601 error = EBUSY; 602 break; 603 } 604 605 nfsd_call_nfscommon = NULL; 606 callout_drain(&newnfsd_callout); 607 /* and get rid of the mutexes */ 608 mtx_destroy(&nfs_nameid_mutex); 609 mtx_destroy(&newnfsd_mtx); 610 mtx_destroy(&nfs_state_mutex); 611 mtx_destroy(&nfs_sockl_mutex); 612 mtx_destroy(&nfs_slock_mutex); 613 mtx_destroy(&nfs_req_mutex); 614 mtx_destroy(&nfsrv_nfsuserdsock.nr_mtx); 615 loaded = 0; 616 break; 617 default: 618 error = EOPNOTSUPP; 619 break; 620 } 621 622out: 623 NFSEXITCODE(error); 624 return error; 625} 626static moduledata_t nfscommon_mod = { 627 "nfscommon", 628 nfscommon_modevent, 629 NULL, 630}; 631DECLARE_MODULE(nfscommon, nfscommon_mod, SI_SUB_VFS, SI_ORDER_ANY); 632 633/* So that loader and kldload(2) can find us, wherever we are.. */ 634MODULE_VERSION(nfscommon, 1); 635MODULE_DEPEND(nfscommon, nfssvc, 1, 1, 1); 636MODULE_DEPEND(nfscommon, krpc, 1, 1, 1); 637 638