nfs_clvfsops.c revision 233326
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: stable/9/sys/fs/nfsclient/nfs_clvfsops.c 233326 2012-03-22 21:07:54Z jhb $"); 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; 83191783Srmacklem 84191783SrmacklemMALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header"); 85191783SrmacklemMALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct"); 86191783Srmacklem 87221973SrmacklemSYSCTL_DECL(_vfs_nfs); 88191783Srmacklemstatic int nfs_ip_paranoia = 1; 89221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW, 90191783Srmacklem &nfs_ip_paranoia, 0, ""); 91191783Srmacklemstatic int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY; 92221973SrmacklemSYSCTL_INT(_vfs_nfs, NFS_TPRINTF_INITIAL_DELAY, 93191783Srmacklem downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, ""); 94191783Srmacklem/* how long between console messages "nfs server foo not responding" */ 95191783Srmacklemstatic int nfs_tprintf_delay = NFS_TPRINTF_DELAY; 96221973SrmacklemSYSCTL_INT(_vfs_nfs, NFS_TPRINTF_DELAY, 97191783Srmacklem downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, ""); 98191783Srmacklem 99221040Srmacklemstatic int nfs_mountroot(struct mount *); 100192585Srmacklemstatic void nfs_sec_name(char *, int *); 101191783Srmacklemstatic void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, 102214048Srmacklem struct nfs_args *argp, const char *, struct ucred *, 103214048Srmacklem struct thread *); 104191783Srmacklemstatic int mountnfs(struct nfs_args *, struct mount *, 105221014Srmacklem struct sockaddr *, char *, u_char *, int, u_char *, int, 106221014Srmacklem u_char *, int, struct vnode **, struct ucred *, 107233326Sjhb struct thread *, int, int); 108214053Srmacklemstatic void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *, 109216931Srmacklem struct sockaddr_storage *, int *, off_t *, 110216931Srmacklem struct timeval *); 111191783Srmacklemstatic vfs_mount_t nfs_mount; 112191783Srmacklemstatic vfs_cmount_t nfs_cmount; 113191783Srmacklemstatic vfs_unmount_t nfs_unmount; 114191783Srmacklemstatic vfs_root_t nfs_root; 115191783Srmacklemstatic vfs_statfs_t nfs_statfs; 116191783Srmacklemstatic vfs_sync_t nfs_sync; 117191783Srmacklemstatic vfs_sysctl_t nfs_sysctl; 118191783Srmacklem 119191783Srmacklem/* 120191783Srmacklem * nfs vfs operations. 121191783Srmacklem */ 122191783Srmacklemstatic struct vfsops nfs_vfsops = { 123191783Srmacklem .vfs_init = ncl_init, 124191783Srmacklem .vfs_mount = nfs_mount, 125191783Srmacklem .vfs_cmount = nfs_cmount, 126191783Srmacklem .vfs_root = nfs_root, 127191783Srmacklem .vfs_statfs = nfs_statfs, 128191783Srmacklem .vfs_sync = nfs_sync, 129191783Srmacklem .vfs_uninit = ncl_uninit, 130191783Srmacklem .vfs_unmount = nfs_unmount, 131191783Srmacklem .vfs_sysctl = nfs_sysctl, 132191783Srmacklem}; 133221124SrmacklemVFS_SET(nfs_vfsops, nfs, VFCF_NETWORK); 134191783Srmacklem 135191783Srmacklem/* So that loader and kldload(2) can find us, wherever we are.. */ 136221139SrmacklemMODULE_VERSION(nfs, 1); 137221139SrmacklemMODULE_DEPEND(nfs, nfscommon, 1, 1, 1); 138221139SrmacklemMODULE_DEPEND(nfs, krpc, 1, 1, 1); 139221139SrmacklemMODULE_DEPEND(nfs, nfssvc, 1, 1, 1); 140221139SrmacklemMODULE_DEPEND(nfs, nfslock, 1, 1, 1); 141191783Srmacklem 142191783Srmacklem/* 143221066Srmacklem * This structure is now defined in sys/nfs/nfs_diskless.c so that it 144221066Srmacklem * can be shared by both NFS clients. It is declared here so that it 145221066Srmacklem * will be defined for kernels built without NFS_ROOT, although it 146221066Srmacklem * isn't used in that case. 147191783Srmacklem */ 148221066Srmacklem#if !defined(NFS_ROOT) && !defined(NFSCLIENT) 149221066Srmacklemstruct nfs_diskless nfs_diskless = { { { 0 } } }; 150221066Srmacklemstruct nfsv3_diskless nfsv3_diskless = { { { 0 } } }; 151221066Srmacklemint nfs_diskless_valid = 0; 152221066Srmacklem#endif 153221066Srmacklem 154221973SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD, 155221040Srmacklem &nfs_diskless_valid, 0, 156192145Srmacklem "Has the diskless struct been filled correctly"); 157191783Srmacklem 158221973SrmacklemSYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD, 159221040Srmacklem nfsv3_diskless.root_hostnam, 0, "Path to nfs root"); 160191783Srmacklem 161221973SrmacklemSYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD, 162221040Srmacklem &nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr), 163192145Srmacklem "%Ssockaddr_in", "Diskless root nfs address"); 164191783Srmacklem 165191783Srmacklem 166191783Srmacklemvoid newnfsargs_ntoh(struct nfs_args *); 167191783Srmacklemstatic int nfs_mountdiskless(char *, 168191783Srmacklem struct sockaddr_in *, struct nfs_args *, 169191783Srmacklem struct thread *, struct vnode **, struct mount *); 170191783Srmacklemstatic void nfs_convert_diskless(void); 171191783Srmacklemstatic void nfs_convert_oargs(struct nfs_args *args, 172191783Srmacklem struct onfs_args *oargs); 173191783Srmacklem 174191783Srmacklemint 175191783Srmacklemnewnfs_iosize(struct nfsmount *nmp) 176191783Srmacklem{ 177191783Srmacklem int iosize, maxio; 178191783Srmacklem 179191783Srmacklem /* First, set the upper limit for iosize */ 180191783Srmacklem if (nmp->nm_flag & NFSMNT_NFSV4) { 181191783Srmacklem maxio = NFS_MAXBSIZE; 182191783Srmacklem } else if (nmp->nm_flag & NFSMNT_NFSV3) { 183191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 184191783Srmacklem maxio = NFS_MAXDGRAMDATA; 185191783Srmacklem else 186191783Srmacklem maxio = NFS_MAXBSIZE; 187191783Srmacklem } else { 188191783Srmacklem maxio = NFS_V2MAXDATA; 189191783Srmacklem } 190191783Srmacklem if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0) 191191783Srmacklem nmp->nm_rsize = maxio; 192191783Srmacklem if (nmp->nm_rsize > MAXBSIZE) 193191783Srmacklem nmp->nm_rsize = MAXBSIZE; 194191783Srmacklem if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0) 195191783Srmacklem nmp->nm_readdirsize = maxio; 196191783Srmacklem if (nmp->nm_readdirsize > nmp->nm_rsize) 197191783Srmacklem nmp->nm_readdirsize = nmp->nm_rsize; 198191783Srmacklem if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0) 199191783Srmacklem nmp->nm_wsize = maxio; 200191783Srmacklem if (nmp->nm_wsize > MAXBSIZE) 201191783Srmacklem nmp->nm_wsize = MAXBSIZE; 202191783Srmacklem 203191783Srmacklem /* 204191783Srmacklem * Calculate the size used for io buffers. Use the larger 205191783Srmacklem * of the two sizes to minimise nfs requests but make sure 206191783Srmacklem * that it is at least one VM page to avoid wasting buffer 207191783Srmacklem * space. 208191783Srmacklem */ 209191783Srmacklem iosize = imax(nmp->nm_rsize, nmp->nm_wsize); 210191783Srmacklem iosize = imax(iosize, PAGE_SIZE); 211191783Srmacklem nmp->nm_mountp->mnt_stat.f_iosize = iosize; 212191783Srmacklem return (iosize); 213191783Srmacklem} 214191783Srmacklem 215191783Srmacklemstatic void 216191783Srmacklemnfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs) 217191783Srmacklem{ 218191783Srmacklem 219191783Srmacklem args->version = NFS_ARGSVERSION; 220191783Srmacklem args->addr = oargs->addr; 221191783Srmacklem args->addrlen = oargs->addrlen; 222191783Srmacklem args->sotype = oargs->sotype; 223191783Srmacklem args->proto = oargs->proto; 224191783Srmacklem args->fh = oargs->fh; 225191783Srmacklem args->fhsize = oargs->fhsize; 226191783Srmacklem args->flags = oargs->flags; 227191783Srmacklem args->wsize = oargs->wsize; 228191783Srmacklem args->rsize = oargs->rsize; 229191783Srmacklem args->readdirsize = oargs->readdirsize; 230191783Srmacklem args->timeo = oargs->timeo; 231191783Srmacklem args->retrans = oargs->retrans; 232191783Srmacklem args->readahead = oargs->readahead; 233191783Srmacklem args->hostname = oargs->hostname; 234191783Srmacklem} 235191783Srmacklem 236191783Srmacklemstatic void 237191783Srmacklemnfs_convert_diskless(void) 238191783Srmacklem{ 239191783Srmacklem 240221040Srmacklem bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif, 241221040Srmacklem sizeof(struct ifaliasreq)); 242221040Srmacklem bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway, 243221040Srmacklem sizeof(struct sockaddr_in)); 244221040Srmacklem nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args); 245221040Srmacklem if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) { 246221040Srmacklem nfsv3_diskless.root_fhsize = NFSX_MYFH; 247221040Srmacklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH); 248191783Srmacklem } else { 249221040Srmacklem nfsv3_diskless.root_fhsize = NFSX_V2FH; 250221040Srmacklem bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH); 251191783Srmacklem } 252221040Srmacklem bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr, 253221040Srmacklem sizeof(struct sockaddr_in)); 254221040Srmacklem bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN); 255221040Srmacklem nfsv3_diskless.root_time = nfs_diskless.root_time; 256221040Srmacklem bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam, 257221040Srmacklem MAXHOSTNAMELEN); 258221040Srmacklem nfs_diskless_valid = 3; 259191783Srmacklem} 260191783Srmacklem 261191783Srmacklem/* 262191783Srmacklem * nfs statfs call 263191783Srmacklem */ 264191783Srmacklemstatic int 265191990Sattilionfs_statfs(struct mount *mp, struct statfs *sbp) 266191783Srmacklem{ 267191783Srmacklem struct vnode *vp; 268191990Sattilio struct thread *td; 269191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 270191783Srmacklem struct nfsvattr nfsva; 271191783Srmacklem struct nfsfsinfo fs; 272191783Srmacklem struct nfsstatfs sb; 273191783Srmacklem int error = 0, attrflag, gotfsinfo = 0, ret; 274191783Srmacklem struct nfsnode *np; 275191783Srmacklem 276191990Sattilio td = curthread; 277191990Sattilio 278191783Srmacklem error = vfs_busy(mp, MBF_NOWAIT); 279191783Srmacklem if (error) 280191783Srmacklem return (error); 281220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE); 282191783Srmacklem if (error) { 283191783Srmacklem vfs_unbusy(mp); 284191783Srmacklem return (error); 285191783Srmacklem } 286191783Srmacklem vp = NFSTOV(np); 287191783Srmacklem mtx_lock(&nmp->nm_mtx); 288191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 289191783Srmacklem mtx_unlock(&nmp->nm_mtx); 290191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva, 291191783Srmacklem &attrflag, NULL); 292191783Srmacklem if (!error) 293191783Srmacklem gotfsinfo = 1; 294191783Srmacklem } else 295191783Srmacklem mtx_unlock(&nmp->nm_mtx); 296191783Srmacklem if (!error) 297191783Srmacklem error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, 298191783Srmacklem &attrflag, NULL); 299191783Srmacklem if (attrflag == 0) { 300191783Srmacklem ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 301191783Srmacklem td->td_ucred, td, &nfsva, NULL); 302191783Srmacklem if (ret) { 303191783Srmacklem /* 304191783Srmacklem * Just set default values to get things going. 305191783Srmacklem */ 306191783Srmacklem NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 307191783Srmacklem nfsva.na_vattr.va_type = VDIR; 308191783Srmacklem nfsva.na_vattr.va_mode = 0777; 309191783Srmacklem nfsva.na_vattr.va_nlink = 100; 310191783Srmacklem nfsva.na_vattr.va_uid = (uid_t)0; 311191783Srmacklem nfsva.na_vattr.va_gid = (gid_t)0; 312191783Srmacklem nfsva.na_vattr.va_fileid = 2; 313191783Srmacklem nfsva.na_vattr.va_gen = 1; 314191783Srmacklem nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 315191783Srmacklem nfsva.na_vattr.va_size = 512 * 1024; 316191783Srmacklem } 317191783Srmacklem } 318191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 319191783Srmacklem if (!error) { 320191783Srmacklem mtx_lock(&nmp->nm_mtx); 321191783Srmacklem if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4)) 322191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 323191783Srmacklem nfscl_loadsbinfo(nmp, &sb, sbp); 324191783Srmacklem sbp->f_iosize = newnfs_iosize(nmp); 325191783Srmacklem mtx_unlock(&nmp->nm_mtx); 326191783Srmacklem if (sbp != &mp->mnt_stat) { 327191783Srmacklem bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 328191783Srmacklem bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 329191783Srmacklem } 330191783Srmacklem strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 331191783Srmacklem } else if (NFS_ISV4(vp)) { 332191783Srmacklem error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 333191783Srmacklem } 334191783Srmacklem vput(vp); 335191783Srmacklem vfs_unbusy(mp); 336191783Srmacklem return (error); 337191783Srmacklem} 338191783Srmacklem 339191783Srmacklem/* 340191783Srmacklem * nfs version 3 fsinfo rpc call 341191783Srmacklem */ 342191783Srmacklemint 343191783Srmacklemncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, 344191783Srmacklem struct thread *td) 345191783Srmacklem{ 346191783Srmacklem struct nfsfsinfo fs; 347191783Srmacklem struct nfsvattr nfsva; 348191783Srmacklem int error, attrflag; 349191783Srmacklem 350191783Srmacklem error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL); 351191783Srmacklem if (!error) { 352191783Srmacklem if (attrflag) 353191783Srmacklem (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 354191783Srmacklem 1); 355191783Srmacklem mtx_lock(&nmp->nm_mtx); 356191783Srmacklem nfscl_loadfsinfo(nmp, &fs); 357191783Srmacklem mtx_unlock(&nmp->nm_mtx); 358191783Srmacklem } 359191783Srmacklem return (error); 360191783Srmacklem} 361191783Srmacklem 362191783Srmacklem/* 363191783Srmacklem * Mount a remote root fs via. nfs. This depends on the info in the 364221040Srmacklem * nfs_diskless structure that has been filled in properly by some primary 365191783Srmacklem * bootstrap. 366191783Srmacklem * It goes something like this: 367191783Srmacklem * - do enough of "ifconfig" by calling ifioctl() so that the system 368191783Srmacklem * can talk to the server 369221040Srmacklem * - If nfs_diskless.mygateway is filled in, use that address as 370191783Srmacklem * a default gateway. 371191783Srmacklem * - build the rootfs mount point and call mountnfs() to do the rest. 372191783Srmacklem * 373191783Srmacklem * It is assumed to be safe to read, modify, and write the nfsv3_diskless 374191783Srmacklem * structure, as well as other global NFS client variables here, as 375192145Srmacklem * nfs_mountroot() will be called once in the boot before any other NFS 376191783Srmacklem * client activity occurs. 377191783Srmacklem */ 378221040Srmacklemstatic int 379221040Srmacklemnfs_mountroot(struct mount *mp) 380191783Srmacklem{ 381192145Srmacklem struct thread *td = curthread; 382221040Srmacklem struct nfsv3_diskless *nd = &nfsv3_diskless; 383191783Srmacklem struct socket *so; 384191783Srmacklem struct vnode *vp; 385191783Srmacklem struct ifreq ir; 386193066Sjamie int error; 387191783Srmacklem u_long l; 388191783Srmacklem char buf[128]; 389191783Srmacklem char *cp; 390191783Srmacklem 391191783Srmacklem#if defined(BOOTP_NFSROOT) && defined(BOOTP) 392192145Srmacklem bootpc_init(); /* use bootp to get nfs_diskless filled in */ 393191783Srmacklem#elif defined(NFS_ROOT) 394191783Srmacklem nfs_setup_diskless(); 395191783Srmacklem#endif 396191783Srmacklem 397221040Srmacklem if (nfs_diskless_valid == 0) 398191783Srmacklem return (-1); 399221040Srmacklem if (nfs_diskless_valid == 1) 400191783Srmacklem nfs_convert_diskless(); 401191783Srmacklem 402191783Srmacklem /* 403191783Srmacklem * XXX splnet, so networks will receive... 404191783Srmacklem */ 405191783Srmacklem splnet(); 406191783Srmacklem 407191783Srmacklem /* 408191783Srmacklem * Do enough of ifconfig(8) so that the critical net interface can 409191783Srmacklem * talk to the server. 410191783Srmacklem */ 411191783Srmacklem error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0, 412191783Srmacklem td->td_ucred, td); 413191783Srmacklem if (error) 414192145Srmacklem panic("nfs_mountroot: socreate(%04x): %d", 415191783Srmacklem nd->myif.ifra_addr.sa_family, error); 416191783Srmacklem 417191783Srmacklem#if 0 /* XXX Bad idea */ 418191783Srmacklem /* 419191783Srmacklem * We might not have been told the right interface, so we pass 420191783Srmacklem * over the first ten interfaces of the same kind, until we get 421191783Srmacklem * one of them configured. 422191783Srmacklem */ 423191783Srmacklem 424191783Srmacklem for (i = strlen(nd->myif.ifra_name) - 1; 425191783Srmacklem nd->myif.ifra_name[i] >= '0' && 426191783Srmacklem nd->myif.ifra_name[i] <= '9'; 427191783Srmacklem nd->myif.ifra_name[i] ++) { 428191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 429191783Srmacklem if(!error) 430191783Srmacklem break; 431191783Srmacklem } 432191783Srmacklem#endif 433191783Srmacklem error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 434191783Srmacklem if (error) 435192145Srmacklem panic("nfs_mountroot: SIOCAIFADDR: %d", error); 436191783Srmacklem if ((cp = getenv("boot.netif.mtu")) != NULL) { 437191783Srmacklem ir.ifr_mtu = strtol(cp, NULL, 10); 438191783Srmacklem bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); 439191783Srmacklem freeenv(cp); 440191783Srmacklem error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); 441191783Srmacklem if (error) 442192145Srmacklem printf("nfs_mountroot: SIOCSIFMTU: %d", error); 443191783Srmacklem } 444191783Srmacklem soclose(so); 445191783Srmacklem 446191783Srmacklem /* 447191783Srmacklem * If the gateway field is filled in, set it as the default route. 448191783Srmacklem * Note that pxeboot will set a default route of 0 if the route 449191783Srmacklem * is not set by the DHCP server. Check also for a value of 0 450191783Srmacklem * to avoid panicking inappropriately in that situation. 451191783Srmacklem */ 452191783Srmacklem if (nd->mygateway.sin_len != 0 && 453191783Srmacklem nd->mygateway.sin_addr.s_addr != 0) { 454191783Srmacklem struct sockaddr_in mask, sin; 455191783Srmacklem 456191783Srmacklem bzero((caddr_t)&mask, sizeof(mask)); 457191783Srmacklem sin = mask; 458191783Srmacklem sin.sin_family = AF_INET; 459191783Srmacklem sin.sin_len = sizeof(sin); 460192145Srmacklem /* XXX MRT use table 0 for this sort of thing */ 461218757Sbz CURVNET_SET(TD_TO_VNET(td)); 462232292Sbz error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin, 463191783Srmacklem (struct sockaddr *)&nd->mygateway, 464191783Srmacklem (struct sockaddr *)&mask, 465232292Sbz RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB); 466218757Sbz CURVNET_RESTORE(); 467191783Srmacklem if (error) 468192145Srmacklem panic("nfs_mountroot: RTM_ADD: %d", error); 469191783Srmacklem } 470191783Srmacklem 471191783Srmacklem /* 472191783Srmacklem * Create the rootfs mount point. 473191783Srmacklem */ 474191783Srmacklem nd->root_args.fh = nd->root_fh; 475191783Srmacklem nd->root_args.fhsize = nd->root_fhsize; 476191783Srmacklem l = ntohl(nd->root_saddr.sin_addr.s_addr); 477191783Srmacklem snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", 478191783Srmacklem (l >> 24) & 0xff, (l >> 16) & 0xff, 479191783Srmacklem (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); 480191783Srmacklem printf("NFS ROOT: %s\n", buf); 481192145Srmacklem nd->root_args.hostname = buf; 482191783Srmacklem if ((error = nfs_mountdiskless(buf, 483191783Srmacklem &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { 484191783Srmacklem return (error); 485191783Srmacklem } 486191783Srmacklem 487191783Srmacklem /* 488191783Srmacklem * This is not really an nfs issue, but it is much easier to 489191783Srmacklem * set hostname here and then let the "/etc/rc.xxx" files 490191783Srmacklem * mount the right /var based upon its preset value. 491191783Srmacklem */ 492193066Sjamie mtx_lock(&prison0.pr_mtx); 493194118Sjamie strlcpy(prison0.pr_hostname, nd->my_hostnam, 494194118Sjamie sizeof(prison0.pr_hostname)); 495193066Sjamie mtx_unlock(&prison0.pr_mtx); 496191783Srmacklem inittodr(ntohl(nd->root_time)); 497191783Srmacklem return (0); 498191783Srmacklem} 499191783Srmacklem 500191783Srmacklem/* 501191783Srmacklem * Internal version of mount system call for diskless setup. 502191783Srmacklem */ 503191783Srmacklemstatic int 504191783Srmacklemnfs_mountdiskless(char *path, 505191783Srmacklem struct sockaddr_in *sin, struct nfs_args *args, struct thread *td, 506191783Srmacklem struct vnode **vpp, struct mount *mp) 507191783Srmacklem{ 508191783Srmacklem struct sockaddr *nam; 509221014Srmacklem int dirlen, error; 510221014Srmacklem char *dirpath; 511191783Srmacklem 512221014Srmacklem /* 513221014Srmacklem * Find the directory path in "path", which also has the server's 514221014Srmacklem * name/ip address in it. 515221014Srmacklem */ 516221014Srmacklem dirpath = strchr(path, ':'); 517221014Srmacklem if (dirpath != NULL) 518221014Srmacklem dirlen = strlen(++dirpath); 519221014Srmacklem else 520221014Srmacklem dirlen = 0; 521191783Srmacklem nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); 522221014Srmacklem if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen, 523233326Sjhb NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO, 524233326Sjhb NFS_DEFAULT_NEGNAMETIMEO)) != 0) { 525192145Srmacklem printf("nfs_mountroot: mount %s on /: %d\n", path, error); 526191783Srmacklem return (error); 527191783Srmacklem } 528191783Srmacklem return (0); 529191783Srmacklem} 530191783Srmacklem 531191783Srmacklemstatic void 532192585Srmacklemnfs_sec_name(char *sec, int *flagsp) 533192585Srmacklem{ 534192585Srmacklem if (!strcmp(sec, "krb5")) 535192585Srmacklem *flagsp |= NFSMNT_KERB; 536192585Srmacklem else if (!strcmp(sec, "krb5i")) 537192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY); 538192585Srmacklem else if (!strcmp(sec, "krb5p")) 539192585Srmacklem *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY); 540192585Srmacklem} 541192585Srmacklem 542192585Srmacklemstatic void 543191783Srmacklemnfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, 544214048Srmacklem const char *hostname, struct ucred *cred, struct thread *td) 545191783Srmacklem{ 546191783Srmacklem int s; 547191783Srmacklem int adjsock; 548214048Srmacklem char *p; 549191783Srmacklem 550191783Srmacklem s = splnet(); 551191783Srmacklem 552191783Srmacklem /* 553191783Srmacklem * Set read-only flag if requested; otherwise, clear it if this is 554191783Srmacklem * an update. If this is not an update, then either the read-only 555191783Srmacklem * flag is already clear, or this is a root mount and it was set 556191783Srmacklem * intentionally at some previous point. 557191783Srmacklem */ 558191783Srmacklem if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) { 559191783Srmacklem MNT_ILOCK(mp); 560191783Srmacklem mp->mnt_flag |= MNT_RDONLY; 561191783Srmacklem MNT_IUNLOCK(mp); 562191783Srmacklem } else if (mp->mnt_flag & MNT_UPDATE) { 563191783Srmacklem MNT_ILOCK(mp); 564191783Srmacklem mp->mnt_flag &= ~MNT_RDONLY; 565191783Srmacklem MNT_IUNLOCK(mp); 566191783Srmacklem } 567191783Srmacklem 568191783Srmacklem /* 569191783Srmacklem * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 570191783Srmacklem * no sense in that context. Also, set up appropriate retransmit 571191783Srmacklem * and soft timeout behavior. 572191783Srmacklem */ 573191783Srmacklem if (argp->sotype == SOCK_STREAM) { 574191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOCONN; 575191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 576220739Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0) 577220739Srmacklem nmp->nm_retry = INT_MAX; 578220739Srmacklem else 579220739Srmacklem nmp->nm_retry = NFS_RETRANS_TCP; 580191783Srmacklem } 581191783Srmacklem 582220739Srmacklem /* Also clear RDIRPLUS if NFSv2, it crashes some servers */ 583220739Srmacklem if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 584220739Srmacklem argp->flags &= ~NFSMNT_RDIRPLUS; 585191783Srmacklem nmp->nm_flag &= ~NFSMNT_RDIRPLUS; 586220739Srmacklem } 587191783Srmacklem 588220739Srmacklem /* Clear NFSMNT_RESVPORT for NFSv4, since it is not required. */ 589220739Srmacklem if ((argp->flags & NFSMNT_NFSV4) != 0) { 590220739Srmacklem argp->flags &= ~NFSMNT_RESVPORT; 591220739Srmacklem nmp->nm_flag &= ~NFSMNT_RESVPORT; 592220739Srmacklem } 593220739Srmacklem 594220739Srmacklem /* Re-bind if rsrvd port requested and wasn't on one */ 595220739Srmacklem adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT) 596220739Srmacklem && (argp->flags & NFSMNT_RESVPORT); 597191783Srmacklem /* Also re-bind if we're switching to/from a connected UDP socket */ 598220739Srmacklem adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) != 599191783Srmacklem (argp->flags & NFSMNT_NOCONN)); 600191783Srmacklem 601191783Srmacklem /* Update flags atomically. Don't change the lock bits. */ 602191783Srmacklem nmp->nm_flag = argp->flags | nmp->nm_flag; 603191783Srmacklem splx(s); 604191783Srmacklem 605191783Srmacklem if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 606191783Srmacklem nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 607191783Srmacklem if (nmp->nm_timeo < NFS_MINTIMEO) 608191783Srmacklem nmp->nm_timeo = NFS_MINTIMEO; 609191783Srmacklem else if (nmp->nm_timeo > NFS_MAXTIMEO) 610191783Srmacklem nmp->nm_timeo = NFS_MAXTIMEO; 611191783Srmacklem } 612191783Srmacklem 613191783Srmacklem if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 614191783Srmacklem nmp->nm_retry = argp->retrans; 615191783Srmacklem if (nmp->nm_retry > NFS_MAXREXMIT) 616191783Srmacklem nmp->nm_retry = NFS_MAXREXMIT; 617191783Srmacklem } 618191783Srmacklem 619191783Srmacklem if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 620191783Srmacklem nmp->nm_wsize = argp->wsize; 621191783Srmacklem /* Round down to multiple of blocksize */ 622191783Srmacklem nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); 623191783Srmacklem if (nmp->nm_wsize <= 0) 624191783Srmacklem nmp->nm_wsize = NFS_FABLKSIZE; 625191783Srmacklem } 626191783Srmacklem 627191783Srmacklem if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 628191783Srmacklem nmp->nm_rsize = argp->rsize; 629191783Srmacklem /* Round down to multiple of blocksize */ 630191783Srmacklem nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); 631191783Srmacklem if (nmp->nm_rsize <= 0) 632191783Srmacklem nmp->nm_rsize = NFS_FABLKSIZE; 633191783Srmacklem } 634191783Srmacklem 635191783Srmacklem if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 636191783Srmacklem nmp->nm_readdirsize = argp->readdirsize; 637191783Srmacklem } 638191783Srmacklem 639191783Srmacklem if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) 640191783Srmacklem nmp->nm_acregmin = argp->acregmin; 641191783Srmacklem else 642191783Srmacklem nmp->nm_acregmin = NFS_MINATTRTIMO; 643191783Srmacklem if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) 644191783Srmacklem nmp->nm_acregmax = argp->acregmax; 645191783Srmacklem else 646191783Srmacklem nmp->nm_acregmax = NFS_MAXATTRTIMO; 647191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) 648191783Srmacklem nmp->nm_acdirmin = argp->acdirmin; 649191783Srmacklem else 650191783Srmacklem nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; 651191783Srmacklem if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) 652191783Srmacklem nmp->nm_acdirmax = argp->acdirmax; 653191783Srmacklem else 654191783Srmacklem nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; 655191783Srmacklem if (nmp->nm_acdirmin > nmp->nm_acdirmax) 656191783Srmacklem nmp->nm_acdirmin = nmp->nm_acdirmax; 657191783Srmacklem if (nmp->nm_acregmin > nmp->nm_acregmax) 658191783Srmacklem nmp->nm_acregmin = nmp->nm_acregmax; 659191783Srmacklem 660191783Srmacklem if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { 661191783Srmacklem if (argp->readahead <= NFS_MAXRAHEAD) 662191783Srmacklem nmp->nm_readahead = argp->readahead; 663191783Srmacklem else 664191783Srmacklem nmp->nm_readahead = NFS_MAXRAHEAD; 665191783Srmacklem } 666191783Srmacklem if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) { 667191783Srmacklem if (argp->wcommitsize < nmp->nm_wsize) 668191783Srmacklem nmp->nm_wcommitsize = nmp->nm_wsize; 669191783Srmacklem else 670191783Srmacklem nmp->nm_wcommitsize = argp->wcommitsize; 671191783Srmacklem } 672191783Srmacklem 673191783Srmacklem adjsock |= ((nmp->nm_sotype != argp->sotype) || 674191783Srmacklem (nmp->nm_soproto != argp->proto)); 675191783Srmacklem 676191783Srmacklem if (nmp->nm_client != NULL && adjsock) { 677191783Srmacklem int haslock = 0, error = 0; 678191783Srmacklem 679191783Srmacklem if (nmp->nm_sotype == SOCK_STREAM) { 680191783Srmacklem error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock); 681191783Srmacklem if (!error) 682191783Srmacklem haslock = 1; 683191783Srmacklem } 684191783Srmacklem if (!error) { 685191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 686191783Srmacklem if (haslock) 687191783Srmacklem newnfs_sndunlock(&nmp->nm_sockreq.nr_lock); 688191783Srmacklem nmp->nm_sotype = argp->sotype; 689191783Srmacklem nmp->nm_soproto = argp->proto; 690191783Srmacklem if (nmp->nm_sotype == SOCK_DGRAM) 691191783Srmacklem while (newnfs_connect(nmp, &nmp->nm_sockreq, 692191783Srmacklem cred, td, 0)) { 693191783Srmacklem printf("newnfs_args: retrying connect\n"); 694207170Srmacklem (void) nfs_catnap(PSOCK, 0, "newnfscon"); 695191783Srmacklem } 696191783Srmacklem } 697191783Srmacklem } else { 698191783Srmacklem nmp->nm_sotype = argp->sotype; 699191783Srmacklem nmp->nm_soproto = argp->proto; 700191783Srmacklem } 701214048Srmacklem 702214048Srmacklem if (hostname != NULL) { 703214048Srmacklem strlcpy(nmp->nm_hostname, hostname, 704214048Srmacklem sizeof(nmp->nm_hostname)); 705214048Srmacklem p = strchr(nmp->nm_hostname, ':'); 706214048Srmacklem if (p != NULL) 707214048Srmacklem *p = '\0'; 708214048Srmacklem } 709191783Srmacklem} 710191783Srmacklem 711221190Srmacklemstatic const char *nfs_opts[] = { "from", "nfs_args", 712191783Srmacklem "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union", 713191783Srmacklem "noclusterr", "noclusterw", "multilabel", "acls", "force", "update", 714192585Srmacklem "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus", 715192585Srmacklem "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize", 716192585Srmacklem "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport", 717192585Srmacklem "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec", 718192585Srmacklem "principal", "nfsv4", "gssname", "allgssname", "dirpath", 719233326Sjhb "nametimeo", "negnametimeo", "nocto", "wcommitsize", 720191783Srmacklem NULL }; 721191783Srmacklem 722191783Srmacklem/* 723191783Srmacklem * VFS Operations. 724191783Srmacklem * 725191783Srmacklem * mount system call 726191783Srmacklem * It seems a bit dumb to copyinstr() the host and path here and then 727191783Srmacklem * bcopy() them in mountnfs(), but I wanted to detect errors before 728191783Srmacklem * doing the sockargs() call because sockargs() allocates an mbuf and 729191783Srmacklem * an error after that means that I have to release the mbuf. 730191783Srmacklem */ 731191783Srmacklem/* ARGSUSED */ 732191783Srmacklemstatic int 733191990Sattilionfs_mount(struct mount *mp) 734191783Srmacklem{ 735191783Srmacklem struct nfs_args args = { 736191783Srmacklem .version = NFS_ARGSVERSION, 737191783Srmacklem .addr = NULL, 738191783Srmacklem .addrlen = sizeof (struct sockaddr_in), 739191783Srmacklem .sotype = SOCK_STREAM, 740191783Srmacklem .proto = 0, 741191783Srmacklem .fh = NULL, 742191783Srmacklem .fhsize = 0, 743220739Srmacklem .flags = NFSMNT_RESVPORT, 744191783Srmacklem .wsize = NFS_WSIZE, 745191783Srmacklem .rsize = NFS_RSIZE, 746191783Srmacklem .readdirsize = NFS_READDIRSIZE, 747191783Srmacklem .timeo = 10, 748191783Srmacklem .retrans = NFS_RETRANS, 749191783Srmacklem .readahead = NFS_DEFRAHEAD, 750191783Srmacklem .wcommitsize = 0, /* was: NQ_DEFLEASE */ 751191783Srmacklem .hostname = NULL, 752191783Srmacklem .acregmin = NFS_MINATTRTIMO, 753191783Srmacklem .acregmax = NFS_MAXATTRTIMO, 754191783Srmacklem .acdirmin = NFS_MINDIRATTRTIMO, 755191783Srmacklem .acdirmax = NFS_MAXDIRATTRTIMO, 756191783Srmacklem }; 757192585Srmacklem int error = 0, ret, len; 758192585Srmacklem struct sockaddr *nam = NULL; 759191783Srmacklem struct vnode *vp; 760191990Sattilio struct thread *td; 761191783Srmacklem char hst[MNAMELEN]; 762191783Srmacklem u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100]; 763192585Srmacklem char *opt, *name, *secname; 764233326Sjhb int nametimeo = NFS_DEFAULT_NAMETIMEO; 765203303Srmacklem int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO; 766221190Srmacklem int dirlen, has_nfs_args_opt, krbnamelen, srvkrbnamelen; 767221205Srmacklem size_t hstlen; 768191783Srmacklem 769221190Srmacklem has_nfs_args_opt = 0; 770191783Srmacklem if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) { 771191783Srmacklem error = EINVAL; 772191783Srmacklem goto out; 773191783Srmacklem } 774191783Srmacklem 775191990Sattilio td = curthread; 776191783Srmacklem if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) { 777221040Srmacklem error = nfs_mountroot(mp); 778191783Srmacklem goto out; 779191783Srmacklem } 780191783Srmacklem 781192585Srmacklem nfscl_init(); 782191783Srmacklem 783221190Srmacklem /* 784221190Srmacklem * The old mount_nfs program passed the struct nfs_args 785221190Srmacklem * from userspace to kernel. The new mount_nfs program 786221190Srmacklem * passes string options via nmount() from userspace to kernel 787221190Srmacklem * and we populate the struct nfs_args in the kernel. 788221190Srmacklem */ 789221190Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) { 790221190Srmacklem error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args, 791221190Srmacklem sizeof(args)); 792221190Srmacklem if (error != 0) 793221190Srmacklem goto out; 794221190Srmacklem 795221190Srmacklem if (args.version != NFS_ARGSVERSION) { 796221190Srmacklem error = EPROGMISMATCH; 797221190Srmacklem goto out; 798221190Srmacklem } 799221190Srmacklem has_nfs_args_opt = 1; 800221190Srmacklem } 801221190Srmacklem 802192585Srmacklem /* Handle the new style options. */ 803192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0) 804192585Srmacklem args.flags |= NFSMNT_NOCONN; 805192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0) 806192585Srmacklem args.flags |= NFSMNT_NOCONN; 807192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0) 808192585Srmacklem args.flags |= NFSMNT_NOLOCKD; 809192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0) 810192585Srmacklem args.flags &= ~NFSMNT_NOLOCKD; 811192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0) 812192585Srmacklem args.flags |= NFSMNT_INT; 813192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0) 814192585Srmacklem args.flags |= NFSMNT_RDIRPLUS; 815192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0) 816192585Srmacklem args.flags |= NFSMNT_RESVPORT; 817192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0) 818192585Srmacklem args.flags &= ~NFSMNT_RESVPORT; 819192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0) 820192585Srmacklem args.flags |= NFSMNT_SOFT; 821192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0) 822192585Srmacklem args.flags &= ~NFSMNT_SOFT; 823192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0) 824192585Srmacklem args.sotype = SOCK_DGRAM; 825192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0) 826192585Srmacklem args.sotype = SOCK_DGRAM; 827192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0) 828192585Srmacklem args.sotype = SOCK_STREAM; 829192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0) 830192585Srmacklem args.flags |= NFSMNT_NFSV3; 831192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) { 832192585Srmacklem args.flags |= NFSMNT_NFSV4; 833192585Srmacklem args.sotype = SOCK_STREAM; 834191783Srmacklem } 835192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0) 836192585Srmacklem args.flags |= NFSMNT_ALLGSSNAME; 837221436Sru if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0) 838221436Sru args.flags |= NFSMNT_NOCTO; 839192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) { 840192585Srmacklem if (opt == NULL) { 841192585Srmacklem vfs_mount_error(mp, "illegal readdirsize"); 842192585Srmacklem error = EINVAL; 843192585Srmacklem goto out; 844192585Srmacklem } 845192585Srmacklem ret = sscanf(opt, "%d", &args.readdirsize); 846192585Srmacklem if (ret != 1 || args.readdirsize <= 0) { 847192585Srmacklem vfs_mount_error(mp, "illegal readdirsize: %s", 848192585Srmacklem opt); 849192585Srmacklem error = EINVAL; 850192585Srmacklem goto out; 851192585Srmacklem } 852192585Srmacklem args.flags |= NFSMNT_READDIRSIZE; 853192585Srmacklem } 854192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) { 855192585Srmacklem if (opt == NULL) { 856192585Srmacklem vfs_mount_error(mp, "illegal readahead"); 857192585Srmacklem error = EINVAL; 858192585Srmacklem goto out; 859192585Srmacklem } 860192585Srmacklem ret = sscanf(opt, "%d", &args.readahead); 861192585Srmacklem if (ret != 1 || args.readahead <= 0) { 862192585Srmacklem vfs_mount_error(mp, "illegal readahead: %s", 863192585Srmacklem opt); 864192585Srmacklem error = EINVAL; 865192585Srmacklem goto out; 866192585Srmacklem } 867192585Srmacklem args.flags |= NFSMNT_READAHEAD; 868192585Srmacklem } 869192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) { 870192585Srmacklem if (opt == NULL) { 871192585Srmacklem vfs_mount_error(mp, "illegal wsize"); 872192585Srmacklem error = EINVAL; 873192585Srmacklem goto out; 874192585Srmacklem } 875192585Srmacklem ret = sscanf(opt, "%d", &args.wsize); 876192585Srmacklem if (ret != 1 || args.wsize <= 0) { 877192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 878192585Srmacklem opt); 879192585Srmacklem error = EINVAL; 880192585Srmacklem goto out; 881192585Srmacklem } 882192585Srmacklem args.flags |= NFSMNT_WSIZE; 883192585Srmacklem } 884192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) { 885192585Srmacklem if (opt == NULL) { 886192585Srmacklem vfs_mount_error(mp, "illegal rsize"); 887192585Srmacklem error = EINVAL; 888192585Srmacklem goto out; 889192585Srmacklem } 890192585Srmacklem ret = sscanf(opt, "%d", &args.rsize); 891192585Srmacklem if (ret != 1 || args.rsize <= 0) { 892192585Srmacklem vfs_mount_error(mp, "illegal wsize: %s", 893192585Srmacklem opt); 894192585Srmacklem error = EINVAL; 895192585Srmacklem goto out; 896192585Srmacklem } 897192585Srmacklem args.flags |= NFSMNT_RSIZE; 898192585Srmacklem } 899192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) { 900192585Srmacklem if (opt == NULL) { 901192585Srmacklem vfs_mount_error(mp, "illegal retrans"); 902192585Srmacklem error = EINVAL; 903192585Srmacklem goto out; 904192585Srmacklem } 905192585Srmacklem ret = sscanf(opt, "%d", &args.retrans); 906192585Srmacklem if (ret != 1 || args.retrans <= 0) { 907192585Srmacklem vfs_mount_error(mp, "illegal retrans: %s", 908192585Srmacklem opt); 909192585Srmacklem error = EINVAL; 910192585Srmacklem goto out; 911192585Srmacklem } 912192585Srmacklem args.flags |= NFSMNT_RETRANS; 913192585Srmacklem } 914192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) { 915192585Srmacklem ret = sscanf(opt, "%d", &args.acregmin); 916192585Srmacklem if (ret != 1 || args.acregmin < 0) { 917192585Srmacklem vfs_mount_error(mp, "illegal acregmin: %s", 918192585Srmacklem opt); 919192585Srmacklem error = EINVAL; 920192585Srmacklem goto out; 921192585Srmacklem } 922192585Srmacklem args.flags |= NFSMNT_ACREGMIN; 923192585Srmacklem } 924192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) { 925192585Srmacklem ret = sscanf(opt, "%d", &args.acregmax); 926192585Srmacklem if (ret != 1 || args.acregmax < 0) { 927192585Srmacklem vfs_mount_error(mp, "illegal acregmax: %s", 928192585Srmacklem opt); 929192585Srmacklem error = EINVAL; 930192585Srmacklem goto out; 931192585Srmacklem } 932192585Srmacklem args.flags |= NFSMNT_ACREGMAX; 933192585Srmacklem } 934192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) { 935192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmin); 936192585Srmacklem if (ret != 1 || args.acdirmin < 0) { 937192585Srmacklem vfs_mount_error(mp, "illegal acdirmin: %s", 938192585Srmacklem opt); 939192585Srmacklem error = EINVAL; 940192585Srmacklem goto out; 941192585Srmacklem } 942192585Srmacklem args.flags |= NFSMNT_ACDIRMIN; 943192585Srmacklem } 944192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) { 945192585Srmacklem ret = sscanf(opt, "%d", &args.acdirmax); 946192585Srmacklem if (ret != 1 || args.acdirmax < 0) { 947192585Srmacklem vfs_mount_error(mp, "illegal acdirmax: %s", 948192585Srmacklem opt); 949192585Srmacklem error = EINVAL; 950192585Srmacklem goto out; 951192585Srmacklem } 952192585Srmacklem args.flags |= NFSMNT_ACDIRMAX; 953192585Srmacklem } 954229604Sjhb if (vfs_getopt(mp->mnt_optnew, "wcommitsize", (void **)&opt, NULL) == 0) { 955229604Sjhb ret = sscanf(opt, "%d", &args.wcommitsize); 956229604Sjhb if (ret != 1 || args.wcommitsize < 0) { 957229604Sjhb vfs_mount_error(mp, "illegal wcommitsize: %s", opt); 958229604Sjhb error = EINVAL; 959229604Sjhb goto out; 960229604Sjhb } 961229604Sjhb args.flags |= NFSMNT_WCOMMITSIZE; 962229604Sjhb } 963192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) { 964192585Srmacklem ret = sscanf(opt, "%d", &args.timeo); 965192585Srmacklem if (ret != 1 || args.timeo <= 0) { 966192585Srmacklem vfs_mount_error(mp, "illegal timeout: %s", 967192585Srmacklem opt); 968192585Srmacklem error = EINVAL; 969192585Srmacklem goto out; 970192585Srmacklem } 971192585Srmacklem args.flags |= NFSMNT_TIMEO; 972192585Srmacklem } 973233326Sjhb if (vfs_getopt(mp->mnt_optnew, "nametimeo", (void **)&opt, NULL) == 0) { 974233326Sjhb ret = sscanf(opt, "%d", &nametimeo); 975233326Sjhb if (ret != 1 || nametimeo < 0) { 976233326Sjhb vfs_mount_error(mp, "illegal nametimeo: %s", opt); 977233326Sjhb error = EINVAL; 978233326Sjhb goto out; 979233326Sjhb } 980233326Sjhb } 981203303Srmacklem if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL) 982203303Srmacklem == 0) { 983203303Srmacklem ret = sscanf(opt, "%d", &negnametimeo); 984203303Srmacklem if (ret != 1 || negnametimeo < 0) { 985203303Srmacklem vfs_mount_error(mp, "illegal negnametimeo: %s", 986203303Srmacklem opt); 987203303Srmacklem error = EINVAL; 988203303Srmacklem goto out; 989203303Srmacklem } 990203303Srmacklem } 991192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "sec", 992192585Srmacklem (void **) &secname, NULL) == 0) 993192585Srmacklem nfs_sec_name(secname, &args.flags); 994191783Srmacklem 995191783Srmacklem if (mp->mnt_flag & MNT_UPDATE) { 996191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 997191783Srmacklem 998191783Srmacklem if (nmp == NULL) { 999191783Srmacklem error = EIO; 1000191783Srmacklem goto out; 1001191783Srmacklem } 1002231636Srmacklem 1003191783Srmacklem /* 1004231636Srmacklem * If a change from TCP->UDP is done and there are thread(s) 1005231636Srmacklem * that have I/O RPC(s) in progress with a tranfer size 1006231636Srmacklem * greater than NFS_MAXDGRAMDATA, those thread(s) will be 1007231636Srmacklem * hung, retrying the RPC(s) forever. Usually these threads 1008231636Srmacklem * will be seen doing an uninterruptible sleep on wait channel 1009231636Srmacklem * "newnfsreq" (truncated to "newnfsre" by procstat). 1010231636Srmacklem */ 1011231636Srmacklem if (args.sotype == SOCK_DGRAM && nmp->nm_sotype == SOCK_STREAM) 1012231636Srmacklem tprintf(td->td_proc, LOG_WARNING, 1013231636Srmacklem "Warning: mount -u that changes TCP->UDP can result in hung threads\n"); 1014231636Srmacklem 1015231636Srmacklem /* 1016191783Srmacklem * When doing an update, we can't change version, 1017191783Srmacklem * security, switch lockd strategies or change cookie 1018191783Srmacklem * translation 1019191783Srmacklem */ 1020191783Srmacklem args.flags = (args.flags & 1021191783Srmacklem ~(NFSMNT_NFSV3 | 1022191783Srmacklem NFSMNT_NFSV4 | 1023191783Srmacklem NFSMNT_KERB | 1024191783Srmacklem NFSMNT_INTEGRITY | 1025191783Srmacklem NFSMNT_PRIVACY | 1026191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) | 1027191783Srmacklem (nmp->nm_flag & 1028191783Srmacklem (NFSMNT_NFSV3 | 1029191783Srmacklem NFSMNT_NFSV4 | 1030191783Srmacklem NFSMNT_KERB | 1031191783Srmacklem NFSMNT_INTEGRITY | 1032191783Srmacklem NFSMNT_PRIVACY | 1033191783Srmacklem NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); 1034214048Srmacklem nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td); 1035191783Srmacklem goto out; 1036191783Srmacklem } 1037191783Srmacklem 1038191783Srmacklem /* 1039191783Srmacklem * Make the nfs_ip_paranoia sysctl serve as the default connection 1040191783Srmacklem * or no-connection mode for those protocols that support 1041191783Srmacklem * no-connection mode (the flag will be cleared later for protocols 1042191783Srmacklem * that do not support no-connection mode). This will allow a client 1043191783Srmacklem * to receive replies from a different IP then the request was 1044191783Srmacklem * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid), 1045191783Srmacklem * not 0. 1046191783Srmacklem */ 1047191783Srmacklem if (nfs_ip_paranoia == 0) 1048191783Srmacklem args.flags |= NFSMNT_NOCONN; 1049192585Srmacklem 1050221190Srmacklem if (has_nfs_args_opt != 0) { 1051221190Srmacklem /* 1052221190Srmacklem * In the 'nfs_args' case, the pointers in the args 1053221190Srmacklem * structure are in userland - we copy them in here. 1054221190Srmacklem */ 1055221190Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) { 1056192585Srmacklem vfs_mount_error(mp, "Bad file handle"); 1057191783Srmacklem error = EINVAL; 1058191783Srmacklem goto out; 1059191783Srmacklem } 1060221190Srmacklem error = copyin((caddr_t)args.fh, (caddr_t)nfh, 1061221190Srmacklem args.fhsize); 1062221190Srmacklem if (error != 0) 1063221190Srmacklem goto out; 1064221205Srmacklem error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen); 1065221190Srmacklem if (error != 0) 1066221190Srmacklem goto out; 1067221205Srmacklem bzero(&hst[hstlen], MNAMELEN - hstlen); 1068221190Srmacklem args.hostname = hst; 1069221190Srmacklem /* sockargs() call must be after above copyin() calls */ 1070221190Srmacklem error = getsockaddr(&nam, (caddr_t)args.addr, 1071221190Srmacklem args.addrlen); 1072221190Srmacklem if (error != 0) 1073221190Srmacklem goto out; 1074191783Srmacklem } else { 1075221190Srmacklem if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh, 1076221190Srmacklem &args.fhsize) == 0) { 1077221190Srmacklem if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) { 1078221190Srmacklem vfs_mount_error(mp, "Bad file handle"); 1079221190Srmacklem error = EINVAL; 1080221190Srmacklem goto out; 1081221190Srmacklem } 1082221190Srmacklem bcopy(args.fh, nfh, args.fhsize); 1083221190Srmacklem } else { 1084221190Srmacklem args.fhsize = 0; 1085221190Srmacklem } 1086221190Srmacklem (void) vfs_getopt(mp->mnt_optnew, "hostname", 1087221190Srmacklem (void **)&args.hostname, &len); 1088221190Srmacklem if (args.hostname == NULL) { 1089221190Srmacklem vfs_mount_error(mp, "Invalid hostname"); 1090221190Srmacklem error = EINVAL; 1091221190Srmacklem goto out; 1092221190Srmacklem } 1093221190Srmacklem bcopy(args.hostname, hst, MNAMELEN); 1094221190Srmacklem hst[MNAMELEN - 1] = '\0'; 1095192585Srmacklem } 1096192585Srmacklem 1097192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0) 1098192585Srmacklem strlcpy(srvkrbname, name, sizeof (srvkrbname)); 1099192585Srmacklem else 1100192585Srmacklem snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst); 1101221014Srmacklem srvkrbnamelen = strlen(srvkrbname); 1102192585Srmacklem 1103192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0) 1104192585Srmacklem strlcpy(krbname, name, sizeof (krbname)); 1105192585Srmacklem else 1106191783Srmacklem krbname[0] = '\0'; 1107221014Srmacklem krbnamelen = strlen(krbname); 1108192585Srmacklem 1109192585Srmacklem if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0) 1110192585Srmacklem strlcpy(dirpath, name, sizeof (dirpath)); 1111192585Srmacklem else 1112191783Srmacklem dirpath[0] = '\0'; 1113221014Srmacklem dirlen = strlen(dirpath); 1114192585Srmacklem 1115222075Srmacklem if (has_nfs_args_opt == 0) { 1116222075Srmacklem if (vfs_getopt(mp->mnt_optnew, "addr", 1117222075Srmacklem (void **)&args.addr, &args.addrlen) == 0) { 1118222075Srmacklem if (args.addrlen > SOCK_MAXADDRLEN) { 1119222075Srmacklem error = ENAMETOOLONG; 1120222075Srmacklem goto out; 1121222075Srmacklem } 1122222075Srmacklem nam = malloc(args.addrlen, M_SONAME, M_WAITOK); 1123222075Srmacklem bcopy(args.addr, nam, args.addrlen); 1124222075Srmacklem nam->sa_len = args.addrlen; 1125222075Srmacklem } else { 1126222075Srmacklem vfs_mount_error(mp, "No server address"); 1127222075Srmacklem error = EINVAL; 1128191783Srmacklem goto out; 1129191783Srmacklem } 1130191783Srmacklem } 1131192585Srmacklem 1132191783Srmacklem args.fh = nfh; 1133221014Srmacklem error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath, 1134221014Srmacklem dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td, 1135233326Sjhb nametimeo, negnametimeo); 1136191783Srmacklemout: 1137191783Srmacklem if (!error) { 1138191783Srmacklem MNT_ILOCK(mp); 1139191783Srmacklem mp->mnt_kern_flag |= (MNTK_MPSAFE|MNTK_LOOKUP_SHARED); 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; 1412191783Srmacklem int error, flags = 0, 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); 1447191783Srmacklem newnfs_disconnect(&nmp->nm_sockreq); 1448191783Srmacklem crfree(nmp->nm_sockreq.nr_cred); 1449191783Srmacklem FREE(nmp->nm_nam, M_SONAME); 1450191783Srmacklem 1451191783Srmacklem mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1452191783Srmacklem mtx_destroy(&nmp->nm_mtx); 1453191783Srmacklem FREE(nmp, M_NEWNFSMNT); 1454191783Srmacklemout: 1455191783Srmacklem return (error); 1456191783Srmacklem} 1457191783Srmacklem 1458191783Srmacklem/* 1459191783Srmacklem * Return root of a filesystem 1460191783Srmacklem */ 1461191783Srmacklemstatic int 1462191990Sattilionfs_root(struct mount *mp, int flags, struct vnode **vpp) 1463191783Srmacklem{ 1464191783Srmacklem struct vnode *vp; 1465191783Srmacklem struct nfsmount *nmp; 1466191783Srmacklem struct nfsnode *np; 1467191783Srmacklem int error; 1468191783Srmacklem 1469191783Srmacklem nmp = VFSTONFS(mp); 1470220732Srmacklem error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags); 1471191783Srmacklem if (error) 1472191783Srmacklem return error; 1473191783Srmacklem vp = NFSTOV(np); 1474191783Srmacklem /* 1475191783Srmacklem * Get transfer parameters and attributes for root vnode once. 1476191783Srmacklem */ 1477191783Srmacklem mtx_lock(&nmp->nm_mtx); 1478191783Srmacklem if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 1479191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1480191783Srmacklem ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread); 1481191783Srmacklem } else 1482191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1483191783Srmacklem if (vp->v_type == VNON) 1484191783Srmacklem vp->v_type = VDIR; 1485191783Srmacklem vp->v_vflag |= VV_ROOT; 1486191783Srmacklem *vpp = vp; 1487191783Srmacklem return (0); 1488191783Srmacklem} 1489191783Srmacklem 1490191783Srmacklem/* 1491191783Srmacklem * Flush out the buffer cache 1492191783Srmacklem */ 1493191783Srmacklem/* ARGSUSED */ 1494191783Srmacklemstatic int 1495191990Sattilionfs_sync(struct mount *mp, int waitfor) 1496191783Srmacklem{ 1497191783Srmacklem struct vnode *vp, *mvp; 1498191990Sattilio struct thread *td; 1499191783Srmacklem int error, allerror = 0; 1500191783Srmacklem 1501191990Sattilio td = curthread; 1502191990Sattilio 1503222329Srmacklem MNT_ILOCK(mp); 1504191783Srmacklem /* 1505222329Srmacklem * If a forced dismount is in progress, return from here so that 1506222329Srmacklem * the umount(2) syscall doesn't get stuck in VFS_SYNC() before 1507222329Srmacklem * calling VFS_UNMOUNT(). 1508222329Srmacklem */ 1509222329Srmacklem if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1510222329Srmacklem MNT_IUNLOCK(mp); 1511222329Srmacklem return (EBADF); 1512222329Srmacklem } 1513222329Srmacklem 1514222329Srmacklem /* 1515191783Srmacklem * Force stale buffer cache information to be flushed. 1516191783Srmacklem */ 1517191783Srmacklemloop: 1518191783Srmacklem MNT_VNODE_FOREACH(vp, mp, mvp) { 1519191783Srmacklem VI_LOCK(vp); 1520191783Srmacklem MNT_IUNLOCK(mp); 1521191783Srmacklem /* XXX Racy bv_cnt check. */ 1522224083Szack if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1523191783Srmacklem waitfor == MNT_LAZY) { 1524191783Srmacklem VI_UNLOCK(vp); 1525191783Srmacklem MNT_ILOCK(mp); 1526191783Srmacklem continue; 1527191783Srmacklem } 1528191783Srmacklem if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 1529191783Srmacklem MNT_ILOCK(mp); 1530191783Srmacklem MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); 1531191783Srmacklem goto loop; 1532191783Srmacklem } 1533191783Srmacklem error = VOP_FSYNC(vp, waitfor, td); 1534191783Srmacklem if (error) 1535191783Srmacklem allerror = error; 1536224082Szack NFSVOPUNLOCK(vp, 0); 1537191783Srmacklem vrele(vp); 1538191783Srmacklem 1539191783Srmacklem MNT_ILOCK(mp); 1540191783Srmacklem } 1541191783Srmacklem MNT_IUNLOCK(mp); 1542191783Srmacklem return (allerror); 1543191783Srmacklem} 1544191783Srmacklem 1545191783Srmacklemstatic int 1546191783Srmacklemnfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 1547191783Srmacklem{ 1548191783Srmacklem struct nfsmount *nmp = VFSTONFS(mp); 1549191783Srmacklem struct vfsquery vq; 1550191783Srmacklem int error; 1551191783Srmacklem 1552191783Srmacklem bzero(&vq, sizeof(vq)); 1553191783Srmacklem switch (op) { 1554191783Srmacklem#if 0 1555191783Srmacklem case VFS_CTL_NOLOCKS: 1556191783Srmacklem val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; 1557191783Srmacklem if (req->oldptr != NULL) { 1558191783Srmacklem error = SYSCTL_OUT(req, &val, sizeof(val)); 1559191783Srmacklem if (error) 1560191783Srmacklem return (error); 1561191783Srmacklem } 1562191783Srmacklem if (req->newptr != NULL) { 1563191783Srmacklem error = SYSCTL_IN(req, &val, sizeof(val)); 1564191783Srmacklem if (error) 1565191783Srmacklem return (error); 1566191783Srmacklem if (val) 1567191783Srmacklem nmp->nm_flag |= NFSMNT_NOLOCKS; 1568191783Srmacklem else 1569191783Srmacklem nmp->nm_flag &= ~NFSMNT_NOLOCKS; 1570191783Srmacklem } 1571191783Srmacklem break; 1572191783Srmacklem#endif 1573191783Srmacklem case VFS_CTL_QUERY: 1574191783Srmacklem mtx_lock(&nmp->nm_mtx); 1575191783Srmacklem if (nmp->nm_state & NFSSTA_TIMEO) 1576191783Srmacklem vq.vq_flags |= VQ_NOTRESP; 1577191783Srmacklem mtx_unlock(&nmp->nm_mtx); 1578191783Srmacklem#if 0 1579191783Srmacklem if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && 1580191783Srmacklem (nmp->nm_state & NFSSTA_LOCKTIMEO)) 1581191783Srmacklem vq.vq_flags |= VQ_NOTRESPLOCK; 1582191783Srmacklem#endif 1583191783Srmacklem error = SYSCTL_OUT(req, &vq, sizeof(vq)); 1584191783Srmacklem break; 1585191783Srmacklem case VFS_CTL_TIMEO: 1586191783Srmacklem if (req->oldptr != NULL) { 1587191783Srmacklem error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, 1588191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1589191783Srmacklem if (error) 1590191783Srmacklem return (error); 1591191783Srmacklem } 1592191783Srmacklem if (req->newptr != NULL) { 1593191783Srmacklem error = vfs_suser(mp, req->td); 1594191783Srmacklem if (error) 1595191783Srmacklem return (error); 1596191783Srmacklem error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, 1597191783Srmacklem sizeof(nmp->nm_tprintf_initial_delay)); 1598191783Srmacklem if (error) 1599191783Srmacklem return (error); 1600191783Srmacklem if (nmp->nm_tprintf_initial_delay < 0) 1601191783Srmacklem nmp->nm_tprintf_initial_delay = 0; 1602191783Srmacklem } 1603191783Srmacklem break; 1604191783Srmacklem default: 1605191783Srmacklem return (ENOTSUP); 1606191783Srmacklem } 1607191783Srmacklem return (0); 1608191783Srmacklem} 1609191783Srmacklem 1610214048Srmacklem/* 1611214048Srmacklem * Extract the information needed by the nlm from the nfs vnode. 1612214048Srmacklem */ 1613214048Srmacklemstatic void 1614214053Srmacklemnfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp, 1615216931Srmacklem struct sockaddr_storage *sp, int *is_v3p, off_t *sizep, 1616216931Srmacklem struct timeval *timeop) 1617214048Srmacklem{ 1618214048Srmacklem struct nfsmount *nmp; 1619214048Srmacklem struct nfsnode *np = VTONFS(vp); 1620214048Srmacklem 1621214048Srmacklem nmp = VFSTONFS(vp->v_mount); 1622214048Srmacklem if (fhlenp != NULL) 1623214053Srmacklem *fhlenp = (size_t)np->n_fhp->nfh_len; 1624214048Srmacklem if (fhp != NULL) 1625214048Srmacklem bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len); 1626214048Srmacklem if (sp != NULL) 1627214048Srmacklem bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp))); 1628214048Srmacklem if (is_v3p != NULL) 1629214048Srmacklem *is_v3p = NFS_ISV3(vp); 1630214048Srmacklem if (sizep != NULL) 1631214048Srmacklem *sizep = np->n_size; 1632216931Srmacklem if (timeop != NULL) { 1633216931Srmacklem timeop->tv_sec = nmp->nm_timeo / NFS_HZ; 1634216931Srmacklem timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ); 1635216931Srmacklem } 1636214048Srmacklem} 1637214048Srmacklem 1638