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$"); 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; 83250258Srmacklemextern enum nfsiod_state ncl_iodwant[NFS_MAXASYNCDAEMON]; 84250258Srmacklemextern struct nfsmount *ncl_iodmount[NFS_MAXASYNCDAEMON]; 85250258Srmacklemextern struct mtx ncl_iod_mutex; 86191783Srmacklem 87191783SrmacklemMALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header"); 88191783SrmacklemMALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct"); 89191783Srmacklem 90221973SrmacklemSYSCTL_DECL(_vfs_nfs); 91191783Srmacklemstatic int nfs_ip_paranoia = 1; 92221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW, 93191783Srmacklem &nfs_ip_paranoia, 0, ""); 94191783Srmacklemstatic int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY; 95221973SrmacklemSYSCTL_INT(_vfs_nfs, NFS_TPRINTF_INITIAL_DELAY, 96191783Srmacklem downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, ""); 97191783Srmacklem/* how long between console messages "nfs server foo not responding" */ 98191783Srmacklemstatic int nfs_tprintf_delay = NFS_TPRINTF_DELAY; 99221973SrmacklemSYSCTL_INT(_vfs_nfs, NFS_TPRINTF_DELAY, 100191783Srmacklem downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, ""); 101191783Srmacklem 102221040Srmacklemstatic int nfs_mountroot(struct mount *); 103192585Srmacklemstatic void nfs_sec_name(char *, int *); 104191783Srmacklemstatic void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, 105214048Srmacklem struct nfs_args *argp, const char *, struct ucred *, 106214048Srmacklem struct thread *); 107191783Srmacklemstatic int mountnfs(struct nfs_args *, struct mount *, 108221014Srmacklem struct sockaddr *, char *, u_char *, int, u_char *, int, 109221014Srmacklem u_char *, int, struct vnode **, struct ucred *, 110233326Sjhb struct thread *, int, int); 111214053Srmacklemstatic void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *, 112216931Srmacklem struct sockaddr_storage *, int *, off_t *, 113216931Srmacklem struct timeval *); 114191783Srmacklemstatic vfs_mount_t nfs_mount; 115191783Srmacklemstatic vfs_cmount_t nfs_cmount; 116191783Srmacklemstatic vfs_unmount_t nfs_unmount; 117191783Srmacklemstatic vfs_root_t nfs_root; 118191783Srmacklemstatic vfs_statfs_t nfs_statfs; 119191783Srmacklemstatic vfs_sync_t nfs_sync; 120191783Srmacklemstatic vfs_sysctl_t nfs_sysctl; 121191783Srmacklem 122191783Srmacklem/* 123191783Srmacklem * nfs vfs operations. 124191783Srmacklem */ 125191783Srmacklemstatic struct vfsops nfs_vfsops = { 126191783Srmacklem .vfs_init = ncl_init, 127191783Srmacklem .vfs_mount = nfs_mount, 128191783Srmacklem .vfs_cmount = nfs_cmount, 129191783Srmacklem .vfs_root = nfs_root, 130191783Srmacklem .vfs_statfs = nfs_statfs, 131191783Srmacklem .vfs_sync = nfs_sync, 132191783Srmacklem .vfs_uninit = ncl_uninit, 133191783Srmacklem .vfs_unmount = nfs_unmount, 134191783Srmacklem .vfs_sysctl = nfs_sysctl, 135191783Srmacklem}; 136251147SjhbVFS_SET(nfs_vfsops, nfs, VFCF_NETWORK | VFCF_SBDRY); 137191783Srmacklem 138191783Srmacklem/* So that loader and kldload(2) can find us, wherever we are.. */ 139221139SrmacklemMODULE_VERSION(nfs, 1); 140221139SrmacklemMODULE_DEPEND(nfs, nfscommon, 1, 1, 1); 141221139SrmacklemMODULE_DEPEND(nfs, krpc, 1, 1, 1); 142221139SrmacklemMODULE_DEPEND(nfs, nfssvc, 1, 1, 1); 143221139SrmacklemMODULE_DEPEND(nfs, nfslock, 1, 1, 1); 144191783Srmacklem 145191783Srmacklem/* 146221066Srmacklem * This structure is now defined in sys/nfs/nfs_diskless.c so that it 147221066Srmacklem * can be shared by both NFS clients. It is declared here so that it 148221066Srmacklem * will be defined for kernels built without NFS_ROOT, although it 149221066Srmacklem * isn't used in that case. 150191783Srmacklem */ 151221066Srmacklem#if !defined(NFS_ROOT) && !defined(NFSCLIENT) 152221066Srmacklemstruct nfs_diskless nfs_diskless = { { { 0 } } }; 153221066Srmacklemstruct nfsv3_diskless nfsv3_diskless = { { { 0 } } }; 154221066Srmacklemint nfs_diskless_valid = 0; 155221066Srmacklem#endif 156221066Srmacklem 157221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD, 158221040Srmacklem &nfs_diskless_valid, 0, 159192145Srmacklem "Has the diskless struct been filled correctly"); 160191783Srmacklem 161221973SrmacklemSYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD, 162221040Srmacklem nfsv3_diskless.root_hostnam, 0, "Path to nfs root"); 163191783Srmacklem 164221973SrmacklemSYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD, 165221040Srmacklem &nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr), 166192145Srmacklem "%Ssockaddr_in", "Diskless root nfs address"); 167191783Srmacklem 168191783Srmacklem 169191783Srmacklemvoid newnfsargs_ntoh(struct nfs_args *); 170191783Srmacklemstatic int nfs_mountdiskless(char *, 171191783Srmacklem struct sockaddr_in *, struct nfs_args *, 172191783Srmacklem struct thread *, struct vnode **, struct mount *); 173191783Srmacklemstatic void nfs_convert_diskless(void); 174191783Srmacklemstatic void nfs_convert_oargs(struct nfs_args *args, 175191783Srmacklem struct onfs_args *oargs); 176191783Srmacklem 177191783Srmacklemint 178191783Srmacklemnewnfs_iosize(struct nfsmount *nmp) 179191783Srmacklem{ 180191783Srmacklem int iosize, maxio; 181191783Srmacklem 182191783Srmacklem /* First, set the upper limit for iosize */ 183191783Srmacklem if (nmp->nm_flag & NFSMNT_NFSV4) { 184191783Srmacklem maxio = NFS_MAXBSIZE; 185191783Srmacklem } else if (nmp->nm_flag & NFSMNT_NFSV3) { 186191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 187191783Srmacklem maxio = NFS_MAXDGRAMDATA; 188191783Srmacklem else 189191783Srmacklem maxio = NFS_MAXBSIZE; 190191783Srmacklem } else { 191191783Srmacklem maxio = NFS_V2MAXDATA; 192191783Srmacklem } 193191783Srmacklem if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0) 194191783Srmacklem nmp->nm_rsize = maxio; 195191783Srmacklem if (nmp->nm_rsize > MAXBSIZE) 196191783Srmacklem nmp->nm_rsize = MAXBSIZE; 197191783Srmacklem if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0) 198191783Srmacklem nmp->nm_readdirsize = maxio; 199191783Srmacklem if (nmp->nm_readdirsize > nmp->nm_rsize) 200191783Srmacklem nmp->nm_readdirsize = nmp->nm_rsize; 201191783Srmacklem if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0) 202191783Srmacklem nmp->nm_wsize = maxio; 203191783Srmacklem if (nmp->nm_wsize > MAXBSIZE) 204191783Srmacklem nmp->nm_wsize = MAXBSIZE; 205191783Srmacklem 206191783Srmacklem /* 207191783Srmacklem * Calculate the size used for io buffers. Use the larger 208191783Srmacklem * of the two sizes to minimise nfs requests but make sure 209191783Srmacklem * that it is at least one VM page to avoid wasting buffer 210191783Srmacklem * space. 211191783Srmacklem */ 212191783Srmacklem iosize = imax(nmp->nm_rsize, nmp->nm_wsize); 213191783Srmacklem iosize = imax(iosize, PAGE_SIZE); 214191783Srmacklem nmp->nm_mountp->mnt_stat.f_iosize = iosize; 215191783Srmacklem return (iosize); 216191783Srmacklem} 217191783Srmacklem 218191783Srmacklemstatic void 219191783Srmacklemnfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs) 220191783Srmacklem{ 221191783Srmacklem 222191783Srmacklem args->version = NFS_ARGSVERSION; 223191783Srmacklem args->addr = oargs->addr; 224191783Srmacklem args->addrlen = oargs->addrlen; 225191783Srmacklem args->sotype = oargs->sotype; 226191783Srmacklem args->proto = oargs->proto; 227191783Srmacklem args->fh = oargs->fh; 228191783Srmacklem args->fhsize = oargs->fhsize; 229191783Srmacklem args->flags = oargs->flags; 230191783Srmacklem args->wsize = oargs->wsize; 231191783Srmacklem args->rsize = oargs->rsize; 232191783Srmacklem args->readdirsize = oargs->readdirsize; 233191783Srmacklem args->timeo = oargs->timeo; 234191783Srmacklem args->retrans = oargs->retrans; 235191783Srmacklem args->readahead = oargs->readahead; 236191783Srmacklem args->hostname = oargs->hostname; 237191783Srmacklem} 238191783Srmacklem 239191783Srmacklemstatic void 240191783Srmacklemnfs_convert_diskless(void) 241191783Srmacklem{ 242191783Srmacklem 243221040Srmacklem bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif, 244221040Srmacklem sizeof(struct ifaliasreq)); 245221040Srmacklem bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway, 246221040Srmacklem sizeof(struct sockaddr_in)); 247221040Srmacklem nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args); 248221040Srmacklem if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) { 249221040Srmacklem nfsv3_diskless.root_fhsize = NFSX_MYFH; 250221040Srmacklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH); 251191783Srmacklem } else { 252221040Srmacklem nfsv3_diskless.root_fhsize = NFSX_V2FH; 253221040Srmacklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH); 254191783Srmacklem } 255221040Srmacklem bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr, 256221040Srmacklem sizeof(struct sockaddr_in)); 257221040Srmacklem bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN); 258221040Srmacklem nfsv3_diskless.root_time = nfs_diskless.root_time; 259221040Srmacklem bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam, 260221040Srmacklem MAXHOSTNAMELEN); 261221040Srmacklem nfs_diskless_valid = 3; 262191783Srmacklem} 263191783Srmacklem 264191783Srmacklem/* 265191783Srmacklem * nfs statfs call 266191783Srmacklem */ 267191783Srmacklemstatic int 268191990Sattilionfs_statfs(struct mount *mp, struct statfs *sbp) 269191783Srmacklem{ 270191783Srmacklem struct vnode *vp; 271191990Sattilio struct thread *td; 272191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 273191783Srmacklem struct nfsvattr nfsva; 274191783Srmacklem struct nfsfsinfo fs; 275191783Srmacklem struct nfsstatfs sb; 276191783Srmacklem int error = 0, attrflag, gotfsinfo = 0, ret; 277191783Srmacklem struct nfsnode *np; 278191783Srmacklem 279191990Sattilio td = curthread; 280191990Sattilio 281191783Srmacklem error = vfs_busy(mp, MBF_NOWAIT); 282191783Srmacklem if (error) 283191783Srmacklem return (error); 284220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE); 285191783Srmacklem if (error) { 286191783Srmacklem vfs_unbusy(mp); 287191783Srmacklem return (error); 288191783Srmacklem } 289191783Srmacklem vp = NFSTOV(np); 290191783Srmacklem mtx_lock(&nmp->nm_mtx); 291191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 292191783Srmacklem mtx_unlock(&nmp->nm_mtx); 293191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva, 294191783Srmacklem &attrflag, NULL); 295191783Srmacklem if (!error) 296191783Srmacklem gotfsinfo = 1; 297191783Srmacklem } else 298191783Srmacklem mtx_unlock(&nmp->nm_mtx); 299191783Srmacklem if (!error) 300191783Srmacklem error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, 301191783Srmacklem &attrflag, NULL); 302191783Srmacklem if (attrflag == 0) { 303191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 304191783Srmacklem td->td_ucred, td, &nfsva, NULL); 305191783Srmacklem if (ret) { 306191783Srmacklem /* 307191783Srmacklem * Just set default values to get things going. 308191783Srmacklem */ 309191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 310191783Srmacklem nfsva.na_vattr.va_type = VDIR; 311191783Srmacklem nfsva.na_vattr.va_mode = 0777; 312191783Srmacklem nfsva.na_vattr.va_nlink = 100; 313191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 314191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 315191783Srmacklem nfsva.na_vattr.va_fileid = 2; 316191783Srmacklem nfsva.na_vattr.va_gen = 1; 317191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 318191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 319191783Srmacklem } 320191783Srmacklem } 321191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 322191783Srmacklem if (!error) { 323191783Srmacklem mtx_lock(&nmp->nm_mtx); 324191783Srmacklem if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4)) 325191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 326191783Srmacklem nfscl_loadsbinfo(nmp, &sb, sbp); 327191783Srmacklem sbp->f_iosize = newnfs_iosize(nmp); 328191783Srmacklem mtx_unlock(&nmp->nm_mtx); 329191783Srmacklem if (sbp != &mp->mnt_stat) { 330191783Srmacklem bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 331191783Srmacklem bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 332191783Srmacklem } 333191783Srmacklem strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 334191783Srmacklem } else if (NFS_ISV4(vp)) { 335191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 336191783Srmacklem } 337191783Srmacklem vput(vp); 338191783Srmacklem vfs_unbusy(mp); 339191783Srmacklem return (error); 340191783Srmacklem} 341191783Srmacklem 342191783Srmacklem/* 343191783Srmacklem * nfs version 3 fsinfo rpc call 344191783Srmacklem */ 345191783Srmacklemint 346191783Srmacklemncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, 347191783Srmacklem struct thread *td) 348191783Srmacklem{ 349191783Srmacklem struct nfsfsinfo fs; 350191783Srmacklem struct nfsvattr nfsva; 351191783Srmacklem int error, attrflag; 352191783Srmacklem 353191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL); 354191783Srmacklem if (!error) { 355191783Srmacklem if (attrflag) 356191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 357191783Srmacklem 1); 358191783Srmacklem mtx_lock(&nmp->nm_mtx); 359191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 360191783Srmacklem mtx_unlock(&nmp->nm_mtx); 361191783Srmacklem } 362191783Srmacklem return (error); 363191783Srmacklem} 364191783Srmacklem 365191783Srmacklem/* 366191783Srmacklem * Mount a remote root fs via. nfs. This depends on the info in the 367221040Srmacklem * nfs_diskless structure that has been filled in properly by some primary 368191783Srmacklem * bootstrap. 369191783Srmacklem * It goes something like this: 370191783Srmacklem * - do enough of "ifconfig" by calling ifioctl() so that the system 371191783Srmacklem * can talk to the server 372221040Srmacklem * - If nfs_diskless.mygateway is filled in, use that address as 373191783Srmacklem * a default gateway. 374191783Srmacklem * - build the rootfs mount point and call mountnfs() to do the rest. 375191783Srmacklem * 376191783Srmacklem * It is assumed to be safe to read, modify, and write the nfsv3_diskless 377191783Srmacklem * structure, as well as other global NFS client variables here, as 378192145Srmacklem * nfs_mountroot() will be called once in the boot before any other NFS 379191783Srmacklem * client activity occurs. 380191783Srmacklem */ 381221040Srmacklemstatic int 382221040Srmacklemnfs_mountroot(struct mount *mp) 383191783Srmacklem{ 384192145Srmacklem struct thread *td = curthread; 385221040Srmacklem struct nfsv3_diskless *nd = &nfsv3_diskless; 386191783Srmacklem struct socket *so; 387191783Srmacklem struct vnode *vp; 388191783Srmacklem struct ifreq ir; 389193066Sjamie int error; 390191783Srmacklem u_long l; 391191783Srmacklem char buf[128]; 392191783Srmacklem char *cp; 393191783Srmacklem 394191783Srmacklem#if defined(BOOTP_NFSROOT) && defined(BOOTP) 395192145Srmacklem bootpc_init(); /* use bootp to get nfs_diskless filled in */ 396191783Srmacklem#elif defined(NFS_ROOT) 397191783Srmacklem nfs_setup_diskless(); 398191783Srmacklem#endif 399191783Srmacklem 400221040Srmacklem if (nfs_diskless_valid == 0) 401191783Srmacklem return (-1); 402221040Srmacklem if (nfs_diskless_valid == 1) 403191783Srmacklem nfs_convert_diskless(); 404191783Srmacklem 405191783Srmacklem /* 406191783Srmacklem * XXX splnet, so networks will receive... 407191783Srmacklem */ 408191783Srmacklem splnet(); 409191783Srmacklem 410191783Srmacklem /* 411191783Srmacklem * Do enough of ifconfig(8) so that the critical net interface can 412191783Srmacklem * talk to the server. 413191783Srmacklem */ 414191783Srmacklem error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0, 415191783Srmacklem td->td_ucred, td); 416191783Srmacklem if (error) 417192145Srmacklem panic("nfs_mountroot: socreate(%04x): %d", 418191783Srmacklem nd->myif.ifra_addr.sa_family, error); 419191783Srmacklem 420191783Srmacklem#if 0 /* XXX Bad idea */ 421191783Srmacklem /* 422191783Srmacklem * We might not have been told the right interface, so we pass 423191783Srmacklem * over the first ten interfaces of the same kind, until we get 424191783Srmacklem * one of them configured. 425191783Srmacklem */ 426191783Srmacklem 427191783Srmacklem for (i = strlen(nd->myif.ifra_name) - 1; 428191783Srmacklem nd->myif.ifra_name[i] >= '0' && 429191783Srmacklem nd->myif.ifra_name[i] <= '9'; 430191783Srmacklem nd->myif.ifra_name[i] ++) { 431191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 432191783Srmacklem if(!error) 433191783Srmacklem break; 434191783Srmacklem } 435191783Srmacklem#endif 436191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 437191783Srmacklem if (error) 438192145Srmacklem panic("nfs_mountroot: SIOCAIFADDR: %d", error); 439191783Srmacklem if ((cp = getenv("boot.netif.mtu")) != NULL) { 440191783Srmacklem ir.ifr_mtu = strtol(cp, NULL, 10); 441191783Srmacklem bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); 442191783Srmacklem freeenv(cp); 443191783Srmacklem error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); 444191783Srmacklem if (error) 445192145Srmacklem printf("nfs_mountroot: SIOCSIFMTU: %d", error); 446191783Srmacklem } 447191783Srmacklem soclose(so); 448191783Srmacklem 449191783Srmacklem /* 450191783Srmacklem * If the gateway field is filled in, set it as the default route. 451191783Srmacklem * Note that pxeboot will set a default route of 0 if the route 452191783Srmacklem * is not set by the DHCP server. Check also for a value of 0 453191783Srmacklem * to avoid panicking inappropriately in that situation. 454191783Srmacklem */ 455191783Srmacklem if (nd->mygateway.sin_len != 0 && 456191783Srmacklem nd->mygateway.sin_addr.s_addr != 0) { 457191783Srmacklem struct sockaddr_in mask, sin; 458191783Srmacklem 459191783Srmacklem bzero((caddr_t)&mask, sizeof(mask)); 460191783Srmacklem sin = mask; 461191783Srmacklem sin.sin_family = AF_INET; 462191783Srmacklem sin.sin_len = sizeof(sin); 463192145Srmacklem /* XXX MRT use table 0 for this sort of thing */ 464218757Sbz CURVNET_SET(TD_TO_VNET(td)); 465232292Sbz error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin, 466191783Srmacklem (struct sockaddr *)&nd->mygateway, 467191783Srmacklem (struct sockaddr *)&mask, 468232292Sbz RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB); 469218757Sbz CURVNET_RESTORE(); 470191783Srmacklem if (error) 471192145Srmacklem panic("nfs_mountroot: RTM_ADD: %d", error); 472191783Srmacklem } 473191783Srmacklem 474191783Srmacklem /* 475191783Srmacklem * Create the rootfs mount point. 476191783Srmacklem */ 477191783Srmacklem nd->root_args.fh = nd->root_fh; 478191783Srmacklem nd->root_args.fhsize = nd->root_fhsize; 479191783Srmacklem l = ntohl(nd->root_saddr.sin_addr.s_addr); 480191783Srmacklem snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", 481191783Srmacklem (l >> 24) & 0xff, (l >> 16) & 0xff, 482191783Srmacklem (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); 483191783Srmacklem printf("NFS ROOT: %s\n", buf); 484192145Srmacklem nd->root_args.hostname = buf; 485191783Srmacklem if ((error = nfs_mountdiskless(buf, 486191783Srmacklem &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { 487191783Srmacklem return (error); 488191783Srmacklem } 489191783Srmacklem 490191783Srmacklem /* 491191783Srmacklem * This is not really an nfs issue, but it is much easier to 492191783Srmacklem * set hostname here and then let the "/etc/rc.xxx" files 493191783Srmacklem * mount the right /var based upon its preset value. 494191783Srmacklem */ 495193066Sjamie mtx_lock(&prison0.pr_mtx); 496194118Sjamie strlcpy(prison0.pr_hostname, nd->my_hostnam, 497194118Sjamie sizeof(prison0.pr_hostname)); 498193066Sjamie mtx_unlock(&prison0.pr_mtx); 499191783Srmacklem inittodr(ntohl(nd->root_time)); 500191783Srmacklem return (0); 501191783Srmacklem} 502191783Srmacklem 503191783Srmacklem/* 504191783Srmacklem * Internal version of mount system call for diskless setup. 505191783Srmacklem */ 506191783Srmacklemstatic int 507191783Srmacklemnfs_mountdiskless(char *path, 508191783Srmacklem struct sockaddr_in *sin, struct nfs_args *args, struct thread *td, 509191783Srmacklem struct vnode **vpp, struct mount *mp) 510191783Srmacklem{ 511191783Srmacklem struct sockaddr *nam; 512221014Srmacklem int dirlen, error; 513221014Srmacklem char *dirpath; 514191783Srmacklem 515221014Srmacklem /* 516221014Srmacklem * Find the directory path in "path", which also has the server's 517221014Srmacklem * name/ip address in it. 518221014Srmacklem */ 519221014Srmacklem dirpath = strchr(path, ':'); 520221014Srmacklem if (dirpath != NULL) 521221014Srmacklem dirlen = strlen(++dirpath); 522221014Srmacklem else 523221014Srmacklem dirlen = 0; 524191783Srmacklem nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); 525221014Srmacklem if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen, 526233326Sjhb NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO, 527233326Sjhb NFS_DEFAULT_NEGNAMETIMEO)) != 0) { 528192145Srmacklem printf("nfs_mountroot: mount %s on /: %d\n", path, error); 529191783Srmacklem return (error); 530191783Srmacklem } 531191783Srmacklem return (0); 532191783Srmacklem} 533191783Srmacklem 534191783Srmacklemstatic void 535192585Srmacklemnfs_sec_name(char *sec, int *flagsp) 536192585Srmacklem{ 537192585Srmacklem if (!strcmp(sec, "krb5")) 538192585Srmacklem *flagsp |= NFSMNT_KERB; 539192585Srmacklem else if (!strcmp(sec, "krb5i")) 540192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY); 541192585Srmacklem else if (!strcmp(sec, "krb5p")) 542192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY); 543192585Srmacklem} 544192585Srmacklem 545192585Srmacklemstatic void 546191783Srmacklemnfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, 547214048Srmacklem const char *hostname, struct ucred *cred, struct thread *td) 548191783Srmacklem{ 549191783Srmacklem int s; 550191783Srmacklem int adjsock; 551214048Srmacklem char *p; 552191783Srmacklem 553191783Srmacklem s = splnet(); 554191783Srmacklem 555191783Srmacklem /* 556191783Srmacklem * Set read-only flag if requested; otherwise, clear it if this is 557191783Srmacklem * an update. If this is not an update, then either the read-only 558191783Srmacklem * flag is already clear, or this is a root mount and it was set 559191783Srmacklem * intentionally at some previous point. 560191783Srmacklem */ 561191783Srmacklem if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) { 562191783Srmacklem MNT_ILOCK(mp); 563191783Srmacklem mp->mnt_flag |= MNT_RDONLY; 564191783Srmacklem MNT_IUNLOCK(mp); 565191783Srmacklem } else if (mp->mnt_flag & MNT_UPDATE) { 566191783Srmacklem MNT_ILOCK(mp); 567191783Srmacklem mp->mnt_flag &= ~MNT_RDONLY; 568191783Srmacklem MNT_IUNLOCK(mp); 569191783Srmacklem } 570191783Srmacklem 571191783Srmacklem /* 572191783Srmacklem * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 573191783Srmacklem * no sense in that context. Also, set up appropriate retransmit 574191783Srmacklem * and soft timeout behavior. 575191783Srmacklem */ 576191783Srmacklem if (argp->sotype == SOCK_STREAM) { 577191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOCONN; 578191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 579220739Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0) 580220739Srmacklem nmp->nm_retry = INT_MAX; 581220739Srmacklem else 582220739Srmacklem nmp->nm_retry = NFS_RETRANS_TCP; 583191783Srmacklem } 584191783Srmacklem 585220739Srmacklem /* Also clear RDIRPLUS if NFSv2, it crashes some servers */ 586220739Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 587220739Srmacklem argp->flags &= ~NFSMNT_RDIRPLUS; 588191783Srmacklem nmp->nm_flag &= ~NFSMNT_RDIRPLUS; 589220739Srmacklem } 590191783Srmacklem 591220739Srmacklem /* Re-bind if rsrvd port requested and wasn't on one */ 592220739Srmacklem adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT) 593220739Srmacklem && (argp->flags & NFSMNT_RESVPORT); 594191783Srmacklem /* Also re-bind if we're switching to/from a connected UDP socket */ 595220739Srmacklem adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) != 596191783Srmacklem (argp->flags & NFSMNT_NOCONN)); 597191783Srmacklem 598191783Srmacklem /* Update flags atomically. Don't change the lock bits. */ 599191783Srmacklem nmp->nm_flag = argp->flags | nmp->nm_flag; 600191783Srmacklem splx(s); 601191783Srmacklem 602191783Srmacklem if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 603191783Srmacklem nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 604191783Srmacklem if (nmp->nm_timeo < NFS_MINTIMEO) 605191783Srmacklem nmp->nm_timeo = NFS_MINTIMEO; 606191783Srmacklem else if (nmp->nm_timeo > NFS_MAXTIMEO) 607191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 608191783Srmacklem } 609191783Srmacklem 610191783Srmacklem if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 611191783Srmacklem nmp->nm_retry = argp->retrans; 612191783Srmacklem if (nmp->nm_retry > NFS_MAXREXMIT) 613191783Srmacklem nmp->nm_retry = NFS_MAXREXMIT; 614191783Srmacklem } 615191783Srmacklem 616191783Srmacklem if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 617191783Srmacklem nmp->nm_wsize = argp->wsize; 618191783Srmacklem /* Round down to multiple of blocksize */ 619191783Srmacklem nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); 620191783Srmacklem if (nmp->nm_wsize <= 0) 621191783Srmacklem nmp->nm_wsize = NFS_FABLKSIZE; 622191783Srmacklem } 623191783Srmacklem 624191783Srmacklem if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 625191783Srmacklem nmp->nm_rsize = argp->rsize; 626191783Srmacklem /* Round down to multiple of blocksize */ 627191783Srmacklem nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); 628191783Srmacklem if (nmp->nm_rsize <= 0) 629191783Srmacklem nmp->nm_rsize = NFS_FABLKSIZE; 630191783Srmacklem } 631191783Srmacklem 632191783Srmacklem if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 633191783Srmacklem nmp->nm_readdirsize = argp->readdirsize; 634191783Srmacklem } 635191783Srmacklem 636191783Srmacklem if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) 637191783Srmacklem nmp->nm_acregmin = argp->acregmin; 638191783Srmacklem else 639191783Srmacklem nmp->nm_acregmin = NFS_MINATTRTIMO; 640191783Srmacklem if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) 641191783Srmacklem nmp->nm_acregmax = argp->acregmax; 642191783Srmacklem else 643191783Srmacklem nmp->nm_acregmax = NFS_MAXATTRTIMO; 644191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) 645191783Srmacklem nmp->nm_acdirmin = argp->acdirmin; 646191783Srmacklem else 647191783Srmacklem nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; 648191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) 649191783Srmacklem nmp->nm_acdirmax = argp->acdirmax; 650191783Srmacklem else 651191783Srmacklem nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; 652191783Srmacklem if (nmp->nm_acdirmin > nmp->nm_acdirmax) 653191783Srmacklem nmp->nm_acdirmin = nmp->nm_acdirmax; 654191783Srmacklem if (nmp->nm_acregmin > nmp->nm_acregmax) 655191783Srmacklem nmp->nm_acregmin = nmp->nm_acregmax; 656191783Srmacklem 657191783Srmacklem if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { 658191783Srmacklem if (argp->readahead <= NFS_MAXRAHEAD) 659191783Srmacklem nmp->nm_readahead = argp->readahead; 660191783Srmacklem else 661191783Srmacklem nmp->nm_readahead = NFS_MAXRAHEAD; 662191783Srmacklem } 663191783Srmacklem if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) { 664191783Srmacklem if (argp->wcommitsize < nmp->nm_wsize) 665191783Srmacklem nmp->nm_wcommitsize = nmp->nm_wsize; 666191783Srmacklem else 667191783Srmacklem nmp->nm_wcommitsize = argp->wcommitsize; 668191783Srmacklem } 669191783Srmacklem 670191783Srmacklem adjsock |= ((nmp->nm_sotype != argp->sotype) || 671191783Srmacklem (nmp->nm_soproto != argp->proto)); 672191783Srmacklem 673191783Srmacklem if (nmp->nm_client != NULL && adjsock) { 674191783Srmacklem int haslock = 0, error = 0; 675191783Srmacklem 676191783Srmacklem if (nmp->nm_sotype == SOCK_STREAM) { 677191783Srmacklem error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock); 678191783Srmacklem if (!error) 679191783Srmacklem haslock = 1; 680191783Srmacklem } 681191783Srmacklem if (!error) { 682191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 683191783Srmacklem if (haslock) 684191783Srmacklem newnfs_sndunlock(&nmp->nm_sockreq.nr_lock); 685191783Srmacklem nmp->nm_sotype = argp->sotype; 686191783Srmacklem nmp->nm_soproto = argp->proto; 687191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 688191783Srmacklem while (newnfs_connect(nmp, &nmp->nm_sockreq, 689191783Srmacklem cred, td, 0)) { 690191783Srmacklem printf("newnfs_args: retrying connect\n"); 691207170Srmacklem (void) nfs_catnap(PSOCK, 0, "newnfscon"); 692191783Srmacklem } 693191783Srmacklem } 694191783Srmacklem } else { 695191783Srmacklem nmp->nm_sotype = argp->sotype; 696191783Srmacklem nmp->nm_soproto = argp->proto; 697191783Srmacklem } 698214048Srmacklem 699214048Srmacklem if (hostname != NULL) { 700214048Srmacklem strlcpy(nmp->nm_hostname, hostname, 701214048Srmacklem sizeof(nmp->nm_hostname)); 702214048Srmacklem p = strchr(nmp->nm_hostname, ':'); 703214048Srmacklem if (p != NULL) 704214048Srmacklem *p = '\0'; 705214048Srmacklem } 706191783Srmacklem} 707191783Srmacklem 708221190Srmacklemstatic const char *nfs_opts[] = { "from", "nfs_args", 709191783Srmacklem "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union", 710191783Srmacklem "noclusterr", "noclusterw", "multilabel", "acls", "force", "update", 711192585Srmacklem "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus", 712192585Srmacklem "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize", 713192585Srmacklem "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport", 714192585Srmacklem "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec", 715192585Srmacklem "principal", "nfsv4", "gssname", "allgssname", "dirpath", 716260170Srmacklem "nametimeo", "negnametimeo", "nocto", "noncontigwr", "wcommitsize", 717191783Srmacklem NULL }; 718191783Srmacklem 719191783Srmacklem/* 720191783Srmacklem * VFS Operations. 721191783Srmacklem * 722191783Srmacklem * mount system call 723191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 724191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 725191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 726191783Srmacklem * an error after that means that I have to release the mbuf. 727191783Srmacklem */ 728191783Srmacklem/* ARGSUSED */ 729191783Srmacklemstatic int 730191990Sattilionfs_mount(struct mount *mp) 731191783Srmacklem{ 732191783Srmacklem struct nfs_args args = { 733191783Srmacklem .version = NFS_ARGSVERSION, 734191783Srmacklem .addr = NULL, 735191783Srmacklem .addrlen = sizeof (struct sockaddr_in), 736191783Srmacklem .sotype = SOCK_STREAM, 737191783Srmacklem .proto = 0, 738191783Srmacklem .fh = NULL, 739191783Srmacklem .fhsize = 0, 740220739Srmacklem .flags = NFSMNT_RESVPORT, 741191783Srmacklem .wsize = NFS_WSIZE, 742191783Srmacklem .rsize = NFS_RSIZE, 743191783Srmacklem .readdirsize = NFS_READDIRSIZE, 744191783Srmacklem .timeo = 10, 745191783Srmacklem .retrans = NFS_RETRANS, 746191783Srmacklem .readahead = NFS_DEFRAHEAD, 747191783Srmacklem .wcommitsize = 0, /* was: NQ_DEFLEASE */ 748191783Srmacklem .hostname = NULL, 749191783Srmacklem .acregmin = NFS_MINATTRTIMO, 750191783Srmacklem .acregmax = NFS_MAXATTRTIMO, 751191783Srmacklem .acdirmin = NFS_MINDIRATTRTIMO, 752191783Srmacklem .acdirmax = NFS_MAXDIRATTRTIMO, 753191783Srmacklem }; 754192585Srmacklem int error = 0, ret, len; 755192585Srmacklem struct sockaddr *nam = NULL; 756191783Srmacklem struct vnode *vp; 757191990Sattilio struct thread *td; 758191783Srmacklem char hst[MNAMELEN]; 759191783Srmacklem u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100]; 760192585Srmacklem char *opt, *name, *secname; 761233326Sjhb int nametimeo = NFS_DEFAULT_NAMETIMEO; 762203303Srmacklem int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO; 763221190Srmacklem int dirlen, has_nfs_args_opt, krbnamelen, srvkrbnamelen; 764221205Srmacklem size_t hstlen; 765191783Srmacklem 766221190Srmacklem has_nfs_args_opt = 0; 767191783Srmacklem if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) { 768191783Srmacklem error = EINVAL; 769191783Srmacklem goto out; 770191783Srmacklem } 771191783Srmacklem 772191990Sattilio td = curthread; 773191783Srmacklem if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) { 774221040Srmacklem error = nfs_mountroot(mp); 775191783Srmacklem goto out; 776191783Srmacklem } 777191783Srmacklem 778192585Srmacklem nfscl_init(); 779191783Srmacklem 780221190Srmacklem /* 781221190Srmacklem * The old mount_nfs program passed the struct nfs_args 782221190Srmacklem * from userspace to kernel. The new mount_nfs program 783221190Srmacklem * passes string options via nmount() from userspace to kernel 784221190Srmacklem * and we populate the struct nfs_args in the kernel. 785221190Srmacklem */ 786221190Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) { 787221190Srmacklem error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args, 788221190Srmacklem sizeof(args)); 789221190Srmacklem if (error != 0) 790221190Srmacklem goto out; 791221190Srmacklem 792221190Srmacklem if (args.version != NFS_ARGSVERSION) { 793221190Srmacklem error = EPROGMISMATCH; 794221190Srmacklem goto out; 795221190Srmacklem } 796221190Srmacklem has_nfs_args_opt = 1; 797221190Srmacklem } 798221190Srmacklem 799192585Srmacklem /* Handle the new style options. */ 800192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0) 801192585Srmacklem args.flags |= NFSMNT_NOCONN; 802192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0) 803192585Srmacklem args.flags |= NFSMNT_NOCONN; 804192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0) 805192585Srmacklem args.flags |= NFSMNT_NOLOCKD; 806192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0) 807192585Srmacklem args.flags &= ~NFSMNT_NOLOCKD; 808192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0) 809192585Srmacklem args.flags |= NFSMNT_INT; 810192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0) 811192585Srmacklem args.flags |= NFSMNT_RDIRPLUS; 812192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0) 813192585Srmacklem args.flags |= NFSMNT_RESVPORT; 814192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0) 815192585Srmacklem args.flags &= ~NFSMNT_RESVPORT; 816192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0) 817192585Srmacklem args.flags |= NFSMNT_SOFT; 818192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0) 819192585Srmacklem args.flags &= ~NFSMNT_SOFT; 820192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0) 821192585Srmacklem args.sotype = SOCK_DGRAM; 822192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0) 823192585Srmacklem args.sotype = SOCK_DGRAM; 824192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0) 825192585Srmacklem args.sotype = SOCK_STREAM; 826192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0) 827192585Srmacklem args.flags |= NFSMNT_NFSV3; 828192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) { 829192585Srmacklem args.flags |= NFSMNT_NFSV4; 830192585Srmacklem args.sotype = SOCK_STREAM; 831191783Srmacklem } 832192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0) 833192585Srmacklem args.flags |= NFSMNT_ALLGSSNAME; 834221436Sru if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0) 835221436Sru args.flags |= NFSMNT_NOCTO; 836260170Srmacklem if (vfs_getopt(mp->mnt_optnew, "noncontigwr", NULL, NULL) == 0) 837260170Srmacklem args.flags |= NFSMNT_NONCONTIGWR; 838192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) { 839192585Srmacklem if (opt == NULL) { 840192585Srmacklem vfs_mount_error(mp, "illegal readdirsize"); 841192585Srmacklem error = EINVAL; 842192585Srmacklem goto out; 843192585Srmacklem } 844192585Srmacklem ret = sscanf(opt, "%d", &args.readdirsize); 845192585Srmacklem if (ret != 1 || args.readdirsize <= 0) { 846192585Srmacklem vfs_mount_error(mp, "illegal readdirsize: %s", 847192585Srmacklem opt); 848192585Srmacklem error = EINVAL; 849192585Srmacklem goto out; 850192585Srmacklem } 851192585Srmacklem args.flags |= NFSMNT_READDIRSIZE; 852192585Srmacklem } 853192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) { 854192585Srmacklem if (opt == NULL) { 855192585Srmacklem vfs_mount_error(mp, "illegal readahead"); 856192585Srmacklem error = EINVAL; 857192585Srmacklem goto out; 858192585Srmacklem } 859192585Srmacklem ret = sscanf(opt, "%d", &args.readahead); 860192585Srmacklem if (ret != 1 || args.readahead <= 0) { 861192585Srmacklem vfs_mount_error(mp, "illegal readahead: %s", 862192585Srmacklem opt); 863192585Srmacklem error = EINVAL; 864192585Srmacklem goto out; 865192585Srmacklem } 866192585Srmacklem args.flags |= NFSMNT_READAHEAD; 867192585Srmacklem } 868192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) { 869192585Srmacklem if (opt == NULL) { 870192585Srmacklem vfs_mount_error(mp, "illegal wsize"); 871192585Srmacklem error = EINVAL; 872192585Srmacklem goto out; 873192585Srmacklem } 874192585Srmacklem ret = sscanf(opt, "%d", &args.wsize); 875192585Srmacklem if (ret != 1 || args.wsize <= 0) { 876192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 877192585Srmacklem opt); 878192585Srmacklem error = EINVAL; 879192585Srmacklem goto out; 880192585Srmacklem } 881192585Srmacklem args.flags |= NFSMNT_WSIZE; 882192585Srmacklem } 883192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) { 884192585Srmacklem if (opt == NULL) { 885192585Srmacklem vfs_mount_error(mp, "illegal rsize"); 886192585Srmacklem error = EINVAL; 887192585Srmacklem goto out; 888192585Srmacklem } 889192585Srmacklem ret = sscanf(opt, "%d", &args.rsize); 890192585Srmacklem if (ret != 1 || args.rsize <= 0) { 891192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 892192585Srmacklem opt); 893192585Srmacklem error = EINVAL; 894192585Srmacklem goto out; 895192585Srmacklem } 896192585Srmacklem args.flags |= NFSMNT_RSIZE; 897192585Srmacklem } 898192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) { 899192585Srmacklem if (opt == NULL) { 900192585Srmacklem vfs_mount_error(mp, "illegal retrans"); 901192585Srmacklem error = EINVAL; 902192585Srmacklem goto out; 903192585Srmacklem } 904192585Srmacklem ret = sscanf(opt, "%d", &args.retrans); 905192585Srmacklem if (ret != 1 || args.retrans <= 0) { 906192585Srmacklem vfs_mount_error(mp, "illegal retrans: %s", 907192585Srmacklem opt); 908192585Srmacklem error = EINVAL; 909192585Srmacklem goto out; 910192585Srmacklem } 911192585Srmacklem args.flags |= NFSMNT_RETRANS; 912192585Srmacklem } 913192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) { 914192585Srmacklem ret = sscanf(opt, "%d", &args.acregmin); 915192585Srmacklem if (ret != 1 || args.acregmin < 0) { 916192585Srmacklem vfs_mount_error(mp, "illegal acregmin: %s", 917192585Srmacklem opt); 918192585Srmacklem error = EINVAL; 919192585Srmacklem goto out; 920192585Srmacklem } 921192585Srmacklem args.flags |= NFSMNT_ACREGMIN; 922192585Srmacklem } 923192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) { 924192585Srmacklem ret = sscanf(opt, "%d", &args.acregmax); 925192585Srmacklem if (ret != 1 || args.acregmax < 0) { 926192585Srmacklem vfs_mount_error(mp, "illegal acregmax: %s", 927192585Srmacklem opt); 928192585Srmacklem error = EINVAL; 929192585Srmacklem goto out; 930192585Srmacklem } 931192585Srmacklem args.flags |= NFSMNT_ACREGMAX; 932192585Srmacklem } 933192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) { 934192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmin); 935192585Srmacklem if (ret != 1 || args.acdirmin < 0) { 936192585Srmacklem vfs_mount_error(mp, "illegal acdirmin: %s", 937192585Srmacklem opt); 938192585Srmacklem error = EINVAL; 939192585Srmacklem goto out; 940192585Srmacklem } 941192585Srmacklem args.flags |= NFSMNT_ACDIRMIN; 942192585Srmacklem } 943192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) { 944192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmax); 945192585Srmacklem if (ret != 1 || args.acdirmax < 0) { 946192585Srmacklem vfs_mount_error(mp, "illegal acdirmax: %s", 947192585Srmacklem opt); 948192585Srmacklem error = EINVAL; 949192585Srmacklem goto out; 950192585Srmacklem } 951192585Srmacklem args.flags |= NFSMNT_ACDIRMAX; 952192585Srmacklem } 953229604Sjhb if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) { 954229604Sjhb ret = sscanf(opt, "%d", &args.wcommitsize); 955229604Sjhb if (ret != 1 || args.wcommitsize < 0) { 956229604Sjhb vfs_mount_error(mp, "illegal wcommitsize: %s", opt); 957229604Sjhb error = EINVAL; 958229604Sjhb goto out; 959229604Sjhb } 960229604Sjhb args.flags |= NFSMNT_WCOMMITSIZE; 961229604Sjhb } 962192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) { 963192585Srmacklem ret = sscanf(opt, "%d", &args.timeo); 964192585Srmacklem if (ret != 1 || args.timeo <= 0) { 965192585Srmacklem vfs_mount_error(mp, "illegal timeout: %s", 966192585Srmacklem opt); 967192585Srmacklem error = EINVAL; 968192585Srmacklem goto out; 969192585Srmacklem } 970192585Srmacklem args.flags |= NFSMNT_TIMEO; 971192585Srmacklem } 972233326Sjhb if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) { 973233326Sjhb ret = sscanf(opt, "%d", &nametimeo); 974233326Sjhb if (ret != 1 || nametimeo < 0) { 975233326Sjhb vfs_mount_error(mp, "illegal nametimeo: %s", opt); 976233326Sjhb error = EINVAL; 977233326Sjhb goto out; 978233326Sjhb } 979233326Sjhb } 980203303Srmacklem if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL) 981203303Srmacklem == 0) { 982203303Srmacklem ret = sscanf(opt, "%d", &negnametimeo); 983203303Srmacklem if (ret != 1 || negnametimeo < 0) { 984203303Srmacklem vfs_mount_error(mp, "illegal negnametimeo: %s", 985203303Srmacklem opt); 986203303Srmacklem error = EINVAL; 987203303Srmacklem goto out; 988203303Srmacklem } 989203303Srmacklem } 990192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "sec", 991192585Srmacklem (void **) &secname, NULL) == 0) 992192585Srmacklem nfs_sec_name(secname, &args.flags); 993191783Srmacklem 994191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 995191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 996191783Srmacklem 997191783Srmacklem if (nmp == NULL) { 998191783Srmacklem error = EIO; 999191783Srmacklem goto out; 1000191783Srmacklem } 1001231636Srmacklem 1002191783Srmacklem /* 1003231636Srmacklem * If a change from TCP->UDP is done and there are thread(s) 1004231636Srmacklem * that have I/O RPC(s) in progress with a tranfer size 1005231636Srmacklem * greater than NFS_MAXDGRAMDATA, those thread(s) will be 1006231636Srmacklem * hung, retrying the RPC(s) forever. Usually these threads 1007231636Srmacklem * will be seen doing an uninterruptible sleep on wait channel 1008231636Srmacklem * "newnfsreq" (truncated to "newnfsre" by procstat). 1009231636Srmacklem */ 1010231636Srmacklem if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM) 1011231636Srmacklem tprintf(td->td_proc, LOG_WARNING, 1012231636Srmacklem "Warning: mount -u that changes TCP->UDP can result in hung threads\n"); 1013231636Srmacklem 1014231636Srmacklem /* 1015191783Srmacklem * When doing an update, we can't change version, 1016191783Srmacklem * security, switch lockd strategies or change cookie 1017191783Srmacklem * translation 1018191783Srmacklem */ 1019191783Srmacklem args.flags = (args.flags & 1020191783Srmacklem ~(NFSMNT_NFSV3 | 1021191783Srmacklem NFSMNT_NFSV4 | 1022191783Srmacklem NFSMNT_KERB | 1023191783Srmacklem NFSMNT_INTEGRITY | 1024191783Srmacklem NFSMNT_PRIVACY | 1025191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) | 1026191783Srmacklem (nmp->nm_flag & 1027191783Srmacklem (NFSMNT_NFSV3 | 1028191783Srmacklem NFSMNT_NFSV4 | 1029191783Srmacklem NFSMNT_KERB | 1030191783Srmacklem NFSMNT_INTEGRITY | 1031191783Srmacklem NFSMNT_PRIVACY | 1032191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); 1033214048Srmacklem nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td); 1034191783Srmacklem goto out; 1035191783Srmacklem } 1036191783Srmacklem 1037191783Srmacklem /* 1038191783Srmacklem * Make the nfs_ip_paranoia sysctl serve as the default connection 1039191783Srmacklem * or no-connection mode for those protocols that support 1040191783Srmacklem * no-connection mode (the flag will be cleared later for protocols 1041191783Srmacklem * that do not support no-connection mode). This will allow a client 1042191783Srmacklem * to receive replies from a different IP then the request was 1043191783Srmacklem * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid), 1044191783Srmacklem * not 0. 1045191783Srmacklem */ 1046191783Srmacklem if (nfs_ip_paranoia == 0) 1047191783Srmacklem args.flags |= NFSMNT_NOCONN; 1048192585Srmacklem 1049221190Srmacklem if (has_nfs_args_opt != 0) { 1050221190Srmacklem /* 1051221190Srmacklem * In the 'nfs_args' case, the pointers in the args 1052221190Srmacklem * structure are in userland - we copy them in here. 1053221190Srmacklem */ 1054221190Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) { 1055192585Srmacklem vfs_mount_error(mp, "Bad file handle"); 1056191783Srmacklem error = EINVAL; 1057191783Srmacklem goto out; 1058191783Srmacklem } 1059221190Srmacklem error = copyin((caddr_t)args.fh, (caddr_t)nfh, 1060221190Srmacklem args.fhsize); 1061221190Srmacklem if (error != 0) 1062221190Srmacklem goto out; 1063221205Srmacklem error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen); 1064221190Srmacklem if (error != 0) 1065221190Srmacklem goto out; 1066221205Srmacklem bzero(&hst[hstlen], MNAMELEN - hstlen); 1067221190Srmacklem args.hostname = hst; 1068221190Srmacklem /* sockargs() call must be after above copyin() calls */ 1069221190Srmacklem error = getsockaddr(&nam, (caddr_t)args.addr, 1070221190Srmacklem args.addrlen); 1071221190Srmacklem if (error != 0) 1072221190Srmacklem goto out; 1073191783Srmacklem } else { 1074221190Srmacklem if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh, 1075221190Srmacklem &args.fhsize) == 0) { 1076221190Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) { 1077221190Srmacklem vfs_mount_error(mp, "Bad file handle"); 1078221190Srmacklem error = EINVAL; 1079221190Srmacklem goto out; 1080221190Srmacklem } 1081221190Srmacklem bcopy(args.fh, nfh, args.fhsize); 1082221190Srmacklem } else { 1083221190Srmacklem args.fhsize = 0; 1084221190Srmacklem } 1085221190Srmacklem (void) vfs_getopt(mp->mnt_optnew, "hostname", 1086221190Srmacklem (void **)&args.hostname, &len); 1087221190Srmacklem if (args.hostname == NULL) { 1088221190Srmacklem vfs_mount_error(mp, "Invalid hostname"); 1089221190Srmacklem error = EINVAL; 1090221190Srmacklem goto out; 1091221190Srmacklem } 1092221190Srmacklem bcopy(args.hostname, hst, MNAMELEN); 1093221190Srmacklem hst[MNAMELEN - 1] = '\0'; 1094192585Srmacklem } 1095192585Srmacklem 1096192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0) 1097192585Srmacklem strlcpy(srvkrbname, name, sizeof (srvkrbname)); 1098192585Srmacklem else 1099192585Srmacklem snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst); 1100221014Srmacklem srvkrbnamelen = strlen(srvkrbname); 1101192585Srmacklem 1102192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0) 1103192585Srmacklem strlcpy(krbname, name, sizeof (krbname)); 1104192585Srmacklem else 1105191783Srmacklem krbname[0] = '\0'; 1106221014Srmacklem krbnamelen = strlen(krbname); 1107192585Srmacklem 1108192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0) 1109192585Srmacklem strlcpy(dirpath, name, sizeof (dirpath)); 1110192585Srmacklem else 1111191783Srmacklem dirpath[0] = '\0'; 1112221014Srmacklem dirlen = strlen(dirpath); 1113192585Srmacklem 1114222075Srmacklem if (has_nfs_args_opt == 0) { 1115222075Srmacklem if (vfs_getopt(mp->mnt_optnew, "addr", 1116222075Srmacklem (void **)&args.addr, &args.addrlen) == 0) { 1117222075Srmacklem if (args.addrlen > SOCK_MAXADDRLEN) { 1118222075Srmacklem error = ENAMETOOLONG; 1119222075Srmacklem goto out; 1120222075Srmacklem } 1121222075Srmacklem nam = malloc(args.addrlen, M_SONAME, M_WAITOK); 1122222075Srmacklem bcopy(args.addr, nam, args.addrlen); 1123222075Srmacklem nam->sa_len = args.addrlen; 1124222075Srmacklem } else { 1125222075Srmacklem vfs_mount_error(mp, "No server address"); 1126222075Srmacklem error = EINVAL; 1127191783Srmacklem goto out; 1128191783Srmacklem } 1129191783Srmacklem } 1130192585Srmacklem 1131191783Srmacklem args.fh = nfh; 1132221014Srmacklem error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath, 1133221014Srmacklem dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td, 1134233326Sjhb nametimeo, negnametimeo); 1135191783Srmacklemout: 1136191783Srmacklem if (!error) { 1137191783Srmacklem MNT_ILOCK(mp); 1138239852Skib mp->mnt_kern_flag |= MNTK_MPSAFE | MNTK_LOOKUP_SHARED | 1139239852Skib MNTK_NO_IOPF; 1140191783Srmacklem MNT_IUNLOCK(mp); 1141191783Srmacklem } 1142191783Srmacklem return (error); 1143191783Srmacklem} 1144191783Srmacklem 1145191783Srmacklem 1146191783Srmacklem/* 1147191783Srmacklem * VFS Operations. 1148191783Srmacklem * 1149191783Srmacklem * mount system call 1150191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 1151191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 1152191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 1153191783Srmacklem * an error after that means that I have to release the mbuf. 1154191783Srmacklem */ 1155191783Srmacklem/* ARGSUSED */ 1156191783Srmacklemstatic int 1157230725Smckusicknfs_cmount(struct mntarg *ma, void *data, uint64_t flags) 1158191783Srmacklem{ 1159191783Srmacklem int error; 1160191783Srmacklem struct nfs_args args; 1161191783Srmacklem 1162191783Srmacklem error = copyin(data, &args, sizeof (struct nfs_args)); 1163191783Srmacklem if (error) 1164191783Srmacklem return error; 1165191783Srmacklem 1166191783Srmacklem ma = mount_arg(ma, "nfs_args", &args, sizeof args); 1167191783Srmacklem 1168191783Srmacklem error = kernel_mount(ma, flags); 1169191783Srmacklem return (error); 1170191783Srmacklem} 1171191783Srmacklem 1172191783Srmacklem/* 1173191783Srmacklem * Common code for mount and mountroot 1174191783Srmacklem */ 1175191783Srmacklemstatic int 1176191783Srmacklemmountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, 1177221014Srmacklem char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen, 1178221014Srmacklem u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp, 1179233326Sjhb struct ucred *cred, struct thread *td, int nametimeo, int negnametimeo) 1180191783Srmacklem{ 1181191783Srmacklem struct nfsmount *nmp; 1182191783Srmacklem struct nfsnode *np; 1183195762Srmacklem int error, trycnt, ret; 1184191783Srmacklem struct nfsvattr nfsva; 1185191783Srmacklem static u_int64_t clval = 0; 1186191783Srmacklem 1187191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 1188191783Srmacklem nmp = VFSTONFS(mp); 1189191783Srmacklem printf("%s: MNT_UPDATE is no longer handled here\n", __func__); 1190191783Srmacklem FREE(nam, M_SONAME); 1191191783Srmacklem return (0); 1192191783Srmacklem } else { 1193191783Srmacklem MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) + 1194221014Srmacklem krbnamelen + dirlen + srvkrbnamelen + 2, 1195221014Srmacklem M_NEWNFSMNT, M_WAITOK | M_ZERO); 1196191783Srmacklem TAILQ_INIT(&nmp->nm_bufq); 1197191783Srmacklem if (clval == 0) 1198191783Srmacklem clval = (u_int64_t)nfsboottime.tv_sec; 1199191783Srmacklem nmp->nm_clval = clval++; 1200221014Srmacklem nmp->nm_krbnamelen = krbnamelen; 1201221014Srmacklem nmp->nm_dirpathlen = dirlen; 1202221014Srmacklem nmp->nm_srvkrbnamelen = srvkrbnamelen; 1203192675Srmacklem if (td->td_ucred->cr_uid != (uid_t)0) { 1204191783Srmacklem /* 1205192675Srmacklem * nm_uid is used to get KerberosV credentials for 1206192675Srmacklem * the nfsv4 state handling operations if there is 1207192675Srmacklem * no host based principal set. Use the uid of 1208192675Srmacklem * this user if not root, since they are doing the 1209192675Srmacklem * mount. I don't think setting this for root will 1210192675Srmacklem * work, since root normally does not have user 1211192675Srmacklem * credentials in a credentials cache. 1212191783Srmacklem */ 1213192675Srmacklem nmp->nm_uid = td->td_ucred->cr_uid; 1214191783Srmacklem } else { 1215191783Srmacklem /* 1216192675Srmacklem * Just set to -1, so it won't be used. 1217191783Srmacklem */ 1218191783Srmacklem nmp->nm_uid = (uid_t)-1; 1219191783Srmacklem } 1220191783Srmacklem 1221191783Srmacklem /* Copy and null terminate all the names */ 1222191783Srmacklem if (nmp->nm_krbnamelen > 0) { 1223191783Srmacklem bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen); 1224191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen] = '\0'; 1225191783Srmacklem } 1226191783Srmacklem if (nmp->nm_dirpathlen > 0) { 1227191783Srmacklem bcopy(dirpath, NFSMNT_DIRPATH(nmp), 1228191783Srmacklem nmp->nm_dirpathlen); 1229191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1230191783Srmacklem + 1] = '\0'; 1231191783Srmacklem } 1232191783Srmacklem if (nmp->nm_srvkrbnamelen > 0) { 1233191783Srmacklem bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp), 1234191783Srmacklem nmp->nm_srvkrbnamelen); 1235191783Srmacklem nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1236191783Srmacklem + nmp->nm_srvkrbnamelen + 2] = '\0'; 1237191783Srmacklem } 1238191783Srmacklem nmp->nm_sockreq.nr_cred = crhold(cred); 1239191783Srmacklem mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF); 1240191783Srmacklem mp->mnt_data = nmp; 1241214048Srmacklem nmp->nm_getinfo = nfs_getnlminfo; 1242216931Srmacklem nmp->nm_vinvalbuf = ncl_vinvalbuf; 1243191783Srmacklem } 1244191783Srmacklem vfs_getnewfsid(mp); 1245191783Srmacklem nmp->nm_mountp = mp; 1246233326Sjhb mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK); 1247229172Srmacklem 1248229172Srmacklem /* 1249233326Sjhb * Since nfs_decode_args() might optionally set them, these 1250233326Sjhb * need to be set to defaults before the call, so that the 1251233326Sjhb * optional settings aren't overwritten. 1252229172Srmacklem */ 1253233326Sjhb nmp->nm_nametimeo = nametimeo; 1254203303Srmacklem nmp->nm_negnametimeo = negnametimeo; 1255229172Srmacklem nmp->nm_timeo = NFS_TIMEO; 1256229172Srmacklem nmp->nm_retry = NFS_RETRANS; 1257229172Srmacklem nmp->nm_readahead = NFS_DEFRAHEAD; 1258229263Srmacklem if (desiredvnodes >= 11000) 1259229263Srmacklem nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000); 1260229263Srmacklem else 1261229263Srmacklem nmp->nm_wcommitsize = hibufspace / 10; 1262191783Srmacklem 1263214048Srmacklem nfs_decode_args(mp, nmp, argp, hst, cred, td); 1264192585Srmacklem 1265191783Srmacklem /* 1266191783Srmacklem * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too 1267191783Srmacklem * high, depending on whether we end up with negative offsets in 1268191783Srmacklem * the client or server somewhere. 2GB-1 may be safer. 1269191783Srmacklem * 1270191783Srmacklem * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum 1271191783Srmacklem * that we can handle until we find out otherwise. 1272191783Srmacklem * XXX Our "safe" limit on the client is what we can store in our 1273191783Srmacklem * buffer cache using signed(!) block numbers. 1274191783Srmacklem */ 1275191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) 1276191783Srmacklem nmp->nm_maxfilesize = 0xffffffffLL; 1277191783Srmacklem else 1278221537Srmacklem nmp->nm_maxfilesize = OFF_MAX; 1279191783Srmacklem 1280191783Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 1281191783Srmacklem nmp->nm_wsize = NFS_WSIZE; 1282191783Srmacklem nmp->nm_rsize = NFS_RSIZE; 1283191783Srmacklem nmp->nm_readdirsize = NFS_READDIRSIZE; 1284191783Srmacklem } 1285191783Srmacklem nmp->nm_numgrps = NFS_MAXGRPS; 1286191783Srmacklem nmp->nm_tprintf_delay = nfs_tprintf_delay; 1287191783Srmacklem if (nmp->nm_tprintf_delay < 0) 1288191783Srmacklem nmp->nm_tprintf_delay = 0; 1289191783Srmacklem nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay; 1290191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1291191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1292191783Srmacklem nmp->nm_fhsize = argp->fhsize; 1293191783Srmacklem if (nmp->nm_fhsize > 0) 1294191783Srmacklem bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 1295191783Srmacklem bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 1296191783Srmacklem nmp->nm_nam = nam; 1297191783Srmacklem /* Set up the sockets and per-host congestion */ 1298191783Srmacklem nmp->nm_sotype = argp->sotype; 1299191783Srmacklem nmp->nm_soproto = argp->proto; 1300191783Srmacklem nmp->nm_sockreq.nr_prog = NFS_PROG; 1301191783Srmacklem if ((argp->flags & NFSMNT_NFSV4)) 1302191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER4; 1303191783Srmacklem else if ((argp->flags & NFSMNT_NFSV3)) 1304191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER3; 1305191783Srmacklem else 1306191783Srmacklem nmp->nm_sockreq.nr_vers = NFS_VER2; 1307191783Srmacklem 1308191783Srmacklem 1309191783Srmacklem if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0))) 1310191783Srmacklem goto bad; 1311191783Srmacklem 1312191783Srmacklem /* 1313191783Srmacklem * A reference count is needed on the nfsnode representing the 1314191783Srmacklem * remote root. If this object is not persistent, then backward 1315191783Srmacklem * traversals of the mount point (i.e. "..") will not work if 1316191783Srmacklem * the nfsnode gets flushed out of the cache. Ufs does not have 1317191783Srmacklem * this problem, because one can identify root inodes by their 1318191783Srmacklem * number == ROOTINO (2). 1319191783Srmacklem */ 1320191783Srmacklem if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) && 1321191783Srmacklem nmp->nm_dirpathlen > 0) { 1322191783Srmacklem /* 1323191783Srmacklem * If the fhsize on the mount point == 0 for V4, the mount 1324191783Srmacklem * path needs to be looked up. 1325191783Srmacklem */ 1326191783Srmacklem trycnt = 3; 1327191783Srmacklem do { 1328191783Srmacklem error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 1329191783Srmacklem cred, td); 1330191783Srmacklem if (error) 1331207170Srmacklem (void) nfs_catnap(PZERO, error, "nfsgetdirp"); 1332191783Srmacklem } while (error && --trycnt > 0); 1333191783Srmacklem if (error) { 1334191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1335191783Srmacklem goto bad; 1336191783Srmacklem } 1337191783Srmacklem } 1338191783Srmacklem if (nmp->nm_fhsize > 0) { 1339195762Srmacklem /* 1340195762Srmacklem * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set 1341195762Srmacklem * non-zero for the root vnode. f_iosize will be set correctly 1342195762Srmacklem * by nfs_statfs() before any I/O occurs. 1343195762Srmacklem */ 1344195762Srmacklem mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ; 1345220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, 1346220732Srmacklem LK_EXCLUSIVE); 1347191783Srmacklem if (error) 1348191783Srmacklem goto bad; 1349191783Srmacklem *vpp = NFSTOV(np); 1350191783Srmacklem 1351191783Srmacklem /* 1352191783Srmacklem * Get file attributes and transfer parameters for the 1353191783Srmacklem * mountpoint. This has the side effect of filling in 1354191783Srmacklem * (*vpp)->v_type with the correct value. 1355191783Srmacklem */ 1356191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 1357191783Srmacklem cred, td, &nfsva, NULL); 1358191783Srmacklem if (ret) { 1359191783Srmacklem /* 1360191783Srmacklem * Just set default values to get things going. 1361191783Srmacklem */ 1362191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 1363191783Srmacklem nfsva.na_vattr.va_type = VDIR; 1364191783Srmacklem nfsva.na_vattr.va_mode = 0777; 1365191783Srmacklem nfsva.na_vattr.va_nlink = 100; 1366191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 1367191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 1368191783Srmacklem nfsva.na_vattr.va_fileid = 2; 1369191783Srmacklem nfsva.na_vattr.va_gen = 1; 1370191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 1371191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 1372191783Srmacklem } 1373191783Srmacklem (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1); 1374191783Srmacklem if (argp->flags & NFSMNT_NFSV3) 1375191783Srmacklem ncl_fsinfo(nmp, *vpp, cred, td); 1376191783Srmacklem 1377222233Srmacklem /* Mark if the mount point supports NFSv4 ACLs. */ 1378222233Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 && 1379222233Srmacklem ret == 0 && 1380222233Srmacklem NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) { 1381222233Srmacklem MNT_ILOCK(mp); 1382222233Srmacklem mp->mnt_flag |= MNT_NFS4ACLS; 1383222233Srmacklem MNT_IUNLOCK(mp); 1384222233Srmacklem } 1385222233Srmacklem 1386191783Srmacklem /* 1387191783Srmacklem * Lose the lock but keep the ref. 1388191783Srmacklem */ 1389224082Szack NFSVOPUNLOCK(*vpp, 0); 1390191783Srmacklem return (0); 1391191783Srmacklem } 1392191783Srmacklem error = EIO; 1393191783Srmacklem 1394191783Srmacklembad: 1395191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1396191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1397191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1398191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1399191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1400191783Srmacklem FREE(nam, M_SONAME); 1401191783Srmacklem return (error); 1402191783Srmacklem} 1403191783Srmacklem 1404191783Srmacklem/* 1405191783Srmacklem * unmount system call 1406191783Srmacklem */ 1407191783Srmacklemstatic int 1408191990Sattilionfs_unmount(struct mount *mp, int mntflags) 1409191783Srmacklem{ 1410191990Sattilio struct thread *td; 1411191783Srmacklem struct nfsmount *nmp; 1412250258Srmacklem int error, flags = 0, i, trycnt = 0; 1413191783Srmacklem 1414191990Sattilio td = curthread; 1415191990Sattilio 1416191783Srmacklem if (mntflags & MNT_FORCE) 1417191783Srmacklem flags |= FORCECLOSE; 1418191783Srmacklem nmp = VFSTONFS(mp); 1419191783Srmacklem /* 1420191783Srmacklem * Goes something like this.. 1421191783Srmacklem * - Call vflush() to clear out vnodes for this filesystem 1422191783Srmacklem * - Close the socket 1423191783Srmacklem * - Free up the data structures 1424191783Srmacklem */ 1425191783Srmacklem /* In the forced case, cancel any outstanding requests. */ 1426191783Srmacklem if (mntflags & MNT_FORCE) { 1427191783Srmacklem error = newnfs_nmcancelreqs(nmp); 1428191783Srmacklem if (error) 1429191783Srmacklem goto out; 1430191783Srmacklem /* For a forced close, get rid of the renew thread now */ 1431191783Srmacklem nfscl_umount(nmp, td); 1432191783Srmacklem } 1433191783Srmacklem /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ 1434191783Srmacklem do { 1435191783Srmacklem error = vflush(mp, 1, flags, td); 1436191783Srmacklem if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30) 1437207170Srmacklem (void) nfs_catnap(PSOCK, error, "newndm"); 1438191783Srmacklem } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30); 1439191783Srmacklem if (error) 1440191783Srmacklem goto out; 1441191783Srmacklem 1442191783Srmacklem /* 1443191783Srmacklem * We are now committed to the unmount. 1444191783Srmacklem */ 1445191783Srmacklem if ((mntflags & MNT_FORCE) == 0) 1446191783Srmacklem nfscl_umount(nmp, td); 1447250258Srmacklem /* Make sure no nfsiods are assigned to this mount. */ 1448250258Srmacklem mtx_lock(&ncl_iod_mutex); 1449250258Srmacklem for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 1450250258Srmacklem if (ncl_iodmount[i] == nmp) { 1451250258Srmacklem ncl_iodwant[i] = NFSIOD_AVAILABLE; 1452250258Srmacklem ncl_iodmount[i] = NULL; 1453250258Srmacklem } 1454250258Srmacklem mtx_unlock(&ncl_iod_mutex); 1455191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1456191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1457191783Srmacklem FREE(nmp->nm_nam, M_SONAME); 1458191783Srmacklem 1459191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1460191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1461191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1462191783Srmacklemout: 1463191783Srmacklem return (error); 1464191783Srmacklem} 1465191783Srmacklem 1466191783Srmacklem/* 1467191783Srmacklem * Return root of a filesystem 1468191783Srmacklem */ 1469191783Srmacklemstatic int 1470191990Sattilionfs_root(struct mount *mp, int flags, struct vnode **vpp) 1471191783Srmacklem{ 1472191783Srmacklem struct vnode *vp; 1473191783Srmacklem struct nfsmount *nmp; 1474191783Srmacklem struct nfsnode *np; 1475191783Srmacklem int error; 1476191783Srmacklem 1477191783Srmacklem nmp = VFSTONFS(mp); 1478220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags); 1479191783Srmacklem if (error) 1480191783Srmacklem return error; 1481191783Srmacklem vp = NFSTOV(np); 1482191783Srmacklem /* 1483191783Srmacklem * Get transfer parameters and attributes for root vnode once. 1484191783Srmacklem */ 1485191783Srmacklem mtx_lock(&nmp->nm_mtx); 1486191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 1487191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1488191783Srmacklem ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread); 1489191783Srmacklem } else 1490191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1491191783Srmacklem if (vp->v_type == VNON) 1492191783Srmacklem vp->v_type = VDIR; 1493191783Srmacklem vp->v_vflag |= VV_ROOT; 1494191783Srmacklem *vpp = vp; 1495191783Srmacklem return (0); 1496191783Srmacklem} 1497191783Srmacklem 1498191783Srmacklem/* 1499191783Srmacklem * Flush out the buffer cache 1500191783Srmacklem */ 1501191783Srmacklem/* ARGSUSED */ 1502191783Srmacklemstatic int 1503191990Sattilionfs_sync(struct mount *mp, int waitfor) 1504191783Srmacklem{ 1505191783Srmacklem struct vnode *vp, *mvp; 1506191990Sattilio struct thread *td; 1507191783Srmacklem int error, allerror = 0; 1508191783Srmacklem 1509191990Sattilio td = curthread; 1510191990Sattilio 1511222329Srmacklem MNT_ILOCK(mp); 1512191783Srmacklem /* 1513222329Srmacklem * If a forced dismount is in progress, return from here so that 1514222329Srmacklem * the umount(2) syscall doesn't get stuck in VFS_SYNC() before 1515222329Srmacklem * calling VFS_UNMOUNT(). 1516222329Srmacklem */ 1517222329Srmacklem if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1518222329Srmacklem MNT_IUNLOCK(mp); 1519222329Srmacklem return (EBADF); 1520222329Srmacklem } 1521235626Smckusick MNT_IUNLOCK(mp); 1522222329Srmacklem 1523222329Srmacklem /* 1524191783Srmacklem * Force stale buffer cache information to be flushed. 1525191783Srmacklem */ 1526191783Srmacklemloop: 1527235626Smckusick MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { 1528191783Srmacklem /* XXX Racy bv_cnt check. */ 1529224083Szack if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1530191783Srmacklem waitfor == MNT_LAZY) { 1531191783Srmacklem VI_UNLOCK(vp); 1532191783Srmacklem continue; 1533191783Srmacklem } 1534191783Srmacklem if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 1535235626Smckusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 1536191783Srmacklem goto loop; 1537191783Srmacklem } 1538191783Srmacklem error = VOP_FSYNC(vp, waitfor, td); 1539191783Srmacklem if (error) 1540191783Srmacklem allerror = error; 1541224082Szack NFSVOPUNLOCK(vp, 0); 1542191783Srmacklem vrele(vp); 1543191783Srmacklem } 1544191783Srmacklem return (allerror); 1545191783Srmacklem} 1546191783Srmacklem 1547191783Srmacklemstatic int 1548191783Srmacklemnfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 1549191783Srmacklem{ 1550191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1551191783Srmacklem struct vfsquery vq; 1552191783Srmacklem int error; 1553191783Srmacklem 1554191783Srmacklem bzero(&vq, sizeof(vq)); 1555191783Srmacklem switch (op) { 1556191783Srmacklem#if 0 1557191783Srmacklem case VFS_CTL_NOLOCKS: 1558191783Srmacklem val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; 1559191783Srmacklem if (req->oldptr != NULL) { 1560191783Srmacklem error = SYSCTL_OUT(req, &val, sizeof(val)); 1561191783Srmacklem if (error) 1562191783Srmacklem return (error); 1563191783Srmacklem } 1564191783Srmacklem if (req->newptr != NULL) { 1565191783Srmacklem error = SYSCTL_IN(req, &val, sizeof(val)); 1566191783Srmacklem if (error) 1567191783Srmacklem return (error); 1568191783Srmacklem if (val) 1569191783Srmacklem nmp->nm_flag |= NFSMNT_NOLOCKS; 1570191783Srmacklem else 1571191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOLOCKS; 1572191783Srmacklem } 1573191783Srmacklem break; 1574191783Srmacklem#endif 1575191783Srmacklem case VFS_CTL_QUERY: 1576191783Srmacklem mtx_lock(&nmp->nm_mtx); 1577191783Srmacklem if (nmp->nm_state & NFSSTA_TIMEO) 1578191783Srmacklem vq.vq_flags |= VQ_NOTRESP; 1579191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1580191783Srmacklem#if 0 1581191783Srmacklem if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && 1582191783Srmacklem (nmp->nm_state & NFSSTA_LOCKTIMEO)) 1583191783Srmacklem vq.vq_flags |= VQ_NOTRESPLOCK; 1584191783Srmacklem#endif 1585191783Srmacklem error = SYSCTL_OUT(req, &vq, sizeof(vq)); 1586191783Srmacklem break; 1587191783Srmacklem case VFS_CTL_TIMEO: 1588191783Srmacklem if (req->oldptr != NULL) { 1589191783Srmacklem error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, 1590191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1591191783Srmacklem if (error) 1592191783Srmacklem return (error); 1593191783Srmacklem } 1594191783Srmacklem if (req->newptr != NULL) { 1595191783Srmacklem error = vfs_suser(mp, req->td); 1596191783Srmacklem if (error) 1597191783Srmacklem return (error); 1598191783Srmacklem error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, 1599191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1600191783Srmacklem if (error) 1601191783Srmacklem return (error); 1602191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1603191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1604191783Srmacklem } 1605191783Srmacklem break; 1606191783Srmacklem default: 1607191783Srmacklem return (ENOTSUP); 1608191783Srmacklem } 1609191783Srmacklem return (0); 1610191783Srmacklem} 1611191783Srmacklem 1612214048Srmacklem/* 1613214048Srmacklem * Extract the information needed by the nlm from the nfs vnode. 1614214048Srmacklem */ 1615214048Srmacklemstatic void 1616214053Srmacklemnfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp, 1617216931Srmacklem struct sockaddr_storage *sp, int *is_v3p, off_t *sizep, 1618216931Srmacklem struct timeval *timeop) 1619214048Srmacklem{ 1620214048Srmacklem struct nfsmount *nmp; 1621214048Srmacklem struct nfsnode *np = VTONFS(vp); 1622214048Srmacklem 1623214048Srmacklem nmp = VFSTONFS(vp->v_mount); 1624214048Srmacklem if (fhlenp != NULL) 1625214053Srmacklem *fhlenp = (size_t)np->n_fhp->nfh_len; 1626214048Srmacklem if (fhp != NULL) 1627214048Srmacklem bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len); 1628214048Srmacklem if (sp != NULL) 1629214048Srmacklem bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp))); 1630214048Srmacklem if (is_v3p != NULL) 1631214048Srmacklem *is_v3p = NFS_ISV3(vp); 1632214048Srmacklem if (sizep != NULL) 1633214048Srmacklem *sizep = np->n_size; 1634216931Srmacklem if (timeop != NULL) { 1635216931Srmacklem timeop->tv_sec = nmp->nm_timeo / NFS_HZ; 1636216931Srmacklem timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ); 1637216931Srmacklem } 1638214048Srmacklem} 1639214048Srmacklem 1640244289Srmacklem/* 1641244289Srmacklem * This function prints out an option name, based on the conditional 1642244289Srmacklem * argument. 1643244289Srmacklem */ 1644244289Srmacklemstatic __inline void nfscl_printopt(struct nfsmount *nmp, int testval, 1645244289Srmacklem char *opt, char **buf, size_t *blen) 1646244289Srmacklem{ 1647244289Srmacklem int len; 1648244289Srmacklem 1649244289Srmacklem if (testval != 0 && *blen > strlen(opt)) { 1650244289Srmacklem len = snprintf(*buf, *blen, "%s", opt); 1651244289Srmacklem if (len != strlen(opt)) 1652244289Srmacklem printf("EEK!!\n"); 1653244289Srmacklem *buf += len; 1654244289Srmacklem *blen -= len; 1655244289Srmacklem } 1656244289Srmacklem} 1657244289Srmacklem 1658244289Srmacklem/* 1659244289Srmacklem * This function printf out an options integer value. 1660244289Srmacklem */ 1661244289Srmacklemstatic __inline void nfscl_printoptval(struct nfsmount *nmp, int optval, 1662244289Srmacklem char *opt, char **buf, size_t *blen) 1663244289Srmacklem{ 1664244289Srmacklem int len; 1665244289Srmacklem 1666244289Srmacklem if (*blen > strlen(opt) + 1) { 1667244289Srmacklem /* Could result in truncated output string. */ 1668244289Srmacklem len = snprintf(*buf, *blen, "%s=%d", opt, optval); 1669244289Srmacklem if (len < *blen) { 1670244289Srmacklem *buf += len; 1671244289Srmacklem *blen -= len; 1672244289Srmacklem } 1673244289Srmacklem } 1674244289Srmacklem} 1675244289Srmacklem 1676244289Srmacklem/* 1677244289Srmacklem * Load the option flags and values into the buffer. 1678244289Srmacklem */ 1679244289Srmacklemvoid nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen) 1680244289Srmacklem{ 1681244289Srmacklem char *buf; 1682244289Srmacklem size_t blen; 1683244289Srmacklem 1684244289Srmacklem buf = buffer; 1685244289Srmacklem blen = buflen; 1686244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV4) != 0, "nfsv4", &buf, 1687244289Srmacklem &blen); 1688244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NFSV3) != 0, "nfsv3", &buf, 1689244289Srmacklem &blen); 1690244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0, 1691244289Srmacklem "nfsv2", &buf, &blen); 1692244289Srmacklem nfscl_printopt(nmp, nmp->nm_sotype == SOCK_STREAM, ",tcp", &buf, &blen); 1693244289Srmacklem nfscl_printopt(nmp, nmp->nm_sotype != SOCK_STREAM, ",udp", &buf, &blen); 1694244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RESVPORT) != 0, ",resvport", 1695244289Srmacklem &buf, &blen); 1696244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn", 1697244289Srmacklem &buf, &blen); 1698244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) == 0, ",hard", &buf, 1699244289Srmacklem &blen); 1700244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_SOFT) != 0, ",soft", &buf, 1701244289Srmacklem &blen); 1702244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_INT) != 0, ",intr", &buf, 1703244289Srmacklem &blen); 1704244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) == 0, ",cto", &buf, 1705244289Srmacklem &blen); 1706244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCTO) != 0, ",nocto", &buf, 1707244289Srmacklem &blen); 1708260170Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NONCONTIGWR) != 0, 1709260170Srmacklem ",noncontigwr", &buf, &blen); 1710244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) == 1711244289Srmacklem 0, ",lockd", &buf, &blen); 1712244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_NOLOCKD | NFSMNT_NFSV4)) == 1713244289Srmacklem NFSMNT_NOLOCKD, ",nolockd", &buf, &blen); 1714244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_RDIRPLUS) != 0, ",rdirplus", 1715244289Srmacklem &buf, &blen); 1716244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_KERB) == 0, ",sec=sys", 1717244289Srmacklem &buf, &blen); 1718244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY | 1719244289Srmacklem NFSMNT_PRIVACY)) == NFSMNT_KERB, ",sec=krb5", &buf, &blen); 1720244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY | 1721244289Srmacklem NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_INTEGRITY), ",sec=krb5i", 1722244289Srmacklem &buf, &blen); 1723244289Srmacklem nfscl_printopt(nmp, (nmp->nm_flag & (NFSMNT_KERB | NFSMNT_INTEGRITY | 1724244289Srmacklem NFSMNT_PRIVACY)) == (NFSMNT_KERB | NFSMNT_PRIVACY), ",sec=krb5p", 1725244289Srmacklem &buf, &blen); 1726244289Srmacklem nfscl_printoptval(nmp, nmp->nm_acdirmin, ",acdirmin", &buf, &blen); 1727244289Srmacklem nfscl_printoptval(nmp, nmp->nm_acdirmax, ",acdirmax", &buf, &blen); 1728244289Srmacklem nfscl_printoptval(nmp, nmp->nm_acregmin, ",acregmin", &buf, &blen); 1729244289Srmacklem nfscl_printoptval(nmp, nmp->nm_acregmax, ",acregmax", &buf, &blen); 1730244289Srmacklem nfscl_printoptval(nmp, nmp->nm_nametimeo, ",nametimeo", &buf, &blen); 1731244289Srmacklem nfscl_printoptval(nmp, nmp->nm_negnametimeo, ",negnametimeo", &buf, 1732244289Srmacklem &blen); 1733244289Srmacklem nfscl_printoptval(nmp, nmp->nm_rsize, ",rsize", &buf, &blen); 1734244289Srmacklem nfscl_printoptval(nmp, nmp->nm_wsize, ",wsize", &buf, &blen); 1735244289Srmacklem nfscl_printoptval(nmp, nmp->nm_readdirsize, ",readdirsize", &buf, 1736244289Srmacklem &blen); 1737244289Srmacklem nfscl_printoptval(nmp, nmp->nm_readahead, ",readahead", &buf, &blen); 1738244289Srmacklem nfscl_printoptval(nmp, nmp->nm_wcommitsize, ",wcommitsize", &buf, 1739244289Srmacklem &blen); 1740244289Srmacklem nfscl_printoptval(nmp, nmp->nm_timeo, ",timeout", &buf, &blen); 1741244289Srmacklem nfscl_printoptval(nmp, nmp->nm_retry, ",retrans", &buf, &blen); 1742244289Srmacklem} 1743244289Srmacklem 1744