nfs_clvfsops.c revision 214048
1191783Srmacklem/*- 2191783Srmacklem * Copyright (c) 1989, 1993, 1995 3191783Srmacklem * The Regents of the University of California. All rights reserved. 4191783Srmacklem * 5191783Srmacklem * This code is derived from software contributed to Berkeley by 6191783Srmacklem * Rick Macklem at The University of Guelph. 7191783Srmacklem * 8191783Srmacklem * Redistribution and use in source and binary forms, with or without 9191783Srmacklem * modification, are permitted provided that the following conditions 10191783Srmacklem * are met: 11191783Srmacklem * 1. Redistributions of source code must retain the above copyright 12191783Srmacklem * notice, this list of conditions and the following disclaimer. 13191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright 14191783Srmacklem * notice, this list of conditions and the following disclaimer in the 15191783Srmacklem * documentation and/or other materials provided with the distribution. 16191783Srmacklem * 4. Neither the name of the University nor the names of its contributors 17191783Srmacklem * may be used to endorse or promote products derived from this software 18191783Srmacklem * without specific prior written permission. 19191783Srmacklem * 20191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21191783Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22191783Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23191783Srmacklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24191783Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25191783Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26191783Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27191783Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28191783Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29191783Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30191783Srmacklem * SUCH DAMAGE. 31191783Srmacklem * 32191783Srmacklem * from nfs_vfsops.c 8.12 (Berkeley) 5/20/95 33191783Srmacklem */ 34191783Srmacklem 35191783Srmacklem#include <sys/cdefs.h> 36191783Srmacklem__FBSDID("$FreeBSD: head/sys/fs/nfsclient/nfs_clvfsops.c 214048 2010-10-19 00:20:00Z rmacklem $"); 37191783Srmacklem 38191783Srmacklem 39191783Srmacklem#include "opt_bootp.h" 40191783Srmacklem#include "opt_nfsroot.h" 41191783Srmacklem 42191783Srmacklem#include <sys/param.h> 43191783Srmacklem#include <sys/systm.h> 44191783Srmacklem#include <sys/kernel.h> 45191783Srmacklem#include <sys/bio.h> 46191783Srmacklem#include <sys/buf.h> 47191783Srmacklem#include <sys/clock.h> 48193066Sjamie#include <sys/jail.h> 49191783Srmacklem#include <sys/lock.h> 50191783Srmacklem#include <sys/malloc.h> 51191783Srmacklem#include <sys/mbuf.h> 52191783Srmacklem#include <sys/module.h> 53191783Srmacklem#include <sys/mount.h> 54191783Srmacklem#include <sys/proc.h> 55191783Srmacklem#include <sys/socket.h> 56191783Srmacklem#include <sys/socketvar.h> 57191783Srmacklem#include <sys/sockio.h> 58191783Srmacklem#include <sys/sysctl.h> 59191783Srmacklem#include <sys/vnode.h> 60191783Srmacklem#include <sys/signalvar.h> 61191783Srmacklem 62191783Srmacklem#include <vm/vm.h> 63191783Srmacklem#include <vm/vm_extern.h> 64191783Srmacklem#include <vm/uma.h> 65191783Srmacklem 66191783Srmacklem#include <net/if.h> 67191783Srmacklem#include <net/route.h> 68191783Srmacklem#include <netinet/in.h> 69191783Srmacklem 70191783Srmacklem#include <fs/nfs/nfsport.h> 71191783Srmacklem#include <fs/nfsclient/nfsnode.h> 72191783Srmacklem#include <fs/nfsclient/nfsmount.h> 73191783Srmacklem#include <fs/nfsclient/nfs.h> 74191783Srmacklem#include <fs/nfsclient/nfsdiskless.h> 75191783Srmacklem 76191783Srmacklemextern int nfscl_ticks; 77191783Srmacklemextern struct timeval nfsboottime; 78191783Srmacklemextern struct nfsstats newnfsstats; 79191783Srmacklem 80191783SrmacklemMALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header"); 81191783SrmacklemMALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct"); 82191783Srmacklem 83191783SrmacklemSYSCTL_DECL(_vfs_newnfs); 84191783SrmacklemSYSCTL_STRUCT(_vfs_newnfs, NFS_NFSSTATS, nfsstats, CTLFLAG_RW, 85191783Srmacklem &newnfsstats, nfsstats, "S,nfsstats"); 86191783Srmacklemstatic int nfs_ip_paranoia = 1; 87191783SrmacklemSYSCTL_INT(_vfs_newnfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW, 88191783Srmacklem &nfs_ip_paranoia, 0, ""); 89191783Srmacklemstatic int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY; 90191783SrmacklemSYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_INITIAL_DELAY, 91191783Srmacklem downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, ""); 92191783Srmacklem/* how long between console messages "nfs server foo not responding" */ 93191783Srmacklemstatic int nfs_tprintf_delay = NFS_TPRINTF_DELAY; 94191783SrmacklemSYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_DELAY, 95191783Srmacklem downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, ""); 96191783Srmacklem 97192585Srmacklemstatic void nfs_sec_name(char *, int *); 98191783Srmacklemstatic void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, 99214048Srmacklem struct nfs_args *argp, const char *, struct ucred *, 100214048Srmacklem struct thread *); 101191783Srmacklemstatic int mountnfs(struct nfs_args *, struct mount *, 102191783Srmacklem struct sockaddr *, char *, u_char *, u_char *, u_char *, 103203303Srmacklem struct vnode **, struct ucred *, struct thread *, int); 104214048Srmacklemstatic void nfs_getnlminfo(struct vnode *, uint8_t *, int *, 105214048Srmacklem struct sockaddr_storage *, int *, off_t *); 106191783Srmacklemstatic vfs_mount_t nfs_mount; 107191783Srmacklemstatic vfs_cmount_t nfs_cmount; 108191783Srmacklemstatic vfs_unmount_t nfs_unmount; 109191783Srmacklemstatic vfs_root_t nfs_root; 110191783Srmacklemstatic vfs_statfs_t nfs_statfs; 111191783Srmacklemstatic vfs_sync_t nfs_sync; 112191783Srmacklemstatic vfs_sysctl_t nfs_sysctl; 113191783Srmacklem 114191783Srmacklem/* 115191783Srmacklem * nfs vfs operations. 116191783Srmacklem */ 117191783Srmacklemstatic struct vfsops nfs_vfsops = { 118191783Srmacklem .vfs_init = ncl_init, 119191783Srmacklem .vfs_mount = nfs_mount, 120191783Srmacklem .vfs_cmount = nfs_cmount, 121191783Srmacklem .vfs_root = nfs_root, 122191783Srmacklem .vfs_statfs = nfs_statfs, 123191783Srmacklem .vfs_sync = nfs_sync, 124191783Srmacklem .vfs_uninit = ncl_uninit, 125191783Srmacklem .vfs_unmount = nfs_unmount, 126191783Srmacklem .vfs_sysctl = nfs_sysctl, 127191783Srmacklem}; 128191783SrmacklemVFS_SET(nfs_vfsops, newnfs, VFCF_NETWORK); 129191783Srmacklem 130191783Srmacklem/* So that loader and kldload(2) can find us, wherever we are.. */ 131191783SrmacklemMODULE_VERSION(newnfs, 1); 132191783Srmacklem 133191783Srmacklem/* 134191783Srmacklem * This structure must be filled in by a primary bootstrap or bootstrap 135191783Srmacklem * server for a diskless/dataless machine. It is initialized below just 136191783Srmacklem * to ensure that it is allocated to initialized data (.data not .bss). 137191783Srmacklem */ 138191783Srmacklemstruct nfs_diskless newnfs_diskless = { { { 0 } } }; 139191783Srmacklemstruct nfsv3_diskless newnfsv3_diskless = { { { 0 } } }; 140191783Srmacklemint newnfs_diskless_valid = 0; 141191783Srmacklem 142191783SrmacklemSYSCTL_INT(_vfs_newnfs, OID_AUTO, diskless_valid, CTLFLAG_RD, 143192145Srmacklem &newnfs_diskless_valid, 0, 144192145Srmacklem "Has the diskless struct been filled correctly"); 145191783Srmacklem 146191783SrmacklemSYSCTL_STRING(_vfs_newnfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD, 147192145Srmacklem newnfsv3_diskless.root_hostnam, 0, "Path to nfs root"); 148191783Srmacklem 149191783SrmacklemSYSCTL_OPAQUE(_vfs_newnfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD, 150192145Srmacklem &newnfsv3_diskless.root_saddr, sizeof newnfsv3_diskless.root_saddr, 151192145Srmacklem "%Ssockaddr_in", "Diskless root nfs address"); 152191783Srmacklem 153191783Srmacklem 154191783Srmacklemvoid newnfsargs_ntoh(struct nfs_args *); 155191783Srmacklemstatic int nfs_mountdiskless(char *, 156191783Srmacklem struct sockaddr_in *, struct nfs_args *, 157191783Srmacklem struct thread *, struct vnode **, struct mount *); 158191783Srmacklemstatic void nfs_convert_diskless(void); 159191783Srmacklemstatic void nfs_convert_oargs(struct nfs_args *args, 160191783Srmacklem struct onfs_args *oargs); 161191783Srmacklem 162191783Srmacklemint 163191783Srmacklemnewnfs_iosize(struct nfsmount *nmp) 164191783Srmacklem{ 165191783Srmacklem int iosize, maxio; 166191783Srmacklem 167191783Srmacklem /* First, set the upper limit for iosize */ 168191783Srmacklem if (nmp->nm_flag & NFSMNT_NFSV4) { 169191783Srmacklem maxio = NFS_MAXBSIZE; 170191783Srmacklem } else if (nmp->nm_flag & NFSMNT_NFSV3) { 171191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 172191783Srmacklem maxio = NFS_MAXDGRAMDATA; 173191783Srmacklem else 174191783Srmacklem maxio = NFS_MAXBSIZE; 175191783Srmacklem } else { 176191783Srmacklem maxio = NFS_V2MAXDATA; 177191783Srmacklem } 178191783Srmacklem if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0) 179191783Srmacklem nmp->nm_rsize = maxio; 180191783Srmacklem if (nmp->nm_rsize > MAXBSIZE) 181191783Srmacklem nmp->nm_rsize = MAXBSIZE; 182191783Srmacklem if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0) 183191783Srmacklem nmp->nm_readdirsize = maxio; 184191783Srmacklem if (nmp->nm_readdirsize > nmp->nm_rsize) 185191783Srmacklem nmp->nm_readdirsize = nmp->nm_rsize; 186191783Srmacklem if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0) 187191783Srmacklem nmp->nm_wsize = maxio; 188191783Srmacklem if (nmp->nm_wsize > MAXBSIZE) 189191783Srmacklem nmp->nm_wsize = MAXBSIZE; 190191783Srmacklem 191191783Srmacklem /* 192191783Srmacklem * Calculate the size used for io buffers. Use the larger 193191783Srmacklem * of the two sizes to minimise nfs requests but make sure 194191783Srmacklem * that it is at least one VM page to avoid wasting buffer 195191783Srmacklem * space. 196191783Srmacklem */ 197191783Srmacklem iosize = imax(nmp->nm_rsize, nmp->nm_wsize); 198191783Srmacklem iosize = imax(iosize, PAGE_SIZE); 199191783Srmacklem nmp->nm_mountp->mnt_stat.f_iosize = iosize; 200191783Srmacklem return (iosize); 201191783Srmacklem} 202191783Srmacklem 203191783Srmacklemstatic void 204191783Srmacklemnfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs) 205191783Srmacklem{ 206191783Srmacklem 207191783Srmacklem args->version = NFS_ARGSVERSION; 208191783Srmacklem args->addr = oargs->addr; 209191783Srmacklem args->addrlen = oargs->addrlen; 210191783Srmacklem args->sotype = oargs->sotype; 211191783Srmacklem args->proto = oargs->proto; 212191783Srmacklem args->fh = oargs->fh; 213191783Srmacklem args->fhsize = oargs->fhsize; 214191783Srmacklem args->flags = oargs->flags; 215191783Srmacklem args->wsize = oargs->wsize; 216191783Srmacklem args->rsize = oargs->rsize; 217191783Srmacklem args->readdirsize = oargs->readdirsize; 218191783Srmacklem args->timeo = oargs->timeo; 219191783Srmacklem args->retrans = oargs->retrans; 220191783Srmacklem args->readahead = oargs->readahead; 221191783Srmacklem args->hostname = oargs->hostname; 222191783Srmacklem} 223191783Srmacklem 224191783Srmacklemstatic void 225191783Srmacklemnfs_convert_diskless(void) 226191783Srmacklem{ 227191783Srmacklem 228191783Srmacklem bcopy(&newnfs_diskless.myif, &newnfsv3_diskless.myif, 229192145Srmacklem sizeof (struct ifaliasreq)); 230191783Srmacklem bcopy(&newnfs_diskless.mygateway, &newnfsv3_diskless.mygateway, 231192145Srmacklem sizeof (struct sockaddr_in)); 232192145Srmacklem nfs_convert_oargs(&newnfsv3_diskless.root_args, 233192145Srmacklem &newnfs_diskless.root_args); 234191783Srmacklem if (newnfsv3_diskless.root_args.flags & NFSMNT_NFSV3) { 235191783Srmacklem newnfsv3_diskless.root_fhsize = NFSX_MYFH; 236192145Srmacklem bcopy(newnfs_diskless.root_fh, newnfsv3_diskless.root_fh, 237192145Srmacklem NFSX_MYFH); 238191783Srmacklem } else { 239191783Srmacklem newnfsv3_diskless.root_fhsize = NFSX_V2FH; 240192145Srmacklem bcopy(newnfs_diskless.root_fh, newnfsv3_diskless.root_fh, 241192145Srmacklem NFSX_V2FH); 242191783Srmacklem } 243191783Srmacklem bcopy(&newnfs_diskless.root_saddr,&newnfsv3_diskless.root_saddr, 244192145Srmacklem sizeof(struct sockaddr_in)); 245192145Srmacklem bcopy(newnfs_diskless.root_hostnam, newnfsv3_diskless.root_hostnam, 246192145Srmacklem MNAMELEN); 247191783Srmacklem newnfsv3_diskless.root_time = newnfs_diskless.root_time; 248191783Srmacklem bcopy(newnfs_diskless.my_hostnam, newnfsv3_diskless.my_hostnam, 249192145Srmacklem MAXHOSTNAMELEN); 250191783Srmacklem newnfs_diskless_valid = 3; 251191783Srmacklem} 252191783Srmacklem 253191783Srmacklem/* 254191783Srmacklem * nfs statfs call 255191783Srmacklem */ 256191783Srmacklemstatic int 257191990Sattilionfs_statfs(struct mount *mp, struct statfs *sbp) 258191783Srmacklem{ 259191783Srmacklem struct vnode *vp; 260191990Sattilio struct thread *td; 261191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 262191783Srmacklem struct nfsvattr nfsva; 263191783Srmacklem struct nfsfsinfo fs; 264191783Srmacklem struct nfsstatfs sb; 265191783Srmacklem int error = 0, attrflag, gotfsinfo = 0, ret; 266191783Srmacklem struct nfsnode *np; 267191783Srmacklem 268191990Sattilio td = curthread; 269191990Sattilio 270191783Srmacklem error = vfs_busy(mp, MBF_NOWAIT); 271191783Srmacklem if (error) 272191783Srmacklem return (error); 273191783Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np); 274191783Srmacklem if (error) { 275191783Srmacklem vfs_unbusy(mp); 276191783Srmacklem return (error); 277191783Srmacklem } 278191783Srmacklem vp = NFSTOV(np); 279191783Srmacklem mtx_lock(&nmp->nm_mtx); 280191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 281191783Srmacklem mtx_unlock(&nmp->nm_mtx); 282191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva, 283191783Srmacklem &attrflag, NULL); 284191783Srmacklem if (!error) 285191783Srmacklem gotfsinfo = 1; 286191783Srmacklem } else 287191783Srmacklem mtx_unlock(&nmp->nm_mtx); 288191783Srmacklem if (!error) 289191783Srmacklem error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, 290191783Srmacklem &attrflag, NULL); 291191783Srmacklem if (attrflag == 0) { 292191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 293191783Srmacklem td->td_ucred, td, &nfsva, NULL); 294191783Srmacklem if (ret) { 295191783Srmacklem /* 296191783Srmacklem * Just set default values to get things going. 297191783Srmacklem */ 298191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 299191783Srmacklem nfsva.na_vattr.va_type = VDIR; 300191783Srmacklem nfsva.na_vattr.va_mode = 0777; 301191783Srmacklem nfsva.na_vattr.va_nlink = 100; 302191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 303191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 304191783Srmacklem nfsva.na_vattr.va_fileid = 2; 305191783Srmacklem nfsva.na_vattr.va_gen = 1; 306191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 307191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 308191783Srmacklem } 309191783Srmacklem } 310191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 311191783Srmacklem if (!error) { 312191783Srmacklem mtx_lock(&nmp->nm_mtx); 313191783Srmacklem if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4)) 314191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 315191783Srmacklem nfscl_loadsbinfo(nmp, &sb, sbp); 316191783Srmacklem sbp->f_flags = nmp->nm_flag; 317191783Srmacklem sbp->f_iosize = newnfs_iosize(nmp); 318191783Srmacklem mtx_unlock(&nmp->nm_mtx); 319191783Srmacklem if (sbp != &mp->mnt_stat) { 320191783Srmacklem bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 321191783Srmacklem bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 322191783Srmacklem } 323191783Srmacklem strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 324191783Srmacklem } else if (NFS_ISV4(vp)) { 325191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 326191783Srmacklem } 327191783Srmacklem vput(vp); 328191783Srmacklem vfs_unbusy(mp); 329191783Srmacklem return (error); 330191783Srmacklem} 331191783Srmacklem 332191783Srmacklem/* 333191783Srmacklem * nfs version 3 fsinfo rpc call 334191783Srmacklem */ 335191783Srmacklemint 336191783Srmacklemncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, 337191783Srmacklem struct thread *td) 338191783Srmacklem{ 339191783Srmacklem struct nfsfsinfo fs; 340191783Srmacklem struct nfsvattr nfsva; 341191783Srmacklem int error, attrflag; 342191783Srmacklem 343191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL); 344191783Srmacklem if (!error) { 345191783Srmacklem if (attrflag) 346191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 347191783Srmacklem 1); 348191783Srmacklem mtx_lock(&nmp->nm_mtx); 349191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 350191783Srmacklem mtx_unlock(&nmp->nm_mtx); 351191783Srmacklem } 352191783Srmacklem return (error); 353191783Srmacklem} 354191783Srmacklem 355191783Srmacklem/* 356191783Srmacklem * Mount a remote root fs via. nfs. This depends on the info in the 357191783Srmacklem * newnfs_diskless structure that has been filled in properly by some primary 358191783Srmacklem * bootstrap. 359191783Srmacklem * It goes something like this: 360191783Srmacklem * - do enough of "ifconfig" by calling ifioctl() so that the system 361191783Srmacklem * can talk to the server 362191783Srmacklem * - If newnfs_diskless.mygateway is filled in, use that address as 363191783Srmacklem * a default gateway. 364191783Srmacklem * - build the rootfs mount point and call mountnfs() to do the rest. 365191783Srmacklem * 366191783Srmacklem * It is assumed to be safe to read, modify, and write the nfsv3_diskless 367191783Srmacklem * structure, as well as other global NFS client variables here, as 368192145Srmacklem * nfs_mountroot() will be called once in the boot before any other NFS 369191783Srmacklem * client activity occurs. 370191783Srmacklem */ 371191783Srmacklemint 372192145Srmacklemncl_mountroot(struct mount *mp) 373191783Srmacklem{ 374192145Srmacklem struct thread *td = curthread; 375191783Srmacklem struct nfsv3_diskless *nd = &newnfsv3_diskless; 376191783Srmacklem struct socket *so; 377191783Srmacklem struct vnode *vp; 378191783Srmacklem struct ifreq ir; 379193066Sjamie int error; 380191783Srmacklem u_long l; 381191783Srmacklem char buf[128]; 382191783Srmacklem char *cp; 383191783Srmacklem 384191783Srmacklem#if defined(BOOTP_NFSROOT) && defined(BOOTP) 385192145Srmacklem bootpc_init(); /* use bootp to get nfs_diskless filled in */ 386191783Srmacklem#elif defined(NFS_ROOT) 387191783Srmacklem nfs_setup_diskless(); 388191783Srmacklem#endif 389191783Srmacklem 390191783Srmacklem if (newnfs_diskless_valid == 0) 391191783Srmacklem return (-1); 392191783Srmacklem if (newnfs_diskless_valid == 1) 393191783Srmacklem nfs_convert_diskless(); 394191783Srmacklem 395191783Srmacklem /* 396191783Srmacklem * XXX splnet, so networks will receive... 397191783Srmacklem */ 398191783Srmacklem splnet(); 399191783Srmacklem 400191783Srmacklem /* 401191783Srmacklem * Do enough of ifconfig(8) so that the critical net interface can 402191783Srmacklem * talk to the server. 403191783Srmacklem */ 404191783Srmacklem error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0, 405191783Srmacklem td->td_ucred, td); 406191783Srmacklem if (error) 407192145Srmacklem panic("nfs_mountroot: socreate(%04x): %d", 408191783Srmacklem nd->myif.ifra_addr.sa_family, error); 409191783Srmacklem 410191783Srmacklem#if 0 /* XXX Bad idea */ 411191783Srmacklem /* 412191783Srmacklem * We might not have been told the right interface, so we pass 413191783Srmacklem * over the first ten interfaces of the same kind, until we get 414191783Srmacklem * one of them configured. 415191783Srmacklem */ 416191783Srmacklem 417191783Srmacklem for (i = strlen(nd->myif.ifra_name) - 1; 418191783Srmacklem nd->myif.ifra_name[i] >= '0' && 419191783Srmacklem nd->myif.ifra_name[i] <= '9'; 420191783Srmacklem nd->myif.ifra_name[i] ++) { 421191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 422191783Srmacklem if(!error) 423191783Srmacklem break; 424191783Srmacklem } 425191783Srmacklem#endif 426191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 427191783Srmacklem if (error) 428192145Srmacklem panic("nfs_mountroot: SIOCAIFADDR: %d", error); 429191783Srmacklem if ((cp = getenv("boot.netif.mtu")) != NULL) { 430191783Srmacklem ir.ifr_mtu = strtol(cp, NULL, 10); 431191783Srmacklem bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); 432191783Srmacklem freeenv(cp); 433191783Srmacklem error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); 434191783Srmacklem if (error) 435192145Srmacklem printf("nfs_mountroot: SIOCSIFMTU: %d", error); 436191783Srmacklem } 437191783Srmacklem soclose(so); 438191783Srmacklem 439191783Srmacklem /* 440191783Srmacklem * If the gateway field is filled in, set it as the default route. 441191783Srmacklem * Note that pxeboot will set a default route of 0 if the route 442191783Srmacklem * is not set by the DHCP server. Check also for a value of 0 443191783Srmacklem * to avoid panicking inappropriately in that situation. 444191783Srmacklem */ 445191783Srmacklem if (nd->mygateway.sin_len != 0 && 446191783Srmacklem nd->mygateway.sin_addr.s_addr != 0) { 447191783Srmacklem struct sockaddr_in mask, sin; 448191783Srmacklem 449191783Srmacklem bzero((caddr_t)&mask, sizeof(mask)); 450191783Srmacklem sin = mask; 451191783Srmacklem sin.sin_family = AF_INET; 452191783Srmacklem sin.sin_len = sizeof(sin); 453192145Srmacklem /* XXX MRT use table 0 for this sort of thing */ 454191783Srmacklem error = rtrequest(RTM_ADD, (struct sockaddr *)&sin, 455191783Srmacklem (struct sockaddr *)&nd->mygateway, 456191783Srmacklem (struct sockaddr *)&mask, 457191783Srmacklem RTF_UP | RTF_GATEWAY, NULL); 458191783Srmacklem if (error) 459192145Srmacklem panic("nfs_mountroot: RTM_ADD: %d", error); 460191783Srmacklem } 461191783Srmacklem 462191783Srmacklem /* 463191783Srmacklem * Create the rootfs mount point. 464191783Srmacklem */ 465191783Srmacklem nd->root_args.fh = nd->root_fh; 466191783Srmacklem nd->root_args.fhsize = nd->root_fhsize; 467191783Srmacklem l = ntohl(nd->root_saddr.sin_addr.s_addr); 468191783Srmacklem snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", 469191783Srmacklem (l >> 24) & 0xff, (l >> 16) & 0xff, 470191783Srmacklem (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); 471191783Srmacklem printf("NFS ROOT: %s\n", buf); 472192145Srmacklem nd->root_args.hostname = buf; 473191783Srmacklem if ((error = nfs_mountdiskless(buf, 474191783Srmacklem &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { 475191783Srmacklem return (error); 476191783Srmacklem } 477191783Srmacklem 478191783Srmacklem /* 479191783Srmacklem * This is not really an nfs issue, but it is much easier to 480191783Srmacklem * set hostname here and then let the "/etc/rc.xxx" files 481191783Srmacklem * mount the right /var based upon its preset value. 482191783Srmacklem */ 483193066Sjamie mtx_lock(&prison0.pr_mtx); 484194118Sjamie strlcpy(prison0.pr_hostname, nd->my_hostnam, 485194118Sjamie sizeof(prison0.pr_hostname)); 486193066Sjamie mtx_unlock(&prison0.pr_mtx); 487191783Srmacklem inittodr(ntohl(nd->root_time)); 488191783Srmacklem return (0); 489191783Srmacklem} 490191783Srmacklem 491191783Srmacklem/* 492191783Srmacklem * Internal version of mount system call for diskless setup. 493191783Srmacklem */ 494191783Srmacklemstatic int 495191783Srmacklemnfs_mountdiskless(char *path, 496191783Srmacklem struct sockaddr_in *sin, struct nfs_args *args, struct thread *td, 497191783Srmacklem struct vnode **vpp, struct mount *mp) 498191783Srmacklem{ 499191783Srmacklem struct sockaddr *nam; 500191783Srmacklem int error; 501191783Srmacklem 502191783Srmacklem nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); 503191783Srmacklem if ((error = mountnfs(args, mp, nam, path, NULL, NULL, NULL, vpp, 504203303Srmacklem td->td_ucred, td, NFS_DEFAULT_NEGNAMETIMEO)) != 0) { 505192145Srmacklem printf("nfs_mountroot: mount %s on /: %d\n", path, error); 506191783Srmacklem return (error); 507191783Srmacklem } 508191783Srmacklem return (0); 509191783Srmacklem} 510191783Srmacklem 511191783Srmacklemstatic void 512192585Srmacklemnfs_sec_name(char *sec, int *flagsp) 513192585Srmacklem{ 514192585Srmacklem if (!strcmp(sec, "krb5")) 515192585Srmacklem *flagsp |= NFSMNT_KERB; 516192585Srmacklem else if (!strcmp(sec, "krb5i")) 517192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY); 518192585Srmacklem else if (!strcmp(sec, "krb5p")) 519192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY); 520192585Srmacklem} 521192585Srmacklem 522192585Srmacklemstatic void 523191783Srmacklemnfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, 524214048Srmacklem const char *hostname, struct ucred *cred, struct thread *td) 525191783Srmacklem{ 526191783Srmacklem int s; 527191783Srmacklem int adjsock; 528214048Srmacklem char *p; 529191783Srmacklem 530191783Srmacklem s = splnet(); 531191783Srmacklem 532191783Srmacklem /* 533191783Srmacklem * Set read-only flag if requested; otherwise, clear it if this is 534191783Srmacklem * an update. If this is not an update, then either the read-only 535191783Srmacklem * flag is already clear, or this is a root mount and it was set 536191783Srmacklem * intentionally at some previous point. 537191783Srmacklem */ 538191783Srmacklem if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) { 539191783Srmacklem MNT_ILOCK(mp); 540191783Srmacklem mp->mnt_flag |= MNT_RDONLY; 541191783Srmacklem MNT_IUNLOCK(mp); 542191783Srmacklem } else if (mp->mnt_flag & MNT_UPDATE) { 543191783Srmacklem MNT_ILOCK(mp); 544191783Srmacklem mp->mnt_flag &= ~MNT_RDONLY; 545191783Srmacklem MNT_IUNLOCK(mp); 546191783Srmacklem } 547191783Srmacklem 548191783Srmacklem /* 549191783Srmacklem * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 550191783Srmacklem * no sense in that context. Also, set up appropriate retransmit 551191783Srmacklem * and soft timeout behavior. 552191783Srmacklem */ 553191783Srmacklem if (argp->sotype == SOCK_STREAM) { 554191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOCONN; 555191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 556191783Srmacklem } 557191783Srmacklem 558191783Srmacklem /* Also clear RDIRPLUS if not NFSv3, it crashes some servers */ 559191783Srmacklem if ((argp->flags & NFSMNT_NFSV3) == 0) 560191783Srmacklem nmp->nm_flag &= ~NFSMNT_RDIRPLUS; 561191783Srmacklem 562191783Srmacklem /* Also re-bind if we're switching to/from a connected UDP socket */ 563191783Srmacklem adjsock = ((nmp->nm_flag & NFSMNT_NOCONN) != 564191783Srmacklem (argp->flags & NFSMNT_NOCONN)); 565191783Srmacklem 566191783Srmacklem /* Update flags atomically. Don't change the lock bits. */ 567191783Srmacklem nmp->nm_flag = argp->flags | nmp->nm_flag; 568191783Srmacklem splx(s); 569191783Srmacklem 570191783Srmacklem if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 571191783Srmacklem nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 572191783Srmacklem if (nmp->nm_timeo < NFS_MINTIMEO) 573191783Srmacklem nmp->nm_timeo = NFS_MINTIMEO; 574191783Srmacklem else if (nmp->nm_timeo > NFS_MAXTIMEO) 575191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 576191783Srmacklem } 577191783Srmacklem 578191783Srmacklem if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 579191783Srmacklem nmp->nm_retry = argp->retrans; 580191783Srmacklem if (nmp->nm_retry > NFS_MAXREXMIT) 581191783Srmacklem nmp->nm_retry = NFS_MAXREXMIT; 582191783Srmacklem } 583191783Srmacklem 584191783Srmacklem if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 585191783Srmacklem nmp->nm_wsize = argp->wsize; 586191783Srmacklem /* Round down to multiple of blocksize */ 587191783Srmacklem nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); 588191783Srmacklem if (nmp->nm_wsize <= 0) 589191783Srmacklem nmp->nm_wsize = NFS_FABLKSIZE; 590191783Srmacklem } 591191783Srmacklem 592191783Srmacklem if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 593191783Srmacklem nmp->nm_rsize = argp->rsize; 594191783Srmacklem /* Round down to multiple of blocksize */ 595191783Srmacklem nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); 596191783Srmacklem if (nmp->nm_rsize <= 0) 597191783Srmacklem nmp->nm_rsize = NFS_FABLKSIZE; 598191783Srmacklem } 599191783Srmacklem 600191783Srmacklem if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 601191783Srmacklem nmp->nm_readdirsize = argp->readdirsize; 602191783Srmacklem } 603191783Srmacklem 604191783Srmacklem if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) 605191783Srmacklem nmp->nm_acregmin = argp->acregmin; 606191783Srmacklem else 607191783Srmacklem nmp->nm_acregmin = NFS_MINATTRTIMO; 608191783Srmacklem if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) 609191783Srmacklem nmp->nm_acregmax = argp->acregmax; 610191783Srmacklem else 611191783Srmacklem nmp->nm_acregmax = NFS_MAXATTRTIMO; 612191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) 613191783Srmacklem nmp->nm_acdirmin = argp->acdirmin; 614191783Srmacklem else 615191783Srmacklem nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; 616191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) 617191783Srmacklem nmp->nm_acdirmax = argp->acdirmax; 618191783Srmacklem else 619191783Srmacklem nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; 620191783Srmacklem if (nmp->nm_acdirmin > nmp->nm_acdirmax) 621191783Srmacklem nmp->nm_acdirmin = nmp->nm_acdirmax; 622191783Srmacklem if (nmp->nm_acregmin > nmp->nm_acregmax) 623191783Srmacklem nmp->nm_acregmin = nmp->nm_acregmax; 624191783Srmacklem 625191783Srmacklem if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { 626191783Srmacklem if (argp->readahead <= NFS_MAXRAHEAD) 627191783Srmacklem nmp->nm_readahead = argp->readahead; 628191783Srmacklem else 629191783Srmacklem nmp->nm_readahead = NFS_MAXRAHEAD; 630191783Srmacklem } 631191783Srmacklem if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) { 632191783Srmacklem if (argp->wcommitsize < nmp->nm_wsize) 633191783Srmacklem nmp->nm_wcommitsize = nmp->nm_wsize; 634191783Srmacklem else 635191783Srmacklem nmp->nm_wcommitsize = argp->wcommitsize; 636191783Srmacklem } 637191783Srmacklem 638191783Srmacklem adjsock |= ((nmp->nm_sotype != argp->sotype) || 639191783Srmacklem (nmp->nm_soproto != argp->proto)); 640191783Srmacklem 641191783Srmacklem if (nmp->nm_client != NULL && adjsock) { 642191783Srmacklem int haslock = 0, error = 0; 643191783Srmacklem 644191783Srmacklem if (nmp->nm_sotype == SOCK_STREAM) { 645191783Srmacklem error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock); 646191783Srmacklem if (!error) 647191783Srmacklem haslock = 1; 648191783Srmacklem } 649191783Srmacklem if (!error) { 650191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 651191783Srmacklem if (haslock) 652191783Srmacklem newnfs_sndunlock(&nmp->nm_sockreq.nr_lock); 653191783Srmacklem nmp->nm_sotype = argp->sotype; 654191783Srmacklem nmp->nm_soproto = argp->proto; 655191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 656191783Srmacklem while (newnfs_connect(nmp, &nmp->nm_sockreq, 657191783Srmacklem cred, td, 0)) { 658191783Srmacklem printf("newnfs_args: retrying connect\n"); 659207170Srmacklem (void) nfs_catnap(PSOCK, 0, "newnfscon"); 660191783Srmacklem } 661191783Srmacklem } 662191783Srmacklem } else { 663191783Srmacklem nmp->nm_sotype = argp->sotype; 664191783Srmacklem nmp->nm_soproto = argp->proto; 665191783Srmacklem } 666214048Srmacklem 667214048Srmacklem if (hostname != NULL) { 668214048Srmacklem strlcpy(nmp->nm_hostname, hostname, 669214048Srmacklem sizeof(nmp->nm_hostname)); 670214048Srmacklem p = strchr(nmp->nm_hostname, ':'); 671214048Srmacklem if (p != NULL) 672214048Srmacklem *p = '\0'; 673214048Srmacklem } 674191783Srmacklem} 675191783Srmacklem 676192585Srmacklemstatic const char *nfs_opts[] = { "from", 677191783Srmacklem "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union", 678191783Srmacklem "noclusterr", "noclusterw", "multilabel", "acls", "force", "update", 679192585Srmacklem "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus", 680192585Srmacklem "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize", 681192585Srmacklem "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport", 682192585Srmacklem "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec", 683192585Srmacklem "principal", "nfsv4", "gssname", "allgssname", "dirpath", 684203303Srmacklem "negnametimeo", 685191783Srmacklem NULL }; 686191783Srmacklem 687191783Srmacklem/* 688191783Srmacklem * VFS Operations. 689191783Srmacklem * 690191783Srmacklem * mount system call 691191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 692191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 693191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 694191783Srmacklem * an error after that means that I have to release the mbuf. 695191783Srmacklem */ 696191783Srmacklem/* ARGSUSED */ 697191783Srmacklemstatic int 698191990Sattilionfs_mount(struct mount *mp) 699191783Srmacklem{ 700191783Srmacklem struct nfs_args args = { 701191783Srmacklem .version = NFS_ARGSVERSION, 702191783Srmacklem .addr = NULL, 703191783Srmacklem .addrlen = sizeof (struct sockaddr_in), 704191783Srmacklem .sotype = SOCK_STREAM, 705191783Srmacklem .proto = 0, 706191783Srmacklem .fh = NULL, 707191783Srmacklem .fhsize = 0, 708191783Srmacklem .flags = 0, 709191783Srmacklem .wsize = NFS_WSIZE, 710191783Srmacklem .rsize = NFS_RSIZE, 711191783Srmacklem .readdirsize = NFS_READDIRSIZE, 712191783Srmacklem .timeo = 10, 713191783Srmacklem .retrans = NFS_RETRANS, 714191783Srmacklem .readahead = NFS_DEFRAHEAD, 715191783Srmacklem .wcommitsize = 0, /* was: NQ_DEFLEASE */ 716191783Srmacklem .hostname = NULL, 717191783Srmacklem /* args version 4 */ 718191783Srmacklem .acregmin = NFS_MINATTRTIMO, 719191783Srmacklem .acregmax = NFS_MAXATTRTIMO, 720191783Srmacklem .acdirmin = NFS_MINDIRATTRTIMO, 721191783Srmacklem .acdirmax = NFS_MAXDIRATTRTIMO, 722191783Srmacklem .dirlen = 0, 723191783Srmacklem .krbnamelen = 0, 724192585Srmacklem .srvkrbnamelen = 0, 725191783Srmacklem }; 726192585Srmacklem int error = 0, ret, len; 727192585Srmacklem struct sockaddr *nam = NULL; 728191783Srmacklem struct vnode *vp; 729191990Sattilio struct thread *td; 730191783Srmacklem char hst[MNAMELEN]; 731191783Srmacklem u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100]; 732192585Srmacklem char *opt, *name, *secname; 733203303Srmacklem int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO; 734191783Srmacklem 735191783Srmacklem if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) { 736191783Srmacklem error = EINVAL; 737191783Srmacklem goto out; 738191783Srmacklem } 739191783Srmacklem 740191990Sattilio td = curthread; 741191783Srmacklem if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) { 742192145Srmacklem error = ncl_mountroot(mp); 743191783Srmacklem goto out; 744191783Srmacklem } 745191783Srmacklem 746192585Srmacklem nfscl_init(); 747191783Srmacklem 748192585Srmacklem /* Handle the new style options. */ 749192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0) 750192585Srmacklem args.flags |= NFSMNT_NOCONN; 751192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0) 752192585Srmacklem args.flags |= NFSMNT_NOCONN; 753192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0) 754192585Srmacklem args.flags |= NFSMNT_NOLOCKD; 755192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0) 756192585Srmacklem args.flags &= ~NFSMNT_NOLOCKD; 757192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0) 758192585Srmacklem args.flags |= NFSMNT_INT; 759192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0) 760192585Srmacklem args.flags |= NFSMNT_RDIRPLUS; 761192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0) 762192585Srmacklem args.flags |= NFSMNT_RESVPORT; 763192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0) 764192585Srmacklem args.flags &= ~NFSMNT_RESVPORT; 765192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0) 766192585Srmacklem args.flags |= NFSMNT_SOFT; 767192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0) 768192585Srmacklem args.flags &= ~NFSMNT_SOFT; 769192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0) 770192585Srmacklem args.sotype = SOCK_DGRAM; 771192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0) 772192585Srmacklem args.sotype = SOCK_DGRAM; 773192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0) 774192585Srmacklem args.sotype = SOCK_STREAM; 775192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0) 776192585Srmacklem args.flags |= NFSMNT_NFSV3; 777192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) { 778192585Srmacklem args.flags |= NFSMNT_NFSV4; 779192585Srmacklem args.sotype = SOCK_STREAM; 780191783Srmacklem } 781192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0) 782192585Srmacklem args.flags |= NFSMNT_ALLGSSNAME; 783192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) { 784192585Srmacklem if (opt == NULL) { 785192585Srmacklem vfs_mount_error(mp, "illegal readdirsize"); 786192585Srmacklem error = EINVAL; 787192585Srmacklem goto out; 788192585Srmacklem } 789192585Srmacklem ret = sscanf(opt, "%d", &args.readdirsize); 790192585Srmacklem if (ret != 1 || args.readdirsize <= 0) { 791192585Srmacklem vfs_mount_error(mp, "illegal readdirsize: %s", 792192585Srmacklem opt); 793192585Srmacklem error = EINVAL; 794192585Srmacklem goto out; 795192585Srmacklem } 796192585Srmacklem args.flags |= NFSMNT_READDIRSIZE; 797192585Srmacklem } 798192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) { 799192585Srmacklem if (opt == NULL) { 800192585Srmacklem vfs_mount_error(mp, "illegal readahead"); 801192585Srmacklem error = EINVAL; 802192585Srmacklem goto out; 803192585Srmacklem } 804192585Srmacklem ret = sscanf(opt, "%d", &args.readahead); 805192585Srmacklem if (ret != 1 || args.readahead <= 0) { 806192585Srmacklem vfs_mount_error(mp, "illegal readahead: %s", 807192585Srmacklem opt); 808192585Srmacklem error = EINVAL; 809192585Srmacklem goto out; 810192585Srmacklem } 811192585Srmacklem args.flags |= NFSMNT_READAHEAD; 812192585Srmacklem } 813192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) { 814192585Srmacklem if (opt == NULL) { 815192585Srmacklem vfs_mount_error(mp, "illegal wsize"); 816192585Srmacklem error = EINVAL; 817192585Srmacklem goto out; 818192585Srmacklem } 819192585Srmacklem ret = sscanf(opt, "%d", &args.wsize); 820192585Srmacklem if (ret != 1 || args.wsize <= 0) { 821192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 822192585Srmacklem opt); 823192585Srmacklem error = EINVAL; 824192585Srmacklem goto out; 825192585Srmacklem } 826192585Srmacklem args.flags |= NFSMNT_WSIZE; 827192585Srmacklem } 828192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) { 829192585Srmacklem if (opt == NULL) { 830192585Srmacklem vfs_mount_error(mp, "illegal rsize"); 831192585Srmacklem error = EINVAL; 832192585Srmacklem goto out; 833192585Srmacklem } 834192585Srmacklem ret = sscanf(opt, "%d", &args.rsize); 835192585Srmacklem if (ret != 1 || args.rsize <= 0) { 836192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 837192585Srmacklem opt); 838192585Srmacklem error = EINVAL; 839192585Srmacklem goto out; 840192585Srmacklem } 841192585Srmacklem args.flags |= NFSMNT_RSIZE; 842192585Srmacklem } 843192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) { 844192585Srmacklem if (opt == NULL) { 845192585Srmacklem vfs_mount_error(mp, "illegal retrans"); 846192585Srmacklem error = EINVAL; 847192585Srmacklem goto out; 848192585Srmacklem } 849192585Srmacklem ret = sscanf(opt, "%d", &args.retrans); 850192585Srmacklem if (ret != 1 || args.retrans <= 0) { 851192585Srmacklem vfs_mount_error(mp, "illegal retrans: %s", 852192585Srmacklem opt); 853192585Srmacklem error = EINVAL; 854192585Srmacklem goto out; 855192585Srmacklem } 856192585Srmacklem args.flags |= NFSMNT_RETRANS; 857192585Srmacklem } 858192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) { 859192585Srmacklem ret = sscanf(opt, "%d", &args.acregmin); 860192585Srmacklem if (ret != 1 || args.acregmin < 0) { 861192585Srmacklem vfs_mount_error(mp, "illegal acregmin: %s", 862192585Srmacklem opt); 863192585Srmacklem error = EINVAL; 864192585Srmacklem goto out; 865192585Srmacklem } 866192585Srmacklem args.flags |= NFSMNT_ACREGMIN; 867192585Srmacklem } 868192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) { 869192585Srmacklem ret = sscanf(opt, "%d", &args.acregmax); 870192585Srmacklem if (ret != 1 || args.acregmax < 0) { 871192585Srmacklem vfs_mount_error(mp, "illegal acregmax: %s", 872192585Srmacklem opt); 873192585Srmacklem error = EINVAL; 874192585Srmacklem goto out; 875192585Srmacklem } 876192585Srmacklem args.flags |= NFSMNT_ACREGMAX; 877192585Srmacklem } 878192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) { 879192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmin); 880192585Srmacklem if (ret != 1 || args.acdirmin < 0) { 881192585Srmacklem vfs_mount_error(mp, "illegal acdirmin: %s", 882192585Srmacklem opt); 883192585Srmacklem error = EINVAL; 884192585Srmacklem goto out; 885192585Srmacklem } 886192585Srmacklem args.flags |= NFSMNT_ACDIRMIN; 887192585Srmacklem } 888192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) { 889192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmax); 890192585Srmacklem if (ret != 1 || args.acdirmax < 0) { 891192585Srmacklem vfs_mount_error(mp, "illegal acdirmax: %s", 892192585Srmacklem opt); 893192585Srmacklem error = EINVAL; 894192585Srmacklem goto out; 895192585Srmacklem } 896192585Srmacklem args.flags |= NFSMNT_ACDIRMAX; 897192585Srmacklem } 898192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) { 899192585Srmacklem ret = sscanf(opt, "%d", &args.timeo); 900192585Srmacklem if (ret != 1 || args.timeo <= 0) { 901192585Srmacklem vfs_mount_error(mp, "illegal timeout: %s", 902192585Srmacklem opt); 903192585Srmacklem error = EINVAL; 904192585Srmacklem goto out; 905192585Srmacklem } 906192585Srmacklem args.flags |= NFSMNT_TIMEO; 907192585Srmacklem } 908203303Srmacklem if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL) 909203303Srmacklem == 0) { 910203303Srmacklem ret = sscanf(opt, "%d", &negnametimeo); 911203303Srmacklem if (ret != 1 || negnametimeo < 0) { 912203303Srmacklem vfs_mount_error(mp, "illegal negnametimeo: %s", 913203303Srmacklem opt); 914203303Srmacklem error = EINVAL; 915203303Srmacklem goto out; 916203303Srmacklem } 917203303Srmacklem } 918192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "sec", 919192585Srmacklem (void **) &secname, NULL) == 0) 920192585Srmacklem nfs_sec_name(secname, &args.flags); 921191783Srmacklem 922191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 923191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 924191783Srmacklem 925191783Srmacklem if (nmp == NULL) { 926191783Srmacklem error = EIO; 927191783Srmacklem goto out; 928191783Srmacklem } 929191783Srmacklem /* 930191783Srmacklem * When doing an update, we can't change version, 931191783Srmacklem * security, switch lockd strategies or change cookie 932191783Srmacklem * translation 933191783Srmacklem */ 934191783Srmacklem args.flags = (args.flags & 935191783Srmacklem ~(NFSMNT_NFSV3 | 936191783Srmacklem NFSMNT_NFSV4 | 937191783Srmacklem NFSMNT_KERB | 938191783Srmacklem NFSMNT_INTEGRITY | 939191783Srmacklem NFSMNT_PRIVACY | 940191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) | 941191783Srmacklem (nmp->nm_flag & 942191783Srmacklem (NFSMNT_NFSV3 | 943191783Srmacklem NFSMNT_NFSV4 | 944191783Srmacklem NFSMNT_KERB | 945191783Srmacklem NFSMNT_INTEGRITY | 946191783Srmacklem NFSMNT_PRIVACY | 947191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); 948214048Srmacklem nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td); 949191783Srmacklem goto out; 950191783Srmacklem } 951191783Srmacklem 952191783Srmacklem /* 953191783Srmacklem * Make the nfs_ip_paranoia sysctl serve as the default connection 954191783Srmacklem * or no-connection mode for those protocols that support 955191783Srmacklem * no-connection mode (the flag will be cleared later for protocols 956191783Srmacklem * that do not support no-connection mode). This will allow a client 957191783Srmacklem * to receive replies from a different IP then the request was 958191783Srmacklem * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid), 959191783Srmacklem * not 0. 960191783Srmacklem */ 961191783Srmacklem if (nfs_ip_paranoia == 0) 962191783Srmacklem args.flags |= NFSMNT_NOCONN; 963192585Srmacklem 964192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh, 965192585Srmacklem &args.fhsize) == 0) { 966208234Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) { 967192585Srmacklem vfs_mount_error(mp, "Bad file handle"); 968191783Srmacklem error = EINVAL; 969191783Srmacklem goto out; 970191783Srmacklem } 971192585Srmacklem bcopy(args.fh, nfh, args.fhsize); 972191783Srmacklem } else { 973192585Srmacklem args.fhsize = 0; 974192585Srmacklem } 975192585Srmacklem 976192585Srmacklem (void) vfs_getopt(mp->mnt_optnew, "hostname", (void **)&args.hostname, 977192585Srmacklem &len); 978192585Srmacklem if (args.hostname == NULL) { 979192585Srmacklem vfs_mount_error(mp, "Invalid hostname"); 980192585Srmacklem error = EINVAL; 981192585Srmacklem goto out; 982192585Srmacklem } 983192585Srmacklem bcopy(args.hostname, hst, MNAMELEN); 984192585Srmacklem hst[MNAMELEN - 1] = '\0'; 985192585Srmacklem 986192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0) 987192585Srmacklem strlcpy(srvkrbname, name, sizeof (srvkrbname)); 988192585Srmacklem else 989192585Srmacklem snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst); 990192585Srmacklem args.srvkrbnamelen = strlen(srvkrbname); 991192585Srmacklem 992192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0) 993192585Srmacklem strlcpy(krbname, name, sizeof (krbname)); 994192585Srmacklem else 995191783Srmacklem krbname[0] = '\0'; 996192585Srmacklem args.krbnamelen = strlen(krbname); 997192585Srmacklem 998192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0) 999192585Srmacklem strlcpy(dirpath, name, sizeof (dirpath)); 1000192585Srmacklem else 1001191783Srmacklem dirpath[0] = '\0'; 1002192585Srmacklem args.dirlen = strlen(dirpath); 1003192585Srmacklem 1004192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "addr", (void **)&args.addr, 1005192585Srmacklem &args.addrlen) == 0) { 1006192585Srmacklem if (args.addrlen > SOCK_MAXADDRLEN) { 1007192585Srmacklem error = ENAMETOOLONG; 1008191783Srmacklem goto out; 1009191783Srmacklem } 1010192585Srmacklem nam = malloc(args.addrlen, M_SONAME, M_WAITOK); 1011192585Srmacklem bcopy(args.addr, nam, args.addrlen); 1012192585Srmacklem nam->sa_len = args.addrlen; 1013191783Srmacklem } 1014192585Srmacklem 1015191783Srmacklem args.fh = nfh; 1016191783Srmacklem error = mountnfs(&args, mp, nam, hst, krbname, dirpath, srvkrbname, 1017203303Srmacklem &vp, td->td_ucred, td, negnametimeo); 1018191783Srmacklemout: 1019191783Srmacklem if (!error) { 1020191783Srmacklem MNT_ILOCK(mp); 1021191783Srmacklem mp->mnt_kern_flag |= (MNTK_MPSAFE|MNTK_LOOKUP_SHARED); 1022191783Srmacklem MNT_IUNLOCK(mp); 1023191783Srmacklem } 1024191783Srmacklem return (error); 1025191783Srmacklem} 1026191783Srmacklem 1027191783Srmacklem 1028191783Srmacklem/* 1029191783Srmacklem * VFS Operations. 1030191783Srmacklem * 1031191783Srmacklem * mount system call 1032191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 1033191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 1034191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 1035191783Srmacklem * an error after that means that I have to release the mbuf. 1036191783Srmacklem */ 1037191783Srmacklem/* ARGSUSED */ 1038191783Srmacklemstatic int 1039191990Sattilionfs_cmount(struct mntarg *ma, void *data, int flags) 1040191783Srmacklem{ 1041191783Srmacklem int error; 1042191783Srmacklem struct nfs_args args; 1043191783Srmacklem 1044191783Srmacklem error = copyin(data, &args, sizeof (struct nfs_args)); 1045191783Srmacklem if (error) 1046191783Srmacklem return error; 1047191783Srmacklem 1048191783Srmacklem ma = mount_arg(ma, "nfs_args", &args, sizeof args); 1049191783Srmacklem 1050191783Srmacklem error = kernel_mount(ma, flags); 1051191783Srmacklem return (error); 1052191783Srmacklem} 1053191783Srmacklem 1054191783Srmacklem/* 1055191783Srmacklem * Common code for mount and mountroot 1056191783Srmacklem */ 1057191783Srmacklemstatic int 1058191783Srmacklemmountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, 1059191783Srmacklem char *hst, u_char *krbname, u_char *dirpath, u_char *srvkrbname, 1060203303Srmacklem struct vnode **vpp, struct ucred *cred, struct thread *td, 1061203303Srmacklem int negnametimeo) 1062191783Srmacklem{ 1063191783Srmacklem struct nfsmount *nmp; 1064191783Srmacklem struct nfsnode *np; 1065195762Srmacklem int error, trycnt, ret; 1066191783Srmacklem struct nfsvattr nfsva; 1067191783Srmacklem static u_int64_t clval = 0; 1068191783Srmacklem 1069191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 1070191783Srmacklem nmp = VFSTONFS(mp); 1071191783Srmacklem printf("%s: MNT_UPDATE is no longer handled here\n", __func__); 1072191783Srmacklem FREE(nam, M_SONAME); 1073191783Srmacklem return (0); 1074191783Srmacklem } else { 1075191783Srmacklem MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) + 1076191783Srmacklem argp->krbnamelen + argp->dirlen + argp->srvkrbnamelen + 2, 1077191783Srmacklem M_NEWNFSMNT, M_WAITOK); 1078191783Srmacklem bzero((caddr_t)nmp, sizeof (struct nfsmount) + 1079191783Srmacklem argp->krbnamelen + argp->dirlen + argp->srvkrbnamelen + 2); 1080191783Srmacklem TAILQ_INIT(&nmp->nm_bufq); 1081191783Srmacklem if (clval == 0) 1082191783Srmacklem clval = (u_int64_t)nfsboottime.tv_sec; 1083191783Srmacklem nmp->nm_clval = clval++; 1084191783Srmacklem nmp->nm_krbnamelen = argp->krbnamelen; 1085191783Srmacklem nmp->nm_dirpathlen = argp->dirlen; 1086191783Srmacklem nmp->nm_srvkrbnamelen = argp->srvkrbnamelen; 1087192675Srmacklem if (td->td_ucred->cr_uid != (uid_t)0) { 1088191783Srmacklem /* 1089192675Srmacklem * nm_uid is used to get KerberosV credentials for 1090192675Srmacklem * the nfsv4 state handling operations if there is 1091192675Srmacklem * no host based principal set. Use the uid of 1092192675Srmacklem * this user if not root, since they are doing the 1093192675Srmacklem * mount. I don't think setting this for root will 1094192675Srmacklem * work, since root normally does not have user 1095192675Srmacklem * credentials in a credentials cache. 1096191783Srmacklem */ 1097192675Srmacklem nmp->nm_uid = td->td_ucred->cr_uid; 1098191783Srmacklem } else { 1099191783Srmacklem /* 1100192675Srmacklem * Just set to -1, so it won't be used. 1101191783Srmacklem */ 1102191783Srmacklem nmp->nm_uid = (uid_t)-1; 1103191783Srmacklem } 1104191783Srmacklem 1105191783Srmacklem /* Copy and null terminate all the names */ 1106191783Srmacklem if (nmp->nm_krbnamelen > 0) { 1107191783Srmacklem bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen); 1108191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen] = '\0'; 1109191783Srmacklem } 1110191783Srmacklem if (nmp->nm_dirpathlen > 0) { 1111191783Srmacklem bcopy(dirpath, NFSMNT_DIRPATH(nmp), 1112191783Srmacklem nmp->nm_dirpathlen); 1113191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1114191783Srmacklem + 1] = '\0'; 1115191783Srmacklem } 1116191783Srmacklem if (nmp->nm_srvkrbnamelen > 0) { 1117191783Srmacklem bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp), 1118191783Srmacklem nmp->nm_srvkrbnamelen); 1119191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1120191783Srmacklem + nmp->nm_srvkrbnamelen + 2] = '\0'; 1121191783Srmacklem } 1122191783Srmacklem nmp->nm_sockreq.nr_cred = crhold(cred); 1123191783Srmacklem mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF); 1124191783Srmacklem mp->mnt_data = nmp; 1125214048Srmacklem nmp->nm_getinfo = nfs_getnlminfo; 1126191783Srmacklem } 1127191783Srmacklem vfs_getnewfsid(mp); 1128191783Srmacklem nmp->nm_mountp = mp; 1129191783Srmacklem mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK); 1130203303Srmacklem nmp->nm_negnametimeo = negnametimeo; 1131191783Srmacklem 1132214048Srmacklem nfs_decode_args(mp, nmp, argp, hst, cred, td); 1133192585Srmacklem 1134191783Srmacklem /* 1135191783Srmacklem * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too 1136191783Srmacklem * high, depending on whether we end up with negative offsets in 1137191783Srmacklem * the client or server somewhere. 2GB-1 may be safer. 1138191783Srmacklem * 1139191783Srmacklem * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum 1140191783Srmacklem * that we can handle until we find out otherwise. 1141191783Srmacklem * XXX Our "safe" limit on the client is what we can store in our 1142191783Srmacklem * buffer cache using signed(!) block numbers. 1143191783Srmacklem */ 1144191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) 1145191783Srmacklem nmp->nm_maxfilesize = 0xffffffffLL; 1146191783Srmacklem else 1147191783Srmacklem nmp->nm_maxfilesize = (u_int64_t)0x80000000 * DEV_BSIZE - 1; 1148191783Srmacklem 1149191783Srmacklem nmp->nm_timeo = NFS_TIMEO; 1150191783Srmacklem nmp->nm_retry = NFS_RETRANS; 1151191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 1152191783Srmacklem nmp->nm_wsize = NFS_WSIZE; 1153191783Srmacklem nmp->nm_rsize = NFS_RSIZE; 1154191783Srmacklem nmp->nm_readdirsize = NFS_READDIRSIZE; 1155191783Srmacklem } 1156191783Srmacklem nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000); 1157191783Srmacklem nmp->nm_numgrps = NFS_MAXGRPS; 1158191783Srmacklem nmp->nm_readahead = NFS_DEFRAHEAD; 1159191783Srmacklem nmp->nm_tprintf_delay = nfs_tprintf_delay; 1160191783Srmacklem if (nmp->nm_tprintf_delay < 0) 1161191783Srmacklem nmp->nm_tprintf_delay = 0; 1162191783Srmacklem nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay; 1163191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1164191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1165191783Srmacklem nmp->nm_fhsize = argp->fhsize; 1166191783Srmacklem if (nmp->nm_fhsize > 0) 1167191783Srmacklem bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 1168191783Srmacklem bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 1169191783Srmacklem nmp->nm_nam = nam; 1170191783Srmacklem /* Set up the sockets and per-host congestion */ 1171191783Srmacklem nmp->nm_sotype = argp->sotype; 1172191783Srmacklem nmp->nm_soproto = argp->proto; 1173191783Srmacklem nmp->nm_sockreq.nr_prog = NFS_PROG; 1174191783Srmacklem if ((argp->flags & NFSMNT_NFSV4)) 1175191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER4; 1176191783Srmacklem else if ((argp->flags & NFSMNT_NFSV3)) 1177191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER3; 1178191783Srmacklem else 1179191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER2; 1180191783Srmacklem 1181191783Srmacklem 1182191783Srmacklem if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0))) 1183191783Srmacklem goto bad; 1184191783Srmacklem 1185191783Srmacklem /* 1186191783Srmacklem * A reference count is needed on the nfsnode representing the 1187191783Srmacklem * remote root. If this object is not persistent, then backward 1188191783Srmacklem * traversals of the mount point (i.e. "..") will not work if 1189191783Srmacklem * the nfsnode gets flushed out of the cache. Ufs does not have 1190191783Srmacklem * this problem, because one can identify root inodes by their 1191191783Srmacklem * number == ROOTINO (2). 1192191783Srmacklem */ 1193191783Srmacklem if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) && 1194191783Srmacklem nmp->nm_dirpathlen > 0) { 1195191783Srmacklem /* 1196191783Srmacklem * If the fhsize on the mount point == 0 for V4, the mount 1197191783Srmacklem * path needs to be looked up. 1198191783Srmacklem */ 1199191783Srmacklem trycnt = 3; 1200191783Srmacklem do { 1201191783Srmacklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 1202191783Srmacklem cred, td); 1203191783Srmacklem if (error) 1204207170Srmacklem (void) nfs_catnap(PZERO, error, "nfsgetdirp"); 1205191783Srmacklem } while (error && --trycnt > 0); 1206191783Srmacklem if (error) { 1207191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1208191783Srmacklem goto bad; 1209191783Srmacklem } 1210191783Srmacklem } 1211191783Srmacklem if (nmp->nm_fhsize > 0) { 1212195762Srmacklem /* 1213195762Srmacklem * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set 1214195762Srmacklem * non-zero for the root vnode. f_iosize will be set correctly 1215195762Srmacklem * by nfs_statfs() before any I/O occurs. 1216195762Srmacklem */ 1217195762Srmacklem mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ; 1218191783Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np); 1219191783Srmacklem if (error) 1220191783Srmacklem goto bad; 1221191783Srmacklem *vpp = NFSTOV(np); 1222191783Srmacklem 1223191783Srmacklem /* 1224191783Srmacklem * Get file attributes and transfer parameters for the 1225191783Srmacklem * mountpoint. This has the side effect of filling in 1226191783Srmacklem * (*vpp)->v_type with the correct value. 1227191783Srmacklem */ 1228191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 1229191783Srmacklem cred, td, &nfsva, NULL); 1230191783Srmacklem if (ret) { 1231191783Srmacklem /* 1232191783Srmacklem * Just set default values to get things going. 1233191783Srmacklem */ 1234191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 1235191783Srmacklem nfsva.na_vattr.va_type = VDIR; 1236191783Srmacklem nfsva.na_vattr.va_mode = 0777; 1237191783Srmacklem nfsva.na_vattr.va_nlink = 100; 1238191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 1239191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 1240191783Srmacklem nfsva.na_vattr.va_fileid = 2; 1241191783Srmacklem nfsva.na_vattr.va_gen = 1; 1242191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 1243191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 1244191783Srmacklem } 1245191783Srmacklem (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1); 1246191783Srmacklem if (argp->flags & NFSMNT_NFSV3) 1247191783Srmacklem ncl_fsinfo(nmp, *vpp, cred, td); 1248191783Srmacklem 1249191783Srmacklem /* 1250191783Srmacklem * Lose the lock but keep the ref. 1251191783Srmacklem */ 1252191783Srmacklem VOP_UNLOCK(*vpp, 0); 1253191783Srmacklem return (0); 1254191783Srmacklem } 1255191783Srmacklem error = EIO; 1256191783Srmacklem 1257191783Srmacklembad: 1258191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1259191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1260191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1261191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1262191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1263191783Srmacklem FREE(nam, M_SONAME); 1264191783Srmacklem return (error); 1265191783Srmacklem} 1266191783Srmacklem 1267191783Srmacklem/* 1268191783Srmacklem * unmount system call 1269191783Srmacklem */ 1270191783Srmacklemstatic int 1271191990Sattilionfs_unmount(struct mount *mp, int mntflags) 1272191783Srmacklem{ 1273191990Sattilio struct thread *td; 1274191783Srmacklem struct nfsmount *nmp; 1275191783Srmacklem int error, flags = 0, trycnt = 0; 1276191783Srmacklem 1277191990Sattilio td = curthread; 1278191990Sattilio 1279191783Srmacklem if (mntflags & MNT_FORCE) 1280191783Srmacklem flags |= FORCECLOSE; 1281191783Srmacklem nmp = VFSTONFS(mp); 1282191783Srmacklem /* 1283191783Srmacklem * Goes something like this.. 1284191783Srmacklem * - Call vflush() to clear out vnodes for this filesystem 1285191783Srmacklem * - Close the socket 1286191783Srmacklem * - Free up the data structures 1287191783Srmacklem */ 1288191783Srmacklem /* In the forced case, cancel any outstanding requests. */ 1289191783Srmacklem if (mntflags & MNT_FORCE) { 1290191783Srmacklem error = newnfs_nmcancelreqs(nmp); 1291191783Srmacklem if (error) 1292191783Srmacklem goto out; 1293191783Srmacklem /* For a forced close, get rid of the renew thread now */ 1294191783Srmacklem nfscl_umount(nmp, td); 1295191783Srmacklem } 1296191783Srmacklem /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ 1297191783Srmacklem do { 1298191783Srmacklem error = vflush(mp, 1, flags, td); 1299191783Srmacklem if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30) 1300207170Srmacklem (void) nfs_catnap(PSOCK, error, "newndm"); 1301191783Srmacklem } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30); 1302191783Srmacklem if (error) 1303191783Srmacklem goto out; 1304191783Srmacklem 1305191783Srmacklem /* 1306191783Srmacklem * We are now committed to the unmount. 1307191783Srmacklem */ 1308191783Srmacklem if ((mntflags & MNT_FORCE) == 0) 1309191783Srmacklem nfscl_umount(nmp, td); 1310191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1311191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1312191783Srmacklem FREE(nmp->nm_nam, M_SONAME); 1313191783Srmacklem 1314191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1315191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1316191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1317191783Srmacklemout: 1318191783Srmacklem return (error); 1319191783Srmacklem} 1320191783Srmacklem 1321191783Srmacklem/* 1322191783Srmacklem * Return root of a filesystem 1323191783Srmacklem */ 1324191783Srmacklemstatic int 1325191990Sattilionfs_root(struct mount *mp, int flags, struct vnode **vpp) 1326191783Srmacklem{ 1327191783Srmacklem struct vnode *vp; 1328191783Srmacklem struct nfsmount *nmp; 1329191783Srmacklem struct nfsnode *np; 1330191783Srmacklem int error; 1331191783Srmacklem 1332191783Srmacklem nmp = VFSTONFS(mp); 1333191783Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np); 1334191783Srmacklem if (error) 1335191783Srmacklem return error; 1336191783Srmacklem vp = NFSTOV(np); 1337191783Srmacklem /* 1338191783Srmacklem * Get transfer parameters and attributes for root vnode once. 1339191783Srmacklem */ 1340191783Srmacklem mtx_lock(&nmp->nm_mtx); 1341191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 1342191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1343191783Srmacklem ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread); 1344191783Srmacklem } else 1345191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1346191783Srmacklem if (vp->v_type == VNON) 1347191783Srmacklem vp->v_type = VDIR; 1348191783Srmacklem vp->v_vflag |= VV_ROOT; 1349191783Srmacklem *vpp = vp; 1350191783Srmacklem return (0); 1351191783Srmacklem} 1352191783Srmacklem 1353191783Srmacklem/* 1354191783Srmacklem * Flush out the buffer cache 1355191783Srmacklem */ 1356191783Srmacklem/* ARGSUSED */ 1357191783Srmacklemstatic int 1358191990Sattilionfs_sync(struct mount *mp, int waitfor) 1359191783Srmacklem{ 1360191783Srmacklem struct vnode *vp, *mvp; 1361191990Sattilio struct thread *td; 1362191783Srmacklem int error, allerror = 0; 1363191783Srmacklem 1364191990Sattilio td = curthread; 1365191990Sattilio 1366191783Srmacklem /* 1367191783Srmacklem * Force stale buffer cache information to be flushed. 1368191783Srmacklem */ 1369191783Srmacklem MNT_ILOCK(mp); 1370191783Srmacklemloop: 1371191783Srmacklem MNT_VNODE_FOREACH(vp, mp, mvp) { 1372191783Srmacklem VI_LOCK(vp); 1373191783Srmacklem MNT_IUNLOCK(mp); 1374191783Srmacklem /* XXX Racy bv_cnt check. */ 1375191783Srmacklem if (VOP_ISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1376191783Srmacklem waitfor == MNT_LAZY) { 1377191783Srmacklem VI_UNLOCK(vp); 1378191783Srmacklem MNT_ILOCK(mp); 1379191783Srmacklem continue; 1380191783Srmacklem } 1381191783Srmacklem if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 1382191783Srmacklem MNT_ILOCK(mp); 1383191783Srmacklem MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); 1384191783Srmacklem goto loop; 1385191783Srmacklem } 1386191783Srmacklem error = VOP_FSYNC(vp, waitfor, td); 1387191783Srmacklem if (error) 1388191783Srmacklem allerror = error; 1389191783Srmacklem VOP_UNLOCK(vp, 0); 1390191783Srmacklem vrele(vp); 1391191783Srmacklem 1392191783Srmacklem MNT_ILOCK(mp); 1393191783Srmacklem } 1394191783Srmacklem MNT_IUNLOCK(mp); 1395191783Srmacklem return (allerror); 1396191783Srmacklem} 1397191783Srmacklem 1398191783Srmacklemstatic int 1399191783Srmacklemnfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 1400191783Srmacklem{ 1401191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1402191783Srmacklem struct vfsquery vq; 1403191783Srmacklem int error; 1404191783Srmacklem 1405191783Srmacklem bzero(&vq, sizeof(vq)); 1406191783Srmacklem switch (op) { 1407191783Srmacklem#if 0 1408191783Srmacklem case VFS_CTL_NOLOCKS: 1409191783Srmacklem val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; 1410191783Srmacklem if (req->oldptr != NULL) { 1411191783Srmacklem error = SYSCTL_OUT(req, &val, sizeof(val)); 1412191783Srmacklem if (error) 1413191783Srmacklem return (error); 1414191783Srmacklem } 1415191783Srmacklem if (req->newptr != NULL) { 1416191783Srmacklem error = SYSCTL_IN(req, &val, sizeof(val)); 1417191783Srmacklem if (error) 1418191783Srmacklem return (error); 1419191783Srmacklem if (val) 1420191783Srmacklem nmp->nm_flag |= NFSMNT_NOLOCKS; 1421191783Srmacklem else 1422191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOLOCKS; 1423191783Srmacklem } 1424191783Srmacklem break; 1425191783Srmacklem#endif 1426191783Srmacklem case VFS_CTL_QUERY: 1427191783Srmacklem mtx_lock(&nmp->nm_mtx); 1428191783Srmacklem if (nmp->nm_state & NFSSTA_TIMEO) 1429191783Srmacklem vq.vq_flags |= VQ_NOTRESP; 1430191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1431191783Srmacklem#if 0 1432191783Srmacklem if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && 1433191783Srmacklem (nmp->nm_state & NFSSTA_LOCKTIMEO)) 1434191783Srmacklem vq.vq_flags |= VQ_NOTRESPLOCK; 1435191783Srmacklem#endif 1436191783Srmacklem error = SYSCTL_OUT(req, &vq, sizeof(vq)); 1437191783Srmacklem break; 1438191783Srmacklem case VFS_CTL_TIMEO: 1439191783Srmacklem if (req->oldptr != NULL) { 1440191783Srmacklem error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, 1441191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1442191783Srmacklem if (error) 1443191783Srmacklem return (error); 1444191783Srmacklem } 1445191783Srmacklem if (req->newptr != NULL) { 1446191783Srmacklem error = vfs_suser(mp, req->td); 1447191783Srmacklem if (error) 1448191783Srmacklem return (error); 1449191783Srmacklem error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, 1450191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1451191783Srmacklem if (error) 1452191783Srmacklem return (error); 1453191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1454191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1455191783Srmacklem } 1456191783Srmacklem break; 1457191783Srmacklem default: 1458191783Srmacklem return (ENOTSUP); 1459191783Srmacklem } 1460191783Srmacklem return (0); 1461191783Srmacklem} 1462191783Srmacklem 1463214048Srmacklem/* 1464214048Srmacklem * Extract the information needed by the nlm from the nfs vnode. 1465214048Srmacklem */ 1466214048Srmacklemstatic void 1467214048Srmacklemnfs_getnlminfo(struct vnode *vp, uint8_t *fhp, int *fhlenp, 1468214048Srmacklem struct sockaddr_storage *sp, int *is_v3p, off_t *sizep) 1469214048Srmacklem{ 1470214048Srmacklem struct nfsmount *nmp; 1471214048Srmacklem struct nfsnode *np = VTONFS(vp); 1472214048Srmacklem 1473214048Srmacklem nmp = VFSTONFS(vp->v_mount); 1474214048Srmacklem if (fhlenp != NULL) 1475214048Srmacklem *fhlenp = np->n_fhp->nfh_len; 1476214048Srmacklem if (fhp != NULL) 1477214048Srmacklem bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len); 1478214048Srmacklem if (sp != NULL) 1479214048Srmacklem bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp))); 1480214048Srmacklem if (is_v3p != NULL) 1481214048Srmacklem *is_v3p = NFS_ISV3(vp); 1482214048Srmacklem if (sizep != NULL) 1483214048Srmacklem *sizep = np->n_size; 1484214048Srmacklem} 1485214048Srmacklem 1486