nfs_clvfsops.c revision 192675
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 192675 2009-05-24 03:22:49Z rmacklem $"); 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 96192585Srmacklemstatic void nfs_sec_name(char *, int *); 97191783Srmacklemstatic void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, 98191783Srmacklem struct nfs_args *argp, struct ucred *, struct thread *); 99191783Srmacklemstatic int mountnfs(struct nfs_args *, struct mount *, 100191783Srmacklem struct sockaddr *, char *, u_char *, u_char *, u_char *, 101191783Srmacklem struct vnode **, struct ucred *, struct thread *); 102191783Srmacklemstatic vfs_mount_t nfs_mount; 103191783Srmacklemstatic vfs_cmount_t nfs_cmount; 104191783Srmacklemstatic vfs_unmount_t nfs_unmount; 105191783Srmacklemstatic vfs_root_t nfs_root; 106191783Srmacklemstatic vfs_statfs_t nfs_statfs; 107191783Srmacklemstatic vfs_sync_t nfs_sync; 108191783Srmacklemstatic vfs_sysctl_t nfs_sysctl; 109191783Srmacklem 110191783Srmacklem/* 111191783Srmacklem * nfs vfs operations. 112191783Srmacklem */ 113191783Srmacklemstatic struct vfsops nfs_vfsops = { 114191783Srmacklem .vfs_init = ncl_init, 115191783Srmacklem .vfs_mount = nfs_mount, 116191783Srmacklem .vfs_cmount = nfs_cmount, 117191783Srmacklem .vfs_root = nfs_root, 118191783Srmacklem .vfs_statfs = nfs_statfs, 119191783Srmacklem .vfs_sync = nfs_sync, 120191783Srmacklem .vfs_uninit = ncl_uninit, 121191783Srmacklem .vfs_unmount = nfs_unmount, 122191783Srmacklem .vfs_sysctl = nfs_sysctl, 123191783Srmacklem}; 124191783SrmacklemVFS_SET(nfs_vfsops, newnfs, VFCF_NETWORK); 125191783Srmacklem 126191783Srmacklem/* So that loader and kldload(2) can find us, wherever we are.. */ 127191783SrmacklemMODULE_VERSION(newnfs, 1); 128191783Srmacklem 129191783Srmacklem/* 130191783Srmacklem * This structure must be filled in by a primary bootstrap or bootstrap 131191783Srmacklem * server for a diskless/dataless machine. It is initialized below just 132191783Srmacklem * to ensure that it is allocated to initialized data (.data not .bss). 133191783Srmacklem */ 134191783Srmacklemstruct nfs_diskless newnfs_diskless = { { { 0 } } }; 135191783Srmacklemstruct nfsv3_diskless newnfsv3_diskless = { { { 0 } } }; 136191783Srmacklemint newnfs_diskless_valid = 0; 137191783Srmacklem 138191783SrmacklemSYSCTL_INT(_vfs_newnfs, OID_AUTO, diskless_valid, CTLFLAG_RD, 139192145Srmacklem &newnfs_diskless_valid, 0, 140192145Srmacklem "Has the diskless struct been filled correctly"); 141191783Srmacklem 142191783SrmacklemSYSCTL_STRING(_vfs_newnfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD, 143192145Srmacklem newnfsv3_diskless.root_hostnam, 0, "Path to nfs root"); 144191783Srmacklem 145191783SrmacklemSYSCTL_OPAQUE(_vfs_newnfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD, 146192145Srmacklem &newnfsv3_diskless.root_saddr, sizeof newnfsv3_diskless.root_saddr, 147192145Srmacklem "%Ssockaddr_in", "Diskless root nfs address"); 148191783Srmacklem 149191783Srmacklem 150191783Srmacklemvoid newnfsargs_ntoh(struct nfs_args *); 151191783Srmacklemstatic int nfs_mountdiskless(char *, 152191783Srmacklem struct sockaddr_in *, struct nfs_args *, 153191783Srmacklem struct thread *, struct vnode **, struct mount *); 154191783Srmacklemstatic void nfs_convert_diskless(void); 155191783Srmacklemstatic void nfs_convert_oargs(struct nfs_args *args, 156191783Srmacklem struct onfs_args *oargs); 157191783Srmacklem 158191783Srmacklemint 159191783Srmacklemnewnfs_iosize(struct nfsmount *nmp) 160191783Srmacklem{ 161191783Srmacklem int iosize, maxio; 162191783Srmacklem 163191783Srmacklem /* First, set the upper limit for iosize */ 164191783Srmacklem if (nmp->nm_flag & NFSMNT_NFSV4) { 165191783Srmacklem maxio = NFS_MAXBSIZE; 166191783Srmacklem } else if (nmp->nm_flag & NFSMNT_NFSV3) { 167191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 168191783Srmacklem maxio = NFS_MAXDGRAMDATA; 169191783Srmacklem else 170191783Srmacklem maxio = NFS_MAXBSIZE; 171191783Srmacklem } else { 172191783Srmacklem maxio = NFS_V2MAXDATA; 173191783Srmacklem } 174191783Srmacklem if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0) 175191783Srmacklem nmp->nm_rsize = maxio; 176191783Srmacklem if (nmp->nm_rsize > MAXBSIZE) 177191783Srmacklem nmp->nm_rsize = MAXBSIZE; 178191783Srmacklem if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0) 179191783Srmacklem nmp->nm_readdirsize = maxio; 180191783Srmacklem if (nmp->nm_readdirsize > nmp->nm_rsize) 181191783Srmacklem nmp->nm_readdirsize = nmp->nm_rsize; 182191783Srmacklem if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0) 183191783Srmacklem nmp->nm_wsize = maxio; 184191783Srmacklem if (nmp->nm_wsize > MAXBSIZE) 185191783Srmacklem nmp->nm_wsize = MAXBSIZE; 186191783Srmacklem 187191783Srmacklem /* 188191783Srmacklem * Calculate the size used for io buffers. Use the larger 189191783Srmacklem * of the two sizes to minimise nfs requests but make sure 190191783Srmacklem * that it is at least one VM page to avoid wasting buffer 191191783Srmacklem * space. 192191783Srmacklem */ 193191783Srmacklem iosize = imax(nmp->nm_rsize, nmp->nm_wsize); 194191783Srmacklem iosize = imax(iosize, PAGE_SIZE); 195191783Srmacklem nmp->nm_mountp->mnt_stat.f_iosize = iosize; 196191783Srmacklem return (iosize); 197191783Srmacklem} 198191783Srmacklem 199191783Srmacklemstatic void 200191783Srmacklemnfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs) 201191783Srmacklem{ 202191783Srmacklem 203191783Srmacklem args->version = NFS_ARGSVERSION; 204191783Srmacklem args->addr = oargs->addr; 205191783Srmacklem args->addrlen = oargs->addrlen; 206191783Srmacklem args->sotype = oargs->sotype; 207191783Srmacklem args->proto = oargs->proto; 208191783Srmacklem args->fh = oargs->fh; 209191783Srmacklem args->fhsize = oargs->fhsize; 210191783Srmacklem args->flags = oargs->flags; 211191783Srmacklem args->wsize = oargs->wsize; 212191783Srmacklem args->rsize = oargs->rsize; 213191783Srmacklem args->readdirsize = oargs->readdirsize; 214191783Srmacklem args->timeo = oargs->timeo; 215191783Srmacklem args->retrans = oargs->retrans; 216191783Srmacklem args->readahead = oargs->readahead; 217191783Srmacklem args->hostname = oargs->hostname; 218191783Srmacklem} 219191783Srmacklem 220191783Srmacklemstatic void 221191783Srmacklemnfs_convert_diskless(void) 222191783Srmacklem{ 223191783Srmacklem 224191783Srmacklem bcopy(&newnfs_diskless.myif, &newnfsv3_diskless.myif, 225192145Srmacklem sizeof (struct ifaliasreq)); 226191783Srmacklem bcopy(&newnfs_diskless.mygateway, &newnfsv3_diskless.mygateway, 227192145Srmacklem sizeof (struct sockaddr_in)); 228192145Srmacklem nfs_convert_oargs(&newnfsv3_diskless.root_args, 229192145Srmacklem &newnfs_diskless.root_args); 230191783Srmacklem if (newnfsv3_diskless.root_args.flags & NFSMNT_NFSV3) { 231191783Srmacklem newnfsv3_diskless.root_fhsize = NFSX_MYFH; 232192145Srmacklem bcopy(newnfs_diskless.root_fh, newnfsv3_diskless.root_fh, 233192145Srmacklem NFSX_MYFH); 234191783Srmacklem } else { 235191783Srmacklem newnfsv3_diskless.root_fhsize = NFSX_V2FH; 236192145Srmacklem bcopy(newnfs_diskless.root_fh, newnfsv3_diskless.root_fh, 237192145Srmacklem NFSX_V2FH); 238191783Srmacklem } 239191783Srmacklem bcopy(&newnfs_diskless.root_saddr,&newnfsv3_diskless.root_saddr, 240192145Srmacklem sizeof(struct sockaddr_in)); 241192145Srmacklem bcopy(newnfs_diskless.root_hostnam, newnfsv3_diskless.root_hostnam, 242192145Srmacklem MNAMELEN); 243191783Srmacklem newnfsv3_diskless.root_time = newnfs_diskless.root_time; 244191783Srmacklem bcopy(newnfs_diskless.my_hostnam, newnfsv3_diskless.my_hostnam, 245192145Srmacklem MAXHOSTNAMELEN); 246191783Srmacklem newnfs_diskless_valid = 3; 247191783Srmacklem} 248191783Srmacklem 249191783Srmacklem/* 250191783Srmacklem * nfs statfs call 251191783Srmacklem */ 252191783Srmacklemstatic int 253191990Sattilionfs_statfs(struct mount *mp, struct statfs *sbp) 254191783Srmacklem{ 255191783Srmacklem struct vnode *vp; 256191990Sattilio struct thread *td; 257191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 258191783Srmacklem struct nfsvattr nfsva; 259191783Srmacklem struct nfsfsinfo fs; 260191783Srmacklem struct nfsstatfs sb; 261191783Srmacklem int error = 0, attrflag, gotfsinfo = 0, ret; 262191783Srmacklem struct nfsnode *np; 263191783Srmacklem 264191990Sattilio td = curthread; 265191990Sattilio 266191783Srmacklem error = vfs_busy(mp, MBF_NOWAIT); 267191783Srmacklem if (error) 268191783Srmacklem return (error); 269191783Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np); 270191783Srmacklem if (error) { 271191783Srmacklem vfs_unbusy(mp); 272191783Srmacklem return (error); 273191783Srmacklem } 274191783Srmacklem vp = NFSTOV(np); 275191783Srmacklem mtx_lock(&nmp->nm_mtx); 276191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 277191783Srmacklem mtx_unlock(&nmp->nm_mtx); 278191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva, 279191783Srmacklem &attrflag, NULL); 280191783Srmacklem if (!error) 281191783Srmacklem gotfsinfo = 1; 282191783Srmacklem } else 283191783Srmacklem mtx_unlock(&nmp->nm_mtx); 284191783Srmacklem if (!error) 285191783Srmacklem error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, 286191783Srmacklem &attrflag, NULL); 287191783Srmacklem if (attrflag == 0) { 288191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 289191783Srmacklem td->td_ucred, td, &nfsva, NULL); 290191783Srmacklem if (ret) { 291191783Srmacklem /* 292191783Srmacklem * Just set default values to get things going. 293191783Srmacklem */ 294191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 295191783Srmacklem nfsva.na_vattr.va_type = VDIR; 296191783Srmacklem nfsva.na_vattr.va_mode = 0777; 297191783Srmacklem nfsva.na_vattr.va_nlink = 100; 298191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 299191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 300191783Srmacklem nfsva.na_vattr.va_fileid = 2; 301191783Srmacklem nfsva.na_vattr.va_gen = 1; 302191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 303191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 304191783Srmacklem } 305191783Srmacklem } 306191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 307191783Srmacklem if (!error) { 308191783Srmacklem mtx_lock(&nmp->nm_mtx); 309191783Srmacklem if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4)) 310191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 311191783Srmacklem nfscl_loadsbinfo(nmp, &sb, sbp); 312191783Srmacklem sbp->f_flags = nmp->nm_flag; 313191783Srmacklem sbp->f_iosize = newnfs_iosize(nmp); 314191783Srmacklem mtx_unlock(&nmp->nm_mtx); 315191783Srmacklem if (sbp != &mp->mnt_stat) { 316191783Srmacklem bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 317191783Srmacklem bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 318191783Srmacklem } 319191783Srmacklem strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 320191783Srmacklem } else if (NFS_ISV4(vp)) { 321191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 322191783Srmacklem } 323191783Srmacklem vput(vp); 324191783Srmacklem vfs_unbusy(mp); 325191783Srmacklem return (error); 326191783Srmacklem} 327191783Srmacklem 328191783Srmacklem/* 329191783Srmacklem * nfs version 3 fsinfo rpc call 330191783Srmacklem */ 331191783Srmacklemint 332191783Srmacklemncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, 333191783Srmacklem struct thread *td) 334191783Srmacklem{ 335191783Srmacklem struct nfsfsinfo fs; 336191783Srmacklem struct nfsvattr nfsva; 337191783Srmacklem int error, attrflag; 338191783Srmacklem 339191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL); 340191783Srmacklem if (!error) { 341191783Srmacklem if (attrflag) 342191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 343191783Srmacklem 1); 344191783Srmacklem mtx_lock(&nmp->nm_mtx); 345191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 346191783Srmacklem mtx_unlock(&nmp->nm_mtx); 347191783Srmacklem } 348191783Srmacklem return (error); 349191783Srmacklem} 350191783Srmacklem 351191783Srmacklem/* 352191783Srmacklem * Mount a remote root fs via. nfs. This depends on the info in the 353191783Srmacklem * newnfs_diskless structure that has been filled in properly by some primary 354191783Srmacklem * bootstrap. 355191783Srmacklem * It goes something like this: 356191783Srmacklem * - do enough of "ifconfig" by calling ifioctl() so that the system 357191783Srmacklem * can talk to the server 358191783Srmacklem * - If newnfs_diskless.mygateway is filled in, use that address as 359191783Srmacklem * a default gateway. 360191783Srmacklem * - build the rootfs mount point and call mountnfs() to do the rest. 361191783Srmacklem * 362191783Srmacklem * It is assumed to be safe to read, modify, and write the nfsv3_diskless 363191783Srmacklem * structure, as well as other global NFS client variables here, as 364192145Srmacklem * nfs_mountroot() will be called once in the boot before any other NFS 365191783Srmacklem * client activity occurs. 366191783Srmacklem */ 367191783Srmacklemint 368192145Srmacklemncl_mountroot(struct mount *mp) 369191783Srmacklem{ 370192145Srmacklem struct thread *td = curthread; 371192145Srmacklem INIT_VPROCG(TD_TO_VPROCG(td)); 372191783Srmacklem struct nfsv3_diskless *nd = &newnfsv3_diskless; 373191783Srmacklem struct socket *so; 374191783Srmacklem struct vnode *vp; 375191783Srmacklem struct ifreq ir; 376191783Srmacklem int error, i; 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 */ 480192145Srmacklem mtx_lock(&hostname_mtx); 481192145Srmacklem bcopy(nd->my_hostnam, V_hostname, MAXHOSTNAMELEN); 482192145Srmacklem V_hostname[MAXHOSTNAMELEN - 1] = '\0'; 483191783Srmacklem for (i = 0; i < MAXHOSTNAMELEN; i++) 484192145Srmacklem if (V_hostname[i] == '\0') 485191783Srmacklem break; 486192145Srmacklem mtx_unlock(&hostname_mtx); 487191783Srmacklem inittodr(ntohl(nd->root_time)); 488191783Srmacklem return (0); 489191783Srmacklem} 490191783Srmacklem 491191783Srmacklem/* 492191783Srmacklem * Internal version of mount system call for diskless setup. 493191783Srmacklem */ 494191783Srmacklemstatic int 495191783Srmacklemnfs_mountdiskless(char *path, 496191783Srmacklem struct sockaddr_in *sin, struct nfs_args *args, struct thread *td, 497191783Srmacklem struct vnode **vpp, struct mount *mp) 498191783Srmacklem{ 499191783Srmacklem struct sockaddr *nam; 500191783Srmacklem int error; 501191783Srmacklem 502191783Srmacklem nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); 503191783Srmacklem if ((error = mountnfs(args, mp, nam, path, NULL, NULL, NULL, vpp, 504191783Srmacklem td->td_ucred, td)) != 0) { 505192145Srmacklem printf("nfs_mountroot: mount %s on /: %d\n", path, error); 506191783Srmacklem return (error); 507191783Srmacklem } 508191783Srmacklem return (0); 509191783Srmacklem} 510191783Srmacklem 511191783Srmacklemstatic void 512192585Srmacklemnfs_sec_name(char *sec, int *flagsp) 513192585Srmacklem{ 514192585Srmacklem if (!strcmp(sec, "krb5")) 515192585Srmacklem *flagsp |= NFSMNT_KERB; 516192585Srmacklem else if (!strcmp(sec, "krb5i")) 517192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY); 518192585Srmacklem else if (!strcmp(sec, "krb5p")) 519192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY); 520192585Srmacklem} 521192585Srmacklem 522192585Srmacklemstatic void 523191783Srmacklemnfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, 524191783Srmacklem struct ucred *cred, struct thread *td) 525191783Srmacklem{ 526191783Srmacklem int s; 527191783Srmacklem int adjsock; 528191783Srmacklem 529191783Srmacklem s = splnet(); 530191783Srmacklem 531191783Srmacklem /* 532191783Srmacklem * Set read-only flag if requested; otherwise, clear it if this is 533191783Srmacklem * an update. If this is not an update, then either the read-only 534191783Srmacklem * flag is already clear, or this is a root mount and it was set 535191783Srmacklem * intentionally at some previous point. 536191783Srmacklem */ 537191783Srmacklem if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) { 538191783Srmacklem MNT_ILOCK(mp); 539191783Srmacklem mp->mnt_flag |= MNT_RDONLY; 540191783Srmacklem MNT_IUNLOCK(mp); 541191783Srmacklem } else if (mp->mnt_flag & MNT_UPDATE) { 542191783Srmacklem MNT_ILOCK(mp); 543191783Srmacklem mp->mnt_flag &= ~MNT_RDONLY; 544191783Srmacklem MNT_IUNLOCK(mp); 545191783Srmacklem } 546191783Srmacklem 547191783Srmacklem /* 548191783Srmacklem * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 549191783Srmacklem * no sense in that context. Also, set up appropriate retransmit 550191783Srmacklem * and soft timeout behavior. 551191783Srmacklem */ 552191783Srmacklem if (argp->sotype == SOCK_STREAM) { 553191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOCONN; 554191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 555191783Srmacklem } 556191783Srmacklem 557191783Srmacklem /* Also clear RDIRPLUS if not NFSv3, it crashes some servers */ 558191783Srmacklem if ((argp->flags & NFSMNT_NFSV3) == 0) 559191783Srmacklem nmp->nm_flag &= ~NFSMNT_RDIRPLUS; 560191783Srmacklem 561191783Srmacklem /* Also re-bind if we're switching to/from a connected UDP socket */ 562191783Srmacklem adjsock = ((nmp->nm_flag & NFSMNT_NOCONN) != 563191783Srmacklem (argp->flags & NFSMNT_NOCONN)); 564191783Srmacklem 565191783Srmacklem /* Update flags atomically. Don't change the lock bits. */ 566191783Srmacklem nmp->nm_flag = argp->flags | nmp->nm_flag; 567191783Srmacklem splx(s); 568191783Srmacklem 569191783Srmacklem if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 570191783Srmacklem nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 571191783Srmacklem if (nmp->nm_timeo < NFS_MINTIMEO) 572191783Srmacklem nmp->nm_timeo = NFS_MINTIMEO; 573191783Srmacklem else if (nmp->nm_timeo > NFS_MAXTIMEO) 574191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 575191783Srmacklem } 576191783Srmacklem 577191783Srmacklem if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 578191783Srmacklem nmp->nm_retry = argp->retrans; 579191783Srmacklem if (nmp->nm_retry > NFS_MAXREXMIT) 580191783Srmacklem nmp->nm_retry = NFS_MAXREXMIT; 581191783Srmacklem } 582191783Srmacklem 583191783Srmacklem if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 584191783Srmacklem nmp->nm_wsize = argp->wsize; 585191783Srmacklem /* Round down to multiple of blocksize */ 586191783Srmacklem nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); 587191783Srmacklem if (nmp->nm_wsize <= 0) 588191783Srmacklem nmp->nm_wsize = NFS_FABLKSIZE; 589191783Srmacklem } 590191783Srmacklem 591191783Srmacklem if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 592191783Srmacklem nmp->nm_rsize = argp->rsize; 593191783Srmacklem /* Round down to multiple of blocksize */ 594191783Srmacklem nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); 595191783Srmacklem if (nmp->nm_rsize <= 0) 596191783Srmacklem nmp->nm_rsize = NFS_FABLKSIZE; 597191783Srmacklem } 598191783Srmacklem 599191783Srmacklem if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 600191783Srmacklem nmp->nm_readdirsize = argp->readdirsize; 601191783Srmacklem } 602191783Srmacklem 603191783Srmacklem if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) 604191783Srmacklem nmp->nm_acregmin = argp->acregmin; 605191783Srmacklem else 606191783Srmacklem nmp->nm_acregmin = NFS_MINATTRTIMO; 607191783Srmacklem if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) 608191783Srmacklem nmp->nm_acregmax = argp->acregmax; 609191783Srmacklem else 610191783Srmacklem nmp->nm_acregmax = NFS_MAXATTRTIMO; 611191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) 612191783Srmacklem nmp->nm_acdirmin = argp->acdirmin; 613191783Srmacklem else 614191783Srmacklem nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; 615191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) 616191783Srmacklem nmp->nm_acdirmax = argp->acdirmax; 617191783Srmacklem else 618191783Srmacklem nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; 619191783Srmacklem if (nmp->nm_acdirmin > nmp->nm_acdirmax) 620191783Srmacklem nmp->nm_acdirmin = nmp->nm_acdirmax; 621191783Srmacklem if (nmp->nm_acregmin > nmp->nm_acregmax) 622191783Srmacklem nmp->nm_acregmin = nmp->nm_acregmax; 623191783Srmacklem 624191783Srmacklem if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { 625191783Srmacklem if (argp->readahead <= NFS_MAXRAHEAD) 626191783Srmacklem nmp->nm_readahead = argp->readahead; 627191783Srmacklem else 628191783Srmacklem nmp->nm_readahead = NFS_MAXRAHEAD; 629191783Srmacklem } 630191783Srmacklem if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) { 631191783Srmacklem if (argp->wcommitsize < nmp->nm_wsize) 632191783Srmacklem nmp->nm_wcommitsize = nmp->nm_wsize; 633191783Srmacklem else 634191783Srmacklem nmp->nm_wcommitsize = argp->wcommitsize; 635191783Srmacklem } 636191783Srmacklem 637191783Srmacklem adjsock |= ((nmp->nm_sotype != argp->sotype) || 638191783Srmacklem (nmp->nm_soproto != argp->proto)); 639191783Srmacklem 640191783Srmacklem if (nmp->nm_client != NULL && adjsock) { 641191783Srmacklem int haslock = 0, error = 0; 642191783Srmacklem 643191783Srmacklem if (nmp->nm_sotype == SOCK_STREAM) { 644191783Srmacklem error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock); 645191783Srmacklem if (!error) 646191783Srmacklem haslock = 1; 647191783Srmacklem } 648191783Srmacklem if (!error) { 649191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 650191783Srmacklem if (haslock) 651191783Srmacklem newnfs_sndunlock(&nmp->nm_sockreq.nr_lock); 652191783Srmacklem nmp->nm_sotype = argp->sotype; 653191783Srmacklem nmp->nm_soproto = argp->proto; 654191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 655191783Srmacklem while (newnfs_connect(nmp, &nmp->nm_sockreq, 656191783Srmacklem cred, td, 0)) { 657191783Srmacklem printf("newnfs_args: retrying connect\n"); 658191783Srmacklem (void) nfs_catnap(PSOCK, "newnfscon"); 659191783Srmacklem } 660191783Srmacklem } 661191783Srmacklem } else { 662191783Srmacklem nmp->nm_sotype = argp->sotype; 663191783Srmacklem nmp->nm_soproto = argp->proto; 664191783Srmacklem } 665191783Srmacklem} 666191783Srmacklem 667192585Srmacklemstatic const char *nfs_opts[] = { "from", 668191783Srmacklem "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union", 669191783Srmacklem "noclusterr", "noclusterw", "multilabel", "acls", "force", "update", 670192585Srmacklem "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus", 671192585Srmacklem "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize", 672192585Srmacklem "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport", 673192585Srmacklem "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec", 674192585Srmacklem "principal", "nfsv4", "gssname", "allgssname", "dirpath", 675191783Srmacklem NULL }; 676191783Srmacklem 677191783Srmacklem/* 678191783Srmacklem * VFS Operations. 679191783Srmacklem * 680191783Srmacklem * mount system call 681191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 682191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 683191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 684191783Srmacklem * an error after that means that I have to release the mbuf. 685191783Srmacklem */ 686191783Srmacklem/* ARGSUSED */ 687191783Srmacklemstatic int 688191990Sattilionfs_mount(struct mount *mp) 689191783Srmacklem{ 690191783Srmacklem struct nfs_args args = { 691191783Srmacklem .version = NFS_ARGSVERSION, 692191783Srmacklem .addr = NULL, 693191783Srmacklem .addrlen = sizeof (struct sockaddr_in), 694191783Srmacklem .sotype = SOCK_STREAM, 695191783Srmacklem .proto = 0, 696191783Srmacklem .fh = NULL, 697191783Srmacklem .fhsize = 0, 698191783Srmacklem .flags = 0, 699191783Srmacklem .wsize = NFS_WSIZE, 700191783Srmacklem .rsize = NFS_RSIZE, 701191783Srmacklem .readdirsize = NFS_READDIRSIZE, 702191783Srmacklem .timeo = 10, 703191783Srmacklem .retrans = NFS_RETRANS, 704191783Srmacklem .readahead = NFS_DEFRAHEAD, 705191783Srmacklem .wcommitsize = 0, /* was: NQ_DEFLEASE */ 706191783Srmacklem .hostname = NULL, 707191783Srmacklem /* args version 4 */ 708191783Srmacklem .acregmin = NFS_MINATTRTIMO, 709191783Srmacklem .acregmax = NFS_MAXATTRTIMO, 710191783Srmacklem .acdirmin = NFS_MINDIRATTRTIMO, 711191783Srmacklem .acdirmax = NFS_MAXDIRATTRTIMO, 712191783Srmacklem .dirlen = 0, 713191783Srmacklem .krbnamelen = 0, 714192585Srmacklem .srvkrbnamelen = 0, 715191783Srmacklem }; 716192585Srmacklem int error = 0, ret, len; 717192585Srmacklem struct sockaddr *nam = NULL; 718191783Srmacklem struct vnode *vp; 719191990Sattilio struct thread *td; 720191783Srmacklem char hst[MNAMELEN]; 721191783Srmacklem u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100]; 722192585Srmacklem char *opt, *name, *secname; 723191783Srmacklem 724191783Srmacklem if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) { 725191783Srmacklem error = EINVAL; 726191783Srmacklem goto out; 727191783Srmacklem } 728191783Srmacklem 729191990Sattilio td = curthread; 730191783Srmacklem if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) { 731192145Srmacklem error = ncl_mountroot(mp); 732191783Srmacklem goto out; 733191783Srmacklem } 734191783Srmacklem 735192585Srmacklem nfscl_init(); 736191783Srmacklem 737192585Srmacklem /* Handle the new style options. */ 738192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0) 739192585Srmacklem args.flags |= NFSMNT_NOCONN; 740192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0) 741192585Srmacklem args.flags |= NFSMNT_NOCONN; 742192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0) 743192585Srmacklem args.flags |= NFSMNT_NOLOCKD; 744192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0) 745192585Srmacklem args.flags &= ~NFSMNT_NOLOCKD; 746192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0) 747192585Srmacklem args.flags |= NFSMNT_INT; 748192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0) 749192585Srmacklem args.flags |= NFSMNT_RDIRPLUS; 750192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0) 751192585Srmacklem args.flags |= NFSMNT_RESVPORT; 752192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0) 753192585Srmacklem args.flags &= ~NFSMNT_RESVPORT; 754192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0) 755192585Srmacklem args.flags |= NFSMNT_SOFT; 756192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0) 757192585Srmacklem args.flags &= ~NFSMNT_SOFT; 758192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0) 759192585Srmacklem args.sotype = SOCK_DGRAM; 760192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0) 761192585Srmacklem args.sotype = SOCK_DGRAM; 762192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0) 763192585Srmacklem args.sotype = SOCK_STREAM; 764192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0) 765192585Srmacklem args.flags |= NFSMNT_NFSV3; 766192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) { 767192585Srmacklem args.flags |= NFSMNT_NFSV4; 768192585Srmacklem args.sotype = SOCK_STREAM; 769191783Srmacklem } 770192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0) 771192585Srmacklem args.flags |= NFSMNT_ALLGSSNAME; 772192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) { 773192585Srmacklem if (opt == NULL) { 774192585Srmacklem vfs_mount_error(mp, "illegal readdirsize"); 775192585Srmacklem error = EINVAL; 776192585Srmacklem goto out; 777192585Srmacklem } 778192585Srmacklem ret = sscanf(opt, "%d", &args.readdirsize); 779192585Srmacklem if (ret != 1 || args.readdirsize <= 0) { 780192585Srmacklem vfs_mount_error(mp, "illegal readdirsize: %s", 781192585Srmacklem opt); 782192585Srmacklem error = EINVAL; 783192585Srmacklem goto out; 784192585Srmacklem } 785192585Srmacklem args.flags |= NFSMNT_READDIRSIZE; 786192585Srmacklem } 787192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) { 788192585Srmacklem if (opt == NULL) { 789192585Srmacklem vfs_mount_error(mp, "illegal readahead"); 790192585Srmacklem error = EINVAL; 791192585Srmacklem goto out; 792192585Srmacklem } 793192585Srmacklem ret = sscanf(opt, "%d", &args.readahead); 794192585Srmacklem if (ret != 1 || args.readahead <= 0) { 795192585Srmacklem vfs_mount_error(mp, "illegal readahead: %s", 796192585Srmacklem opt); 797192585Srmacklem error = EINVAL; 798192585Srmacklem goto out; 799192585Srmacklem } 800192585Srmacklem args.flags |= NFSMNT_READAHEAD; 801192585Srmacklem } 802192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) { 803192585Srmacklem if (opt == NULL) { 804192585Srmacklem vfs_mount_error(mp, "illegal wsize"); 805192585Srmacklem error = EINVAL; 806192585Srmacklem goto out; 807192585Srmacklem } 808192585Srmacklem ret = sscanf(opt, "%d", &args.wsize); 809192585Srmacklem if (ret != 1 || args.wsize <= 0) { 810192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 811192585Srmacklem opt); 812192585Srmacklem error = EINVAL; 813192585Srmacklem goto out; 814192585Srmacklem } 815192585Srmacklem args.flags |= NFSMNT_WSIZE; 816192585Srmacklem } 817192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) { 818192585Srmacklem if (opt == NULL) { 819192585Srmacklem vfs_mount_error(mp, "illegal rsize"); 820192585Srmacklem error = EINVAL; 821192585Srmacklem goto out; 822192585Srmacklem } 823192585Srmacklem ret = sscanf(opt, "%d", &args.rsize); 824192585Srmacklem if (ret != 1 || args.rsize <= 0) { 825192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 826192585Srmacklem opt); 827192585Srmacklem error = EINVAL; 828192585Srmacklem goto out; 829192585Srmacklem } 830192585Srmacklem args.flags |= NFSMNT_RSIZE; 831192585Srmacklem } 832192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) { 833192585Srmacklem if (opt == NULL) { 834192585Srmacklem vfs_mount_error(mp, "illegal retrans"); 835192585Srmacklem error = EINVAL; 836192585Srmacklem goto out; 837192585Srmacklem } 838192585Srmacklem ret = sscanf(opt, "%d", &args.retrans); 839192585Srmacklem if (ret != 1 || args.retrans <= 0) { 840192585Srmacklem vfs_mount_error(mp, "illegal retrans: %s", 841192585Srmacklem opt); 842192585Srmacklem error = EINVAL; 843192585Srmacklem goto out; 844192585Srmacklem } 845192585Srmacklem args.flags |= NFSMNT_RETRANS; 846192585Srmacklem } 847192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) { 848192585Srmacklem ret = sscanf(opt, "%d", &args.acregmin); 849192585Srmacklem if (ret != 1 || args.acregmin < 0) { 850192585Srmacklem vfs_mount_error(mp, "illegal acregmin: %s", 851192585Srmacklem opt); 852192585Srmacklem error = EINVAL; 853192585Srmacklem goto out; 854192585Srmacklem } 855192585Srmacklem args.flags |= NFSMNT_ACREGMIN; 856192585Srmacklem } 857192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) { 858192585Srmacklem ret = sscanf(opt, "%d", &args.acregmax); 859192585Srmacklem if (ret != 1 || args.acregmax < 0) { 860192585Srmacklem vfs_mount_error(mp, "illegal acregmax: %s", 861192585Srmacklem opt); 862192585Srmacklem error = EINVAL; 863192585Srmacklem goto out; 864192585Srmacklem } 865192585Srmacklem args.flags |= NFSMNT_ACREGMAX; 866192585Srmacklem } 867192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) { 868192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmin); 869192585Srmacklem if (ret != 1 || args.acdirmin < 0) { 870192585Srmacklem vfs_mount_error(mp, "illegal acdirmin: %s", 871192585Srmacklem opt); 872192585Srmacklem error = EINVAL; 873192585Srmacklem goto out; 874192585Srmacklem } 875192585Srmacklem args.flags |= NFSMNT_ACDIRMIN; 876192585Srmacklem } 877192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) { 878192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmax); 879192585Srmacklem if (ret != 1 || args.acdirmax < 0) { 880192585Srmacklem vfs_mount_error(mp, "illegal acdirmax: %s", 881192585Srmacklem opt); 882192585Srmacklem error = EINVAL; 883192585Srmacklem goto out; 884192585Srmacklem } 885192585Srmacklem args.flags |= NFSMNT_ACDIRMAX; 886192585Srmacklem } 887192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) { 888192585Srmacklem ret = sscanf(opt, "%d", &args.timeo); 889192585Srmacklem if (ret != 1 || args.timeo <= 0) { 890192585Srmacklem vfs_mount_error(mp, "illegal timeout: %s", 891192585Srmacklem opt); 892192585Srmacklem error = EINVAL; 893192585Srmacklem goto out; 894192585Srmacklem } 895192585Srmacklem args.flags |= NFSMNT_TIMEO; 896192585Srmacklem } 897192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "sec", 898192585Srmacklem (void **) &secname, NULL) == 0) 899192585Srmacklem nfs_sec_name(secname, &args.flags); 900191783Srmacklem 901191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 902191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 903191783Srmacklem 904191783Srmacklem if (nmp == NULL) { 905191783Srmacklem error = EIO; 906191783Srmacklem goto out; 907191783Srmacklem } 908191783Srmacklem /* 909191783Srmacklem * When doing an update, we can't change version, 910191783Srmacklem * security, switch lockd strategies or change cookie 911191783Srmacklem * translation 912191783Srmacklem */ 913191783Srmacklem args.flags = (args.flags & 914191783Srmacklem ~(NFSMNT_NFSV3 | 915191783Srmacklem NFSMNT_NFSV4 | 916191783Srmacklem NFSMNT_KERB | 917191783Srmacklem NFSMNT_INTEGRITY | 918191783Srmacklem NFSMNT_PRIVACY | 919191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) | 920191783Srmacklem (nmp->nm_flag & 921191783Srmacklem (NFSMNT_NFSV3 | 922191783Srmacklem NFSMNT_NFSV4 | 923191783Srmacklem NFSMNT_KERB | 924191783Srmacklem NFSMNT_INTEGRITY | 925191783Srmacklem NFSMNT_PRIVACY | 926191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); 927191783Srmacklem nfs_decode_args(mp, nmp, &args, td->td_ucred, td); 928191783Srmacklem goto out; 929191783Srmacklem } 930191783Srmacklem 931191783Srmacklem /* 932191783Srmacklem * Make the nfs_ip_paranoia sysctl serve as the default connection 933191783Srmacklem * or no-connection mode for those protocols that support 934191783Srmacklem * no-connection mode (the flag will be cleared later for protocols 935191783Srmacklem * that do not support no-connection mode). This will allow a client 936191783Srmacklem * to receive replies from a different IP then the request was 937191783Srmacklem * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid), 938191783Srmacklem * not 0. 939191783Srmacklem */ 940191783Srmacklem if (nfs_ip_paranoia == 0) 941191783Srmacklem args.flags |= NFSMNT_NOCONN; 942192585Srmacklem 943192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh, 944192585Srmacklem &args.fhsize) == 0) { 945192585Srmacklem if (args.fhsize > NFSX_FHMAX) { 946192585Srmacklem vfs_mount_error(mp, "Bad file handle"); 947191783Srmacklem error = EINVAL; 948191783Srmacklem goto out; 949191783Srmacklem } 950192585Srmacklem bcopy(args.fh, nfh, args.fhsize); 951191783Srmacklem } else { 952192585Srmacklem args.fhsize = 0; 953192585Srmacklem } 954192585Srmacklem 955192585Srmacklem (void) vfs_getopt(mp->mnt_optnew, "hostname", (void **)&args.hostname, 956192585Srmacklem &len); 957192585Srmacklem if (args.hostname == NULL) { 958192585Srmacklem vfs_mount_error(mp, "Invalid hostname"); 959192585Srmacklem error = EINVAL; 960192585Srmacklem goto out; 961192585Srmacklem } 962192585Srmacklem bcopy(args.hostname, hst, MNAMELEN); 963192585Srmacklem hst[MNAMELEN - 1] = '\0'; 964192585Srmacklem 965192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0) 966192585Srmacklem strlcpy(srvkrbname, name, sizeof (srvkrbname)); 967192585Srmacklem else 968192585Srmacklem snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst); 969192585Srmacklem args.srvkrbnamelen = strlen(srvkrbname); 970192585Srmacklem 971192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0) 972192585Srmacklem strlcpy(krbname, name, sizeof (krbname)); 973192585Srmacklem else 974191783Srmacklem krbname[0] = '\0'; 975192585Srmacklem args.krbnamelen = strlen(krbname); 976192585Srmacklem 977192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0) 978192585Srmacklem strlcpy(dirpath, name, sizeof (dirpath)); 979192585Srmacklem else 980191783Srmacklem dirpath[0] = '\0'; 981192585Srmacklem args.dirlen = strlen(dirpath); 982192585Srmacklem 983192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "addr", (void **)&args.addr, 984192585Srmacklem &args.addrlen) == 0) { 985192585Srmacklem if (args.addrlen > SOCK_MAXADDRLEN) { 986192585Srmacklem error = ENAMETOOLONG; 987191783Srmacklem goto out; 988191783Srmacklem } 989192585Srmacklem nam = malloc(args.addrlen, M_SONAME, M_WAITOK); 990192585Srmacklem bcopy(args.addr, nam, args.addrlen); 991192585Srmacklem nam->sa_len = args.addrlen; 992191783Srmacklem } 993192585Srmacklem 994191783Srmacklem args.fh = nfh; 995191783Srmacklem error = mountnfs(&args, mp, nam, hst, krbname, dirpath, srvkrbname, 996191783Srmacklem &vp, td->td_ucred, td); 997191783Srmacklemout: 998191783Srmacklem if (!error) { 999191783Srmacklem MNT_ILOCK(mp); 1000191783Srmacklem mp->mnt_kern_flag |= (MNTK_MPSAFE|MNTK_LOOKUP_SHARED); 1001191783Srmacklem MNT_IUNLOCK(mp); 1002191783Srmacklem } 1003191783Srmacklem return (error); 1004191783Srmacklem} 1005191783Srmacklem 1006191783Srmacklem 1007191783Srmacklem/* 1008191783Srmacklem * VFS Operations. 1009191783Srmacklem * 1010191783Srmacklem * mount system call 1011191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 1012191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 1013191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 1014191783Srmacklem * an error after that means that I have to release the mbuf. 1015191783Srmacklem */ 1016191783Srmacklem/* ARGSUSED */ 1017191783Srmacklemstatic int 1018191990Sattilionfs_cmount(struct mntarg *ma, void *data, int flags) 1019191783Srmacklem{ 1020191783Srmacklem int error; 1021191783Srmacklem struct nfs_args args; 1022191783Srmacklem 1023191783Srmacklem error = copyin(data, &args, sizeof (struct nfs_args)); 1024191783Srmacklem if (error) 1025191783Srmacklem return error; 1026191783Srmacklem 1027191783Srmacklem ma = mount_arg(ma, "nfs_args", &args, sizeof args); 1028191783Srmacklem 1029191783Srmacklem error = kernel_mount(ma, flags); 1030191783Srmacklem return (error); 1031191783Srmacklem} 1032191783Srmacklem 1033191783Srmacklem/* 1034191783Srmacklem * Common code for mount and mountroot 1035191783Srmacklem */ 1036191783Srmacklemstatic int 1037191783Srmacklemmountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, 1038191783Srmacklem char *hst, u_char *krbname, u_char *dirpath, u_char *srvkrbname, 1039191783Srmacklem struct vnode **vpp, struct ucred *cred, struct thread *td) 1040191783Srmacklem{ 1041191783Srmacklem struct nfsmount *nmp; 1042191783Srmacklem struct nfsnode *np; 1043191783Srmacklem int error, trycnt, ret, clearintr; 1044191783Srmacklem struct nfsvattr nfsva; 1045191783Srmacklem static u_int64_t clval = 0; 1046191783Srmacklem 1047191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 1048191783Srmacklem nmp = VFSTONFS(mp); 1049191783Srmacklem printf("%s: MNT_UPDATE is no longer handled here\n", __func__); 1050191783Srmacklem FREE(nam, M_SONAME); 1051191783Srmacklem return (0); 1052191783Srmacklem } else { 1053191783Srmacklem MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) + 1054191783Srmacklem argp->krbnamelen + argp->dirlen + argp->srvkrbnamelen + 2, 1055191783Srmacklem M_NEWNFSMNT, M_WAITOK); 1056191783Srmacklem bzero((caddr_t)nmp, sizeof (struct nfsmount) + 1057191783Srmacklem argp->krbnamelen + argp->dirlen + argp->srvkrbnamelen + 2); 1058191783Srmacklem TAILQ_INIT(&nmp->nm_bufq); 1059191783Srmacklem if (clval == 0) 1060191783Srmacklem clval = (u_int64_t)nfsboottime.tv_sec; 1061191783Srmacklem nmp->nm_clval = clval++; 1062191783Srmacklem nmp->nm_krbnamelen = argp->krbnamelen; 1063191783Srmacklem nmp->nm_dirpathlen = argp->dirlen; 1064191783Srmacklem nmp->nm_srvkrbnamelen = argp->srvkrbnamelen; 1065192675Srmacklem if (td->td_ucred->cr_uid != (uid_t)0) { 1066191783Srmacklem /* 1067192675Srmacklem * nm_uid is used to get KerberosV credentials for 1068192675Srmacklem * the nfsv4 state handling operations if there is 1069192675Srmacklem * no host based principal set. Use the uid of 1070192675Srmacklem * this user if not root, since they are doing the 1071192675Srmacklem * mount. I don't think setting this for root will 1072192675Srmacklem * work, since root normally does not have user 1073192675Srmacklem * credentials in a credentials cache. 1074191783Srmacklem */ 1075192675Srmacklem nmp->nm_uid = td->td_ucred->cr_uid; 1076191783Srmacklem } else { 1077191783Srmacklem /* 1078192675Srmacklem * Just set to -1, so it won't be used. 1079191783Srmacklem */ 1080191783Srmacklem nmp->nm_uid = (uid_t)-1; 1081191783Srmacklem } 1082191783Srmacklem 1083191783Srmacklem /* Copy and null terminate all the names */ 1084191783Srmacklem if (nmp->nm_krbnamelen > 0) { 1085191783Srmacklem bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen); 1086191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen] = '\0'; 1087191783Srmacklem } 1088191783Srmacklem if (nmp->nm_dirpathlen > 0) { 1089191783Srmacklem bcopy(dirpath, NFSMNT_DIRPATH(nmp), 1090191783Srmacklem nmp->nm_dirpathlen); 1091191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1092191783Srmacklem + 1] = '\0'; 1093191783Srmacklem } 1094191783Srmacklem if (nmp->nm_srvkrbnamelen > 0) { 1095191783Srmacklem bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp), 1096191783Srmacklem nmp->nm_srvkrbnamelen); 1097191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1098191783Srmacklem + nmp->nm_srvkrbnamelen + 2] = '\0'; 1099191783Srmacklem } 1100191783Srmacklem nmp->nm_sockreq.nr_cred = crhold(cred); 1101191783Srmacklem mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF); 1102191783Srmacklem mp->mnt_data = nmp; 1103191783Srmacklem } 1104191783Srmacklem vfs_getnewfsid(mp); 1105191783Srmacklem nmp->nm_mountp = mp; 1106191783Srmacklem mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK); 1107191783Srmacklem 1108192585Srmacklem nfs_decode_args(mp, nmp, argp, cred, td); 1109192585Srmacklem 1110191783Srmacklem /* 1111191783Srmacklem * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too 1112191783Srmacklem * high, depending on whether we end up with negative offsets in 1113191783Srmacklem * the client or server somewhere. 2GB-1 may be safer. 1114191783Srmacklem * 1115191783Srmacklem * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum 1116191783Srmacklem * that we can handle until we find out otherwise. 1117191783Srmacklem * XXX Our "safe" limit on the client is what we can store in our 1118191783Srmacklem * buffer cache using signed(!) block numbers. 1119191783Srmacklem */ 1120191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) 1121191783Srmacklem nmp->nm_maxfilesize = 0xffffffffLL; 1122191783Srmacklem else 1123191783Srmacklem nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1; 1124191783Srmacklem 1125191783Srmacklem nmp->nm_timeo = NFS_TIMEO; 1126191783Srmacklem nmp->nm_retry = NFS_RETRANS; 1127191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 1128191783Srmacklem nmp->nm_wsize = NFS_WSIZE; 1129191783Srmacklem nmp->nm_rsize = NFS_RSIZE; 1130191783Srmacklem nmp->nm_readdirsize = NFS_READDIRSIZE; 1131191783Srmacklem } 1132191783Srmacklem nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000); 1133191783Srmacklem nmp->nm_numgrps = NFS_MAXGRPS; 1134191783Srmacklem nmp->nm_readahead = NFS_DEFRAHEAD; 1135191783Srmacklem nmp->nm_tprintf_delay = nfs_tprintf_delay; 1136191783Srmacklem if (nmp->nm_tprintf_delay < 0) 1137191783Srmacklem nmp->nm_tprintf_delay = 0; 1138191783Srmacklem nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay; 1139191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1140191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1141191783Srmacklem nmp->nm_fhsize = argp->fhsize; 1142191783Srmacklem if (nmp->nm_fhsize > 0) 1143191783Srmacklem bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 1144191783Srmacklem bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 1145191783Srmacklem nmp->nm_nam = nam; 1146191783Srmacklem /* Set up the sockets and per-host congestion */ 1147191783Srmacklem nmp->nm_sotype = argp->sotype; 1148191783Srmacklem nmp->nm_soproto = argp->proto; 1149191783Srmacklem nmp->nm_sockreq.nr_prog = NFS_PROG; 1150191783Srmacklem if ((argp->flags & NFSMNT_NFSV4)) 1151191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER4; 1152191783Srmacklem else if ((argp->flags & NFSMNT_NFSV3)) 1153191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER3; 1154191783Srmacklem else 1155191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER2; 1156191783Srmacklem 1157191783Srmacklem 1158191783Srmacklem /* 1159191783Srmacklem * For Connection based sockets (TCP,...) do the connect here, 1160191783Srmacklem * but make it interruptible, even for non-interuptible mounts. 1161191783Srmacklem */ 1162191783Srmacklem if ((nmp->nm_flag & NFSMNT_INT) == 0) { 1163191783Srmacklem nmp->nm_flag |= NFSMNT_INT; 1164191783Srmacklem clearintr = 1; 1165191783Srmacklem } else { 1166191783Srmacklem clearintr = 0; 1167191783Srmacklem } 1168191783Srmacklem if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0))) 1169191783Srmacklem goto bad; 1170191783Srmacklem if (clearintr) 1171191783Srmacklem nmp->nm_flag &= ~NFSMNT_INT; 1172191783Srmacklem 1173191783Srmacklem /* 1174191783Srmacklem * A reference count is needed on the nfsnode representing the 1175191783Srmacklem * remote root. If this object is not persistent, then backward 1176191783Srmacklem * traversals of the mount point (i.e. "..") will not work if 1177191783Srmacklem * the nfsnode gets flushed out of the cache. Ufs does not have 1178191783Srmacklem * this problem, because one can identify root inodes by their 1179191783Srmacklem * number == ROOTINO (2). 1180191783Srmacklem */ 1181191783Srmacklem if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) && 1182191783Srmacklem nmp->nm_dirpathlen > 0) { 1183191783Srmacklem /* 1184191783Srmacklem * If the fhsize on the mount point == 0 for V4, the mount 1185191783Srmacklem * path needs to be looked up. 1186191783Srmacklem */ 1187191783Srmacklem trycnt = 3; 1188191783Srmacklem do { 1189191783Srmacklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 1190191783Srmacklem cred, td); 1191191783Srmacklem if (error) 1192191783Srmacklem (void) nfs_catnap(PZERO, "nfsgetdirp"); 1193191783Srmacklem } while (error && --trycnt > 0); 1194191783Srmacklem if (error) { 1195191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1196191783Srmacklem goto bad; 1197191783Srmacklem } 1198191783Srmacklem } 1199191783Srmacklem if (nmp->nm_fhsize > 0) { 1200191783Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np); 1201191783Srmacklem if (error) 1202191783Srmacklem goto bad; 1203191783Srmacklem *vpp = NFSTOV(np); 1204191783Srmacklem 1205191783Srmacklem /* 1206191783Srmacklem * Get file attributes and transfer parameters for the 1207191783Srmacklem * mountpoint. This has the side effect of filling in 1208191783Srmacklem * (*vpp)->v_type with the correct value. 1209191783Srmacklem */ 1210191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 1211191783Srmacklem cred, td, &nfsva, NULL); 1212191783Srmacklem if (ret) { 1213191783Srmacklem /* 1214191783Srmacklem * Just set default values to get things going. 1215191783Srmacklem */ 1216191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 1217191783Srmacklem nfsva.na_vattr.va_type = VDIR; 1218191783Srmacklem nfsva.na_vattr.va_mode = 0777; 1219191783Srmacklem nfsva.na_vattr.va_nlink = 100; 1220191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 1221191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 1222191783Srmacklem nfsva.na_vattr.va_fileid = 2; 1223191783Srmacklem nfsva.na_vattr.va_gen = 1; 1224191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 1225191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 1226191783Srmacklem } 1227191783Srmacklem (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1); 1228191783Srmacklem if (argp->flags & NFSMNT_NFSV3) 1229191783Srmacklem ncl_fsinfo(nmp, *vpp, cred, td); 1230191783Srmacklem 1231191783Srmacklem /* 1232191783Srmacklem * Lose the lock but keep the ref. 1233191783Srmacklem */ 1234191783Srmacklem VOP_UNLOCK(*vpp, 0); 1235191783Srmacklem return (0); 1236191783Srmacklem } 1237191783Srmacklem error = EIO; 1238191783Srmacklem 1239191783Srmacklembad: 1240191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1241191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1242191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1243191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1244191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1245191783Srmacklem FREE(nam, M_SONAME); 1246191783Srmacklem return (error); 1247191783Srmacklem} 1248191783Srmacklem 1249191783Srmacklem/* 1250191783Srmacklem * unmount system call 1251191783Srmacklem */ 1252191783Srmacklemstatic int 1253191990Sattilionfs_unmount(struct mount *mp, int mntflags) 1254191783Srmacklem{ 1255191990Sattilio struct thread *td; 1256191783Srmacklem struct nfsmount *nmp; 1257191783Srmacklem int error, flags = 0, trycnt = 0; 1258191783Srmacklem 1259191990Sattilio td = curthread; 1260191990Sattilio 1261191783Srmacklem if (mntflags & MNT_FORCE) 1262191783Srmacklem flags |= FORCECLOSE; 1263191783Srmacklem nmp = VFSTONFS(mp); 1264191783Srmacklem /* 1265191783Srmacklem * Goes something like this.. 1266191783Srmacklem * - Call vflush() to clear out vnodes for this filesystem 1267191783Srmacklem * - Close the socket 1268191783Srmacklem * - Free up the data structures 1269191783Srmacklem */ 1270191783Srmacklem /* In the forced case, cancel any outstanding requests. */ 1271191783Srmacklem if (mntflags & MNT_FORCE) { 1272191783Srmacklem error = newnfs_nmcancelreqs(nmp); 1273191783Srmacklem if (error) 1274191783Srmacklem goto out; 1275191783Srmacklem /* For a forced close, get rid of the renew thread now */ 1276191783Srmacklem nfscl_umount(nmp, td); 1277191783Srmacklem } 1278191783Srmacklem /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ 1279191783Srmacklem do { 1280191783Srmacklem error = vflush(mp, 1, flags, td); 1281191783Srmacklem if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30) 1282191783Srmacklem (void) nfs_catnap(PSOCK, "newndm"); 1283191783Srmacklem } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30); 1284191783Srmacklem if (error) 1285191783Srmacklem goto out; 1286191783Srmacklem 1287191783Srmacklem /* 1288191783Srmacklem * We are now committed to the unmount. 1289191783Srmacklem */ 1290191783Srmacklem if ((mntflags & MNT_FORCE) == 0) 1291191783Srmacklem nfscl_umount(nmp, td); 1292191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1293191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1294191783Srmacklem FREE(nmp->nm_nam, M_SONAME); 1295191783Srmacklem 1296191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1297191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1298191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1299191783Srmacklemout: 1300191783Srmacklem return (error); 1301191783Srmacklem} 1302191783Srmacklem 1303191783Srmacklem/* 1304191783Srmacklem * Return root of a filesystem 1305191783Srmacklem */ 1306191783Srmacklemstatic int 1307191990Sattilionfs_root(struct mount *mp, int flags, struct vnode **vpp) 1308191783Srmacklem{ 1309191783Srmacklem struct vnode *vp; 1310191783Srmacklem struct nfsmount *nmp; 1311191783Srmacklem struct nfsnode *np; 1312191783Srmacklem int error; 1313191783Srmacklem 1314191783Srmacklem nmp = VFSTONFS(mp); 1315191783Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np); 1316191783Srmacklem if (error) 1317191783Srmacklem return error; 1318191783Srmacklem vp = NFSTOV(np); 1319191783Srmacklem /* 1320191783Srmacklem * Get transfer parameters and attributes for root vnode once. 1321191783Srmacklem */ 1322191783Srmacklem mtx_lock(&nmp->nm_mtx); 1323191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 1324191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1325191783Srmacklem ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread); 1326191783Srmacklem } else 1327191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1328191783Srmacklem if (vp->v_type == VNON) 1329191783Srmacklem vp->v_type = VDIR; 1330191783Srmacklem vp->v_vflag |= VV_ROOT; 1331191783Srmacklem *vpp = vp; 1332191783Srmacklem return (0); 1333191783Srmacklem} 1334191783Srmacklem 1335191783Srmacklem/* 1336191783Srmacklem * Flush out the buffer cache 1337191783Srmacklem */ 1338191783Srmacklem/* ARGSUSED */ 1339191783Srmacklemstatic int 1340191990Sattilionfs_sync(struct mount *mp, int waitfor) 1341191783Srmacklem{ 1342191783Srmacklem struct vnode *vp, *mvp; 1343191990Sattilio struct thread *td; 1344191783Srmacklem int error, allerror = 0; 1345191783Srmacklem 1346191990Sattilio td = curthread; 1347191990Sattilio 1348191783Srmacklem /* 1349191783Srmacklem * Force stale buffer cache information to be flushed. 1350191783Srmacklem */ 1351191783Srmacklem MNT_ILOCK(mp); 1352191783Srmacklemloop: 1353191783Srmacklem MNT_VNODE_FOREACH(vp, mp, mvp) { 1354191783Srmacklem VI_LOCK(vp); 1355191783Srmacklem MNT_IUNLOCK(mp); 1356191783Srmacklem /* XXX Racy bv_cnt check. */ 1357191783Srmacklem if (VOP_ISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1358191783Srmacklem waitfor == MNT_LAZY) { 1359191783Srmacklem VI_UNLOCK(vp); 1360191783Srmacklem MNT_ILOCK(mp); 1361191783Srmacklem continue; 1362191783Srmacklem } 1363191783Srmacklem if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 1364191783Srmacklem MNT_ILOCK(mp); 1365191783Srmacklem MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); 1366191783Srmacklem goto loop; 1367191783Srmacklem } 1368191783Srmacklem error = VOP_FSYNC(vp, waitfor, td); 1369191783Srmacklem if (error) 1370191783Srmacklem allerror = error; 1371191783Srmacklem VOP_UNLOCK(vp, 0); 1372191783Srmacklem vrele(vp); 1373191783Srmacklem 1374191783Srmacklem MNT_ILOCK(mp); 1375191783Srmacklem } 1376191783Srmacklem MNT_IUNLOCK(mp); 1377191783Srmacklem return (allerror); 1378191783Srmacklem} 1379191783Srmacklem 1380191783Srmacklemstatic int 1381191783Srmacklemnfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 1382191783Srmacklem{ 1383191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1384191783Srmacklem struct vfsquery vq; 1385191783Srmacklem int error; 1386191783Srmacklem 1387191783Srmacklem bzero(&vq, sizeof(vq)); 1388191783Srmacklem switch (op) { 1389191783Srmacklem#if 0 1390191783Srmacklem case VFS_CTL_NOLOCKS: 1391191783Srmacklem val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; 1392191783Srmacklem if (req->oldptr != NULL) { 1393191783Srmacklem error = SYSCTL_OUT(req, &val, sizeof(val)); 1394191783Srmacklem if (error) 1395191783Srmacklem return (error); 1396191783Srmacklem } 1397191783Srmacklem if (req->newptr != NULL) { 1398191783Srmacklem error = SYSCTL_IN(req, &val, sizeof(val)); 1399191783Srmacklem if (error) 1400191783Srmacklem return (error); 1401191783Srmacklem if (val) 1402191783Srmacklem nmp->nm_flag |= NFSMNT_NOLOCKS; 1403191783Srmacklem else 1404191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOLOCKS; 1405191783Srmacklem } 1406191783Srmacklem break; 1407191783Srmacklem#endif 1408191783Srmacklem case VFS_CTL_QUERY: 1409191783Srmacklem mtx_lock(&nmp->nm_mtx); 1410191783Srmacklem if (nmp->nm_state & NFSSTA_TIMEO) 1411191783Srmacklem vq.vq_flags |= VQ_NOTRESP; 1412191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1413191783Srmacklem#if 0 1414191783Srmacklem if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && 1415191783Srmacklem (nmp->nm_state & NFSSTA_LOCKTIMEO)) 1416191783Srmacklem vq.vq_flags |= VQ_NOTRESPLOCK; 1417191783Srmacklem#endif 1418191783Srmacklem error = SYSCTL_OUT(req, &vq, sizeof(vq)); 1419191783Srmacklem break; 1420191783Srmacklem case VFS_CTL_TIMEO: 1421191783Srmacklem if (req->oldptr != NULL) { 1422191783Srmacklem error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, 1423191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1424191783Srmacklem if (error) 1425191783Srmacklem return (error); 1426191783Srmacklem } 1427191783Srmacklem if (req->newptr != NULL) { 1428191783Srmacklem error = vfs_suser(mp, req->td); 1429191783Srmacklem if (error) 1430191783Srmacklem return (error); 1431191783Srmacklem error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, 1432191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1433191783Srmacklem if (error) 1434191783Srmacklem return (error); 1435191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1436191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1437191783Srmacklem } 1438191783Srmacklem break; 1439191783Srmacklem default: 1440191783Srmacklem return (ENOTSUP); 1441191783Srmacklem } 1442191783Srmacklem return (0); 1443191783Srmacklem} 1444191783Srmacklem 1445