nfs_clvfsops.c revision 220732
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 220732 2011-04-16 23:20:21Z 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> 49191783Srmacklem#include <sys/lock.h> 50191783Srmacklem#include <sys/malloc.h> 51191783Srmacklem#include <sys/mbuf.h> 52191783Srmacklem#include <sys/module.h> 53191783Srmacklem#include <sys/mount.h> 54191783Srmacklem#include <sys/proc.h> 55191783Srmacklem#include <sys/socket.h> 56191783Srmacklem#include <sys/socketvar.h> 57191783Srmacklem#include <sys/sockio.h> 58191783Srmacklem#include <sys/sysctl.h> 59191783Srmacklem#include <sys/vnode.h> 60191783Srmacklem#include <sys/signalvar.h> 61191783Srmacklem 62191783Srmacklem#include <vm/vm.h> 63191783Srmacklem#include <vm/vm_extern.h> 64191783Srmacklem#include <vm/uma.h> 65191783Srmacklem 66191783Srmacklem#include <net/if.h> 67191783Srmacklem#include <net/route.h> 68191783Srmacklem#include <netinet/in.h> 69191783Srmacklem 70191783Srmacklem#include <fs/nfs/nfsport.h> 71191783Srmacklem#include <fs/nfsclient/nfsnode.h> 72191783Srmacklem#include <fs/nfsclient/nfsmount.h> 73191783Srmacklem#include <fs/nfsclient/nfs.h> 74191783Srmacklem#include <fs/nfsclient/nfsdiskless.h> 75191783Srmacklem 76219028SnetchildFEATURE(nfscl, "NFSv4 client"); 77219028Snetchild 78191783Srmacklemextern int nfscl_ticks; 79191783Srmacklemextern struct timeval nfsboottime; 80191783Srmacklemextern struct nfsstats newnfsstats; 81191783Srmacklem 82191783SrmacklemMALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header"); 83191783SrmacklemMALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct"); 84191783Srmacklem 85191783SrmacklemSYSCTL_DECL(_vfs_newnfs); 86191783SrmacklemSYSCTL_STRUCT(_vfs_newnfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RW, 87191783Srmacklem &newnfsstats, nfsstats, "S,nfsstats"); 88191783Srmacklemstatic int nfs_ip_paranoia = 1; 89191783SrmacklemSYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW, 90191783Srmacklem &nfs_ip_paranoia, 0, ""); 91191783Srmacklemstatic int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY; 92191783SrmacklemSYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_INITIAL_DELAY, 93191783Srmacklem downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, ""); 94191783Srmacklem/* how long between console messages "nfs server foo not responding" */ 95191783Srmacklemstatic int nfs_tprintf_delay = NFS_TPRINTF_DELAY; 96191783SrmacklemSYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_DELAY, 97191783Srmacklem downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, ""); 98191783Srmacklem 99192585Srmacklemstatic void nfs_sec_name(char *, int *); 100191783Srmacklemstatic void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, 101214048Srmacklem struct nfs_args *argp, const char *, struct ucred *, 102214048Srmacklem struct thread *); 103191783Srmacklemstatic int mountnfs(struct nfs_args *, struct mount *, 104191783Srmacklem struct sockaddr *, char *, u_char *, u_char *, u_char *, 105203303Srmacklem struct vnode **, struct ucred *, struct thread *, int); 106214053Srmacklemstatic void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *, 107216931Srmacklem struct sockaddr_storage *, int *, off_t *, 108216931Srmacklem struct timeval *); 109191783Srmacklemstatic vfs_mount_t nfs_mount; 110191783Srmacklemstatic vfs_cmount_t nfs_cmount; 111191783Srmacklemstatic vfs_unmount_t nfs_unmount; 112191783Srmacklemstatic vfs_root_t nfs_root; 113191783Srmacklemstatic vfs_statfs_t nfs_statfs; 114191783Srmacklemstatic vfs_sync_t nfs_sync; 115191783Srmacklemstatic vfs_sysctl_t nfs_sysctl; 116191783Srmacklem 117191783Srmacklem/* 118191783Srmacklem * nfs vfs operations. 119191783Srmacklem */ 120191783Srmacklemstatic struct vfsops nfs_vfsops = { 121191783Srmacklem .vfs_init = ncl_init, 122191783Srmacklem .vfs_mount = nfs_mount, 123191783Srmacklem .vfs_cmount = nfs_cmount, 124191783Srmacklem .vfs_root = nfs_root, 125191783Srmacklem .vfs_statfs = nfs_statfs, 126191783Srmacklem .vfs_sync = nfs_sync, 127191783Srmacklem .vfs_uninit = ncl_uninit, 128191783Srmacklem .vfs_unmount = nfs_unmount, 129191783Srmacklem .vfs_sysctl = nfs_sysctl, 130191783Srmacklem}; 131191783SrmacklemVFS_SET(nfs_vfsops, newnfs, VFCF_NETWORK); 132191783Srmacklem 133191783Srmacklem/* So that loader and kldload(2) can find us, wherever we are.. */ 134191783SrmacklemMODULE_VERSION(newnfs, 1); 135191783Srmacklem 136191783Srmacklem/* 137191783Srmacklem * This structure must be filled in by a primary bootstrap or bootstrap 138191783Srmacklem * server for a diskless/dataless machine. It is initialized below just 139191783Srmacklem * to ensure that it is allocated to initialized data (.data not .bss). 140191783Srmacklem */ 141191783Srmacklemstruct nfs_diskless newnfs_diskless = { { { 0 } } }; 142191783Srmacklemstruct nfsv3_diskless newnfsv3_diskless = { { { 0 } } }; 143191783Srmacklemint newnfs_diskless_valid = 0; 144191783Srmacklem 145191783SrmacklemSYSCTL_INT(_vfs_newnfs, OID_AUTO, diskless_valid, CTLFLAG_RD, 146192145Srmacklem &newnfs_diskless_valid, 0, 147192145Srmacklem "Has the diskless struct been filled correctly"); 148191783Srmacklem 149191783SrmacklemSYSCTL_STRING(_vfs_newnfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD, 150192145Srmacklem newnfsv3_diskless.root_hostnam, 0, "Path to nfs root"); 151191783Srmacklem 152191783SrmacklemSYSCTL_OPAQUE(_vfs_newnfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD, 153192145Srmacklem &newnfsv3_diskless.root_saddr, sizeof newnfsv3_diskless.root_saddr, 154192145Srmacklem "%Ssockaddr_in", "Diskless root nfs address"); 155191783Srmacklem 156191783Srmacklem 157191783Srmacklemvoid newnfsargs_ntoh(struct nfs_args *); 158191783Srmacklemstatic int nfs_mountdiskless(char *, 159191783Srmacklem struct sockaddr_in *, struct nfs_args *, 160191783Srmacklem struct thread *, struct vnode **, struct mount *); 161191783Srmacklemstatic void nfs_convert_diskless(void); 162191783Srmacklemstatic void nfs_convert_oargs(struct nfs_args *args, 163191783Srmacklem struct onfs_args *oargs); 164191783Srmacklem 165191783Srmacklemint 166191783Srmacklemnewnfs_iosize(struct nfsmount *nmp) 167191783Srmacklem{ 168191783Srmacklem int iosize, maxio; 169191783Srmacklem 170191783Srmacklem /* First, set the upper limit for iosize */ 171191783Srmacklem if (nmp->nm_flag & NFSMNT_NFSV4) { 172191783Srmacklem maxio = NFS_MAXBSIZE; 173191783Srmacklem } else if (nmp->nm_flag & NFSMNT_NFSV3) { 174191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 175191783Srmacklem maxio = NFS_MAXDGRAMDATA; 176191783Srmacklem else 177191783Srmacklem maxio = NFS_MAXBSIZE; 178191783Srmacklem } else { 179191783Srmacklem maxio = NFS_V2MAXDATA; 180191783Srmacklem } 181191783Srmacklem if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0) 182191783Srmacklem nmp->nm_rsize = maxio; 183191783Srmacklem if (nmp->nm_rsize > MAXBSIZE) 184191783Srmacklem nmp->nm_rsize = MAXBSIZE; 185191783Srmacklem if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0) 186191783Srmacklem nmp->nm_readdirsize = maxio; 187191783Srmacklem if (nmp->nm_readdirsize > nmp->nm_rsize) 188191783Srmacklem nmp->nm_readdirsize = nmp->nm_rsize; 189191783Srmacklem if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0) 190191783Srmacklem nmp->nm_wsize = maxio; 191191783Srmacklem if (nmp->nm_wsize > MAXBSIZE) 192191783Srmacklem nmp->nm_wsize = MAXBSIZE; 193191783Srmacklem 194191783Srmacklem /* 195191783Srmacklem * Calculate the size used for io buffers. Use the larger 196191783Srmacklem * of the two sizes to minimise nfs requests but make sure 197191783Srmacklem * that it is at least one VM page to avoid wasting buffer 198191783Srmacklem * space. 199191783Srmacklem */ 200191783Srmacklem iosize = imax(nmp->nm_rsize, nmp->nm_wsize); 201191783Srmacklem iosize = imax(iosize, PAGE_SIZE); 202191783Srmacklem nmp->nm_mountp->mnt_stat.f_iosize = iosize; 203191783Srmacklem return (iosize); 204191783Srmacklem} 205191783Srmacklem 206191783Srmacklemstatic void 207191783Srmacklemnfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs) 208191783Srmacklem{ 209191783Srmacklem 210191783Srmacklem args->version = NFS_ARGSVERSION; 211191783Srmacklem args->addr = oargs->addr; 212191783Srmacklem args->addrlen = oargs->addrlen; 213191783Srmacklem args->sotype = oargs->sotype; 214191783Srmacklem args->proto = oargs->proto; 215191783Srmacklem args->fh = oargs->fh; 216191783Srmacklem args->fhsize = oargs->fhsize; 217191783Srmacklem args->flags = oargs->flags; 218191783Srmacklem args->wsize = oargs->wsize; 219191783Srmacklem args->rsize = oargs->rsize; 220191783Srmacklem args->readdirsize = oargs->readdirsize; 221191783Srmacklem args->timeo = oargs->timeo; 222191783Srmacklem args->retrans = oargs->retrans; 223191783Srmacklem args->readahead = oargs->readahead; 224191783Srmacklem args->hostname = oargs->hostname; 225191783Srmacklem} 226191783Srmacklem 227191783Srmacklemstatic void 228191783Srmacklemnfs_convert_diskless(void) 229191783Srmacklem{ 230191783Srmacklem 231191783Srmacklem bcopy(&newnfs_diskless.myif, &newnfsv3_diskless.myif, 232192145Srmacklem sizeof (struct ifaliasreq)); 233191783Srmacklem bcopy(&newnfs_diskless.mygateway, &newnfsv3_diskless.mygateway, 234192145Srmacklem sizeof (struct sockaddr_in)); 235192145Srmacklem nfs_convert_oargs(&newnfsv3_diskless.root_args, 236192145Srmacklem &newnfs_diskless.root_args); 237191783Srmacklem if (newnfsv3_diskless.root_args.flags & NFSMNT_NFSV3) { 238191783Srmacklem newnfsv3_diskless.root_fhsize = NFSX_MYFH; 239192145Srmacklem bcopy(newnfs_diskless.root_fh, newnfsv3_diskless.root_fh, 240192145Srmacklem NFSX_MYFH); 241191783Srmacklem } else { 242191783Srmacklem newnfsv3_diskless.root_fhsize = NFSX_V2FH; 243192145Srmacklem bcopy(newnfs_diskless.root_fh, newnfsv3_diskless.root_fh, 244192145Srmacklem NFSX_V2FH); 245191783Srmacklem } 246191783Srmacklem bcopy(&newnfs_diskless.root_saddr,&newnfsv3_diskless.root_saddr, 247192145Srmacklem sizeof(struct sockaddr_in)); 248192145Srmacklem bcopy(newnfs_diskless.root_hostnam, newnfsv3_diskless.root_hostnam, 249192145Srmacklem MNAMELEN); 250191783Srmacklem newnfsv3_diskless.root_time = newnfs_diskless.root_time; 251191783Srmacklem bcopy(newnfs_diskless.my_hostnam, newnfsv3_diskless.my_hostnam, 252192145Srmacklem MAXHOSTNAMELEN); 253191783Srmacklem newnfs_diskless_valid = 3; 254191783Srmacklem} 255191783Srmacklem 256191783Srmacklem/* 257191783Srmacklem * nfs statfs call 258191783Srmacklem */ 259191783Srmacklemstatic int 260191990Sattilionfs_statfs(struct mount *mp, struct statfs *sbp) 261191783Srmacklem{ 262191783Srmacklem struct vnode *vp; 263191990Sattilio struct thread *td; 264191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 265191783Srmacklem struct nfsvattr nfsva; 266191783Srmacklem struct nfsfsinfo fs; 267191783Srmacklem struct nfsstatfs sb; 268191783Srmacklem int error = 0, attrflag, gotfsinfo = 0, ret; 269191783Srmacklem struct nfsnode *np; 270191783Srmacklem 271191990Sattilio td = curthread; 272191990Sattilio 273191783Srmacklem error = vfs_busy(mp, MBF_NOWAIT); 274191783Srmacklem if (error) 275191783Srmacklem return (error); 276220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE); 277191783Srmacklem if (error) { 278191783Srmacklem vfs_unbusy(mp); 279191783Srmacklem return (error); 280191783Srmacklem } 281191783Srmacklem vp = NFSTOV(np); 282191783Srmacklem mtx_lock(&nmp->nm_mtx); 283191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 284191783Srmacklem mtx_unlock(&nmp->nm_mtx); 285191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva, 286191783Srmacklem &attrflag, NULL); 287191783Srmacklem if (!error) 288191783Srmacklem gotfsinfo = 1; 289191783Srmacklem } else 290191783Srmacklem mtx_unlock(&nmp->nm_mtx); 291191783Srmacklem if (!error) 292191783Srmacklem error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, 293191783Srmacklem &attrflag, NULL); 294191783Srmacklem if (attrflag == 0) { 295191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 296191783Srmacklem td->td_ucred, td, &nfsva, NULL); 297191783Srmacklem if (ret) { 298191783Srmacklem /* 299191783Srmacklem * Just set default values to get things going. 300191783Srmacklem */ 301191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 302191783Srmacklem nfsva.na_vattr.va_type = VDIR; 303191783Srmacklem nfsva.na_vattr.va_mode = 0777; 304191783Srmacklem nfsva.na_vattr.va_nlink = 100; 305191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 306191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 307191783Srmacklem nfsva.na_vattr.va_fileid = 2; 308191783Srmacklem nfsva.na_vattr.va_gen = 1; 309191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 310191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 311191783Srmacklem } 312191783Srmacklem } 313191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 314191783Srmacklem if (!error) { 315191783Srmacklem mtx_lock(&nmp->nm_mtx); 316191783Srmacklem if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4)) 317191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 318191783Srmacklem nfscl_loadsbinfo(nmp, &sb, sbp); 319191783Srmacklem sbp->f_flags = nmp->nm_flag; 320191783Srmacklem sbp->f_iosize = newnfs_iosize(nmp); 321191783Srmacklem mtx_unlock(&nmp->nm_mtx); 322191783Srmacklem if (sbp != &mp->mnt_stat) { 323191783Srmacklem bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 324191783Srmacklem bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 325191783Srmacklem } 326191783Srmacklem strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 327191783Srmacklem } else if (NFS_ISV4(vp)) { 328191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 329191783Srmacklem } 330191783Srmacklem vput(vp); 331191783Srmacklem vfs_unbusy(mp); 332191783Srmacklem return (error); 333191783Srmacklem} 334191783Srmacklem 335191783Srmacklem/* 336191783Srmacklem * nfs version 3 fsinfo rpc call 337191783Srmacklem */ 338191783Srmacklemint 339191783Srmacklemncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, 340191783Srmacklem struct thread *td) 341191783Srmacklem{ 342191783Srmacklem struct nfsfsinfo fs; 343191783Srmacklem struct nfsvattr nfsva; 344191783Srmacklem int error, attrflag; 345191783Srmacklem 346191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL); 347191783Srmacklem if (!error) { 348191783Srmacklem if (attrflag) 349191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 350191783Srmacklem 1); 351191783Srmacklem mtx_lock(&nmp->nm_mtx); 352191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 353191783Srmacklem mtx_unlock(&nmp->nm_mtx); 354191783Srmacklem } 355191783Srmacklem return (error); 356191783Srmacklem} 357191783Srmacklem 358191783Srmacklem/* 359191783Srmacklem * Mount a remote root fs via. nfs. This depends on the info in the 360191783Srmacklem * newnfs_diskless structure that has been filled in properly by some primary 361191783Srmacklem * bootstrap. 362191783Srmacklem * It goes something like this: 363191783Srmacklem * - do enough of "ifconfig" by calling ifioctl() so that the system 364191783Srmacklem * can talk to the server 365191783Srmacklem * - If newnfs_diskless.mygateway is filled in, use that address as 366191783Srmacklem * a default gateway. 367191783Srmacklem * - build the rootfs mount point and call mountnfs() to do the rest. 368191783Srmacklem * 369191783Srmacklem * It is assumed to be safe to read, modify, and write the nfsv3_diskless 370191783Srmacklem * structure, as well as other global NFS client variables here, as 371192145Srmacklem * nfs_mountroot() will be called once in the boot before any other NFS 372191783Srmacklem * client activity occurs. 373191783Srmacklem */ 374191783Srmacklemint 375192145Srmacklemncl_mountroot(struct mount *mp) 376191783Srmacklem{ 377192145Srmacklem struct thread *td = curthread; 378191783Srmacklem struct nfsv3_diskless *nd = &newnfsv3_diskless; 379191783Srmacklem struct socket *so; 380191783Srmacklem struct vnode *vp; 381191783Srmacklem struct ifreq ir; 382193066Sjamie int error; 383191783Srmacklem u_long l; 384191783Srmacklem char buf[128]; 385191783Srmacklem char *cp; 386191783Srmacklem 387191783Srmacklem#if defined(BOOTP_NFSROOT) && defined(BOOTP) 388192145Srmacklem bootpc_init(); /* use bootp to get nfs_diskless filled in */ 389191783Srmacklem#elif defined(NFS_ROOT) 390191783Srmacklem nfs_setup_diskless(); 391191783Srmacklem#endif 392191783Srmacklem 393191783Srmacklem if (newnfs_diskless_valid == 0) 394191783Srmacklem return (-1); 395191783Srmacklem if (newnfs_diskless_valid == 1) 396191783Srmacklem nfs_convert_diskless(); 397191783Srmacklem 398191783Srmacklem /* 399191783Srmacklem * XXX splnet, so networks will receive... 400191783Srmacklem */ 401191783Srmacklem splnet(); 402191783Srmacklem 403191783Srmacklem /* 404191783Srmacklem * Do enough of ifconfig(8) so that the critical net interface can 405191783Srmacklem * talk to the server. 406191783Srmacklem */ 407191783Srmacklem error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0, 408191783Srmacklem td->td_ucred, td); 409191783Srmacklem if (error) 410192145Srmacklem panic("nfs_mountroot: socreate(%04x): %d", 411191783Srmacklem nd->myif.ifra_addr.sa_family, error); 412191783Srmacklem 413191783Srmacklem#if 0 /* XXX Bad idea */ 414191783Srmacklem /* 415191783Srmacklem * We might not have been told the right interface, so we pass 416191783Srmacklem * over the first ten interfaces of the same kind, until we get 417191783Srmacklem * one of them configured. 418191783Srmacklem */ 419191783Srmacklem 420191783Srmacklem for (i = strlen(nd->myif.ifra_name) - 1; 421191783Srmacklem nd->myif.ifra_name[i] >= '0' && 422191783Srmacklem nd->myif.ifra_name[i] <= '9'; 423191783Srmacklem nd->myif.ifra_name[i] ++) { 424191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 425191783Srmacklem if(!error) 426191783Srmacklem break; 427191783Srmacklem } 428191783Srmacklem#endif 429191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 430191783Srmacklem if (error) 431192145Srmacklem panic("nfs_mountroot: SIOCAIFADDR: %d", error); 432191783Srmacklem if ((cp = getenv("boot.netif.mtu")) != NULL) { 433191783Srmacklem ir.ifr_mtu = strtol(cp, NULL, 10); 434191783Srmacklem bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); 435191783Srmacklem freeenv(cp); 436191783Srmacklem error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); 437191783Srmacklem if (error) 438192145Srmacklem printf("nfs_mountroot: SIOCSIFMTU: %d", error); 439191783Srmacklem } 440191783Srmacklem soclose(so); 441191783Srmacklem 442191783Srmacklem /* 443191783Srmacklem * If the gateway field is filled in, set it as the default route. 444191783Srmacklem * Note that pxeboot will set a default route of 0 if the route 445191783Srmacklem * is not set by the DHCP server. Check also for a value of 0 446191783Srmacklem * to avoid panicking inappropriately in that situation. 447191783Srmacklem */ 448191783Srmacklem if (nd->mygateway.sin_len != 0 && 449191783Srmacklem nd->mygateway.sin_addr.s_addr != 0) { 450191783Srmacklem struct sockaddr_in mask, sin; 451191783Srmacklem 452191783Srmacklem bzero((caddr_t)&mask, sizeof(mask)); 453191783Srmacklem sin = mask; 454191783Srmacklem sin.sin_family = AF_INET; 455191783Srmacklem sin.sin_len = sizeof(sin); 456192145Srmacklem /* XXX MRT use table 0 for this sort of thing */ 457218757Sbz CURVNET_SET(TD_TO_VNET(td)); 458191783Srmacklem error = rtrequest(RTM_ADD, (struct sockaddr *)&sin, 459191783Srmacklem (struct sockaddr *)&nd->mygateway, 460191783Srmacklem (struct sockaddr *)&mask, 461191783Srmacklem RTF_UP | RTF_GATEWAY, NULL); 462218757Sbz CURVNET_RESTORE(); 463191783Srmacklem if (error) 464192145Srmacklem panic("nfs_mountroot: RTM_ADD: %d", error); 465191783Srmacklem } 466191783Srmacklem 467191783Srmacklem /* 468191783Srmacklem * Create the rootfs mount point. 469191783Srmacklem */ 470191783Srmacklem nd->root_args.fh = nd->root_fh; 471191783Srmacklem nd->root_args.fhsize = nd->root_fhsize; 472191783Srmacklem l = ntohl(nd->root_saddr.sin_addr.s_addr); 473191783Srmacklem snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", 474191783Srmacklem (l >> 24) & 0xff, (l >> 16) & 0xff, 475191783Srmacklem (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); 476191783Srmacklem printf("NFS ROOT: %s\n", buf); 477192145Srmacklem nd->root_args.hostname = buf; 478191783Srmacklem if ((error = nfs_mountdiskless(buf, 479191783Srmacklem &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { 480191783Srmacklem return (error); 481191783Srmacklem } 482191783Srmacklem 483191783Srmacklem /* 484191783Srmacklem * This is not really an nfs issue, but it is much easier to 485191783Srmacklem * set hostname here and then let the "/etc/rc.xxx" files 486191783Srmacklem * mount the right /var based upon its preset value. 487191783Srmacklem */ 488193066Sjamie mtx_lock(&prison0.pr_mtx); 489194118Sjamie strlcpy(prison0.pr_hostname, nd->my_hostnam, 490194118Sjamie sizeof(prison0.pr_hostname)); 491193066Sjamie mtx_unlock(&prison0.pr_mtx); 492191783Srmacklem inittodr(ntohl(nd->root_time)); 493191783Srmacklem return (0); 494191783Srmacklem} 495191783Srmacklem 496191783Srmacklem/* 497191783Srmacklem * Internal version of mount system call for diskless setup. 498191783Srmacklem */ 499191783Srmacklemstatic int 500191783Srmacklemnfs_mountdiskless(char *path, 501191783Srmacklem struct sockaddr_in *sin, struct nfs_args *args, struct thread *td, 502191783Srmacklem struct vnode **vpp, struct mount *mp) 503191783Srmacklem{ 504191783Srmacklem struct sockaddr *nam; 505191783Srmacklem int error; 506191783Srmacklem 507191783Srmacklem nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); 508191783Srmacklem if ((error = mountnfs(args, mp, nam, path, NULL, NULL, NULL, vpp, 509203303Srmacklem td->td_ucred, td, NFS_DEFAULT_NEGNAMETIMEO)) != 0) { 510192145Srmacklem printf("nfs_mountroot: mount %s on /: %d\n", path, error); 511191783Srmacklem return (error); 512191783Srmacklem } 513191783Srmacklem return (0); 514191783Srmacklem} 515191783Srmacklem 516191783Srmacklemstatic void 517192585Srmacklemnfs_sec_name(char *sec, int *flagsp) 518192585Srmacklem{ 519192585Srmacklem if (!strcmp(sec, "krb5")) 520192585Srmacklem *flagsp |= NFSMNT_KERB; 521192585Srmacklem else if (!strcmp(sec, "krb5i")) 522192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY); 523192585Srmacklem else if (!strcmp(sec, "krb5p")) 524192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY); 525192585Srmacklem} 526192585Srmacklem 527192585Srmacklemstatic void 528191783Srmacklemnfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, 529214048Srmacklem const char *hostname, struct ucred *cred, struct thread *td) 530191783Srmacklem{ 531191783Srmacklem int s; 532191783Srmacklem int adjsock; 533214048Srmacklem char *p; 534191783Srmacklem 535191783Srmacklem s = splnet(); 536191783Srmacklem 537191783Srmacklem /* 538191783Srmacklem * Set read-only flag if requested; otherwise, clear it if this is 539191783Srmacklem * an update. If this is not an update, then either the read-only 540191783Srmacklem * flag is already clear, or this is a root mount and it was set 541191783Srmacklem * intentionally at some previous point. 542191783Srmacklem */ 543191783Srmacklem if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) { 544191783Srmacklem MNT_ILOCK(mp); 545191783Srmacklem mp->mnt_flag |= MNT_RDONLY; 546191783Srmacklem MNT_IUNLOCK(mp); 547191783Srmacklem } else if (mp->mnt_flag & MNT_UPDATE) { 548191783Srmacklem MNT_ILOCK(mp); 549191783Srmacklem mp->mnt_flag &= ~MNT_RDONLY; 550191783Srmacklem MNT_IUNLOCK(mp); 551191783Srmacklem } 552191783Srmacklem 553191783Srmacklem /* 554191783Srmacklem * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 555191783Srmacklem * no sense in that context. Also, set up appropriate retransmit 556191783Srmacklem * and soft timeout behavior. 557191783Srmacklem */ 558191783Srmacklem if (argp->sotype == SOCK_STREAM) { 559191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOCONN; 560191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 561191783Srmacklem } 562191783Srmacklem 563191783Srmacklem /* Also clear RDIRPLUS if not NFSv3, it crashes some servers */ 564191783Srmacklem if ((argp->flags & NFSMNT_NFSV3) == 0) 565191783Srmacklem nmp->nm_flag &= ~NFSMNT_RDIRPLUS; 566191783Srmacklem 567191783Srmacklem /* Also re-bind if we're switching to/from a connected UDP socket */ 568191783Srmacklem adjsock = ((nmp->nm_flag & NFSMNT_NOCONN) != 569191783Srmacklem (argp->flags & NFSMNT_NOCONN)); 570191783Srmacklem 571191783Srmacklem /* Update flags atomically. Don't change the lock bits. */ 572191783Srmacklem nmp->nm_flag = argp->flags | nmp->nm_flag; 573191783Srmacklem splx(s); 574191783Srmacklem 575191783Srmacklem if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 576191783Srmacklem nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 577191783Srmacklem if (nmp->nm_timeo < NFS_MINTIMEO) 578191783Srmacklem nmp->nm_timeo = NFS_MINTIMEO; 579191783Srmacklem else if (nmp->nm_timeo > NFS_MAXTIMEO) 580191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 581191783Srmacklem } 582191783Srmacklem 583191783Srmacklem if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 584191783Srmacklem nmp->nm_retry = argp->retrans; 585191783Srmacklem if (nmp->nm_retry > NFS_MAXREXMIT) 586191783Srmacklem nmp->nm_retry = NFS_MAXREXMIT; 587191783Srmacklem } 588191783Srmacklem 589191783Srmacklem if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 590191783Srmacklem nmp->nm_wsize = argp->wsize; 591191783Srmacklem /* Round down to multiple of blocksize */ 592191783Srmacklem nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); 593191783Srmacklem if (nmp->nm_wsize <= 0) 594191783Srmacklem nmp->nm_wsize = NFS_FABLKSIZE; 595191783Srmacklem } 596191783Srmacklem 597191783Srmacklem if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 598191783Srmacklem nmp->nm_rsize = argp->rsize; 599191783Srmacklem /* Round down to multiple of blocksize */ 600191783Srmacklem nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); 601191783Srmacklem if (nmp->nm_rsize <= 0) 602191783Srmacklem nmp->nm_rsize = NFS_FABLKSIZE; 603191783Srmacklem } 604191783Srmacklem 605191783Srmacklem if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 606191783Srmacklem nmp->nm_readdirsize = argp->readdirsize; 607191783Srmacklem } 608191783Srmacklem 609191783Srmacklem if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) 610191783Srmacklem nmp->nm_acregmin = argp->acregmin; 611191783Srmacklem else 612191783Srmacklem nmp->nm_acregmin = NFS_MINATTRTIMO; 613191783Srmacklem if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) 614191783Srmacklem nmp->nm_acregmax = argp->acregmax; 615191783Srmacklem else 616191783Srmacklem nmp->nm_acregmax = NFS_MAXATTRTIMO; 617191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) 618191783Srmacklem nmp->nm_acdirmin = argp->acdirmin; 619191783Srmacklem else 620191783Srmacklem nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; 621191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) 622191783Srmacklem nmp->nm_acdirmax = argp->acdirmax; 623191783Srmacklem else 624191783Srmacklem nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; 625191783Srmacklem if (nmp->nm_acdirmin > nmp->nm_acdirmax) 626191783Srmacklem nmp->nm_acdirmin = nmp->nm_acdirmax; 627191783Srmacklem if (nmp->nm_acregmin > nmp->nm_acregmax) 628191783Srmacklem nmp->nm_acregmin = nmp->nm_acregmax; 629191783Srmacklem 630191783Srmacklem if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { 631191783Srmacklem if (argp->readahead <= NFS_MAXRAHEAD) 632191783Srmacklem nmp->nm_readahead = argp->readahead; 633191783Srmacklem else 634191783Srmacklem nmp->nm_readahead = NFS_MAXRAHEAD; 635191783Srmacklem } 636191783Srmacklem if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) { 637191783Srmacklem if (argp->wcommitsize < nmp->nm_wsize) 638191783Srmacklem nmp->nm_wcommitsize = nmp->nm_wsize; 639191783Srmacklem else 640191783Srmacklem nmp->nm_wcommitsize = argp->wcommitsize; 641191783Srmacklem } 642191783Srmacklem 643191783Srmacklem adjsock |= ((nmp->nm_sotype != argp->sotype) || 644191783Srmacklem (nmp->nm_soproto != argp->proto)); 645191783Srmacklem 646191783Srmacklem if (nmp->nm_client != NULL && adjsock) { 647191783Srmacklem int haslock = 0, error = 0; 648191783Srmacklem 649191783Srmacklem if (nmp->nm_sotype == SOCK_STREAM) { 650191783Srmacklem error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock); 651191783Srmacklem if (!error) 652191783Srmacklem haslock = 1; 653191783Srmacklem } 654191783Srmacklem if (!error) { 655191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 656191783Srmacklem if (haslock) 657191783Srmacklem newnfs_sndunlock(&nmp->nm_sockreq.nr_lock); 658191783Srmacklem nmp->nm_sotype = argp->sotype; 659191783Srmacklem nmp->nm_soproto = argp->proto; 660191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 661191783Srmacklem while (newnfs_connect(nmp, &nmp->nm_sockreq, 662191783Srmacklem cred, td, 0)) { 663191783Srmacklem printf("newnfs_args: retrying connect\n"); 664207170Srmacklem (void) nfs_catnap(PSOCK, 0, "newnfscon"); 665191783Srmacklem } 666191783Srmacklem } 667191783Srmacklem } else { 668191783Srmacklem nmp->nm_sotype = argp->sotype; 669191783Srmacklem nmp->nm_soproto = argp->proto; 670191783Srmacklem } 671214048Srmacklem 672214048Srmacklem if (hostname != NULL) { 673214048Srmacklem strlcpy(nmp->nm_hostname, hostname, 674214048Srmacklem sizeof(nmp->nm_hostname)); 675214048Srmacklem p = strchr(nmp->nm_hostname, ':'); 676214048Srmacklem if (p != NULL) 677214048Srmacklem *p = '\0'; 678214048Srmacklem } 679191783Srmacklem} 680191783Srmacklem 681192585Srmacklemstatic const char *nfs_opts[] = { "from", 682191783Srmacklem "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union", 683191783Srmacklem "noclusterr", "noclusterw", "multilabel", "acls", "force", "update", 684192585Srmacklem "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus", 685192585Srmacklem "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize", 686192585Srmacklem "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport", 687192585Srmacklem "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec", 688192585Srmacklem "principal", "nfsv4", "gssname", "allgssname", "dirpath", 689203303Srmacklem "negnametimeo", 690191783Srmacklem NULL }; 691191783Srmacklem 692191783Srmacklem/* 693191783Srmacklem * VFS Operations. 694191783Srmacklem * 695191783Srmacklem * mount system call 696191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 697191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 698191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 699191783Srmacklem * an error after that means that I have to release the mbuf. 700191783Srmacklem */ 701191783Srmacklem/* ARGSUSED */ 702191783Srmacklemstatic int 703191990Sattilionfs_mount(struct mount *mp) 704191783Srmacklem{ 705191783Srmacklem struct nfs_args args = { 706191783Srmacklem .version = NFS_ARGSVERSION, 707191783Srmacklem .addr = NULL, 708191783Srmacklem .addrlen = sizeof (struct sockaddr_in), 709191783Srmacklem .sotype = SOCK_STREAM, 710191783Srmacklem .proto = 0, 711191783Srmacklem .fh = NULL, 712191783Srmacklem .fhsize = 0, 713191783Srmacklem .flags = 0, 714191783Srmacklem .wsize = NFS_WSIZE, 715191783Srmacklem .rsize = NFS_RSIZE, 716191783Srmacklem .readdirsize = NFS_READDIRSIZE, 717191783Srmacklem .timeo = 10, 718191783Srmacklem .retrans = NFS_RETRANS, 719191783Srmacklem .readahead = NFS_DEFRAHEAD, 720191783Srmacklem .wcommitsize = 0, /* was: NQ_DEFLEASE */ 721191783Srmacklem .hostname = NULL, 722191783Srmacklem /* args version 4 */ 723191783Srmacklem .acregmin = NFS_MINATTRTIMO, 724191783Srmacklem .acregmax = NFS_MAXATTRTIMO, 725191783Srmacklem .acdirmin = NFS_MINDIRATTRTIMO, 726191783Srmacklem .acdirmax = NFS_MAXDIRATTRTIMO, 727191783Srmacklem .dirlen = 0, 728191783Srmacklem .krbnamelen = 0, 729192585Srmacklem .srvkrbnamelen = 0, 730191783Srmacklem }; 731192585Srmacklem int error = 0, ret, len; 732192585Srmacklem struct sockaddr *nam = NULL; 733191783Srmacklem struct vnode *vp; 734191990Sattilio struct thread *td; 735191783Srmacklem char hst[MNAMELEN]; 736191783Srmacklem u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100]; 737192585Srmacklem char *opt, *name, *secname; 738203303Srmacklem int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO; 739191783Srmacklem 740191783Srmacklem if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) { 741191783Srmacklem error = EINVAL; 742191783Srmacklem goto out; 743191783Srmacklem } 744191783Srmacklem 745191990Sattilio td = curthread; 746191783Srmacklem if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) { 747192145Srmacklem error = ncl_mountroot(mp); 748191783Srmacklem goto out; 749191783Srmacklem } 750191783Srmacklem 751192585Srmacklem nfscl_init(); 752191783Srmacklem 753192585Srmacklem /* Handle the new style options. */ 754192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0) 755192585Srmacklem args.flags |= NFSMNT_NOCONN; 756192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0) 757192585Srmacklem args.flags |= NFSMNT_NOCONN; 758192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0) 759192585Srmacklem args.flags |= NFSMNT_NOLOCKD; 760192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0) 761192585Srmacklem args.flags &= ~NFSMNT_NOLOCKD; 762192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0) 763192585Srmacklem args.flags |= NFSMNT_INT; 764192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0) 765192585Srmacklem args.flags |= NFSMNT_RDIRPLUS; 766192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0) 767192585Srmacklem args.flags |= NFSMNT_RESVPORT; 768192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0) 769192585Srmacklem args.flags &= ~NFSMNT_RESVPORT; 770192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0) 771192585Srmacklem args.flags |= NFSMNT_SOFT; 772192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0) 773192585Srmacklem args.flags &= ~NFSMNT_SOFT; 774192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0) 775192585Srmacklem args.sotype = SOCK_DGRAM; 776192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0) 777192585Srmacklem args.sotype = SOCK_DGRAM; 778192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0) 779192585Srmacklem args.sotype = SOCK_STREAM; 780192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0) 781192585Srmacklem args.flags |= NFSMNT_NFSV3; 782192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) { 783192585Srmacklem args.flags |= NFSMNT_NFSV4; 784192585Srmacklem args.sotype = SOCK_STREAM; 785191783Srmacklem } 786192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0) 787192585Srmacklem args.flags |= NFSMNT_ALLGSSNAME; 788192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) { 789192585Srmacklem if (opt == NULL) { 790192585Srmacklem vfs_mount_error(mp, "illegal readdirsize"); 791192585Srmacklem error = EINVAL; 792192585Srmacklem goto out; 793192585Srmacklem } 794192585Srmacklem ret = sscanf(opt, "%d", &args.readdirsize); 795192585Srmacklem if (ret != 1 || args.readdirsize <= 0) { 796192585Srmacklem vfs_mount_error(mp, "illegal readdirsize: %s", 797192585Srmacklem opt); 798192585Srmacklem error = EINVAL; 799192585Srmacklem goto out; 800192585Srmacklem } 801192585Srmacklem args.flags |= NFSMNT_READDIRSIZE; 802192585Srmacklem } 803192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) { 804192585Srmacklem if (opt == NULL) { 805192585Srmacklem vfs_mount_error(mp, "illegal readahead"); 806192585Srmacklem error = EINVAL; 807192585Srmacklem goto out; 808192585Srmacklem } 809192585Srmacklem ret = sscanf(opt, "%d", &args.readahead); 810192585Srmacklem if (ret != 1 || args.readahead <= 0) { 811192585Srmacklem vfs_mount_error(mp, "illegal readahead: %s", 812192585Srmacklem opt); 813192585Srmacklem error = EINVAL; 814192585Srmacklem goto out; 815192585Srmacklem } 816192585Srmacklem args.flags |= NFSMNT_READAHEAD; 817192585Srmacklem } 818192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) { 819192585Srmacklem if (opt == NULL) { 820192585Srmacklem vfs_mount_error(mp, "illegal wsize"); 821192585Srmacklem error = EINVAL; 822192585Srmacklem goto out; 823192585Srmacklem } 824192585Srmacklem ret = sscanf(opt, "%d", &args.wsize); 825192585Srmacklem if (ret != 1 || args.wsize <= 0) { 826192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 827192585Srmacklem opt); 828192585Srmacklem error = EINVAL; 829192585Srmacklem goto out; 830192585Srmacklem } 831192585Srmacklem args.flags |= NFSMNT_WSIZE; 832192585Srmacklem } 833192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) { 834192585Srmacklem if (opt == NULL) { 835192585Srmacklem vfs_mount_error(mp, "illegal rsize"); 836192585Srmacklem error = EINVAL; 837192585Srmacklem goto out; 838192585Srmacklem } 839192585Srmacklem ret = sscanf(opt, "%d", &args.rsize); 840192585Srmacklem if (ret != 1 || args.rsize <= 0) { 841192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 842192585Srmacklem opt); 843192585Srmacklem error = EINVAL; 844192585Srmacklem goto out; 845192585Srmacklem } 846192585Srmacklem args.flags |= NFSMNT_RSIZE; 847192585Srmacklem } 848192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) { 849192585Srmacklem if (opt == NULL) { 850192585Srmacklem vfs_mount_error(mp, "illegal retrans"); 851192585Srmacklem error = EINVAL; 852192585Srmacklem goto out; 853192585Srmacklem } 854192585Srmacklem ret = sscanf(opt, "%d", &args.retrans); 855192585Srmacklem if (ret != 1 || args.retrans <= 0) { 856192585Srmacklem vfs_mount_error(mp, "illegal retrans: %s", 857192585Srmacklem opt); 858192585Srmacklem error = EINVAL; 859192585Srmacklem goto out; 860192585Srmacklem } 861192585Srmacklem args.flags |= NFSMNT_RETRANS; 862192585Srmacklem } 863192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) { 864192585Srmacklem ret = sscanf(opt, "%d", &args.acregmin); 865192585Srmacklem if (ret != 1 || args.acregmin < 0) { 866192585Srmacklem vfs_mount_error(mp, "illegal acregmin: %s", 867192585Srmacklem opt); 868192585Srmacklem error = EINVAL; 869192585Srmacklem goto out; 870192585Srmacklem } 871192585Srmacklem args.flags |= NFSMNT_ACREGMIN; 872192585Srmacklem } 873192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) { 874192585Srmacklem ret = sscanf(opt, "%d", &args.acregmax); 875192585Srmacklem if (ret != 1 || args.acregmax < 0) { 876192585Srmacklem vfs_mount_error(mp, "illegal acregmax: %s", 877192585Srmacklem opt); 878192585Srmacklem error = EINVAL; 879192585Srmacklem goto out; 880192585Srmacklem } 881192585Srmacklem args.flags |= NFSMNT_ACREGMAX; 882192585Srmacklem } 883192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) { 884192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmin); 885192585Srmacklem if (ret != 1 || args.acdirmin < 0) { 886192585Srmacklem vfs_mount_error(mp, "illegal acdirmin: %s", 887192585Srmacklem opt); 888192585Srmacklem error = EINVAL; 889192585Srmacklem goto out; 890192585Srmacklem } 891192585Srmacklem args.flags |= NFSMNT_ACDIRMIN; 892192585Srmacklem } 893192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) { 894192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmax); 895192585Srmacklem if (ret != 1 || args.acdirmax < 0) { 896192585Srmacklem vfs_mount_error(mp, "illegal acdirmax: %s", 897192585Srmacklem opt); 898192585Srmacklem error = EINVAL; 899192585Srmacklem goto out; 900192585Srmacklem } 901192585Srmacklem args.flags |= NFSMNT_ACDIRMAX; 902192585Srmacklem } 903192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) { 904192585Srmacklem ret = sscanf(opt, "%d", &args.timeo); 905192585Srmacklem if (ret != 1 || args.timeo <= 0) { 906192585Srmacklem vfs_mount_error(mp, "illegal timeout: %s", 907192585Srmacklem opt); 908192585Srmacklem error = EINVAL; 909192585Srmacklem goto out; 910192585Srmacklem } 911192585Srmacklem args.flags |= NFSMNT_TIMEO; 912192585Srmacklem } 913203303Srmacklem if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL) 914203303Srmacklem == 0) { 915203303Srmacklem ret = sscanf(opt, "%d", &negnametimeo); 916203303Srmacklem if (ret != 1 || negnametimeo < 0) { 917203303Srmacklem vfs_mount_error(mp, "illegal negnametimeo: %s", 918203303Srmacklem opt); 919203303Srmacklem error = EINVAL; 920203303Srmacklem goto out; 921203303Srmacklem } 922203303Srmacklem } 923192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "sec", 924192585Srmacklem (void **) &secname, NULL) == 0) 925192585Srmacklem nfs_sec_name(secname, &args.flags); 926191783Srmacklem 927191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 928191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 929191783Srmacklem 930191783Srmacklem if (nmp == NULL) { 931191783Srmacklem error = EIO; 932191783Srmacklem goto out; 933191783Srmacklem } 934191783Srmacklem /* 935191783Srmacklem * When doing an update, we can't change version, 936191783Srmacklem * security, switch lockd strategies or change cookie 937191783Srmacklem * translation 938191783Srmacklem */ 939191783Srmacklem args.flags = (args.flags & 940191783Srmacklem ~(NFSMNT_NFSV3 | 941191783Srmacklem NFSMNT_NFSV4 | 942191783Srmacklem NFSMNT_KERB | 943191783Srmacklem NFSMNT_INTEGRITY | 944191783Srmacklem NFSMNT_PRIVACY | 945191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) | 946191783Srmacklem (nmp->nm_flag & 947191783Srmacklem (NFSMNT_NFSV3 | 948191783Srmacklem NFSMNT_NFSV4 | 949191783Srmacklem NFSMNT_KERB | 950191783Srmacklem NFSMNT_INTEGRITY | 951191783Srmacklem NFSMNT_PRIVACY | 952191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); 953214048Srmacklem nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td); 954191783Srmacklem goto out; 955191783Srmacklem } 956191783Srmacklem 957191783Srmacklem /* 958191783Srmacklem * Make the nfs_ip_paranoia sysctl serve as the default connection 959191783Srmacklem * or no-connection mode for those protocols that support 960191783Srmacklem * no-connection mode (the flag will be cleared later for protocols 961191783Srmacklem * that do not support no-connection mode). This will allow a client 962191783Srmacklem * to receive replies from a different IP then the request was 963191783Srmacklem * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid), 964191783Srmacklem * not 0. 965191783Srmacklem */ 966191783Srmacklem if (nfs_ip_paranoia == 0) 967191783Srmacklem args.flags |= NFSMNT_NOCONN; 968192585Srmacklem 969192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh, 970192585Srmacklem &args.fhsize) == 0) { 971208234Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) { 972192585Srmacklem vfs_mount_error(mp, "Bad file handle"); 973191783Srmacklem error = EINVAL; 974191783Srmacklem goto out; 975191783Srmacklem } 976192585Srmacklem bcopy(args.fh, nfh, args.fhsize); 977191783Srmacklem } else { 978192585Srmacklem args.fhsize = 0; 979192585Srmacklem } 980192585Srmacklem 981192585Srmacklem (void) vfs_getopt(mp->mnt_optnew, "hostname", (void **)&args.hostname, 982192585Srmacklem &len); 983192585Srmacklem if (args.hostname == NULL) { 984192585Srmacklem vfs_mount_error(mp, "Invalid hostname"); 985192585Srmacklem error = EINVAL; 986192585Srmacklem goto out; 987192585Srmacklem } 988192585Srmacklem bcopy(args.hostname, hst, MNAMELEN); 989192585Srmacklem hst[MNAMELEN - 1] = '\0'; 990192585Srmacklem 991192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0) 992192585Srmacklem strlcpy(srvkrbname, name, sizeof (srvkrbname)); 993192585Srmacklem else 994192585Srmacklem snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst); 995192585Srmacklem args.srvkrbnamelen = strlen(srvkrbname); 996192585Srmacklem 997192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0) 998192585Srmacklem strlcpy(krbname, name, sizeof (krbname)); 999192585Srmacklem else 1000191783Srmacklem krbname[0] = '\0'; 1001192585Srmacklem args.krbnamelen = strlen(krbname); 1002192585Srmacklem 1003192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0) 1004192585Srmacklem strlcpy(dirpath, name, sizeof (dirpath)); 1005192585Srmacklem else 1006191783Srmacklem dirpath[0] = '\0'; 1007192585Srmacklem args.dirlen = strlen(dirpath); 1008192585Srmacklem 1009192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "addr", (void **)&args.addr, 1010192585Srmacklem &args.addrlen) == 0) { 1011192585Srmacklem if (args.addrlen > SOCK_MAXADDRLEN) { 1012192585Srmacklem error = ENAMETOOLONG; 1013191783Srmacklem goto out; 1014191783Srmacklem } 1015192585Srmacklem nam = malloc(args.addrlen, M_SONAME, M_WAITOK); 1016192585Srmacklem bcopy(args.addr, nam, args.addrlen); 1017192585Srmacklem nam->sa_len = args.addrlen; 1018191783Srmacklem } 1019192585Srmacklem 1020191783Srmacklem args.fh = nfh; 1021191783Srmacklem error = mountnfs(&args, mp, nam, hst, krbname, dirpath, srvkrbname, 1022203303Srmacklem &vp, td->td_ucred, td, negnametimeo); 1023191783Srmacklemout: 1024191783Srmacklem if (!error) { 1025191783Srmacklem MNT_ILOCK(mp); 1026191783Srmacklem mp->mnt_kern_flag |= (MNTK_MPSAFE|MNTK_LOOKUP_SHARED); 1027191783Srmacklem MNT_IUNLOCK(mp); 1028191783Srmacklem } 1029191783Srmacklem return (error); 1030191783Srmacklem} 1031191783Srmacklem 1032191783Srmacklem 1033191783Srmacklem/* 1034191783Srmacklem * VFS Operations. 1035191783Srmacklem * 1036191783Srmacklem * mount system call 1037191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 1038191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 1039191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 1040191783Srmacklem * an error after that means that I have to release the mbuf. 1041191783Srmacklem */ 1042191783Srmacklem/* ARGSUSED */ 1043191783Srmacklemstatic int 1044191990Sattilionfs_cmount(struct mntarg *ma, void *data, int flags) 1045191783Srmacklem{ 1046191783Srmacklem int error; 1047191783Srmacklem struct nfs_args args; 1048191783Srmacklem 1049191783Srmacklem error = copyin(data, &args, sizeof (struct nfs_args)); 1050191783Srmacklem if (error) 1051191783Srmacklem return error; 1052191783Srmacklem 1053191783Srmacklem ma = mount_arg(ma, "nfs_args", &args, sizeof args); 1054191783Srmacklem 1055191783Srmacklem error = kernel_mount(ma, flags); 1056191783Srmacklem return (error); 1057191783Srmacklem} 1058191783Srmacklem 1059191783Srmacklem/* 1060191783Srmacklem * Common code for mount and mountroot 1061191783Srmacklem */ 1062191783Srmacklemstatic int 1063191783Srmacklemmountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, 1064191783Srmacklem char *hst, u_char *krbname, u_char *dirpath, u_char *srvkrbname, 1065203303Srmacklem struct vnode **vpp, struct ucred *cred, struct thread *td, 1066203303Srmacklem int negnametimeo) 1067191783Srmacklem{ 1068191783Srmacklem struct nfsmount *nmp; 1069191783Srmacklem struct nfsnode *np; 1070195762Srmacklem int error, trycnt, ret; 1071191783Srmacklem struct nfsvattr nfsva; 1072191783Srmacklem static u_int64_t clval = 0; 1073191783Srmacklem 1074191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 1075191783Srmacklem nmp = VFSTONFS(mp); 1076191783Srmacklem printf("%s: MNT_UPDATE is no longer handled here\n", __func__); 1077191783Srmacklem FREE(nam, M_SONAME); 1078191783Srmacklem return (0); 1079191783Srmacklem } else { 1080191783Srmacklem MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) + 1081191783Srmacklem argp->krbnamelen + argp->dirlen + argp->srvkrbnamelen + 2, 1082191783Srmacklem M_NEWNFSMNT, M_WAITOK); 1083191783Srmacklem bzero((caddr_t)nmp, sizeof (struct nfsmount) + 1084191783Srmacklem argp->krbnamelen + argp->dirlen + argp->srvkrbnamelen + 2); 1085191783Srmacklem TAILQ_INIT(&nmp->nm_bufq); 1086191783Srmacklem if (clval == 0) 1087191783Srmacklem clval = (u_int64_t)nfsboottime.tv_sec; 1088191783Srmacklem nmp->nm_clval = clval++; 1089191783Srmacklem nmp->nm_krbnamelen = argp->krbnamelen; 1090191783Srmacklem nmp->nm_dirpathlen = argp->dirlen; 1091191783Srmacklem nmp->nm_srvkrbnamelen = argp->srvkrbnamelen; 1092192675Srmacklem if (td->td_ucred->cr_uid != (uid_t)0) { 1093191783Srmacklem /* 1094192675Srmacklem * nm_uid is used to get KerberosV credentials for 1095192675Srmacklem * the nfsv4 state handling operations if there is 1096192675Srmacklem * no host based principal set. Use the uid of 1097192675Srmacklem * this user if not root, since they are doing the 1098192675Srmacklem * mount. I don't think setting this for root will 1099192675Srmacklem * work, since root normally does not have user 1100192675Srmacklem * credentials in a credentials cache. 1101191783Srmacklem */ 1102192675Srmacklem nmp->nm_uid = td->td_ucred->cr_uid; 1103191783Srmacklem } else { 1104191783Srmacklem /* 1105192675Srmacklem * Just set to -1, so it won't be used. 1106191783Srmacklem */ 1107191783Srmacklem nmp->nm_uid = (uid_t)-1; 1108191783Srmacklem } 1109191783Srmacklem 1110191783Srmacklem /* Copy and null terminate all the names */ 1111191783Srmacklem if (nmp->nm_krbnamelen > 0) { 1112191783Srmacklem bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen); 1113191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen] = '\0'; 1114191783Srmacklem } 1115191783Srmacklem if (nmp->nm_dirpathlen > 0) { 1116191783Srmacklem bcopy(dirpath, NFSMNT_DIRPATH(nmp), 1117191783Srmacklem nmp->nm_dirpathlen); 1118191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1119191783Srmacklem + 1] = '\0'; 1120191783Srmacklem } 1121191783Srmacklem if (nmp->nm_srvkrbnamelen > 0) { 1122191783Srmacklem bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp), 1123191783Srmacklem nmp->nm_srvkrbnamelen); 1124191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1125191783Srmacklem + nmp->nm_srvkrbnamelen + 2] = '\0'; 1126191783Srmacklem } 1127191783Srmacklem nmp->nm_sockreq.nr_cred = crhold(cred); 1128191783Srmacklem mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF); 1129191783Srmacklem mp->mnt_data = nmp; 1130214048Srmacklem nmp->nm_getinfo = nfs_getnlminfo; 1131216931Srmacklem nmp->nm_vinvalbuf = ncl_vinvalbuf; 1132191783Srmacklem } 1133191783Srmacklem vfs_getnewfsid(mp); 1134191783Srmacklem nmp->nm_mountp = mp; 1135191783Srmacklem mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK); 1136203303Srmacklem nmp->nm_negnametimeo = negnametimeo; 1137191783Srmacklem 1138214048Srmacklem nfs_decode_args(mp, nmp, argp, hst, cred, td); 1139192585Srmacklem 1140191783Srmacklem /* 1141191783Srmacklem * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too 1142191783Srmacklem * high, depending on whether we end up with negative offsets in 1143191783Srmacklem * the client or server somewhere. 2GB-1 may be safer. 1144191783Srmacklem * 1145191783Srmacklem * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum 1146191783Srmacklem * that we can handle until we find out otherwise. 1147191783Srmacklem * XXX Our "safe" limit on the client is what we can store in our 1148191783Srmacklem * buffer cache using signed(!) block numbers. 1149191783Srmacklem */ 1150191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) 1151191783Srmacklem nmp->nm_maxfilesize = 0xffffffffLL; 1152191783Srmacklem else 1153191783Srmacklem nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1; 1154191783Srmacklem 1155191783Srmacklem nmp->nm_timeo = NFS_TIMEO; 1156191783Srmacklem nmp->nm_retry = NFS_RETRANS; 1157191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 1158191783Srmacklem nmp->nm_wsize = NFS_WSIZE; 1159191783Srmacklem nmp->nm_rsize = NFS_RSIZE; 1160191783Srmacklem nmp->nm_readdirsize = NFS_READDIRSIZE; 1161191783Srmacklem } 1162191783Srmacklem nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000); 1163191783Srmacklem nmp->nm_numgrps = NFS_MAXGRPS; 1164191783Srmacklem nmp->nm_readahead = NFS_DEFRAHEAD; 1165191783Srmacklem nmp->nm_tprintf_delay = nfs_tprintf_delay; 1166191783Srmacklem if (nmp->nm_tprintf_delay < 0) 1167191783Srmacklem nmp->nm_tprintf_delay = 0; 1168191783Srmacklem nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay; 1169191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1170191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1171191783Srmacklem nmp->nm_fhsize = argp->fhsize; 1172191783Srmacklem if (nmp->nm_fhsize > 0) 1173191783Srmacklem bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 1174191783Srmacklem bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 1175191783Srmacklem nmp->nm_nam = nam; 1176191783Srmacklem /* Set up the sockets and per-host congestion */ 1177191783Srmacklem nmp->nm_sotype = argp->sotype; 1178191783Srmacklem nmp->nm_soproto = argp->proto; 1179191783Srmacklem nmp->nm_sockreq.nr_prog = NFS_PROG; 1180191783Srmacklem if ((argp->flags & NFSMNT_NFSV4)) 1181191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER4; 1182191783Srmacklem else if ((argp->flags & NFSMNT_NFSV3)) 1183191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER3; 1184191783Srmacklem else 1185191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER2; 1186191783Srmacklem 1187191783Srmacklem 1188191783Srmacklem if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0))) 1189191783Srmacklem goto bad; 1190191783Srmacklem 1191191783Srmacklem /* 1192191783Srmacklem * A reference count is needed on the nfsnode representing the 1193191783Srmacklem * remote root. If this object is not persistent, then backward 1194191783Srmacklem * traversals of the mount point (i.e. "..") will not work if 1195191783Srmacklem * the nfsnode gets flushed out of the cache. Ufs does not have 1196191783Srmacklem * this problem, because one can identify root inodes by their 1197191783Srmacklem * number == ROOTINO (2). 1198191783Srmacklem */ 1199191783Srmacklem if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) && 1200191783Srmacklem nmp->nm_dirpathlen > 0) { 1201191783Srmacklem /* 1202191783Srmacklem * If the fhsize on the mount point == 0 for V4, the mount 1203191783Srmacklem * path needs to be looked up. 1204191783Srmacklem */ 1205191783Srmacklem trycnt = 3; 1206191783Srmacklem do { 1207191783Srmacklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 1208191783Srmacklem cred, td); 1209191783Srmacklem if (error) 1210207170Srmacklem (void) nfs_catnap(PZERO, error, "nfsgetdirp"); 1211191783Srmacklem } while (error && --trycnt > 0); 1212191783Srmacklem if (error) { 1213191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1214191783Srmacklem goto bad; 1215191783Srmacklem } 1216191783Srmacklem } 1217191783Srmacklem if (nmp->nm_fhsize > 0) { 1218195762Srmacklem /* 1219195762Srmacklem * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set 1220195762Srmacklem * non-zero for the root vnode. f_iosize will be set correctly 1221195762Srmacklem * by nfs_statfs() before any I/O occurs. 1222195762Srmacklem */ 1223195762Srmacklem mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ; 1224220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, 1225220732Srmacklem LK_EXCLUSIVE); 1226191783Srmacklem if (error) 1227191783Srmacklem goto bad; 1228191783Srmacklem *vpp = NFSTOV(np); 1229191783Srmacklem 1230191783Srmacklem /* 1231191783Srmacklem * Get file attributes and transfer parameters for the 1232191783Srmacklem * mountpoint. This has the side effect of filling in 1233191783Srmacklem * (*vpp)->v_type with the correct value. 1234191783Srmacklem */ 1235191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 1236191783Srmacklem cred, td, &nfsva, NULL); 1237191783Srmacklem if (ret) { 1238191783Srmacklem /* 1239191783Srmacklem * Just set default values to get things going. 1240191783Srmacklem */ 1241191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 1242191783Srmacklem nfsva.na_vattr.va_type = VDIR; 1243191783Srmacklem nfsva.na_vattr.va_mode = 0777; 1244191783Srmacklem nfsva.na_vattr.va_nlink = 100; 1245191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 1246191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 1247191783Srmacklem nfsva.na_vattr.va_fileid = 2; 1248191783Srmacklem nfsva.na_vattr.va_gen = 1; 1249191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 1250191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 1251191783Srmacklem } 1252191783Srmacklem (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1); 1253191783Srmacklem if (argp->flags & NFSMNT_NFSV3) 1254191783Srmacklem ncl_fsinfo(nmp, *vpp, cred, td); 1255191783Srmacklem 1256191783Srmacklem /* 1257191783Srmacklem * Lose the lock but keep the ref. 1258191783Srmacklem */ 1259191783Srmacklem VOP_UNLOCK(*vpp, 0); 1260191783Srmacklem return (0); 1261191783Srmacklem } 1262191783Srmacklem error = EIO; 1263191783Srmacklem 1264191783Srmacklembad: 1265191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1266191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1267191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1268191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1269191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1270191783Srmacklem FREE(nam, M_SONAME); 1271191783Srmacklem return (error); 1272191783Srmacklem} 1273191783Srmacklem 1274191783Srmacklem/* 1275191783Srmacklem * unmount system call 1276191783Srmacklem */ 1277191783Srmacklemstatic int 1278191990Sattilionfs_unmount(struct mount *mp, int mntflags) 1279191783Srmacklem{ 1280191990Sattilio struct thread *td; 1281191783Srmacklem struct nfsmount *nmp; 1282191783Srmacklem int error, flags = 0, trycnt = 0; 1283191783Srmacklem 1284191990Sattilio td = curthread; 1285191990Sattilio 1286191783Srmacklem if (mntflags & MNT_FORCE) 1287191783Srmacklem flags |= FORCECLOSE; 1288191783Srmacklem nmp = VFSTONFS(mp); 1289191783Srmacklem /* 1290191783Srmacklem * Goes something like this.. 1291191783Srmacklem * - Call vflush() to clear out vnodes for this filesystem 1292191783Srmacklem * - Close the socket 1293191783Srmacklem * - Free up the data structures 1294191783Srmacklem */ 1295191783Srmacklem /* In the forced case, cancel any outstanding requests. */ 1296191783Srmacklem if (mntflags & MNT_FORCE) { 1297191783Srmacklem error = newnfs_nmcancelreqs(nmp); 1298191783Srmacklem if (error) 1299191783Srmacklem goto out; 1300191783Srmacklem /* For a forced close, get rid of the renew thread now */ 1301191783Srmacklem nfscl_umount(nmp, td); 1302191783Srmacklem } 1303191783Srmacklem /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ 1304191783Srmacklem do { 1305191783Srmacklem error = vflush(mp, 1, flags, td); 1306191783Srmacklem if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30) 1307207170Srmacklem (void) nfs_catnap(PSOCK, error, "newndm"); 1308191783Srmacklem } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30); 1309191783Srmacklem if (error) 1310191783Srmacklem goto out; 1311191783Srmacklem 1312191783Srmacklem /* 1313191783Srmacklem * We are now committed to the unmount. 1314191783Srmacklem */ 1315191783Srmacklem if ((mntflags & MNT_FORCE) == 0) 1316191783Srmacklem nfscl_umount(nmp, td); 1317191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1318191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1319191783Srmacklem FREE(nmp->nm_nam, M_SONAME); 1320191783Srmacklem 1321191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1322191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1323191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1324191783Srmacklemout: 1325191783Srmacklem return (error); 1326191783Srmacklem} 1327191783Srmacklem 1328191783Srmacklem/* 1329191783Srmacklem * Return root of a filesystem 1330191783Srmacklem */ 1331191783Srmacklemstatic int 1332191990Sattilionfs_root(struct mount *mp, int flags, struct vnode **vpp) 1333191783Srmacklem{ 1334191783Srmacklem struct vnode *vp; 1335191783Srmacklem struct nfsmount *nmp; 1336191783Srmacklem struct nfsnode *np; 1337191783Srmacklem int error; 1338191783Srmacklem 1339191783Srmacklem nmp = VFSTONFS(mp); 1340220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags); 1341191783Srmacklem if (error) 1342191783Srmacklem return error; 1343191783Srmacklem vp = NFSTOV(np); 1344191783Srmacklem /* 1345191783Srmacklem * Get transfer parameters and attributes for root vnode once. 1346191783Srmacklem */ 1347191783Srmacklem mtx_lock(&nmp->nm_mtx); 1348191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 1349191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1350191783Srmacklem ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread); 1351191783Srmacklem } else 1352191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1353191783Srmacklem if (vp->v_type == VNON) 1354191783Srmacklem vp->v_type = VDIR; 1355191783Srmacklem vp->v_vflag |= VV_ROOT; 1356191783Srmacklem *vpp = vp; 1357191783Srmacklem return (0); 1358191783Srmacklem} 1359191783Srmacklem 1360191783Srmacklem/* 1361191783Srmacklem * Flush out the buffer cache 1362191783Srmacklem */ 1363191783Srmacklem/* ARGSUSED */ 1364191783Srmacklemstatic int 1365191990Sattilionfs_sync(struct mount *mp, int waitfor) 1366191783Srmacklem{ 1367191783Srmacklem struct vnode *vp, *mvp; 1368191990Sattilio struct thread *td; 1369191783Srmacklem int error, allerror = 0; 1370191783Srmacklem 1371191990Sattilio td = curthread; 1372191990Sattilio 1373191783Srmacklem /* 1374191783Srmacklem * Force stale buffer cache information to be flushed. 1375191783Srmacklem */ 1376191783Srmacklem MNT_ILOCK(mp); 1377191783Srmacklemloop: 1378191783Srmacklem MNT_VNODE_FOREACH(vp, mp, mvp) { 1379191783Srmacklem VI_LOCK(vp); 1380191783Srmacklem MNT_IUNLOCK(mp); 1381191783Srmacklem /* XXX Racy bv_cnt check. */ 1382191783Srmacklem if (VOP_ISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1383191783Srmacklem waitfor == MNT_LAZY) { 1384191783Srmacklem VI_UNLOCK(vp); 1385191783Srmacklem MNT_ILOCK(mp); 1386191783Srmacklem continue; 1387191783Srmacklem } 1388191783Srmacklem if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 1389191783Srmacklem MNT_ILOCK(mp); 1390191783Srmacklem MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); 1391191783Srmacklem goto loop; 1392191783Srmacklem } 1393191783Srmacklem error = VOP_FSYNC(vp, waitfor, td); 1394191783Srmacklem if (error) 1395191783Srmacklem allerror = error; 1396191783Srmacklem VOP_UNLOCK(vp, 0); 1397191783Srmacklem vrele(vp); 1398191783Srmacklem 1399191783Srmacklem MNT_ILOCK(mp); 1400191783Srmacklem } 1401191783Srmacklem MNT_IUNLOCK(mp); 1402191783Srmacklem return (allerror); 1403191783Srmacklem} 1404191783Srmacklem 1405191783Srmacklemstatic int 1406191783Srmacklemnfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 1407191783Srmacklem{ 1408191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1409191783Srmacklem struct vfsquery vq; 1410191783Srmacklem int error; 1411191783Srmacklem 1412191783Srmacklem bzero(&vq, sizeof(vq)); 1413191783Srmacklem switch (op) { 1414191783Srmacklem#if 0 1415191783Srmacklem case VFS_CTL_NOLOCKS: 1416191783Srmacklem val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; 1417191783Srmacklem if (req->oldptr != NULL) { 1418191783Srmacklem error = SYSCTL_OUT(req, &val, sizeof(val)); 1419191783Srmacklem if (error) 1420191783Srmacklem return (error); 1421191783Srmacklem } 1422191783Srmacklem if (req->newptr != NULL) { 1423191783Srmacklem error = SYSCTL_IN(req, &val, sizeof(val)); 1424191783Srmacklem if (error) 1425191783Srmacklem return (error); 1426191783Srmacklem if (val) 1427191783Srmacklem nmp->nm_flag |= NFSMNT_NOLOCKS; 1428191783Srmacklem else 1429191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOLOCKS; 1430191783Srmacklem } 1431191783Srmacklem break; 1432191783Srmacklem#endif 1433191783Srmacklem case VFS_CTL_QUERY: 1434191783Srmacklem mtx_lock(&nmp->nm_mtx); 1435191783Srmacklem if (nmp->nm_state & NFSSTA_TIMEO) 1436191783Srmacklem vq.vq_flags |= VQ_NOTRESP; 1437191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1438191783Srmacklem#if 0 1439191783Srmacklem if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && 1440191783Srmacklem (nmp->nm_state & NFSSTA_LOCKTIMEO)) 1441191783Srmacklem vq.vq_flags |= VQ_NOTRESPLOCK; 1442191783Srmacklem#endif 1443191783Srmacklem error = SYSCTL_OUT(req, &vq, sizeof(vq)); 1444191783Srmacklem break; 1445191783Srmacklem case VFS_CTL_TIMEO: 1446191783Srmacklem if (req->oldptr != NULL) { 1447191783Srmacklem error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, 1448191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1449191783Srmacklem if (error) 1450191783Srmacklem return (error); 1451191783Srmacklem } 1452191783Srmacklem if (req->newptr != NULL) { 1453191783Srmacklem error = vfs_suser(mp, req->td); 1454191783Srmacklem if (error) 1455191783Srmacklem return (error); 1456191783Srmacklem error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, 1457191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1458191783Srmacklem if (error) 1459191783Srmacklem return (error); 1460191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1461191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1462191783Srmacklem } 1463191783Srmacklem break; 1464191783Srmacklem default: 1465191783Srmacklem return (ENOTSUP); 1466191783Srmacklem } 1467191783Srmacklem return (0); 1468191783Srmacklem} 1469191783Srmacklem 1470214048Srmacklem/* 1471214048Srmacklem * Extract the information needed by the nlm from the nfs vnode. 1472214048Srmacklem */ 1473214048Srmacklemstatic void 1474214053Srmacklemnfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp, 1475216931Srmacklem struct sockaddr_storage *sp, int *is_v3p, off_t *sizep, 1476216931Srmacklem struct timeval *timeop) 1477214048Srmacklem{ 1478214048Srmacklem struct nfsmount *nmp; 1479214048Srmacklem struct nfsnode *np = VTONFS(vp); 1480214048Srmacklem 1481214048Srmacklem nmp = VFSTONFS(vp->v_mount); 1482214048Srmacklem if (fhlenp != NULL) 1483214053Srmacklem *fhlenp = (size_t)np->n_fhp->nfh_len; 1484214048Srmacklem if (fhp != NULL) 1485214048Srmacklem bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len); 1486214048Srmacklem if (sp != NULL) 1487214048Srmacklem bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp))); 1488214048Srmacklem if (is_v3p != NULL) 1489214048Srmacklem *is_v3p = NFS_ISV3(vp); 1490214048Srmacklem if (sizep != NULL) 1491214048Srmacklem *sizep = np->n_size; 1492216931Srmacklem if (timeop != NULL) { 1493216931Srmacklem timeop->tv_sec = nmp->nm_timeo / NFS_HZ; 1494216931Srmacklem timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ); 1495216931Srmacklem } 1496214048Srmacklem} 1497214048Srmacklem 1498