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.3/sys/fs/nfsclient/nfs_clvfsops.c 291551 2015-12-01 02:30:41Z 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 214291551Srmacklem * space. It must also be at least NFS_DIRBLKSIZ, since 215291551Srmacklem * that is the buffer size used for directories. 216191783Srmacklem */ 217191783Srmacklem iosize = imax(nmp->nm_rsize, nmp->nm_wsize); 218191783Srmacklem iosize = imax(iosize, PAGE_SIZE); 219291551Srmacklem iosize = imax(iosize, NFS_DIRBLKSIZ); 220191783Srmacklem nmp->nm_mountp->mnt_stat.f_iosize = iosize; 221191783Srmacklem return (iosize); 222191783Srmacklem} 223191783Srmacklem 224191783Srmacklemstatic void 225191783Srmacklemnfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs) 226191783Srmacklem{ 227191783Srmacklem 228191783Srmacklem args->version = NFS_ARGSVERSION; 229191783Srmacklem args->addr = oargs->addr; 230191783Srmacklem args->addrlen = oargs->addrlen; 231191783Srmacklem args->sotype = oargs->sotype; 232191783Srmacklem args->proto = oargs->proto; 233191783Srmacklem args->fh = oargs->fh; 234191783Srmacklem args->fhsize = oargs->fhsize; 235191783Srmacklem args->flags = oargs->flags; 236191783Srmacklem args->wsize = oargs->wsize; 237191783Srmacklem args->rsize = oargs->rsize; 238191783Srmacklem args->readdirsize = oargs->readdirsize; 239191783Srmacklem args->timeo = oargs->timeo; 240191783Srmacklem args->retrans = oargs->retrans; 241191783Srmacklem args->readahead = oargs->readahead; 242191783Srmacklem args->hostname = oargs->hostname; 243191783Srmacklem} 244191783Srmacklem 245191783Srmacklemstatic void 246191783Srmacklemnfs_convert_diskless(void) 247191783Srmacklem{ 248191783Srmacklem 249221040Srmacklem bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif, 250221040Srmacklem sizeof(struct ifaliasreq)); 251221040Srmacklem bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway, 252221040Srmacklem sizeof(struct sockaddr_in)); 253221040Srmacklem nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args); 254221040Srmacklem if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) { 255221040Srmacklem nfsv3_diskless.root_fhsize = NFSX_MYFH; 256221040Srmacklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH); 257191783Srmacklem } else { 258221040Srmacklem nfsv3_diskless.root_fhsize = NFSX_V2FH; 259221040Srmacklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH); 260191783Srmacklem } 261221040Srmacklem bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr, 262221040Srmacklem sizeof(struct sockaddr_in)); 263221040Srmacklem bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN); 264221040Srmacklem nfsv3_diskless.root_time = nfs_diskless.root_time; 265221040Srmacklem bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam, 266221040Srmacklem MAXHOSTNAMELEN); 267221040Srmacklem nfs_diskless_valid = 3; 268191783Srmacklem} 269191783Srmacklem 270191783Srmacklem/* 271191783Srmacklem * nfs statfs call 272191783Srmacklem */ 273191783Srmacklemstatic int 274191990Sattilionfs_statfs(struct mount *mp, struct statfs *sbp) 275191783Srmacklem{ 276191783Srmacklem struct vnode *vp; 277191990Sattilio struct thread *td; 278191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 279191783Srmacklem struct nfsvattr nfsva; 280191783Srmacklem struct nfsfsinfo fs; 281191783Srmacklem struct nfsstatfs sb; 282191783Srmacklem int error = 0, attrflag, gotfsinfo = 0, ret; 283191783Srmacklem struct nfsnode *np; 284191783Srmacklem 285191990Sattilio td = curthread; 286191990Sattilio 287191783Srmacklem error = vfs_busy(mp, MBF_NOWAIT); 288191783Srmacklem if (error) 289191783Srmacklem return (error); 290220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE); 291191783Srmacklem if (error) { 292191783Srmacklem vfs_unbusy(mp); 293191783Srmacklem return (error); 294191783Srmacklem } 295191783Srmacklem vp = NFSTOV(np); 296191783Srmacklem mtx_lock(&nmp->nm_mtx); 297191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 298191783Srmacklem mtx_unlock(&nmp->nm_mtx); 299191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva, 300191783Srmacklem &attrflag, NULL); 301191783Srmacklem if (!error) 302191783Srmacklem gotfsinfo = 1; 303191783Srmacklem } else 304191783Srmacklem mtx_unlock(&nmp->nm_mtx); 305191783Srmacklem if (!error) 306191783Srmacklem error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, 307191783Srmacklem &attrflag, NULL); 308244042Srmacklem if (error != 0) 309244042Srmacklem NFSCL_DEBUG(2, "statfs=%d\n", error); 310191783Srmacklem if (attrflag == 0) { 311191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 312244042Srmacklem td->td_ucred, td, &nfsva, NULL, NULL); 313191783Srmacklem if (ret) { 314191783Srmacklem /* 315191783Srmacklem * Just set default values to get things going. 316191783Srmacklem */ 317191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 318191783Srmacklem nfsva.na_vattr.va_type = VDIR; 319191783Srmacklem nfsva.na_vattr.va_mode = 0777; 320191783Srmacklem nfsva.na_vattr.va_nlink = 100; 321191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 322191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 323191783Srmacklem nfsva.na_vattr.va_fileid = 2; 324191783Srmacklem nfsva.na_vattr.va_gen = 1; 325191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 326191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 327191783Srmacklem } 328191783Srmacklem } 329191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 330191783Srmacklem if (!error) { 331191783Srmacklem mtx_lock(&nmp->nm_mtx); 332191783Srmacklem if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4)) 333191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 334191783Srmacklem nfscl_loadsbinfo(nmp, &sb, sbp); 335191783Srmacklem sbp->f_iosize = newnfs_iosize(nmp); 336191783Srmacklem mtx_unlock(&nmp->nm_mtx); 337191783Srmacklem if (sbp != &mp->mnt_stat) { 338191783Srmacklem bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 339191783Srmacklem bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 340191783Srmacklem } 341191783Srmacklem strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 342191783Srmacklem } else if (NFS_ISV4(vp)) { 343191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 344191783Srmacklem } 345191783Srmacklem vput(vp); 346191783Srmacklem vfs_unbusy(mp); 347191783Srmacklem return (error); 348191783Srmacklem} 349191783Srmacklem 350191783Srmacklem/* 351191783Srmacklem * nfs version 3 fsinfo rpc call 352191783Srmacklem */ 353191783Srmacklemint 354191783Srmacklemncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, 355191783Srmacklem struct thread *td) 356191783Srmacklem{ 357191783Srmacklem struct nfsfsinfo fs; 358191783Srmacklem struct nfsvattr nfsva; 359191783Srmacklem int error, attrflag; 360191783Srmacklem 361191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL); 362191783Srmacklem if (!error) { 363191783Srmacklem if (attrflag) 364191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 365191783Srmacklem 1); 366191783Srmacklem mtx_lock(&nmp->nm_mtx); 367191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 368191783Srmacklem mtx_unlock(&nmp->nm_mtx); 369191783Srmacklem } 370191783Srmacklem return (error); 371191783Srmacklem} 372191783Srmacklem 373191783Srmacklem/* 374191783Srmacklem * Mount a remote root fs via. nfs. This depends on the info in the 375221040Srmacklem * nfs_diskless structure that has been filled in properly by some primary 376191783Srmacklem * bootstrap. 377191783Srmacklem * It goes something like this: 378191783Srmacklem * - do enough of "ifconfig" by calling ifioctl() so that the system 379191783Srmacklem * can talk to the server 380221040Srmacklem * - If nfs_diskless.mygateway is filled in, use that address as 381191783Srmacklem * a default gateway. 382191783Srmacklem * - build the rootfs mount point and call mountnfs() to do the rest. 383191783Srmacklem * 384191783Srmacklem * It is assumed to be safe to read, modify, and write the nfsv3_diskless 385191783Srmacklem * structure, as well as other global NFS client variables here, as 386192145Srmacklem * nfs_mountroot() will be called once in the boot before any other NFS 387191783Srmacklem * client activity occurs. 388191783Srmacklem */ 389221040Srmacklemstatic int 390221040Srmacklemnfs_mountroot(struct mount *mp) 391191783Srmacklem{ 392192145Srmacklem struct thread *td = curthread; 393221040Srmacklem struct nfsv3_diskless *nd = &nfsv3_diskless; 394191783Srmacklem struct socket *so; 395191783Srmacklem struct vnode *vp; 396191783Srmacklem struct ifreq ir; 397193066Sjamie int error; 398191783Srmacklem u_long l; 399191783Srmacklem char buf[128]; 400191783Srmacklem char *cp; 401191783Srmacklem 402191783Srmacklem#if defined(BOOTP_NFSROOT) && defined(BOOTP) 403192145Srmacklem bootpc_init(); /* use bootp to get nfs_diskless filled in */ 404191783Srmacklem#elif defined(NFS_ROOT) 405191783Srmacklem nfs_setup_diskless(); 406191783Srmacklem#endif 407191783Srmacklem 408221040Srmacklem if (nfs_diskless_valid == 0) 409191783Srmacklem return (-1); 410221040Srmacklem if (nfs_diskless_valid == 1) 411191783Srmacklem nfs_convert_diskless(); 412191783Srmacklem 413191783Srmacklem /* 414191783Srmacklem * XXX splnet, so networks will receive... 415191783Srmacklem */ 416191783Srmacklem splnet(); 417191783Srmacklem 418191783Srmacklem /* 419191783Srmacklem * Do enough of ifconfig(8) so that the critical net interface can 420191783Srmacklem * talk to the server. 421191783Srmacklem */ 422191783Srmacklem error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0, 423191783Srmacklem td->td_ucred, td); 424191783Srmacklem if (error) 425192145Srmacklem panic("nfs_mountroot: socreate(%04x): %d", 426191783Srmacklem nd->myif.ifra_addr.sa_family, error); 427191783Srmacklem 428191783Srmacklem#if 0 /* XXX Bad idea */ 429191783Srmacklem /* 430191783Srmacklem * We might not have been told the right interface, so we pass 431191783Srmacklem * over the first ten interfaces of the same kind, until we get 432191783Srmacklem * one of them configured. 433191783Srmacklem */ 434191783Srmacklem 435191783Srmacklem for (i = strlen(nd->myif.ifra_name) - 1; 436191783Srmacklem nd->myif.ifra_name[i] >= '0' && 437191783Srmacklem nd->myif.ifra_name[i] <= '9'; 438191783Srmacklem nd->myif.ifra_name[i] ++) { 439191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 440191783Srmacklem if(!error) 441191783Srmacklem break; 442191783Srmacklem } 443191783Srmacklem#endif 444191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 445191783Srmacklem if (error) 446192145Srmacklem panic("nfs_mountroot: SIOCAIFADDR: %d", error); 447191783Srmacklem if ((cp = getenv("boot.netif.mtu")) != NULL) { 448191783Srmacklem ir.ifr_mtu = strtol(cp, NULL, 10); 449191783Srmacklem bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); 450191783Srmacklem freeenv(cp); 451191783Srmacklem error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); 452191783Srmacklem if (error) 453192145Srmacklem printf("nfs_mountroot: SIOCSIFMTU: %d", error); 454191783Srmacklem } 455191783Srmacklem soclose(so); 456191783Srmacklem 457191783Srmacklem /* 458191783Srmacklem * If the gateway field is filled in, set it as the default route. 459191783Srmacklem * Note that pxeboot will set a default route of 0 if the route 460191783Srmacklem * is not set by the DHCP server. Check also for a value of 0 461191783Srmacklem * to avoid panicking inappropriately in that situation. 462191783Srmacklem */ 463191783Srmacklem if (nd->mygateway.sin_len != 0 && 464191783Srmacklem nd->mygateway.sin_addr.s_addr != 0) { 465191783Srmacklem struct sockaddr_in mask, sin; 466191783Srmacklem 467191783Srmacklem bzero((caddr_t)&mask, sizeof(mask)); 468191783Srmacklem sin = mask; 469191783Srmacklem sin.sin_family = AF_INET; 470191783Srmacklem sin.sin_len = sizeof(sin); 471192145Srmacklem /* XXX MRT use table 0 for this sort of thing */ 472218757Sbz CURVNET_SET(TD_TO_VNET(td)); 473231852Sbz error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin, 474191783Srmacklem (struct sockaddr *)&nd->mygateway, 475191783Srmacklem (struct sockaddr *)&mask, 476231852Sbz RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB); 477218757Sbz CURVNET_RESTORE(); 478191783Srmacklem if (error) 479192145Srmacklem panic("nfs_mountroot: RTM_ADD: %d", error); 480191783Srmacklem } 481191783Srmacklem 482191783Srmacklem /* 483191783Srmacklem * Create the rootfs mount point. 484191783Srmacklem */ 485191783Srmacklem nd->root_args.fh = nd->root_fh; 486191783Srmacklem nd->root_args.fhsize = nd->root_fhsize; 487191783Srmacklem l = ntohl(nd->root_saddr.sin_addr.s_addr); 488191783Srmacklem snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", 489191783Srmacklem (l >> 24) & 0xff, (l >> 16) & 0xff, 490191783Srmacklem (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); 491191783Srmacklem printf("NFS ROOT: %s\n", buf); 492192145Srmacklem nd->root_args.hostname = buf; 493191783Srmacklem if ((error = nfs_mountdiskless(buf, 494191783Srmacklem &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { 495191783Srmacklem return (error); 496191783Srmacklem } 497191783Srmacklem 498191783Srmacklem /* 499191783Srmacklem * This is not really an nfs issue, but it is much easier to 500191783Srmacklem * set hostname here and then let the "/etc/rc.xxx" files 501191783Srmacklem * mount the right /var based upon its preset value. 502191783Srmacklem */ 503193066Sjamie mtx_lock(&prison0.pr_mtx); 504194118Sjamie strlcpy(prison0.pr_hostname, nd->my_hostnam, 505194118Sjamie sizeof(prison0.pr_hostname)); 506193066Sjamie mtx_unlock(&prison0.pr_mtx); 507191783Srmacklem inittodr(ntohl(nd->root_time)); 508191783Srmacklem return (0); 509191783Srmacklem} 510191783Srmacklem 511191783Srmacklem/* 512191783Srmacklem * Internal version of mount system call for diskless setup. 513191783Srmacklem */ 514191783Srmacklemstatic int 515191783Srmacklemnfs_mountdiskless(char *path, 516191783Srmacklem struct sockaddr_in *sin, struct nfs_args *args, struct thread *td, 517191783Srmacklem struct vnode **vpp, struct mount *mp) 518191783Srmacklem{ 519191783Srmacklem struct sockaddr *nam; 520221014Srmacklem int dirlen, error; 521221014Srmacklem char *dirpath; 522191783Srmacklem 523221014Srmacklem /* 524221014Srmacklem * Find the directory path in "path", which also has the server's 525221014Srmacklem * name/ip address in it. 526221014Srmacklem */ 527221014Srmacklem dirpath = strchr(path, ':'); 528221014Srmacklem if (dirpath != NULL) 529221014Srmacklem dirlen = strlen(++dirpath); 530221014Srmacklem else 531221014Srmacklem dirlen = 0; 532191783Srmacklem nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); 533221014Srmacklem if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen, 534230547Sjhb NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO, 535244042Srmacklem NFS_DEFAULT_NEGNAMETIMEO, 0)) != 0) { 536192145Srmacklem printf("nfs_mountroot: mount %s on /: %d\n", path, error); 537191783Srmacklem return (error); 538191783Srmacklem } 539191783Srmacklem return (0); 540191783Srmacklem} 541191783Srmacklem 542191783Srmacklemstatic void 543192585Srmacklemnfs_sec_name(char *sec, int *flagsp) 544192585Srmacklem{ 545192585Srmacklem if (!strcmp(sec, "krb5")) 546192585Srmacklem *flagsp |= NFSMNT_KERB; 547192585Srmacklem else if (!strcmp(sec, "krb5i")) 548192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY); 549192585Srmacklem else if (!strcmp(sec, "krb5p")) 550192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY); 551192585Srmacklem} 552192585Srmacklem 553192585Srmacklemstatic void 554191783Srmacklemnfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, 555214048Srmacklem const char *hostname, struct ucred *cred, struct thread *td) 556191783Srmacklem{ 557191783Srmacklem int s; 558191783Srmacklem int adjsock; 559214048Srmacklem char *p; 560191783Srmacklem 561191783Srmacklem s = splnet(); 562191783Srmacklem 563191783Srmacklem /* 564191783Srmacklem * Set read-only flag if requested; otherwise, clear it if this is 565191783Srmacklem * an update. If this is not an update, then either the read-only 566191783Srmacklem * flag is already clear, or this is a root mount and it was set 567191783Srmacklem * intentionally at some previous point. 568191783Srmacklem */ 569191783Srmacklem if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) { 570191783Srmacklem MNT_ILOCK(mp); 571191783Srmacklem mp->mnt_flag |= MNT_RDONLY; 572191783Srmacklem MNT_IUNLOCK(mp); 573191783Srmacklem } else if (mp->mnt_flag & MNT_UPDATE) { 574191783Srmacklem MNT_ILOCK(mp); 575191783Srmacklem mp->mnt_flag &= ~MNT_RDONLY; 576191783Srmacklem MNT_IUNLOCK(mp); 577191783Srmacklem } 578191783Srmacklem 579191783Srmacklem /* 580191783Srmacklem * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 581191783Srmacklem * no sense in that context. Also, set up appropriate retransmit 582191783Srmacklem * and soft timeout behavior. 583191783Srmacklem */ 584191783Srmacklem if (argp->sotype == SOCK_STREAM) { 585191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOCONN; 586191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 587220739Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0) 588220739Srmacklem nmp->nm_retry = INT_MAX; 589220739Srmacklem else 590220739Srmacklem nmp->nm_retry = NFS_RETRANS_TCP; 591191783Srmacklem } 592191783Srmacklem 593220739Srmacklem /* Also clear RDIRPLUS if NFSv2, it crashes some servers */ 594220739Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 595220739Srmacklem argp->flags &= ~NFSMNT_RDIRPLUS; 596191783Srmacklem nmp->nm_flag &= ~NFSMNT_RDIRPLUS; 597220739Srmacklem } 598191783Srmacklem 599220739Srmacklem /* Re-bind if rsrvd port requested and wasn't on one */ 600220739Srmacklem adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT) 601220739Srmacklem && (argp->flags & NFSMNT_RESVPORT); 602191783Srmacklem /* Also re-bind if we're switching to/from a connected UDP socket */ 603220739Srmacklem adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) != 604191783Srmacklem (argp->flags & NFSMNT_NOCONN)); 605191783Srmacklem 606191783Srmacklem /* Update flags atomically. Don't change the lock bits. */ 607191783Srmacklem nmp->nm_flag = argp->flags | nmp->nm_flag; 608191783Srmacklem splx(s); 609191783Srmacklem 610191783Srmacklem if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 611191783Srmacklem nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 612191783Srmacklem if (nmp->nm_timeo < NFS_MINTIMEO) 613191783Srmacklem nmp->nm_timeo = NFS_MINTIMEO; 614191783Srmacklem else if (nmp->nm_timeo > NFS_MAXTIMEO) 615191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 616191783Srmacklem } 617191783Srmacklem 618191783Srmacklem if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 619191783Srmacklem nmp->nm_retry = argp->retrans; 620191783Srmacklem if (nmp->nm_retry > NFS_MAXREXMIT) 621191783Srmacklem nmp->nm_retry = NFS_MAXREXMIT; 622191783Srmacklem } 623191783Srmacklem 624191783Srmacklem if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 625191783Srmacklem nmp->nm_wsize = argp->wsize; 626274150Srmacklem /* 627274150Srmacklem * Clip at the power of 2 below the size. There is an 628274150Srmacklem * issue (not isolated) that causes intermittent page 629274150Srmacklem * faults if this is not done. 630274150Srmacklem */ 631274150Srmacklem if (nmp->nm_wsize > NFS_FABLKSIZE) 632274150Srmacklem nmp->nm_wsize = 1 << (fls(nmp->nm_wsize) - 1); 633274150Srmacklem else 634191783Srmacklem nmp->nm_wsize = NFS_FABLKSIZE; 635191783Srmacklem } 636191783Srmacklem 637191783Srmacklem if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 638191783Srmacklem nmp->nm_rsize = argp->rsize; 639274150Srmacklem /* 640274150Srmacklem * Clip at the power of 2 below the size. There is an 641274150Srmacklem * issue (not isolated) that causes intermittent page 642274150Srmacklem * faults if this is not done. 643274150Srmacklem */ 644274150Srmacklem if (nmp->nm_rsize > NFS_FABLKSIZE) 645274150Srmacklem nmp->nm_rsize = 1 << (fls(nmp->nm_rsize) - 1); 646274150Srmacklem else 647191783Srmacklem nmp->nm_rsize = NFS_FABLKSIZE; 648191783Srmacklem } 649191783Srmacklem 650191783Srmacklem if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 651191783Srmacklem nmp->nm_readdirsize = argp->readdirsize; 652191783Srmacklem } 653191783Srmacklem 654191783Srmacklem if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) 655191783Srmacklem nmp->nm_acregmin = argp->acregmin; 656191783Srmacklem else 657191783Srmacklem nmp->nm_acregmin = NFS_MINATTRTIMO; 658191783Srmacklem if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) 659191783Srmacklem nmp->nm_acregmax = argp->acregmax; 660191783Srmacklem else 661191783Srmacklem nmp->nm_acregmax = NFS_MAXATTRTIMO; 662191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) 663191783Srmacklem nmp->nm_acdirmin = argp->acdirmin; 664191783Srmacklem else 665191783Srmacklem nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; 666191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) 667191783Srmacklem nmp->nm_acdirmax = argp->acdirmax; 668191783Srmacklem else 669191783Srmacklem nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; 670191783Srmacklem if (nmp->nm_acdirmin > nmp->nm_acdirmax) 671191783Srmacklem nmp->nm_acdirmin = nmp->nm_acdirmax; 672191783Srmacklem if (nmp->nm_acregmin > nmp->nm_acregmax) 673191783Srmacklem nmp->nm_acregmin = nmp->nm_acregmax; 674191783Srmacklem 675191783Srmacklem if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { 676191783Srmacklem if (argp->readahead <= NFS_MAXRAHEAD) 677191783Srmacklem nmp->nm_readahead = argp->readahead; 678191783Srmacklem else 679191783Srmacklem nmp->nm_readahead = NFS_MAXRAHEAD; 680191783Srmacklem } 681191783Srmacklem if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) { 682191783Srmacklem if (argp->wcommitsize < nmp->nm_wsize) 683191783Srmacklem nmp->nm_wcommitsize = nmp->nm_wsize; 684191783Srmacklem else 685191783Srmacklem nmp->nm_wcommitsize = argp->wcommitsize; 686191783Srmacklem } 687191783Srmacklem 688191783Srmacklem adjsock |= ((nmp->nm_sotype != argp->sotype) || 689191783Srmacklem (nmp->nm_soproto != argp->proto)); 690191783Srmacklem 691191783Srmacklem if (nmp->nm_client != NULL && adjsock) { 692191783Srmacklem int haslock = 0, error = 0; 693191783Srmacklem 694191783Srmacklem if (nmp->nm_sotype == SOCK_STREAM) { 695191783Srmacklem error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock); 696191783Srmacklem if (!error) 697191783Srmacklem haslock = 1; 698191783Srmacklem } 699191783Srmacklem if (!error) { 700191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 701191783Srmacklem if (haslock) 702191783Srmacklem newnfs_sndunlock(&nmp->nm_sockreq.nr_lock); 703191783Srmacklem nmp->nm_sotype = argp->sotype; 704191783Srmacklem nmp->nm_soproto = argp->proto; 705191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 706191783Srmacklem while (newnfs_connect(nmp, &nmp->nm_sockreq, 707191783Srmacklem cred, td, 0)) { 708191783Srmacklem printf("newnfs_args: retrying connect\n"); 709207170Srmacklem (void) nfs_catnap(PSOCK, 0, "newnfscon"); 710191783Srmacklem } 711191783Srmacklem } 712191783Srmacklem } else { 713191783Srmacklem nmp->nm_sotype = argp->sotype; 714191783Srmacklem nmp->nm_soproto = argp->proto; 715191783Srmacklem } 716214048Srmacklem 717214048Srmacklem if (hostname != NULL) { 718214048Srmacklem strlcpy(nmp->nm_hostname, hostname, 719214048Srmacklem sizeof(nmp->nm_hostname)); 720214048Srmacklem p = strchr(nmp->nm_hostname, ':'); 721214048Srmacklem if (p != NULL) 722214048Srmacklem *p = '\0'; 723214048Srmacklem } 724191783Srmacklem} 725191783Srmacklem 726221190Srmacklemstatic const char *nfs_opts[] = { "from", "nfs_args", 727275249Strasz "noac", "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union", 728191783Srmacklem "noclusterr", "noclusterw", "multilabel", "acls", "force", "update", 729192585Srmacklem "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus", 730192585Srmacklem "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize", 731275249Strasz "retrans", "actimeo", "acregmin", "acregmax", "acdirmin", "acdirmax", 732275249Strasz "resvport", "readahead", "hostname", "timeo", "timeout", "addr", "fh", 733275249Strasz "nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath", 734275249Strasz "minorversion", "nametimeo", "negnametimeo", "nocto", "noncontigwr", 735275249Strasz "pnfs", "wcommitsize", 736191783Srmacklem NULL }; 737191783Srmacklem 738191783Srmacklem/* 739191783Srmacklem * VFS Operations. 740191783Srmacklem * 741191783Srmacklem * mount system call 742191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 743191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 744191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 745191783Srmacklem * an error after that means that I have to release the mbuf. 746191783Srmacklem */ 747191783Srmacklem/* ARGSUSED */ 748191783Srmacklemstatic int 749191990Sattilionfs_mount(struct mount *mp) 750191783Srmacklem{ 751191783Srmacklem struct nfs_args args = { 752191783Srmacklem .version = NFS_ARGSVERSION, 753191783Srmacklem .addr = NULL, 754191783Srmacklem .addrlen = sizeof (struct sockaddr_in), 755191783Srmacklem .sotype = SOCK_STREAM, 756191783Srmacklem .proto = 0, 757191783Srmacklem .fh = NULL, 758191783Srmacklem .fhsize = 0, 759220739Srmacklem .flags = NFSMNT_RESVPORT, 760191783Srmacklem .wsize = NFS_WSIZE, 761191783Srmacklem .rsize = NFS_RSIZE, 762191783Srmacklem .readdirsize = NFS_READDIRSIZE, 763191783Srmacklem .timeo = 10, 764191783Srmacklem .retrans = NFS_RETRANS, 765191783Srmacklem .readahead = NFS_DEFRAHEAD, 766191783Srmacklem .wcommitsize = 0, /* was: NQ_DEFLEASE */ 767191783Srmacklem .hostname = NULL, 768191783Srmacklem .acregmin = NFS_MINATTRTIMO, 769191783Srmacklem .acregmax = NFS_MAXATTRTIMO, 770191783Srmacklem .acdirmin = NFS_MINDIRATTRTIMO, 771191783Srmacklem .acdirmax = NFS_MAXDIRATTRTIMO, 772191783Srmacklem }; 773192585Srmacklem int error = 0, ret, len; 774192585Srmacklem struct sockaddr *nam = NULL; 775191783Srmacklem struct vnode *vp; 776191990Sattilio struct thread *td; 777191783Srmacklem char hst[MNAMELEN]; 778191783Srmacklem u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100]; 779286141Srmacklem char *cp, *opt, *name, *secname; 780230547Sjhb int nametimeo = NFS_DEFAULT_NAMETIMEO; 781203303Srmacklem int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO; 782244042Srmacklem int minvers = 0; 783221190Srmacklem int dirlen, has_nfs_args_opt, krbnamelen, srvkrbnamelen; 784221205Srmacklem size_t hstlen; 785191783Srmacklem 786221190Srmacklem has_nfs_args_opt = 0; 787191783Srmacklem if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) { 788191783Srmacklem error = EINVAL; 789191783Srmacklem goto out; 790191783Srmacklem } 791191783Srmacklem 792191990Sattilio td = curthread; 793191783Srmacklem if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) { 794221040Srmacklem error = nfs_mountroot(mp); 795191783Srmacklem goto out; 796191783Srmacklem } 797191783Srmacklem 798192585Srmacklem nfscl_init(); 799191783Srmacklem 800221190Srmacklem /* 801221190Srmacklem * The old mount_nfs program passed the struct nfs_args 802221190Srmacklem * from userspace to kernel. The new mount_nfs program 803221190Srmacklem * passes string options via nmount() from userspace to kernel 804221190Srmacklem * and we populate the struct nfs_args in the kernel. 805221190Srmacklem */ 806221190Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) { 807221190Srmacklem error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args, 808221190Srmacklem sizeof(args)); 809221190Srmacklem if (error != 0) 810221190Srmacklem goto out; 811221190Srmacklem 812221190Srmacklem if (args.version != NFS_ARGSVERSION) { 813221190Srmacklem error = EPROGMISMATCH; 814221190Srmacklem goto out; 815221190Srmacklem } 816221190Srmacklem has_nfs_args_opt = 1; 817221190Srmacklem } 818221190Srmacklem 819192585Srmacklem /* Handle the new style options. */ 820275249Strasz if (vfs_getopt(mp->mnt_optnew, "noac", NULL, NULL) == 0) { 821275249Strasz args.acdirmin = args.acdirmax = 822275249Strasz args.acregmin = args.acregmax = 0; 823275249Strasz args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX | 824275249Strasz NFSMNT_ACREGMIN | NFSMNT_ACREGMAX; 825275249Strasz } 826192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0) 827192585Srmacklem args.flags |= NFSMNT_NOCONN; 828192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0) 829275252Strasz args.flags &= ~NFSMNT_NOCONN; 830192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0) 831192585Srmacklem args.flags |= NFSMNT_NOLOCKD; 832192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0) 833192585Srmacklem args.flags &= ~NFSMNT_NOLOCKD; 834192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0) 835192585Srmacklem args.flags |= NFSMNT_INT; 836192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0) 837192585Srmacklem args.flags |= NFSMNT_RDIRPLUS; 838192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0) 839192585Srmacklem args.flags |= NFSMNT_RESVPORT; 840192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0) 841192585Srmacklem args.flags &= ~NFSMNT_RESVPORT; 842192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0) 843192585Srmacklem args.flags |= NFSMNT_SOFT; 844192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0) 845192585Srmacklem args.flags &= ~NFSMNT_SOFT; 846192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0) 847192585Srmacklem args.sotype = SOCK_DGRAM; 848192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0) 849192585Srmacklem args.sotype = SOCK_DGRAM; 850192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0) 851192585Srmacklem args.sotype = SOCK_STREAM; 852192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0) 853192585Srmacklem args.flags |= NFSMNT_NFSV3; 854192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) { 855192585Srmacklem args.flags |= NFSMNT_NFSV4; 856192585Srmacklem args.sotype = SOCK_STREAM; 857191783Srmacklem } 858192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0) 859192585Srmacklem args.flags |= NFSMNT_ALLGSSNAME; 860221436Sru if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0) 861221436Sru args.flags |= NFSMNT_NOCTO; 862260107Srmacklem if (vfs_getopt(mp->mnt_optnew, "noncontigwr", NULL, NULL) == 0) 863260107Srmacklem args.flags |= NFSMNT_NONCONTIGWR; 864244042Srmacklem if (vfs_getopt(mp->mnt_optnew, "pnfs", NULL, NULL) == 0) 865244042Srmacklem args.flags |= NFSMNT_PNFS; 866192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) { 867192585Srmacklem if (opt == NULL) { 868192585Srmacklem vfs_mount_error(mp, "illegal readdirsize"); 869192585Srmacklem error = EINVAL; 870192585Srmacklem goto out; 871192585Srmacklem } 872192585Srmacklem ret = sscanf(opt, "%d", &args.readdirsize); 873192585Srmacklem if (ret != 1 || args.readdirsize <= 0) { 874192585Srmacklem vfs_mount_error(mp, "illegal readdirsize: %s", 875192585Srmacklem opt); 876192585Srmacklem error = EINVAL; 877192585Srmacklem goto out; 878192585Srmacklem } 879192585Srmacklem args.flags |= NFSMNT_READDIRSIZE; 880192585Srmacklem } 881192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) { 882192585Srmacklem if (opt == NULL) { 883192585Srmacklem vfs_mount_error(mp, "illegal readahead"); 884192585Srmacklem error = EINVAL; 885192585Srmacklem goto out; 886192585Srmacklem } 887192585Srmacklem ret = sscanf(opt, "%d", &args.readahead); 888192585Srmacklem if (ret != 1 || args.readahead <= 0) { 889192585Srmacklem vfs_mount_error(mp, "illegal readahead: %s", 890192585Srmacklem opt); 891192585Srmacklem error = EINVAL; 892192585Srmacklem goto out; 893192585Srmacklem } 894192585Srmacklem args.flags |= NFSMNT_READAHEAD; 895192585Srmacklem } 896192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) { 897192585Srmacklem if (opt == NULL) { 898192585Srmacklem vfs_mount_error(mp, "illegal wsize"); 899192585Srmacklem error = EINVAL; 900192585Srmacklem goto out; 901192585Srmacklem } 902192585Srmacklem ret = sscanf(opt, "%d", &args.wsize); 903192585Srmacklem if (ret != 1 || args.wsize <= 0) { 904192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 905192585Srmacklem opt); 906192585Srmacklem error = EINVAL; 907192585Srmacklem goto out; 908192585Srmacklem } 909192585Srmacklem args.flags |= NFSMNT_WSIZE; 910192585Srmacklem } 911192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) { 912192585Srmacklem if (opt == NULL) { 913192585Srmacklem vfs_mount_error(mp, "illegal rsize"); 914192585Srmacklem error = EINVAL; 915192585Srmacklem goto out; 916192585Srmacklem } 917192585Srmacklem ret = sscanf(opt, "%d", &args.rsize); 918192585Srmacklem if (ret != 1 || args.rsize <= 0) { 919192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 920192585Srmacklem opt); 921192585Srmacklem error = EINVAL; 922192585Srmacklem goto out; 923192585Srmacklem } 924192585Srmacklem args.flags |= NFSMNT_RSIZE; 925192585Srmacklem } 926192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) { 927192585Srmacklem if (opt == NULL) { 928192585Srmacklem vfs_mount_error(mp, "illegal retrans"); 929192585Srmacklem error = EINVAL; 930192585Srmacklem goto out; 931192585Srmacklem } 932192585Srmacklem ret = sscanf(opt, "%d", &args.retrans); 933192585Srmacklem if (ret != 1 || args.retrans <= 0) { 934192585Srmacklem vfs_mount_error(mp, "illegal retrans: %s", 935192585Srmacklem opt); 936192585Srmacklem error = EINVAL; 937192585Srmacklem goto out; 938192585Srmacklem } 939192585Srmacklem args.flags |= NFSMNT_RETRANS; 940192585Srmacklem } 941275249Strasz if (vfs_getopt(mp->mnt_optnew, "actimeo", (void **)&opt, NULL) == 0) { 942275249Strasz ret = sscanf(opt, "%d", &args.acregmin); 943275249Strasz if (ret != 1 || args.acregmin < 0) { 944275249Strasz vfs_mount_error(mp, "illegal actimeo: %s", 945275249Strasz opt); 946275249Strasz error = EINVAL; 947275249Strasz goto out; 948275249Strasz } 949275249Strasz args.acdirmin = args.acdirmax = args.acregmax = args.acregmin; 950275249Strasz args.flags |= NFSMNT_ACDIRMIN | NFSMNT_ACDIRMAX | 951275249Strasz NFSMNT_ACREGMIN | NFSMNT_ACREGMAX; 952275249Strasz } 953192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) { 954192585Srmacklem ret = sscanf(opt, "%d", &args.acregmin); 955192585Srmacklem if (ret != 1 || args.acregmin < 0) { 956192585Srmacklem vfs_mount_error(mp, "illegal acregmin: %s", 957192585Srmacklem opt); 958192585Srmacklem error = EINVAL; 959192585Srmacklem goto out; 960192585Srmacklem } 961192585Srmacklem args.flags |= NFSMNT_ACREGMIN; 962192585Srmacklem } 963192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) { 964192585Srmacklem ret = sscanf(opt, "%d", &args.acregmax); 965192585Srmacklem if (ret != 1 || args.acregmax < 0) { 966192585Srmacklem vfs_mount_error(mp, "illegal acregmax: %s", 967192585Srmacklem opt); 968192585Srmacklem error = EINVAL; 969192585Srmacklem goto out; 970192585Srmacklem } 971192585Srmacklem args.flags |= NFSMNT_ACREGMAX; 972192585Srmacklem } 973192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) { 974192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmin); 975192585Srmacklem if (ret != 1 || args.acdirmin < 0) { 976192585Srmacklem vfs_mount_error(mp, "illegal acdirmin: %s", 977192585Srmacklem opt); 978192585Srmacklem error = EINVAL; 979192585Srmacklem goto out; 980192585Srmacklem } 981192585Srmacklem args.flags |= NFSMNT_ACDIRMIN; 982192585Srmacklem } 983192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) { 984192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmax); 985192585Srmacklem if (ret != 1 || args.acdirmax < 0) { 986192585Srmacklem vfs_mount_error(mp, "illegal acdirmax: %s", 987192585Srmacklem opt); 988192585Srmacklem error = EINVAL; 989192585Srmacklem goto out; 990192585Srmacklem } 991192585Srmacklem args.flags |= NFSMNT_ACDIRMAX; 992192585Srmacklem } 993227507Sjhb if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) { 994227507Sjhb ret = sscanf(opt, "%d", &args.wcommitsize); 995227507Sjhb if (ret != 1 || args.wcommitsize < 0) { 996227507Sjhb vfs_mount_error(mp, "illegal wcommitsize: %s", opt); 997227507Sjhb error = EINVAL; 998227507Sjhb goto out; 999227507Sjhb } 1000227507Sjhb args.flags |= NFSMNT_WCOMMITSIZE; 1001227507Sjhb } 1002275249Strasz if (vfs_getopt(mp->mnt_optnew, "timeo", (void **)&opt, NULL) == 0) { 1003275249Strasz ret = sscanf(opt, "%d", &args.timeo); 1004275249Strasz if (ret != 1 || args.timeo <= 0) { 1005275249Strasz vfs_mount_error(mp, "illegal timeo: %s", 1006275249Strasz opt); 1007275249Strasz error = EINVAL; 1008275249Strasz goto out; 1009275249Strasz } 1010275249Strasz args.flags |= NFSMNT_TIMEO; 1011275249Strasz } 1012192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) { 1013192585Srmacklem ret = sscanf(opt, "%d", &args.timeo); 1014192585Srmacklem if (ret != 1 || args.timeo <= 0) { 1015192585Srmacklem vfs_mount_error(mp, "illegal timeout: %s", 1016192585Srmacklem opt); 1017192585Srmacklem error = EINVAL; 1018192585Srmacklem goto out; 1019192585Srmacklem } 1020192585Srmacklem args.flags |= NFSMNT_TIMEO; 1021192585Srmacklem } 1022230547Sjhb if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) { 1023230547Sjhb ret = sscanf(opt, "%d", &nametimeo); 1024230547Sjhb if (ret != 1 || nametimeo < 0) { 1025230547Sjhb vfs_mount_error(mp, "illegal nametimeo: %s", opt); 1026230547Sjhb error = EINVAL; 1027230547Sjhb goto out; 1028230547Sjhb } 1029230547Sjhb } 1030203303Srmacklem if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL) 1031203303Srmacklem == 0) { 1032203303Srmacklem ret = sscanf(opt, "%d", &negnametimeo); 1033203303Srmacklem if (ret != 1 || negnametimeo < 0) { 1034203303Srmacklem vfs_mount_error(mp, "illegal negnametimeo: %s", 1035203303Srmacklem opt); 1036203303Srmacklem error = EINVAL; 1037203303Srmacklem goto out; 1038203303Srmacklem } 1039203303Srmacklem } 1040244042Srmacklem if (vfs_getopt(mp->mnt_optnew, "minorversion", (void **)&opt, NULL) == 1041244042Srmacklem 0) { 1042244042Srmacklem ret = sscanf(opt, "%d", &minvers); 1043244042Srmacklem if (ret != 1 || minvers < 0 || minvers > 1 || 1044244042Srmacklem (args.flags & NFSMNT_NFSV4) == 0) { 1045244042Srmacklem vfs_mount_error(mp, "illegal minorversion: %s", opt); 1046244042Srmacklem error = EINVAL; 1047244042Srmacklem goto out; 1048244042Srmacklem } 1049244042Srmacklem } 1050192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "sec", 1051192585Srmacklem (void **) &secname, NULL) == 0) 1052192585Srmacklem nfs_sec_name(secname, &args.flags); 1053191783Srmacklem 1054191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 1055191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1056191783Srmacklem 1057191783Srmacklem if (nmp == NULL) { 1058191783Srmacklem error = EIO; 1059191783Srmacklem goto out; 1060191783Srmacklem } 1061230803Srmacklem 1062191783Srmacklem /* 1063230803Srmacklem * If a change from TCP->UDP is done and there are thread(s) 1064230803Srmacklem * that have I/O RPC(s) in progress with a tranfer size 1065230803Srmacklem * greater than NFS_MAXDGRAMDATA, those thread(s) will be 1066230803Srmacklem * hung, retrying the RPC(s) forever. Usually these threads 1067230803Srmacklem * will be seen doing an uninterruptible sleep on wait channel 1068230803Srmacklem * "newnfsreq" (truncated to "newnfsre" by procstat). 1069230803Srmacklem */ 1070230803Srmacklem if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM) 1071230803Srmacklem tprintf(td->td_proc, LOG_WARNING, 1072230803Srmacklem "Warning: mount -u that changes TCP->UDP can result in hung threads\n"); 1073230803Srmacklem 1074230803Srmacklem /* 1075191783Srmacklem * When doing an update, we can't change version, 1076191783Srmacklem * security, switch lockd strategies or change cookie 1077191783Srmacklem * translation 1078191783Srmacklem */ 1079191783Srmacklem args.flags = (args.flags & 1080191783Srmacklem ~(NFSMNT_NFSV3 | 1081191783Srmacklem NFSMNT_NFSV4 | 1082191783Srmacklem NFSMNT_KERB | 1083191783Srmacklem NFSMNT_INTEGRITY | 1084191783Srmacklem NFSMNT_PRIVACY | 1085191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) | 1086191783Srmacklem (nmp->nm_flag & 1087191783Srmacklem (NFSMNT_NFSV3 | 1088191783Srmacklem NFSMNT_NFSV4 | 1089191783Srmacklem NFSMNT_KERB | 1090191783Srmacklem NFSMNT_INTEGRITY | 1091191783Srmacklem NFSMNT_PRIVACY | 1092191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); 1093214048Srmacklem nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td); 1094191783Srmacklem goto out; 1095191783Srmacklem } 1096191783Srmacklem 1097191783Srmacklem /* 1098191783Srmacklem * Make the nfs_ip_paranoia sysctl serve as the default connection 1099191783Srmacklem * or no-connection mode for those protocols that support 1100191783Srmacklem * no-connection mode (the flag will be cleared later for protocols 1101191783Srmacklem * that do not support no-connection mode). This will allow a client 1102191783Srmacklem * to receive replies from a different IP then the request was 1103191783Srmacklem * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid), 1104191783Srmacklem * not 0. 1105191783Srmacklem */ 1106191783Srmacklem if (nfs_ip_paranoia == 0) 1107191783Srmacklem args.flags |= NFSMNT_NOCONN; 1108192585Srmacklem 1109221190Srmacklem if (has_nfs_args_opt != 0) { 1110221190Srmacklem /* 1111221190Srmacklem * In the 'nfs_args' case, the pointers in the args 1112221190Srmacklem * structure are in userland - we copy them in here. 1113221190Srmacklem */ 1114221190Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) { 1115192585Srmacklem vfs_mount_error(mp, "Bad file handle"); 1116191783Srmacklem error = EINVAL; 1117191783Srmacklem goto out; 1118191783Srmacklem } 1119221190Srmacklem error = copyin((caddr_t)args.fh, (caddr_t)nfh, 1120221190Srmacklem args.fhsize); 1121221190Srmacklem if (error != 0) 1122221190Srmacklem goto out; 1123221205Srmacklem error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen); 1124221190Srmacklem if (error != 0) 1125221190Srmacklem goto out; 1126221205Srmacklem bzero(&hst[hstlen], MNAMELEN - hstlen); 1127221190Srmacklem args.hostname = hst; 1128221190Srmacklem /* sockargs() call must be after above copyin() calls */ 1129221190Srmacklem error = getsockaddr(&nam, (caddr_t)args.addr, 1130221190Srmacklem args.addrlen); 1131221190Srmacklem if (error != 0) 1132221190Srmacklem goto out; 1133191783Srmacklem } else { 1134221190Srmacklem if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh, 1135221190Srmacklem &args.fhsize) == 0) { 1136221190Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) { 1137221190Srmacklem vfs_mount_error(mp, "Bad file handle"); 1138221190Srmacklem error = EINVAL; 1139221190Srmacklem goto out; 1140221190Srmacklem } 1141221190Srmacklem bcopy(args.fh, nfh, args.fhsize); 1142221190Srmacklem } else { 1143221190Srmacklem args.fhsize = 0; 1144221190Srmacklem } 1145221190Srmacklem (void) vfs_getopt(mp->mnt_optnew, "hostname", 1146221190Srmacklem (void **)&args.hostname, &len); 1147221190Srmacklem if (args.hostname == NULL) { 1148221190Srmacklem vfs_mount_error(mp, "Invalid hostname"); 1149221190Srmacklem error = EINVAL; 1150221190Srmacklem goto out; 1151221190Srmacklem } 1152221190Srmacklem bcopy(args.hostname, hst, MNAMELEN); 1153221190Srmacklem hst[MNAMELEN - 1] = '\0'; 1154192585Srmacklem } 1155192585Srmacklem 1156192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0) 1157192585Srmacklem strlcpy(srvkrbname, name, sizeof (srvkrbname)); 1158286141Srmacklem else { 1159192585Srmacklem snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst); 1160286141Srmacklem cp = strchr(srvkrbname, ':'); 1161286141Srmacklem if (cp != NULL) 1162286141Srmacklem *cp = '\0'; 1163286141Srmacklem } 1164221014Srmacklem srvkrbnamelen = strlen(srvkrbname); 1165192585Srmacklem 1166192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0) 1167192585Srmacklem strlcpy(krbname, name, sizeof (krbname)); 1168192585Srmacklem else 1169191783Srmacklem krbname[0] = '\0'; 1170221014Srmacklem krbnamelen = strlen(krbname); 1171192585Srmacklem 1172192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0) 1173192585Srmacklem strlcpy(dirpath, name, sizeof (dirpath)); 1174192585Srmacklem else 1175191783Srmacklem dirpath[0] = '\0'; 1176221014Srmacklem dirlen = strlen(dirpath); 1177192585Srmacklem 1178222075Srmacklem if (has_nfs_args_opt == 0) { 1179222075Srmacklem if (vfs_getopt(mp->mnt_optnew, "addr", 1180222075Srmacklem (void **)&args.addr, &args.addrlen) == 0) { 1181222075Srmacklem if (args.addrlen > SOCK_MAXADDRLEN) { 1182222075Srmacklem error = ENAMETOOLONG; 1183222075Srmacklem goto out; 1184222075Srmacklem } 1185222075Srmacklem nam = malloc(args.addrlen, M_SONAME, M_WAITOK); 1186222075Srmacklem bcopy(args.addr, nam, args.addrlen); 1187222075Srmacklem nam->sa_len = args.addrlen; 1188222075Srmacklem } else { 1189222075Srmacklem vfs_mount_error(mp, "No server address"); 1190222075Srmacklem error = EINVAL; 1191191783Srmacklem goto out; 1192191783Srmacklem } 1193191783Srmacklem } 1194192585Srmacklem 1195191783Srmacklem args.fh = nfh; 1196221014Srmacklem error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath, 1197221014Srmacklem dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td, 1198244042Srmacklem nametimeo, negnametimeo, minvers); 1199191783Srmacklemout: 1200191783Srmacklem if (!error) { 1201191783Srmacklem MNT_ILOCK(mp); 1202282270Srmacklem mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_NO_IOPF | 1203282270Srmacklem MNTK_USES_BCACHE; 1204191783Srmacklem MNT_IUNLOCK(mp); 1205191783Srmacklem } 1206191783Srmacklem return (error); 1207191783Srmacklem} 1208191783Srmacklem 1209191783Srmacklem 1210191783Srmacklem/* 1211191783Srmacklem * VFS Operations. 1212191783Srmacklem * 1213191783Srmacklem * mount system call 1214191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 1215191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 1216191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 1217191783Srmacklem * an error after that means that I have to release the mbuf. 1218191783Srmacklem */ 1219191783Srmacklem/* ARGSUSED */ 1220191783Srmacklemstatic int 1221230249Smckusicknfs_cmount(struct mntarg *ma, void *data, uint64_t flags) 1222191783Srmacklem{ 1223191783Srmacklem int error; 1224191783Srmacklem struct nfs_args args; 1225191783Srmacklem 1226191783Srmacklem error = copyin(data, &args, sizeof (struct nfs_args)); 1227191783Srmacklem if (error) 1228191783Srmacklem return error; 1229191783Srmacklem 1230191783Srmacklem ma = mount_arg(ma, "nfs_args", &args, sizeof args); 1231191783Srmacklem 1232191783Srmacklem error = kernel_mount(ma, flags); 1233191783Srmacklem return (error); 1234191783Srmacklem} 1235191783Srmacklem 1236191783Srmacklem/* 1237191783Srmacklem * Common code for mount and mountroot 1238191783Srmacklem */ 1239191783Srmacklemstatic int 1240191783Srmacklemmountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, 1241221014Srmacklem char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen, 1242221014Srmacklem u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp, 1243244042Srmacklem struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo, 1244244042Srmacklem int minvers) 1245191783Srmacklem{ 1246191783Srmacklem struct nfsmount *nmp; 1247191783Srmacklem struct nfsnode *np; 1248195762Srmacklem int error, trycnt, ret; 1249191783Srmacklem struct nfsvattr nfsva; 1250244042Srmacklem struct nfsclclient *clp; 1251244042Srmacklem struct nfsclds *dsp, *tdsp; 1252244042Srmacklem uint32_t lease; 1253191783Srmacklem static u_int64_t clval = 0; 1254191783Srmacklem 1255244042Srmacklem NFSCL_DEBUG(3, "in mnt\n"); 1256244042Srmacklem clp = NULL; 1257191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 1258191783Srmacklem nmp = VFSTONFS(mp); 1259191783Srmacklem printf("%s: MNT_UPDATE is no longer handled here\n", __func__); 1260191783Srmacklem FREE(nam, M_SONAME); 1261191783Srmacklem return (0); 1262191783Srmacklem } else { 1263191783Srmacklem MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) + 1264221014Srmacklem krbnamelen + dirlen + srvkrbnamelen + 2, 1265221014Srmacklem M_NEWNFSMNT, M_WAITOK | M_ZERO); 1266191783Srmacklem TAILQ_INIT(&nmp->nm_bufq); 1267191783Srmacklem if (clval == 0) 1268191783Srmacklem clval = (u_int64_t)nfsboottime.tv_sec; 1269191783Srmacklem nmp->nm_clval = clval++; 1270221014Srmacklem nmp->nm_krbnamelen = krbnamelen; 1271221014Srmacklem nmp->nm_dirpathlen = dirlen; 1272221014Srmacklem nmp->nm_srvkrbnamelen = srvkrbnamelen; 1273192675Srmacklem if (td->td_ucred->cr_uid != (uid_t)0) { 1274191783Srmacklem /* 1275192675Srmacklem * nm_uid is used to get KerberosV credentials for 1276192675Srmacklem * the nfsv4 state handling operations if there is 1277192675Srmacklem * no host based principal set. Use the uid of 1278192675Srmacklem * this user if not root, since they are doing the 1279192675Srmacklem * mount. I don't think setting this for root will 1280192675Srmacklem * work, since root normally does not have user 1281192675Srmacklem * credentials in a credentials cache. 1282191783Srmacklem */ 1283192675Srmacklem nmp->nm_uid = td->td_ucred->cr_uid; 1284191783Srmacklem } else { 1285191783Srmacklem /* 1286192675Srmacklem * Just set to -1, so it won't be used. 1287191783Srmacklem */ 1288191783Srmacklem nmp->nm_uid = (uid_t)-1; 1289191783Srmacklem } 1290191783Srmacklem 1291191783Srmacklem /* Copy and null terminate all the names */ 1292191783Srmacklem if (nmp->nm_krbnamelen > 0) { 1293191783Srmacklem bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen); 1294191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen] = '\0'; 1295191783Srmacklem } 1296191783Srmacklem if (nmp->nm_dirpathlen > 0) { 1297191783Srmacklem bcopy(dirpath, NFSMNT_DIRPATH(nmp), 1298191783Srmacklem nmp->nm_dirpathlen); 1299191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1300191783Srmacklem + 1] = '\0'; 1301191783Srmacklem } 1302191783Srmacklem if (nmp->nm_srvkrbnamelen > 0) { 1303191783Srmacklem bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp), 1304191783Srmacklem nmp->nm_srvkrbnamelen); 1305191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1306191783Srmacklem + nmp->nm_srvkrbnamelen + 2] = '\0'; 1307191783Srmacklem } 1308191783Srmacklem nmp->nm_sockreq.nr_cred = crhold(cred); 1309191783Srmacklem mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF); 1310191783Srmacklem mp->mnt_data = nmp; 1311214048Srmacklem nmp->nm_getinfo = nfs_getnlminfo; 1312216931Srmacklem nmp->nm_vinvalbuf = ncl_vinvalbuf; 1313191783Srmacklem } 1314191783Srmacklem vfs_getnewfsid(mp); 1315191783Srmacklem nmp->nm_mountp = mp; 1316230547Sjhb mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK); 1317227493Srmacklem 1318227493Srmacklem /* 1319230547Sjhb * Since nfs_decode_args() might optionally set them, these 1320230547Sjhb * need to be set to defaults before the call, so that the 1321230547Sjhb * optional settings aren't overwritten. 1322227493Srmacklem */ 1323230547Sjhb nmp->nm_nametimeo = nametimeo; 1324203303Srmacklem nmp->nm_negnametimeo = negnametimeo; 1325227493Srmacklem nmp->nm_timeo = NFS_TIMEO; 1326227493Srmacklem nmp->nm_retry = NFS_RETRANS; 1327227493Srmacklem nmp->nm_readahead = NFS_DEFRAHEAD; 1328282362Smav 1329282362Smav /* This is empirical approximation of sqrt(hibufspace) * 256. */ 1330282362Smav nmp->nm_wcommitsize = NFS_MAXBSIZE / 256; 1331282362Smav while ((long)nmp->nm_wcommitsize * nmp->nm_wcommitsize < hibufspace) 1332282362Smav nmp->nm_wcommitsize *= 2; 1333282362Smav nmp->nm_wcommitsize *= 256; 1334282362Smav 1335244042Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0) 1336244042Srmacklem nmp->nm_minorvers = minvers; 1337244042Srmacklem else 1338244042Srmacklem nmp->nm_minorvers = 0; 1339191783Srmacklem 1340214048Srmacklem nfs_decode_args(mp, nmp, argp, hst, cred, td); 1341192585Srmacklem 1342191783Srmacklem /* 1343191783Srmacklem * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too 1344191783Srmacklem * high, depending on whether we end up with negative offsets in 1345191783Srmacklem * the client or server somewhere. 2GB-1 may be safer. 1346191783Srmacklem * 1347191783Srmacklem * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum 1348191783Srmacklem * that we can handle until we find out otherwise. 1349191783Srmacklem */ 1350191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) 1351191783Srmacklem nmp->nm_maxfilesize = 0xffffffffLL; 1352191783Srmacklem else 1353221537Srmacklem nmp->nm_maxfilesize = OFF_MAX; 1354191783Srmacklem 1355191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 1356191783Srmacklem nmp->nm_wsize = NFS_WSIZE; 1357191783Srmacklem nmp->nm_rsize = NFS_RSIZE; 1358191783Srmacklem nmp->nm_readdirsize = NFS_READDIRSIZE; 1359191783Srmacklem } 1360191783Srmacklem nmp->nm_numgrps = NFS_MAXGRPS; 1361191783Srmacklem nmp->nm_tprintf_delay = nfs_tprintf_delay; 1362191783Srmacklem if (nmp->nm_tprintf_delay < 0) 1363191783Srmacklem nmp->nm_tprintf_delay = 0; 1364191783Srmacklem nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay; 1365191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1366191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1367191783Srmacklem nmp->nm_fhsize = argp->fhsize; 1368191783Srmacklem if (nmp->nm_fhsize > 0) 1369191783Srmacklem bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 1370191783Srmacklem bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 1371191783Srmacklem nmp->nm_nam = nam; 1372191783Srmacklem /* Set up the sockets and per-host congestion */ 1373191783Srmacklem nmp->nm_sotype = argp->sotype; 1374191783Srmacklem nmp->nm_soproto = argp->proto; 1375191783Srmacklem nmp->nm_sockreq.nr_prog = NFS_PROG; 1376191783Srmacklem if ((argp->flags & NFSMNT_NFSV4)) 1377191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER4; 1378191783Srmacklem else if ((argp->flags & NFSMNT_NFSV3)) 1379191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER3; 1380191783Srmacklem else 1381191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER2; 1382191783Srmacklem 1383191783Srmacklem 1384191783Srmacklem if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0))) 1385191783Srmacklem goto bad; 1386244042Srmacklem /* For NFSv4.1, get the clientid now. */ 1387244042Srmacklem if (nmp->nm_minorvers > 0) { 1388244042Srmacklem NFSCL_DEBUG(3, "at getcl\n"); 1389244042Srmacklem error = nfscl_getcl(mp, cred, td, 0, &clp); 1390244042Srmacklem NFSCL_DEBUG(3, "aft getcl=%d\n", error); 1391244042Srmacklem if (error != 0) 1392244042Srmacklem goto bad; 1393244042Srmacklem } 1394191783Srmacklem 1395191783Srmacklem if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) && 1396191783Srmacklem nmp->nm_dirpathlen > 0) { 1397244042Srmacklem NFSCL_DEBUG(3, "in dirp\n"); 1398191783Srmacklem /* 1399191783Srmacklem * If the fhsize on the mount point == 0 for V4, the mount 1400191783Srmacklem * path needs to be looked up. 1401191783Srmacklem */ 1402191783Srmacklem trycnt = 3; 1403191783Srmacklem do { 1404191783Srmacklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 1405191783Srmacklem cred, td); 1406244042Srmacklem NFSCL_DEBUG(3, "aft dirp=%d\n", error); 1407191783Srmacklem if (error) 1408207170Srmacklem (void) nfs_catnap(PZERO, error, "nfsgetdirp"); 1409191783Srmacklem } while (error && --trycnt > 0); 1410191783Srmacklem if (error) { 1411191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1412191783Srmacklem goto bad; 1413191783Srmacklem } 1414191783Srmacklem } 1415244042Srmacklem 1416244042Srmacklem /* 1417244042Srmacklem * A reference count is needed on the nfsnode representing the 1418244042Srmacklem * remote root. If this object is not persistent, then backward 1419244042Srmacklem * traversals of the mount point (i.e. "..") will not work if 1420244042Srmacklem * the nfsnode gets flushed out of the cache. Ufs does not have 1421244042Srmacklem * this problem, because one can identify root inodes by their 1422244042Srmacklem * number == ROOTINO (2). 1423244042Srmacklem */ 1424191783Srmacklem if (nmp->nm_fhsize > 0) { 1425195762Srmacklem /* 1426195762Srmacklem * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set 1427195762Srmacklem * non-zero for the root vnode. f_iosize will be set correctly 1428195762Srmacklem * by nfs_statfs() before any I/O occurs. 1429195762Srmacklem */ 1430195762Srmacklem mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ; 1431220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, 1432220732Srmacklem LK_EXCLUSIVE); 1433191783Srmacklem if (error) 1434191783Srmacklem goto bad; 1435191783Srmacklem *vpp = NFSTOV(np); 1436191783Srmacklem 1437191783Srmacklem /* 1438191783Srmacklem * Get file attributes and transfer parameters for the 1439191783Srmacklem * mountpoint. This has the side effect of filling in 1440191783Srmacklem * (*vpp)->v_type with the correct value. 1441191783Srmacklem */ 1442191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 1443244042Srmacklem cred, td, &nfsva, NULL, &lease); 1444191783Srmacklem if (ret) { 1445191783Srmacklem /* 1446191783Srmacklem * Just set default values to get things going. 1447191783Srmacklem */ 1448191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 1449191783Srmacklem nfsva.na_vattr.va_type = VDIR; 1450191783Srmacklem nfsva.na_vattr.va_mode = 0777; 1451191783Srmacklem nfsva.na_vattr.va_nlink = 100; 1452191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 1453191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 1454191783Srmacklem nfsva.na_vattr.va_fileid = 2; 1455191783Srmacklem nfsva.na_vattr.va_gen = 1; 1456191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 1457191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 1458244042Srmacklem lease = 60; 1459191783Srmacklem } 1460191783Srmacklem (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1); 1461244042Srmacklem if (nmp->nm_minorvers > 0) { 1462244042Srmacklem NFSCL_DEBUG(3, "lease=%d\n", (int)lease); 1463244042Srmacklem NFSLOCKCLSTATE(); 1464244042Srmacklem clp->nfsc_renew = NFSCL_RENEW(lease); 1465244042Srmacklem clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew; 1466244042Srmacklem clp->nfsc_clientidrev++; 1467244042Srmacklem if (clp->nfsc_clientidrev == 0) 1468244042Srmacklem clp->nfsc_clientidrev++; 1469244042Srmacklem NFSUNLOCKCLSTATE(); 1470244042Srmacklem /* 1471244042Srmacklem * Mount will succeed, so the renew thread can be 1472244042Srmacklem * started now. 1473244042Srmacklem */ 1474244042Srmacklem nfscl_start_renewthread(clp); 1475244042Srmacklem nfscl_clientrelease(clp); 1476244042Srmacklem } 1477191783Srmacklem if (argp->flags & NFSMNT_NFSV3) 1478191783Srmacklem ncl_fsinfo(nmp, *vpp, cred, td); 1479191783Srmacklem 1480222233Srmacklem /* Mark if the mount point supports NFSv4 ACLs. */ 1481222233Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 && 1482222233Srmacklem ret == 0 && 1483222233Srmacklem NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) { 1484222233Srmacklem MNT_ILOCK(mp); 1485222233Srmacklem mp->mnt_flag |= MNT_NFS4ACLS; 1486222233Srmacklem MNT_IUNLOCK(mp); 1487222233Srmacklem } 1488222233Srmacklem 1489191783Srmacklem /* 1490191783Srmacklem * Lose the lock but keep the ref. 1491191783Srmacklem */ 1492224082Szack NFSVOPUNLOCK(*vpp, 0); 1493191783Srmacklem return (0); 1494191783Srmacklem } 1495191783Srmacklem error = EIO; 1496191783Srmacklem 1497191783Srmacklembad: 1498244042Srmacklem if (clp != NULL) 1499244042Srmacklem nfscl_clientrelease(clp); 1500191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1501191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1502253049Srmacklem if (nmp->nm_sockreq.nr_auth != NULL) 1503253049Srmacklem AUTH_DESTROY(nmp->nm_sockreq.nr_auth); 1504191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1505191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1506244042Srmacklem if (nmp->nm_clp != NULL) { 1507244042Srmacklem NFSLOCKCLSTATE(); 1508244042Srmacklem LIST_REMOVE(nmp->nm_clp, nfsc_list); 1509244042Srmacklem NFSUNLOCKCLSTATE(); 1510244042Srmacklem free(nmp->nm_clp, M_NFSCLCLIENT); 1511244042Srmacklem } 1512244042Srmacklem TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) 1513244042Srmacklem nfscl_freenfsclds(dsp); 1514191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1515191783Srmacklem FREE(nam, M_SONAME); 1516191783Srmacklem return (error); 1517191783Srmacklem} 1518191783Srmacklem 1519191783Srmacklem/* 1520191783Srmacklem * unmount system call 1521191783Srmacklem */ 1522191783Srmacklemstatic int 1523191990Sattilionfs_unmount(struct mount *mp, int mntflags) 1524191783Srmacklem{ 1525191990Sattilio struct thread *td; 1526191783Srmacklem struct nfsmount *nmp; 1527249630Srmacklem int error, flags = 0, i, trycnt = 0; 1528244042Srmacklem struct nfsclds *dsp, *tdsp; 1529191783Srmacklem 1530191990Sattilio td = curthread; 1531191990Sattilio 1532191783Srmacklem if (mntflags & MNT_FORCE) 1533191783Srmacklem flags |= FORCECLOSE; 1534191783Srmacklem nmp = VFSTONFS(mp); 1535191783Srmacklem /* 1536191783Srmacklem * Goes something like this.. 1537191783Srmacklem * - Call vflush() to clear out vnodes for this filesystem 1538191783Srmacklem * - Close the socket 1539191783Srmacklem * - Free up the data structures 1540191783Srmacklem */ 1541191783Srmacklem /* In the forced case, cancel any outstanding requests. */ 1542191783Srmacklem if (mntflags & MNT_FORCE) { 1543191783Srmacklem error = newnfs_nmcancelreqs(nmp); 1544191783Srmacklem if (error) 1545191783Srmacklem goto out; 1546191783Srmacklem /* For a forced close, get rid of the renew thread now */ 1547191783Srmacklem nfscl_umount(nmp, td); 1548191783Srmacklem } 1549191783Srmacklem /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ 1550191783Srmacklem do { 1551191783Srmacklem error = vflush(mp, 1, flags, td); 1552191783Srmacklem if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30) 1553207170Srmacklem (void) nfs_catnap(PSOCK, error, "newndm"); 1554191783Srmacklem } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30); 1555191783Srmacklem if (error) 1556191783Srmacklem goto out; 1557191783Srmacklem 1558191783Srmacklem /* 1559191783Srmacklem * We are now committed to the unmount. 1560191783Srmacklem */ 1561191783Srmacklem if ((mntflags & MNT_FORCE) == 0) 1562191783Srmacklem nfscl_umount(nmp, td); 1563249630Srmacklem /* Make sure no nfsiods are assigned to this mount. */ 1564249630Srmacklem mtx_lock(&ncl_iod_mutex); 1565249630Srmacklem for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 1566249630Srmacklem if (ncl_iodmount[i] == nmp) { 1567249630Srmacklem ncl_iodwant[i] = NFSIOD_AVAILABLE; 1568249630Srmacklem ncl_iodmount[i] = NULL; 1569249630Srmacklem } 1570249630Srmacklem mtx_unlock(&ncl_iod_mutex); 1571191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1572191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1573191783Srmacklem FREE(nmp->nm_nam, M_SONAME); 1574253049Srmacklem if (nmp->nm_sockreq.nr_auth != NULL) 1575253049Srmacklem AUTH_DESTROY(nmp->nm_sockreq.nr_auth); 1576191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1577191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1578244042Srmacklem TAILQ_FOREACH_SAFE(dsp, &nmp->nm_sess, nfsclds_list, tdsp) 1579244042Srmacklem nfscl_freenfsclds(dsp); 1580191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1581191783Srmacklemout: 1582191783Srmacklem return (error); 1583191783Srmacklem} 1584191783Srmacklem 1585191783Srmacklem/* 1586191783Srmacklem * Return root of a filesystem 1587191783Srmacklem */ 1588191783Srmacklemstatic int 1589191990Sattilionfs_root(struct mount *mp, int flags, struct vnode **vpp) 1590191783Srmacklem{ 1591191783Srmacklem struct vnode *vp; 1592191783Srmacklem struct nfsmount *nmp; 1593191783Srmacklem struct nfsnode *np; 1594191783Srmacklem int error; 1595191783Srmacklem 1596191783Srmacklem nmp = VFSTONFS(mp); 1597220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags); 1598191783Srmacklem if (error) 1599191783Srmacklem return error; 1600191783Srmacklem vp = NFSTOV(np); 1601191783Srmacklem /* 1602191783Srmacklem * Get transfer parameters and attributes for root vnode once. 1603191783Srmacklem */ 1604191783Srmacklem mtx_lock(&nmp->nm_mtx); 1605191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 1606191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1607191783Srmacklem ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread); 1608191783Srmacklem } else 1609191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1610191783Srmacklem if (vp->v_type == VNON) 1611191783Srmacklem vp->v_type = VDIR; 1612191783Srmacklem vp->v_vflag |= VV_ROOT; 1613191783Srmacklem *vpp = vp; 1614191783Srmacklem return (0); 1615191783Srmacklem} 1616191783Srmacklem 1617191783Srmacklem/* 1618191783Srmacklem * Flush out the buffer cache 1619191783Srmacklem */ 1620191783Srmacklem/* ARGSUSED */ 1621191783Srmacklemstatic int 1622191990Sattilionfs_sync(struct mount *mp, int waitfor) 1623191783Srmacklem{ 1624191783Srmacklem struct vnode *vp, *mvp; 1625191990Sattilio struct thread *td; 1626191783Srmacklem int error, allerror = 0; 1627191783Srmacklem 1628191990Sattilio td = curthread; 1629191990Sattilio 1630222329Srmacklem MNT_ILOCK(mp); 1631191783Srmacklem /* 1632222329Srmacklem * If a forced dismount is in progress, return from here so that 1633222329Srmacklem * the umount(2) syscall doesn't get stuck in VFS_SYNC() before 1634222329Srmacklem * calling VFS_UNMOUNT(). 1635222329Srmacklem */ 1636222329Srmacklem if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1637222329Srmacklem MNT_IUNLOCK(mp); 1638222329Srmacklem return (EBADF); 1639222329Srmacklem } 1640234386Smckusick MNT_IUNLOCK(mp); 1641222329Srmacklem 1642222329Srmacklem /* 1643191783Srmacklem * Force stale buffer cache information to be flushed. 1644191783Srmacklem */ 1645191783Srmacklemloop: 1646234386Smckusick MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { 1647191783Srmacklem /* XXX Racy bv_cnt check. */ 1648224083Szack if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1649191783Srmacklem waitfor == MNT_LAZY) { 1650191783Srmacklem VI_UNLOCK(vp); 1651191783Srmacklem continue; 1652191783Srmacklem } 1653191783Srmacklem if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 1654234386Smckusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 1655191783Srmacklem goto loop; 1656191783Srmacklem } 1657191783Srmacklem error = VOP_FSYNC(vp, waitfor, td); 1658191783Srmacklem if (error) 1659191783Srmacklem allerror = error; 1660224082Szack NFSVOPUNLOCK(vp, 0); 1661191783Srmacklem vrele(vp); 1662191783Srmacklem } 1663191783Srmacklem return (allerror); 1664191783Srmacklem} 1665191783Srmacklem 1666191783Srmacklemstatic int 1667191783Srmacklemnfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 1668191783Srmacklem{ 1669191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1670191783Srmacklem struct vfsquery vq; 1671191783Srmacklem int error; 1672191783Srmacklem 1673191783Srmacklem bzero(&vq, sizeof(vq)); 1674191783Srmacklem switch (op) { 1675191783Srmacklem#if 0 1676191783Srmacklem case VFS_CTL_NOLOCKS: 1677191783Srmacklem val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; 1678191783Srmacklem if (req->oldptr != NULL) { 1679191783Srmacklem error = SYSCTL_OUT(req, &val, sizeof(val)); 1680191783Srmacklem if (error) 1681191783Srmacklem return (error); 1682191783Srmacklem } 1683191783Srmacklem if (req->newptr != NULL) { 1684191783Srmacklem error = SYSCTL_IN(req, &val, sizeof(val)); 1685191783Srmacklem if (error) 1686191783Srmacklem return (error); 1687191783Srmacklem if (val) 1688191783Srmacklem nmp->nm_flag |= NFSMNT_NOLOCKS; 1689191783Srmacklem else 1690191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOLOCKS; 1691191783Srmacklem } 1692191783Srmacklem break; 1693191783Srmacklem#endif 1694191783Srmacklem case VFS_CTL_QUERY: 1695191783Srmacklem mtx_lock(&nmp->nm_mtx); 1696191783Srmacklem if (nmp->nm_state & NFSSTA_TIMEO) 1697191783Srmacklem vq.vq_flags |= VQ_NOTRESP; 1698191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1699191783Srmacklem#if 0 1700191783Srmacklem if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && 1701191783Srmacklem (nmp->nm_state & NFSSTA_LOCKTIMEO)) 1702191783Srmacklem vq.vq_flags |= VQ_NOTRESPLOCK; 1703191783Srmacklem#endif 1704191783Srmacklem error = SYSCTL_OUT(req, &vq, sizeof(vq)); 1705191783Srmacklem break; 1706191783Srmacklem case VFS_CTL_TIMEO: 1707191783Srmacklem if (req->oldptr != NULL) { 1708191783Srmacklem error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, 1709191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1710191783Srmacklem if (error) 1711191783Srmacklem return (error); 1712191783Srmacklem } 1713191783Srmacklem if (req->newptr != NULL) { 1714191783Srmacklem error = vfs_suser(mp, req->td); 1715191783Srmacklem if (error) 1716191783Srmacklem return (error); 1717191783Srmacklem error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, 1718191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1719191783Srmacklem if (error) 1720191783Srmacklem return (error); 1721191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1722191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1723191783Srmacklem } 1724191783Srmacklem break; 1725191783Srmacklem default: 1726191783Srmacklem return (ENOTSUP); 1727191783Srmacklem } 1728191783Srmacklem return (0); 1729191783Srmacklem} 1730191783Srmacklem 1731214048Srmacklem/* 1732255136Srmacklem * Purge any RPCs in progress, so that they will all return errors. 1733255136Srmacklem * This allows dounmount() to continue as far as VFS_UNMOUNT() for a 1734255136Srmacklem * forced dismount. 1735255136Srmacklem */ 1736255136Srmacklemstatic void 1737255136Srmacklemnfs_purge(struct mount *mp) 1738255136Srmacklem{ 1739255136Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1740255136Srmacklem 1741255136Srmacklem newnfs_nmcancelreqs(nmp); 1742255136Srmacklem} 1743255136Srmacklem 1744255136Srmacklem/* 1745214048Srmacklem * Extract the information needed by the nlm from the nfs vnode. 1746214048Srmacklem */ 1747214048Srmacklemstatic void 1748214053Srmacklemnfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp, 1749216931Srmacklem struct sockaddr_storage *sp, int *is_v3p, off_t *sizep, 1750216931Srmacklem struct timeval *timeop) 1751214048Srmacklem{ 1752214048Srmacklem struct nfsmount *nmp; 1753214048Srmacklem struct nfsnode *np = VTONFS(vp); 1754214048Srmacklem 1755214048Srmacklem nmp = VFSTONFS(vp->v_mount); 1756214048Srmacklem if (fhlenp != NULL) 1757214053Srmacklem *fhlenp = (size_t)np->n_fhp->nfh_len; 1758214048Srmacklem if (fhp != NULL) 1759214048Srmacklem bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len); 1760214048Srmacklem if (sp != NULL) 1761214048Srmacklem bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp))); 1762214048Srmacklem if (is_v3p != NULL) 1763214048Srmacklem *is_v3p = NFS_ISV3(vp); 1764214048Srmacklem if (sizep != NULL) 1765214048Srmacklem *sizep = np->n_size; 1766216931Srmacklem if (timeop != NULL) { 1767216931Srmacklem timeop->tv_sec = nmp->nm_timeo / NFS_HZ; 1768216931Srmacklem timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ); 1769216931Srmacklem } 1770214048Srmacklem} 1771214048Srmacklem 1772243782Srmacklem/* 1773243782Srmacklem * This function prints out an option name, based on the conditional 1774243782Srmacklem * argument. 1775243782Srmacklem */ 1776243782Srmacklemstatic __inline void nfscl_printopt(struct nfsmount *nmp, int testval, 1777243782Srmacklem char *opt, char **buf, size_t *blen) 1778243782Srmacklem{ 1779243782Srmacklem int len; 1780243782Srmacklem 1781243782Srmacklem if (testval != 0 && *blen > strlen(opt)) { 1782243782Srmacklem len = snprintf(*buf, *blen, "%s", opt); 1783243782Srmacklem if (len != strlen(opt)) 1784243782Srmacklem printf("EEK!!\n"); 1785243782Srmacklem *buf += len; 1786243782Srmacklem *blen -= len; 1787243782Srmacklem } 1788243782Srmacklem} 1789243782Srmacklem 1790243782Srmacklem/* 1791243782Srmacklem * This function printf out an options integer value. 1792243782Srmacklem */ 1793243782Srmacklemstatic __inline void nfscl_printoptval(struct nfsmount *nmp, int optval, 1794243782Srmacklem char *opt, char **buf, size_t *blen) 1795243782Srmacklem{ 1796243782Srmacklem int len; 1797243782Srmacklem 1798243782Srmacklem if (*blen > strlen(opt) + 1) { 1799243782Srmacklem /* Could result in truncated output string. */ 1800243782Srmacklem len = snprintf(*buf, *blen, "%s=%d", opt, optval); 1801243782Srmacklem if (len < *blen) { 1802243782Srmacklem *buf += len; 1803243782Srmacklem *blen -= len; 1804243782Srmacklem } 1805243782Srmacklem } 1806243782Srmacklem} 1807243782Srmacklem 1808243782Srmacklem/* 1809243782Srmacklem * Load the option flags and values into the buffer. 1810243782Srmacklem */ 1811243782Srmacklemvoid nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen) 1812243782Srmacklem{ 1813243782Srmacklem char *buf; 1814243782Srmacklem size_t blen; 1815243782Srmacklem 1816243782Srmacklem buf = buffer; 1817243782Srmacklem blen = buflen; 1818243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV4) != 0, "nfsv4", &buf, 1819243782Srmacklem &blen); 1820244056Srmacklem if ((nmp->nm_flag & NFSMNT_NFSV4) != 0) { 1821244056Srmacklem nfscl_printoptval(nmp, nmp->nm_minorvers, ",minorversion", &buf, 1822244056Srmacklem &blen); 1823244056Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_PNFS) != 0, ",pnfs", 1824244056Srmacklem &buf, &blen); 1825244056Srmacklem } 1826243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV3) != 0, "nfsv3", &buf, 1827243782Srmacklem &blen); 1828243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0, 1829243782Srmacklem "nfsv2", &buf, &blen); 1830243782Srmacklem nfscl_printopt(nmp, nmp->nm_sotype == SOCK_STREAM, ",tcp", &buf, &blen); 1831243782Srmacklem nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen); 1832243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport", 1833243782Srmacklem &buf, &blen); 1834243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn", 1835243782Srmacklem &buf, &blen); 1836243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf, 1837243782Srmacklem &blen); 1838243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) != 0, ",soft", &buf, 1839243782Srmacklem &blen); 1840243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_INT) != 0, ",intr", &buf, 1841243782Srmacklem &blen); 1842243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) == 0, ",cto", &buf, 1843243782Srmacklem &blen); 1844243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf, 1845243782Srmacklem &blen); 1846260107Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NONCONTIGWR) != 0, 1847260107Srmacklem ",noncontigwr", &buf, &blen); 1848243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) == 1849243782Srmacklem 0, ",lockd", &buf, &blen); 1850243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) == 1851243782Srmacklem NFSMNT_NOLOCKD, ",nolockd", &buf, &blen); 1852243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RDIRPLUS) != 0, ",rdirplus", 1853243782Srmacklem &buf, &blen); 1854243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_KERB) == 0, ",sec=sys", 1855243782Srmacklem &buf, &blen); 1856243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY | 1857243782Srmacklem NFSMNT_PRIVACY)) == NFSMNT_KERB, ",sec=krb5", &buf, &blen); 1858243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY | 1859243782Srmacklem NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_INTEGRITY), ",sec=krb5i", 1860243782Srmacklem &buf, &blen); 1861243782Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY | 1862243782Srmacklem NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_PRIVACY), ",sec=krb5p", 1863243782Srmacklem &buf, &blen); 1864243782Srmacklem nfscl_printoptval(nmp, nmp->nm_acdirmin, ",acdirmin", &buf, &blen); 1865243782Srmacklem nfscl_printoptval(nmp, nmp->nm_acdirmax, ",acdirmax", &buf, &blen); 1866243782Srmacklem nfscl_printoptval(nmp, nmp->nm_acregmin, ",acregmin", &buf, &blen); 1867243782Srmacklem nfscl_printoptval(nmp, nmp->nm_acregmax, ",acregmax", &buf, &blen); 1868243782Srmacklem nfscl_printoptval(nmp, nmp->nm_nametimeo, ",nametimeo", &buf, &blen); 1869243782Srmacklem nfscl_printoptval(nmp, nmp->nm_negnametimeo, ",negnametimeo", &buf, 1870243782Srmacklem &blen); 1871243782Srmacklem nfscl_printoptval(nmp, nmp->nm_rsize, ",rsize", &buf, &blen); 1872243782Srmacklem nfscl_printoptval(nmp, nmp->nm_wsize, ",wsize", &buf, &blen); 1873243782Srmacklem nfscl_printoptval(nmp, nmp->nm_readdirsize, ",readdirsize", &buf, 1874243782Srmacklem &blen); 1875243782Srmacklem nfscl_printoptval(nmp, nmp->nm_readahead, ",readahead", &buf, &blen); 1876243782Srmacklem nfscl_printoptval(nmp, nmp->nm_wcommitsize, ",wcommitsize", &buf, 1877243782Srmacklem &blen); 1878243782Srmacklem nfscl_printoptval(nmp, nmp->nm_timeo, ",timeout", &buf, &blen); 1879243782Srmacklem nfscl_printoptval(nmp, nmp->nm_retry, ",retrans", &buf, &blen); 1880243782Srmacklem} 1881243782Srmacklem 1882