nfs_clvfsops.c revision 221066
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 221066 2011-04-26 13:50:11Z 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> 48193066Sjamie#include <sys/jail.h> 49220739Srmacklem#include <sys/limits.h> 50191783Srmacklem#include <sys/lock.h> 51191783Srmacklem#include <sys/malloc.h> 52191783Srmacklem#include <sys/mbuf.h> 53191783Srmacklem#include <sys/module.h> 54191783Srmacklem#include <sys/mount.h> 55191783Srmacklem#include <sys/proc.h> 56191783Srmacklem#include <sys/socket.h> 57191783Srmacklem#include <sys/socketvar.h> 58191783Srmacklem#include <sys/sockio.h> 59191783Srmacklem#include <sys/sysctl.h> 60191783Srmacklem#include <sys/vnode.h> 61191783Srmacklem#include <sys/signalvar.h> 62191783Srmacklem 63191783Srmacklem#include <vm/vm.h> 64191783Srmacklem#include <vm/vm_extern.h> 65191783Srmacklem#include <vm/uma.h> 66191783Srmacklem 67191783Srmacklem#include <net/if.h> 68191783Srmacklem#include <net/route.h> 69191783Srmacklem#include <netinet/in.h> 70191783Srmacklem 71191783Srmacklem#include <fs/nfs/nfsport.h> 72191783Srmacklem#include <fs/nfsclient/nfsnode.h> 73191783Srmacklem#include <fs/nfsclient/nfsmount.h> 74191783Srmacklem#include <fs/nfsclient/nfs.h> 75221040Srmacklem#include <nfs/nfsdiskless.h> 76191783Srmacklem 77219028SnetchildFEATURE(nfscl, "NFSv4 client"); 78219028Snetchild 79191783Srmacklemextern int nfscl_ticks; 80191783Srmacklemextern struct timeval nfsboottime; 81191783Srmacklemextern struct nfsstats newnfsstats; 82191783Srmacklem 83191783SrmacklemMALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header"); 84191783SrmacklemMALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct"); 85191783Srmacklem 86191783SrmacklemSYSCTL_DECL(_vfs_newnfs); 87191783SrmacklemSYSCTL_STRUCT(_vfs_newnfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RW, 88191783Srmacklem &newnfsstats, nfsstats, "S,nfsstats"); 89191783Srmacklemstatic int nfs_ip_paranoia = 1; 90191783SrmacklemSYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW, 91191783Srmacklem &nfs_ip_paranoia, 0, ""); 92191783Srmacklemstatic int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY; 93191783SrmacklemSYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_INITIAL_DELAY, 94191783Srmacklem downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, ""); 95191783Srmacklem/* how long between console messages "nfs server foo not responding" */ 96191783Srmacklemstatic int nfs_tprintf_delay = NFS_TPRINTF_DELAY; 97191783SrmacklemSYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_DELAY, 98191783Srmacklem downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, ""); 99191783Srmacklem 100221040Srmacklemstatic int nfs_mountroot(struct mount *); 101192585Srmacklemstatic void nfs_sec_name(char *, int *); 102191783Srmacklemstatic void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, 103214048Srmacklem struct nfs_args *argp, const char *, struct ucred *, 104214048Srmacklem struct thread *); 105191783Srmacklemstatic int mountnfs(struct nfs_args *, struct mount *, 106221014Srmacklem struct sockaddr *, char *, u_char *, int, u_char *, int, 107221014Srmacklem u_char *, int, struct vnode **, struct ucred *, 108221014Srmacklem struct thread *, int); 109214053Srmacklemstatic void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *, 110216931Srmacklem struct sockaddr_storage *, int *, off_t *, 111216931Srmacklem struct timeval *); 112191783Srmacklemstatic vfs_mount_t nfs_mount; 113191783Srmacklemstatic vfs_cmount_t nfs_cmount; 114191783Srmacklemstatic vfs_unmount_t nfs_unmount; 115191783Srmacklemstatic vfs_root_t nfs_root; 116191783Srmacklemstatic vfs_statfs_t nfs_statfs; 117191783Srmacklemstatic vfs_sync_t nfs_sync; 118191783Srmacklemstatic vfs_sysctl_t nfs_sysctl; 119191783Srmacklem 120191783Srmacklem/* 121191783Srmacklem * nfs vfs operations. 122191783Srmacklem */ 123191783Srmacklemstatic struct vfsops nfs_vfsops = { 124191783Srmacklem .vfs_init = ncl_init, 125191783Srmacklem .vfs_mount = nfs_mount, 126191783Srmacklem .vfs_cmount = nfs_cmount, 127191783Srmacklem .vfs_root = nfs_root, 128191783Srmacklem .vfs_statfs = nfs_statfs, 129191783Srmacklem .vfs_sync = nfs_sync, 130191783Srmacklem .vfs_uninit = ncl_uninit, 131191783Srmacklem .vfs_unmount = nfs_unmount, 132191783Srmacklem .vfs_sysctl = nfs_sysctl, 133191783Srmacklem}; 134191783SrmacklemVFS_SET(nfs_vfsops, newnfs, VFCF_NETWORK); 135191783Srmacklem 136191783Srmacklem/* So that loader and kldload(2) can find us, wherever we are.. */ 137191783SrmacklemMODULE_VERSION(newnfs, 1); 138191783Srmacklem 139191783Srmacklem/* 140221066Srmacklem * This structure is now defined in sys/nfs/nfs_diskless.c so that it 141221066Srmacklem * can be shared by both NFS clients. It is declared here so that it 142221066Srmacklem * will be defined for kernels built without NFS_ROOT, although it 143221066Srmacklem * isn't used in that case. 144191783Srmacklem */ 145221066Srmacklem#if !defined(NFS_ROOT) && !defined(NFSCLIENT) 146221066Srmacklemstruct nfs_diskless nfs_diskless = { { { 0 } } }; 147221066Srmacklemstruct nfsv3_diskless nfsv3_diskless = { { { 0 } } }; 148221066Srmacklemint nfs_diskless_valid = 0; 149221066Srmacklem#endif 150221066Srmacklem 151191783SrmacklemSYSCTL_INT(_vfs_newnfs, OID_AUTO, diskless_valid, CTLFLAG_RD, 152221040Srmacklem &nfs_diskless_valid, 0, 153192145Srmacklem "Has the diskless struct been filled correctly"); 154191783Srmacklem 155191783SrmacklemSYSCTL_STRING(_vfs_newnfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD, 156221040Srmacklem nfsv3_diskless.root_hostnam, 0, "Path to nfs root"); 157191783Srmacklem 158191783SrmacklemSYSCTL_OPAQUE(_vfs_newnfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD, 159221040Srmacklem &nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr), 160192145Srmacklem "%Ssockaddr_in", "Diskless root nfs address"); 161191783Srmacklem 162191783Srmacklem 163191783Srmacklemvoid newnfsargs_ntoh(struct nfs_args *); 164191783Srmacklemstatic int nfs_mountdiskless(char *, 165191783Srmacklem struct sockaddr_in *, struct nfs_args *, 166191783Srmacklem struct thread *, struct vnode **, struct mount *); 167191783Srmacklemstatic void nfs_convert_diskless(void); 168191783Srmacklemstatic void nfs_convert_oargs(struct nfs_args *args, 169191783Srmacklem struct onfs_args *oargs); 170191783Srmacklem 171191783Srmacklemint 172191783Srmacklemnewnfs_iosize(struct nfsmount *nmp) 173191783Srmacklem{ 174191783Srmacklem int iosize, maxio; 175191783Srmacklem 176191783Srmacklem /* First, set the upper limit for iosize */ 177191783Srmacklem if (nmp->nm_flag & NFSMNT_NFSV4) { 178191783Srmacklem maxio = NFS_MAXBSIZE; 179191783Srmacklem } else if (nmp->nm_flag & NFSMNT_NFSV3) { 180191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 181191783Srmacklem maxio = NFS_MAXDGRAMDATA; 182191783Srmacklem else 183191783Srmacklem maxio = NFS_MAXBSIZE; 184191783Srmacklem } else { 185191783Srmacklem maxio = NFS_V2MAXDATA; 186191783Srmacklem } 187191783Srmacklem if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0) 188191783Srmacklem nmp->nm_rsize = maxio; 189191783Srmacklem if (nmp->nm_rsize > MAXBSIZE) 190191783Srmacklem nmp->nm_rsize = MAXBSIZE; 191191783Srmacklem if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0) 192191783Srmacklem nmp->nm_readdirsize = maxio; 193191783Srmacklem if (nmp->nm_readdirsize > nmp->nm_rsize) 194191783Srmacklem nmp->nm_readdirsize = nmp->nm_rsize; 195191783Srmacklem if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0) 196191783Srmacklem nmp->nm_wsize = maxio; 197191783Srmacklem if (nmp->nm_wsize > MAXBSIZE) 198191783Srmacklem nmp->nm_wsize = MAXBSIZE; 199191783Srmacklem 200191783Srmacklem /* 201191783Srmacklem * Calculate the size used for io buffers. Use the larger 202191783Srmacklem * of the two sizes to minimise nfs requests but make sure 203191783Srmacklem * that it is at least one VM page to avoid wasting buffer 204191783Srmacklem * space. 205191783Srmacklem */ 206191783Srmacklem iosize = imax(nmp->nm_rsize, nmp->nm_wsize); 207191783Srmacklem iosize = imax(iosize, PAGE_SIZE); 208191783Srmacklem nmp->nm_mountp->mnt_stat.f_iosize = iosize; 209191783Srmacklem return (iosize); 210191783Srmacklem} 211191783Srmacklem 212191783Srmacklemstatic void 213191783Srmacklemnfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs) 214191783Srmacklem{ 215191783Srmacklem 216191783Srmacklem args->version = NFS_ARGSVERSION; 217191783Srmacklem args->addr = oargs->addr; 218191783Srmacklem args->addrlen = oargs->addrlen; 219191783Srmacklem args->sotype = oargs->sotype; 220191783Srmacklem args->proto = oargs->proto; 221191783Srmacklem args->fh = oargs->fh; 222191783Srmacklem args->fhsize = oargs->fhsize; 223191783Srmacklem args->flags = oargs->flags; 224191783Srmacklem args->wsize = oargs->wsize; 225191783Srmacklem args->rsize = oargs->rsize; 226191783Srmacklem args->readdirsize = oargs->readdirsize; 227191783Srmacklem args->timeo = oargs->timeo; 228191783Srmacklem args->retrans = oargs->retrans; 229191783Srmacklem args->readahead = oargs->readahead; 230191783Srmacklem args->hostname = oargs->hostname; 231191783Srmacklem} 232191783Srmacklem 233191783Srmacklemstatic void 234191783Srmacklemnfs_convert_diskless(void) 235191783Srmacklem{ 236191783Srmacklem 237221040Srmacklem bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif, 238221040Srmacklem sizeof(struct ifaliasreq)); 239221040Srmacklem bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway, 240221040Srmacklem sizeof(struct sockaddr_in)); 241221040Srmacklem nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args); 242221040Srmacklem if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) { 243221040Srmacklem nfsv3_diskless.root_fhsize = NFSX_MYFH; 244221040Srmacklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH); 245191783Srmacklem } else { 246221040Srmacklem nfsv3_diskless.root_fhsize = NFSX_V2FH; 247221040Srmacklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH); 248191783Srmacklem } 249221040Srmacklem bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr, 250221040Srmacklem sizeof(struct sockaddr_in)); 251221040Srmacklem bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN); 252221040Srmacklem nfsv3_diskless.root_time = nfs_diskless.root_time; 253221040Srmacklem bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam, 254221040Srmacklem MAXHOSTNAMELEN); 255221040Srmacklem nfs_diskless_valid = 3; 256191783Srmacklem} 257191783Srmacklem 258191783Srmacklem/* 259191783Srmacklem * nfs statfs call 260191783Srmacklem */ 261191783Srmacklemstatic int 262191990Sattilionfs_statfs(struct mount *mp, struct statfs *sbp) 263191783Srmacklem{ 264191783Srmacklem struct vnode *vp; 265191990Sattilio struct thread *td; 266191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 267191783Srmacklem struct nfsvattr nfsva; 268191783Srmacklem struct nfsfsinfo fs; 269191783Srmacklem struct nfsstatfs sb; 270191783Srmacklem int error = 0, attrflag, gotfsinfo = 0, ret; 271191783Srmacklem struct nfsnode *np; 272191783Srmacklem 273191990Sattilio td = curthread; 274191990Sattilio 275191783Srmacklem error = vfs_busy(mp, MBF_NOWAIT); 276191783Srmacklem if (error) 277191783Srmacklem return (error); 278220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE); 279191783Srmacklem if (error) { 280191783Srmacklem vfs_unbusy(mp); 281191783Srmacklem return (error); 282191783Srmacklem } 283191783Srmacklem vp = NFSTOV(np); 284191783Srmacklem mtx_lock(&nmp->nm_mtx); 285191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 286191783Srmacklem mtx_unlock(&nmp->nm_mtx); 287191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva, 288191783Srmacklem &attrflag, NULL); 289191783Srmacklem if (!error) 290191783Srmacklem gotfsinfo = 1; 291191783Srmacklem } else 292191783Srmacklem mtx_unlock(&nmp->nm_mtx); 293191783Srmacklem if (!error) 294191783Srmacklem error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, 295191783Srmacklem &attrflag, NULL); 296191783Srmacklem if (attrflag == 0) { 297191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 298191783Srmacklem td->td_ucred, td, &nfsva, NULL); 299191783Srmacklem if (ret) { 300191783Srmacklem /* 301191783Srmacklem * Just set default values to get things going. 302191783Srmacklem */ 303191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 304191783Srmacklem nfsva.na_vattr.va_type = VDIR; 305191783Srmacklem nfsva.na_vattr.va_mode = 0777; 306191783Srmacklem nfsva.na_vattr.va_nlink = 100; 307191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 308191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 309191783Srmacklem nfsva.na_vattr.va_fileid = 2; 310191783Srmacklem nfsva.na_vattr.va_gen = 1; 311191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 312191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 313191783Srmacklem } 314191783Srmacklem } 315191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 316191783Srmacklem if (!error) { 317191783Srmacklem mtx_lock(&nmp->nm_mtx); 318191783Srmacklem if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4)) 319191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 320191783Srmacklem nfscl_loadsbinfo(nmp, &sb, sbp); 321191783Srmacklem sbp->f_iosize = newnfs_iosize(nmp); 322191783Srmacklem mtx_unlock(&nmp->nm_mtx); 323191783Srmacklem if (sbp != &mp->mnt_stat) { 324191783Srmacklem bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 325191783Srmacklem bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 326191783Srmacklem } 327191783Srmacklem strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 328191783Srmacklem } else if (NFS_ISV4(vp)) { 329191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 330191783Srmacklem } 331191783Srmacklem vput(vp); 332191783Srmacklem vfs_unbusy(mp); 333191783Srmacklem return (error); 334191783Srmacklem} 335191783Srmacklem 336191783Srmacklem/* 337191783Srmacklem * nfs version 3 fsinfo rpc call 338191783Srmacklem */ 339191783Srmacklemint 340191783Srmacklemncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, 341191783Srmacklem struct thread *td) 342191783Srmacklem{ 343191783Srmacklem struct nfsfsinfo fs; 344191783Srmacklem struct nfsvattr nfsva; 345191783Srmacklem int error, attrflag; 346191783Srmacklem 347191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL); 348191783Srmacklem if (!error) { 349191783Srmacklem if (attrflag) 350191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 351191783Srmacklem 1); 352191783Srmacklem mtx_lock(&nmp->nm_mtx); 353191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 354191783Srmacklem mtx_unlock(&nmp->nm_mtx); 355191783Srmacklem } 356191783Srmacklem return (error); 357191783Srmacklem} 358191783Srmacklem 359191783Srmacklem/* 360191783Srmacklem * Mount a remote root fs via. nfs. This depends on the info in the 361221040Srmacklem * nfs_diskless structure that has been filled in properly by some primary 362191783Srmacklem * bootstrap. 363191783Srmacklem * It goes something like this: 364191783Srmacklem * - do enough of "ifconfig" by calling ifioctl() so that the system 365191783Srmacklem * can talk to the server 366221040Srmacklem * - If nfs_diskless.mygateway is filled in, use that address as 367191783Srmacklem * a default gateway. 368191783Srmacklem * - build the rootfs mount point and call mountnfs() to do the rest. 369191783Srmacklem * 370191783Srmacklem * It is assumed to be safe to read, modify, and write the nfsv3_diskless 371191783Srmacklem * structure, as well as other global NFS client variables here, as 372192145Srmacklem * nfs_mountroot() will be called once in the boot before any other NFS 373191783Srmacklem * client activity occurs. 374191783Srmacklem */ 375221040Srmacklemstatic int 376221040Srmacklemnfs_mountroot(struct mount *mp) 377191783Srmacklem{ 378192145Srmacklem struct thread *td = curthread; 379221040Srmacklem struct nfsv3_diskless *nd = &nfsv3_diskless; 380191783Srmacklem struct socket *so; 381191783Srmacklem struct vnode *vp; 382191783Srmacklem struct ifreq ir; 383193066Sjamie int error; 384191783Srmacklem u_long l; 385191783Srmacklem char buf[128]; 386191783Srmacklem char *cp; 387191783Srmacklem 388191783Srmacklem#if defined(BOOTP_NFSROOT) && defined(BOOTP) 389192145Srmacklem bootpc_init(); /* use bootp to get nfs_diskless filled in */ 390191783Srmacklem#elif defined(NFS_ROOT) 391191783Srmacklem nfs_setup_diskless(); 392191783Srmacklem#endif 393191783Srmacklem 394221040Srmacklem if (nfs_diskless_valid == 0) 395191783Srmacklem return (-1); 396221040Srmacklem if (nfs_diskless_valid == 1) 397191783Srmacklem nfs_convert_diskless(); 398191783Srmacklem 399191783Srmacklem /* 400191783Srmacklem * XXX splnet, so networks will receive... 401191783Srmacklem */ 402191783Srmacklem splnet(); 403191783Srmacklem 404191783Srmacklem /* 405191783Srmacklem * Do enough of ifconfig(8) so that the critical net interface can 406191783Srmacklem * talk to the server. 407191783Srmacklem */ 408191783Srmacklem error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0, 409191783Srmacklem td->td_ucred, td); 410191783Srmacklem if (error) 411192145Srmacklem panic("nfs_mountroot: socreate(%04x): %d", 412191783Srmacklem nd->myif.ifra_addr.sa_family, error); 413191783Srmacklem 414191783Srmacklem#if 0 /* XXX Bad idea */ 415191783Srmacklem /* 416191783Srmacklem * We might not have been told the right interface, so we pass 417191783Srmacklem * over the first ten interfaces of the same kind, until we get 418191783Srmacklem * one of them configured. 419191783Srmacklem */ 420191783Srmacklem 421191783Srmacklem for (i = strlen(nd->myif.ifra_name) - 1; 422191783Srmacklem nd->myif.ifra_name[i] >= '0' && 423191783Srmacklem nd->myif.ifra_name[i] <= '9'; 424191783Srmacklem nd->myif.ifra_name[i] ++) { 425191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 426191783Srmacklem if(!error) 427191783Srmacklem break; 428191783Srmacklem } 429191783Srmacklem#endif 430191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 431191783Srmacklem if (error) 432192145Srmacklem panic("nfs_mountroot: SIOCAIFADDR: %d", error); 433191783Srmacklem if ((cp = getenv("boot.netif.mtu")) != NULL) { 434191783Srmacklem ir.ifr_mtu = strtol(cp, NULL, 10); 435191783Srmacklem bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); 436191783Srmacklem freeenv(cp); 437191783Srmacklem error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); 438191783Srmacklem if (error) 439192145Srmacklem printf("nfs_mountroot: SIOCSIFMTU: %d", error); 440191783Srmacklem } 441191783Srmacklem soclose(so); 442191783Srmacklem 443191783Srmacklem /* 444191783Srmacklem * If the gateway field is filled in, set it as the default route. 445191783Srmacklem * Note that pxeboot will set a default route of 0 if the route 446191783Srmacklem * is not set by the DHCP server. Check also for a value of 0 447191783Srmacklem * to avoid panicking inappropriately in that situation. 448191783Srmacklem */ 449191783Srmacklem if (nd->mygateway.sin_len != 0 && 450191783Srmacklem nd->mygateway.sin_addr.s_addr != 0) { 451191783Srmacklem struct sockaddr_in mask, sin; 452191783Srmacklem 453191783Srmacklem bzero((caddr_t)&mask, sizeof(mask)); 454191783Srmacklem sin = mask; 455191783Srmacklem sin.sin_family = AF_INET; 456191783Srmacklem sin.sin_len = sizeof(sin); 457192145Srmacklem /* XXX MRT use table 0 for this sort of thing */ 458218757Sbz CURVNET_SET(TD_TO_VNET(td)); 459191783Srmacklem error = rtrequest(RTM_ADD, (struct sockaddr *)&sin, 460191783Srmacklem (struct sockaddr *)&nd->mygateway, 461191783Srmacklem (struct sockaddr *)&mask, 462191783Srmacklem RTF_UP | RTF_GATEWAY, NULL); 463218757Sbz CURVNET_RESTORE(); 464191783Srmacklem if (error) 465192145Srmacklem panic("nfs_mountroot: RTM_ADD: %d", error); 466191783Srmacklem } 467191783Srmacklem 468191783Srmacklem /* 469191783Srmacklem * Create the rootfs mount point. 470191783Srmacklem */ 471191783Srmacklem nd->root_args.fh = nd->root_fh; 472191783Srmacklem nd->root_args.fhsize = nd->root_fhsize; 473191783Srmacklem l = ntohl(nd->root_saddr.sin_addr.s_addr); 474191783Srmacklem snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", 475191783Srmacklem (l >> 24) & 0xff, (l >> 16) & 0xff, 476191783Srmacklem (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); 477191783Srmacklem printf("NFS ROOT: %s\n", buf); 478192145Srmacklem nd->root_args.hostname = buf; 479191783Srmacklem if ((error = nfs_mountdiskless(buf, 480191783Srmacklem &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { 481191783Srmacklem return (error); 482191783Srmacklem } 483191783Srmacklem 484191783Srmacklem /* 485191783Srmacklem * This is not really an nfs issue, but it is much easier to 486191783Srmacklem * set hostname here and then let the "/etc/rc.xxx" files 487191783Srmacklem * mount the right /var based upon its preset value. 488191783Srmacklem */ 489193066Sjamie mtx_lock(&prison0.pr_mtx); 490194118Sjamie strlcpy(prison0.pr_hostname, nd->my_hostnam, 491194118Sjamie sizeof(prison0.pr_hostname)); 492193066Sjamie mtx_unlock(&prison0.pr_mtx); 493191783Srmacklem inittodr(ntohl(nd->root_time)); 494191783Srmacklem return (0); 495191783Srmacklem} 496191783Srmacklem 497191783Srmacklem/* 498191783Srmacklem * Internal version of mount system call for diskless setup. 499191783Srmacklem */ 500191783Srmacklemstatic int 501191783Srmacklemnfs_mountdiskless(char *path, 502191783Srmacklem struct sockaddr_in *sin, struct nfs_args *args, struct thread *td, 503191783Srmacklem struct vnode **vpp, struct mount *mp) 504191783Srmacklem{ 505191783Srmacklem struct sockaddr *nam; 506221014Srmacklem int dirlen, error; 507221014Srmacklem char *dirpath; 508191783Srmacklem 509221014Srmacklem /* 510221014Srmacklem * Find the directory path in "path", which also has the server's 511221014Srmacklem * name/ip address in it. 512221014Srmacklem */ 513221014Srmacklem dirpath = strchr(path, ':'); 514221014Srmacklem if (dirpath != NULL) 515221014Srmacklem dirlen = strlen(++dirpath); 516221014Srmacklem else 517221014Srmacklem dirlen = 0; 518191783Srmacklem nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); 519221014Srmacklem if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen, 520221014Srmacklem NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NEGNAMETIMEO)) != 0) { 521192145Srmacklem printf("nfs_mountroot: mount %s on /: %d\n", path, error); 522191783Srmacklem return (error); 523191783Srmacklem } 524191783Srmacklem return (0); 525191783Srmacklem} 526191783Srmacklem 527191783Srmacklemstatic void 528192585Srmacklemnfs_sec_name(char *sec, int *flagsp) 529192585Srmacklem{ 530192585Srmacklem if (!strcmp(sec, "krb5")) 531192585Srmacklem *flagsp |= NFSMNT_KERB; 532192585Srmacklem else if (!strcmp(sec, "krb5i")) 533192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY); 534192585Srmacklem else if (!strcmp(sec, "krb5p")) 535192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY); 536192585Srmacklem} 537192585Srmacklem 538192585Srmacklemstatic void 539191783Srmacklemnfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, 540214048Srmacklem const char *hostname, struct ucred *cred, struct thread *td) 541191783Srmacklem{ 542191783Srmacklem int s; 543191783Srmacklem int adjsock; 544214048Srmacklem char *p; 545191783Srmacklem 546191783Srmacklem s = splnet(); 547191783Srmacklem 548191783Srmacklem /* 549191783Srmacklem * Set read-only flag if requested; otherwise, clear it if this is 550191783Srmacklem * an update. If this is not an update, then either the read-only 551191783Srmacklem * flag is already clear, or this is a root mount and it was set 552191783Srmacklem * intentionally at some previous point. 553191783Srmacklem */ 554191783Srmacklem if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) { 555191783Srmacklem MNT_ILOCK(mp); 556191783Srmacklem mp->mnt_flag |= MNT_RDONLY; 557191783Srmacklem MNT_IUNLOCK(mp); 558191783Srmacklem } else if (mp->mnt_flag & MNT_UPDATE) { 559191783Srmacklem MNT_ILOCK(mp); 560191783Srmacklem mp->mnt_flag &= ~MNT_RDONLY; 561191783Srmacklem MNT_IUNLOCK(mp); 562191783Srmacklem } 563191783Srmacklem 564191783Srmacklem /* 565191783Srmacklem * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 566191783Srmacklem * no sense in that context. Also, set up appropriate retransmit 567191783Srmacklem * and soft timeout behavior. 568191783Srmacklem */ 569191783Srmacklem if (argp->sotype == SOCK_STREAM) { 570191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOCONN; 571191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 572220739Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0) 573220739Srmacklem nmp->nm_retry = INT_MAX; 574220739Srmacklem else 575220739Srmacklem nmp->nm_retry = NFS_RETRANS_TCP; 576191783Srmacklem } 577191783Srmacklem 578220739Srmacklem /* Also clear RDIRPLUS if NFSv2, it crashes some servers */ 579220739Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 580220739Srmacklem argp->flags &= ~NFSMNT_RDIRPLUS; 581191783Srmacklem nmp->nm_flag &= ~NFSMNT_RDIRPLUS; 582220739Srmacklem } 583191783Srmacklem 584220739Srmacklem /* Clear NFSMNT_RESVPORT for NFSv4, since it is not required. */ 585220739Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0) { 586220739Srmacklem argp->flags &= ~NFSMNT_RESVPORT; 587220739Srmacklem nmp->nm_flag &= ~NFSMNT_RESVPORT; 588220739Srmacklem } 589220739Srmacklem 590220739Srmacklem /* Re-bind if rsrvd port requested and wasn't on one */ 591220739Srmacklem adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT) 592220739Srmacklem && (argp->flags & NFSMNT_RESVPORT); 593191783Srmacklem /* Also re-bind if we're switching to/from a connected UDP socket */ 594220739Srmacklem adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) != 595191783Srmacklem (argp->flags & NFSMNT_NOCONN)); 596191783Srmacklem 597191783Srmacklem /* Update flags atomically. Don't change the lock bits. */ 598191783Srmacklem nmp->nm_flag = argp->flags | nmp->nm_flag; 599191783Srmacklem splx(s); 600191783Srmacklem 601191783Srmacklem if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 602191783Srmacklem nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 603191783Srmacklem if (nmp->nm_timeo < NFS_MINTIMEO) 604191783Srmacklem nmp->nm_timeo = NFS_MINTIMEO; 605191783Srmacklem else if (nmp->nm_timeo > NFS_MAXTIMEO) 606191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 607191783Srmacklem } 608191783Srmacklem 609191783Srmacklem if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 610191783Srmacklem nmp->nm_retry = argp->retrans; 611191783Srmacklem if (nmp->nm_retry > NFS_MAXREXMIT) 612191783Srmacklem nmp->nm_retry = NFS_MAXREXMIT; 613191783Srmacklem } 614191783Srmacklem 615191783Srmacklem if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 616191783Srmacklem nmp->nm_wsize = argp->wsize; 617191783Srmacklem /* Round down to multiple of blocksize */ 618191783Srmacklem nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); 619191783Srmacklem if (nmp->nm_wsize <= 0) 620191783Srmacklem nmp->nm_wsize = NFS_FABLKSIZE; 621191783Srmacklem } 622191783Srmacklem 623191783Srmacklem if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 624191783Srmacklem nmp->nm_rsize = argp->rsize; 625191783Srmacklem /* Round down to multiple of blocksize */ 626191783Srmacklem nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); 627191783Srmacklem if (nmp->nm_rsize <= 0) 628191783Srmacklem nmp->nm_rsize = NFS_FABLKSIZE; 629191783Srmacklem } 630191783Srmacklem 631191783Srmacklem if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 632191783Srmacklem nmp->nm_readdirsize = argp->readdirsize; 633191783Srmacklem } 634191783Srmacklem 635191783Srmacklem if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) 636191783Srmacklem nmp->nm_acregmin = argp->acregmin; 637191783Srmacklem else 638191783Srmacklem nmp->nm_acregmin = NFS_MINATTRTIMO; 639191783Srmacklem if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) 640191783Srmacklem nmp->nm_acregmax = argp->acregmax; 641191783Srmacklem else 642191783Srmacklem nmp->nm_acregmax = NFS_MAXATTRTIMO; 643191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) 644191783Srmacklem nmp->nm_acdirmin = argp->acdirmin; 645191783Srmacklem else 646191783Srmacklem nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; 647191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) 648191783Srmacklem nmp->nm_acdirmax = argp->acdirmax; 649191783Srmacklem else 650191783Srmacklem nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; 651191783Srmacklem if (nmp->nm_acdirmin > nmp->nm_acdirmax) 652191783Srmacklem nmp->nm_acdirmin = nmp->nm_acdirmax; 653191783Srmacklem if (nmp->nm_acregmin > nmp->nm_acregmax) 654191783Srmacklem nmp->nm_acregmin = nmp->nm_acregmax; 655191783Srmacklem 656191783Srmacklem if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { 657191783Srmacklem if (argp->readahead <= NFS_MAXRAHEAD) 658191783Srmacklem nmp->nm_readahead = argp->readahead; 659191783Srmacklem else 660191783Srmacklem nmp->nm_readahead = NFS_MAXRAHEAD; 661191783Srmacklem } 662191783Srmacklem if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) { 663191783Srmacklem if (argp->wcommitsize < nmp->nm_wsize) 664191783Srmacklem nmp->nm_wcommitsize = nmp->nm_wsize; 665191783Srmacklem else 666191783Srmacklem nmp->nm_wcommitsize = argp->wcommitsize; 667191783Srmacklem } 668191783Srmacklem 669191783Srmacklem adjsock |= ((nmp->nm_sotype != argp->sotype) || 670191783Srmacklem (nmp->nm_soproto != argp->proto)); 671191783Srmacklem 672191783Srmacklem if (nmp->nm_client != NULL && adjsock) { 673191783Srmacklem int haslock = 0, error = 0; 674191783Srmacklem 675191783Srmacklem if (nmp->nm_sotype == SOCK_STREAM) { 676191783Srmacklem error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock); 677191783Srmacklem if (!error) 678191783Srmacklem haslock = 1; 679191783Srmacklem } 680191783Srmacklem if (!error) { 681191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 682191783Srmacklem if (haslock) 683191783Srmacklem newnfs_sndunlock(&nmp->nm_sockreq.nr_lock); 684191783Srmacklem nmp->nm_sotype = argp->sotype; 685191783Srmacklem nmp->nm_soproto = argp->proto; 686191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 687191783Srmacklem while (newnfs_connect(nmp, &nmp->nm_sockreq, 688191783Srmacklem cred, td, 0)) { 689191783Srmacklem printf("newnfs_args: retrying connect\n"); 690207170Srmacklem (void) nfs_catnap(PSOCK, 0, "newnfscon"); 691191783Srmacklem } 692191783Srmacklem } 693191783Srmacklem } else { 694191783Srmacklem nmp->nm_sotype = argp->sotype; 695191783Srmacklem nmp->nm_soproto = argp->proto; 696191783Srmacklem } 697214048Srmacklem 698214048Srmacklem if (hostname != NULL) { 699214048Srmacklem strlcpy(nmp->nm_hostname, hostname, 700214048Srmacklem sizeof(nmp->nm_hostname)); 701214048Srmacklem p = strchr(nmp->nm_hostname, ':'); 702214048Srmacklem if (p != NULL) 703214048Srmacklem *p = '\0'; 704214048Srmacklem } 705191783Srmacklem} 706191783Srmacklem 707192585Srmacklemstatic const char *nfs_opts[] = { "from", 708191783Srmacklem "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union", 709191783Srmacklem "noclusterr", "noclusterw", "multilabel", "acls", "force", "update", 710192585Srmacklem "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus", 711192585Srmacklem "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize", 712192585Srmacklem "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport", 713192585Srmacklem "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec", 714192585Srmacklem "principal", "nfsv4", "gssname", "allgssname", "dirpath", 715203303Srmacklem "negnametimeo", 716191783Srmacklem NULL }; 717191783Srmacklem 718191783Srmacklem/* 719191783Srmacklem * VFS Operations. 720191783Srmacklem * 721191783Srmacklem * mount system call 722191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 723191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 724191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 725191783Srmacklem * an error after that means that I have to release the mbuf. 726191783Srmacklem */ 727191783Srmacklem/* ARGSUSED */ 728191783Srmacklemstatic int 729191990Sattilionfs_mount(struct mount *mp) 730191783Srmacklem{ 731191783Srmacklem struct nfs_args args = { 732191783Srmacklem .version = NFS_ARGSVERSION, 733191783Srmacklem .addr = NULL, 734191783Srmacklem .addrlen = sizeof (struct sockaddr_in), 735191783Srmacklem .sotype = SOCK_STREAM, 736191783Srmacklem .proto = 0, 737191783Srmacklem .fh = NULL, 738191783Srmacklem .fhsize = 0, 739220739Srmacklem .flags = NFSMNT_RESVPORT, 740191783Srmacklem .wsize = NFS_WSIZE, 741191783Srmacklem .rsize = NFS_RSIZE, 742191783Srmacklem .readdirsize = NFS_READDIRSIZE, 743191783Srmacklem .timeo = 10, 744191783Srmacklem .retrans = NFS_RETRANS, 745191783Srmacklem .readahead = NFS_DEFRAHEAD, 746191783Srmacklem .wcommitsize = 0, /* was: NQ_DEFLEASE */ 747191783Srmacklem .hostname = NULL, 748191783Srmacklem .acregmin = NFS_MINATTRTIMO, 749191783Srmacklem .acregmax = NFS_MAXATTRTIMO, 750191783Srmacklem .acdirmin = NFS_MINDIRATTRTIMO, 751191783Srmacklem .acdirmax = NFS_MAXDIRATTRTIMO, 752191783Srmacklem }; 753192585Srmacklem int error = 0, ret, len; 754192585Srmacklem struct sockaddr *nam = NULL; 755191783Srmacklem struct vnode *vp; 756191990Sattilio struct thread *td; 757191783Srmacklem char hst[MNAMELEN]; 758191783Srmacklem u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100]; 759192585Srmacklem char *opt, *name, *secname; 760203303Srmacklem int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO; 761221014Srmacklem int dirlen, krbnamelen, srvkrbnamelen; 762191783Srmacklem 763191783Srmacklem if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) { 764191783Srmacklem error = EINVAL; 765191783Srmacklem goto out; 766191783Srmacklem } 767191783Srmacklem 768191990Sattilio td = curthread; 769191783Srmacklem if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) { 770221040Srmacklem error = nfs_mountroot(mp); 771191783Srmacklem goto out; 772191783Srmacklem } 773191783Srmacklem 774192585Srmacklem nfscl_init(); 775191783Srmacklem 776192585Srmacklem /* Handle the new style options. */ 777192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0) 778192585Srmacklem args.flags |= NFSMNT_NOCONN; 779192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0) 780192585Srmacklem args.flags |= NFSMNT_NOCONN; 781192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0) 782192585Srmacklem args.flags |= NFSMNT_NOLOCKD; 783192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0) 784192585Srmacklem args.flags &= ~NFSMNT_NOLOCKD; 785192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0) 786192585Srmacklem args.flags |= NFSMNT_INT; 787192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0) 788192585Srmacklem args.flags |= NFSMNT_RDIRPLUS; 789192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0) 790192585Srmacklem args.flags |= NFSMNT_RESVPORT; 791192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0) 792192585Srmacklem args.flags &= ~NFSMNT_RESVPORT; 793192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0) 794192585Srmacklem args.flags |= NFSMNT_SOFT; 795192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0) 796192585Srmacklem args.flags &= ~NFSMNT_SOFT; 797192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0) 798192585Srmacklem args.sotype = SOCK_DGRAM; 799192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0) 800192585Srmacklem args.sotype = SOCK_DGRAM; 801192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0) 802192585Srmacklem args.sotype = SOCK_STREAM; 803192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0) 804192585Srmacklem args.flags |= NFSMNT_NFSV3; 805192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) { 806192585Srmacklem args.flags |= NFSMNT_NFSV4; 807192585Srmacklem args.sotype = SOCK_STREAM; 808191783Srmacklem } 809192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0) 810192585Srmacklem args.flags |= NFSMNT_ALLGSSNAME; 811192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) { 812192585Srmacklem if (opt == NULL) { 813192585Srmacklem vfs_mount_error(mp, "illegal readdirsize"); 814192585Srmacklem error = EINVAL; 815192585Srmacklem goto out; 816192585Srmacklem } 817192585Srmacklem ret = sscanf(opt, "%d", &args.readdirsize); 818192585Srmacklem if (ret != 1 || args.readdirsize <= 0) { 819192585Srmacklem vfs_mount_error(mp, "illegal readdirsize: %s", 820192585Srmacklem opt); 821192585Srmacklem error = EINVAL; 822192585Srmacklem goto out; 823192585Srmacklem } 824192585Srmacklem args.flags |= NFSMNT_READDIRSIZE; 825192585Srmacklem } 826192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) { 827192585Srmacklem if (opt == NULL) { 828192585Srmacklem vfs_mount_error(mp, "illegal readahead"); 829192585Srmacklem error = EINVAL; 830192585Srmacklem goto out; 831192585Srmacklem } 832192585Srmacklem ret = sscanf(opt, "%d", &args.readahead); 833192585Srmacklem if (ret != 1 || args.readahead <= 0) { 834192585Srmacklem vfs_mount_error(mp, "illegal readahead: %s", 835192585Srmacklem opt); 836192585Srmacklem error = EINVAL; 837192585Srmacklem goto out; 838192585Srmacklem } 839192585Srmacklem args.flags |= NFSMNT_READAHEAD; 840192585Srmacklem } 841192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) { 842192585Srmacklem if (opt == NULL) { 843192585Srmacklem vfs_mount_error(mp, "illegal wsize"); 844192585Srmacklem error = EINVAL; 845192585Srmacklem goto out; 846192585Srmacklem } 847192585Srmacklem ret = sscanf(opt, "%d", &args.wsize); 848192585Srmacklem if (ret != 1 || args.wsize <= 0) { 849192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 850192585Srmacklem opt); 851192585Srmacklem error = EINVAL; 852192585Srmacklem goto out; 853192585Srmacklem } 854192585Srmacklem args.flags |= NFSMNT_WSIZE; 855192585Srmacklem } 856192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) { 857192585Srmacklem if (opt == NULL) { 858192585Srmacklem vfs_mount_error(mp, "illegal rsize"); 859192585Srmacklem error = EINVAL; 860192585Srmacklem goto out; 861192585Srmacklem } 862192585Srmacklem ret = sscanf(opt, "%d", &args.rsize); 863192585Srmacklem if (ret != 1 || args.rsize <= 0) { 864192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 865192585Srmacklem opt); 866192585Srmacklem error = EINVAL; 867192585Srmacklem goto out; 868192585Srmacklem } 869192585Srmacklem args.flags |= NFSMNT_RSIZE; 870192585Srmacklem } 871192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) { 872192585Srmacklem if (opt == NULL) { 873192585Srmacklem vfs_mount_error(mp, "illegal retrans"); 874192585Srmacklem error = EINVAL; 875192585Srmacklem goto out; 876192585Srmacklem } 877192585Srmacklem ret = sscanf(opt, "%d", &args.retrans); 878192585Srmacklem if (ret != 1 || args.retrans <= 0) { 879192585Srmacklem vfs_mount_error(mp, "illegal retrans: %s", 880192585Srmacklem opt); 881192585Srmacklem error = EINVAL; 882192585Srmacklem goto out; 883192585Srmacklem } 884192585Srmacklem args.flags |= NFSMNT_RETRANS; 885192585Srmacklem } 886192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) { 887192585Srmacklem ret = sscanf(opt, "%d", &args.acregmin); 888192585Srmacklem if (ret != 1 || args.acregmin < 0) { 889192585Srmacklem vfs_mount_error(mp, "illegal acregmin: %s", 890192585Srmacklem opt); 891192585Srmacklem error = EINVAL; 892192585Srmacklem goto out; 893192585Srmacklem } 894192585Srmacklem args.flags |= NFSMNT_ACREGMIN; 895192585Srmacklem } 896192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) { 897192585Srmacklem ret = sscanf(opt, "%d", &args.acregmax); 898192585Srmacklem if (ret != 1 || args.acregmax < 0) { 899192585Srmacklem vfs_mount_error(mp, "illegal acregmax: %s", 900192585Srmacklem opt); 901192585Srmacklem error = EINVAL; 902192585Srmacklem goto out; 903192585Srmacklem } 904192585Srmacklem args.flags |= NFSMNT_ACREGMAX; 905192585Srmacklem } 906192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) { 907192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmin); 908192585Srmacklem if (ret != 1 || args.acdirmin < 0) { 909192585Srmacklem vfs_mount_error(mp, "illegal acdirmin: %s", 910192585Srmacklem opt); 911192585Srmacklem error = EINVAL; 912192585Srmacklem goto out; 913192585Srmacklem } 914192585Srmacklem args.flags |= NFSMNT_ACDIRMIN; 915192585Srmacklem } 916192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) { 917192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmax); 918192585Srmacklem if (ret != 1 || args.acdirmax < 0) { 919192585Srmacklem vfs_mount_error(mp, "illegal acdirmax: %s", 920192585Srmacklem opt); 921192585Srmacklem error = EINVAL; 922192585Srmacklem goto out; 923192585Srmacklem } 924192585Srmacklem args.flags |= NFSMNT_ACDIRMAX; 925192585Srmacklem } 926192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) { 927192585Srmacklem ret = sscanf(opt, "%d", &args.timeo); 928192585Srmacklem if (ret != 1 || args.timeo <= 0) { 929192585Srmacklem vfs_mount_error(mp, "illegal timeout: %s", 930192585Srmacklem opt); 931192585Srmacklem error = EINVAL; 932192585Srmacklem goto out; 933192585Srmacklem } 934192585Srmacklem args.flags |= NFSMNT_TIMEO; 935192585Srmacklem } 936203303Srmacklem if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL) 937203303Srmacklem == 0) { 938203303Srmacklem ret = sscanf(opt, "%d", &negnametimeo); 939203303Srmacklem if (ret != 1 || negnametimeo < 0) { 940203303Srmacklem vfs_mount_error(mp, "illegal negnametimeo: %s", 941203303Srmacklem opt); 942203303Srmacklem error = EINVAL; 943203303Srmacklem goto out; 944203303Srmacklem } 945203303Srmacklem } 946192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "sec", 947192585Srmacklem (void **) &secname, NULL) == 0) 948192585Srmacklem nfs_sec_name(secname, &args.flags); 949191783Srmacklem 950191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 951191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 952191783Srmacklem 953191783Srmacklem if (nmp == NULL) { 954191783Srmacklem error = EIO; 955191783Srmacklem goto out; 956191783Srmacklem } 957191783Srmacklem /* 958191783Srmacklem * When doing an update, we can't change version, 959191783Srmacklem * security, switch lockd strategies or change cookie 960191783Srmacklem * translation 961191783Srmacklem */ 962191783Srmacklem args.flags = (args.flags & 963191783Srmacklem ~(NFSMNT_NFSV3 | 964191783Srmacklem NFSMNT_NFSV4 | 965191783Srmacklem NFSMNT_KERB | 966191783Srmacklem NFSMNT_INTEGRITY | 967191783Srmacklem NFSMNT_PRIVACY | 968191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) | 969191783Srmacklem (nmp->nm_flag & 970191783Srmacklem (NFSMNT_NFSV3 | 971191783Srmacklem NFSMNT_NFSV4 | 972191783Srmacklem NFSMNT_KERB | 973191783Srmacklem NFSMNT_INTEGRITY | 974191783Srmacklem NFSMNT_PRIVACY | 975191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); 976214048Srmacklem nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td); 977191783Srmacklem goto out; 978191783Srmacklem } 979191783Srmacklem 980191783Srmacklem /* 981191783Srmacklem * Make the nfs_ip_paranoia sysctl serve as the default connection 982191783Srmacklem * or no-connection mode for those protocols that support 983191783Srmacklem * no-connection mode (the flag will be cleared later for protocols 984191783Srmacklem * that do not support no-connection mode). This will allow a client 985191783Srmacklem * to receive replies from a different IP then the request was 986191783Srmacklem * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid), 987191783Srmacklem * not 0. 988191783Srmacklem */ 989191783Srmacklem if (nfs_ip_paranoia == 0) 990191783Srmacklem args.flags |= NFSMNT_NOCONN; 991192585Srmacklem 992192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh, 993192585Srmacklem &args.fhsize) == 0) { 994208234Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) { 995192585Srmacklem vfs_mount_error(mp, "Bad file handle"); 996191783Srmacklem error = EINVAL; 997191783Srmacklem goto out; 998191783Srmacklem } 999192585Srmacklem bcopy(args.fh, nfh, args.fhsize); 1000191783Srmacklem } else { 1001192585Srmacklem args.fhsize = 0; 1002192585Srmacklem } 1003192585Srmacklem 1004192585Srmacklem (void) vfs_getopt(mp->mnt_optnew, "hostname", (void **)&args.hostname, 1005192585Srmacklem &len); 1006192585Srmacklem if (args.hostname == NULL) { 1007192585Srmacklem vfs_mount_error(mp, "Invalid hostname"); 1008192585Srmacklem error = EINVAL; 1009192585Srmacklem goto out; 1010192585Srmacklem } 1011192585Srmacklem bcopy(args.hostname, hst, MNAMELEN); 1012192585Srmacklem hst[MNAMELEN - 1] = '\0'; 1013192585Srmacklem 1014192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0) 1015192585Srmacklem strlcpy(srvkrbname, name, sizeof (srvkrbname)); 1016192585Srmacklem else 1017192585Srmacklem snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst); 1018221014Srmacklem srvkrbnamelen = strlen(srvkrbname); 1019192585Srmacklem 1020192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0) 1021192585Srmacklem strlcpy(krbname, name, sizeof (krbname)); 1022192585Srmacklem else 1023191783Srmacklem krbname[0] = '\0'; 1024221014Srmacklem krbnamelen = strlen(krbname); 1025192585Srmacklem 1026192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0) 1027192585Srmacklem strlcpy(dirpath, name, sizeof (dirpath)); 1028192585Srmacklem else 1029191783Srmacklem dirpath[0] = '\0'; 1030221014Srmacklem dirlen = strlen(dirpath); 1031192585Srmacklem 1032192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "addr", (void **)&args.addr, 1033192585Srmacklem &args.addrlen) == 0) { 1034192585Srmacklem if (args.addrlen > SOCK_MAXADDRLEN) { 1035192585Srmacklem error = ENAMETOOLONG; 1036191783Srmacklem goto out; 1037191783Srmacklem } 1038192585Srmacklem nam = malloc(args.addrlen, M_SONAME, M_WAITOK); 1039192585Srmacklem bcopy(args.addr, nam, args.addrlen); 1040192585Srmacklem nam->sa_len = args.addrlen; 1041191783Srmacklem } 1042192585Srmacklem 1043191783Srmacklem args.fh = nfh; 1044221014Srmacklem error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath, 1045221014Srmacklem dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td, 1046221014Srmacklem negnametimeo); 1047191783Srmacklemout: 1048191783Srmacklem if (!error) { 1049191783Srmacklem MNT_ILOCK(mp); 1050191783Srmacklem mp->mnt_kern_flag |= (MNTK_MPSAFE|MNTK_LOOKUP_SHARED); 1051191783Srmacklem MNT_IUNLOCK(mp); 1052191783Srmacklem } 1053191783Srmacklem return (error); 1054191783Srmacklem} 1055191783Srmacklem 1056191783Srmacklem 1057191783Srmacklem/* 1058191783Srmacklem * VFS Operations. 1059191783Srmacklem * 1060191783Srmacklem * mount system call 1061191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 1062191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 1063191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 1064191783Srmacklem * an error after that means that I have to release the mbuf. 1065191783Srmacklem */ 1066191783Srmacklem/* ARGSUSED */ 1067191783Srmacklemstatic int 1068191990Sattilionfs_cmount(struct mntarg *ma, void *data, int flags) 1069191783Srmacklem{ 1070191783Srmacklem int error; 1071191783Srmacklem struct nfs_args args; 1072191783Srmacklem 1073191783Srmacklem error = copyin(data, &args, sizeof (struct nfs_args)); 1074191783Srmacklem if (error) 1075191783Srmacklem return error; 1076191783Srmacklem 1077191783Srmacklem ma = mount_arg(ma, "nfs_args", &args, sizeof args); 1078191783Srmacklem 1079191783Srmacklem error = kernel_mount(ma, flags); 1080191783Srmacklem return (error); 1081191783Srmacklem} 1082191783Srmacklem 1083191783Srmacklem/* 1084191783Srmacklem * Common code for mount and mountroot 1085191783Srmacklem */ 1086191783Srmacklemstatic int 1087191783Srmacklemmountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, 1088221014Srmacklem char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen, 1089221014Srmacklem u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp, 1090221014Srmacklem struct ucred *cred, struct thread *td, int negnametimeo) 1091191783Srmacklem{ 1092191783Srmacklem struct nfsmount *nmp; 1093191783Srmacklem struct nfsnode *np; 1094195762Srmacklem int error, trycnt, ret; 1095191783Srmacklem struct nfsvattr nfsva; 1096191783Srmacklem static u_int64_t clval = 0; 1097191783Srmacklem 1098191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 1099191783Srmacklem nmp = VFSTONFS(mp); 1100191783Srmacklem printf("%s: MNT_UPDATE is no longer handled here\n", __func__); 1101191783Srmacklem FREE(nam, M_SONAME); 1102191783Srmacklem return (0); 1103191783Srmacklem } else { 1104191783Srmacklem MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) + 1105221014Srmacklem krbnamelen + dirlen + srvkrbnamelen + 2, 1106221014Srmacklem M_NEWNFSMNT, M_WAITOK | M_ZERO); 1107191783Srmacklem TAILQ_INIT(&nmp->nm_bufq); 1108191783Srmacklem if (clval == 0) 1109191783Srmacklem clval = (u_int64_t)nfsboottime.tv_sec; 1110191783Srmacklem nmp->nm_clval = clval++; 1111221014Srmacklem nmp->nm_krbnamelen = krbnamelen; 1112221014Srmacklem nmp->nm_dirpathlen = dirlen; 1113221014Srmacklem nmp->nm_srvkrbnamelen = srvkrbnamelen; 1114192675Srmacklem if (td->td_ucred->cr_uid != (uid_t)0) { 1115191783Srmacklem /* 1116192675Srmacklem * nm_uid is used to get KerberosV credentials for 1117192675Srmacklem * the nfsv4 state handling operations if there is 1118192675Srmacklem * no host based principal set. Use the uid of 1119192675Srmacklem * this user if not root, since they are doing the 1120192675Srmacklem * mount. I don't think setting this for root will 1121192675Srmacklem * work, since root normally does not have user 1122192675Srmacklem * credentials in a credentials cache. 1123191783Srmacklem */ 1124192675Srmacklem nmp->nm_uid = td->td_ucred->cr_uid; 1125191783Srmacklem } else { 1126191783Srmacklem /* 1127192675Srmacklem * Just set to -1, so it won't be used. 1128191783Srmacklem */ 1129191783Srmacklem nmp->nm_uid = (uid_t)-1; 1130191783Srmacklem } 1131191783Srmacklem 1132191783Srmacklem /* Copy and null terminate all the names */ 1133191783Srmacklem if (nmp->nm_krbnamelen > 0) { 1134191783Srmacklem bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen); 1135191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen] = '\0'; 1136191783Srmacklem } 1137191783Srmacklem if (nmp->nm_dirpathlen > 0) { 1138191783Srmacklem bcopy(dirpath, NFSMNT_DIRPATH(nmp), 1139191783Srmacklem nmp->nm_dirpathlen); 1140191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1141191783Srmacklem + 1] = '\0'; 1142191783Srmacklem } 1143191783Srmacklem if (nmp->nm_srvkrbnamelen > 0) { 1144191783Srmacklem bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp), 1145191783Srmacklem nmp->nm_srvkrbnamelen); 1146191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1147191783Srmacklem + nmp->nm_srvkrbnamelen + 2] = '\0'; 1148191783Srmacklem } 1149191783Srmacklem nmp->nm_sockreq.nr_cred = crhold(cred); 1150191783Srmacklem mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF); 1151191783Srmacklem mp->mnt_data = nmp; 1152214048Srmacklem nmp->nm_getinfo = nfs_getnlminfo; 1153216931Srmacklem nmp->nm_vinvalbuf = ncl_vinvalbuf; 1154191783Srmacklem } 1155191783Srmacklem vfs_getnewfsid(mp); 1156191783Srmacklem nmp->nm_mountp = mp; 1157191783Srmacklem mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK); 1158203303Srmacklem nmp->nm_negnametimeo = negnametimeo; 1159191783Srmacklem 1160214048Srmacklem nfs_decode_args(mp, nmp, argp, hst, cred, td); 1161192585Srmacklem 1162191783Srmacklem /* 1163191783Srmacklem * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too 1164191783Srmacklem * high, depending on whether we end up with negative offsets in 1165191783Srmacklem * the client or server somewhere. 2GB-1 may be safer. 1166191783Srmacklem * 1167191783Srmacklem * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum 1168191783Srmacklem * that we can handle until we find out otherwise. 1169191783Srmacklem * XXX Our "safe" limit on the client is what we can store in our 1170191783Srmacklem * buffer cache using signed(!) block numbers. 1171191783Srmacklem */ 1172191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) 1173191783Srmacklem nmp->nm_maxfilesize = 0xffffffffLL; 1174191783Srmacklem else 1175191783Srmacklem nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1; 1176191783Srmacklem 1177191783Srmacklem nmp->nm_timeo = NFS_TIMEO; 1178191783Srmacklem nmp->nm_retry = NFS_RETRANS; 1179191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 1180191783Srmacklem nmp->nm_wsize = NFS_WSIZE; 1181191783Srmacklem nmp->nm_rsize = NFS_RSIZE; 1182191783Srmacklem nmp->nm_readdirsize = NFS_READDIRSIZE; 1183191783Srmacklem } 1184191783Srmacklem nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000); 1185191783Srmacklem nmp->nm_numgrps = NFS_MAXGRPS; 1186191783Srmacklem nmp->nm_readahead = NFS_DEFRAHEAD; 1187191783Srmacklem nmp->nm_tprintf_delay = nfs_tprintf_delay; 1188191783Srmacklem if (nmp->nm_tprintf_delay < 0) 1189191783Srmacklem nmp->nm_tprintf_delay = 0; 1190191783Srmacklem nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay; 1191191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1192191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1193191783Srmacklem nmp->nm_fhsize = argp->fhsize; 1194191783Srmacklem if (nmp->nm_fhsize > 0) 1195191783Srmacklem bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 1196191783Srmacklem bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 1197191783Srmacklem nmp->nm_nam = nam; 1198191783Srmacklem /* Set up the sockets and per-host congestion */ 1199191783Srmacklem nmp->nm_sotype = argp->sotype; 1200191783Srmacklem nmp->nm_soproto = argp->proto; 1201191783Srmacklem nmp->nm_sockreq.nr_prog = NFS_PROG; 1202191783Srmacklem if ((argp->flags & NFSMNT_NFSV4)) 1203191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER4; 1204191783Srmacklem else if ((argp->flags & NFSMNT_NFSV3)) 1205191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER3; 1206191783Srmacklem else 1207191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER2; 1208191783Srmacklem 1209191783Srmacklem 1210191783Srmacklem if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0))) 1211191783Srmacklem goto bad; 1212191783Srmacklem 1213191783Srmacklem /* 1214191783Srmacklem * A reference count is needed on the nfsnode representing the 1215191783Srmacklem * remote root. If this object is not persistent, then backward 1216191783Srmacklem * traversals of the mount point (i.e. "..") will not work if 1217191783Srmacklem * the nfsnode gets flushed out of the cache. Ufs does not have 1218191783Srmacklem * this problem, because one can identify root inodes by their 1219191783Srmacklem * number == ROOTINO (2). 1220191783Srmacklem */ 1221191783Srmacklem if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) && 1222191783Srmacklem nmp->nm_dirpathlen > 0) { 1223191783Srmacklem /* 1224191783Srmacklem * If the fhsize on the mount point == 0 for V4, the mount 1225191783Srmacklem * path needs to be looked up. 1226191783Srmacklem */ 1227191783Srmacklem trycnt = 3; 1228191783Srmacklem do { 1229191783Srmacklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 1230191783Srmacklem cred, td); 1231191783Srmacklem if (error) 1232207170Srmacklem (void) nfs_catnap(PZERO, error, "nfsgetdirp"); 1233191783Srmacklem } while (error && --trycnt > 0); 1234191783Srmacklem if (error) { 1235191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1236191783Srmacklem goto bad; 1237191783Srmacklem } 1238191783Srmacklem } 1239191783Srmacklem if (nmp->nm_fhsize > 0) { 1240195762Srmacklem /* 1241195762Srmacklem * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set 1242195762Srmacklem * non-zero for the root vnode. f_iosize will be set correctly 1243195762Srmacklem * by nfs_statfs() before any I/O occurs. 1244195762Srmacklem */ 1245195762Srmacklem mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ; 1246220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, 1247220732Srmacklem LK_EXCLUSIVE); 1248191783Srmacklem if (error) 1249191783Srmacklem goto bad; 1250191783Srmacklem *vpp = NFSTOV(np); 1251191783Srmacklem 1252191783Srmacklem /* 1253191783Srmacklem * Get file attributes and transfer parameters for the 1254191783Srmacklem * mountpoint. This has the side effect of filling in 1255191783Srmacklem * (*vpp)->v_type with the correct value. 1256191783Srmacklem */ 1257191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 1258191783Srmacklem cred, td, &nfsva, NULL); 1259191783Srmacklem if (ret) { 1260191783Srmacklem /* 1261191783Srmacklem * Just set default values to get things going. 1262191783Srmacklem */ 1263191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 1264191783Srmacklem nfsva.na_vattr.va_type = VDIR; 1265191783Srmacklem nfsva.na_vattr.va_mode = 0777; 1266191783Srmacklem nfsva.na_vattr.va_nlink = 100; 1267191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 1268191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 1269191783Srmacklem nfsva.na_vattr.va_fileid = 2; 1270191783Srmacklem nfsva.na_vattr.va_gen = 1; 1271191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 1272191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 1273191783Srmacklem } 1274191783Srmacklem (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1); 1275191783Srmacklem if (argp->flags & NFSMNT_NFSV3) 1276191783Srmacklem ncl_fsinfo(nmp, *vpp, cred, td); 1277191783Srmacklem 1278191783Srmacklem /* 1279191783Srmacklem * Lose the lock but keep the ref. 1280191783Srmacklem */ 1281191783Srmacklem VOP_UNLOCK(*vpp, 0); 1282191783Srmacklem return (0); 1283191783Srmacklem } 1284191783Srmacklem error = EIO; 1285191783Srmacklem 1286191783Srmacklembad: 1287191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1288191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1289191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1290191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1291191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1292191783Srmacklem FREE(nam, M_SONAME); 1293191783Srmacklem return (error); 1294191783Srmacklem} 1295191783Srmacklem 1296191783Srmacklem/* 1297191783Srmacklem * unmount system call 1298191783Srmacklem */ 1299191783Srmacklemstatic int 1300191990Sattilionfs_unmount(struct mount *mp, int mntflags) 1301191783Srmacklem{ 1302191990Sattilio struct thread *td; 1303191783Srmacklem struct nfsmount *nmp; 1304191783Srmacklem int error, flags = 0, trycnt = 0; 1305191783Srmacklem 1306191990Sattilio td = curthread; 1307191990Sattilio 1308191783Srmacklem if (mntflags & MNT_FORCE) 1309191783Srmacklem flags |= FORCECLOSE; 1310191783Srmacklem nmp = VFSTONFS(mp); 1311191783Srmacklem /* 1312191783Srmacklem * Goes something like this.. 1313191783Srmacklem * - Call vflush() to clear out vnodes for this filesystem 1314191783Srmacklem * - Close the socket 1315191783Srmacklem * - Free up the data structures 1316191783Srmacklem */ 1317191783Srmacklem /* In the forced case, cancel any outstanding requests. */ 1318191783Srmacklem if (mntflags & MNT_FORCE) { 1319191783Srmacklem error = newnfs_nmcancelreqs(nmp); 1320191783Srmacklem if (error) 1321191783Srmacklem goto out; 1322191783Srmacklem /* For a forced close, get rid of the renew thread now */ 1323191783Srmacklem nfscl_umount(nmp, td); 1324191783Srmacklem } 1325191783Srmacklem /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ 1326191783Srmacklem do { 1327191783Srmacklem error = vflush(mp, 1, flags, td); 1328191783Srmacklem if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30) 1329207170Srmacklem (void) nfs_catnap(PSOCK, error, "newndm"); 1330191783Srmacklem } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30); 1331191783Srmacklem if (error) 1332191783Srmacklem goto out; 1333191783Srmacklem 1334191783Srmacklem /* 1335191783Srmacklem * We are now committed to the unmount. 1336191783Srmacklem */ 1337191783Srmacklem if ((mntflags & MNT_FORCE) == 0) 1338191783Srmacklem nfscl_umount(nmp, td); 1339191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1340191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1341191783Srmacklem FREE(nmp->nm_nam, M_SONAME); 1342191783Srmacklem 1343191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1344191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1345191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1346191783Srmacklemout: 1347191783Srmacklem return (error); 1348191783Srmacklem} 1349191783Srmacklem 1350191783Srmacklem/* 1351191783Srmacklem * Return root of a filesystem 1352191783Srmacklem */ 1353191783Srmacklemstatic int 1354191990Sattilionfs_root(struct mount *mp, int flags, struct vnode **vpp) 1355191783Srmacklem{ 1356191783Srmacklem struct vnode *vp; 1357191783Srmacklem struct nfsmount *nmp; 1358191783Srmacklem struct nfsnode *np; 1359191783Srmacklem int error; 1360191783Srmacklem 1361191783Srmacklem nmp = VFSTONFS(mp); 1362220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags); 1363191783Srmacklem if (error) 1364191783Srmacklem return error; 1365191783Srmacklem vp = NFSTOV(np); 1366191783Srmacklem /* 1367191783Srmacklem * Get transfer parameters and attributes for root vnode once. 1368191783Srmacklem */ 1369191783Srmacklem mtx_lock(&nmp->nm_mtx); 1370191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 1371191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1372191783Srmacklem ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread); 1373191783Srmacklem } else 1374191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1375191783Srmacklem if (vp->v_type == VNON) 1376191783Srmacklem vp->v_type = VDIR; 1377191783Srmacklem vp->v_vflag |= VV_ROOT; 1378191783Srmacklem *vpp = vp; 1379191783Srmacklem return (0); 1380191783Srmacklem} 1381191783Srmacklem 1382191783Srmacklem/* 1383191783Srmacklem * Flush out the buffer cache 1384191783Srmacklem */ 1385191783Srmacklem/* ARGSUSED */ 1386191783Srmacklemstatic int 1387191990Sattilionfs_sync(struct mount *mp, int waitfor) 1388191783Srmacklem{ 1389191783Srmacklem struct vnode *vp, *mvp; 1390191990Sattilio struct thread *td; 1391191783Srmacklem int error, allerror = 0; 1392191783Srmacklem 1393191990Sattilio td = curthread; 1394191990Sattilio 1395191783Srmacklem /* 1396191783Srmacklem * Force stale buffer cache information to be flushed. 1397191783Srmacklem */ 1398191783Srmacklem MNT_ILOCK(mp); 1399191783Srmacklemloop: 1400191783Srmacklem MNT_VNODE_FOREACH(vp, mp, mvp) { 1401191783Srmacklem VI_LOCK(vp); 1402191783Srmacklem MNT_IUNLOCK(mp); 1403191783Srmacklem /* XXX Racy bv_cnt check. */ 1404191783Srmacklem if (VOP_ISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1405191783Srmacklem waitfor == MNT_LAZY) { 1406191783Srmacklem VI_UNLOCK(vp); 1407191783Srmacklem MNT_ILOCK(mp); 1408191783Srmacklem continue; 1409191783Srmacklem } 1410191783Srmacklem if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 1411191783Srmacklem MNT_ILOCK(mp); 1412191783Srmacklem MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); 1413191783Srmacklem goto loop; 1414191783Srmacklem } 1415191783Srmacklem error = VOP_FSYNC(vp, waitfor, td); 1416191783Srmacklem if (error) 1417191783Srmacklem allerror = error; 1418191783Srmacklem VOP_UNLOCK(vp, 0); 1419191783Srmacklem vrele(vp); 1420191783Srmacklem 1421191783Srmacklem MNT_ILOCK(mp); 1422191783Srmacklem } 1423191783Srmacklem MNT_IUNLOCK(mp); 1424191783Srmacklem return (allerror); 1425191783Srmacklem} 1426191783Srmacklem 1427191783Srmacklemstatic int 1428191783Srmacklemnfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 1429191783Srmacklem{ 1430191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1431191783Srmacklem struct vfsquery vq; 1432191783Srmacklem int error; 1433191783Srmacklem 1434191783Srmacklem bzero(&vq, sizeof(vq)); 1435191783Srmacklem switch (op) { 1436191783Srmacklem#if 0 1437191783Srmacklem case VFS_CTL_NOLOCKS: 1438191783Srmacklem val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; 1439191783Srmacklem if (req->oldptr != NULL) { 1440191783Srmacklem error = SYSCTL_OUT(req, &val, sizeof(val)); 1441191783Srmacklem if (error) 1442191783Srmacklem return (error); 1443191783Srmacklem } 1444191783Srmacklem if (req->newptr != NULL) { 1445191783Srmacklem error = SYSCTL_IN(req, &val, sizeof(val)); 1446191783Srmacklem if (error) 1447191783Srmacklem return (error); 1448191783Srmacklem if (val) 1449191783Srmacklem nmp->nm_flag |= NFSMNT_NOLOCKS; 1450191783Srmacklem else 1451191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOLOCKS; 1452191783Srmacklem } 1453191783Srmacklem break; 1454191783Srmacklem#endif 1455191783Srmacklem case VFS_CTL_QUERY: 1456191783Srmacklem mtx_lock(&nmp->nm_mtx); 1457191783Srmacklem if (nmp->nm_state & NFSSTA_TIMEO) 1458191783Srmacklem vq.vq_flags |= VQ_NOTRESP; 1459191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1460191783Srmacklem#if 0 1461191783Srmacklem if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && 1462191783Srmacklem (nmp->nm_state & NFSSTA_LOCKTIMEO)) 1463191783Srmacklem vq.vq_flags |= VQ_NOTRESPLOCK; 1464191783Srmacklem#endif 1465191783Srmacklem error = SYSCTL_OUT(req, &vq, sizeof(vq)); 1466191783Srmacklem break; 1467191783Srmacklem case VFS_CTL_TIMEO: 1468191783Srmacklem if (req->oldptr != NULL) { 1469191783Srmacklem error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, 1470191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1471191783Srmacklem if (error) 1472191783Srmacklem return (error); 1473191783Srmacklem } 1474191783Srmacklem if (req->newptr != NULL) { 1475191783Srmacklem error = vfs_suser(mp, req->td); 1476191783Srmacklem if (error) 1477191783Srmacklem return (error); 1478191783Srmacklem error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, 1479191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1480191783Srmacklem if (error) 1481191783Srmacklem return (error); 1482191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1483191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1484191783Srmacklem } 1485191783Srmacklem break; 1486191783Srmacklem default: 1487191783Srmacklem return (ENOTSUP); 1488191783Srmacklem } 1489191783Srmacklem return (0); 1490191783Srmacklem} 1491191783Srmacklem 1492214048Srmacklem/* 1493214048Srmacklem * Extract the information needed by the nlm from the nfs vnode. 1494214048Srmacklem */ 1495214048Srmacklemstatic void 1496214053Srmacklemnfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp, 1497216931Srmacklem struct sockaddr_storage *sp, int *is_v3p, off_t *sizep, 1498216931Srmacklem struct timeval *timeop) 1499214048Srmacklem{ 1500214048Srmacklem struct nfsmount *nmp; 1501214048Srmacklem struct nfsnode *np = VTONFS(vp); 1502214048Srmacklem 1503214048Srmacklem nmp = VFSTONFS(vp->v_mount); 1504214048Srmacklem if (fhlenp != NULL) 1505214053Srmacklem *fhlenp = (size_t)np->n_fhp->nfh_len; 1506214048Srmacklem if (fhp != NULL) 1507214048Srmacklem bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len); 1508214048Srmacklem if (sp != NULL) 1509214048Srmacklem bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp))); 1510214048Srmacklem if (is_v3p != NULL) 1511214048Srmacklem *is_v3p = NFS_ISV3(vp); 1512214048Srmacklem if (sizep != NULL) 1513214048Srmacklem *sizep = np->n_size; 1514216931Srmacklem if (timeop != NULL) { 1515216931Srmacklem timeop->tv_sec = nmp->nm_timeo / NFS_HZ; 1516216931Srmacklem timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ); 1517216931Srmacklem } 1518214048Srmacklem} 1519214048Srmacklem 1520