nfs_clvfsops.c revision 191990
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: head/sys/fs/nfsclient/nfs_clvfsops.c 191990 2009-05-11 15:33:26Z attilio $"); 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> 48191783Srmacklem#include <sys/lock.h> 49191783Srmacklem#include <sys/malloc.h> 50191783Srmacklem#include <sys/mbuf.h> 51191783Srmacklem#include <sys/module.h> 52191783Srmacklem#include <sys/mount.h> 53191783Srmacklem#include <sys/proc.h> 54191783Srmacklem#include <sys/socket.h> 55191783Srmacklem#include <sys/socketvar.h> 56191783Srmacklem#include <sys/sockio.h> 57191783Srmacklem#include <sys/sysctl.h> 58191783Srmacklem#include <sys/vnode.h> 59191783Srmacklem#include <sys/signalvar.h> 60191783Srmacklem 61191783Srmacklem#include <vm/vm.h> 62191783Srmacklem#include <vm/vm_extern.h> 63191783Srmacklem#include <vm/uma.h> 64191783Srmacklem 65191783Srmacklem#include <net/if.h> 66191783Srmacklem#include <net/route.h> 67191783Srmacklem#include <netinet/in.h> 68191783Srmacklem 69191783Srmacklem#include <fs/nfs/nfsport.h> 70191783Srmacklem#include <fs/nfsclient/nfsnode.h> 71191783Srmacklem#include <fs/nfsclient/nfsmount.h> 72191783Srmacklem#include <fs/nfsclient/nfs.h> 73191783Srmacklem#include <fs/nfsclient/nfsdiskless.h> 74191783Srmacklem 75191783Srmacklemextern int nfscl_ticks; 76191783Srmacklemextern struct timeval nfsboottime; 77191783Srmacklemextern struct nfsstats newnfsstats; 78191783Srmacklem 79191783SrmacklemMALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header"); 80191783SrmacklemMALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct"); 81191783Srmacklem 82191783SrmacklemSYSCTL_DECL(_vfs_newnfs); 83191783SrmacklemSYSCTL_STRUCT(_vfs_newnfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RW, 84191783Srmacklem &newnfsstats, nfsstats, "S,nfsstats"); 85191783Srmacklemstatic int nfs_ip_paranoia = 1; 86191783SrmacklemSYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW, 87191783Srmacklem &nfs_ip_paranoia, 0, ""); 88191783Srmacklemstatic int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY; 89191783SrmacklemSYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_INITIAL_DELAY, 90191783Srmacklem downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, ""); 91191783Srmacklem/* how long between console messages "nfs server foo not responding" */ 92191783Srmacklemstatic int nfs_tprintf_delay = NFS_TPRINTF_DELAY; 93191783SrmacklemSYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_DELAY, 94191783Srmacklem downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, ""); 95191783Srmacklem 96191783Srmacklemstatic void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, 97191783Srmacklem struct nfs_args *argp, struct ucred *, struct thread *); 98191783Srmacklemstatic int mountnfs(struct nfs_args *, struct mount *, 99191783Srmacklem struct sockaddr *, char *, u_char *, u_char *, u_char *, 100191783Srmacklem struct vnode **, struct ucred *, struct thread *); 101191783Srmacklemstatic vfs_mount_t nfs_mount; 102191783Srmacklemstatic vfs_cmount_t nfs_cmount; 103191783Srmacklemstatic vfs_unmount_t nfs_unmount; 104191783Srmacklemstatic vfs_root_t nfs_root; 105191783Srmacklemstatic vfs_statfs_t nfs_statfs; 106191783Srmacklemstatic vfs_sync_t nfs_sync; 107191783Srmacklemstatic vfs_sysctl_t nfs_sysctl; 108191783Srmacklem 109191783Srmacklem/* 110191783Srmacklem * nfs vfs operations. 111191783Srmacklem */ 112191783Srmacklemstatic struct vfsops nfs_vfsops = { 113191783Srmacklem .vfs_init = ncl_init, 114191783Srmacklem .vfs_mount = nfs_mount, 115191783Srmacklem .vfs_cmount = nfs_cmount, 116191783Srmacklem .vfs_root = nfs_root, 117191783Srmacklem .vfs_statfs = nfs_statfs, 118191783Srmacklem .vfs_sync = nfs_sync, 119191783Srmacklem .vfs_uninit = ncl_uninit, 120191783Srmacklem .vfs_unmount = nfs_unmount, 121191783Srmacklem .vfs_sysctl = nfs_sysctl, 122191783Srmacklem}; 123191783SrmacklemVFS_SET(nfs_vfsops, newnfs, VFCF_NETWORK); 124191783Srmacklem 125191783Srmacklem/* So that loader and kldload(2) can find us, wherever we are.. */ 126191783SrmacklemMODULE_VERSION(newnfs, 1); 127191783Srmacklem 128191783Srmacklem/* 129191783Srmacklem * This structure must be filled in by a primary bootstrap or bootstrap 130191783Srmacklem * server for a diskless/dataless machine. It is initialized below just 131191783Srmacklem * to ensure that it is allocated to initialized data (.data not .bss). 132191783Srmacklem */ 133191783Srmacklemstruct nfs_diskless newnfs_diskless = { { { 0 } } }; 134191783Srmacklemstruct nfsv3_diskless newnfsv3_diskless = { { { 0 } } }; 135191783Srmacklemint newnfs_diskless_valid = 0; 136191783Srmacklem 137191783SrmacklemSYSCTL_INT(_vfs_newnfs, OID_AUTO, diskless_valid, CTLFLAG_RD, 138191783Srmacklem &newnfs_diskless_valid, 0, ""); 139191783Srmacklem 140191783SrmacklemSYSCTL_STRING(_vfs_newnfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD, 141191783Srmacklem newnfsv3_diskless.root_hostnam, 0, ""); 142191783Srmacklem 143191783SrmacklemSYSCTL_OPAQUE(_vfs_newnfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD, 144191783Srmacklem &newnfsv3_diskless.root_saddr, sizeof newnfsv3_diskless.root_saddr, 145191783Srmacklem "%Ssockaddr_in", ""); 146191783Srmacklem 147191783Srmacklem 148191783Srmacklemvoid newnfsargs_ntoh(struct nfs_args *); 149191783Srmacklemstatic int nfs_mountdiskless(char *, 150191783Srmacklem struct sockaddr_in *, struct nfs_args *, 151191783Srmacklem struct thread *, struct vnode **, struct mount *); 152191783Srmacklemstatic void nfs_convert_diskless(void); 153191783Srmacklemstatic void nfs_convert_oargs(struct nfs_args *args, 154191783Srmacklem struct onfs_args *oargs); 155191783Srmacklem 156191783Srmacklemint 157191783Srmacklemnewnfs_iosize(struct nfsmount *nmp) 158191783Srmacklem{ 159191783Srmacklem int iosize, maxio; 160191783Srmacklem 161191783Srmacklem /* First, set the upper limit for iosize */ 162191783Srmacklem if (nmp->nm_flag & NFSMNT_NFSV4) { 163191783Srmacklem maxio = NFS_MAXBSIZE; 164191783Srmacklem } else if (nmp->nm_flag & NFSMNT_NFSV3) { 165191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 166191783Srmacklem maxio = NFS_MAXDGRAMDATA; 167191783Srmacklem else 168191783Srmacklem maxio = NFS_MAXBSIZE; 169191783Srmacklem } else { 170191783Srmacklem maxio = NFS_V2MAXDATA; 171191783Srmacklem } 172191783Srmacklem if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0) 173191783Srmacklem nmp->nm_rsize = maxio; 174191783Srmacklem if (nmp->nm_rsize > MAXBSIZE) 175191783Srmacklem nmp->nm_rsize = MAXBSIZE; 176191783Srmacklem if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0) 177191783Srmacklem nmp->nm_readdirsize = maxio; 178191783Srmacklem if (nmp->nm_readdirsize > nmp->nm_rsize) 179191783Srmacklem nmp->nm_readdirsize = nmp->nm_rsize; 180191783Srmacklem if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0) 181191783Srmacklem nmp->nm_wsize = maxio; 182191783Srmacklem if (nmp->nm_wsize > MAXBSIZE) 183191783Srmacklem nmp->nm_wsize = MAXBSIZE; 184191783Srmacklem 185191783Srmacklem /* 186191783Srmacklem * Calculate the size used for io buffers. Use the larger 187191783Srmacklem * of the two sizes to minimise nfs requests but make sure 188191783Srmacklem * that it is at least one VM page to avoid wasting buffer 189191783Srmacklem * space. 190191783Srmacklem */ 191191783Srmacklem iosize = imax(nmp->nm_rsize, nmp->nm_wsize); 192191783Srmacklem iosize = imax(iosize, PAGE_SIZE); 193191783Srmacklem nmp->nm_mountp->mnt_stat.f_iosize = iosize; 194191783Srmacklem return (iosize); 195191783Srmacklem} 196191783Srmacklem 197191783Srmacklemstatic void 198191783Srmacklemnfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs) 199191783Srmacklem{ 200191783Srmacklem 201191783Srmacklem args->version = NFS_ARGSVERSION; 202191783Srmacklem args->addr = oargs->addr; 203191783Srmacklem args->addrlen = oargs->addrlen; 204191783Srmacklem args->sotype = oargs->sotype; 205191783Srmacklem args->proto = oargs->proto; 206191783Srmacklem args->fh = oargs->fh; 207191783Srmacklem args->fhsize = oargs->fhsize; 208191783Srmacklem args->flags = oargs->flags; 209191783Srmacklem args->wsize = oargs->wsize; 210191783Srmacklem args->rsize = oargs->rsize; 211191783Srmacklem args->readdirsize = oargs->readdirsize; 212191783Srmacklem args->timeo = oargs->timeo; 213191783Srmacklem args->retrans = oargs->retrans; 214191783Srmacklem args->readahead = oargs->readahead; 215191783Srmacklem args->hostname = oargs->hostname; 216191783Srmacklem} 217191783Srmacklem 218191783Srmacklemstatic void 219191783Srmacklemnfs_convert_diskless(void) 220191783Srmacklem{ 221191783Srmacklem 222191783Srmacklem bcopy(&newnfs_diskless.myif, &newnfsv3_diskless.myif, 223191783Srmacklem sizeof(struct ifaliasreq)); 224191783Srmacklem bcopy(&newnfs_diskless.mygateway, &newnfsv3_diskless.mygateway, 225191783Srmacklem sizeof(struct sockaddr_in)); 226191783Srmacklem nfs_convert_oargs(&newnfsv3_diskless.root_args,&newnfs_diskless.root_args); 227191783Srmacklem if (newnfsv3_diskless.root_args.flags & NFSMNT_NFSV3) { 228191783Srmacklem newnfsv3_diskless.root_fhsize = NFSX_MYFH; 229191783Srmacklem bcopy(newnfs_diskless.root_fh, newnfsv3_diskless.root_fh, NFSX_MYFH); 230191783Srmacklem } else { 231191783Srmacklem newnfsv3_diskless.root_fhsize = NFSX_V2FH; 232191783Srmacklem bcopy(newnfs_diskless.root_fh, newnfsv3_diskless.root_fh, NFSX_V2FH); 233191783Srmacklem } 234191783Srmacklem bcopy(&newnfs_diskless.root_saddr,&newnfsv3_diskless.root_saddr, 235191783Srmacklem sizeof(struct sockaddr_in)); 236191783Srmacklem bcopy(newnfs_diskless.root_hostnam, newnfsv3_diskless.root_hostnam, MNAMELEN); 237191783Srmacklem newnfsv3_diskless.root_time = newnfs_diskless.root_time; 238191783Srmacklem bcopy(newnfs_diskless.my_hostnam, newnfsv3_diskless.my_hostnam, 239191783Srmacklem MAXHOSTNAMELEN); 240191783Srmacklem newnfs_diskless_valid = 3; 241191783Srmacklem} 242191783Srmacklem 243191783Srmacklem/* 244191783Srmacklem * nfs statfs call 245191783Srmacklem */ 246191783Srmacklemstatic int 247191990Sattilionfs_statfs(struct mount *mp, struct statfs *sbp) 248191783Srmacklem{ 249191783Srmacklem struct vnode *vp; 250191990Sattilio struct thread *td; 251191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 252191783Srmacklem struct nfsvattr nfsva; 253191783Srmacklem struct nfsfsinfo fs; 254191783Srmacklem struct nfsstatfs sb; 255191783Srmacklem int error = 0, attrflag, gotfsinfo = 0, ret; 256191783Srmacklem struct nfsnode *np; 257191783Srmacklem 258191990Sattilio td = curthread; 259191990Sattilio 260191783Srmacklem error = vfs_busy(mp, MBF_NOWAIT); 261191783Srmacklem if (error) 262191783Srmacklem return (error); 263191783Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np); 264191783Srmacklem if (error) { 265191783Srmacklem vfs_unbusy(mp); 266191783Srmacklem return (error); 267191783Srmacklem } 268191783Srmacklem vp = NFSTOV(np); 269191783Srmacklem mtx_lock(&nmp->nm_mtx); 270191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 271191783Srmacklem mtx_unlock(&nmp->nm_mtx); 272191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva, 273191783Srmacklem &attrflag, NULL); 274191783Srmacklem if (!error) 275191783Srmacklem gotfsinfo = 1; 276191783Srmacklem } else 277191783Srmacklem mtx_unlock(&nmp->nm_mtx); 278191783Srmacklem if (!error) 279191783Srmacklem error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, 280191783Srmacklem &attrflag, NULL); 281191783Srmacklem if (attrflag == 0) { 282191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 283191783Srmacklem td->td_ucred, td, &nfsva, NULL); 284191783Srmacklem if (ret) { 285191783Srmacklem /* 286191783Srmacklem * Just set default values to get things going. 287191783Srmacklem */ 288191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 289191783Srmacklem nfsva.na_vattr.va_type = VDIR; 290191783Srmacklem nfsva.na_vattr.va_mode = 0777; 291191783Srmacklem nfsva.na_vattr.va_nlink = 100; 292191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 293191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 294191783Srmacklem nfsva.na_vattr.va_fileid = 2; 295191783Srmacklem nfsva.na_vattr.va_gen = 1; 296191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 297191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 298191783Srmacklem } 299191783Srmacklem } 300191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 301191783Srmacklem if (!error) { 302191783Srmacklem mtx_lock(&nmp->nm_mtx); 303191783Srmacklem if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4)) 304191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 305191783Srmacklem nfscl_loadsbinfo(nmp, &sb, sbp); 306191783Srmacklem sbp->f_flags = nmp->nm_flag; 307191783Srmacklem sbp->f_iosize = newnfs_iosize(nmp); 308191783Srmacklem mtx_unlock(&nmp->nm_mtx); 309191783Srmacklem if (sbp != &mp->mnt_stat) { 310191783Srmacklem bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 311191783Srmacklem bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 312191783Srmacklem } 313191783Srmacklem strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 314191783Srmacklem } else if (NFS_ISV4(vp)) { 315191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 316191783Srmacklem } 317191783Srmacklem vput(vp); 318191783Srmacklem vfs_unbusy(mp); 319191783Srmacklem return (error); 320191783Srmacklem} 321191783Srmacklem 322191783Srmacklem/* 323191783Srmacklem * nfs version 3 fsinfo rpc call 324191783Srmacklem */ 325191783Srmacklemint 326191783Srmacklemncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, 327191783Srmacklem struct thread *td) 328191783Srmacklem{ 329191783Srmacklem struct nfsfsinfo fs; 330191783Srmacklem struct nfsvattr nfsva; 331191783Srmacklem int error, attrflag; 332191783Srmacklem 333191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL); 334191783Srmacklem if (!error) { 335191783Srmacklem if (attrflag) 336191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 337191783Srmacklem 1); 338191783Srmacklem mtx_lock(&nmp->nm_mtx); 339191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 340191783Srmacklem mtx_unlock(&nmp->nm_mtx); 341191783Srmacklem } 342191783Srmacklem return (error); 343191783Srmacklem} 344191783Srmacklem 345191783Srmacklem/* 346191783Srmacklem * Mount a remote root fs via. nfs. This depends on the info in the 347191783Srmacklem * newnfs_diskless structure that has been filled in properly by some primary 348191783Srmacklem * bootstrap. 349191783Srmacklem * It goes something like this: 350191783Srmacklem * - do enough of "ifconfig" by calling ifioctl() so that the system 351191783Srmacklem * can talk to the server 352191783Srmacklem * - If newnfs_diskless.mygateway is filled in, use that address as 353191783Srmacklem * a default gateway. 354191783Srmacklem * - build the rootfs mount point and call mountnfs() to do the rest. 355191783Srmacklem * 356191783Srmacklem * It is assumed to be safe to read, modify, and write the nfsv3_diskless 357191783Srmacklem * structure, as well as other global NFS client variables here, as 358191783Srmacklem * ncl_mountroot() will be called once in the boot before any other NFS 359191783Srmacklem * client activity occurs. 360191783Srmacklem */ 361191783Srmacklemint 362191783Srmacklemncl_mountroot(struct mount *mp, struct thread *td) 363191783Srmacklem{ 364191783Srmacklem struct nfsv3_diskless *nd = &newnfsv3_diskless; 365191783Srmacklem struct socket *so; 366191783Srmacklem struct vnode *vp; 367191783Srmacklem struct ifreq ir; 368191783Srmacklem int error, i; 369191783Srmacklem u_long l; 370191783Srmacklem char buf[128]; 371191783Srmacklem char *cp; 372191783Srmacklem 373191783Srmacklem#if defined(BOOTP_NFSROOT) && defined(BOOTP) 374191783Srmacklem bootpc_init(); /* use bootp to get newnfs_diskless filled in */ 375191783Srmacklem#elif defined(NFS_ROOT) 376191783Srmacklem nfs_setup_diskless(); 377191783Srmacklem#endif 378191783Srmacklem 379191783Srmacklem nfscl_init(); 380191783Srmacklem 381191783Srmacklem if (newnfs_diskless_valid == 0) 382191783Srmacklem return (-1); 383191783Srmacklem if (newnfs_diskless_valid == 1) 384191783Srmacklem nfs_convert_diskless(); 385191783Srmacklem 386191783Srmacklem /* 387191783Srmacklem * XXX splnet, so networks will receive... 388191783Srmacklem */ 389191783Srmacklem splnet(); 390191783Srmacklem 391191783Srmacklem /* 392191783Srmacklem * Do enough of ifconfig(8) so that the critical net interface can 393191783Srmacklem * talk to the server. 394191783Srmacklem */ 395191783Srmacklem error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0, 396191783Srmacklem td->td_ucred, td); 397191783Srmacklem if (error) 398191783Srmacklem panic("ncl_mountroot: socreate(%04x): %d", 399191783Srmacklem nd->myif.ifra_addr.sa_family, error); 400191783Srmacklem 401191783Srmacklem#if 0 /* XXX Bad idea */ 402191783Srmacklem /* 403191783Srmacklem * We might not have been told the right interface, so we pass 404191783Srmacklem * over the first ten interfaces of the same kind, until we get 405191783Srmacklem * one of them configured. 406191783Srmacklem */ 407191783Srmacklem 408191783Srmacklem for (i = strlen(nd->myif.ifra_name) - 1; 409191783Srmacklem nd->myif.ifra_name[i] >= '0' && 410191783Srmacklem nd->myif.ifra_name[i] <= '9'; 411191783Srmacklem nd->myif.ifra_name[i] ++) { 412191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 413191783Srmacklem if(!error) 414191783Srmacklem break; 415191783Srmacklem } 416191783Srmacklem#endif 417191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 418191783Srmacklem if (error) 419191783Srmacklem panic("ncl_mountroot: SIOCAIFADDR: %d", error); 420191783Srmacklem if ((cp = getenv("boot.netif.mtu")) != NULL) { 421191783Srmacklem ir.ifr_mtu = strtol(cp, NULL, 10); 422191783Srmacklem bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); 423191783Srmacklem freeenv(cp); 424191783Srmacklem error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); 425191783Srmacklem if (error) 426191783Srmacklem printf("ncl_mountroot: SIOCSIFMTU: %d", error); 427191783Srmacklem } 428191783Srmacklem soclose(so); 429191783Srmacklem 430191783Srmacklem /* 431191783Srmacklem * If the gateway field is filled in, set it as the default route. 432191783Srmacklem * Note that pxeboot will set a default route of 0 if the route 433191783Srmacklem * is not set by the DHCP server. Check also for a value of 0 434191783Srmacklem * to avoid panicking inappropriately in that situation. 435191783Srmacklem */ 436191783Srmacklem if (nd->mygateway.sin_len != 0 && 437191783Srmacklem nd->mygateway.sin_addr.s_addr != 0) { 438191783Srmacklem struct sockaddr_in mask, sin; 439191783Srmacklem 440191783Srmacklem bzero((caddr_t)&mask, sizeof(mask)); 441191783Srmacklem sin = mask; 442191783Srmacklem sin.sin_family = AF_INET; 443191783Srmacklem sin.sin_len = sizeof(sin); 444191783Srmacklem error = rtrequest(RTM_ADD, (struct sockaddr *)&sin, 445191783Srmacklem (struct sockaddr *)&nd->mygateway, 446191783Srmacklem (struct sockaddr *)&mask, 447191783Srmacklem RTF_UP | RTF_GATEWAY, NULL); 448191783Srmacklem if (error) 449191783Srmacklem panic("ncl_mountroot: RTM_ADD: %d", error); 450191783Srmacklem } 451191783Srmacklem 452191783Srmacklem /* 453191783Srmacklem * Create the rootfs mount point. 454191783Srmacklem */ 455191783Srmacklem nd->root_args.fh = nd->root_fh; 456191783Srmacklem nd->root_args.fhsize = nd->root_fhsize; 457191783Srmacklem l = ntohl(nd->root_saddr.sin_addr.s_addr); 458191783Srmacklem snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", 459191783Srmacklem (l >> 24) & 0xff, (l >> 16) & 0xff, 460191783Srmacklem (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); 461191783Srmacklem printf("NFS ROOT: %s\n", buf); 462191783Srmacklem if ((error = nfs_mountdiskless(buf, 463191783Srmacklem &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { 464191783Srmacklem return (error); 465191783Srmacklem } 466191783Srmacklem 467191783Srmacklem /* 468191783Srmacklem * This is not really an nfs issue, but it is much easier to 469191783Srmacklem * set hostname here and then let the "/etc/rc.xxx" files 470191783Srmacklem * mount the right /var based upon its preset value. 471191783Srmacklem */ 472191783Srmacklem bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN); 473191783Srmacklem hostname[MAXHOSTNAMELEN - 1] = '\0'; 474191783Srmacklem for (i = 0; i < MAXHOSTNAMELEN; i++) 475191783Srmacklem if (hostname[i] == '\0') 476191783Srmacklem break; 477191783Srmacklem inittodr(ntohl(nd->root_time)); 478191783Srmacklem return (0); 479191783Srmacklem} 480191783Srmacklem 481191783Srmacklem/* 482191783Srmacklem * Internal version of mount system call for diskless setup. 483191783Srmacklem */ 484191783Srmacklemstatic int 485191783Srmacklemnfs_mountdiskless(char *path, 486191783Srmacklem struct sockaddr_in *sin, struct nfs_args *args, struct thread *td, 487191783Srmacklem struct vnode **vpp, struct mount *mp) 488191783Srmacklem{ 489191783Srmacklem struct sockaddr *nam; 490191783Srmacklem int error; 491191783Srmacklem 492191783Srmacklem nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); 493191783Srmacklem if ((error = mountnfs(args, mp, nam, path, NULL, NULL, NULL, vpp, 494191783Srmacklem td->td_ucred, td)) != 0) { 495191783Srmacklem printf("ncl_mountroot: mount %s on /: %d\n", path, error); 496191783Srmacklem return (error); 497191783Srmacklem } 498191783Srmacklem return (0); 499191783Srmacklem} 500191783Srmacklem 501191783Srmacklemstatic void 502191783Srmacklemnfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, 503191783Srmacklem struct ucred *cred, struct thread *td) 504191783Srmacklem{ 505191783Srmacklem int s; 506191783Srmacklem int adjsock; 507191783Srmacklem 508191783Srmacklem s = splnet(); 509191783Srmacklem 510191783Srmacklem /* 511191783Srmacklem * Set read-only flag if requested; otherwise, clear it if this is 512191783Srmacklem * an update. If this is not an update, then either the read-only 513191783Srmacklem * flag is already clear, or this is a root mount and it was set 514191783Srmacklem * intentionally at some previous point. 515191783Srmacklem */ 516191783Srmacklem if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) { 517191783Srmacklem MNT_ILOCK(mp); 518191783Srmacklem mp->mnt_flag |= MNT_RDONLY; 519191783Srmacklem MNT_IUNLOCK(mp); 520191783Srmacklem } else if (mp->mnt_flag & MNT_UPDATE) { 521191783Srmacklem MNT_ILOCK(mp); 522191783Srmacklem mp->mnt_flag &= ~MNT_RDONLY; 523191783Srmacklem MNT_IUNLOCK(mp); 524191783Srmacklem } 525191783Srmacklem 526191783Srmacklem /* 527191783Srmacklem * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 528191783Srmacklem * no sense in that context. Also, set up appropriate retransmit 529191783Srmacklem * and soft timeout behavior. 530191783Srmacklem */ 531191783Srmacklem if (argp->sotype == SOCK_STREAM) { 532191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOCONN; 533191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 534191783Srmacklem } 535191783Srmacklem 536191783Srmacklem /* Also clear RDIRPLUS if not NFSv3, it crashes some servers */ 537191783Srmacklem if ((argp->flags & NFSMNT_NFSV3) == 0) 538191783Srmacklem nmp->nm_flag &= ~NFSMNT_RDIRPLUS; 539191783Srmacklem 540191783Srmacklem /* Also re-bind if we're switching to/from a connected UDP socket */ 541191783Srmacklem adjsock = ((nmp->nm_flag & NFSMNT_NOCONN) != 542191783Srmacklem (argp->flags & NFSMNT_NOCONN)); 543191783Srmacklem 544191783Srmacklem /* Update flags atomically. Don't change the lock bits. */ 545191783Srmacklem nmp->nm_flag = argp->flags | nmp->nm_flag; 546191783Srmacklem splx(s); 547191783Srmacklem 548191783Srmacklem if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 549191783Srmacklem nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 550191783Srmacklem if (nmp->nm_timeo < NFS_MINTIMEO) 551191783Srmacklem nmp->nm_timeo = NFS_MINTIMEO; 552191783Srmacklem else if (nmp->nm_timeo > NFS_MAXTIMEO) 553191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 554191783Srmacklem } 555191783Srmacklem 556191783Srmacklem if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 557191783Srmacklem nmp->nm_retry = argp->retrans; 558191783Srmacklem if (nmp->nm_retry > NFS_MAXREXMIT) 559191783Srmacklem nmp->nm_retry = NFS_MAXREXMIT; 560191783Srmacklem } 561191783Srmacklem 562191783Srmacklem if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 563191783Srmacklem nmp->nm_wsize = argp->wsize; 564191783Srmacklem /* Round down to multiple of blocksize */ 565191783Srmacklem nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); 566191783Srmacklem if (nmp->nm_wsize <= 0) 567191783Srmacklem nmp->nm_wsize = NFS_FABLKSIZE; 568191783Srmacklem } 569191783Srmacklem 570191783Srmacklem if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 571191783Srmacklem nmp->nm_rsize = argp->rsize; 572191783Srmacklem /* Round down to multiple of blocksize */ 573191783Srmacklem nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); 574191783Srmacklem if (nmp->nm_rsize <= 0) 575191783Srmacklem nmp->nm_rsize = NFS_FABLKSIZE; 576191783Srmacklem } 577191783Srmacklem 578191783Srmacklem if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 579191783Srmacklem nmp->nm_readdirsize = argp->readdirsize; 580191783Srmacklem } 581191783Srmacklem 582191783Srmacklem if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) 583191783Srmacklem nmp->nm_acregmin = argp->acregmin; 584191783Srmacklem else 585191783Srmacklem nmp->nm_acregmin = NFS_MINATTRTIMO; 586191783Srmacklem if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) 587191783Srmacklem nmp->nm_acregmax = argp->acregmax; 588191783Srmacklem else 589191783Srmacklem nmp->nm_acregmax = NFS_MAXATTRTIMO; 590191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) 591191783Srmacklem nmp->nm_acdirmin = argp->acdirmin; 592191783Srmacklem else 593191783Srmacklem nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; 594191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) 595191783Srmacklem nmp->nm_acdirmax = argp->acdirmax; 596191783Srmacklem else 597191783Srmacklem nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; 598191783Srmacklem if (nmp->nm_acdirmin > nmp->nm_acdirmax) 599191783Srmacklem nmp->nm_acdirmin = nmp->nm_acdirmax; 600191783Srmacklem if (nmp->nm_acregmin > nmp->nm_acregmax) 601191783Srmacklem nmp->nm_acregmin = nmp->nm_acregmax; 602191783Srmacklem 603191783Srmacklem if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { 604191783Srmacklem if (argp->readahead <= NFS_MAXRAHEAD) 605191783Srmacklem nmp->nm_readahead = argp->readahead; 606191783Srmacklem else 607191783Srmacklem nmp->nm_readahead = NFS_MAXRAHEAD; 608191783Srmacklem } 609191783Srmacklem if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) { 610191783Srmacklem if (argp->wcommitsize < nmp->nm_wsize) 611191783Srmacklem nmp->nm_wcommitsize = nmp->nm_wsize; 612191783Srmacklem else 613191783Srmacklem nmp->nm_wcommitsize = argp->wcommitsize; 614191783Srmacklem } 615191783Srmacklem 616191783Srmacklem adjsock |= ((nmp->nm_sotype != argp->sotype) || 617191783Srmacklem (nmp->nm_soproto != argp->proto)); 618191783Srmacklem 619191783Srmacklem if (nmp->nm_client != NULL && adjsock) { 620191783Srmacklem int haslock = 0, error = 0; 621191783Srmacklem 622191783Srmacklem if (nmp->nm_sotype == SOCK_STREAM) { 623191783Srmacklem error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock); 624191783Srmacklem if (!error) 625191783Srmacklem haslock = 1; 626191783Srmacklem } 627191783Srmacklem if (!error) { 628191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 629191783Srmacklem if (haslock) 630191783Srmacklem newnfs_sndunlock(&nmp->nm_sockreq.nr_lock); 631191783Srmacklem nmp->nm_sotype = argp->sotype; 632191783Srmacklem nmp->nm_soproto = argp->proto; 633191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 634191783Srmacklem while (newnfs_connect(nmp, &nmp->nm_sockreq, 635191783Srmacklem cred, td, 0)) { 636191783Srmacklem printf("newnfs_args: retrying connect\n"); 637191783Srmacklem (void) nfs_catnap(PSOCK, "newnfscon"); 638191783Srmacklem } 639191783Srmacklem } 640191783Srmacklem } else { 641191783Srmacklem nmp->nm_sotype = argp->sotype; 642191783Srmacklem nmp->nm_soproto = argp->proto; 643191783Srmacklem } 644191783Srmacklem} 645191783Srmacklem 646191783Srmacklemstatic const char *nfs_opts[] = { "from", "nfs_args", 647191783Srmacklem "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union", 648191783Srmacklem "noclusterr", "noclusterw", "multilabel", "acls", "force", "update", 649191783Srmacklem "async", "dumbtimer", "noconn", "nolockd", "intr", "rdirplus", "resvport", 650191783Srmacklem "readdirsize", "soft", "hard", "mntudp", "tcp", "wsize", "rsize", 651191783Srmacklem "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", 652191783Srmacklem NULL }; 653191783Srmacklem 654191783Srmacklem/* 655191783Srmacklem * VFS Operations. 656191783Srmacklem * 657191783Srmacklem * mount system call 658191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 659191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 660191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 661191783Srmacklem * an error after that means that I have to release the mbuf. 662191783Srmacklem */ 663191783Srmacklem/* ARGSUSED */ 664191783Srmacklemstatic int 665191990Sattilionfs_mount(struct mount *mp) 666191783Srmacklem{ 667191783Srmacklem struct nfs_args args = { 668191783Srmacklem .version = NFS_ARGSVERSION, 669191783Srmacklem .addr = NULL, 670191783Srmacklem .addrlen = sizeof (struct sockaddr_in), 671191783Srmacklem .sotype = SOCK_STREAM, 672191783Srmacklem .proto = 0, 673191783Srmacklem .fh = NULL, 674191783Srmacklem .fhsize = 0, 675191783Srmacklem .flags = 0, 676191783Srmacklem .wsize = NFS_WSIZE, 677191783Srmacklem .rsize = NFS_RSIZE, 678191783Srmacklem .readdirsize = NFS_READDIRSIZE, 679191783Srmacklem .timeo = 10, 680191783Srmacklem .retrans = NFS_RETRANS, 681191783Srmacklem .readahead = NFS_DEFRAHEAD, 682191783Srmacklem .wcommitsize = 0, /* was: NQ_DEFLEASE */ 683191783Srmacklem .hostname = NULL, 684191783Srmacklem /* args version 4 */ 685191783Srmacklem .acregmin = NFS_MINATTRTIMO, 686191783Srmacklem .acregmax = NFS_MAXATTRTIMO, 687191783Srmacklem .acdirmin = NFS_MINDIRATTRTIMO, 688191783Srmacklem .acdirmax = NFS_MAXDIRATTRTIMO, 689191783Srmacklem .dirlen = 0, 690191783Srmacklem .krbnamelen = 0, 691191783Srmacklem }; 692191783Srmacklem int error; 693191783Srmacklem struct sockaddr *nam; 694191783Srmacklem struct vnode *vp; 695191990Sattilio struct thread *td; 696191783Srmacklem char hst[MNAMELEN]; 697191783Srmacklem size_t len; 698191783Srmacklem u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100]; 699191783Srmacklem 700191783Srmacklem if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) { 701191783Srmacklem error = EINVAL; 702191783Srmacklem goto out; 703191783Srmacklem } 704191783Srmacklem 705191990Sattilio td = curthread; 706191783Srmacklem if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) { 707191783Srmacklem error = ncl_mountroot(mp, td); 708191783Srmacklem goto out; 709191783Srmacklem } 710191783Srmacklem 711191783Srmacklem error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args, sizeof args); 712191783Srmacklem if (error) 713191783Srmacklem goto out; 714191783Srmacklem 715191783Srmacklem if (args.version != NFS_ARGSVERSION) { 716191783Srmacklem error = EPROGMISMATCH; 717191783Srmacklem goto out; 718191783Srmacklem } 719191783Srmacklem 720191783Srmacklem nfscl_init(); 721191783Srmacklem 722191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 723191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 724191783Srmacklem 725191783Srmacklem if (nmp == NULL) { 726191783Srmacklem error = EIO; 727191783Srmacklem goto out; 728191783Srmacklem } 729191783Srmacklem /* 730191783Srmacklem * When doing an update, we can't change version, 731191783Srmacklem * security, switch lockd strategies or change cookie 732191783Srmacklem * translation 733191783Srmacklem */ 734191783Srmacklem args.flags = (args.flags & 735191783Srmacklem ~(NFSMNT_NFSV3 | 736191783Srmacklem NFSMNT_NFSV4 | 737191783Srmacklem NFSMNT_KERB | 738191783Srmacklem NFSMNT_INTEGRITY | 739191783Srmacklem NFSMNT_PRIVACY | 740191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) | 741191783Srmacklem (nmp->nm_flag & 742191783Srmacklem (NFSMNT_NFSV3 | 743191783Srmacklem NFSMNT_NFSV4 | 744191783Srmacklem NFSMNT_KERB | 745191783Srmacklem NFSMNT_INTEGRITY | 746191783Srmacklem NFSMNT_PRIVACY | 747191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); 748191783Srmacklem nfs_decode_args(mp, nmp, &args, td->td_ucred, td); 749191783Srmacklem goto out; 750191783Srmacklem } 751191783Srmacklem 752191783Srmacklem /* 753191783Srmacklem * Make the nfs_ip_paranoia sysctl serve as the default connection 754191783Srmacklem * or no-connection mode for those protocols that support 755191783Srmacklem * no-connection mode (the flag will be cleared later for protocols 756191783Srmacklem * that do not support no-connection mode). This will allow a client 757191783Srmacklem * to receive replies from a different IP then the request was 758191783Srmacklem * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid), 759191783Srmacklem * not 0. 760191783Srmacklem */ 761191783Srmacklem if (nfs_ip_paranoia == 0) 762191783Srmacklem args.flags |= NFSMNT_NOCONN; 763191783Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) { 764191783Srmacklem error = EINVAL; 765191783Srmacklem goto out; 766191783Srmacklem } 767191783Srmacklem if (args.fhsize > 0) { 768191783Srmacklem error = copyin((caddr_t)args.fh, (caddr_t)nfh, args.fhsize); 769191783Srmacklem if (error) 770191783Srmacklem goto out; 771191783Srmacklem } 772191783Srmacklem error = copyinstr(args.hostname, hst, MNAMELEN-1, &len); 773191783Srmacklem if (error) 774191783Srmacklem goto out; 775191783Srmacklem bzero(&hst[len], MNAMELEN - len); 776191783Srmacklem if (args.krbnamelen > 0) { 777191783Srmacklem if (args.krbnamelen >= 100) { 778191783Srmacklem error = EINVAL; 779191783Srmacklem goto out; 780191783Srmacklem } 781191783Srmacklem error = copyin(args.krbname, krbname, args.krbnamelen); 782191783Srmacklem if (error) 783191783Srmacklem goto out; 784191783Srmacklem krbname[args.krbnamelen] = '\0'; 785191783Srmacklem } else { 786191783Srmacklem krbname[0] = '\0'; 787191783Srmacklem args.krbnamelen = 0; 788191783Srmacklem } 789191783Srmacklem if (args.dirlen > 0) { 790191783Srmacklem if (args.dirlen >= 100) { 791191783Srmacklem error = EINVAL; 792191783Srmacklem goto out; 793191783Srmacklem } 794191783Srmacklem error = copyin(args.dirpath, dirpath, args.dirlen); 795191783Srmacklem if (error) 796191783Srmacklem goto out; 797191783Srmacklem dirpath[args.dirlen] = '\0'; 798191783Srmacklem } else { 799191783Srmacklem dirpath[0] = '\0'; 800191783Srmacklem args.dirlen = 0; 801191783Srmacklem } 802191783Srmacklem if (args.srvkrbnamelen > 0) { 803191783Srmacklem if (args.srvkrbnamelen >= 100) { 804191783Srmacklem error = EINVAL; 805191783Srmacklem goto out; 806191783Srmacklem } 807191783Srmacklem error = copyin(args.srvkrbname, srvkrbname, args.srvkrbnamelen); 808191783Srmacklem if (error) 809191783Srmacklem goto out; 810191783Srmacklem srvkrbname[args.srvkrbnamelen] = '\0'; 811191783Srmacklem } else { 812191783Srmacklem srvkrbname[0] = '\0'; 813191783Srmacklem args.srvkrbnamelen = 0; 814191783Srmacklem } 815191783Srmacklem /* sockargs() call must be after above copyin() calls */ 816191783Srmacklem error = getsockaddr(&nam, (caddr_t)args.addr, args.addrlen); 817191783Srmacklem if (error) 818191783Srmacklem goto out; 819191783Srmacklem args.fh = nfh; 820191783Srmacklem error = mountnfs(&args, mp, nam, hst, krbname, dirpath, srvkrbname, 821191783Srmacklem &vp, td->td_ucred, td); 822191783Srmacklemout: 823191783Srmacklem if (!error) { 824191783Srmacklem MNT_ILOCK(mp); 825191783Srmacklem mp->mnt_kern_flag |= (MNTK_MPSAFE|MNTK_LOOKUP_SHARED); 826191783Srmacklem MNT_IUNLOCK(mp); 827191783Srmacklem } 828191783Srmacklem return (error); 829191783Srmacklem} 830191783Srmacklem 831191783Srmacklem 832191783Srmacklem/* 833191783Srmacklem * VFS Operations. 834191783Srmacklem * 835191783Srmacklem * mount system call 836191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 837191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 838191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 839191783Srmacklem * an error after that means that I have to release the mbuf. 840191783Srmacklem */ 841191783Srmacklem/* ARGSUSED */ 842191783Srmacklemstatic int 843191990Sattilionfs_cmount(struct mntarg *ma, void *data, int flags) 844191783Srmacklem{ 845191783Srmacklem int error; 846191783Srmacklem struct nfs_args args; 847191783Srmacklem 848191783Srmacklem error = copyin(data, &args, sizeof (struct nfs_args)); 849191783Srmacklem if (error) 850191783Srmacklem return error; 851191783Srmacklem 852191783Srmacklem ma = mount_arg(ma, "nfs_args", &args, sizeof args); 853191783Srmacklem 854191783Srmacklem error = kernel_mount(ma, flags); 855191783Srmacklem return (error); 856191783Srmacklem} 857191783Srmacklem 858191783Srmacklem/* 859191783Srmacklem * Common code for mount and mountroot 860191783Srmacklem */ 861191783Srmacklemstatic int 862191783Srmacklemmountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, 863191783Srmacklem char *hst, u_char *krbname, u_char *dirpath, u_char *srvkrbname, 864191783Srmacklem struct vnode **vpp, struct ucred *cred, struct thread *td) 865191783Srmacklem{ 866191783Srmacklem struct nfsmount *nmp; 867191783Srmacklem struct nfsnode *np; 868191783Srmacklem int error, trycnt, ret, clearintr; 869191783Srmacklem struct nfsvattr nfsva; 870191783Srmacklem static u_int64_t clval = 0; 871191783Srmacklem 872191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 873191783Srmacklem nmp = VFSTONFS(mp); 874191783Srmacklem printf("%s: MNT_UPDATE is no longer handled here\n", __func__); 875191783Srmacklem FREE(nam, M_SONAME); 876191783Srmacklem return (0); 877191783Srmacklem } else { 878191783Srmacklem MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) + 879191783Srmacklem argp->krbnamelen + argp->dirlen + argp->srvkrbnamelen + 2, 880191783Srmacklem M_NEWNFSMNT, M_WAITOK); 881191783Srmacklem bzero((caddr_t)nmp, sizeof (struct nfsmount) + 882191783Srmacklem argp->krbnamelen + argp->dirlen + argp->srvkrbnamelen + 2); 883191783Srmacklem TAILQ_INIT(&nmp->nm_bufq); 884191783Srmacklem if (clval == 0) 885191783Srmacklem clval = (u_int64_t)nfsboottime.tv_sec; 886191783Srmacklem nmp->nm_clval = clval++; 887191783Srmacklem nmp->nm_krbnamelen = argp->krbnamelen; 888191783Srmacklem nmp->nm_dirpathlen = argp->dirlen; 889191783Srmacklem nmp->nm_srvkrbnamelen = argp->srvkrbnamelen; 890191783Srmacklem if (nmp->nm_dirpathlen > 0) { 891191783Srmacklem /* 892191783Srmacklem * Since we will be doing dirpath as root, 893191783Srmacklem * set nm_uid to the real uid doing the mount, 894191783Srmacklem * since that is normally the user with a valid TGT. 895191783Srmacklem */ 896191783Srmacklem nmp->nm_uid = td->td_ucred->cr_ruid; 897191783Srmacklem } else { 898191783Srmacklem /* 899191783Srmacklem * Just set to -1, so the first Op 900191783Srmacklem * will set it later, to the uid of 901191783Srmacklem * the process doing that (usually 902191783Srmacklem * from a first open in the mount 903191783Srmacklem * point). 904191783Srmacklem */ 905191783Srmacklem nmp->nm_uid = (uid_t)-1; 906191783Srmacklem } 907191783Srmacklem 908191783Srmacklem /* Copy and null terminate all the names */ 909191783Srmacklem if (nmp->nm_krbnamelen > 0) { 910191783Srmacklem bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen); 911191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen] = '\0'; 912191783Srmacklem } 913191783Srmacklem if (nmp->nm_dirpathlen > 0) { 914191783Srmacklem bcopy(dirpath, NFSMNT_DIRPATH(nmp), 915191783Srmacklem nmp->nm_dirpathlen); 916191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 917191783Srmacklem + 1] = '\0'; 918191783Srmacklem } 919191783Srmacklem if (nmp->nm_srvkrbnamelen > 0) { 920191783Srmacklem bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp), 921191783Srmacklem nmp->nm_srvkrbnamelen); 922191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 923191783Srmacklem + nmp->nm_srvkrbnamelen + 2] = '\0'; 924191783Srmacklem } 925191783Srmacklem nmp->nm_sockreq.nr_cred = crhold(cred); 926191783Srmacklem mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF); 927191783Srmacklem mp->mnt_data = nmp; 928191783Srmacklem } 929191783Srmacklem vfs_getnewfsid(mp); 930191783Srmacklem nmp->nm_mountp = mp; 931191783Srmacklem mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK); 932191783Srmacklem 933191783Srmacklem /* 934191783Srmacklem * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too 935191783Srmacklem * high, depending on whether we end up with negative offsets in 936191783Srmacklem * the client or server somewhere. 2GB-1 may be safer. 937191783Srmacklem * 938191783Srmacklem * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum 939191783Srmacklem * that we can handle until we find out otherwise. 940191783Srmacklem * XXX Our "safe" limit on the client is what we can store in our 941191783Srmacklem * buffer cache using signed(!) block numbers. 942191783Srmacklem */ 943191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) 944191783Srmacklem nmp->nm_maxfilesize = 0xffffffffLL; 945191783Srmacklem else 946191783Srmacklem nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1; 947191783Srmacklem 948191783Srmacklem nmp->nm_timeo = NFS_TIMEO; 949191783Srmacklem nmp->nm_retry = NFS_RETRANS; 950191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 951191783Srmacklem nmp->nm_wsize = NFS_WSIZE; 952191783Srmacklem nmp->nm_rsize = NFS_RSIZE; 953191783Srmacklem nmp->nm_readdirsize = NFS_READDIRSIZE; 954191783Srmacklem } 955191783Srmacklem nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000); 956191783Srmacklem nmp->nm_numgrps = NFS_MAXGRPS; 957191783Srmacklem nmp->nm_readahead = NFS_DEFRAHEAD; 958191783Srmacklem nmp->nm_tprintf_delay = nfs_tprintf_delay; 959191783Srmacklem if (nmp->nm_tprintf_delay < 0) 960191783Srmacklem nmp->nm_tprintf_delay = 0; 961191783Srmacklem nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay; 962191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 963191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 964191783Srmacklem nmp->nm_fhsize = argp->fhsize; 965191783Srmacklem if (nmp->nm_fhsize > 0) 966191783Srmacklem bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 967191783Srmacklem bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 968191783Srmacklem nmp->nm_nam = nam; 969191783Srmacklem /* Set up the sockets and per-host congestion */ 970191783Srmacklem nmp->nm_sotype = argp->sotype; 971191783Srmacklem nmp->nm_soproto = argp->proto; 972191783Srmacklem nmp->nm_sockreq.nr_prog = NFS_PROG; 973191783Srmacklem if ((argp->flags & NFSMNT_NFSV4)) 974191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER4; 975191783Srmacklem else if ((argp->flags & NFSMNT_NFSV3)) 976191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER3; 977191783Srmacklem else 978191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER2; 979191783Srmacklem 980191783Srmacklem nfs_decode_args(mp, nmp, argp, cred, td); 981191783Srmacklem 982191783Srmacklem /* 983191783Srmacklem * For Connection based sockets (TCP,...) do the connect here, 984191783Srmacklem * but make it interruptible, even for non-interuptible mounts. 985191783Srmacklem */ 986191783Srmacklem if ((nmp->nm_flag & NFSMNT_INT) == 0) { 987191783Srmacklem nmp->nm_flag |= NFSMNT_INT; 988191783Srmacklem clearintr = 1; 989191783Srmacklem } else { 990191783Srmacklem clearintr = 0; 991191783Srmacklem } 992191783Srmacklem if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0))) 993191783Srmacklem goto bad; 994191783Srmacklem if (clearintr) 995191783Srmacklem nmp->nm_flag &= ~NFSMNT_INT; 996191783Srmacklem 997191783Srmacklem /* 998191783Srmacklem * A reference count is needed on the nfsnode representing the 999191783Srmacklem * remote root. If this object is not persistent, then backward 1000191783Srmacklem * traversals of the mount point (i.e. "..") will not work if 1001191783Srmacklem * the nfsnode gets flushed out of the cache. Ufs does not have 1002191783Srmacklem * this problem, because one can identify root inodes by their 1003191783Srmacklem * number == ROOTINO (2). 1004191783Srmacklem */ 1005191783Srmacklem if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) && 1006191783Srmacklem nmp->nm_dirpathlen > 0) { 1007191783Srmacklem /* 1008191783Srmacklem * If the fhsize on the mount point == 0 for V4, the mount 1009191783Srmacklem * path needs to be looked up. 1010191783Srmacklem */ 1011191783Srmacklem trycnt = 3; 1012191783Srmacklem do { 1013191783Srmacklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 1014191783Srmacklem cred, td); 1015191783Srmacklem if (error) 1016191783Srmacklem (void) nfs_catnap(PZERO, "nfsgetdirp"); 1017191783Srmacklem } while (error && --trycnt > 0); 1018191783Srmacklem if (error) { 1019191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1020191783Srmacklem goto bad; 1021191783Srmacklem } 1022191783Srmacklem } 1023191783Srmacklem if (nmp->nm_fhsize > 0) { 1024191783Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np); 1025191783Srmacklem if (error) 1026191783Srmacklem goto bad; 1027191783Srmacklem *vpp = NFSTOV(np); 1028191783Srmacklem 1029191783Srmacklem /* 1030191783Srmacklem * Get file attributes and transfer parameters for the 1031191783Srmacklem * mountpoint. This has the side effect of filling in 1032191783Srmacklem * (*vpp)->v_type with the correct value. 1033191783Srmacklem */ 1034191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 1035191783Srmacklem cred, td, &nfsva, NULL); 1036191783Srmacklem if (ret) { 1037191783Srmacklem /* 1038191783Srmacklem * Just set default values to get things going. 1039191783Srmacklem */ 1040191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 1041191783Srmacklem nfsva.na_vattr.va_type = VDIR; 1042191783Srmacklem nfsva.na_vattr.va_mode = 0777; 1043191783Srmacklem nfsva.na_vattr.va_nlink = 100; 1044191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 1045191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 1046191783Srmacklem nfsva.na_vattr.va_fileid = 2; 1047191783Srmacklem nfsva.na_vattr.va_gen = 1; 1048191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 1049191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 1050191783Srmacklem } 1051191783Srmacklem (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1); 1052191783Srmacklem if (argp->flags & NFSMNT_NFSV3) 1053191783Srmacklem ncl_fsinfo(nmp, *vpp, cred, td); 1054191783Srmacklem 1055191783Srmacklem /* 1056191783Srmacklem * Lose the lock but keep the ref. 1057191783Srmacklem */ 1058191783Srmacklem VOP_UNLOCK(*vpp, 0); 1059191783Srmacklem return (0); 1060191783Srmacklem } 1061191783Srmacklem error = EIO; 1062191783Srmacklem 1063191783Srmacklembad: 1064191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1065191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1066191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1067191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1068191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1069191783Srmacklem FREE(nam, M_SONAME); 1070191783Srmacklem return (error); 1071191783Srmacklem} 1072191783Srmacklem 1073191783Srmacklem/* 1074191783Srmacklem * unmount system call 1075191783Srmacklem */ 1076191783Srmacklemstatic int 1077191990Sattilionfs_unmount(struct mount *mp, int mntflags) 1078191783Srmacklem{ 1079191990Sattilio struct thread *td; 1080191783Srmacklem struct nfsmount *nmp; 1081191783Srmacklem int error, flags = 0, trycnt = 0; 1082191783Srmacklem 1083191990Sattilio td = curthread; 1084191990Sattilio 1085191783Srmacklem if (mntflags & MNT_FORCE) 1086191783Srmacklem flags |= FORCECLOSE; 1087191783Srmacklem nmp = VFSTONFS(mp); 1088191783Srmacklem /* 1089191783Srmacklem * Goes something like this.. 1090191783Srmacklem * - Call vflush() to clear out vnodes for this filesystem 1091191783Srmacklem * - Close the socket 1092191783Srmacklem * - Free up the data structures 1093191783Srmacklem */ 1094191783Srmacklem /* In the forced case, cancel any outstanding requests. */ 1095191783Srmacklem if (mntflags & MNT_FORCE) { 1096191783Srmacklem error = newnfs_nmcancelreqs(nmp); 1097191783Srmacklem if (error) 1098191783Srmacklem goto out; 1099191783Srmacklem /* For a forced close, get rid of the renew thread now */ 1100191783Srmacklem nfscl_umount(nmp, td); 1101191783Srmacklem } 1102191783Srmacklem /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ 1103191783Srmacklem do { 1104191783Srmacklem error = vflush(mp, 1, flags, td); 1105191783Srmacklem if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30) 1106191783Srmacklem (void) nfs_catnap(PSOCK, "newndm"); 1107191783Srmacklem } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30); 1108191783Srmacklem if (error) 1109191783Srmacklem goto out; 1110191783Srmacklem 1111191783Srmacklem /* 1112191783Srmacklem * We are now committed to the unmount. 1113191783Srmacklem */ 1114191783Srmacklem if ((mntflags & MNT_FORCE) == 0) 1115191783Srmacklem nfscl_umount(nmp, td); 1116191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1117191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1118191783Srmacklem FREE(nmp->nm_nam, M_SONAME); 1119191783Srmacklem 1120191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1121191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1122191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1123191783Srmacklemout: 1124191783Srmacklem return (error); 1125191783Srmacklem} 1126191783Srmacklem 1127191783Srmacklem/* 1128191783Srmacklem * Return root of a filesystem 1129191783Srmacklem */ 1130191783Srmacklemstatic int 1131191990Sattilionfs_root(struct mount *mp, int flags, struct vnode **vpp) 1132191783Srmacklem{ 1133191783Srmacklem struct vnode *vp; 1134191783Srmacklem struct nfsmount *nmp; 1135191783Srmacklem struct nfsnode *np; 1136191783Srmacklem int error; 1137191783Srmacklem 1138191783Srmacklem nmp = VFSTONFS(mp); 1139191783Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np); 1140191783Srmacklem if (error) 1141191783Srmacklem return error; 1142191783Srmacklem vp = NFSTOV(np); 1143191783Srmacklem /* 1144191783Srmacklem * Get transfer parameters and attributes for root vnode once. 1145191783Srmacklem */ 1146191783Srmacklem mtx_lock(&nmp->nm_mtx); 1147191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 1148191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1149191783Srmacklem ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread); 1150191783Srmacklem } else 1151191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1152191783Srmacklem if (vp->v_type == VNON) 1153191783Srmacklem vp->v_type = VDIR; 1154191783Srmacklem vp->v_vflag |= VV_ROOT; 1155191783Srmacklem *vpp = vp; 1156191783Srmacklem return (0); 1157191783Srmacklem} 1158191783Srmacklem 1159191783Srmacklem/* 1160191783Srmacklem * Flush out the buffer cache 1161191783Srmacklem */ 1162191783Srmacklem/* ARGSUSED */ 1163191783Srmacklemstatic int 1164191990Sattilionfs_sync(struct mount *mp, int waitfor) 1165191783Srmacklem{ 1166191783Srmacklem struct vnode *vp, *mvp; 1167191990Sattilio struct thread *td; 1168191783Srmacklem int error, allerror = 0; 1169191783Srmacklem 1170191990Sattilio td = curthread; 1171191990Sattilio 1172191783Srmacklem /* 1173191783Srmacklem * Force stale buffer cache information to be flushed. 1174191783Srmacklem */ 1175191783Srmacklem MNT_ILOCK(mp); 1176191783Srmacklemloop: 1177191783Srmacklem MNT_VNODE_FOREACH(vp, mp, mvp) { 1178191783Srmacklem VI_LOCK(vp); 1179191783Srmacklem MNT_IUNLOCK(mp); 1180191783Srmacklem /* XXX Racy bv_cnt check. */ 1181191783Srmacklem if (VOP_ISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1182191783Srmacklem waitfor == MNT_LAZY) { 1183191783Srmacklem VI_UNLOCK(vp); 1184191783Srmacklem MNT_ILOCK(mp); 1185191783Srmacklem continue; 1186191783Srmacklem } 1187191783Srmacklem if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 1188191783Srmacklem MNT_ILOCK(mp); 1189191783Srmacklem MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); 1190191783Srmacklem goto loop; 1191191783Srmacklem } 1192191783Srmacklem error = VOP_FSYNC(vp, waitfor, td); 1193191783Srmacklem if (error) 1194191783Srmacklem allerror = error; 1195191783Srmacklem VOP_UNLOCK(vp, 0); 1196191783Srmacklem vrele(vp); 1197191783Srmacklem 1198191783Srmacklem MNT_ILOCK(mp); 1199191783Srmacklem } 1200191783Srmacklem MNT_IUNLOCK(mp); 1201191783Srmacklem return (allerror); 1202191783Srmacklem} 1203191783Srmacklem 1204191783Srmacklemstatic int 1205191783Srmacklemnfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 1206191783Srmacklem{ 1207191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1208191783Srmacklem struct vfsquery vq; 1209191783Srmacklem int error; 1210191783Srmacklem 1211191783Srmacklem bzero(&vq, sizeof(vq)); 1212191783Srmacklem switch (op) { 1213191783Srmacklem#if 0 1214191783Srmacklem case VFS_CTL_NOLOCKS: 1215191783Srmacklem val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; 1216191783Srmacklem if (req->oldptr != NULL) { 1217191783Srmacklem error = SYSCTL_OUT(req, &val, sizeof(val)); 1218191783Srmacklem if (error) 1219191783Srmacklem return (error); 1220191783Srmacklem } 1221191783Srmacklem if (req->newptr != NULL) { 1222191783Srmacklem error = SYSCTL_IN(req, &val, sizeof(val)); 1223191783Srmacklem if (error) 1224191783Srmacklem return (error); 1225191783Srmacklem if (val) 1226191783Srmacklem nmp->nm_flag |= NFSMNT_NOLOCKS; 1227191783Srmacklem else 1228191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOLOCKS; 1229191783Srmacklem } 1230191783Srmacklem break; 1231191783Srmacklem#endif 1232191783Srmacklem case VFS_CTL_QUERY: 1233191783Srmacklem mtx_lock(&nmp->nm_mtx); 1234191783Srmacklem if (nmp->nm_state & NFSSTA_TIMEO) 1235191783Srmacklem vq.vq_flags |= VQ_NOTRESP; 1236191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1237191783Srmacklem#if 0 1238191783Srmacklem if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && 1239191783Srmacklem (nmp->nm_state & NFSSTA_LOCKTIMEO)) 1240191783Srmacklem vq.vq_flags |= VQ_NOTRESPLOCK; 1241191783Srmacklem#endif 1242191783Srmacklem error = SYSCTL_OUT(req, &vq, sizeof(vq)); 1243191783Srmacklem break; 1244191783Srmacklem case VFS_CTL_TIMEO: 1245191783Srmacklem if (req->oldptr != NULL) { 1246191783Srmacklem error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, 1247191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1248191783Srmacklem if (error) 1249191783Srmacklem return (error); 1250191783Srmacklem } 1251191783Srmacklem if (req->newptr != NULL) { 1252191783Srmacklem error = vfs_suser(mp, req->td); 1253191783Srmacklem if (error) 1254191783Srmacklem return (error); 1255191783Srmacklem error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, 1256191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1257191783Srmacklem if (error) 1258191783Srmacklem return (error); 1259191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1260191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1261191783Srmacklem } 1262191783Srmacklem break; 1263191783Srmacklem default: 1264191783Srmacklem return (ENOTSUP); 1265191783Srmacklem } 1266191783Srmacklem return (0); 1267191783Srmacklem} 1268191783Srmacklem 1269