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: releng/10.2/sys/fs/nfsclient/nfs_clvfsops.c 282933 2015-05-14 22:50:07Z 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; 82222233Srmacklemextern int nfsrv_useacl; 83244042Srmacklemextern int nfscl_debuglevel; 84249630Srmacklemextern enum nfsiod_state ncl_iodwant[NFS_MAXASYNCDAEMON]; 85249630Srmacklemextern struct nfsmount *ncl_iodmount[NFS_MAXASYNCDAEMON]; 86249630Srmacklemextern struct mtx ncl_iod_mutex; 87244042SrmacklemNFSCLSTATEMUTEX; 88191783Srmacklem 89191783SrmacklemMALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header"); 90191783SrmacklemMALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct"); 91191783Srmacklem 92221973SrmacklemSYSCTL_DECL(_vfs_nfs); 93191783Srmacklemstatic int nfs_ip_paranoia = 1; 94221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW, 95191783Srmacklem &nfs_ip_paranoia, 0, ""); 96191783Srmacklemstatic int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY; 97221973SrmacklemSYSCTL_INT(_vfs_nfs, NFS_TPRINTF_INITIAL_DELAY, 98191783Srmacklem downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, ""); 99191783Srmacklem/* how long between console messages "nfs server foo not responding" */ 100191783Srmacklemstatic int nfs_tprintf_delay = NFS_TPRINTF_DELAY; 101221973SrmacklemSYSCTL_INT(_vfs_nfs, NFS_TPRINTF_DELAY, 102191783Srmacklem downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, ""); 103191783Srmacklem 104221040Srmacklemstatic int nfs_mountroot(struct mount *); 105192585Srmacklemstatic void nfs_sec_name(char *, int *); 106191783Srmacklemstatic void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, 107214048Srmacklem struct nfs_args *argp, const char *, struct ucred *, 108214048Srmacklem struct thread *); 109191783Srmacklemstatic int mountnfs(struct nfs_args *, struct mount *, 110221014Srmacklem struct sockaddr *, char *, u_char *, int, u_char *, int, 111221014Srmacklem u_char *, int, struct vnode **, struct ucred *, 112244042Srmacklem struct thread *, int, int, int); 113214053Srmacklemstatic void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *, 114216931Srmacklem struct sockaddr_storage *, int *, off_t *, 115216931Srmacklem struct timeval *); 116191783Srmacklemstatic vfs_mount_t nfs_mount; 117191783Srmacklemstatic vfs_cmount_t nfs_cmount; 118191783Srmacklemstatic vfs_unmount_t nfs_unmount; 119191783Srmacklemstatic vfs_root_t nfs_root; 120191783Srmacklemstatic vfs_statfs_t nfs_statfs; 121191783Srmacklemstatic vfs_sync_t nfs_sync; 122191783Srmacklemstatic vfs_sysctl_t nfs_sysctl; 123255136Srmacklemstatic vfs_purge_t nfs_purge; 124191783Srmacklem 125191783Srmacklem/* 126191783Srmacklem * nfs vfs operations. 127191783Srmacklem */ 128191783Srmacklemstatic struct vfsops nfs_vfsops = { 129191783Srmacklem .vfs_init = ncl_init, 130191783Srmacklem .vfs_mount = nfs_mount, 131191783Srmacklem .vfs_cmount = nfs_cmount, 132191783Srmacklem .vfs_root = nfs_root, 133191783Srmacklem .vfs_statfs = nfs_statfs, 134191783Srmacklem .vfs_sync = nfs_sync, 135191783Srmacklem .vfs_uninit = ncl_uninit, 136191783Srmacklem .vfs_unmount = nfs_unmount, 137191783Srmacklem .vfs_sysctl = nfs_sysctl, 138255136Srmacklem .vfs_purge = nfs_purge, 139191783Srmacklem}; 140247116SjhbVFS_SET(nfs_vfsops, nfs, VFCF_NETWORK | VFCF_SBDRY); 141191783Srmacklem 142191783Srmacklem/* So that loader and kldload(2) can find us, wherever we are.. */ 143221139SrmacklemMODULE_VERSION(nfs, 1); 144221139SrmacklemMODULE_DEPEND(nfs, nfscommon, 1, 1, 1); 145221139SrmacklemMODULE_DEPEND(nfs, krpc, 1, 1, 1); 146221139SrmacklemMODULE_DEPEND(nfs, nfssvc, 1, 1, 1); 147221139SrmacklemMODULE_DEPEND(nfs, nfslock, 1, 1, 1); 148191783Srmacklem 149191783Srmacklem/* 150221066Srmacklem * This structure is now defined in sys/nfs/nfs_diskless.c so that it 151221066Srmacklem * can be shared by both NFS clients. It is declared here so that it 152221066Srmacklem * will be defined for kernels built without NFS_ROOT, although it 153221066Srmacklem * isn't used in that case. 154191783Srmacklem */ 155221066Srmacklem#if !defined(NFS_ROOT) && !defined(NFSCLIENT) 156221066Srmacklemstruct nfs_diskless nfs_diskless = { { { 0 } } }; 157221066Srmacklemstruct nfsv3_diskless nfsv3_diskless = { { { 0 } } }; 158221066Srmacklemint nfs_diskless_valid = 0; 159221066Srmacklem#endif 160221066Srmacklem 161221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD, 162221040Srmacklem &nfs_diskless_valid, 0, 163192145Srmacklem "Has the diskless struct been filled correctly"); 164191783Srmacklem 165221973SrmacklemSYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD, 166221040Srmacklem nfsv3_diskless.root_hostnam, 0, "Path to nfs root"); 167191783Srmacklem 168221973SrmacklemSYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD, 169221040Srmacklem &nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr), 170192145Srmacklem "%Ssockaddr_in", "Diskless root nfs address"); 171191783Srmacklem 172191783Srmacklem 173191783Srmacklemvoid newnfsargs_ntoh(struct nfs_args *); 174191783Srmacklemstatic int nfs_mountdiskless(char *, 175191783Srmacklem struct sockaddr_in *, struct nfs_args *, 176191783Srmacklem struct thread *, struct vnode **, struct mount *); 177191783Srmacklemstatic void nfs_convert_diskless(void); 178191783Srmacklemstatic void nfs_convert_oargs(struct nfs_args *args, 179191783Srmacklem struct onfs_args *oargs); 180191783Srmacklem 181191783Srmacklemint 182191783Srmacklemnewnfs_iosize(struct nfsmount *nmp) 183191783Srmacklem{ 184191783Srmacklem int iosize, maxio; 185191783Srmacklem 186191783Srmacklem /* First, set the upper limit for iosize */ 187191783Srmacklem if (nmp->nm_flag & NFSMNT_NFSV4) { 188191783Srmacklem maxio = NFS_MAXBSIZE; 189191783Srmacklem } else if (nmp->nm_flag & NFSMNT_NFSV3) { 190191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 191191783Srmacklem maxio = NFS_MAXDGRAMDATA; 192191783Srmacklem else 193191783Srmacklem maxio = NFS_MAXBSIZE; 194191783Srmacklem } else { 195191783Srmacklem maxio = NFS_V2MAXDATA; 196191783Srmacklem } 197191783Srmacklem if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0) 198191783Srmacklem nmp->nm_rsize = maxio; 199282933Srmacklem if (nmp->nm_rsize > NFS_MAXBSIZE) 200282933Srmacklem nmp->nm_rsize = NFS_MAXBSIZE; 201191783Srmacklem if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0) 202191783Srmacklem nmp->nm_readdirsize = maxio; 203191783Srmacklem if (nmp->nm_readdirsize > nmp->nm_rsize) 204191783Srmacklem nmp->nm_readdirsize = nmp->nm_rsize; 205191783Srmacklem if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0) 206191783Srmacklem nmp->nm_wsize = maxio; 207282933Srmacklem if (nmp->nm_wsize > NFS_MAXBSIZE) 208282933Srmacklem nmp->nm_wsize = NFS_MAXBSIZE; 209191783Srmacklem 210191783Srmacklem /* 211191783Srmacklem * Calculate the size used for io buffers. Use the larger 212191783Srmacklem * of the two sizes to minimise nfs requests but make sure 213191783Srmacklem * that it is at least one VM page to avoid wasting buffer 214191783Srmacklem * space. 215191783Srmacklem */ 216191783Srmacklem iosize = imax(nmp->nm_rsize, nmp->nm_wsize); 217191783Srmacklem iosize = imax(iosize, PAGE_SIZE); 218191783Srmacklem nmp->nm_mountp->mnt_stat.f_iosize = iosize; 219191783Srmacklem return (iosize); 220191783Srmacklem} 221191783Srmacklem 222191783Srmacklemstatic void 223191783Srmacklemnfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs) 224191783Srmacklem{ 225191783Srmacklem 226191783Srmacklem args->version = NFS_ARGSVERSION; 227191783Srmacklem args->addr = oargs->addr; 228191783Srmacklem args->addrlen = oargs->addrlen; 229191783Srmacklem args->sotype = oargs->sotype; 230191783Srmacklem args->proto = oargs->proto; 231191783Srmacklem args->fh = oargs->fh; 232191783Srmacklem args->fhsize = oargs->fhsize; 233191783Srmacklem args->flags = oargs->flags; 234191783Srmacklem args->wsize = oargs->wsize; 235191783Srmacklem args->rsize = oargs->rsize; 236191783Srmacklem args->readdirsize = oargs->readdirsize; 237191783Srmacklem args->timeo = oargs->timeo; 238191783Srmacklem args->retrans = oargs->retrans; 239191783Srmacklem args->readahead = oargs->readahead; 240191783Srmacklem args->hostname = oargs->hostname; 241191783Srmacklem} 242191783Srmacklem 243191783Srmacklemstatic void 244191783Srmacklemnfs_convert_diskless(void) 245191783Srmacklem{ 246191783Srmacklem 247221040Srmacklem bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif, 248221040Srmacklem sizeof(struct ifaliasreq)); 249221040Srmacklem bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway, 250221040Srmacklem sizeof(struct sockaddr_in)); 251221040Srmacklem nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args); 252221040Srmacklem if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) { 253221040Srmacklem nfsv3_diskless.root_fhsize = NFSX_MYFH; 254221040Srmacklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH); 255191783Srmacklem } else { 256221040Srmacklem nfsv3_diskless.root_fhsize = NFSX_V2FH; 257221040Srmacklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH); 258191783Srmacklem } 259221040Srmacklem bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr, 260221040Srmacklem sizeof(struct sockaddr_in)); 261221040Srmacklem bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN); 262221040Srmacklem nfsv3_diskless.root_time = nfs_diskless.root_time; 263221040Srmacklem bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam, 264221040Srmacklem MAXHOSTNAMELEN); 265221040Srmacklem nfs_diskless_valid = 3; 266191783Srmacklem} 267191783Srmacklem 268191783Srmacklem/* 269191783Srmacklem * nfs statfs call 270191783Srmacklem */ 271191783Srmacklemstatic int 272191990Sattilionfs_statfs(struct mount *mp, struct statfs *sbp) 273191783Srmacklem{ 274191783Srmacklem struct vnode *vp; 275191990Sattilio struct thread *td; 276191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 277191783Srmacklem struct nfsvattr nfsva; 278191783Srmacklem struct nfsfsinfo fs; 279191783Srmacklem struct nfsstatfs sb; 280191783Srmacklem int error = 0, attrflag, gotfsinfo = 0, ret; 281191783Srmacklem struct nfsnode *np; 282191783Srmacklem 283191990Sattilio td = curthread; 284191990Sattilio 285191783Srmacklem error = vfs_busy(mp, MBF_NOWAIT); 286191783Srmacklem if (error) 287191783Srmacklem return (error); 288220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE); 289191783Srmacklem if (error) { 290191783Srmacklem vfs_unbusy(mp); 291191783Srmacklem return (error); 292191783Srmacklem } 293191783Srmacklem vp = NFSTOV(np); 294191783Srmacklem mtx_lock(&nmp->nm_mtx); 295191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 296191783Srmacklem mtx_unlock(&nmp->nm_mtx); 297191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva, 298191783Srmacklem &attrflag, NULL); 299191783Srmacklem if (!error) 300191783Srmacklem gotfsinfo = 1; 301191783Srmacklem } else 302191783Srmacklem mtx_unlock(&nmp->nm_mtx); 303191783Srmacklem if (!error) 304191783Srmacklem error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, 305191783Srmacklem &attrflag, NULL); 306244042Srmacklem if (error != 0) 307244042Srmacklem NFSCL_DEBUG(2, "statfs=%d\n", error); 308191783Srmacklem if (attrflag == 0) { 309191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 310244042Srmacklem td->td_ucred, td, &nfsva, NULL, NULL); 311191783Srmacklem if (ret) { 312191783Srmacklem /* 313191783Srmacklem * Just set default values to get things going. 314191783Srmacklem */ 315191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 316191783Srmacklem nfsva.na_vattr.va_type = VDIR; 317191783Srmacklem nfsva.na_vattr.va_mode = 0777; 318191783Srmacklem nfsva.na_vattr.va_nlink = 100; 319191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 320191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 321191783Srmacklem nfsva.na_vattr.va_fileid = 2; 322191783Srmacklem nfsva.na_vattr.va_gen = 1; 323191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 324191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 325191783Srmacklem } 326191783Srmacklem } 327191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 328191783Srmacklem if (!error) { 329191783Srmacklem mtx_lock(&nmp->nm_mtx); 330191783Srmacklem if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4)) 331191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 332191783Srmacklem nfscl_loadsbinfo(nmp, &sb, sbp); 333191783Srmacklem sbp->f_iosize = newnfs_iosize(nmp); 334191783Srmacklem mtx_unlock(&nmp->nm_mtx); 335191783Srmacklem if (sbp != &mp->mnt_stat) { 336191783Srmacklem bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 337191783Srmacklem bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 338191783Srmacklem } 339191783Srmacklem strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 340191783Srmacklem } else if (NFS_ISV4(vp)) { 341191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 342191783Srmacklem } 343191783Srmacklem vput(vp); 344191783Srmacklem vfs_unbusy(mp); 345191783Srmacklem return (error); 346191783Srmacklem} 347191783Srmacklem 348191783Srmacklem/* 349191783Srmacklem * nfs version 3 fsinfo rpc call 350191783Srmacklem */ 351191783Srmacklemint 352191783Srmacklemncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, 353191783Srmacklem struct thread *td) 354191783Srmacklem{ 355191783Srmacklem struct nfsfsinfo fs; 356191783Srmacklem struct nfsvattr nfsva; 357191783Srmacklem int error, attrflag; 358191783Srmacklem 359191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL); 360191783Srmacklem if (!error) { 361191783Srmacklem if (attrflag) 362191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 363191783Srmacklem 1); 364191783Srmacklem mtx_lock(&nmp->nm_mtx); 365191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 366191783Srmacklem mtx_unlock(&nmp->nm_mtx); 367191783Srmacklem } 368191783Srmacklem return (error); 369191783Srmacklem} 370191783Srmacklem 371191783Srmacklem/* 372191783Srmacklem * Mount a remote root fs via. nfs. This depends on the info in the 373221040Srmacklem * nfs_diskless structure that has been filled in properly by some primary 374191783Srmacklem * bootstrap. 375191783Srmacklem * It goes something like this: 376191783Srmacklem * - do enough of "ifconfig" by calling ifioctl() so that the system 377191783Srmacklem * can talk to the server 378221040Srmacklem * - If nfs_diskless.mygateway is filled in, use that address as 379191783Srmacklem * a default gateway. 380191783Srmacklem * - build the rootfs mount point and call mountnfs() to do the rest. 381191783Srmacklem * 382191783Srmacklem * It is assumed to be safe to read, modify, and write the nfsv3_diskless 383191783Srmacklem * structure, as well as other global NFS client variables here, as 384192145Srmacklem * nfs_mountroot() will be called once in the boot before any other NFS 385191783Srmacklem * client activity occurs. 386191783Srmacklem */ 387221040Srmacklemstatic int 388221040Srmacklemnfs_mountroot(struct mount *mp) 389191783Srmacklem{ 390192145Srmacklem struct thread *td = curthread; 391221040Srmacklem struct nfsv3_diskless *nd = &nfsv3_diskless; 392191783Srmacklem struct socket *so; 393191783Srmacklem struct vnode *vp; 394191783Srmacklem struct ifreq ir; 395193066Sjamie int error; 396191783Srmacklem u_long l; 397191783Srmacklem char buf[128]; 398191783Srmacklem char *cp; 399191783Srmacklem 400191783Srmacklem#if defined(BOOTP_NFSROOT) && defined(BOOTP) 401192145Srmacklem bootpc_init(); /* use bootp to get nfs_diskless filled in */ 402191783Srmacklem#elif defined(NFS_ROOT) 403191783Srmacklem nfs_setup_diskless(); 404191783Srmacklem#endif 405191783Srmacklem 406221040Srmacklem if (nfs_diskless_valid == 0) 407191783Srmacklem return (-1); 408221040Srmacklem if (nfs_diskless_valid == 1) 409191783Srmacklem nfs_convert_diskless(); 410191783Srmacklem 411191783Srmacklem /* 412191783Srmacklem * XXX splnet, so networks will receive... 413191783Srmacklem */ 414191783Srmacklem splnet(); 415191783Srmacklem 416191783Srmacklem /* 417191783Srmacklem * Do enough of ifconfig(8) so that the critical net interface can 418191783Srmacklem * talk to the server. 419191783Srmacklem */ 420191783Srmacklem error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0, 421191783Srmacklem td->td_ucred, td); 422191783Srmacklem if (error) 423192145Srmacklem panic("nfs_mountroot: socreate(%04x): %d", 424191783Srmacklem nd->myif.ifra_addr.sa_family, error); 425191783Srmacklem 426191783Srmacklem#if 0 /* XXX Bad idea */ 427191783Srmacklem /* 428191783Srmacklem * We might not have been told the right interface, so we pass 429191783Srmacklem * over the first ten interfaces of the same kind, until we get 430191783Srmacklem * one of them configured. 431191783Srmacklem */ 432191783Srmacklem 433191783Srmacklem for (i = strlen(nd->myif.ifra_name) - 1; 434191783Srmacklem nd->myif.ifra_name[i] >= '0' && 435191783Srmacklem nd->myif.ifra_name[i] <= '9'; 436191783Srmacklem nd->myif.ifra_name[i] ++) { 437191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 438191783Srmacklem if(!error) 439191783Srmacklem break; 440191783Srmacklem } 441191783Srmacklem#endif 442191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 443191783Srmacklem if (error) 444192145Srmacklem panic("nfs_mountroot: SIOCAIFADDR: %d", error); 445191783Srmacklem if ((cp = getenv("boot.netif.mtu")) != NULL) { 446191783Srmacklem ir.ifr_mtu = strtol(cp, NULL, 10); 447191783Srmacklem bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); 448191783Srmacklem freeenv(cp); 449191783Srmacklem error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); 450191783Srmacklem if (error) 451192145Srmacklem printf("nfs_mountroot: SIOCSIFMTU: %d", error); 452191783Srmacklem } 453191783Srmacklem soclose(so); 454191783Srmacklem 455191783Srmacklem /* 456191783Srmacklem * If the gateway field is filled in, set it as the default route. 457191783Srmacklem * Note that pxeboot will set a default route of 0 if the route 458191783Srmacklem * is not set by the DHCP server. Check also for a value of 0 459191783Srmacklem * to avoid panicking inappropriately in that situation. 460191783Srmacklem */ 461191783Srmacklem if (nd->mygateway.sin_len != 0 && 462191783Srmacklem nd->mygateway.sin_addr.s_addr != 0) { 463191783Srmacklem struct sockaddr_in mask, sin; 464191783Srmacklem 465191783Srmacklem bzero((caddr_t)&mask, sizeof(mask)); 466191783Srmacklem sin = mask; 467191783Srmacklem sin.sin_family = AF_INET; 468191783Srmacklem sin.sin_len = sizeof(sin); 469192145Srmacklem /* XXX MRT use table 0 for this sort of thing */ 470218757Sbz CURVNET_SET(TD_TO_VNET(td)); 471231852Sbz error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin, 472191783Srmacklem (struct sockaddr *)&nd->mygateway, 473191783Srmacklem (struct sockaddr *)&mask, 474231852Sbz RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB); 475218757Sbz CURVNET_RESTORE(); 476191783Srmacklem if (error) 477192145Srmacklem panic("nfs_mountroot: RTM_ADD: %d", error); 478191783Srmacklem } 479191783Srmacklem 480191783Srmacklem /* 481191783Srmacklem * Create the rootfs mount point. 482191783Srmacklem */ 483191783Srmacklem nd->root_args.fh = nd->root_fh; 484191783Srmacklem nd->root_args.fhsize = nd->root_fhsize; 485191783Srmacklem l = ntohl(nd->root_saddr.sin_addr.s_addr); 486191783Srmacklem snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", 487191783Srmacklem (l >> 24) & 0xff, (l >> 16) & 0xff, 488191783Srmacklem (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); 489191783Srmacklem printf("NFS ROOT: %s\n", buf); 490192145Srmacklem nd->root_args.hostname = buf; 491191783Srmacklem if ((error = nfs_mountdiskless(buf, 492191783Srmacklem &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { 493191783Srmacklem return (error); 494191783Srmacklem } 495191783Srmacklem 496191783Srmacklem /* 497191783Srmacklem * This is not really an nfs issue, but it is much easier to 498191783Srmacklem * set hostname here and then let the "/etc/rc.xxx" files 499191783Srmacklem * mount the right /var based upon its preset value. 500191783Srmacklem */ 501193066Sjamie mtx_lock(&prison0.pr_mtx); 502194118Sjamie strlcpy(prison0.pr_hostname, nd->my_hostnam, 503194118Sjamie sizeof(prison0.pr_hostname)); 504193066Sjamie mtx_unlock(&prison0.pr_mtx); 505191783Srmacklem inittodr(ntohl(nd->root_time)); 506191783Srmacklem return (0); 507191783Srmacklem} 508191783Srmacklem 509191783Srmacklem/* 510191783Srmacklem * Internal version of mount system call for diskless setup. 511191783Srmacklem */ 512191783Srmacklemstatic int 513191783Srmacklemnfs_mountdiskless(char *path, 514191783Srmacklem struct sockaddr_in *sin, struct nfs_args *args, struct thread *td, 515191783Srmacklem struct vnode **vpp, struct mount *mp) 516191783Srmacklem{ 517191783Srmacklem struct sockaddr *nam; 518221014Srmacklem int dirlen, error; 519221014Srmacklem char *dirpath; 520191783Srmacklem 521221014Srmacklem /* 522221014Srmacklem * Find the directory path in "path", which also has the server's 523221014Srmacklem * name/ip address in it. 524221014Srmacklem */ 525221014Srmacklem dirpath = strchr(path, ':'); 526221014Srmacklem if (dirpath != NULL) 527221014Srmacklem dirlen = strlen(++dirpath); 528221014Srmacklem else 529221014Srmacklem dirlen = 0; 530191783Srmacklem nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); 531221014Srmacklem if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen, 532230547Sjhb NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO, 533244042Srmacklem NFS_DEFAULT_NEGNAMETIMEO, 0)) != 0) { 534192145Srmacklem printf("nfs_mountroot: mount %s on /: %d\n", path, error); 535191783Srmacklem return (error); 536191783Srmacklem } 537191783Srmacklem return (0); 538191783Srmacklem} 539191783Srmacklem 540191783Srmacklemstatic void 541192585Srmacklemnfs_sec_name(char *sec, int *flagsp) 542192585Srmacklem{ 543192585Srmacklem if (!strcmp(sec, "krb5")) 544192585Srmacklem *flagsp |= NFSMNT_KERB; 545192585Srmacklem else if (!strcmp(sec, "krb5i")) 546192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY); 547192585Srmacklem else if (!strcmp(sec, "krb5p")) 548192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY); 549192585Srmacklem} 550192585Srmacklem 551192585Srmacklemstatic void 552191783Srmacklemnfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, 553214048Srmacklem const char *hostname, struct ucred *cred, struct thread *td) 554191783Srmacklem{ 555191783Srmacklem int s; 556191783Srmacklem int adjsock; 557214048Srmacklem char *p; 558191783Srmacklem 559191783Srmacklem s = splnet(); 560191783Srmacklem 561191783Srmacklem /* 562191783Srmacklem * Set read-only flag if requested; otherwise, clear it if this is 563191783Srmacklem * an update. If this is not an update, then either the read-only 564191783Srmacklem * flag is already clear, or this is a root mount and it was set 565191783Srmacklem * intentionally at some previous point. 566191783Srmacklem */ 567191783Srmacklem if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) { 568191783Srmacklem MNT_ILOCK(mp); 569191783Srmacklem mp->mnt_flag |= MNT_RDONLY; 570191783Srmacklem MNT_IUNLOCK(mp); 571191783Srmacklem } else if (mp->mnt_flag & MNT_UPDATE) { 572191783Srmacklem MNT_ILOCK(mp); 573191783Srmacklem mp->mnt_flag &= ~MNT_RDONLY; 574191783Srmacklem MNT_IUNLOCK(mp); 575191783Srmacklem } 576191783Srmacklem 577191783Srmacklem /* 578191783Srmacklem * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 579191783Srmacklem * no sense in that context. Also, set up appropriate retransmit 580191783Srmacklem * and soft timeout behavior. 581191783Srmacklem */ 582191783Srmacklem if (argp->sotype == SOCK_STREAM) { 583191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOCONN; 584191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 585220739Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0) 586220739Srmacklem nmp->nm_retry = INT_MAX; 587220739Srmacklem else 588220739Srmacklem nmp->nm_retry = NFS_RETRANS_TCP; 589191783Srmacklem } 590191783Srmacklem 591220739Srmacklem /* Also clear RDIRPLUS if NFSv2, it crashes some servers */ 592220739Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 593220739Srmacklem argp->flags &= ~NFSMNT_RDIRPLUS; 594191783Srmacklem nmp->nm_flag &= ~NFSMNT_RDIRPLUS; 595220739Srmacklem } 596191783Srmacklem 597220739Srmacklem /* Re-bind if rsrvd port requested and wasn't on one */ 598220739Srmacklem adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT) 599220739Srmacklem && (argp->flags & NFSMNT_RESVPORT); 600191783Srmacklem /* Also re-bind if we're switching to/from a connected UDP socket */ 601220739Srmacklem adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) != 602191783Srmacklem (argp->flags & NFSMNT_NOCONN)); 603191783Srmacklem 604191783Srmacklem /* Update flags atomically. Don't change the lock bits. */ 605191783Srmacklem nmp->nm_flag = argp->flags | nmp->nm_flag; 606191783Srmacklem splx(s); 607191783Srmacklem 608191783Srmacklem if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 609191783Srmacklem nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 610191783Srmacklem if (nmp->nm_timeo < NFS_MINTIMEO) 611191783Srmacklem nmp->nm_timeo = NFS_MINTIMEO; 612191783Srmacklem else if (nmp->nm_timeo > NFS_MAXTIMEO) 613191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 614191783Srmacklem } 615191783Srmacklem 616191783Srmacklem if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 617191783Srmacklem nmp->nm_retry = argp->retrans; 618191783Srmacklem if (nmp->nm_retry > NFS_MAXREXMIT) 619191783Srmacklem nmp->nm_retry = NFS_MAXREXMIT; 620191783Srmacklem } 621191783Srmacklem 622191783Srmacklem if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 623191783Srmacklem nmp->nm_wsize = argp->wsize; 624274150Srmacklem /* 625274150Srmacklem * Clip at the power of 2 below the size. There is an 626274150Srmacklem * issue (not isolated) that causes intermittent page 627274150Srmacklem * faults if this is not done. 628274150Srmacklem */ 629274150Srmacklem if (nmp->nm_wsize > NFS_FABLKSIZE) 630274150Srmacklem nmp->nm_wsize = 1 << (fls(nmp->nm_wsize) - 1); 631274150Srmacklem else 632191783Srmacklem nmp->nm_wsize = NFS_FABLKSIZE; 633191783Srmacklem } 634191783Srmacklem 635191783Srmacklem if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 636191783Srmacklem nmp->nm_rsize = argp->rsize; 637274150Srmacklem /* 638274150Srmacklem * Clip at the power of 2 below the size. There is an 639274150Srmacklem * issue (not isolated) that causes intermittent page 640274150Srmacklem * faults if this is not done. 641274150Srmacklem */ 642274150Srmacklem if (nmp->nm_rsize > NFS_FABLKSIZE) 643274150Srmacklem nmp->nm_rsize = 1 << (fls(nmp->nm_rsize) - 1); 644274150Srmacklem else 645191783Srmacklem nmp->nm_rsize = NFS_FABLKSIZE; 646191783Srmacklem } 647191783Srmacklem 648191783Srmacklem if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 649191783Srmacklem nmp->nm_readdirsize = argp->readdirsize; 650191783Srmacklem } 651191783Srmacklem 652191783Srmacklem if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) 653191783Srmacklem nmp->nm_acregmin = argp->acregmin; 654191783Srmacklem else 655191783Srmacklem nmp->nm_acregmin = NFS_MINATTRTIMO; 656191783Srmacklem if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) 657191783Srmacklem nmp->nm_acregmax = argp->acregmax; 658191783Srmacklem else 659191783Srmacklem nmp->nm_acregmax = NFS_MAXATTRTIMO; 660191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) 661191783Srmacklem nmp->nm_acdirmin = argp->acdirmin; 662191783Srmacklem else 663191783Srmacklem nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; 664191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) 665191783Srmacklem nmp->nm_acdirmax = argp->acdirmax; 666191783Srmacklem else 667191783Srmacklem nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; 668191783Srmacklem if (nmp->nm_acdirmin > nmp->nm_acdirmax) 669191783Srmacklem nmp->nm_acdirmin = nmp->nm_acdirmax; 670191783Srmacklem if (nmp->nm_acregmin > nmp->nm_acregmax) 671191783Srmacklem nmp->nm_acregmin = nmp->nm_acregmax; 672191783Srmacklem 673191783Srmacklem if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { 674191783Srmacklem if (argp->readahead <= NFS_MAXRAHEAD) 675191783Srmacklem nmp->nm_readahead = argp->readahead; 676191783Srmacklem else 677191783Srmacklem nmp->nm_readahead = NFS_MAXRAHEAD; 678191783Srmacklem } 679191783Srmacklem if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) { 680191783Srmacklem if (argp->wcommitsize < nmp->nm_wsize) 681191783Srmacklem nmp->nm_wcommitsize = nmp->nm_wsize; 682191783Srmacklem else 683191783Srmacklem nmp->nm_wcommitsize = argp->wcommitsize; 684191783Srmacklem } 685191783Srmacklem 686191783Srmacklem adjsock |= ((nmp->nm_sotype != argp->sotype) || 687191783Srmacklem (nmp->nm_soproto != argp->proto)); 688191783Srmacklem 689191783Srmacklem if (nmp->nm_client != NULL && adjsock) { 690191783Srmacklem int haslock = 0, error = 0; 691191783Srmacklem 692191783Srmacklem if (nmp->nm_sotype == SOCK_STREAM) { 693191783Srmacklem error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock); 694191783Srmacklem if (!error) 695191783Srmacklem haslock = 1; 696191783Srmacklem } 697191783Srmacklem if (!error) { 698191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 699191783Srmacklem if (haslock) 700191783Srmacklem newnfs_sndunlock(&nmp->nm_sockreq.nr_lock); 701191783Srmacklem nmp->nm_sotype = argp->sotype; 702191783Srmacklem nmp->nm_soproto = argp->proto; 703191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 704191783Srmacklem while (newnfs_connect(nmp, &nmp->nm_sockreq, 705191783Srmacklem cred, td, 0)) { 706191783Srmacklem printf("newnfs_args: retrying connect\n"); 707207170Srmacklem (void) nfs_catnap(PSOCK, 0, "newnfscon"); 708191783Srmacklem } 709191783Srmacklem } 710191783Srmacklem } else { 711191783Srmacklem nmp->nm_sotype = argp->sotype; 712191783Srmacklem nmp->nm_soproto = argp->proto; 713191783Srmacklem } 714214048Srmacklem 715214048Srmacklem if (hostname != NULL) { 716214048Srmacklem strlcpy(nmp->nm_hostname, hostname, 717214048Srmacklem sizeof(nmp->nm_hostname)); 718214048Srmacklem p = strchr(nmp->nm_hostname, ':'); 719214048Srmacklem if (p != NULL) 720214048Srmacklem *p = '\0'; 721214048Srmacklem } 722191783Srmacklem} 723191783Srmacklem 724221190Srmacklemstatic const char *nfs_opts[] = { "from", "nfs_args", 725275249Strasz "noac", "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union", 726191783Srmacklem "noclusterr", "noclusterw", "multilabel", "acls", "force", "update", 727192585Srmacklem "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus", 728192585Srmacklem "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize", 729275249Strasz "retrans", "actimeo", "acregmin", "acregmax", "acdirmin", "acdirmax", 730275249Strasz "resvport", "readahead", "hostname", "timeo", "timeout", "addr", "fh", 731275249Strasz "nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath", 732275249Strasz "minorversion", "nametimeo", "negnametimeo", "nocto", "noncontigwr", 733275249Strasz "pnfs", "wcommitsize", 734191783Srmacklem NULL }; 735191783Srmacklem 736191783Srmacklem/* 737191783Srmacklem * VFS Operations. 738191783Srmacklem * 739191783Srmacklem * mount system call 740191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 741191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 742191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 743191783Srmacklem * an error after that means that I have to release the mbuf. 744191783Srmacklem */ 745191783Srmacklem/* ARGSUSED */ 746191783Srmacklemstatic int 747191990Sattilionfs_mount(struct mount *mp) 748191783Srmacklem{ 749191783Srmacklem struct nfs_args args = { 750191783Srmacklem .version = NFS_ARGSVERSION, 751191783Srmacklem .addr = NULL, 752191783Srmacklem .addrlen = sizeof (struct sockaddr_in), 753191783Srmacklem .sotype = SOCK_STREAM, 754191783Srmacklem .proto = 0, 755191783Srmacklem .fh = NULL, 756191783Srmacklem .fhsize = 0, 757220739Srmacklem .flags = NFSMNT_RESVPORT, 758191783Srmacklem .wsize = NFS_WSIZE, 759191783Srmacklem .rsize = NFS_RSIZE, 760191783Srmacklem .readdirsize = NFS_READDIRSIZE, 761191783Srmacklem .timeo = 10, 762191783Srmacklem .retrans = NFS_RETRANS, 763191783Srmacklem .readahead = NFS_DEFRAHEAD, 764191783Srmacklem .wcommitsize = 0, /* was: NQ_DEFLEASE */ 765191783Srmacklem .hostname = NULL, 766191783Srmacklem .acregmin = NFS_MINATTRTIMO, 767191783Srmacklem .acregmax = NFS_MAXATTRTIMO, 768191783Srmacklem .acdirmin = NFS_MINDIRATTRTIMO, 769191783Srmacklem .acdirmax = NFS_MAXDIRATTRTIMO, 770191783Srmacklem }; 771192585Srmacklem int error = 0, ret, len; 772192585Srmacklem struct sockaddr *nam = NULL; 773191783Srmacklem struct vnode *vp; 774191990Sattilio struct thread *td; 775191783Srmacklem char hst[MNAMELEN]; 776191783Srmacklem u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100]; 777192585Srmacklem char *opt, *name, *secname; 778230547Sjhb int nametimeo = NFS_DEFAULT_NAMETIMEO; 779203303Srmacklem int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO; 780244042Srmacklem int minvers = 0; 781221190Srmacklem int dirlen, has_nfs_args_opt, krbnamelen, srvkrbnamelen; 782221205Srmacklem size_t hstlen; 783191783Srmacklem 784221190Srmacklem has_nfs_args_opt = 0; 785191783Srmacklem if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) { 786191783Srmacklem error = EINVAL; 787191783Srmacklem goto out; 788191783Srmacklem } 789191783Srmacklem 790191990Sattilio td = curthread; 791191783Srmacklem if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) { 792221040Srmacklem error = nfs_mountroot(mp); 793191783Srmacklem goto out; 794191783Srmacklem } 795191783Srmacklem 796192585Srmacklem nfscl_init(); 797191783Srmacklem 798221190Srmacklem /* 799221190Srmacklem * The old mount_nfs program passed the struct nfs_args 800221190Srmacklem * from userspace to kernel. The new mount_nfs program 801221190Srmacklem * passes string options via nmount() from userspace to kernel 802221190Srmacklem * and we populate the struct nfs_args in the kernel. 803221190Srmacklem */ 804221190Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) { 805221190Srmacklem error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args, 806221190Srmacklem sizeof(args)); 807221190Srmacklem if (error != 0) 808221190Srmacklem goto out; 809221190Srmacklem 810221190Srmacklem if (args.version != NFS_ARGSVERSION) { 811221190Srmacklem error = EPROGMISMATCH; 812221190Srmacklem goto out; 813221190Srmacklem } 814221190Srmacklem has_nfs_args_opt = 1; 815221190Srmacklem } 816221190Srmacklem 817192585Srmacklem /* Handle the new style options. */ 818275249Strasz if (vfs_getopt(mp->mnt_optnew, "noac", NULL, NULL) == 0) { 819275249Strasz args.acdirmin = args.acdirmax = 820275249Strasz args.acregmin = args.acregmax = 0; 821275249Strasz args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX | 822275249Strasz NFSMNT_ACREGMIN | NFSMNT_ACREGMAX; 823275249Strasz } 824192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0) 825192585Srmacklem args.flags |= NFSMNT_NOCONN; 826192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0) 827275252Strasz args.flags &= ~NFSMNT_NOCONN; 828192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0) 829192585Srmacklem args.flags |= NFSMNT_NOLOCKD; 830192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0) 831192585Srmacklem args.flags &= ~NFSMNT_NOLOCKD; 832192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0) 833192585Srmacklem args.flags |= NFSMNT_INT; 834192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0) 835192585Srmacklem args.flags |= NFSMNT_RDIRPLUS; 836192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0) 837192585Srmacklem args.flags |= NFSMNT_RESVPORT; 838192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0) 839192585Srmacklem args.flags &= ~NFSMNT_RESVPORT; 840192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0) 841192585Srmacklem args.flags |= NFSMNT_SOFT; 842192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0) 843192585Srmacklem args.flags &= ~NFSMNT_SOFT; 844192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0) 845192585Srmacklem args.sotype = SOCK_DGRAM; 846192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0) 847192585Srmacklem args.sotype = SOCK_DGRAM; 848192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0) 849192585Srmacklem args.sotype = SOCK_STREAM; 850192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0) 851192585Srmacklem args.flags |= NFSMNT_NFSV3; 852192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) { 853192585Srmacklem args.flags |= NFSMNT_NFSV4; 854192585Srmacklem args.sotype = SOCK_STREAM; 855191783Srmacklem } 856192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0) 857192585Srmacklem args.flags |= NFSMNT_ALLGSSNAME; 858221436Sru if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0) 859221436Sru args.flags |= NFSMNT_NOCTO; 860260107Srmacklem if (vfs_getopt(mp->mnt_optnew, "noncontigwr", NULL, NULL) == 0) 861260107Srmacklem args.flags |= NFSMNT_NONCONTIGWR; 862244042Srmacklem if (vfs_getopt(mp->mnt_optnew, "pnfs", NULL, NULL) == 0) 863244042Srmacklem args.flags |= NFSMNT_PNFS; 864192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) { 865192585Srmacklem if (opt == NULL) { 866192585Srmacklem vfs_mount_error(mp, "illegal readdirsize"); 867192585Srmacklem error = EINVAL; 868192585Srmacklem goto out; 869192585Srmacklem } 870192585Srmacklem ret = sscanf(opt, "%d", &args.readdirsize); 871192585Srmacklem if (ret != 1 || args.readdirsize <= 0) { 872192585Srmacklem vfs_mount_error(mp, "illegal readdirsize: %s", 873192585Srmacklem opt); 874192585Srmacklem error = EINVAL; 875192585Srmacklem goto out; 876192585Srmacklem } 877192585Srmacklem args.flags |= NFSMNT_READDIRSIZE; 878192585Srmacklem } 879192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) { 880192585Srmacklem if (opt == NULL) { 881192585Srmacklem vfs_mount_error(mp, "illegal readahead"); 882192585Srmacklem error = EINVAL; 883192585Srmacklem goto out; 884192585Srmacklem } 885192585Srmacklem ret = sscanf(opt, "%d", &args.readahead); 886192585Srmacklem if (ret != 1 || args.readahead <= 0) { 887192585Srmacklem vfs_mount_error(mp, "illegal readahead: %s", 888192585Srmacklem opt); 889192585Srmacklem error = EINVAL; 890192585Srmacklem goto out; 891192585Srmacklem } 892192585Srmacklem args.flags |= NFSMNT_READAHEAD; 893192585Srmacklem } 894192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) { 895192585Srmacklem if (opt == NULL) { 896192585Srmacklem vfs_mount_error(mp, "illegal wsize"); 897192585Srmacklem error = EINVAL; 898192585Srmacklem goto out; 899192585Srmacklem } 900192585Srmacklem ret = sscanf(opt, "%d", &args.wsize); 901192585Srmacklem if (ret != 1 || args.wsize <= 0) { 902192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 903192585Srmacklem opt); 904192585Srmacklem error = EINVAL; 905192585Srmacklem goto out; 906192585Srmacklem } 907192585Srmacklem args.flags |= NFSMNT_WSIZE; 908192585Srmacklem } 909192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) { 910192585Srmacklem if (opt == NULL) { 911192585Srmacklem vfs_mount_error(mp, "illegal rsize"); 912192585Srmacklem error = EINVAL; 913192585Srmacklem goto out; 914192585Srmacklem } 915192585Srmacklem ret = sscanf(opt, "%d", &args.rsize); 916192585Srmacklem if (ret != 1 || args.rsize <= 0) { 917192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 918192585Srmacklem opt); 919192585Srmacklem error = EINVAL; 920192585Srmacklem goto out; 921192585Srmacklem } 922192585Srmacklem args.flags |= NFSMNT_RSIZE; 923192585Srmacklem } 924192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) { 925192585Srmacklem if (opt == NULL) { 926192585Srmacklem vfs_mount_error(mp, "illegal retrans"); 927192585Srmacklem error = EINVAL; 928192585Srmacklem goto out; 929192585Srmacklem } 930192585Srmacklem ret = sscanf(opt, "%d", &args.retrans); 931192585Srmacklem if (ret != 1 || args.retrans <= 0) { 932192585Srmacklem vfs_mount_error(mp, "illegal retrans: %s", 933192585Srmacklem opt); 934192585Srmacklem error = EINVAL; 935192585Srmacklem goto out; 936192585Srmacklem } 937192585Srmacklem args.flags |= NFSMNT_RETRANS; 938192585Srmacklem } 939275249Strasz if (vfs_getopt(mp->mnt_optnew, "actimeo", (void **)&opt, NULL) == 0) { 940275249Strasz ret = sscanf(opt, "%d", &args.acregmin); 941275249Strasz if (ret != 1 || args.acregmin < 0) { 942275249Strasz vfs_mount_error(mp, "illegal actimeo: %s", 943275249Strasz opt); 944275249Strasz error = EINVAL; 945275249Strasz goto out; 946275249Strasz } 947275249Strasz args.acdirmin = args.acdirmax = args.acregmax = args.acregmin; 948275249Strasz args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX | 949275249Strasz NFSMNT_ACREGMIN | NFSMNT_ACREGMAX; 950275249Strasz } 951192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) { 952192585Srmacklem ret = sscanf(opt, "%d", &args.acregmin); 953192585Srmacklem if (ret != 1 || args.acregmin < 0) { 954192585Srmacklem vfs_mount_error(mp, "illegal acregmin: %s", 955192585Srmacklem opt); 956192585Srmacklem error = EINVAL; 957192585Srmacklem goto out; 958192585Srmacklem } 959192585Srmacklem args.flags |= NFSMNT_ACREGMIN; 960192585Srmacklem } 961192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) { 962192585Srmacklem ret = sscanf(opt, "%d", &args.acregmax); 963192585Srmacklem if (ret != 1 || args.acregmax < 0) { 964192585Srmacklem vfs_mount_error(mp, "illegal acregmax: %s", 965192585Srmacklem opt); 966192585Srmacklem error = EINVAL; 967192585Srmacklem goto out; 968192585Srmacklem } 969192585Srmacklem args.flags |= NFSMNT_ACREGMAX; 970192585Srmacklem } 971192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) { 972192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmin); 973192585Srmacklem if (ret != 1 || args.acdirmin < 0) { 974192585Srmacklem vfs_mount_error(mp, "illegal acdirmin: %s", 975192585Srmacklem opt); 976192585Srmacklem error = EINVAL; 977192585Srmacklem goto out; 978192585Srmacklem } 979192585Srmacklem args.flags |= NFSMNT_ACDIRMIN; 980192585Srmacklem } 981192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) { 982192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmax); 983192585Srmacklem if (ret != 1 || args.acdirmax < 0) { 984192585Srmacklem vfs_mount_error(mp, "illegal acdirmax: %s", 985192585Srmacklem opt); 986192585Srmacklem error = EINVAL; 987192585Srmacklem goto out; 988192585Srmacklem } 989192585Srmacklem args.flags |= NFSMNT_ACDIRMAX; 990192585Srmacklem } 991227507Sjhb if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) { 992227507Sjhb ret = sscanf(opt, "%d", &args.wcommitsize); 993227507Sjhb if (ret != 1 || args.wcommitsize < 0) { 994227507Sjhb vfs_mount_error(mp, "illegal wcommitsize: %s", opt); 995227507Sjhb error = EINVAL; 996227507Sjhb goto out; 997227507Sjhb } 998227507Sjhb args.flags |= NFSMNT_WCOMMITSIZE; 999227507Sjhb } 1000275249Strasz if (vfs_getopt(mp->mnt_optnew, "timeo", (void **)&opt, NULL) == 0) { 1001275249Strasz ret = sscanf(opt, "%d", &args.timeo); 1002275249Strasz if (ret != 1 || args.timeo <= 0) { 1003275249Strasz vfs_mount_error(mp, "illegal timeo: %s", 1004275249Strasz opt); 1005275249Strasz error = EINVAL; 1006275249Strasz goto out; 1007275249Strasz } 1008275249Strasz args.flags |= NFSMNT_TIMEO; 1009275249Strasz } 1010192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) { 1011192585Srmacklem ret = sscanf(opt, "%d", &args.timeo); 1012192585Srmacklem if (ret != 1 || args.timeo <= 0) { 1013192585Srmacklem vfs_mount_error(mp, "illegal timeout: %s", 1014192585Srmacklem opt); 1015192585Srmacklem error = EINVAL; 1016192585Srmacklem goto out; 1017192585Srmacklem } 1018192585Srmacklem args.flags |= NFSMNT_TIMEO; 1019192585Srmacklem } 1020230547Sjhb if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) { 1021230547Sjhb ret = sscanf(opt, "%d", &nametimeo); 1022230547Sjhb if (ret != 1 || nametimeo < 0) { 1023230547Sjhb vfs_mount_error(mp, "illegal nametimeo: %s", opt); 1024230547Sjhb error = EINVAL; 1025230547Sjhb goto out; 1026230547Sjhb } 1027230547Sjhb } 1028203303Srmacklem if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL) 1029203303Srmacklem == 0) { 1030203303Srmacklem ret = sscanf(opt, "%d", &negnametimeo); 1031203303Srmacklem if (ret != 1 || negnametimeo < 0) { 1032203303Srmacklem vfs_mount_error(mp, "illegal negnametimeo: %s", 1033203303Srmacklem opt); 1034203303Srmacklem error = EINVAL; 1035203303Srmacklem goto out; 1036203303Srmacklem } 1037203303Srmacklem } 1038244042Srmacklem if (vfs_getopt(mp->mnt_optnew, "minorversion", (void **)&opt, NULL) == 1039244042Srmacklem 0) { 1040244042Srmacklem ret = sscanf(opt, "%d", &minvers); 1041244042Srmacklem if (ret != 1 || minvers < 0 || minvers > 1 || 1042244042Srmacklem (args.flags & NFSMNT_NFSV4) == 0) { 1043244042Srmacklem vfs_mount_error(mp, "illegal minorversion: %s", opt); 1044244042Srmacklem error = EINVAL; 1045244042Srmacklem goto out; 1046244042Srmacklem } 1047244042Srmacklem } 1048192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "sec", 1049192585Srmacklem (void **) &secname, NULL) == 0) 1050192585Srmacklem nfs_sec_name(secname, &args.flags); 1051191783Srmacklem 1052191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 1053191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1054191783Srmacklem 1055191783Srmacklem if (nmp == NULL) { 1056191783Srmacklem error = EIO; 1057191783Srmacklem goto out; 1058191783Srmacklem } 1059230803Srmacklem 1060191783Srmacklem /* 1061230803Srmacklem * If a change from TCP->UDP is done and there are thread(s) 1062230803Srmacklem * that have I/O RPC(s) in progress with a tranfer size 1063230803Srmacklem * greater than NFS_MAXDGRAMDATA, those thread(s) will be 1064230803Srmacklem * hung, retrying the RPC(s) forever. Usually these threads 1065230803Srmacklem * will be seen doing an uninterruptible sleep on wait channel 1066230803Srmacklem * "newnfsreq" (truncated to "newnfsre" by procstat). 1067230803Srmacklem */ 1068230803Srmacklem if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM) 1069230803Srmacklem tprintf(td->td_proc, LOG_WARNING, 1070230803Srmacklem "Warning: mount -u that changes TCP->UDP can result in hung threads\n"); 1071230803Srmacklem 1072230803Srmacklem /* 1073191783Srmacklem * When doing an update, we can't change version, 1074191783Srmacklem * security, switch lockd strategies or change cookie 1075191783Srmacklem * translation 1076191783Srmacklem */ 1077191783Srmacklem args.flags = (args.flags & 1078191783Srmacklem ~(NFSMNT_NFSV3 | 1079191783Srmacklem NFSMNT_NFSV4 | 1080191783Srmacklem NFSMNT_KERB | 1081191783Srmacklem NFSMNT_INTEGRITY | 1082191783Srmacklem NFSMNT_PRIVACY | 1083191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) | 1084191783Srmacklem (nmp->nm_flag & 1085191783Srmacklem (NFSMNT_NFSV3 | 1086191783Srmacklem NFSMNT_NFSV4 | 1087191783Srmacklem NFSMNT_KERB | 1088191783Srmacklem NFSMNT_INTEGRITY | 1089191783Srmacklem NFSMNT_PRIVACY | 1090191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); 1091214048Srmacklem nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td); 1092191783Srmacklem goto out; 1093191783Srmacklem } 1094191783Srmacklem 1095191783Srmacklem /* 1096191783Srmacklem * Make the nfs_ip_paranoia sysctl serve as the default connection 1097191783Srmacklem * or no-connection mode for those protocols that support 1098191783Srmacklem * no-connection mode (the flag will be cleared later for protocols 1099191783Srmacklem * that do not support no-connection mode). This will allow a client 1100191783Srmacklem * to receive replies from a different IP then the request was 1101191783Srmacklem * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid), 1102191783Srmacklem * not 0. 1103191783Srmacklem */ 1104191783Srmacklem if (nfs_ip_paranoia == 0) 1105191783Srmacklem args.flags |= NFSMNT_NOCONN; 1106192585Srmacklem 1107221190Srmacklem if (has_nfs_args_opt != 0) { 1108221190Srmacklem /* 1109221190Srmacklem * In the 'nfs_args' case, the pointers in the args 1110221190Srmacklem * structure are in userland - we copy them in here. 1111221190Srmacklem */ 1112221190Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) { 1113192585Srmacklem vfs_mount_error(mp, "Bad file handle"); 1114191783Srmacklem error = EINVAL; 1115191783Srmacklem goto out; 1116191783Srmacklem } 1117221190Srmacklem error = copyin((caddr_t)args.fh, (caddr_t)nfh, 1118221190Srmacklem args.fhsize); 1119221190Srmacklem if (error != 0) 1120221190Srmacklem goto out; 1121221205Srmacklem error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen); 1122221190Srmacklem if (error != 0) 1123221190Srmacklem goto out; 1124221205Srmacklem bzero(&hst[hstlen], MNAMELEN - hstlen); 1125221190Srmacklem args.hostname = hst; 1126221190Srmacklem /* sockargs() call must be after above copyin() calls */ 1127221190Srmacklem error = getsockaddr(&nam, (caddr_t)args.addr, 1128221190Srmacklem args.addrlen); 1129221190Srmacklem if (error != 0) 1130221190Srmacklem goto out; 1131191783Srmacklem } else { 1132221190Srmacklem if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh, 1133221190Srmacklem &args.fhsize) == 0) { 1134221190Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) { 1135221190Srmacklem vfs_mount_error(mp, "Bad file handle"); 1136221190Srmacklem error = EINVAL; 1137221190Srmacklem goto out; 1138221190Srmacklem } 1139221190Srmacklem bcopy(args.fh, nfh, args.fhsize); 1140221190Srmacklem } else { 1141221190Srmacklem args.fhsize = 0; 1142221190Srmacklem } 1143221190Srmacklem (void) vfs_getopt(mp->mnt_optnew, "hostname", 1144221190Srmacklem (void **)&args.hostname, &len); 1145221190Srmacklem if (args.hostname == NULL) { 1146221190Srmacklem vfs_mount_error(mp, "Invalid hostname"); 1147221190Srmacklem error = EINVAL; 1148221190Srmacklem goto out; 1149221190Srmacklem } 1150221190Srmacklem bcopy(args.hostname, hst, MNAMELEN); 1151221190Srmacklem hst[MNAMELEN - 1] = '\0'; 1152192585Srmacklem } 1153192585Srmacklem 1154192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0) 1155192585Srmacklem strlcpy(srvkrbname, name, sizeof (srvkrbname)); 1156192585Srmacklem else 1157192585Srmacklem snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst); 1158221014Srmacklem srvkrbnamelen = strlen(srvkrbname); 1159192585Srmacklem 1160192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0) 1161192585Srmacklem strlcpy(krbname, name, sizeof (krbname)); 1162192585Srmacklem else 1163191783Srmacklem krbname[0] = '\0'; 1164221014Srmacklem krbnamelen = strlen(krbname); 1165192585Srmacklem 1166192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0) 1167192585Srmacklem strlcpy(dirpath, name, sizeof (dirpath)); 1168192585Srmacklem else 1169191783Srmacklem dirpath[0] = '\0'; 1170221014Srmacklem dirlen = strlen(dirpath); 1171192585Srmacklem 1172222075Srmacklem if (has_nfs_args_opt == 0) { 1173222075Srmacklem if (vfs_getopt(mp->mnt_optnew, "addr", 1174222075Srmacklem (void **)&args.addr, &args.addrlen) == 0) { 1175222075Srmacklem if (args.addrlen > SOCK_MAXADDRLEN) { 1176222075Srmacklem error = ENAMETOOLONG; 1177222075Srmacklem goto out; 1178222075Srmacklem } 1179222075Srmacklem nam = malloc(args.addrlen, M_SONAME, M_WAITOK); 1180222075Srmacklem bcopy(args.addr, nam, args.addrlen); 1181222075Srmacklem nam->sa_len = args.addrlen; 1182222075Srmacklem } else { 1183222075Srmacklem vfs_mount_error(mp, "No server address"); 1184222075Srmacklem error = EINVAL; 1185191783Srmacklem goto out; 1186191783Srmacklem } 1187191783Srmacklem } 1188192585Srmacklem 1189191783Srmacklem args.fh = nfh; 1190221014Srmacklem error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath, 1191221014Srmacklem dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td, 1192244042Srmacklem nametimeo, negnametimeo, minvers); 1193191783Srmacklemout: 1194191783Srmacklem if (!error) { 1195191783Srmacklem MNT_ILOCK(mp); 1196282270Srmacklem mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_NO_IOPF | 1197282270Srmacklem MNTK_USES_BCACHE; 1198191783Srmacklem MNT_IUNLOCK(mp); 1199191783Srmacklem } 1200191783Srmacklem return (error); 1201191783Srmacklem} 1202191783Srmacklem 1203191783Srmacklem 1204191783Srmacklem/* 1205191783Srmacklem * VFS Operations. 1206191783Srmacklem * 1207191783Srmacklem * mount system call 1208191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 1209191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 1210191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 1211191783Srmacklem * an error after that means that I have to release the mbuf. 1212191783Srmacklem */ 1213191783Srmacklem/* ARGSUSED */ 1214191783Srmacklemstatic int 1215230249Smckusicknfs_cmount(struct mntarg *ma, void *data, uint64_t flags) 1216191783Srmacklem{ 1217191783Srmacklem int error; 1218191783Srmacklem struct nfs_args args; 1219191783Srmacklem 1220191783Srmacklem error = copyin(data, &args, sizeof (struct nfs_args)); 1221191783Srmacklem if (error) 1222191783Srmacklem return error; 1223191783Srmacklem 1224191783Srmacklem ma = mount_arg(ma, "nfs_args", &args, sizeof args); 1225191783Srmacklem 1226191783Srmacklem error = kernel_mount(ma, flags); 1227191783Srmacklem return (error); 1228191783Srmacklem} 1229191783Srmacklem 1230191783Srmacklem/* 1231191783Srmacklem * Common code for mount and mountroot 1232191783Srmacklem */ 1233191783Srmacklemstatic int 1234191783Srmacklemmountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, 1235221014Srmacklem char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen, 1236221014Srmacklem u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp, 1237244042Srmacklem struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo, 1238244042Srmacklem int minvers) 1239191783Srmacklem{ 1240191783Srmacklem struct nfsmount *nmp; 1241191783Srmacklem struct nfsnode *np; 1242195762Srmacklem int error, trycnt, ret; 1243191783Srmacklem struct nfsvattr nfsva; 1244244042Srmacklem struct nfsclclient *clp; 1245244042Srmacklem struct nfsclds *dsp, *tdsp; 1246244042Srmacklem uint32_t lease; 1247191783Srmacklem static u_int64_t clval = 0; 1248191783Srmacklem 1249244042Srmacklem NFSCL_DEBUG(3, "in mnt\n"); 1250244042Srmacklem clp = NULL; 1251191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 1252191783Srmacklem nmp = VFSTONFS(mp); 1253191783Srmacklem printf("%s: MNT_UPDATE is no longer handled here\n", __func__); 1254191783Srmacklem FREE(nam, M_SONAME); 1255191783Srmacklem return (0); 1256191783Srmacklem } else { 1257191783Srmacklem MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) + 1258221014Srmacklem krbnamelen + dirlen + srvkrbnamelen + 2, 1259221014Srmacklem M_NEWNFSMNT, M_WAITOK | M_ZERO); 1260191783Srmacklem TAILQ_INIT(&nmp->nm_bufq); 1261191783Srmacklem if (clval == 0) 1262191783Srmacklem clval = (u_int64_t)nfsboottime.tv_sec; 1263191783Srmacklem nmp->nm_clval = clval++; 1264221014Srmacklem nmp->nm_krbnamelen = krbnamelen; 1265221014Srmacklem nmp->nm_dirpathlen = dirlen; 1266221014Srmacklem nmp->nm_srvkrbnamelen = srvkrbnamelen; 1267192675Srmacklem if (td->td_ucred->cr_uid != (uid_t)0) { 1268191783Srmacklem /* 1269192675Srmacklem * nm_uid is used to get KerberosV credentials for 1270192675Srmacklem * the nfsv4 state handling operations if there is 1271192675Srmacklem * no host based principal set. Use the uid of 1272192675Srmacklem * this user if not root, since they are doing the 1273192675Srmacklem * mount. I don't think setting this for root will 1274192675Srmacklem * work, since root normally does not have user 1275192675Srmacklem * credentials in a credentials cache. 1276191783Srmacklem */ 1277192675Srmacklem nmp->nm_uid = td->td_ucred->cr_uid; 1278191783Srmacklem } else { 1279191783Srmacklem /* 1280192675Srmacklem * Just set to -1, so it won't be used. 1281191783Srmacklem */ 1282191783Srmacklem nmp->nm_uid = (uid_t)-1; 1283191783Srmacklem } 1284191783Srmacklem 1285191783Srmacklem /* Copy and null terminate all the names */ 1286191783Srmacklem if (nmp->nm_krbnamelen > 0) { 1287191783Srmacklem bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen); 1288191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen] = '\0'; 1289191783Srmacklem } 1290191783Srmacklem if (nmp->nm_dirpathlen > 0) { 1291191783Srmacklem bcopy(dirpath, NFSMNT_DIRPATH(nmp), 1292191783Srmacklem nmp->nm_dirpathlen); 1293191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1294191783Srmacklem + 1] = '\0'; 1295191783Srmacklem } 1296191783Srmacklem if (nmp->nm_srvkrbnamelen > 0) { 1297191783Srmacklem bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp), 1298191783Srmacklem nmp->nm_srvkrbnamelen); 1299191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1300191783Srmacklem + nmp->nm_srvkrbnamelen + 2] = '\0'; 1301191783Srmacklem } 1302191783Srmacklem nmp->nm_sockreq.nr_cred = crhold(cred); 1303191783Srmacklem mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF); 1304191783Srmacklem mp->mnt_data = nmp; 1305214048Srmacklem nmp->nm_getinfo = nfs_getnlminfo; 1306216931Srmacklem nmp->nm_vinvalbuf = ncl_vinvalbuf; 1307191783Srmacklem } 1308191783Srmacklem vfs_getnewfsid(mp); 1309191783Srmacklem nmp->nm_mountp = mp; 1310230547Sjhb mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK); 1311227493Srmacklem 1312227493Srmacklem /* 1313230547Sjhb * Since nfs_decode_args() might optionally set them, these 1314230547Sjhb * need to be set to defaults before the call, so that the 1315230547Sjhb * optional settings aren't overwritten. 1316227493Srmacklem */ 1317230547Sjhb nmp->nm_nametimeo = nametimeo; 1318203303Srmacklem nmp->nm_negnametimeo = negnametimeo; 1319227493Srmacklem nmp->nm_timeo = NFS_TIMEO; 1320227493Srmacklem nmp->nm_retry = NFS_RETRANS; 1321227493Srmacklem nmp->nm_readahead = NFS_DEFRAHEAD; 1322282362Smav 1323282362Smav /* This is empirical approximation of sqrt(hibufspace) * 256. */ 1324282362Smav nmp->nm_wcommitsize = NFS_MAXBSIZE / 256; 1325282362Smav while ((long)nmp->nm_wcommitsize * nmp->nm_wcommitsize < hibufspace) 1326282362Smav nmp->nm_wcommitsize *= 2; 1327282362Smav nmp->nm_wcommitsize *= 256; 1328282362Smav 1329244042Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0) 1330244042Srmacklem nmp->nm_minorvers = minvers; 1331244042Srmacklem else 1332244042Srmacklem nmp->nm_minorvers = 0; 1333191783Srmacklem 1334214048Srmacklem nfs_decode_args(mp, nmp, argp, hst, cred, td); 1335192585Srmacklem 1336191783Srmacklem /* 1337191783Srmacklem * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too 1338191783Srmacklem * high, depending on whether we end up with negative offsets in 1339191783Srmacklem * the client or server somewhere. 2GB-1 may be safer. 1340191783Srmacklem * 1341191783Srmacklem * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum 1342191783Srmacklem * that we can handle until we find out otherwise. 1343191783Srmacklem */ 1344191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) 1345191783Srmacklem nmp->nm_maxfilesize = 0xffffffffLL; 1346191783Srmacklem else 1347221537Srmacklem nmp->nm_maxfilesize = OFF_MAX; 1348191783Srmacklem 1349191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 1350191783Srmacklem nmp->nm_wsize = NFS_WSIZE; 1351191783Srmacklem nmp->nm_rsize = NFS_RSIZE; 1352191783Srmacklem nmp->nm_readdirsize = NFS_READDIRSIZE; 1353191783Srmacklem } 1354191783Srmacklem nmp->nm_numgrps = NFS_MAXGRPS; 1355191783Srmacklem nmp->nm_tprintf_delay = nfs_tprintf_delay; 1356191783Srmacklem if (nmp->nm_tprintf_delay < 0) 1357191783Srmacklem nmp->nm_tprintf_delay = 0; 1358191783Srmacklem nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay; 1359191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1360191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1361191783Srmacklem nmp->nm_fhsize = argp->fhsize; 1362191783Srmacklem if (nmp->nm_fhsize > 0) 1363191783Srmacklem bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 1364191783Srmacklem bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 1365191783Srmacklem nmp->nm_nam = nam; 1366191783Srmacklem /* Set up the sockets and per-host congestion */ 1367191783Srmacklem nmp->nm_sotype = argp->sotype; 1368191783Srmacklem nmp->nm_soproto = argp->proto; 1369191783Srmacklem nmp->nm_sockreq.nr_prog = NFS_PROG; 1370191783Srmacklem if ((argp->flags & NFSMNT_NFSV4)) 1371191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER4; 1372191783Srmacklem else if ((argp->flags & NFSMNT_NFSV3)) 1373191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER3; 1374191783Srmacklem else 1375191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER2; 1376191783Srmacklem 1377191783Srmacklem 1378191783Srmacklem if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0))) 1379191783Srmacklem goto bad; 1380244042Srmacklem /* For NFSv4.1, get the clientid now. */ 1381244042Srmacklem if (nmp->nm_minorvers > 0) { 1382244042Srmacklem NFSCL_DEBUG(3, "at getcl\n"); 1383244042Srmacklem error = nfscl_getcl(mp, cred, td, 0, &clp); 1384244042Srmacklem NFSCL_DEBUG(3, "aft getcl=%d\n", error); 1385244042Srmacklem if (error != 0) 1386244042Srmacklem goto bad; 1387244042Srmacklem } 1388191783Srmacklem 1389191783Srmacklem if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) && 1390191783Srmacklem nmp->nm_dirpathlen > 0) { 1391244042Srmacklem NFSCL_DEBUG(3, "in dirp\n"); 1392191783Srmacklem /* 1393191783Srmacklem * If the fhsize on the mount point == 0 for V4, the mount 1394191783Srmacklem * path needs to be looked up. 1395191783Srmacklem */ 1396191783Srmacklem trycnt = 3; 1397191783Srmacklem do { 1398191783Srmacklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 1399191783Srmacklem cred, td); 1400244042Srmacklem NFSCL_DEBUG(3, "aft dirp=%d\n", error); 1401191783Srmacklem if (error) 1402207170Srmacklem (void) nfs_catnap(PZERO, error, "nfsgetdirp"); 1403191783Srmacklem } while (error && --trycnt > 0); 1404191783Srmacklem if (error) { 1405191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1406191783Srmacklem goto bad; 1407191783Srmacklem } 1408191783Srmacklem } 1409244042Srmacklem 1410244042Srmacklem /* 1411244042Srmacklem * A reference count is needed on the nfsnode representing the 1412244042Srmacklem * remote root. If this object is not persistent, then backward 1413244042Srmacklem * traversals of the mount point (i.e. "..") will not work if 1414244042Srmacklem * the nfsnode gets flushed out of the cache. Ufs does not have 1415244042Srmacklem * this problem, because one can identify root inodes by their 1416244042Srmacklem * number == ROOTINO (2). 1417244042Srmacklem */ 1418191783Srmacklem if (nmp->nm_fhsize > 0) { 1419195762Srmacklem /* 1420195762Srmacklem * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set 1421195762Srmacklem * non-zero for the root vnode. f_iosize will be set correctly 1422195762Srmacklem * by nfs_statfs() before any I/O occurs. 1423195762Srmacklem */ 1424195762Srmacklem mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ; 1425220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, 1426220732Srmacklem LK_EXCLUSIVE); 1427191783Srmacklem if (error) 1428191783Srmacklem goto bad; 1429191783Srmacklem *vpp = NFSTOV(np); 1430191783Srmacklem 1431191783Srmacklem /* 1432191783Srmacklem * Get file attributes and transfer parameters for the 1433191783Srmacklem * mountpoint. This has the side effect of filling in 1434191783Srmacklem * (*vpp)->v_type with the correct value. 1435191783Srmacklem */ 1436191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 1437244042Srmacklem cred, td, &nfsva, NULL, &lease); 1438191783Srmacklem if (ret) { 1439191783Srmacklem /* 1440191783Srmacklem * Just set default values to get things going. 1441191783Srmacklem */ 1442191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 1443191783Srmacklem nfsva.na_vattr.va_type = VDIR; 1444191783Srmacklem nfsva.na_vattr.va_mode = 0777; 1445191783Srmacklem nfsva.na_vattr.va_nlink = 100; 1446191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 1447191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 1448191783Srmacklem nfsva.na_vattr.va_fileid = 2; 1449191783Srmacklem nfsva.na_vattr.va_gen = 1; 1450191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 1451191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 1452244042Srmacklem lease = 60; 1453191783Srmacklem } 1454191783Srmacklem (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1); 1455244042Srmacklem if (nmp->nm_minorvers > 0) { 1456244042Srmacklem NFSCL_DEBUG(3, "lease=%d\n", (int)lease); 1457244042Srmacklem NFSLOCKCLSTATE(); 1458244042Srmacklem clp->nfsc_renew = NFSCL_RENEW(lease); 1459244042Srmacklem clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew; 1460244042Srmacklem clp->nfsc_clientidrev++; 1461244042Srmacklem if (clp->nfsc_clientidrev == 0) 1462244042Srmacklem clp->nfsc_clientidrev++; 1463244042Srmacklem NFSUNLOCKCLSTATE(); 1464244042Srmacklem /* 1465244042Srmacklem * Mount will succeed, so the renew thread can be 1466244042Srmacklem * started now. 1467244042Srmacklem */ 1468244042Srmacklem nfscl_start_renewthread(clp); 1469244042Srmacklem nfscl_clientrelease(clp); 1470244042Srmacklem } 1471191783Srmacklem if (argp->flags & NFSMNT_NFSV3) 1472191783Srmacklem ncl_fsinfo(nmp, *vpp, cred, td); 1473191783Srmacklem 1474222233Srmacklem /* Mark if the mount point supports NFSv4 ACLs. */ 1475222233Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 && 1476222233Srmacklem ret == 0 && 1477222233Srmacklem NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) { 1478222233Srmacklem MNT_ILOCK(mp); 1479222233Srmacklem mp->mnt_flag |= MNT_NFS4ACLS; 1480222233Srmacklem MNT_IUNLOCK(mp); 1481222233Srmacklem } 1482222233Srmacklem 1483191783Srmacklem /* 1484191783Srmacklem * Lose the lock but keep the ref. 1485191783Srmacklem */ 1486224082Szack NFSVOPUNLOCK(*vpp, 0); 1487191783Srmacklem return (0); 1488191783Srmacklem } 1489191783Srmacklem error = EIO; 1490191783Srmacklem 1491191783Srmacklembad: 1492244042Srmacklem if (clp != NULL) 1493244042Srmacklem nfscl_clientrelease(clp); 1494191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1495191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1496253049Srmacklem if (nmp->nm_sockreq.nr_auth != NULL) 1497253049Srmacklem AUTH_DESTROY(nmp->nm_sockreq.nr_auth); 1498191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1499191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1500244042Srmacklem if (nmp->nm_clp != NULL) { 1501244042Srmacklem NFSLOCKCLSTATE(); 1502244042Srmacklem LIST_REMOVE(nmp->nm_clp, nfsc_list); 1503244042Srmacklem NFSUNLOCKCLSTATE(); 1504244042Srmacklem free(nmp->nm_clp, M_NFSCLCLIENT); 1505244042Srmacklem } 1506244042Srmacklem TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) 1507244042Srmacklem nfscl_freenfsclds(dsp); 1508191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1509191783Srmacklem FREE(nam, M_SONAME); 1510191783Srmacklem return (error); 1511191783Srmacklem} 1512191783Srmacklem 1513191783Srmacklem/* 1514191783Srmacklem * unmount system call 1515191783Srmacklem */ 1516191783Srmacklemstatic int 1517191990Sattilionfs_unmount(struct mount *mp, int mntflags) 1518191783Srmacklem{ 1519191990Sattilio struct thread *td; 1520191783Srmacklem struct nfsmount *nmp; 1521249630Srmacklem int error, flags = 0, i, trycnt = 0; 1522244042Srmacklem struct nfsclds *dsp, *tdsp; 1523191783Srmacklem 1524191990Sattilio td = curthread; 1525191990Sattilio 1526191783Srmacklem if (mntflags & MNT_FORCE) 1527191783Srmacklem flags |= FORCECLOSE; 1528191783Srmacklem nmp = VFSTONFS(mp); 1529191783Srmacklem /* 1530191783Srmacklem * Goes something like this.. 1531191783Srmacklem * - Call vflush() to clear out vnodes for this filesystem 1532191783Srmacklem * - Close the socket 1533191783Srmacklem * - Free up the data structures 1534191783Srmacklem */ 1535191783Srmacklem /* In the forced case, cancel any outstanding requests. */ 1536191783Srmacklem if (mntflags & MNT_FORCE) { 1537191783Srmacklem error = newnfs_nmcancelreqs(nmp); 1538191783Srmacklem if (error) 1539191783Srmacklem goto out; 1540191783Srmacklem /* For a forced close, get rid of the renew thread now */ 1541191783Srmacklem nfscl_umount(nmp, td); 1542191783Srmacklem } 1543191783Srmacklem /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ 1544191783Srmacklem do { 1545191783Srmacklem error = vflush(mp, 1, flags, td); 1546191783Srmacklem if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30) 1547207170Srmacklem (void) nfs_catnap(PSOCK, error, "newndm"); 1548191783Srmacklem } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30); 1549191783Srmacklem if (error) 1550191783Srmacklem goto out; 1551191783Srmacklem 1552191783Srmacklem /* 1553191783Srmacklem * We are now committed to the unmount. 1554191783Srmacklem */ 1555191783Srmacklem if ((mntflags & MNT_FORCE) == 0) 1556191783Srmacklem nfscl_umount(nmp, td); 1557249630Srmacklem /* Make sure no nfsiods are assigned to this mount. */ 1558249630Srmacklem mtx_lock(&ncl_iod_mutex); 1559249630Srmacklem for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 1560249630Srmacklem if (ncl_iodmount[i] == nmp) { 1561249630Srmacklem ncl_iodwant[i] = NFSIOD_AVAILABLE; 1562249630Srmacklem ncl_iodmount[i] = NULL; 1563249630Srmacklem } 1564249630Srmacklem mtx_unlock(&ncl_iod_mutex); 1565191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1566191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1567191783Srmacklem FREE(nmp->nm_nam, M_SONAME); 1568253049Srmacklem if (nmp->nm_sockreq.nr_auth != NULL) 1569253049Srmacklem AUTH_DESTROY(nmp->nm_sockreq.nr_auth); 1570191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1571191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1572244042Srmacklem TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) 1573244042Srmacklem nfscl_freenfsclds(dsp); 1574191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1575191783Srmacklemout: 1576191783Srmacklem return (error); 1577191783Srmacklem} 1578191783Srmacklem 1579191783Srmacklem/* 1580191783Srmacklem * Return root of a filesystem 1581191783Srmacklem */ 1582191783Srmacklemstatic int 1583191990Sattilionfs_root(struct mount *mp, int flags, struct vnode **vpp) 1584191783Srmacklem{ 1585191783Srmacklem struct vnode *vp; 1586191783Srmacklem struct nfsmount *nmp; 1587191783Srmacklem struct nfsnode *np; 1588191783Srmacklem int error; 1589191783Srmacklem 1590191783Srmacklem nmp = VFSTONFS(mp); 1591220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags); 1592191783Srmacklem if (error) 1593191783Srmacklem return error; 1594191783Srmacklem vp = NFSTOV(np); 1595191783Srmacklem /* 1596191783Srmacklem * Get transfer parameters and attributes for root vnode once. 1597191783Srmacklem */ 1598191783Srmacklem mtx_lock(&nmp->nm_mtx); 1599191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 1600191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1601191783Srmacklem ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread); 1602191783Srmacklem } else 1603191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1604191783Srmacklem if (vp->v_type == VNON) 1605191783Srmacklem vp->v_type = VDIR; 1606191783Srmacklem vp->v_vflag |= VV_ROOT; 1607191783Srmacklem *vpp = vp; 1608191783Srmacklem return (0); 1609191783Srmacklem} 1610191783Srmacklem 1611191783Srmacklem/* 1612191783Srmacklem * Flush out the buffer cache 1613191783Srmacklem */ 1614191783Srmacklem/* ARGSUSED */ 1615191783Srmacklemstatic int 1616191990Sattilionfs_sync(struct mount *mp, int waitfor) 1617191783Srmacklem{ 1618191783Srmacklem struct vnode *vp, *mvp; 1619191990Sattilio struct thread *td; 1620191783Srmacklem int error, allerror = 0; 1621191783Srmacklem 1622191990Sattilio td = curthread; 1623191990Sattilio 1624222329Srmacklem MNT_ILOCK(mp); 1625191783Srmacklem /* 1626222329Srmacklem * If a forced dismount is in progress, return from here so that 1627222329Srmacklem * the umount(2) syscall doesn't get stuck in VFS_SYNC() before 1628222329Srmacklem * calling VFS_UNMOUNT(). 1629222329Srmacklem */ 1630222329Srmacklem if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1631222329Srmacklem MNT_IUNLOCK(mp); 1632222329Srmacklem return (EBADF); 1633222329Srmacklem } 1634234386Smckusick MNT_IUNLOCK(mp); 1635222329Srmacklem 1636222329Srmacklem /* 1637191783Srmacklem * Force stale buffer cache information to be flushed. 1638191783Srmacklem */ 1639191783Srmacklemloop: 1640234386Smckusick MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { 1641191783Srmacklem /* XXX Racy bv_cnt check. */ 1642224083Szack if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1643191783Srmacklem waitfor == MNT_LAZY) { 1644191783Srmacklem VI_UNLOCK(vp); 1645191783Srmacklem continue; 1646191783Srmacklem } 1647191783Srmacklem if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 1648234386Smckusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 1649191783Srmacklem goto loop; 1650191783Srmacklem } 1651191783Srmacklem error = VOP_FSYNC(vp, waitfor, td); 1652191783Srmacklem if (error) 1653191783Srmacklem allerror = error; 1654224082Szack NFSVOPUNLOCK(vp, 0); 1655191783Srmacklem vrele(vp); 1656191783Srmacklem } 1657191783Srmacklem return (allerror); 1658191783Srmacklem} 1659191783Srmacklem 1660191783Srmacklemstatic int 1661191783Srmacklemnfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 1662191783Srmacklem{ 1663191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1664191783Srmacklem struct vfsquery vq; 1665191783Srmacklem int error; 1666191783Srmacklem 1667191783Srmacklem bzero(&vq, sizeof(vq)); 1668191783Srmacklem switch (op) { 1669191783Srmacklem#if 0 1670191783Srmacklem case VFS_CTL_NOLOCKS: 1671191783Srmacklem val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; 1672191783Srmacklem if (req->oldptr != NULL) { 1673191783Srmacklem error = SYSCTL_OUT(req, &val, sizeof(val)); 1674191783Srmacklem if (error) 1675191783Srmacklem return (error); 1676191783Srmacklem } 1677191783Srmacklem if (req->newptr != NULL) { 1678191783Srmacklem error = SYSCTL_IN(req, &val, sizeof(val)); 1679191783Srmacklem if (error) 1680191783Srmacklem return (error); 1681191783Srmacklem if (val) 1682191783Srmacklem nmp->nm_flag |= NFSMNT_NOLOCKS; 1683191783Srmacklem else 1684191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOLOCKS; 1685191783Srmacklem } 1686191783Srmacklem break; 1687191783Srmacklem#endif 1688191783Srmacklem case VFS_CTL_QUERY: 1689191783Srmacklem mtx_lock(&nmp->nm_mtx); 1690191783Srmacklem if (nmp->nm_state & NFSSTA_TIMEO) 1691191783Srmacklem vq.vq_flags |= VQ_NOTRESP; 1692191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1693191783Srmacklem#if 0 1694191783Srmacklem if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && 1695191783Srmacklem (nmp->nm_state & NFSSTA_LOCKTIMEO)) 1696191783Srmacklem vq.vq_flags |= VQ_NOTRESPLOCK; 1697191783Srmacklem#endif 1698191783Srmacklem error = SYSCTL_OUT(req, &vq, sizeof(vq)); 1699191783Srmacklem break; 1700191783Srmacklem case VFS_CTL_TIMEO: 1701191783Srmacklem if (req->oldptr != NULL) { 1702191783Srmacklem error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, 1703191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1704191783Srmacklem if (error) 1705191783Srmacklem return (error); 1706191783Srmacklem } 1707191783Srmacklem if (req->newptr != NULL) { 1708191783Srmacklem error = vfs_suser(mp, req->td); 1709191783Srmacklem if (error) 1710191783Srmacklem return (error); 1711191783Srmacklem error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, 1712191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1713191783Srmacklem if (error) 1714191783Srmacklem return (error); 1715191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1716191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1717191783Srmacklem } 1718191783Srmacklem break; 1719191783Srmacklem default: 1720191783Srmacklem return (ENOTSUP); 1721191783Srmacklem } 1722191783Srmacklem return (0); 1723191783Srmacklem} 1724191783Srmacklem 1725214048Srmacklem/* 1726255136Srmacklem * Purge any RPCs in progress, so that they will all return errors. 1727255136Srmacklem * This allows dounmount() to continue as far as VFS_UNMOUNT() for a 1728255136Srmacklem * forced dismount. 1729255136Srmacklem */ 1730255136Srmacklemstatic void 1731255136Srmacklemnfs_purge(struct mount *mp) 1732255136Srmacklem{ 1733255136Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1734255136Srmacklem 1735255136Srmacklem newnfs_nmcancelreqs(nmp); 1736255136Srmacklem} 1737255136Srmacklem 1738255136Srmacklem/* 1739214048Srmacklem * Extract the information needed by the nlm from the nfs vnode. 1740214048Srmacklem */ 1741214048Srmacklemstatic void 1742214053Srmacklemnfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp, 1743216931Srmacklem struct sockaddr_storage *sp, int *is_v3p, off_t *sizep, 1744216931Srmacklem struct timeval *timeop) 1745214048Srmacklem{ 1746214048Srmacklem struct nfsmount *nmp; 1747214048Srmacklem struct nfsnode *np = VTONFS(vp); 1748214048Srmacklem 1749214048Srmacklem nmp = VFSTONFS(vp->v_mount); 1750214048Srmacklem if (fhlenp != NULL) 1751214053Srmacklem *fhlenp = (size_t)np->n_fhp->nfh_len; 1752214048Srmacklem if (fhp != NULL) 1753214048Srmacklem bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len); 1754214048Srmacklem if (sp != NULL) 1755214048Srmacklem bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp))); 1756214048Srmacklem if (is_v3p != NULL) 1757214048Srmacklem *is_v3p = NFS_ISV3(vp); 1758214048Srmacklem if (sizep != NULL) 1759214048Srmacklem *sizep = np->n_size; 1760216931Srmacklem if (timeop != NULL) { 1761216931Srmacklem timeop->tv_sec = nmp->nm_timeo / NFS_HZ; 1762216931Srmacklem timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ); 1763216931Srmacklem } 1764214048Srmacklem} 1765214048Srmacklem 1766243782Srmacklem/* 1767243782Srmacklem * This function prints out an option name, based on the conditional 1768243782Srmacklem * argument. 1769243782Srmacklem */ 1770243782Srmacklemstatic __inline void nfscl_printopt(struct nfsmount *nmp, int testval, 1771243782Srmacklem char *opt, char **buf, size_t *blen) 1772243782Srmacklem{ 1773243782Srmacklem int len; 1774243782Srmacklem 1775243782Srmacklem if (testval != 0 && *blen > strlen(opt)) { 1776243782Srmacklem len = snprintf(*buf, *blen, "%s", opt); 1777243782Srmacklem if (len != strlen(opt)) 1778243782Srmacklem printf("EEK!!\n"); 1779243782Srmacklem *buf += len; 1780243782Srmacklem *blen -= len; 1781243782Srmacklem } 1782243782Srmacklem} 1783243782Srmacklem 1784243782Srmacklem/* 1785243782Srmacklem * This function printf out an options integer value. 1786243782Srmacklem */ 1787243782Srmacklemstatic __inline void nfscl_printoptval(struct nfsmount *nmp, int optval, 1788243782Srmacklem char *opt, char **buf, size_t *blen) 1789243782Srmacklem{ 1790243782Srmacklem int len; 1791243782Srmacklem 1792243782Srmacklem if (*blen > strlen(opt) + 1) { 1793243782Srmacklem /* Could result in truncated output string. */ 1794243782Srmacklem len = snprintf(*buf, *blen, "%s=%d", opt, optval); 1795243782Srmacklem if (len < *blen) { 1796243782Srmacklem *buf += len; 1797243782Srmacklem *blen -= len; 1798243782Srmacklem } 1799243782Srmacklem } 1800243782Srmacklem} 1801243782Srmacklem 1802243782Srmacklem/* 1803243782Srmacklem * Load the option flags and values into the buffer. 1804243782Srmacklem */ 1805243782Srmacklemvoid nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen) 1806243782Srmacklem{ 1807243782Srmacklem char *buf; 1808243782Srmacklem size_t blen; 1809243782Srmacklem 1810243782Srmacklem buf = buffer; 1811243782Srmacklem blen = buflen; 1812243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV4) != 0, "nfsv4", &buf, 1813243782Srmacklem &blen); 1814244056Srmacklem if ((nmp->nm_flag & NFSMNT_NFSV4) != 0) { 1815244056Srmacklem nfscl_printoptval(nmp, nmp->nm_minorvers, ",minorversion", &buf, 1816244056Srmacklem &blen); 1817244056Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_PNFS) != 0, ",pnfs", 1818244056Srmacklem &buf, &blen); 1819244056Srmacklem } 1820243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV3) != 0, "nfsv3", &buf, 1821243782Srmacklem &blen); 1822243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0, 1823243782Srmacklem "nfsv2", &buf, &blen); 1824243782Srmacklem nfscl_printopt(nmp, nmp->nm_sotype == SOCK_STREAM, ",tcp", &buf, &blen); 1825243782Srmacklem nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen); 1826243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport", 1827243782Srmacklem &buf, &blen); 1828243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn", 1829243782Srmacklem &buf, &blen); 1830243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf, 1831243782Srmacklem &blen); 1832243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) != 0, ",soft", &buf, 1833243782Srmacklem &blen); 1834243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_INT) != 0, ",intr", &buf, 1835243782Srmacklem &blen); 1836243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) == 0, ",cto", &buf, 1837243782Srmacklem &blen); 1838243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf, 1839243782Srmacklem &blen); 1840260107Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NONCONTIGWR) != 0, 1841260107Srmacklem ",noncontigwr", &buf, &blen); 1842243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) == 1843243782Srmacklem 0, ",lockd", &buf, &blen); 1844243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) == 1845243782Srmacklem NFSMNT_NOLOCKD, ",nolockd", &buf, &blen); 1846243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RDIRPLUS) != 0, ",rdirplus", 1847243782Srmacklem &buf, &blen); 1848243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_KERB) == 0, ",sec=sys", 1849243782Srmacklem &buf, &blen); 1850243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY | 1851243782Srmacklem NFSMNT_PRIVACY)) == NFSMNT_KERB, ",sec=krb5", &buf, &blen); 1852243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY | 1853243782Srmacklem NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_INTEGRITY), ",sec=krb5i", 1854243782Srmacklem &buf, &blen); 1855243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY | 1856243782Srmacklem NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_PRIVACY), ",sec=krb5p", 1857243782Srmacklem &buf, &blen); 1858243782Srmacklem nfscl_printoptval(nmp, nmp->nm_acdirmin, ",acdirmin", &buf, &blen); 1859243782Srmacklem nfscl_printoptval(nmp, nmp->nm_acdirmax, ",acdirmax", &buf, &blen); 1860243782Srmacklem nfscl_printoptval(nmp, nmp->nm_acregmin, ",acregmin", &buf, &blen); 1861243782Srmacklem nfscl_printoptval(nmp, nmp->nm_acregmax, ",acregmax", &buf, &blen); 1862243782Srmacklem nfscl_printoptval(nmp, nmp->nm_nametimeo, ",nametimeo", &buf, &blen); 1863243782Srmacklem nfscl_printoptval(nmp, nmp->nm_negnametimeo, ",negnametimeo", &buf, 1864243782Srmacklem &blen); 1865243782Srmacklem nfscl_printoptval(nmp, nmp->nm_rsize, ",rsize", &buf, &blen); 1866243782Srmacklem nfscl_printoptval(nmp, nmp->nm_wsize, ",wsize", &buf, &blen); 1867243782Srmacklem nfscl_printoptval(nmp, nmp->nm_readdirsize, ",readdirsize", &buf, 1868243782Srmacklem &blen); 1869243782Srmacklem nfscl_printoptval(nmp, nmp->nm_readahead, ",readahead", &buf, &blen); 1870243782Srmacklem nfscl_printoptval(nmp, nmp->nm_wcommitsize, ",wcommitsize", &buf, 1871243782Srmacklem &blen); 1872243782Srmacklem nfscl_printoptval(nmp, nmp->nm_timeo, ",timeout", &buf, &blen); 1873243782Srmacklem nfscl_printoptval(nmp, nmp->nm_retry, ",retrans", &buf, &blen); 1874243782Srmacklem} 1875243782Srmacklem 1876