nfs_clvfsops.c revision 193066
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 193066 2009-05-29 21:27:12Z jamie $"); 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> 49191783Srmacklem#include <sys/lock.h> 50191783Srmacklem#include <sys/malloc.h> 51191783Srmacklem#include <sys/mbuf.h> 52191783Srmacklem#include <sys/module.h> 53191783Srmacklem#include <sys/mount.h> 54191783Srmacklem#include <sys/proc.h> 55191783Srmacklem#include <sys/socket.h> 56191783Srmacklem#include <sys/socketvar.h> 57191783Srmacklem#include <sys/sockio.h> 58191783Srmacklem#include <sys/sysctl.h> 59191783Srmacklem#include <sys/vnode.h> 60191783Srmacklem#include <sys/signalvar.h> 61191783Srmacklem 62191783Srmacklem#include <vm/vm.h> 63191783Srmacklem#include <vm/vm_extern.h> 64191783Srmacklem#include <vm/uma.h> 65191783Srmacklem 66191783Srmacklem#include <net/if.h> 67191783Srmacklem#include <net/route.h> 68191783Srmacklem#include <netinet/in.h> 69191783Srmacklem 70191783Srmacklem#include <fs/nfs/nfsport.h> 71191783Srmacklem#include <fs/nfsclient/nfsnode.h> 72191783Srmacklem#include <fs/nfsclient/nfsmount.h> 73191783Srmacklem#include <fs/nfsclient/nfs.h> 74191783Srmacklem#include <fs/nfsclient/nfsdiskless.h> 75191783Srmacklem 76191783Srmacklemextern int nfscl_ticks; 77191783Srmacklemextern struct timeval nfsboottime; 78191783Srmacklemextern struct nfsstats newnfsstats; 79191783Srmacklem 80191783SrmacklemMALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header"); 81191783SrmacklemMALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct"); 82191783Srmacklem 83191783SrmacklemSYSCTL_DECL(_vfs_newnfs); 84191783SrmacklemSYSCTL_STRUCT(_vfs_newnfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RW, 85191783Srmacklem &newnfsstats, nfsstats, "S,nfsstats"); 86191783Srmacklemstatic int nfs_ip_paranoia = 1; 87191783SrmacklemSYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW, 88191783Srmacklem &nfs_ip_paranoia, 0, ""); 89191783Srmacklemstatic int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY; 90191783SrmacklemSYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_INITIAL_DELAY, 91191783Srmacklem downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, ""); 92191783Srmacklem/* how long between console messages "nfs server foo not responding" */ 93191783Srmacklemstatic int nfs_tprintf_delay = NFS_TPRINTF_DELAY; 94191783SrmacklemSYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_DELAY, 95191783Srmacklem downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, ""); 96191783Srmacklem 97192585Srmacklemstatic void nfs_sec_name(char *, int *); 98191783Srmacklemstatic void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, 99191783Srmacklem struct nfs_args *argp, struct ucred *, struct thread *); 100191783Srmacklemstatic int mountnfs(struct nfs_args *, struct mount *, 101191783Srmacklem struct sockaddr *, char *, u_char *, u_char *, u_char *, 102191783Srmacklem struct vnode **, struct ucred *, struct thread *); 103191783Srmacklemstatic vfs_mount_t nfs_mount; 104191783Srmacklemstatic vfs_cmount_t nfs_cmount; 105191783Srmacklemstatic vfs_unmount_t nfs_unmount; 106191783Srmacklemstatic vfs_root_t nfs_root; 107191783Srmacklemstatic vfs_statfs_t nfs_statfs; 108191783Srmacklemstatic vfs_sync_t nfs_sync; 109191783Srmacklemstatic vfs_sysctl_t nfs_sysctl; 110191783Srmacklem 111191783Srmacklem/* 112191783Srmacklem * nfs vfs operations. 113191783Srmacklem */ 114191783Srmacklemstatic struct vfsops nfs_vfsops = { 115191783Srmacklem .vfs_init = ncl_init, 116191783Srmacklem .vfs_mount = nfs_mount, 117191783Srmacklem .vfs_cmount = nfs_cmount, 118191783Srmacklem .vfs_root = nfs_root, 119191783Srmacklem .vfs_statfs = nfs_statfs, 120191783Srmacklem .vfs_sync = nfs_sync, 121191783Srmacklem .vfs_uninit = ncl_uninit, 122191783Srmacklem .vfs_unmount = nfs_unmount, 123191783Srmacklem .vfs_sysctl = nfs_sysctl, 124191783Srmacklem}; 125191783SrmacklemVFS_SET(nfs_vfsops, newnfs, VFCF_NETWORK); 126191783Srmacklem 127191783Srmacklem/* So that loader and kldload(2) can find us, wherever we are.. */ 128191783SrmacklemMODULE_VERSION(newnfs, 1); 129191783Srmacklem 130191783Srmacklem/* 131191783Srmacklem * This structure must be filled in by a primary bootstrap or bootstrap 132191783Srmacklem * server for a diskless/dataless machine. It is initialized below just 133191783Srmacklem * to ensure that it is allocated to initialized data (.data not .bss). 134191783Srmacklem */ 135191783Srmacklemstruct nfs_diskless newnfs_diskless = { { { 0 } } }; 136191783Srmacklemstruct nfsv3_diskless newnfsv3_diskless = { { { 0 } } }; 137191783Srmacklemint newnfs_diskless_valid = 0; 138191783Srmacklem 139191783SrmacklemSYSCTL_INT(_vfs_newnfs, OID_AUTO, diskless_valid, CTLFLAG_RD, 140192145Srmacklem &newnfs_diskless_valid, 0, 141192145Srmacklem "Has the diskless struct been filled correctly"); 142191783Srmacklem 143191783SrmacklemSYSCTL_STRING(_vfs_newnfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD, 144192145Srmacklem newnfsv3_diskless.root_hostnam, 0, "Path to nfs root"); 145191783Srmacklem 146191783SrmacklemSYSCTL_OPAQUE(_vfs_newnfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD, 147192145Srmacklem &newnfsv3_diskless.root_saddr, sizeof newnfsv3_diskless.root_saddr, 148192145Srmacklem "%Ssockaddr_in", "Diskless root nfs address"); 149191783Srmacklem 150191783Srmacklem 151191783Srmacklemvoid newnfsargs_ntoh(struct nfs_args *); 152191783Srmacklemstatic int nfs_mountdiskless(char *, 153191783Srmacklem struct sockaddr_in *, struct nfs_args *, 154191783Srmacklem struct thread *, struct vnode **, struct mount *); 155191783Srmacklemstatic void nfs_convert_diskless(void); 156191783Srmacklemstatic void nfs_convert_oargs(struct nfs_args *args, 157191783Srmacklem struct onfs_args *oargs); 158191783Srmacklem 159191783Srmacklemint 160191783Srmacklemnewnfs_iosize(struct nfsmount *nmp) 161191783Srmacklem{ 162191783Srmacklem int iosize, maxio; 163191783Srmacklem 164191783Srmacklem /* First, set the upper limit for iosize */ 165191783Srmacklem if (nmp->nm_flag & NFSMNT_NFSV4) { 166191783Srmacklem maxio = NFS_MAXBSIZE; 167191783Srmacklem } else if (nmp->nm_flag & NFSMNT_NFSV3) { 168191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 169191783Srmacklem maxio = NFS_MAXDGRAMDATA; 170191783Srmacklem else 171191783Srmacklem maxio = NFS_MAXBSIZE; 172191783Srmacklem } else { 173191783Srmacklem maxio = NFS_V2MAXDATA; 174191783Srmacklem } 175191783Srmacklem if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0) 176191783Srmacklem nmp->nm_rsize = maxio; 177191783Srmacklem if (nmp->nm_rsize > MAXBSIZE) 178191783Srmacklem nmp->nm_rsize = MAXBSIZE; 179191783Srmacklem if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0) 180191783Srmacklem nmp->nm_readdirsize = maxio; 181191783Srmacklem if (nmp->nm_readdirsize > nmp->nm_rsize) 182191783Srmacklem nmp->nm_readdirsize = nmp->nm_rsize; 183191783Srmacklem if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0) 184191783Srmacklem nmp->nm_wsize = maxio; 185191783Srmacklem if (nmp->nm_wsize > MAXBSIZE) 186191783Srmacklem nmp->nm_wsize = MAXBSIZE; 187191783Srmacklem 188191783Srmacklem /* 189191783Srmacklem * Calculate the size used for io buffers. Use the larger 190191783Srmacklem * of the two sizes to minimise nfs requests but make sure 191191783Srmacklem * that it is at least one VM page to avoid wasting buffer 192191783Srmacklem * space. 193191783Srmacklem */ 194191783Srmacklem iosize = imax(nmp->nm_rsize, nmp->nm_wsize); 195191783Srmacklem iosize = imax(iosize, PAGE_SIZE); 196191783Srmacklem nmp->nm_mountp->mnt_stat.f_iosize = iosize; 197191783Srmacklem return (iosize); 198191783Srmacklem} 199191783Srmacklem 200191783Srmacklemstatic void 201191783Srmacklemnfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs) 202191783Srmacklem{ 203191783Srmacklem 204191783Srmacklem args->version = NFS_ARGSVERSION; 205191783Srmacklem args->addr = oargs->addr; 206191783Srmacklem args->addrlen = oargs->addrlen; 207191783Srmacklem args->sotype = oargs->sotype; 208191783Srmacklem args->proto = oargs->proto; 209191783Srmacklem args->fh = oargs->fh; 210191783Srmacklem args->fhsize = oargs->fhsize; 211191783Srmacklem args->flags = oargs->flags; 212191783Srmacklem args->wsize = oargs->wsize; 213191783Srmacklem args->rsize = oargs->rsize; 214191783Srmacklem args->readdirsize = oargs->readdirsize; 215191783Srmacklem args->timeo = oargs->timeo; 216191783Srmacklem args->retrans = oargs->retrans; 217191783Srmacklem args->readahead = oargs->readahead; 218191783Srmacklem args->hostname = oargs->hostname; 219191783Srmacklem} 220191783Srmacklem 221191783Srmacklemstatic void 222191783Srmacklemnfs_convert_diskless(void) 223191783Srmacklem{ 224191783Srmacklem 225191783Srmacklem bcopy(&newnfs_diskless.myif, &newnfsv3_diskless.myif, 226192145Srmacklem sizeof (struct ifaliasreq)); 227191783Srmacklem bcopy(&newnfs_diskless.mygateway, &newnfsv3_diskless.mygateway, 228192145Srmacklem sizeof (struct sockaddr_in)); 229192145Srmacklem nfs_convert_oargs(&newnfsv3_diskless.root_args, 230192145Srmacklem &newnfs_diskless.root_args); 231191783Srmacklem if (newnfsv3_diskless.root_args.flags & NFSMNT_NFSV3) { 232191783Srmacklem newnfsv3_diskless.root_fhsize = NFSX_MYFH; 233192145Srmacklem bcopy(newnfs_diskless.root_fh, newnfsv3_diskless.root_fh, 234192145Srmacklem NFSX_MYFH); 235191783Srmacklem } else { 236191783Srmacklem newnfsv3_diskless.root_fhsize = NFSX_V2FH; 237192145Srmacklem bcopy(newnfs_diskless.root_fh, newnfsv3_diskless.root_fh, 238192145Srmacklem NFSX_V2FH); 239191783Srmacklem } 240191783Srmacklem bcopy(&newnfs_diskless.root_saddr,&newnfsv3_diskless.root_saddr, 241192145Srmacklem sizeof(struct sockaddr_in)); 242192145Srmacklem bcopy(newnfs_diskless.root_hostnam, newnfsv3_diskless.root_hostnam, 243192145Srmacklem MNAMELEN); 244191783Srmacklem newnfsv3_diskless.root_time = newnfs_diskless.root_time; 245191783Srmacklem bcopy(newnfs_diskless.my_hostnam, newnfsv3_diskless.my_hostnam, 246192145Srmacklem MAXHOSTNAMELEN); 247191783Srmacklem newnfs_diskless_valid = 3; 248191783Srmacklem} 249191783Srmacklem 250191783Srmacklem/* 251191783Srmacklem * nfs statfs call 252191783Srmacklem */ 253191783Srmacklemstatic int 254191990Sattilionfs_statfs(struct mount *mp, struct statfs *sbp) 255191783Srmacklem{ 256191783Srmacklem struct vnode *vp; 257191990Sattilio struct thread *td; 258191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 259191783Srmacklem struct nfsvattr nfsva; 260191783Srmacklem struct nfsfsinfo fs; 261191783Srmacklem struct nfsstatfs sb; 262191783Srmacklem int error = 0, attrflag, gotfsinfo = 0, ret; 263191783Srmacklem struct nfsnode *np; 264191783Srmacklem 265191990Sattilio td = curthread; 266191990Sattilio 267191783Srmacklem error = vfs_busy(mp, MBF_NOWAIT); 268191783Srmacklem if (error) 269191783Srmacklem return (error); 270191783Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np); 271191783Srmacklem if (error) { 272191783Srmacklem vfs_unbusy(mp); 273191783Srmacklem return (error); 274191783Srmacklem } 275191783Srmacklem vp = NFSTOV(np); 276191783Srmacklem mtx_lock(&nmp->nm_mtx); 277191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 278191783Srmacklem mtx_unlock(&nmp->nm_mtx); 279191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva, 280191783Srmacklem &attrflag, NULL); 281191783Srmacklem if (!error) 282191783Srmacklem gotfsinfo = 1; 283191783Srmacklem } else 284191783Srmacklem mtx_unlock(&nmp->nm_mtx); 285191783Srmacklem if (!error) 286191783Srmacklem error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, 287191783Srmacklem &attrflag, NULL); 288191783Srmacklem if (attrflag == 0) { 289191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 290191783Srmacklem td->td_ucred, td, &nfsva, NULL); 291191783Srmacklem if (ret) { 292191783Srmacklem /* 293191783Srmacklem * Just set default values to get things going. 294191783Srmacklem */ 295191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 296191783Srmacklem nfsva.na_vattr.va_type = VDIR; 297191783Srmacklem nfsva.na_vattr.va_mode = 0777; 298191783Srmacklem nfsva.na_vattr.va_nlink = 100; 299191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 300191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 301191783Srmacklem nfsva.na_vattr.va_fileid = 2; 302191783Srmacklem nfsva.na_vattr.va_gen = 1; 303191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 304191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 305191783Srmacklem } 306191783Srmacklem } 307191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 308191783Srmacklem if (!error) { 309191783Srmacklem mtx_lock(&nmp->nm_mtx); 310191783Srmacklem if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4)) 311191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 312191783Srmacklem nfscl_loadsbinfo(nmp, &sb, sbp); 313191783Srmacklem sbp->f_flags = nmp->nm_flag; 314191783Srmacklem sbp->f_iosize = newnfs_iosize(nmp); 315191783Srmacklem mtx_unlock(&nmp->nm_mtx); 316191783Srmacklem if (sbp != &mp->mnt_stat) { 317191783Srmacklem bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 318191783Srmacklem bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 319191783Srmacklem } 320191783Srmacklem strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 321191783Srmacklem } else if (NFS_ISV4(vp)) { 322191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 323191783Srmacklem } 324191783Srmacklem vput(vp); 325191783Srmacklem vfs_unbusy(mp); 326191783Srmacklem return (error); 327191783Srmacklem} 328191783Srmacklem 329191783Srmacklem/* 330191783Srmacklem * nfs version 3 fsinfo rpc call 331191783Srmacklem */ 332191783Srmacklemint 333191783Srmacklemncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, 334191783Srmacklem struct thread *td) 335191783Srmacklem{ 336191783Srmacklem struct nfsfsinfo fs; 337191783Srmacklem struct nfsvattr nfsva; 338191783Srmacklem int error, attrflag; 339191783Srmacklem 340191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL); 341191783Srmacklem if (!error) { 342191783Srmacklem if (attrflag) 343191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 344191783Srmacklem 1); 345191783Srmacklem mtx_lock(&nmp->nm_mtx); 346191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 347191783Srmacklem mtx_unlock(&nmp->nm_mtx); 348191783Srmacklem } 349191783Srmacklem return (error); 350191783Srmacklem} 351191783Srmacklem 352191783Srmacklem/* 353191783Srmacklem * Mount a remote root fs via. nfs. This depends on the info in the 354191783Srmacklem * newnfs_diskless structure that has been filled in properly by some primary 355191783Srmacklem * bootstrap. 356191783Srmacklem * It goes something like this: 357191783Srmacklem * - do enough of "ifconfig" by calling ifioctl() so that the system 358191783Srmacklem * can talk to the server 359191783Srmacklem * - If newnfs_diskless.mygateway is filled in, use that address as 360191783Srmacklem * a default gateway. 361191783Srmacklem * - build the rootfs mount point and call mountnfs() to do the rest. 362191783Srmacklem * 363191783Srmacklem * It is assumed to be safe to read, modify, and write the nfsv3_diskless 364191783Srmacklem * structure, as well as other global NFS client variables here, as 365192145Srmacklem * nfs_mountroot() will be called once in the boot before any other NFS 366191783Srmacklem * client activity occurs. 367191783Srmacklem */ 368191783Srmacklemint 369192145Srmacklemncl_mountroot(struct mount *mp) 370191783Srmacklem{ 371192145Srmacklem struct thread *td = curthread; 372191783Srmacklem struct nfsv3_diskless *nd = &newnfsv3_diskless; 373191783Srmacklem struct socket *so; 374191783Srmacklem struct vnode *vp; 375191783Srmacklem struct ifreq ir; 376193066Sjamie int error; 377191783Srmacklem u_long l; 378191783Srmacklem char buf[128]; 379191783Srmacklem char *cp; 380191783Srmacklem 381191783Srmacklem#if defined(BOOTP_NFSROOT) && defined(BOOTP) 382192145Srmacklem bootpc_init(); /* use bootp to get nfs_diskless filled in */ 383191783Srmacklem#elif defined(NFS_ROOT) 384191783Srmacklem nfs_setup_diskless(); 385191783Srmacklem#endif 386191783Srmacklem 387191783Srmacklem if (newnfs_diskless_valid == 0) 388191783Srmacklem return (-1); 389191783Srmacklem if (newnfs_diskless_valid == 1) 390191783Srmacklem nfs_convert_diskless(); 391191783Srmacklem 392191783Srmacklem /* 393191783Srmacklem * XXX splnet, so networks will receive... 394191783Srmacklem */ 395191783Srmacklem splnet(); 396191783Srmacklem 397191783Srmacklem /* 398191783Srmacklem * Do enough of ifconfig(8) so that the critical net interface can 399191783Srmacklem * talk to the server. 400191783Srmacklem */ 401191783Srmacklem error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0, 402191783Srmacklem td->td_ucred, td); 403191783Srmacklem if (error) 404192145Srmacklem panic("nfs_mountroot: socreate(%04x): %d", 405191783Srmacklem nd->myif.ifra_addr.sa_family, error); 406191783Srmacklem 407191783Srmacklem#if 0 /* XXX Bad idea */ 408191783Srmacklem /* 409191783Srmacklem * We might not have been told the right interface, so we pass 410191783Srmacklem * over the first ten interfaces of the same kind, until we get 411191783Srmacklem * one of them configured. 412191783Srmacklem */ 413191783Srmacklem 414191783Srmacklem for (i = strlen(nd->myif.ifra_name) - 1; 415191783Srmacklem nd->myif.ifra_name[i] >= '0' && 416191783Srmacklem nd->myif.ifra_name[i] <= '9'; 417191783Srmacklem nd->myif.ifra_name[i] ++) { 418191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 419191783Srmacklem if(!error) 420191783Srmacklem break; 421191783Srmacklem } 422191783Srmacklem#endif 423191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 424191783Srmacklem if (error) 425192145Srmacklem panic("nfs_mountroot: SIOCAIFADDR: %d", error); 426191783Srmacklem if ((cp = getenv("boot.netif.mtu")) != NULL) { 427191783Srmacklem ir.ifr_mtu = strtol(cp, NULL, 10); 428191783Srmacklem bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); 429191783Srmacklem freeenv(cp); 430191783Srmacklem error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); 431191783Srmacklem if (error) 432192145Srmacklem printf("nfs_mountroot: SIOCSIFMTU: %d", error); 433191783Srmacklem } 434191783Srmacklem soclose(so); 435191783Srmacklem 436191783Srmacklem /* 437191783Srmacklem * If the gateway field is filled in, set it as the default route. 438191783Srmacklem * Note that pxeboot will set a default route of 0 if the route 439191783Srmacklem * is not set by the DHCP server. Check also for a value of 0 440191783Srmacklem * to avoid panicking inappropriately in that situation. 441191783Srmacklem */ 442191783Srmacklem if (nd->mygateway.sin_len != 0 && 443191783Srmacklem nd->mygateway.sin_addr.s_addr != 0) { 444191783Srmacklem struct sockaddr_in mask, sin; 445191783Srmacklem 446191783Srmacklem bzero((caddr_t)&mask, sizeof(mask)); 447191783Srmacklem sin = mask; 448191783Srmacklem sin.sin_family = AF_INET; 449191783Srmacklem sin.sin_len = sizeof(sin); 450192145Srmacklem /* XXX MRT use table 0 for this sort of thing */ 451191783Srmacklem error = rtrequest(RTM_ADD, (struct sockaddr *)&sin, 452191783Srmacklem (struct sockaddr *)&nd->mygateway, 453191783Srmacklem (struct sockaddr *)&mask, 454191783Srmacklem RTF_UP | RTF_GATEWAY, NULL); 455191783Srmacklem if (error) 456192145Srmacklem panic("nfs_mountroot: RTM_ADD: %d", error); 457191783Srmacklem } 458191783Srmacklem 459191783Srmacklem /* 460191783Srmacklem * Create the rootfs mount point. 461191783Srmacklem */ 462191783Srmacklem nd->root_args.fh = nd->root_fh; 463191783Srmacklem nd->root_args.fhsize = nd->root_fhsize; 464191783Srmacklem l = ntohl(nd->root_saddr.sin_addr.s_addr); 465191783Srmacklem snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", 466191783Srmacklem (l >> 24) & 0xff, (l >> 16) & 0xff, 467191783Srmacklem (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); 468191783Srmacklem printf("NFS ROOT: %s\n", buf); 469192145Srmacklem nd->root_args.hostname = buf; 470191783Srmacklem if ((error = nfs_mountdiskless(buf, 471191783Srmacklem &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { 472191783Srmacklem return (error); 473191783Srmacklem } 474191783Srmacklem 475191783Srmacklem /* 476191783Srmacklem * This is not really an nfs issue, but it is much easier to 477191783Srmacklem * set hostname here and then let the "/etc/rc.xxx" files 478191783Srmacklem * mount the right /var based upon its preset value. 479191783Srmacklem */ 480193066Sjamie mtx_lock(&prison0.pr_mtx); 481193066Sjamie strlcpy(prison0.pr_host, nd->my_hostnam, sizeof(prison0.pr_host)); 482193066Sjamie mtx_unlock(&prison0.pr_mtx); 483191783Srmacklem inittodr(ntohl(nd->root_time)); 484191783Srmacklem return (0); 485191783Srmacklem} 486191783Srmacklem 487191783Srmacklem/* 488191783Srmacklem * Internal version of mount system call for diskless setup. 489191783Srmacklem */ 490191783Srmacklemstatic int 491191783Srmacklemnfs_mountdiskless(char *path, 492191783Srmacklem struct sockaddr_in *sin, struct nfs_args *args, struct thread *td, 493191783Srmacklem struct vnode **vpp, struct mount *mp) 494191783Srmacklem{ 495191783Srmacklem struct sockaddr *nam; 496191783Srmacklem int error; 497191783Srmacklem 498191783Srmacklem nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); 499191783Srmacklem if ((error = mountnfs(args, mp, nam, path, NULL, NULL, NULL, vpp, 500191783Srmacklem td->td_ucred, td)) != 0) { 501192145Srmacklem printf("nfs_mountroot: mount %s on /: %d\n", path, error); 502191783Srmacklem return (error); 503191783Srmacklem } 504191783Srmacklem return (0); 505191783Srmacklem} 506191783Srmacklem 507191783Srmacklemstatic void 508192585Srmacklemnfs_sec_name(char *sec, int *flagsp) 509192585Srmacklem{ 510192585Srmacklem if (!strcmp(sec, "krb5")) 511192585Srmacklem *flagsp |= NFSMNT_KERB; 512192585Srmacklem else if (!strcmp(sec, "krb5i")) 513192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY); 514192585Srmacklem else if (!strcmp(sec, "krb5p")) 515192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY); 516192585Srmacklem} 517192585Srmacklem 518192585Srmacklemstatic void 519191783Srmacklemnfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, 520191783Srmacklem struct ucred *cred, struct thread *td) 521191783Srmacklem{ 522191783Srmacklem int s; 523191783Srmacklem int adjsock; 524191783Srmacklem 525191783Srmacklem s = splnet(); 526191783Srmacklem 527191783Srmacklem /* 528191783Srmacklem * Set read-only flag if requested; otherwise, clear it if this is 529191783Srmacklem * an update. If this is not an update, then either the read-only 530191783Srmacklem * flag is already clear, or this is a root mount and it was set 531191783Srmacklem * intentionally at some previous point. 532191783Srmacklem */ 533191783Srmacklem if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) { 534191783Srmacklem MNT_ILOCK(mp); 535191783Srmacklem mp->mnt_flag |= MNT_RDONLY; 536191783Srmacklem MNT_IUNLOCK(mp); 537191783Srmacklem } else if (mp->mnt_flag & MNT_UPDATE) { 538191783Srmacklem MNT_ILOCK(mp); 539191783Srmacklem mp->mnt_flag &= ~MNT_RDONLY; 540191783Srmacklem MNT_IUNLOCK(mp); 541191783Srmacklem } 542191783Srmacklem 543191783Srmacklem /* 544191783Srmacklem * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 545191783Srmacklem * no sense in that context. Also, set up appropriate retransmit 546191783Srmacklem * and soft timeout behavior. 547191783Srmacklem */ 548191783Srmacklem if (argp->sotype == SOCK_STREAM) { 549191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOCONN; 550191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 551191783Srmacklem } 552191783Srmacklem 553191783Srmacklem /* Also clear RDIRPLUS if not NFSv3, it crashes some servers */ 554191783Srmacklem if ((argp->flags & NFSMNT_NFSV3) == 0) 555191783Srmacklem nmp->nm_flag &= ~NFSMNT_RDIRPLUS; 556191783Srmacklem 557191783Srmacklem /* Also re-bind if we're switching to/from a connected UDP socket */ 558191783Srmacklem adjsock = ((nmp->nm_flag & NFSMNT_NOCONN) != 559191783Srmacklem (argp->flags & NFSMNT_NOCONN)); 560191783Srmacklem 561191783Srmacklem /* Update flags atomically. Don't change the lock bits. */ 562191783Srmacklem nmp->nm_flag = argp->flags | nmp->nm_flag; 563191783Srmacklem splx(s); 564191783Srmacklem 565191783Srmacklem if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 566191783Srmacklem nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 567191783Srmacklem if (nmp->nm_timeo < NFS_MINTIMEO) 568191783Srmacklem nmp->nm_timeo = NFS_MINTIMEO; 569191783Srmacklem else if (nmp->nm_timeo > NFS_MAXTIMEO) 570191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 571191783Srmacklem } 572191783Srmacklem 573191783Srmacklem if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 574191783Srmacklem nmp->nm_retry = argp->retrans; 575191783Srmacklem if (nmp->nm_retry > NFS_MAXREXMIT) 576191783Srmacklem nmp->nm_retry = NFS_MAXREXMIT; 577191783Srmacklem } 578191783Srmacklem 579191783Srmacklem if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 580191783Srmacklem nmp->nm_wsize = argp->wsize; 581191783Srmacklem /* Round down to multiple of blocksize */ 582191783Srmacklem nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); 583191783Srmacklem if (nmp->nm_wsize <= 0) 584191783Srmacklem nmp->nm_wsize = NFS_FABLKSIZE; 585191783Srmacklem } 586191783Srmacklem 587191783Srmacklem if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 588191783Srmacklem nmp->nm_rsize = argp->rsize; 589191783Srmacklem /* Round down to multiple of blocksize */ 590191783Srmacklem nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); 591191783Srmacklem if (nmp->nm_rsize <= 0) 592191783Srmacklem nmp->nm_rsize = NFS_FABLKSIZE; 593191783Srmacklem } 594191783Srmacklem 595191783Srmacklem if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 596191783Srmacklem nmp->nm_readdirsize = argp->readdirsize; 597191783Srmacklem } 598191783Srmacklem 599191783Srmacklem if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) 600191783Srmacklem nmp->nm_acregmin = argp->acregmin; 601191783Srmacklem else 602191783Srmacklem nmp->nm_acregmin = NFS_MINATTRTIMO; 603191783Srmacklem if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) 604191783Srmacklem nmp->nm_acregmax = argp->acregmax; 605191783Srmacklem else 606191783Srmacklem nmp->nm_acregmax = NFS_MAXATTRTIMO; 607191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) 608191783Srmacklem nmp->nm_acdirmin = argp->acdirmin; 609191783Srmacklem else 610191783Srmacklem nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; 611191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) 612191783Srmacklem nmp->nm_acdirmax = argp->acdirmax; 613191783Srmacklem else 614191783Srmacklem nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; 615191783Srmacklem if (nmp->nm_acdirmin > nmp->nm_acdirmax) 616191783Srmacklem nmp->nm_acdirmin = nmp->nm_acdirmax; 617191783Srmacklem if (nmp->nm_acregmin > nmp->nm_acregmax) 618191783Srmacklem nmp->nm_acregmin = nmp->nm_acregmax; 619191783Srmacklem 620191783Srmacklem if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { 621191783Srmacklem if (argp->readahead <= NFS_MAXRAHEAD) 622191783Srmacklem nmp->nm_readahead = argp->readahead; 623191783Srmacklem else 624191783Srmacklem nmp->nm_readahead = NFS_MAXRAHEAD; 625191783Srmacklem } 626191783Srmacklem if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) { 627191783Srmacklem if (argp->wcommitsize < nmp->nm_wsize) 628191783Srmacklem nmp->nm_wcommitsize = nmp->nm_wsize; 629191783Srmacklem else 630191783Srmacklem nmp->nm_wcommitsize = argp->wcommitsize; 631191783Srmacklem } 632191783Srmacklem 633191783Srmacklem adjsock |= ((nmp->nm_sotype != argp->sotype) || 634191783Srmacklem (nmp->nm_soproto != argp->proto)); 635191783Srmacklem 636191783Srmacklem if (nmp->nm_client != NULL && adjsock) { 637191783Srmacklem int haslock = 0, error = 0; 638191783Srmacklem 639191783Srmacklem if (nmp->nm_sotype == SOCK_STREAM) { 640191783Srmacklem error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock); 641191783Srmacklem if (!error) 642191783Srmacklem haslock = 1; 643191783Srmacklem } 644191783Srmacklem if (!error) { 645191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 646191783Srmacklem if (haslock) 647191783Srmacklem newnfs_sndunlock(&nmp->nm_sockreq.nr_lock); 648191783Srmacklem nmp->nm_sotype = argp->sotype; 649191783Srmacklem nmp->nm_soproto = argp->proto; 650191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 651191783Srmacklem while (newnfs_connect(nmp, &nmp->nm_sockreq, 652191783Srmacklem cred, td, 0)) { 653191783Srmacklem printf("newnfs_args: retrying connect\n"); 654191783Srmacklem (void) nfs_catnap(PSOCK, "newnfscon"); 655191783Srmacklem } 656191783Srmacklem } 657191783Srmacklem } else { 658191783Srmacklem nmp->nm_sotype = argp->sotype; 659191783Srmacklem nmp->nm_soproto = argp->proto; 660191783Srmacklem } 661191783Srmacklem} 662191783Srmacklem 663192585Srmacklemstatic const char *nfs_opts[] = { "from", 664191783Srmacklem "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union", 665191783Srmacklem "noclusterr", "noclusterw", "multilabel", "acls", "force", "update", 666192585Srmacklem "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus", 667192585Srmacklem "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize", 668192585Srmacklem "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport", 669192585Srmacklem "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec", 670192585Srmacklem "principal", "nfsv4", "gssname", "allgssname", "dirpath", 671191783Srmacklem NULL }; 672191783Srmacklem 673191783Srmacklem/* 674191783Srmacklem * VFS Operations. 675191783Srmacklem * 676191783Srmacklem * mount system call 677191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 678191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 679191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 680191783Srmacklem * an error after that means that I have to release the mbuf. 681191783Srmacklem */ 682191783Srmacklem/* ARGSUSED */ 683191783Srmacklemstatic int 684191990Sattilionfs_mount(struct mount *mp) 685191783Srmacklem{ 686191783Srmacklem struct nfs_args args = { 687191783Srmacklem .version = NFS_ARGSVERSION, 688191783Srmacklem .addr = NULL, 689191783Srmacklem .addrlen = sizeof (struct sockaddr_in), 690191783Srmacklem .sotype = SOCK_STREAM, 691191783Srmacklem .proto = 0, 692191783Srmacklem .fh = NULL, 693191783Srmacklem .fhsize = 0, 694191783Srmacklem .flags = 0, 695191783Srmacklem .wsize = NFS_WSIZE, 696191783Srmacklem .rsize = NFS_RSIZE, 697191783Srmacklem .readdirsize = NFS_READDIRSIZE, 698191783Srmacklem .timeo = 10, 699191783Srmacklem .retrans = NFS_RETRANS, 700191783Srmacklem .readahead = NFS_DEFRAHEAD, 701191783Srmacklem .wcommitsize = 0, /* was: NQ_DEFLEASE */ 702191783Srmacklem .hostname = NULL, 703191783Srmacklem /* args version 4 */ 704191783Srmacklem .acregmin = NFS_MINATTRTIMO, 705191783Srmacklem .acregmax = NFS_MAXATTRTIMO, 706191783Srmacklem .acdirmin = NFS_MINDIRATTRTIMO, 707191783Srmacklem .acdirmax = NFS_MAXDIRATTRTIMO, 708191783Srmacklem .dirlen = 0, 709191783Srmacklem .krbnamelen = 0, 710192585Srmacklem .srvkrbnamelen = 0, 711191783Srmacklem }; 712192585Srmacklem int error = 0, ret, len; 713192585Srmacklem struct sockaddr *nam = NULL; 714191783Srmacklem struct vnode *vp; 715191990Sattilio struct thread *td; 716191783Srmacklem char hst[MNAMELEN]; 717191783Srmacklem u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100]; 718192585Srmacklem char *opt, *name, *secname; 719191783Srmacklem 720191783Srmacklem if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) { 721191783Srmacklem error = EINVAL; 722191783Srmacklem goto out; 723191783Srmacklem } 724191783Srmacklem 725191990Sattilio td = curthread; 726191783Srmacklem if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) { 727192145Srmacklem error = ncl_mountroot(mp); 728191783Srmacklem goto out; 729191783Srmacklem } 730191783Srmacklem 731192585Srmacklem nfscl_init(); 732191783Srmacklem 733192585Srmacklem /* Handle the new style options. */ 734192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0) 735192585Srmacklem args.flags |= NFSMNT_NOCONN; 736192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0) 737192585Srmacklem args.flags |= NFSMNT_NOCONN; 738192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0) 739192585Srmacklem args.flags |= NFSMNT_NOLOCKD; 740192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0) 741192585Srmacklem args.flags &= ~NFSMNT_NOLOCKD; 742192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0) 743192585Srmacklem args.flags |= NFSMNT_INT; 744192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0) 745192585Srmacklem args.flags |= NFSMNT_RDIRPLUS; 746192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0) 747192585Srmacklem args.flags |= NFSMNT_RESVPORT; 748192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0) 749192585Srmacklem args.flags &= ~NFSMNT_RESVPORT; 750192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0) 751192585Srmacklem args.flags |= NFSMNT_SOFT; 752192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0) 753192585Srmacklem args.flags &= ~NFSMNT_SOFT; 754192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0) 755192585Srmacklem args.sotype = SOCK_DGRAM; 756192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0) 757192585Srmacklem args.sotype = SOCK_DGRAM; 758192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0) 759192585Srmacklem args.sotype = SOCK_STREAM; 760192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0) 761192585Srmacklem args.flags |= NFSMNT_NFSV3; 762192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) { 763192585Srmacklem args.flags |= NFSMNT_NFSV4; 764192585Srmacklem args.sotype = SOCK_STREAM; 765191783Srmacklem } 766192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0) 767192585Srmacklem args.flags |= NFSMNT_ALLGSSNAME; 768192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) { 769192585Srmacklem if (opt == NULL) { 770192585Srmacklem vfs_mount_error(mp, "illegal readdirsize"); 771192585Srmacklem error = EINVAL; 772192585Srmacklem goto out; 773192585Srmacklem } 774192585Srmacklem ret = sscanf(opt, "%d", &args.readdirsize); 775192585Srmacklem if (ret != 1 || args.readdirsize <= 0) { 776192585Srmacklem vfs_mount_error(mp, "illegal readdirsize: %s", 777192585Srmacklem opt); 778192585Srmacklem error = EINVAL; 779192585Srmacklem goto out; 780192585Srmacklem } 781192585Srmacklem args.flags |= NFSMNT_READDIRSIZE; 782192585Srmacklem } 783192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) { 784192585Srmacklem if (opt == NULL) { 785192585Srmacklem vfs_mount_error(mp, "illegal readahead"); 786192585Srmacklem error = EINVAL; 787192585Srmacklem goto out; 788192585Srmacklem } 789192585Srmacklem ret = sscanf(opt, "%d", &args.readahead); 790192585Srmacklem if (ret != 1 || args.readahead <= 0) { 791192585Srmacklem vfs_mount_error(mp, "illegal readahead: %s", 792192585Srmacklem opt); 793192585Srmacklem error = EINVAL; 794192585Srmacklem goto out; 795192585Srmacklem } 796192585Srmacklem args.flags |= NFSMNT_READAHEAD; 797192585Srmacklem } 798192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) { 799192585Srmacklem if (opt == NULL) { 800192585Srmacklem vfs_mount_error(mp, "illegal wsize"); 801192585Srmacklem error = EINVAL; 802192585Srmacklem goto out; 803192585Srmacklem } 804192585Srmacklem ret = sscanf(opt, "%d", &args.wsize); 805192585Srmacklem if (ret != 1 || args.wsize <= 0) { 806192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 807192585Srmacklem opt); 808192585Srmacklem error = EINVAL; 809192585Srmacklem goto out; 810192585Srmacklem } 811192585Srmacklem args.flags |= NFSMNT_WSIZE; 812192585Srmacklem } 813192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) { 814192585Srmacklem if (opt == NULL) { 815192585Srmacklem vfs_mount_error(mp, "illegal rsize"); 816192585Srmacklem error = EINVAL; 817192585Srmacklem goto out; 818192585Srmacklem } 819192585Srmacklem ret = sscanf(opt, "%d", &args.rsize); 820192585Srmacklem if (ret != 1 || args.rsize <= 0) { 821192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 822192585Srmacklem opt); 823192585Srmacklem error = EINVAL; 824192585Srmacklem goto out; 825192585Srmacklem } 826192585Srmacklem args.flags |= NFSMNT_RSIZE; 827192585Srmacklem } 828192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) { 829192585Srmacklem if (opt == NULL) { 830192585Srmacklem vfs_mount_error(mp, "illegal retrans"); 831192585Srmacklem error = EINVAL; 832192585Srmacklem goto out; 833192585Srmacklem } 834192585Srmacklem ret = sscanf(opt, "%d", &args.retrans); 835192585Srmacklem if (ret != 1 || args.retrans <= 0) { 836192585Srmacklem vfs_mount_error(mp, "illegal retrans: %s", 837192585Srmacklem opt); 838192585Srmacklem error = EINVAL; 839192585Srmacklem goto out; 840192585Srmacklem } 841192585Srmacklem args.flags |= NFSMNT_RETRANS; 842192585Srmacklem } 843192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) { 844192585Srmacklem ret = sscanf(opt, "%d", &args.acregmin); 845192585Srmacklem if (ret != 1 || args.acregmin < 0) { 846192585Srmacklem vfs_mount_error(mp, "illegal acregmin: %s", 847192585Srmacklem opt); 848192585Srmacklem error = EINVAL; 849192585Srmacklem goto out; 850192585Srmacklem } 851192585Srmacklem args.flags |= NFSMNT_ACREGMIN; 852192585Srmacklem } 853192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) { 854192585Srmacklem ret = sscanf(opt, "%d", &args.acregmax); 855192585Srmacklem if (ret != 1 || args.acregmax < 0) { 856192585Srmacklem vfs_mount_error(mp, "illegal acregmax: %s", 857192585Srmacklem opt); 858192585Srmacklem error = EINVAL; 859192585Srmacklem goto out; 860192585Srmacklem } 861192585Srmacklem args.flags |= NFSMNT_ACREGMAX; 862192585Srmacklem } 863192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) { 864192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmin); 865192585Srmacklem if (ret != 1 || args.acdirmin < 0) { 866192585Srmacklem vfs_mount_error(mp, "illegal acdirmin: %s", 867192585Srmacklem opt); 868192585Srmacklem error = EINVAL; 869192585Srmacklem goto out; 870192585Srmacklem } 871192585Srmacklem args.flags |= NFSMNT_ACDIRMIN; 872192585Srmacklem } 873192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) { 874192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmax); 875192585Srmacklem if (ret != 1 || args.acdirmax < 0) { 876192585Srmacklem vfs_mount_error(mp, "illegal acdirmax: %s", 877192585Srmacklem opt); 878192585Srmacklem error = EINVAL; 879192585Srmacklem goto out; 880192585Srmacklem } 881192585Srmacklem args.flags |= NFSMNT_ACDIRMAX; 882192585Srmacklem } 883192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) { 884192585Srmacklem ret = sscanf(opt, "%d", &args.timeo); 885192585Srmacklem if (ret != 1 || args.timeo <= 0) { 886192585Srmacklem vfs_mount_error(mp, "illegal timeout: %s", 887192585Srmacklem opt); 888192585Srmacklem error = EINVAL; 889192585Srmacklem goto out; 890192585Srmacklem } 891192585Srmacklem args.flags |= NFSMNT_TIMEO; 892192585Srmacklem } 893192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "sec", 894192585Srmacklem (void **) &secname, NULL) == 0) 895192585Srmacklem nfs_sec_name(secname, &args.flags); 896191783Srmacklem 897191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 898191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 899191783Srmacklem 900191783Srmacklem if (nmp == NULL) { 901191783Srmacklem error = EIO; 902191783Srmacklem goto out; 903191783Srmacklem } 904191783Srmacklem /* 905191783Srmacklem * When doing an update, we can't change version, 906191783Srmacklem * security, switch lockd strategies or change cookie 907191783Srmacklem * translation 908191783Srmacklem */ 909191783Srmacklem args.flags = (args.flags & 910191783Srmacklem ~(NFSMNT_NFSV3 | 911191783Srmacklem NFSMNT_NFSV4 | 912191783Srmacklem NFSMNT_KERB | 913191783Srmacklem NFSMNT_INTEGRITY | 914191783Srmacklem NFSMNT_PRIVACY | 915191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) | 916191783Srmacklem (nmp->nm_flag & 917191783Srmacklem (NFSMNT_NFSV3 | 918191783Srmacklem NFSMNT_NFSV4 | 919191783Srmacklem NFSMNT_KERB | 920191783Srmacklem NFSMNT_INTEGRITY | 921191783Srmacklem NFSMNT_PRIVACY | 922191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); 923191783Srmacklem nfs_decode_args(mp, nmp, &args, td->td_ucred, td); 924191783Srmacklem goto out; 925191783Srmacklem } 926191783Srmacklem 927191783Srmacklem /* 928191783Srmacklem * Make the nfs_ip_paranoia sysctl serve as the default connection 929191783Srmacklem * or no-connection mode for those protocols that support 930191783Srmacklem * no-connection mode (the flag will be cleared later for protocols 931191783Srmacklem * that do not support no-connection mode). This will allow a client 932191783Srmacklem * to receive replies from a different IP then the request was 933191783Srmacklem * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid), 934191783Srmacklem * not 0. 935191783Srmacklem */ 936191783Srmacklem if (nfs_ip_paranoia == 0) 937191783Srmacklem args.flags |= NFSMNT_NOCONN; 938192585Srmacklem 939192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh, 940192585Srmacklem &args.fhsize) == 0) { 941192585Srmacklem if (args.fhsize > NFSX_FHMAX) { 942192585Srmacklem vfs_mount_error(mp, "Bad file handle"); 943191783Srmacklem error = EINVAL; 944191783Srmacklem goto out; 945191783Srmacklem } 946192585Srmacklem bcopy(args.fh, nfh, args.fhsize); 947191783Srmacklem } else { 948192585Srmacklem args.fhsize = 0; 949192585Srmacklem } 950192585Srmacklem 951192585Srmacklem (void) vfs_getopt(mp->mnt_optnew, "hostname", (void **)&args.hostname, 952192585Srmacklem &len); 953192585Srmacklem if (args.hostname == NULL) { 954192585Srmacklem vfs_mount_error(mp, "Invalid hostname"); 955192585Srmacklem error = EINVAL; 956192585Srmacklem goto out; 957192585Srmacklem } 958192585Srmacklem bcopy(args.hostname, hst, MNAMELEN); 959192585Srmacklem hst[MNAMELEN - 1] = '\0'; 960192585Srmacklem 961192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0) 962192585Srmacklem strlcpy(srvkrbname, name, sizeof (srvkrbname)); 963192585Srmacklem else 964192585Srmacklem snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst); 965192585Srmacklem args.srvkrbnamelen = strlen(srvkrbname); 966192585Srmacklem 967192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0) 968192585Srmacklem strlcpy(krbname, name, sizeof (krbname)); 969192585Srmacklem else 970191783Srmacklem krbname[0] = '\0'; 971192585Srmacklem args.krbnamelen = strlen(krbname); 972192585Srmacklem 973192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0) 974192585Srmacklem strlcpy(dirpath, name, sizeof (dirpath)); 975192585Srmacklem else 976191783Srmacklem dirpath[0] = '\0'; 977192585Srmacklem args.dirlen = strlen(dirpath); 978192585Srmacklem 979192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "addr", (void **)&args.addr, 980192585Srmacklem &args.addrlen) == 0) { 981192585Srmacklem if (args.addrlen > SOCK_MAXADDRLEN) { 982192585Srmacklem error = ENAMETOOLONG; 983191783Srmacklem goto out; 984191783Srmacklem } 985192585Srmacklem nam = malloc(args.addrlen, M_SONAME, M_WAITOK); 986192585Srmacklem bcopy(args.addr, nam, args.addrlen); 987192585Srmacklem nam->sa_len = args.addrlen; 988191783Srmacklem } 989192585Srmacklem 990191783Srmacklem args.fh = nfh; 991191783Srmacklem error = mountnfs(&args, mp, nam, hst, krbname, dirpath, srvkrbname, 992191783Srmacklem &vp, td->td_ucred, td); 993191783Srmacklemout: 994191783Srmacklem if (!error) { 995191783Srmacklem MNT_ILOCK(mp); 996191783Srmacklem mp->mnt_kern_flag |= (MNTK_MPSAFE|MNTK_LOOKUP_SHARED); 997191783Srmacklem MNT_IUNLOCK(mp); 998191783Srmacklem } 999191783Srmacklem return (error); 1000191783Srmacklem} 1001191783Srmacklem 1002191783Srmacklem 1003191783Srmacklem/* 1004191783Srmacklem * VFS Operations. 1005191783Srmacklem * 1006191783Srmacklem * mount system call 1007191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 1008191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 1009191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 1010191783Srmacklem * an error after that means that I have to release the mbuf. 1011191783Srmacklem */ 1012191783Srmacklem/* ARGSUSED */ 1013191783Srmacklemstatic int 1014191990Sattilionfs_cmount(struct mntarg *ma, void *data, int flags) 1015191783Srmacklem{ 1016191783Srmacklem int error; 1017191783Srmacklem struct nfs_args args; 1018191783Srmacklem 1019191783Srmacklem error = copyin(data, &args, sizeof (struct nfs_args)); 1020191783Srmacklem if (error) 1021191783Srmacklem return error; 1022191783Srmacklem 1023191783Srmacklem ma = mount_arg(ma, "nfs_args", &args, sizeof args); 1024191783Srmacklem 1025191783Srmacklem error = kernel_mount(ma, flags); 1026191783Srmacklem return (error); 1027191783Srmacklem} 1028191783Srmacklem 1029191783Srmacklem/* 1030191783Srmacklem * Common code for mount and mountroot 1031191783Srmacklem */ 1032191783Srmacklemstatic int 1033191783Srmacklemmountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, 1034191783Srmacklem char *hst, u_char *krbname, u_char *dirpath, u_char *srvkrbname, 1035191783Srmacklem struct vnode **vpp, struct ucred *cred, struct thread *td) 1036191783Srmacklem{ 1037191783Srmacklem struct nfsmount *nmp; 1038191783Srmacklem struct nfsnode *np; 1039191783Srmacklem int error, trycnt, ret, clearintr; 1040191783Srmacklem struct nfsvattr nfsva; 1041191783Srmacklem static u_int64_t clval = 0; 1042191783Srmacklem 1043191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 1044191783Srmacklem nmp = VFSTONFS(mp); 1045191783Srmacklem printf("%s: MNT_UPDATE is no longer handled here\n", __func__); 1046191783Srmacklem FREE(nam, M_SONAME); 1047191783Srmacklem return (0); 1048191783Srmacklem } else { 1049191783Srmacklem MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) + 1050191783Srmacklem argp->krbnamelen + argp->dirlen + argp->srvkrbnamelen + 2, 1051191783Srmacklem M_NEWNFSMNT, M_WAITOK); 1052191783Srmacklem bzero((caddr_t)nmp, sizeof (struct nfsmount) + 1053191783Srmacklem argp->krbnamelen + argp->dirlen + argp->srvkrbnamelen + 2); 1054191783Srmacklem TAILQ_INIT(&nmp->nm_bufq); 1055191783Srmacklem if (clval == 0) 1056191783Srmacklem clval = (u_int64_t)nfsboottime.tv_sec; 1057191783Srmacklem nmp->nm_clval = clval++; 1058191783Srmacklem nmp->nm_krbnamelen = argp->krbnamelen; 1059191783Srmacklem nmp->nm_dirpathlen = argp->dirlen; 1060191783Srmacklem nmp->nm_srvkrbnamelen = argp->srvkrbnamelen; 1061192675Srmacklem if (td->td_ucred->cr_uid != (uid_t)0) { 1062191783Srmacklem /* 1063192675Srmacklem * nm_uid is used to get KerberosV credentials for 1064192675Srmacklem * the nfsv4 state handling operations if there is 1065192675Srmacklem * no host based principal set. Use the uid of 1066192675Srmacklem * this user if not root, since they are doing the 1067192675Srmacklem * mount. I don't think setting this for root will 1068192675Srmacklem * work, since root normally does not have user 1069192675Srmacklem * credentials in a credentials cache. 1070191783Srmacklem */ 1071192675Srmacklem nmp->nm_uid = td->td_ucred->cr_uid; 1072191783Srmacklem } else { 1073191783Srmacklem /* 1074192675Srmacklem * Just set to -1, so it won't be used. 1075191783Srmacklem */ 1076191783Srmacklem nmp->nm_uid = (uid_t)-1; 1077191783Srmacklem } 1078191783Srmacklem 1079191783Srmacklem /* Copy and null terminate all the names */ 1080191783Srmacklem if (nmp->nm_krbnamelen > 0) { 1081191783Srmacklem bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen); 1082191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen] = '\0'; 1083191783Srmacklem } 1084191783Srmacklem if (nmp->nm_dirpathlen > 0) { 1085191783Srmacklem bcopy(dirpath, NFSMNT_DIRPATH(nmp), 1086191783Srmacklem nmp->nm_dirpathlen); 1087191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1088191783Srmacklem + 1] = '\0'; 1089191783Srmacklem } 1090191783Srmacklem if (nmp->nm_srvkrbnamelen > 0) { 1091191783Srmacklem bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp), 1092191783Srmacklem nmp->nm_srvkrbnamelen); 1093191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1094191783Srmacklem + nmp->nm_srvkrbnamelen + 2] = '\0'; 1095191783Srmacklem } 1096191783Srmacklem nmp->nm_sockreq.nr_cred = crhold(cred); 1097191783Srmacklem mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF); 1098191783Srmacklem mp->mnt_data = nmp; 1099191783Srmacklem } 1100191783Srmacklem vfs_getnewfsid(mp); 1101191783Srmacklem nmp->nm_mountp = mp; 1102191783Srmacklem mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK); 1103191783Srmacklem 1104192585Srmacklem nfs_decode_args(mp, nmp, argp, cred, td); 1105192585Srmacklem 1106191783Srmacklem /* 1107191783Srmacklem * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too 1108191783Srmacklem * high, depending on whether we end up with negative offsets in 1109191783Srmacklem * the client or server somewhere. 2GB-1 may be safer. 1110191783Srmacklem * 1111191783Srmacklem * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum 1112191783Srmacklem * that we can handle until we find out otherwise. 1113191783Srmacklem * XXX Our "safe" limit on the client is what we can store in our 1114191783Srmacklem * buffer cache using signed(!) block numbers. 1115191783Srmacklem */ 1116191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) 1117191783Srmacklem nmp->nm_maxfilesize = 0xffffffffLL; 1118191783Srmacklem else 1119191783Srmacklem nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1; 1120191783Srmacklem 1121191783Srmacklem nmp->nm_timeo = NFS_TIMEO; 1122191783Srmacklem nmp->nm_retry = NFS_RETRANS; 1123191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 1124191783Srmacklem nmp->nm_wsize = NFS_WSIZE; 1125191783Srmacklem nmp->nm_rsize = NFS_RSIZE; 1126191783Srmacklem nmp->nm_readdirsize = NFS_READDIRSIZE; 1127191783Srmacklem } 1128191783Srmacklem nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000); 1129191783Srmacklem nmp->nm_numgrps = NFS_MAXGRPS; 1130191783Srmacklem nmp->nm_readahead = NFS_DEFRAHEAD; 1131191783Srmacklem nmp->nm_tprintf_delay = nfs_tprintf_delay; 1132191783Srmacklem if (nmp->nm_tprintf_delay < 0) 1133191783Srmacklem nmp->nm_tprintf_delay = 0; 1134191783Srmacklem nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay; 1135191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1136191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1137191783Srmacklem nmp->nm_fhsize = argp->fhsize; 1138191783Srmacklem if (nmp->nm_fhsize > 0) 1139191783Srmacklem bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 1140191783Srmacklem bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 1141191783Srmacklem nmp->nm_nam = nam; 1142191783Srmacklem /* Set up the sockets and per-host congestion */ 1143191783Srmacklem nmp->nm_sotype = argp->sotype; 1144191783Srmacklem nmp->nm_soproto = argp->proto; 1145191783Srmacklem nmp->nm_sockreq.nr_prog = NFS_PROG; 1146191783Srmacklem if ((argp->flags & NFSMNT_NFSV4)) 1147191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER4; 1148191783Srmacklem else if ((argp->flags & NFSMNT_NFSV3)) 1149191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER3; 1150191783Srmacklem else 1151191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER2; 1152191783Srmacklem 1153191783Srmacklem 1154191783Srmacklem /* 1155191783Srmacklem * For Connection based sockets (TCP,...) do the connect here, 1156191783Srmacklem * but make it interruptible, even for non-interuptible mounts. 1157191783Srmacklem */ 1158191783Srmacklem if ((nmp->nm_flag & NFSMNT_INT) == 0) { 1159191783Srmacklem nmp->nm_flag |= NFSMNT_INT; 1160191783Srmacklem clearintr = 1; 1161191783Srmacklem } else { 1162191783Srmacklem clearintr = 0; 1163191783Srmacklem } 1164191783Srmacklem if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0))) 1165191783Srmacklem goto bad; 1166191783Srmacklem if (clearintr) 1167191783Srmacklem nmp->nm_flag &= ~NFSMNT_INT; 1168191783Srmacklem 1169191783Srmacklem /* 1170191783Srmacklem * A reference count is needed on the nfsnode representing the 1171191783Srmacklem * remote root. If this object is not persistent, then backward 1172191783Srmacklem * traversals of the mount point (i.e. "..") will not work if 1173191783Srmacklem * the nfsnode gets flushed out of the cache. Ufs does not have 1174191783Srmacklem * this problem, because one can identify root inodes by their 1175191783Srmacklem * number == ROOTINO (2). 1176191783Srmacklem */ 1177191783Srmacklem if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) && 1178191783Srmacklem nmp->nm_dirpathlen > 0) { 1179191783Srmacklem /* 1180191783Srmacklem * If the fhsize on the mount point == 0 for V4, the mount 1181191783Srmacklem * path needs to be looked up. 1182191783Srmacklem */ 1183191783Srmacklem trycnt = 3; 1184191783Srmacklem do { 1185191783Srmacklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 1186191783Srmacklem cred, td); 1187191783Srmacklem if (error) 1188191783Srmacklem (void) nfs_catnap(PZERO, "nfsgetdirp"); 1189191783Srmacklem } while (error && --trycnt > 0); 1190191783Srmacklem if (error) { 1191191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1192191783Srmacklem goto bad; 1193191783Srmacklem } 1194191783Srmacklem } 1195191783Srmacklem if (nmp->nm_fhsize > 0) { 1196191783Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np); 1197191783Srmacklem if (error) 1198191783Srmacklem goto bad; 1199191783Srmacklem *vpp = NFSTOV(np); 1200191783Srmacklem 1201191783Srmacklem /* 1202191783Srmacklem * Get file attributes and transfer parameters for the 1203191783Srmacklem * mountpoint. This has the side effect of filling in 1204191783Srmacklem * (*vpp)->v_type with the correct value. 1205191783Srmacklem */ 1206191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 1207191783Srmacklem cred, td, &nfsva, NULL); 1208191783Srmacklem if (ret) { 1209191783Srmacklem /* 1210191783Srmacklem * Just set default values to get things going. 1211191783Srmacklem */ 1212191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 1213191783Srmacklem nfsva.na_vattr.va_type = VDIR; 1214191783Srmacklem nfsva.na_vattr.va_mode = 0777; 1215191783Srmacklem nfsva.na_vattr.va_nlink = 100; 1216191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 1217191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 1218191783Srmacklem nfsva.na_vattr.va_fileid = 2; 1219191783Srmacklem nfsva.na_vattr.va_gen = 1; 1220191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 1221191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 1222191783Srmacklem } 1223191783Srmacklem (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1); 1224191783Srmacklem if (argp->flags & NFSMNT_NFSV3) 1225191783Srmacklem ncl_fsinfo(nmp, *vpp, cred, td); 1226191783Srmacklem 1227191783Srmacklem /* 1228191783Srmacklem * Lose the lock but keep the ref. 1229191783Srmacklem */ 1230191783Srmacklem VOP_UNLOCK(*vpp, 0); 1231191783Srmacklem return (0); 1232191783Srmacklem } 1233191783Srmacklem error = EIO; 1234191783Srmacklem 1235191783Srmacklembad: 1236191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1237191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1238191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1239191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1240191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1241191783Srmacklem FREE(nam, M_SONAME); 1242191783Srmacklem return (error); 1243191783Srmacklem} 1244191783Srmacklem 1245191783Srmacklem/* 1246191783Srmacklem * unmount system call 1247191783Srmacklem */ 1248191783Srmacklemstatic int 1249191990Sattilionfs_unmount(struct mount *mp, int mntflags) 1250191783Srmacklem{ 1251191990Sattilio struct thread *td; 1252191783Srmacklem struct nfsmount *nmp; 1253191783Srmacklem int error, flags = 0, trycnt = 0; 1254191783Srmacklem 1255191990Sattilio td = curthread; 1256191990Sattilio 1257191783Srmacklem if (mntflags & MNT_FORCE) 1258191783Srmacklem flags |= FORCECLOSE; 1259191783Srmacklem nmp = VFSTONFS(mp); 1260191783Srmacklem /* 1261191783Srmacklem * Goes something like this.. 1262191783Srmacklem * - Call vflush() to clear out vnodes for this filesystem 1263191783Srmacklem * - Close the socket 1264191783Srmacklem * - Free up the data structures 1265191783Srmacklem */ 1266191783Srmacklem /* In the forced case, cancel any outstanding requests. */ 1267191783Srmacklem if (mntflags & MNT_FORCE) { 1268191783Srmacklem error = newnfs_nmcancelreqs(nmp); 1269191783Srmacklem if (error) 1270191783Srmacklem goto out; 1271191783Srmacklem /* For a forced close, get rid of the renew thread now */ 1272191783Srmacklem nfscl_umount(nmp, td); 1273191783Srmacklem } 1274191783Srmacklem /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ 1275191783Srmacklem do { 1276191783Srmacklem error = vflush(mp, 1, flags, td); 1277191783Srmacklem if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30) 1278191783Srmacklem (void) nfs_catnap(PSOCK, "newndm"); 1279191783Srmacklem } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30); 1280191783Srmacklem if (error) 1281191783Srmacklem goto out; 1282191783Srmacklem 1283191783Srmacklem /* 1284191783Srmacklem * We are now committed to the unmount. 1285191783Srmacklem */ 1286191783Srmacklem if ((mntflags & MNT_FORCE) == 0) 1287191783Srmacklem nfscl_umount(nmp, td); 1288191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1289191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1290191783Srmacklem FREE(nmp->nm_nam, M_SONAME); 1291191783Srmacklem 1292191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1293191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1294191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1295191783Srmacklemout: 1296191783Srmacklem return (error); 1297191783Srmacklem} 1298191783Srmacklem 1299191783Srmacklem/* 1300191783Srmacklem * Return root of a filesystem 1301191783Srmacklem */ 1302191783Srmacklemstatic int 1303191990Sattilionfs_root(struct mount *mp, int flags, struct vnode **vpp) 1304191783Srmacklem{ 1305191783Srmacklem struct vnode *vp; 1306191783Srmacklem struct nfsmount *nmp; 1307191783Srmacklem struct nfsnode *np; 1308191783Srmacklem int error; 1309191783Srmacklem 1310191783Srmacklem nmp = VFSTONFS(mp); 1311191783Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np); 1312191783Srmacklem if (error) 1313191783Srmacklem return error; 1314191783Srmacklem vp = NFSTOV(np); 1315191783Srmacklem /* 1316191783Srmacklem * Get transfer parameters and attributes for root vnode once. 1317191783Srmacklem */ 1318191783Srmacklem mtx_lock(&nmp->nm_mtx); 1319191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 1320191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1321191783Srmacklem ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread); 1322191783Srmacklem } else 1323191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1324191783Srmacklem if (vp->v_type == VNON) 1325191783Srmacklem vp->v_type = VDIR; 1326191783Srmacklem vp->v_vflag |= VV_ROOT; 1327191783Srmacklem *vpp = vp; 1328191783Srmacklem return (0); 1329191783Srmacklem} 1330191783Srmacklem 1331191783Srmacklem/* 1332191783Srmacklem * Flush out the buffer cache 1333191783Srmacklem */ 1334191783Srmacklem/* ARGSUSED */ 1335191783Srmacklemstatic int 1336191990Sattilionfs_sync(struct mount *mp, int waitfor) 1337191783Srmacklem{ 1338191783Srmacklem struct vnode *vp, *mvp; 1339191990Sattilio struct thread *td; 1340191783Srmacklem int error, allerror = 0; 1341191783Srmacklem 1342191990Sattilio td = curthread; 1343191990Sattilio 1344191783Srmacklem /* 1345191783Srmacklem * Force stale buffer cache information to be flushed. 1346191783Srmacklem */ 1347191783Srmacklem MNT_ILOCK(mp); 1348191783Srmacklemloop: 1349191783Srmacklem MNT_VNODE_FOREACH(vp, mp, mvp) { 1350191783Srmacklem VI_LOCK(vp); 1351191783Srmacklem MNT_IUNLOCK(mp); 1352191783Srmacklem /* XXX Racy bv_cnt check. */ 1353191783Srmacklem if (VOP_ISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1354191783Srmacklem waitfor == MNT_LAZY) { 1355191783Srmacklem VI_UNLOCK(vp); 1356191783Srmacklem MNT_ILOCK(mp); 1357191783Srmacklem continue; 1358191783Srmacklem } 1359191783Srmacklem if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 1360191783Srmacklem MNT_ILOCK(mp); 1361191783Srmacklem MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); 1362191783Srmacklem goto loop; 1363191783Srmacklem } 1364191783Srmacklem error = VOP_FSYNC(vp, waitfor, td); 1365191783Srmacklem if (error) 1366191783Srmacklem allerror = error; 1367191783Srmacklem VOP_UNLOCK(vp, 0); 1368191783Srmacklem vrele(vp); 1369191783Srmacklem 1370191783Srmacklem MNT_ILOCK(mp); 1371191783Srmacklem } 1372191783Srmacklem MNT_IUNLOCK(mp); 1373191783Srmacklem return (allerror); 1374191783Srmacklem} 1375191783Srmacklem 1376191783Srmacklemstatic int 1377191783Srmacklemnfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 1378191783Srmacklem{ 1379191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1380191783Srmacklem struct vfsquery vq; 1381191783Srmacklem int error; 1382191783Srmacklem 1383191783Srmacklem bzero(&vq, sizeof(vq)); 1384191783Srmacklem switch (op) { 1385191783Srmacklem#if 0 1386191783Srmacklem case VFS_CTL_NOLOCKS: 1387191783Srmacklem val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; 1388191783Srmacklem if (req->oldptr != NULL) { 1389191783Srmacklem error = SYSCTL_OUT(req, &val, sizeof(val)); 1390191783Srmacklem if (error) 1391191783Srmacklem return (error); 1392191783Srmacklem } 1393191783Srmacklem if (req->newptr != NULL) { 1394191783Srmacklem error = SYSCTL_IN(req, &val, sizeof(val)); 1395191783Srmacklem if (error) 1396191783Srmacklem return (error); 1397191783Srmacklem if (val) 1398191783Srmacklem nmp->nm_flag |= NFSMNT_NOLOCKS; 1399191783Srmacklem else 1400191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOLOCKS; 1401191783Srmacklem } 1402191783Srmacklem break; 1403191783Srmacklem#endif 1404191783Srmacklem case VFS_CTL_QUERY: 1405191783Srmacklem mtx_lock(&nmp->nm_mtx); 1406191783Srmacklem if (nmp->nm_state & NFSSTA_TIMEO) 1407191783Srmacklem vq.vq_flags |= VQ_NOTRESP; 1408191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1409191783Srmacklem#if 0 1410191783Srmacklem if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && 1411191783Srmacklem (nmp->nm_state & NFSSTA_LOCKTIMEO)) 1412191783Srmacklem vq.vq_flags |= VQ_NOTRESPLOCK; 1413191783Srmacklem#endif 1414191783Srmacklem error = SYSCTL_OUT(req, &vq, sizeof(vq)); 1415191783Srmacklem break; 1416191783Srmacklem case VFS_CTL_TIMEO: 1417191783Srmacklem if (req->oldptr != NULL) { 1418191783Srmacklem error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, 1419191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1420191783Srmacklem if (error) 1421191783Srmacklem return (error); 1422191783Srmacklem } 1423191783Srmacklem if (req->newptr != NULL) { 1424191783Srmacklem error = vfs_suser(mp, req->td); 1425191783Srmacklem if (error) 1426191783Srmacklem return (error); 1427191783Srmacklem error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, 1428191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1429191783Srmacklem if (error) 1430191783Srmacklem return (error); 1431191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1432191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1433191783Srmacklem } 1434191783Srmacklem break; 1435191783Srmacklem default: 1436191783Srmacklem return (ENOTSUP); 1437191783Srmacklem } 1438191783Srmacklem return (0); 1439191783Srmacklem} 1440191783Srmacklem 1441