nfs_clvfsops.c revision 232292
1191783Srmacklem/*- 2191783Srmacklem * Copyright (c) 1989, 1993, 1995 3191783Srmacklem * The Regents of the University of California. All rights reserved. 4191783Srmacklem * 5191783Srmacklem * This code is derived from software contributed to Berkeley by 6191783Srmacklem * Rick Macklem at The University of Guelph. 7191783Srmacklem * 8191783Srmacklem * Redistribution and use in source and binary forms, with or without 9191783Srmacklem * modification, are permitted provided that the following conditions 10191783Srmacklem * are met: 11191783Srmacklem * 1. Redistributions of source code must retain the above copyright 12191783Srmacklem * notice, this list of conditions and the following disclaimer. 13191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright 14191783Srmacklem * notice, this list of conditions and the following disclaimer in the 15191783Srmacklem * documentation and/or other materials provided with the distribution. 16191783Srmacklem * 4. Neither the name of the University nor the names of its contributors 17191783Srmacklem * may be used to endorse or promote products derived from this software 18191783Srmacklem * without specific prior written permission. 19191783Srmacklem * 20191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21191783Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22191783Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23191783Srmacklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24191783Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25191783Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26191783Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27191783Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28191783Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29191783Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30191783Srmacklem * SUCH DAMAGE. 31191783Srmacklem * 32191783Srmacklem * from nfs_vfsops.c 8.12 (Berkeley) 5/20/95 33191783Srmacklem */ 34191783Srmacklem 35191783Srmacklem#include <sys/cdefs.h> 36191783Srmacklem__FBSDID("$FreeBSD: stable/9/sys/fs/nfsclient/nfs_clvfsops.c 232292 2012-02-29 09:47:26Z bz $"); 37191783Srmacklem 38191783Srmacklem 39191783Srmacklem#include "opt_bootp.h" 40191783Srmacklem#include "opt_nfsroot.h" 41191783Srmacklem 42191783Srmacklem#include <sys/param.h> 43191783Srmacklem#include <sys/systm.h> 44191783Srmacklem#include <sys/kernel.h> 45191783Srmacklem#include <sys/bio.h> 46191783Srmacklem#include <sys/buf.h> 47191783Srmacklem#include <sys/clock.h> 48193066Sjamie#include <sys/jail.h> 49220739Srmacklem#include <sys/limits.h> 50191783Srmacklem#include <sys/lock.h> 51191783Srmacklem#include <sys/malloc.h> 52191783Srmacklem#include <sys/mbuf.h> 53191783Srmacklem#include <sys/module.h> 54191783Srmacklem#include <sys/mount.h> 55191783Srmacklem#include <sys/proc.h> 56191783Srmacklem#include <sys/socket.h> 57191783Srmacklem#include <sys/socketvar.h> 58191783Srmacklem#include <sys/sockio.h> 59191783Srmacklem#include <sys/sysctl.h> 60191783Srmacklem#include <sys/vnode.h> 61191783Srmacklem#include <sys/signalvar.h> 62191783Srmacklem 63191783Srmacklem#include <vm/vm.h> 64191783Srmacklem#include <vm/vm_extern.h> 65191783Srmacklem#include <vm/uma.h> 66191783Srmacklem 67191783Srmacklem#include <net/if.h> 68191783Srmacklem#include <net/route.h> 69191783Srmacklem#include <netinet/in.h> 70191783Srmacklem 71191783Srmacklem#include <fs/nfs/nfsport.h> 72191783Srmacklem#include <fs/nfsclient/nfsnode.h> 73191783Srmacklem#include <fs/nfsclient/nfsmount.h> 74191783Srmacklem#include <fs/nfsclient/nfs.h> 75221040Srmacklem#include <nfs/nfsdiskless.h> 76191783Srmacklem 77219028SnetchildFEATURE(nfscl, "NFSv4 client"); 78219028Snetchild 79191783Srmacklemextern int nfscl_ticks; 80191783Srmacklemextern struct timeval nfsboottime; 81191783Srmacklemextern struct nfsstats newnfsstats; 82222233Srmacklemextern int nfsrv_useacl; 83191783Srmacklem 84191783SrmacklemMALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header"); 85191783SrmacklemMALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct"); 86191783Srmacklem 87221973SrmacklemSYSCTL_DECL(_vfs_nfs); 88191783Srmacklemstatic int nfs_ip_paranoia = 1; 89221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW, 90191783Srmacklem &nfs_ip_paranoia, 0, ""); 91191783Srmacklemstatic int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY; 92221973SrmacklemSYSCTL_INT(_vfs_nfs, NFS_TPRINTF_INITIAL_DELAY, 93191783Srmacklem downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, ""); 94191783Srmacklem/* how long between console messages "nfs server foo not responding" */ 95191783Srmacklemstatic int nfs_tprintf_delay = NFS_TPRINTF_DELAY; 96221973SrmacklemSYSCTL_INT(_vfs_nfs, NFS_TPRINTF_DELAY, 97191783Srmacklem downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, ""); 98191783Srmacklem 99221040Srmacklemstatic int nfs_mountroot(struct mount *); 100192585Srmacklemstatic void nfs_sec_name(char *, int *); 101191783Srmacklemstatic void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, 102214048Srmacklem struct nfs_args *argp, const char *, struct ucred *, 103214048Srmacklem struct thread *); 104191783Srmacklemstatic int mountnfs(struct nfs_args *, struct mount *, 105221014Srmacklem struct sockaddr *, char *, u_char *, int, u_char *, int, 106221014Srmacklem u_char *, int, struct vnode **, struct ucred *, 107221014Srmacklem struct thread *, int); 108214053Srmacklemstatic void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *, 109216931Srmacklem struct sockaddr_storage *, int *, off_t *, 110216931Srmacklem struct timeval *); 111191783Srmacklemstatic vfs_mount_t nfs_mount; 112191783Srmacklemstatic vfs_cmount_t nfs_cmount; 113191783Srmacklemstatic vfs_unmount_t nfs_unmount; 114191783Srmacklemstatic vfs_root_t nfs_root; 115191783Srmacklemstatic vfs_statfs_t nfs_statfs; 116191783Srmacklemstatic vfs_sync_t nfs_sync; 117191783Srmacklemstatic vfs_sysctl_t nfs_sysctl; 118191783Srmacklem 119191783Srmacklem/* 120191783Srmacklem * nfs vfs operations. 121191783Srmacklem */ 122191783Srmacklemstatic struct vfsops nfs_vfsops = { 123191783Srmacklem .vfs_init = ncl_init, 124191783Srmacklem .vfs_mount = nfs_mount, 125191783Srmacklem .vfs_cmount = nfs_cmount, 126191783Srmacklem .vfs_root = nfs_root, 127191783Srmacklem .vfs_statfs = nfs_statfs, 128191783Srmacklem .vfs_sync = nfs_sync, 129191783Srmacklem .vfs_uninit = ncl_uninit, 130191783Srmacklem .vfs_unmount = nfs_unmount, 131191783Srmacklem .vfs_sysctl = nfs_sysctl, 132191783Srmacklem}; 133221124SrmacklemVFS_SET(nfs_vfsops, nfs, VFCF_NETWORK); 134191783Srmacklem 135191783Srmacklem/* So that loader and kldload(2) can find us, wherever we are.. */ 136221139SrmacklemMODULE_VERSION(nfs, 1); 137221139SrmacklemMODULE_DEPEND(nfs, nfscommon, 1, 1, 1); 138221139SrmacklemMODULE_DEPEND(nfs, krpc, 1, 1, 1); 139221139SrmacklemMODULE_DEPEND(nfs, nfssvc, 1, 1, 1); 140221139SrmacklemMODULE_DEPEND(nfs, nfslock, 1, 1, 1); 141191783Srmacklem 142191783Srmacklem/* 143221066Srmacklem * This structure is now defined in sys/nfs/nfs_diskless.c so that it 144221066Srmacklem * can be shared by both NFS clients. It is declared here so that it 145221066Srmacklem * will be defined for kernels built without NFS_ROOT, although it 146221066Srmacklem * isn't used in that case. 147191783Srmacklem */ 148221066Srmacklem#if !defined(NFS_ROOT) && !defined(NFSCLIENT) 149221066Srmacklemstruct nfs_diskless nfs_diskless = { { { 0 } } }; 150221066Srmacklemstruct nfsv3_diskless nfsv3_diskless = { { { 0 } } }; 151221066Srmacklemint nfs_diskless_valid = 0; 152221066Srmacklem#endif 153221066Srmacklem 154221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD, 155221040Srmacklem &nfs_diskless_valid, 0, 156192145Srmacklem "Has the diskless struct been filled correctly"); 157191783Srmacklem 158221973SrmacklemSYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD, 159221040Srmacklem nfsv3_diskless.root_hostnam, 0, "Path to nfs root"); 160191783Srmacklem 161221973SrmacklemSYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD, 162221040Srmacklem &nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr), 163192145Srmacklem "%Ssockaddr_in", "Diskless root nfs address"); 164191783Srmacklem 165191783Srmacklem 166191783Srmacklemvoid newnfsargs_ntoh(struct nfs_args *); 167191783Srmacklemstatic int nfs_mountdiskless(char *, 168191783Srmacklem struct sockaddr_in *, struct nfs_args *, 169191783Srmacklem struct thread *, struct vnode **, struct mount *); 170191783Srmacklemstatic void nfs_convert_diskless(void); 171191783Srmacklemstatic void nfs_convert_oargs(struct nfs_args *args, 172191783Srmacklem struct onfs_args *oargs); 173191783Srmacklem 174191783Srmacklemint 175191783Srmacklemnewnfs_iosize(struct nfsmount *nmp) 176191783Srmacklem{ 177191783Srmacklem int iosize, maxio; 178191783Srmacklem 179191783Srmacklem /* First, set the upper limit for iosize */ 180191783Srmacklem if (nmp->nm_flag & NFSMNT_NFSV4) { 181191783Srmacklem maxio = NFS_MAXBSIZE; 182191783Srmacklem } else if (nmp->nm_flag & NFSMNT_NFSV3) { 183191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 184191783Srmacklem maxio = NFS_MAXDGRAMDATA; 185191783Srmacklem else 186191783Srmacklem maxio = NFS_MAXBSIZE; 187191783Srmacklem } else { 188191783Srmacklem maxio = NFS_V2MAXDATA; 189191783Srmacklem } 190191783Srmacklem if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0) 191191783Srmacklem nmp->nm_rsize = maxio; 192191783Srmacklem if (nmp->nm_rsize > MAXBSIZE) 193191783Srmacklem nmp->nm_rsize = MAXBSIZE; 194191783Srmacklem if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0) 195191783Srmacklem nmp->nm_readdirsize = maxio; 196191783Srmacklem if (nmp->nm_readdirsize > nmp->nm_rsize) 197191783Srmacklem nmp->nm_readdirsize = nmp->nm_rsize; 198191783Srmacklem if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0) 199191783Srmacklem nmp->nm_wsize = maxio; 200191783Srmacklem if (nmp->nm_wsize > MAXBSIZE) 201191783Srmacklem nmp->nm_wsize = MAXBSIZE; 202191783Srmacklem 203191783Srmacklem /* 204191783Srmacklem * Calculate the size used for io buffers. Use the larger 205191783Srmacklem * of the two sizes to minimise nfs requests but make sure 206191783Srmacklem * that it is at least one VM page to avoid wasting buffer 207191783Srmacklem * space. 208191783Srmacklem */ 209191783Srmacklem iosize = imax(nmp->nm_rsize, nmp->nm_wsize); 210191783Srmacklem iosize = imax(iosize, PAGE_SIZE); 211191783Srmacklem nmp->nm_mountp->mnt_stat.f_iosize = iosize; 212191783Srmacklem return (iosize); 213191783Srmacklem} 214191783Srmacklem 215191783Srmacklemstatic void 216191783Srmacklemnfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs) 217191783Srmacklem{ 218191783Srmacklem 219191783Srmacklem args->version = NFS_ARGSVERSION; 220191783Srmacklem args->addr = oargs->addr; 221191783Srmacklem args->addrlen = oargs->addrlen; 222191783Srmacklem args->sotype = oargs->sotype; 223191783Srmacklem args->proto = oargs->proto; 224191783Srmacklem args->fh = oargs->fh; 225191783Srmacklem args->fhsize = oargs->fhsize; 226191783Srmacklem args->flags = oargs->flags; 227191783Srmacklem args->wsize = oargs->wsize; 228191783Srmacklem args->rsize = oargs->rsize; 229191783Srmacklem args->readdirsize = oargs->readdirsize; 230191783Srmacklem args->timeo = oargs->timeo; 231191783Srmacklem args->retrans = oargs->retrans; 232191783Srmacklem args->readahead = oargs->readahead; 233191783Srmacklem args->hostname = oargs->hostname; 234191783Srmacklem} 235191783Srmacklem 236191783Srmacklemstatic void 237191783Srmacklemnfs_convert_diskless(void) 238191783Srmacklem{ 239191783Srmacklem 240221040Srmacklem bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif, 241221040Srmacklem sizeof(struct ifaliasreq)); 242221040Srmacklem bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway, 243221040Srmacklem sizeof(struct sockaddr_in)); 244221040Srmacklem nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args); 245221040Srmacklem if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) { 246221040Srmacklem nfsv3_diskless.root_fhsize = NFSX_MYFH; 247221040Srmacklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH); 248191783Srmacklem } else { 249221040Srmacklem nfsv3_diskless.root_fhsize = NFSX_V2FH; 250221040Srmacklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH); 251191783Srmacklem } 252221040Srmacklem bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr, 253221040Srmacklem sizeof(struct sockaddr_in)); 254221040Srmacklem bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN); 255221040Srmacklem nfsv3_diskless.root_time = nfs_diskless.root_time; 256221040Srmacklem bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam, 257221040Srmacklem MAXHOSTNAMELEN); 258221040Srmacklem nfs_diskless_valid = 3; 259191783Srmacklem} 260191783Srmacklem 261191783Srmacklem/* 262191783Srmacklem * nfs statfs call 263191783Srmacklem */ 264191783Srmacklemstatic int 265191990Sattilionfs_statfs(struct mount *mp, struct statfs *sbp) 266191783Srmacklem{ 267191783Srmacklem struct vnode *vp; 268191990Sattilio struct thread *td; 269191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 270191783Srmacklem struct nfsvattr nfsva; 271191783Srmacklem struct nfsfsinfo fs; 272191783Srmacklem struct nfsstatfs sb; 273191783Srmacklem int error = 0, attrflag, gotfsinfo = 0, ret; 274191783Srmacklem struct nfsnode *np; 275191783Srmacklem 276191990Sattilio td = curthread; 277191990Sattilio 278191783Srmacklem error = vfs_busy(mp, MBF_NOWAIT); 279191783Srmacklem if (error) 280191783Srmacklem return (error); 281220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE); 282191783Srmacklem if (error) { 283191783Srmacklem vfs_unbusy(mp); 284191783Srmacklem return (error); 285191783Srmacklem } 286191783Srmacklem vp = NFSTOV(np); 287191783Srmacklem mtx_lock(&nmp->nm_mtx); 288191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 289191783Srmacklem mtx_unlock(&nmp->nm_mtx); 290191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva, 291191783Srmacklem &attrflag, NULL); 292191783Srmacklem if (!error) 293191783Srmacklem gotfsinfo = 1; 294191783Srmacklem } else 295191783Srmacklem mtx_unlock(&nmp->nm_mtx); 296191783Srmacklem if (!error) 297191783Srmacklem error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, 298191783Srmacklem &attrflag, NULL); 299191783Srmacklem if (attrflag == 0) { 300191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 301191783Srmacklem td->td_ucred, td, &nfsva, NULL); 302191783Srmacklem if (ret) { 303191783Srmacklem /* 304191783Srmacklem * Just set default values to get things going. 305191783Srmacklem */ 306191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 307191783Srmacklem nfsva.na_vattr.va_type = VDIR; 308191783Srmacklem nfsva.na_vattr.va_mode = 0777; 309191783Srmacklem nfsva.na_vattr.va_nlink = 100; 310191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 311191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 312191783Srmacklem nfsva.na_vattr.va_fileid = 2; 313191783Srmacklem nfsva.na_vattr.va_gen = 1; 314191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 315191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 316191783Srmacklem } 317191783Srmacklem } 318191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 319191783Srmacklem if (!error) { 320191783Srmacklem mtx_lock(&nmp->nm_mtx); 321191783Srmacklem if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4)) 322191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 323191783Srmacklem nfscl_loadsbinfo(nmp, &sb, sbp); 324191783Srmacklem sbp->f_iosize = newnfs_iosize(nmp); 325191783Srmacklem mtx_unlock(&nmp->nm_mtx); 326191783Srmacklem if (sbp != &mp->mnt_stat) { 327191783Srmacklem bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 328191783Srmacklem bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 329191783Srmacklem } 330191783Srmacklem strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 331191783Srmacklem } else if (NFS_ISV4(vp)) { 332191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 333191783Srmacklem } 334191783Srmacklem vput(vp); 335191783Srmacklem vfs_unbusy(mp); 336191783Srmacklem return (error); 337191783Srmacklem} 338191783Srmacklem 339191783Srmacklem/* 340191783Srmacklem * nfs version 3 fsinfo rpc call 341191783Srmacklem */ 342191783Srmacklemint 343191783Srmacklemncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, 344191783Srmacklem struct thread *td) 345191783Srmacklem{ 346191783Srmacklem struct nfsfsinfo fs; 347191783Srmacklem struct nfsvattr nfsva; 348191783Srmacklem int error, attrflag; 349191783Srmacklem 350191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL); 351191783Srmacklem if (!error) { 352191783Srmacklem if (attrflag) 353191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 354191783Srmacklem 1); 355191783Srmacklem mtx_lock(&nmp->nm_mtx); 356191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 357191783Srmacklem mtx_unlock(&nmp->nm_mtx); 358191783Srmacklem } 359191783Srmacklem return (error); 360191783Srmacklem} 361191783Srmacklem 362191783Srmacklem/* 363191783Srmacklem * Mount a remote root fs via. nfs. This depends on the info in the 364221040Srmacklem * nfs_diskless structure that has been filled in properly by some primary 365191783Srmacklem * bootstrap. 366191783Srmacklem * It goes something like this: 367191783Srmacklem * - do enough of "ifconfig" by calling ifioctl() so that the system 368191783Srmacklem * can talk to the server 369221040Srmacklem * - If nfs_diskless.mygateway is filled in, use that address as 370191783Srmacklem * a default gateway. 371191783Srmacklem * - build the rootfs mount point and call mountnfs() to do the rest. 372191783Srmacklem * 373191783Srmacklem * It is assumed to be safe to read, modify, and write the nfsv3_diskless 374191783Srmacklem * structure, as well as other global NFS client variables here, as 375192145Srmacklem * nfs_mountroot() will be called once in the boot before any other NFS 376191783Srmacklem * client activity occurs. 377191783Srmacklem */ 378221040Srmacklemstatic int 379221040Srmacklemnfs_mountroot(struct mount *mp) 380191783Srmacklem{ 381192145Srmacklem struct thread *td = curthread; 382221040Srmacklem struct nfsv3_diskless *nd = &nfsv3_diskless; 383191783Srmacklem struct socket *so; 384191783Srmacklem struct vnode *vp; 385191783Srmacklem struct ifreq ir; 386193066Sjamie int error; 387191783Srmacklem u_long l; 388191783Srmacklem char buf[128]; 389191783Srmacklem char *cp; 390191783Srmacklem 391191783Srmacklem#if defined(BOOTP_NFSROOT) && defined(BOOTP) 392192145Srmacklem bootpc_init(); /* use bootp to get nfs_diskless filled in */ 393191783Srmacklem#elif defined(NFS_ROOT) 394191783Srmacklem nfs_setup_diskless(); 395191783Srmacklem#endif 396191783Srmacklem 397221040Srmacklem if (nfs_diskless_valid == 0) 398191783Srmacklem return (-1); 399221040Srmacklem if (nfs_diskless_valid == 1) 400191783Srmacklem nfs_convert_diskless(); 401191783Srmacklem 402191783Srmacklem /* 403191783Srmacklem * XXX splnet, so networks will receive... 404191783Srmacklem */ 405191783Srmacklem splnet(); 406191783Srmacklem 407191783Srmacklem /* 408191783Srmacklem * Do enough of ifconfig(8) so that the critical net interface can 409191783Srmacklem * talk to the server. 410191783Srmacklem */ 411191783Srmacklem error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0, 412191783Srmacklem td->td_ucred, td); 413191783Srmacklem if (error) 414192145Srmacklem panic("nfs_mountroot: socreate(%04x): %d", 415191783Srmacklem nd->myif.ifra_addr.sa_family, error); 416191783Srmacklem 417191783Srmacklem#if 0 /* XXX Bad idea */ 418191783Srmacklem /* 419191783Srmacklem * We might not have been told the right interface, so we pass 420191783Srmacklem * over the first ten interfaces of the same kind, until we get 421191783Srmacklem * one of them configured. 422191783Srmacklem */ 423191783Srmacklem 424191783Srmacklem for (i = strlen(nd->myif.ifra_name) - 1; 425191783Srmacklem nd->myif.ifra_name[i] >= '0' && 426191783Srmacklem nd->myif.ifra_name[i] <= '9'; 427191783Srmacklem nd->myif.ifra_name[i] ++) { 428191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 429191783Srmacklem if(!error) 430191783Srmacklem break; 431191783Srmacklem } 432191783Srmacklem#endif 433191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 434191783Srmacklem if (error) 435192145Srmacklem panic("nfs_mountroot: SIOCAIFADDR: %d", error); 436191783Srmacklem if ((cp = getenv("boot.netif.mtu")) != NULL) { 437191783Srmacklem ir.ifr_mtu = strtol(cp, NULL, 10); 438191783Srmacklem bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); 439191783Srmacklem freeenv(cp); 440191783Srmacklem error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); 441191783Srmacklem if (error) 442192145Srmacklem printf("nfs_mountroot: SIOCSIFMTU: %d", error); 443191783Srmacklem } 444191783Srmacklem soclose(so); 445191783Srmacklem 446191783Srmacklem /* 447191783Srmacklem * If the gateway field is filled in, set it as the default route. 448191783Srmacklem * Note that pxeboot will set a default route of 0 if the route 449191783Srmacklem * is not set by the DHCP server. Check also for a value of 0 450191783Srmacklem * to avoid panicking inappropriately in that situation. 451191783Srmacklem */ 452191783Srmacklem if (nd->mygateway.sin_len != 0 && 453191783Srmacklem nd->mygateway.sin_addr.s_addr != 0) { 454191783Srmacklem struct sockaddr_in mask, sin; 455191783Srmacklem 456191783Srmacklem bzero((caddr_t)&mask, sizeof(mask)); 457191783Srmacklem sin = mask; 458191783Srmacklem sin.sin_family = AF_INET; 459191783Srmacklem sin.sin_len = sizeof(sin); 460192145Srmacklem /* XXX MRT use table 0 for this sort of thing */ 461218757Sbz CURVNET_SET(TD_TO_VNET(td)); 462232292Sbz error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin, 463191783Srmacklem (struct sockaddr *)&nd->mygateway, 464191783Srmacklem (struct sockaddr *)&mask, 465232292Sbz RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB); 466218757Sbz CURVNET_RESTORE(); 467191783Srmacklem if (error) 468192145Srmacklem panic("nfs_mountroot: RTM_ADD: %d", error); 469191783Srmacklem } 470191783Srmacklem 471191783Srmacklem /* 472191783Srmacklem * Create the rootfs mount point. 473191783Srmacklem */ 474191783Srmacklem nd->root_args.fh = nd->root_fh; 475191783Srmacklem nd->root_args.fhsize = nd->root_fhsize; 476191783Srmacklem l = ntohl(nd->root_saddr.sin_addr.s_addr); 477191783Srmacklem snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", 478191783Srmacklem (l >> 24) & 0xff, (l >> 16) & 0xff, 479191783Srmacklem (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); 480191783Srmacklem printf("NFS ROOT: %s\n", buf); 481192145Srmacklem nd->root_args.hostname = buf; 482191783Srmacklem if ((error = nfs_mountdiskless(buf, 483191783Srmacklem &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { 484191783Srmacklem return (error); 485191783Srmacklem } 486191783Srmacklem 487191783Srmacklem /* 488191783Srmacklem * This is not really an nfs issue, but it is much easier to 489191783Srmacklem * set hostname here and then let the "/etc/rc.xxx" files 490191783Srmacklem * mount the right /var based upon its preset value. 491191783Srmacklem */ 492193066Sjamie mtx_lock(&prison0.pr_mtx); 493194118Sjamie strlcpy(prison0.pr_hostname, nd->my_hostnam, 494194118Sjamie sizeof(prison0.pr_hostname)); 495193066Sjamie mtx_unlock(&prison0.pr_mtx); 496191783Srmacklem inittodr(ntohl(nd->root_time)); 497191783Srmacklem return (0); 498191783Srmacklem} 499191783Srmacklem 500191783Srmacklem/* 501191783Srmacklem * Internal version of mount system call for diskless setup. 502191783Srmacklem */ 503191783Srmacklemstatic int 504191783Srmacklemnfs_mountdiskless(char *path, 505191783Srmacklem struct sockaddr_in *sin, struct nfs_args *args, struct thread *td, 506191783Srmacklem struct vnode **vpp, struct mount *mp) 507191783Srmacklem{ 508191783Srmacklem struct sockaddr *nam; 509221014Srmacklem int dirlen, error; 510221014Srmacklem char *dirpath; 511191783Srmacklem 512221014Srmacklem /* 513221014Srmacklem * Find the directory path in "path", which also has the server's 514221014Srmacklem * name/ip address in it. 515221014Srmacklem */ 516221014Srmacklem dirpath = strchr(path, ':'); 517221014Srmacklem if (dirpath != NULL) 518221014Srmacklem dirlen = strlen(++dirpath); 519221014Srmacklem else 520221014Srmacklem dirlen = 0; 521191783Srmacklem nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); 522221014Srmacklem if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen, 523221014Srmacklem NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NEGNAMETIMEO)) != 0) { 524192145Srmacklem printf("nfs_mountroot: mount %s on /: %d\n", path, error); 525191783Srmacklem return (error); 526191783Srmacklem } 527191783Srmacklem return (0); 528191783Srmacklem} 529191783Srmacklem 530191783Srmacklemstatic void 531192585Srmacklemnfs_sec_name(char *sec, int *flagsp) 532192585Srmacklem{ 533192585Srmacklem if (!strcmp(sec, "krb5")) 534192585Srmacklem *flagsp |= NFSMNT_KERB; 535192585Srmacklem else if (!strcmp(sec, "krb5i")) 536192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY); 537192585Srmacklem else if (!strcmp(sec, "krb5p")) 538192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY); 539192585Srmacklem} 540192585Srmacklem 541192585Srmacklemstatic void 542191783Srmacklemnfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, 543214048Srmacklem const char *hostname, struct ucred *cred, struct thread *td) 544191783Srmacklem{ 545191783Srmacklem int s; 546191783Srmacklem int adjsock; 547214048Srmacklem char *p; 548191783Srmacklem 549191783Srmacklem s = splnet(); 550191783Srmacklem 551191783Srmacklem /* 552191783Srmacklem * Set read-only flag if requested; otherwise, clear it if this is 553191783Srmacklem * an update. If this is not an update, then either the read-only 554191783Srmacklem * flag is already clear, or this is a root mount and it was set 555191783Srmacklem * intentionally at some previous point. 556191783Srmacklem */ 557191783Srmacklem if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) { 558191783Srmacklem MNT_ILOCK(mp); 559191783Srmacklem mp->mnt_flag |= MNT_RDONLY; 560191783Srmacklem MNT_IUNLOCK(mp); 561191783Srmacklem } else if (mp->mnt_flag & MNT_UPDATE) { 562191783Srmacklem MNT_ILOCK(mp); 563191783Srmacklem mp->mnt_flag &= ~MNT_RDONLY; 564191783Srmacklem MNT_IUNLOCK(mp); 565191783Srmacklem } 566191783Srmacklem 567191783Srmacklem /* 568191783Srmacklem * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 569191783Srmacklem * no sense in that context. Also, set up appropriate retransmit 570191783Srmacklem * and soft timeout behavior. 571191783Srmacklem */ 572191783Srmacklem if (argp->sotype == SOCK_STREAM) { 573191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOCONN; 574191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 575220739Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0) 576220739Srmacklem nmp->nm_retry = INT_MAX; 577220739Srmacklem else 578220739Srmacklem nmp->nm_retry = NFS_RETRANS_TCP; 579191783Srmacklem } 580191783Srmacklem 581220739Srmacklem /* Also clear RDIRPLUS if NFSv2, it crashes some servers */ 582220739Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 583220739Srmacklem argp->flags &= ~NFSMNT_RDIRPLUS; 584191783Srmacklem nmp->nm_flag &= ~NFSMNT_RDIRPLUS; 585220739Srmacklem } 586191783Srmacklem 587220739Srmacklem /* Clear NFSMNT_RESVPORT for NFSv4, since it is not required. */ 588220739Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0) { 589220739Srmacklem argp->flags &= ~NFSMNT_RESVPORT; 590220739Srmacklem nmp->nm_flag &= ~NFSMNT_RESVPORT; 591220739Srmacklem } 592220739Srmacklem 593220739Srmacklem /* Re-bind if rsrvd port requested and wasn't on one */ 594220739Srmacklem adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT) 595220739Srmacklem && (argp->flags & NFSMNT_RESVPORT); 596191783Srmacklem /* Also re-bind if we're switching to/from a connected UDP socket */ 597220739Srmacklem adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) != 598191783Srmacklem (argp->flags & NFSMNT_NOCONN)); 599191783Srmacklem 600191783Srmacklem /* Update flags atomically. Don't change the lock bits. */ 601191783Srmacklem nmp->nm_flag = argp->flags | nmp->nm_flag; 602191783Srmacklem splx(s); 603191783Srmacklem 604191783Srmacklem if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 605191783Srmacklem nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 606191783Srmacklem if (nmp->nm_timeo < NFS_MINTIMEO) 607191783Srmacklem nmp->nm_timeo = NFS_MINTIMEO; 608191783Srmacklem else if (nmp->nm_timeo > NFS_MAXTIMEO) 609191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 610191783Srmacklem } 611191783Srmacklem 612191783Srmacklem if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 613191783Srmacklem nmp->nm_retry = argp->retrans; 614191783Srmacklem if (nmp->nm_retry > NFS_MAXREXMIT) 615191783Srmacklem nmp->nm_retry = NFS_MAXREXMIT; 616191783Srmacklem } 617191783Srmacklem 618191783Srmacklem if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 619191783Srmacklem nmp->nm_wsize = argp->wsize; 620191783Srmacklem /* Round down to multiple of blocksize */ 621191783Srmacklem nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); 622191783Srmacklem if (nmp->nm_wsize <= 0) 623191783Srmacklem nmp->nm_wsize = NFS_FABLKSIZE; 624191783Srmacklem } 625191783Srmacklem 626191783Srmacklem if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 627191783Srmacklem nmp->nm_rsize = argp->rsize; 628191783Srmacklem /* Round down to multiple of blocksize */ 629191783Srmacklem nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); 630191783Srmacklem if (nmp->nm_rsize <= 0) 631191783Srmacklem nmp->nm_rsize = NFS_FABLKSIZE; 632191783Srmacklem } 633191783Srmacklem 634191783Srmacklem if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 635191783Srmacklem nmp->nm_readdirsize = argp->readdirsize; 636191783Srmacklem } 637191783Srmacklem 638191783Srmacklem if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) 639191783Srmacklem nmp->nm_acregmin = argp->acregmin; 640191783Srmacklem else 641191783Srmacklem nmp->nm_acregmin = NFS_MINATTRTIMO; 642191783Srmacklem if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) 643191783Srmacklem nmp->nm_acregmax = argp->acregmax; 644191783Srmacklem else 645191783Srmacklem nmp->nm_acregmax = NFS_MAXATTRTIMO; 646191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) 647191783Srmacklem nmp->nm_acdirmin = argp->acdirmin; 648191783Srmacklem else 649191783Srmacklem nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; 650191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) 651191783Srmacklem nmp->nm_acdirmax = argp->acdirmax; 652191783Srmacklem else 653191783Srmacklem nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; 654191783Srmacklem if (nmp->nm_acdirmin > nmp->nm_acdirmax) 655191783Srmacklem nmp->nm_acdirmin = nmp->nm_acdirmax; 656191783Srmacklem if (nmp->nm_acregmin > nmp->nm_acregmax) 657191783Srmacklem nmp->nm_acregmin = nmp->nm_acregmax; 658191783Srmacklem 659191783Srmacklem if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { 660191783Srmacklem if (argp->readahead <= NFS_MAXRAHEAD) 661191783Srmacklem nmp->nm_readahead = argp->readahead; 662191783Srmacklem else 663191783Srmacklem nmp->nm_readahead = NFS_MAXRAHEAD; 664191783Srmacklem } 665191783Srmacklem if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) { 666191783Srmacklem if (argp->wcommitsize < nmp->nm_wsize) 667191783Srmacklem nmp->nm_wcommitsize = nmp->nm_wsize; 668191783Srmacklem else 669191783Srmacklem nmp->nm_wcommitsize = argp->wcommitsize; 670191783Srmacklem } 671191783Srmacklem 672191783Srmacklem adjsock |= ((nmp->nm_sotype != argp->sotype) || 673191783Srmacklem (nmp->nm_soproto != argp->proto)); 674191783Srmacklem 675191783Srmacklem if (nmp->nm_client != NULL && adjsock) { 676191783Srmacklem int haslock = 0, error = 0; 677191783Srmacklem 678191783Srmacklem if (nmp->nm_sotype == SOCK_STREAM) { 679191783Srmacklem error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock); 680191783Srmacklem if (!error) 681191783Srmacklem haslock = 1; 682191783Srmacklem } 683191783Srmacklem if (!error) { 684191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 685191783Srmacklem if (haslock) 686191783Srmacklem newnfs_sndunlock(&nmp->nm_sockreq.nr_lock); 687191783Srmacklem nmp->nm_sotype = argp->sotype; 688191783Srmacklem nmp->nm_soproto = argp->proto; 689191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 690191783Srmacklem while (newnfs_connect(nmp, &nmp->nm_sockreq, 691191783Srmacklem cred, td, 0)) { 692191783Srmacklem printf("newnfs_args: retrying connect\n"); 693207170Srmacklem (void) nfs_catnap(PSOCK, 0, "newnfscon"); 694191783Srmacklem } 695191783Srmacklem } 696191783Srmacklem } else { 697191783Srmacklem nmp->nm_sotype = argp->sotype; 698191783Srmacklem nmp->nm_soproto = argp->proto; 699191783Srmacklem } 700214048Srmacklem 701214048Srmacklem if (hostname != NULL) { 702214048Srmacklem strlcpy(nmp->nm_hostname, hostname, 703214048Srmacklem sizeof(nmp->nm_hostname)); 704214048Srmacklem p = strchr(nmp->nm_hostname, ':'); 705214048Srmacklem if (p != NULL) 706214048Srmacklem *p = '\0'; 707214048Srmacklem } 708191783Srmacklem} 709191783Srmacklem 710221190Srmacklemstatic const char *nfs_opts[] = { "from", "nfs_args", 711191783Srmacklem "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union", 712191783Srmacklem "noclusterr", "noclusterw", "multilabel", "acls", "force", "update", 713192585Srmacklem "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus", 714192585Srmacklem "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize", 715192585Srmacklem "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport", 716192585Srmacklem "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec", 717192585Srmacklem "principal", "nfsv4", "gssname", "allgssname", "dirpath", 718229604Sjhb "negnametimeo", "nocto", "wcommitsize", 719191783Srmacklem NULL }; 720191783Srmacklem 721191783Srmacklem/* 722191783Srmacklem * VFS Operations. 723191783Srmacklem * 724191783Srmacklem * mount system call 725191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 726191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 727191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 728191783Srmacklem * an error after that means that I have to release the mbuf. 729191783Srmacklem */ 730191783Srmacklem/* ARGSUSED */ 731191783Srmacklemstatic int 732191990Sattilionfs_mount(struct mount *mp) 733191783Srmacklem{ 734191783Srmacklem struct nfs_args args = { 735191783Srmacklem .version = NFS_ARGSVERSION, 736191783Srmacklem .addr = NULL, 737191783Srmacklem .addrlen = sizeof (struct sockaddr_in), 738191783Srmacklem .sotype = SOCK_STREAM, 739191783Srmacklem .proto = 0, 740191783Srmacklem .fh = NULL, 741191783Srmacklem .fhsize = 0, 742220739Srmacklem .flags = NFSMNT_RESVPORT, 743191783Srmacklem .wsize = NFS_WSIZE, 744191783Srmacklem .rsize = NFS_RSIZE, 745191783Srmacklem .readdirsize = NFS_READDIRSIZE, 746191783Srmacklem .timeo = 10, 747191783Srmacklem .retrans = NFS_RETRANS, 748191783Srmacklem .readahead = NFS_DEFRAHEAD, 749191783Srmacklem .wcommitsize = 0, /* was: NQ_DEFLEASE */ 750191783Srmacklem .hostname = NULL, 751191783Srmacklem .acregmin = NFS_MINATTRTIMO, 752191783Srmacklem .acregmax = NFS_MAXATTRTIMO, 753191783Srmacklem .acdirmin = NFS_MINDIRATTRTIMO, 754191783Srmacklem .acdirmax = NFS_MAXDIRATTRTIMO, 755191783Srmacklem }; 756192585Srmacklem int error = 0, ret, len; 757192585Srmacklem struct sockaddr *nam = NULL; 758191783Srmacklem struct vnode *vp; 759191990Sattilio struct thread *td; 760191783Srmacklem char hst[MNAMELEN]; 761191783Srmacklem u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100]; 762192585Srmacklem char *opt, *name, *secname; 763203303Srmacklem int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO; 764221190Srmacklem int dirlen, has_nfs_args_opt, krbnamelen, srvkrbnamelen; 765221205Srmacklem size_t hstlen; 766191783Srmacklem 767221190Srmacklem has_nfs_args_opt = 0; 768191783Srmacklem if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) { 769191783Srmacklem error = EINVAL; 770191783Srmacklem goto out; 771191783Srmacklem } 772191783Srmacklem 773191990Sattilio td = curthread; 774191783Srmacklem if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) { 775221040Srmacklem error = nfs_mountroot(mp); 776191783Srmacklem goto out; 777191783Srmacklem } 778191783Srmacklem 779192585Srmacklem nfscl_init(); 780191783Srmacklem 781221190Srmacklem /* 782221190Srmacklem * The old mount_nfs program passed the struct nfs_args 783221190Srmacklem * from userspace to kernel. The new mount_nfs program 784221190Srmacklem * passes string options via nmount() from userspace to kernel 785221190Srmacklem * and we populate the struct nfs_args in the kernel. 786221190Srmacklem */ 787221190Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) { 788221190Srmacklem error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args, 789221190Srmacklem sizeof(args)); 790221190Srmacklem if (error != 0) 791221190Srmacklem goto out; 792221190Srmacklem 793221190Srmacklem if (args.version != NFS_ARGSVERSION) { 794221190Srmacklem error = EPROGMISMATCH; 795221190Srmacklem goto out; 796221190Srmacklem } 797221190Srmacklem has_nfs_args_opt = 1; 798221190Srmacklem } 799221190Srmacklem 800192585Srmacklem /* Handle the new style options. */ 801192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0) 802192585Srmacklem args.flags |= NFSMNT_NOCONN; 803192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0) 804192585Srmacklem args.flags |= NFSMNT_NOCONN; 805192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0) 806192585Srmacklem args.flags |= NFSMNT_NOLOCKD; 807192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0) 808192585Srmacklem args.flags &= ~NFSMNT_NOLOCKD; 809192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0) 810192585Srmacklem args.flags |= NFSMNT_INT; 811192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0) 812192585Srmacklem args.flags |= NFSMNT_RDIRPLUS; 813192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0) 814192585Srmacklem args.flags |= NFSMNT_RESVPORT; 815192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0) 816192585Srmacklem args.flags &= ~NFSMNT_RESVPORT; 817192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0) 818192585Srmacklem args.flags |= NFSMNT_SOFT; 819192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0) 820192585Srmacklem args.flags &= ~NFSMNT_SOFT; 821192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0) 822192585Srmacklem args.sotype = SOCK_DGRAM; 823192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0) 824192585Srmacklem args.sotype = SOCK_DGRAM; 825192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0) 826192585Srmacklem args.sotype = SOCK_STREAM; 827192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0) 828192585Srmacklem args.flags |= NFSMNT_NFSV3; 829192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) { 830192585Srmacklem args.flags |= NFSMNT_NFSV4; 831192585Srmacklem args.sotype = SOCK_STREAM; 832191783Srmacklem } 833192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0) 834192585Srmacklem args.flags |= NFSMNT_ALLGSSNAME; 835221436Sru if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0) 836221436Sru args.flags |= NFSMNT_NOCTO; 837192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) { 838192585Srmacklem if (opt == NULL) { 839192585Srmacklem vfs_mount_error(mp, "illegal readdirsize"); 840192585Srmacklem error = EINVAL; 841192585Srmacklem goto out; 842192585Srmacklem } 843192585Srmacklem ret = sscanf(opt, "%d", &args.readdirsize); 844192585Srmacklem if (ret != 1 || args.readdirsize <= 0) { 845192585Srmacklem vfs_mount_error(mp, "illegal readdirsize: %s", 846192585Srmacklem opt); 847192585Srmacklem error = EINVAL; 848192585Srmacklem goto out; 849192585Srmacklem } 850192585Srmacklem args.flags |= NFSMNT_READDIRSIZE; 851192585Srmacklem } 852192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) { 853192585Srmacklem if (opt == NULL) { 854192585Srmacklem vfs_mount_error(mp, "illegal readahead"); 855192585Srmacklem error = EINVAL; 856192585Srmacklem goto out; 857192585Srmacklem } 858192585Srmacklem ret = sscanf(opt, "%d", &args.readahead); 859192585Srmacklem if (ret != 1 || args.readahead <= 0) { 860192585Srmacklem vfs_mount_error(mp, "illegal readahead: %s", 861192585Srmacklem opt); 862192585Srmacklem error = EINVAL; 863192585Srmacklem goto out; 864192585Srmacklem } 865192585Srmacklem args.flags |= NFSMNT_READAHEAD; 866192585Srmacklem } 867192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) { 868192585Srmacklem if (opt == NULL) { 869192585Srmacklem vfs_mount_error(mp, "illegal wsize"); 870192585Srmacklem error = EINVAL; 871192585Srmacklem goto out; 872192585Srmacklem } 873192585Srmacklem ret = sscanf(opt, "%d", &args.wsize); 874192585Srmacklem if (ret != 1 || args.wsize <= 0) { 875192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 876192585Srmacklem opt); 877192585Srmacklem error = EINVAL; 878192585Srmacklem goto out; 879192585Srmacklem } 880192585Srmacklem args.flags |= NFSMNT_WSIZE; 881192585Srmacklem } 882192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) { 883192585Srmacklem if (opt == NULL) { 884192585Srmacklem vfs_mount_error(mp, "illegal rsize"); 885192585Srmacklem error = EINVAL; 886192585Srmacklem goto out; 887192585Srmacklem } 888192585Srmacklem ret = sscanf(opt, "%d", &args.rsize); 889192585Srmacklem if (ret != 1 || args.rsize <= 0) { 890192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 891192585Srmacklem opt); 892192585Srmacklem error = EINVAL; 893192585Srmacklem goto out; 894192585Srmacklem } 895192585Srmacklem args.flags |= NFSMNT_RSIZE; 896192585Srmacklem } 897192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) { 898192585Srmacklem if (opt == NULL) { 899192585Srmacklem vfs_mount_error(mp, "illegal retrans"); 900192585Srmacklem error = EINVAL; 901192585Srmacklem goto out; 902192585Srmacklem } 903192585Srmacklem ret = sscanf(opt, "%d", &args.retrans); 904192585Srmacklem if (ret != 1 || args.retrans <= 0) { 905192585Srmacklem vfs_mount_error(mp, "illegal retrans: %s", 906192585Srmacklem opt); 907192585Srmacklem error = EINVAL; 908192585Srmacklem goto out; 909192585Srmacklem } 910192585Srmacklem args.flags |= NFSMNT_RETRANS; 911192585Srmacklem } 912192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) { 913192585Srmacklem ret = sscanf(opt, "%d", &args.acregmin); 914192585Srmacklem if (ret != 1 || args.acregmin < 0) { 915192585Srmacklem vfs_mount_error(mp, "illegal acregmin: %s", 916192585Srmacklem opt); 917192585Srmacklem error = EINVAL; 918192585Srmacklem goto out; 919192585Srmacklem } 920192585Srmacklem args.flags |= NFSMNT_ACREGMIN; 921192585Srmacklem } 922192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) { 923192585Srmacklem ret = sscanf(opt, "%d", &args.acregmax); 924192585Srmacklem if (ret != 1 || args.acregmax < 0) { 925192585Srmacklem vfs_mount_error(mp, "illegal acregmax: %s", 926192585Srmacklem opt); 927192585Srmacklem error = EINVAL; 928192585Srmacklem goto out; 929192585Srmacklem } 930192585Srmacklem args.flags |= NFSMNT_ACREGMAX; 931192585Srmacklem } 932192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) { 933192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmin); 934192585Srmacklem if (ret != 1 || args.acdirmin < 0) { 935192585Srmacklem vfs_mount_error(mp, "illegal acdirmin: %s", 936192585Srmacklem opt); 937192585Srmacklem error = EINVAL; 938192585Srmacklem goto out; 939192585Srmacklem } 940192585Srmacklem args.flags |= NFSMNT_ACDIRMIN; 941192585Srmacklem } 942192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) { 943192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmax); 944192585Srmacklem if (ret != 1 || args.acdirmax < 0) { 945192585Srmacklem vfs_mount_error(mp, "illegal acdirmax: %s", 946192585Srmacklem opt); 947192585Srmacklem error = EINVAL; 948192585Srmacklem goto out; 949192585Srmacklem } 950192585Srmacklem args.flags |= NFSMNT_ACDIRMAX; 951192585Srmacklem } 952229604Sjhb if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) { 953229604Sjhb ret = sscanf(opt, "%d", &args.wcommitsize); 954229604Sjhb if (ret != 1 || args.wcommitsize < 0) { 955229604Sjhb vfs_mount_error(mp, "illegal wcommitsize: %s", opt); 956229604Sjhb error = EINVAL; 957229604Sjhb goto out; 958229604Sjhb } 959229604Sjhb args.flags |= NFSMNT_WCOMMITSIZE; 960229604Sjhb } 961192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) { 962192585Srmacklem ret = sscanf(opt, "%d", &args.timeo); 963192585Srmacklem if (ret != 1 || args.timeo <= 0) { 964192585Srmacklem vfs_mount_error(mp, "illegal timeout: %s", 965192585Srmacklem opt); 966192585Srmacklem error = EINVAL; 967192585Srmacklem goto out; 968192585Srmacklem } 969192585Srmacklem args.flags |= NFSMNT_TIMEO; 970192585Srmacklem } 971203303Srmacklem if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL) 972203303Srmacklem == 0) { 973203303Srmacklem ret = sscanf(opt, "%d", &negnametimeo); 974203303Srmacklem if (ret != 1 || negnametimeo < 0) { 975203303Srmacklem vfs_mount_error(mp, "illegal negnametimeo: %s", 976203303Srmacklem opt); 977203303Srmacklem error = EINVAL; 978203303Srmacklem goto out; 979203303Srmacklem } 980203303Srmacklem } 981192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "sec", 982192585Srmacklem (void **) &secname, NULL) == 0) 983192585Srmacklem nfs_sec_name(secname, &args.flags); 984191783Srmacklem 985191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 986191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 987191783Srmacklem 988191783Srmacklem if (nmp == NULL) { 989191783Srmacklem error = EIO; 990191783Srmacklem goto out; 991191783Srmacklem } 992231636Srmacklem 993191783Srmacklem /* 994231636Srmacklem * If a change from TCP->UDP is done and there are thread(s) 995231636Srmacklem * that have I/O RPC(s) in progress with a tranfer size 996231636Srmacklem * greater than NFS_MAXDGRAMDATA, those thread(s) will be 997231636Srmacklem * hung, retrying the RPC(s) forever. Usually these threads 998231636Srmacklem * will be seen doing an uninterruptible sleep on wait channel 999231636Srmacklem * "newnfsreq" (truncated to "newnfsre" by procstat). 1000231636Srmacklem */ 1001231636Srmacklem if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM) 1002231636Srmacklem tprintf(td->td_proc, LOG_WARNING, 1003231636Srmacklem "Warning: mount -u that changes TCP->UDP can result in hung threads\n"); 1004231636Srmacklem 1005231636Srmacklem /* 1006191783Srmacklem * When doing an update, we can't change version, 1007191783Srmacklem * security, switch lockd strategies or change cookie 1008191783Srmacklem * translation 1009191783Srmacklem */ 1010191783Srmacklem args.flags = (args.flags & 1011191783Srmacklem ~(NFSMNT_NFSV3 | 1012191783Srmacklem NFSMNT_NFSV4 | 1013191783Srmacklem NFSMNT_KERB | 1014191783Srmacklem NFSMNT_INTEGRITY | 1015191783Srmacklem NFSMNT_PRIVACY | 1016191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) | 1017191783Srmacklem (nmp->nm_flag & 1018191783Srmacklem (NFSMNT_NFSV3 | 1019191783Srmacklem NFSMNT_NFSV4 | 1020191783Srmacklem NFSMNT_KERB | 1021191783Srmacklem NFSMNT_INTEGRITY | 1022191783Srmacklem NFSMNT_PRIVACY | 1023191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); 1024214048Srmacklem nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td); 1025191783Srmacklem goto out; 1026191783Srmacklem } 1027191783Srmacklem 1028191783Srmacklem /* 1029191783Srmacklem * Make the nfs_ip_paranoia sysctl serve as the default connection 1030191783Srmacklem * or no-connection mode for those protocols that support 1031191783Srmacklem * no-connection mode (the flag will be cleared later for protocols 1032191783Srmacklem * that do not support no-connection mode). This will allow a client 1033191783Srmacklem * to receive replies from a different IP then the request was 1034191783Srmacklem * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid), 1035191783Srmacklem * not 0. 1036191783Srmacklem */ 1037191783Srmacklem if (nfs_ip_paranoia == 0) 1038191783Srmacklem args.flags |= NFSMNT_NOCONN; 1039192585Srmacklem 1040221190Srmacklem if (has_nfs_args_opt != 0) { 1041221190Srmacklem /* 1042221190Srmacklem * In the 'nfs_args' case, the pointers in the args 1043221190Srmacklem * structure are in userland - we copy them in here. 1044221190Srmacklem */ 1045221190Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) { 1046192585Srmacklem vfs_mount_error(mp, "Bad file handle"); 1047191783Srmacklem error = EINVAL; 1048191783Srmacklem goto out; 1049191783Srmacklem } 1050221190Srmacklem error = copyin((caddr_t)args.fh, (caddr_t)nfh, 1051221190Srmacklem args.fhsize); 1052221190Srmacklem if (error != 0) 1053221190Srmacklem goto out; 1054221205Srmacklem error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen); 1055221190Srmacklem if (error != 0) 1056221190Srmacklem goto out; 1057221205Srmacklem bzero(&hst[hstlen], MNAMELEN - hstlen); 1058221190Srmacklem args.hostname = hst; 1059221190Srmacklem /* sockargs() call must be after above copyin() calls */ 1060221190Srmacklem error = getsockaddr(&nam, (caddr_t)args.addr, 1061221190Srmacklem args.addrlen); 1062221190Srmacklem if (error != 0) 1063221190Srmacklem goto out; 1064191783Srmacklem } else { 1065221190Srmacklem if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh, 1066221190Srmacklem &args.fhsize) == 0) { 1067221190Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) { 1068221190Srmacklem vfs_mount_error(mp, "Bad file handle"); 1069221190Srmacklem error = EINVAL; 1070221190Srmacklem goto out; 1071221190Srmacklem } 1072221190Srmacklem bcopy(args.fh, nfh, args.fhsize); 1073221190Srmacklem } else { 1074221190Srmacklem args.fhsize = 0; 1075221190Srmacklem } 1076221190Srmacklem (void) vfs_getopt(mp->mnt_optnew, "hostname", 1077221190Srmacklem (void **)&args.hostname, &len); 1078221190Srmacklem if (args.hostname == NULL) { 1079221190Srmacklem vfs_mount_error(mp, "Invalid hostname"); 1080221190Srmacklem error = EINVAL; 1081221190Srmacklem goto out; 1082221190Srmacklem } 1083221190Srmacklem bcopy(args.hostname, hst, MNAMELEN); 1084221190Srmacklem hst[MNAMELEN - 1] = '\0'; 1085192585Srmacklem } 1086192585Srmacklem 1087192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0) 1088192585Srmacklem strlcpy(srvkrbname, name, sizeof (srvkrbname)); 1089192585Srmacklem else 1090192585Srmacklem snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst); 1091221014Srmacklem srvkrbnamelen = strlen(srvkrbname); 1092192585Srmacklem 1093192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0) 1094192585Srmacklem strlcpy(krbname, name, sizeof (krbname)); 1095192585Srmacklem else 1096191783Srmacklem krbname[0] = '\0'; 1097221014Srmacklem krbnamelen = strlen(krbname); 1098192585Srmacklem 1099192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0) 1100192585Srmacklem strlcpy(dirpath, name, sizeof (dirpath)); 1101192585Srmacklem else 1102191783Srmacklem dirpath[0] = '\0'; 1103221014Srmacklem dirlen = strlen(dirpath); 1104192585Srmacklem 1105222075Srmacklem if (has_nfs_args_opt == 0) { 1106222075Srmacklem if (vfs_getopt(mp->mnt_optnew, "addr", 1107222075Srmacklem (void **)&args.addr, &args.addrlen) == 0) { 1108222075Srmacklem if (args.addrlen > SOCK_MAXADDRLEN) { 1109222075Srmacklem error = ENAMETOOLONG; 1110222075Srmacklem goto out; 1111222075Srmacklem } 1112222075Srmacklem nam = malloc(args.addrlen, M_SONAME, M_WAITOK); 1113222075Srmacklem bcopy(args.addr, nam, args.addrlen); 1114222075Srmacklem nam->sa_len = args.addrlen; 1115222075Srmacklem } else { 1116222075Srmacklem vfs_mount_error(mp, "No server address"); 1117222075Srmacklem error = EINVAL; 1118191783Srmacklem goto out; 1119191783Srmacklem } 1120191783Srmacklem } 1121192585Srmacklem 1122191783Srmacklem args.fh = nfh; 1123221014Srmacklem error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath, 1124221014Srmacklem dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td, 1125221014Srmacklem negnametimeo); 1126191783Srmacklemout: 1127191783Srmacklem if (!error) { 1128191783Srmacklem MNT_ILOCK(mp); 1129191783Srmacklem mp->mnt_kern_flag |= (MNTK_MPSAFE|MNTK_LOOKUP_SHARED); 1130191783Srmacklem MNT_IUNLOCK(mp); 1131191783Srmacklem } 1132191783Srmacklem return (error); 1133191783Srmacklem} 1134191783Srmacklem 1135191783Srmacklem 1136191783Srmacklem/* 1137191783Srmacklem * VFS Operations. 1138191783Srmacklem * 1139191783Srmacklem * mount system call 1140191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 1141191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 1142191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 1143191783Srmacklem * an error after that means that I have to release the mbuf. 1144191783Srmacklem */ 1145191783Srmacklem/* ARGSUSED */ 1146191783Srmacklemstatic int 1147230725Smckusicknfs_cmount(struct mntarg *ma, void *data, uint64_t flags) 1148191783Srmacklem{ 1149191783Srmacklem int error; 1150191783Srmacklem struct nfs_args args; 1151191783Srmacklem 1152191783Srmacklem error = copyin(data, &args, sizeof (struct nfs_args)); 1153191783Srmacklem if (error) 1154191783Srmacklem return error; 1155191783Srmacklem 1156191783Srmacklem ma = mount_arg(ma, "nfs_args", &args, sizeof args); 1157191783Srmacklem 1158191783Srmacklem error = kernel_mount(ma, flags); 1159191783Srmacklem return (error); 1160191783Srmacklem} 1161191783Srmacklem 1162191783Srmacklem/* 1163191783Srmacklem * Common code for mount and mountroot 1164191783Srmacklem */ 1165191783Srmacklemstatic int 1166191783Srmacklemmountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, 1167221014Srmacklem char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen, 1168221014Srmacklem u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp, 1169221014Srmacklem struct ucred *cred, struct thread *td, int negnametimeo) 1170191783Srmacklem{ 1171191783Srmacklem struct nfsmount *nmp; 1172191783Srmacklem struct nfsnode *np; 1173195762Srmacklem int error, trycnt, ret; 1174191783Srmacklem struct nfsvattr nfsva; 1175191783Srmacklem static u_int64_t clval = 0; 1176191783Srmacklem 1177191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 1178191783Srmacklem nmp = VFSTONFS(mp); 1179191783Srmacklem printf("%s: MNT_UPDATE is no longer handled here\n", __func__); 1180191783Srmacklem FREE(nam, M_SONAME); 1181191783Srmacklem return (0); 1182191783Srmacklem } else { 1183191783Srmacklem MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) + 1184221014Srmacklem krbnamelen + dirlen + srvkrbnamelen + 2, 1185221014Srmacklem M_NEWNFSMNT, M_WAITOK | M_ZERO); 1186191783Srmacklem TAILQ_INIT(&nmp->nm_bufq); 1187191783Srmacklem if (clval == 0) 1188191783Srmacklem clval = (u_int64_t)nfsboottime.tv_sec; 1189191783Srmacklem nmp->nm_clval = clval++; 1190221014Srmacklem nmp->nm_krbnamelen = krbnamelen; 1191221014Srmacklem nmp->nm_dirpathlen = dirlen; 1192221014Srmacklem nmp->nm_srvkrbnamelen = srvkrbnamelen; 1193192675Srmacklem if (td->td_ucred->cr_uid != (uid_t)0) { 1194191783Srmacklem /* 1195192675Srmacklem * nm_uid is used to get KerberosV credentials for 1196192675Srmacklem * the nfsv4 state handling operations if there is 1197192675Srmacklem * no host based principal set. Use the uid of 1198192675Srmacklem * this user if not root, since they are doing the 1199192675Srmacklem * mount. I don't think setting this for root will 1200192675Srmacklem * work, since root normally does not have user 1201192675Srmacklem * credentials in a credentials cache. 1202191783Srmacklem */ 1203192675Srmacklem nmp->nm_uid = td->td_ucred->cr_uid; 1204191783Srmacklem } else { 1205191783Srmacklem /* 1206192675Srmacklem * Just set to -1, so it won't be used. 1207191783Srmacklem */ 1208191783Srmacklem nmp->nm_uid = (uid_t)-1; 1209191783Srmacklem } 1210191783Srmacklem 1211191783Srmacklem /* Copy and null terminate all the names */ 1212191783Srmacklem if (nmp->nm_krbnamelen > 0) { 1213191783Srmacklem bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen); 1214191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen] = '\0'; 1215191783Srmacklem } 1216191783Srmacklem if (nmp->nm_dirpathlen > 0) { 1217191783Srmacklem bcopy(dirpath, NFSMNT_DIRPATH(nmp), 1218191783Srmacklem nmp->nm_dirpathlen); 1219191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1220191783Srmacklem + 1] = '\0'; 1221191783Srmacklem } 1222191783Srmacklem if (nmp->nm_srvkrbnamelen > 0) { 1223191783Srmacklem bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp), 1224191783Srmacklem nmp->nm_srvkrbnamelen); 1225191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1226191783Srmacklem + nmp->nm_srvkrbnamelen + 2] = '\0'; 1227191783Srmacklem } 1228191783Srmacklem nmp->nm_sockreq.nr_cred = crhold(cred); 1229191783Srmacklem mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF); 1230191783Srmacklem mp->mnt_data = nmp; 1231214048Srmacklem nmp->nm_getinfo = nfs_getnlminfo; 1232216931Srmacklem nmp->nm_vinvalbuf = ncl_vinvalbuf; 1233191783Srmacklem } 1234191783Srmacklem vfs_getnewfsid(mp); 1235191783Srmacklem nmp->nm_mountp = mp; 1236191783Srmacklem mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK); 1237229172Srmacklem 1238229172Srmacklem /* 1239229172Srmacklem * Since nfs_decode_args() might optionally set them, these need to 1240229172Srmacklem * set to defaults before the call, so that the optional settings 1241229172Srmacklem * aren't overwritten. 1242229172Srmacklem */ 1243203303Srmacklem nmp->nm_negnametimeo = negnametimeo; 1244229172Srmacklem nmp->nm_timeo = NFS_TIMEO; 1245229172Srmacklem nmp->nm_retry = NFS_RETRANS; 1246229172Srmacklem nmp->nm_readahead = NFS_DEFRAHEAD; 1247229263Srmacklem if (desiredvnodes >= 11000) 1248229263Srmacklem nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000); 1249229263Srmacklem else 1250229263Srmacklem nmp->nm_wcommitsize = hibufspace / 10; 1251191783Srmacklem 1252214048Srmacklem nfs_decode_args(mp, nmp, argp, hst, cred, td); 1253192585Srmacklem 1254191783Srmacklem /* 1255191783Srmacklem * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too 1256191783Srmacklem * high, depending on whether we end up with negative offsets in 1257191783Srmacklem * the client or server somewhere. 2GB-1 may be safer. 1258191783Srmacklem * 1259191783Srmacklem * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum 1260191783Srmacklem * that we can handle until we find out otherwise. 1261191783Srmacklem * XXX Our "safe" limit on the client is what we can store in our 1262191783Srmacklem * buffer cache using signed(!) block numbers. 1263191783Srmacklem */ 1264191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) 1265191783Srmacklem nmp->nm_maxfilesize = 0xffffffffLL; 1266191783Srmacklem else 1267221537Srmacklem nmp->nm_maxfilesize = OFF_MAX; 1268191783Srmacklem 1269191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 1270191783Srmacklem nmp->nm_wsize = NFS_WSIZE; 1271191783Srmacklem nmp->nm_rsize = NFS_RSIZE; 1272191783Srmacklem nmp->nm_readdirsize = NFS_READDIRSIZE; 1273191783Srmacklem } 1274191783Srmacklem nmp->nm_numgrps = NFS_MAXGRPS; 1275191783Srmacklem nmp->nm_tprintf_delay = nfs_tprintf_delay; 1276191783Srmacklem if (nmp->nm_tprintf_delay < 0) 1277191783Srmacklem nmp->nm_tprintf_delay = 0; 1278191783Srmacklem nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay; 1279191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1280191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1281191783Srmacklem nmp->nm_fhsize = argp->fhsize; 1282191783Srmacklem if (nmp->nm_fhsize > 0) 1283191783Srmacklem bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 1284191783Srmacklem bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 1285191783Srmacklem nmp->nm_nam = nam; 1286191783Srmacklem /* Set up the sockets and per-host congestion */ 1287191783Srmacklem nmp->nm_sotype = argp->sotype; 1288191783Srmacklem nmp->nm_soproto = argp->proto; 1289191783Srmacklem nmp->nm_sockreq.nr_prog = NFS_PROG; 1290191783Srmacklem if ((argp->flags & NFSMNT_NFSV4)) 1291191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER4; 1292191783Srmacklem else if ((argp->flags & NFSMNT_NFSV3)) 1293191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER3; 1294191783Srmacklem else 1295191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER2; 1296191783Srmacklem 1297191783Srmacklem 1298191783Srmacklem if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0))) 1299191783Srmacklem goto bad; 1300191783Srmacklem 1301191783Srmacklem /* 1302191783Srmacklem * A reference count is needed on the nfsnode representing the 1303191783Srmacklem * remote root. If this object is not persistent, then backward 1304191783Srmacklem * traversals of the mount point (i.e. "..") will not work if 1305191783Srmacklem * the nfsnode gets flushed out of the cache. Ufs does not have 1306191783Srmacklem * this problem, because one can identify root inodes by their 1307191783Srmacklem * number == ROOTINO (2). 1308191783Srmacklem */ 1309191783Srmacklem if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) && 1310191783Srmacklem nmp->nm_dirpathlen > 0) { 1311191783Srmacklem /* 1312191783Srmacklem * If the fhsize on the mount point == 0 for V4, the mount 1313191783Srmacklem * path needs to be looked up. 1314191783Srmacklem */ 1315191783Srmacklem trycnt = 3; 1316191783Srmacklem do { 1317191783Srmacklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 1318191783Srmacklem cred, td); 1319191783Srmacklem if (error) 1320207170Srmacklem (void) nfs_catnap(PZERO, error, "nfsgetdirp"); 1321191783Srmacklem } while (error && --trycnt > 0); 1322191783Srmacklem if (error) { 1323191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1324191783Srmacklem goto bad; 1325191783Srmacklem } 1326191783Srmacklem } 1327191783Srmacklem if (nmp->nm_fhsize > 0) { 1328195762Srmacklem /* 1329195762Srmacklem * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set 1330195762Srmacklem * non-zero for the root vnode. f_iosize will be set correctly 1331195762Srmacklem * by nfs_statfs() before any I/O occurs. 1332195762Srmacklem */ 1333195762Srmacklem mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ; 1334220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, 1335220732Srmacklem LK_EXCLUSIVE); 1336191783Srmacklem if (error) 1337191783Srmacklem goto bad; 1338191783Srmacklem *vpp = NFSTOV(np); 1339191783Srmacklem 1340191783Srmacklem /* 1341191783Srmacklem * Get file attributes and transfer parameters for the 1342191783Srmacklem * mountpoint. This has the side effect of filling in 1343191783Srmacklem * (*vpp)->v_type with the correct value. 1344191783Srmacklem */ 1345191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 1346191783Srmacklem cred, td, &nfsva, NULL); 1347191783Srmacklem if (ret) { 1348191783Srmacklem /* 1349191783Srmacklem * Just set default values to get things going. 1350191783Srmacklem */ 1351191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 1352191783Srmacklem nfsva.na_vattr.va_type = VDIR; 1353191783Srmacklem nfsva.na_vattr.va_mode = 0777; 1354191783Srmacklem nfsva.na_vattr.va_nlink = 100; 1355191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 1356191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 1357191783Srmacklem nfsva.na_vattr.va_fileid = 2; 1358191783Srmacklem nfsva.na_vattr.va_gen = 1; 1359191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 1360191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 1361191783Srmacklem } 1362191783Srmacklem (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1); 1363191783Srmacklem if (argp->flags & NFSMNT_NFSV3) 1364191783Srmacklem ncl_fsinfo(nmp, *vpp, cred, td); 1365191783Srmacklem 1366222233Srmacklem /* Mark if the mount point supports NFSv4 ACLs. */ 1367222233Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 && 1368222233Srmacklem ret == 0 && 1369222233Srmacklem NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) { 1370222233Srmacklem MNT_ILOCK(mp); 1371222233Srmacklem mp->mnt_flag |= MNT_NFS4ACLS; 1372222233Srmacklem MNT_IUNLOCK(mp); 1373222233Srmacklem } 1374222233Srmacklem 1375191783Srmacklem /* 1376191783Srmacklem * Lose the lock but keep the ref. 1377191783Srmacklem */ 1378224082Szack NFSVOPUNLOCK(*vpp, 0); 1379191783Srmacklem return (0); 1380191783Srmacklem } 1381191783Srmacklem error = EIO; 1382191783Srmacklem 1383191783Srmacklembad: 1384191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1385191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1386191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1387191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1388191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1389191783Srmacklem FREE(nam, M_SONAME); 1390191783Srmacklem return (error); 1391191783Srmacklem} 1392191783Srmacklem 1393191783Srmacklem/* 1394191783Srmacklem * unmount system call 1395191783Srmacklem */ 1396191783Srmacklemstatic int 1397191990Sattilionfs_unmount(struct mount *mp, int mntflags) 1398191783Srmacklem{ 1399191990Sattilio struct thread *td; 1400191783Srmacklem struct nfsmount *nmp; 1401191783Srmacklem int error, flags = 0, trycnt = 0; 1402191783Srmacklem 1403191990Sattilio td = curthread; 1404191990Sattilio 1405191783Srmacklem if (mntflags & MNT_FORCE) 1406191783Srmacklem flags |= FORCECLOSE; 1407191783Srmacklem nmp = VFSTONFS(mp); 1408191783Srmacklem /* 1409191783Srmacklem * Goes something like this.. 1410191783Srmacklem * - Call vflush() to clear out vnodes for this filesystem 1411191783Srmacklem * - Close the socket 1412191783Srmacklem * - Free up the data structures 1413191783Srmacklem */ 1414191783Srmacklem /* In the forced case, cancel any outstanding requests. */ 1415191783Srmacklem if (mntflags & MNT_FORCE) { 1416191783Srmacklem error = newnfs_nmcancelreqs(nmp); 1417191783Srmacklem if (error) 1418191783Srmacklem goto out; 1419191783Srmacklem /* For a forced close, get rid of the renew thread now */ 1420191783Srmacklem nfscl_umount(nmp, td); 1421191783Srmacklem } 1422191783Srmacklem /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ 1423191783Srmacklem do { 1424191783Srmacklem error = vflush(mp, 1, flags, td); 1425191783Srmacklem if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30) 1426207170Srmacklem (void) nfs_catnap(PSOCK, error, "newndm"); 1427191783Srmacklem } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30); 1428191783Srmacklem if (error) 1429191783Srmacklem goto out; 1430191783Srmacklem 1431191783Srmacklem /* 1432191783Srmacklem * We are now committed to the unmount. 1433191783Srmacklem */ 1434191783Srmacklem if ((mntflags & MNT_FORCE) == 0) 1435191783Srmacklem nfscl_umount(nmp, td); 1436191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1437191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1438191783Srmacklem FREE(nmp->nm_nam, M_SONAME); 1439191783Srmacklem 1440191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1441191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1442191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1443191783Srmacklemout: 1444191783Srmacklem return (error); 1445191783Srmacklem} 1446191783Srmacklem 1447191783Srmacklem/* 1448191783Srmacklem * Return root of a filesystem 1449191783Srmacklem */ 1450191783Srmacklemstatic int 1451191990Sattilionfs_root(struct mount *mp, int flags, struct vnode **vpp) 1452191783Srmacklem{ 1453191783Srmacklem struct vnode *vp; 1454191783Srmacklem struct nfsmount *nmp; 1455191783Srmacklem struct nfsnode *np; 1456191783Srmacklem int error; 1457191783Srmacklem 1458191783Srmacklem nmp = VFSTONFS(mp); 1459220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags); 1460191783Srmacklem if (error) 1461191783Srmacklem return error; 1462191783Srmacklem vp = NFSTOV(np); 1463191783Srmacklem /* 1464191783Srmacklem * Get transfer parameters and attributes for root vnode once. 1465191783Srmacklem */ 1466191783Srmacklem mtx_lock(&nmp->nm_mtx); 1467191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 1468191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1469191783Srmacklem ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread); 1470191783Srmacklem } else 1471191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1472191783Srmacklem if (vp->v_type == VNON) 1473191783Srmacklem vp->v_type = VDIR; 1474191783Srmacklem vp->v_vflag |= VV_ROOT; 1475191783Srmacklem *vpp = vp; 1476191783Srmacklem return (0); 1477191783Srmacklem} 1478191783Srmacklem 1479191783Srmacklem/* 1480191783Srmacklem * Flush out the buffer cache 1481191783Srmacklem */ 1482191783Srmacklem/* ARGSUSED */ 1483191783Srmacklemstatic int 1484191990Sattilionfs_sync(struct mount *mp, int waitfor) 1485191783Srmacklem{ 1486191783Srmacklem struct vnode *vp, *mvp; 1487191990Sattilio struct thread *td; 1488191783Srmacklem int error, allerror = 0; 1489191783Srmacklem 1490191990Sattilio td = curthread; 1491191990Sattilio 1492222329Srmacklem MNT_ILOCK(mp); 1493191783Srmacklem /* 1494222329Srmacklem * If a forced dismount is in progress, return from here so that 1495222329Srmacklem * the umount(2) syscall doesn't get stuck in VFS_SYNC() before 1496222329Srmacklem * calling VFS_UNMOUNT(). 1497222329Srmacklem */ 1498222329Srmacklem if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1499222329Srmacklem MNT_IUNLOCK(mp); 1500222329Srmacklem return (EBADF); 1501222329Srmacklem } 1502222329Srmacklem 1503222329Srmacklem /* 1504191783Srmacklem * Force stale buffer cache information to be flushed. 1505191783Srmacklem */ 1506191783Srmacklemloop: 1507191783Srmacklem MNT_VNODE_FOREACH(vp, mp, mvp) { 1508191783Srmacklem VI_LOCK(vp); 1509191783Srmacklem MNT_IUNLOCK(mp); 1510191783Srmacklem /* XXX Racy bv_cnt check. */ 1511224083Szack if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1512191783Srmacklem waitfor == MNT_LAZY) { 1513191783Srmacklem VI_UNLOCK(vp); 1514191783Srmacklem MNT_ILOCK(mp); 1515191783Srmacklem continue; 1516191783Srmacklem } 1517191783Srmacklem if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 1518191783Srmacklem MNT_ILOCK(mp); 1519191783Srmacklem MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); 1520191783Srmacklem goto loop; 1521191783Srmacklem } 1522191783Srmacklem error = VOP_FSYNC(vp, waitfor, td); 1523191783Srmacklem if (error) 1524191783Srmacklem allerror = error; 1525224082Szack NFSVOPUNLOCK(vp, 0); 1526191783Srmacklem vrele(vp); 1527191783Srmacklem 1528191783Srmacklem MNT_ILOCK(mp); 1529191783Srmacklem } 1530191783Srmacklem MNT_IUNLOCK(mp); 1531191783Srmacklem return (allerror); 1532191783Srmacklem} 1533191783Srmacklem 1534191783Srmacklemstatic int 1535191783Srmacklemnfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 1536191783Srmacklem{ 1537191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1538191783Srmacklem struct vfsquery vq; 1539191783Srmacklem int error; 1540191783Srmacklem 1541191783Srmacklem bzero(&vq, sizeof(vq)); 1542191783Srmacklem switch (op) { 1543191783Srmacklem#if 0 1544191783Srmacklem case VFS_CTL_NOLOCKS: 1545191783Srmacklem val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; 1546191783Srmacklem if (req->oldptr != NULL) { 1547191783Srmacklem error = SYSCTL_OUT(req, &val, sizeof(val)); 1548191783Srmacklem if (error) 1549191783Srmacklem return (error); 1550191783Srmacklem } 1551191783Srmacklem if (req->newptr != NULL) { 1552191783Srmacklem error = SYSCTL_IN(req, &val, sizeof(val)); 1553191783Srmacklem if (error) 1554191783Srmacklem return (error); 1555191783Srmacklem if (val) 1556191783Srmacklem nmp->nm_flag |= NFSMNT_NOLOCKS; 1557191783Srmacklem else 1558191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOLOCKS; 1559191783Srmacklem } 1560191783Srmacklem break; 1561191783Srmacklem#endif 1562191783Srmacklem case VFS_CTL_QUERY: 1563191783Srmacklem mtx_lock(&nmp->nm_mtx); 1564191783Srmacklem if (nmp->nm_state & NFSSTA_TIMEO) 1565191783Srmacklem vq.vq_flags |= VQ_NOTRESP; 1566191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1567191783Srmacklem#if 0 1568191783Srmacklem if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && 1569191783Srmacklem (nmp->nm_state & NFSSTA_LOCKTIMEO)) 1570191783Srmacklem vq.vq_flags |= VQ_NOTRESPLOCK; 1571191783Srmacklem#endif 1572191783Srmacklem error = SYSCTL_OUT(req, &vq, sizeof(vq)); 1573191783Srmacklem break; 1574191783Srmacklem case VFS_CTL_TIMEO: 1575191783Srmacklem if (req->oldptr != NULL) { 1576191783Srmacklem error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, 1577191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1578191783Srmacklem if (error) 1579191783Srmacklem return (error); 1580191783Srmacklem } 1581191783Srmacklem if (req->newptr != NULL) { 1582191783Srmacklem error = vfs_suser(mp, req->td); 1583191783Srmacklem if (error) 1584191783Srmacklem return (error); 1585191783Srmacklem error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, 1586191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1587191783Srmacklem if (error) 1588191783Srmacklem return (error); 1589191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1590191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1591191783Srmacklem } 1592191783Srmacklem break; 1593191783Srmacklem default: 1594191783Srmacklem return (ENOTSUP); 1595191783Srmacklem } 1596191783Srmacklem return (0); 1597191783Srmacklem} 1598191783Srmacklem 1599214048Srmacklem/* 1600214048Srmacklem * Extract the information needed by the nlm from the nfs vnode. 1601214048Srmacklem */ 1602214048Srmacklemstatic void 1603214053Srmacklemnfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp, 1604216931Srmacklem struct sockaddr_storage *sp, int *is_v3p, off_t *sizep, 1605216931Srmacklem struct timeval *timeop) 1606214048Srmacklem{ 1607214048Srmacklem struct nfsmount *nmp; 1608214048Srmacklem struct nfsnode *np = VTONFS(vp); 1609214048Srmacklem 1610214048Srmacklem nmp = VFSTONFS(vp->v_mount); 1611214048Srmacklem if (fhlenp != NULL) 1612214053Srmacklem *fhlenp = (size_t)np->n_fhp->nfh_len; 1613214048Srmacklem if (fhp != NULL) 1614214048Srmacklem bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len); 1615214048Srmacklem if (sp != NULL) 1616214048Srmacklem bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp))); 1617214048Srmacklem if (is_v3p != NULL) 1618214048Srmacklem *is_v3p = NFS_ISV3(vp); 1619214048Srmacklem if (sizep != NULL) 1620214048Srmacklem *sizep = np->n_size; 1621216931Srmacklem if (timeop != NULL) { 1622216931Srmacklem timeop->tv_sec = nmp->nm_timeo / NFS_HZ; 1623216931Srmacklem timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ); 1624216931Srmacklem } 1625214048Srmacklem} 1626214048Srmacklem 1627