nfs_clvfsops.c revision 229263
1697Spaul/*- 21156Sjkh * Copyright (c) 1989, 1993, 1995 31156Sjkh * The Regents of the University of California. All rights reserved. 41156Sjkh * 51156Sjkh * This code is derived from software contributed to Berkeley by 61156Sjkh * Rick Macklem at The University of Guelph. 71156Sjkh * 81156Sjkh * Redistribution and use in source and binary forms, with or without 91156Sjkh * modification, are permitted provided that the following conditions 101156Sjkh * are met: 111156Sjkh * 1. Redistributions of source code must retain the above copyright 121156Sjkh * notice, this list of conditions and the following disclaimer. 131156Sjkh * 2. Redistributions in binary form must reproduce the above copyright 141156Sjkh * notice, this list of conditions and the following disclaimer in the 151156Sjkh * documentation and/or other materials provided with the distribution. 161156Sjkh * 4. Neither the name of the University nor the names of its contributors 1713771Smpp * may be used to endorse or promote products derived from this software 181156Sjkh * without specific prior written permission. 191156Sjkh * 201156Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211156Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221156Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231156Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241156Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251156Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261156Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271156Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281156Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291156Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3050473Speter * SUCH DAMAGE. 311156Sjkh * 321156Sjkh * from nfs_vfsops.c 8.12 (Berkeley) 5/20/95 331156Sjkh */ 34697Spaul 35697Spaul#include <sys/cdefs.h> 361156Sjkh__FBSDID("$FreeBSD: stable/9/sys/fs/nfsclient/nfs_clvfsops.c 229263 2012-01-02 04:25:25Z rmacklem $"); 371156Sjkh 381156Sjkh 39697Spaul#include "opt_bootp.h" 40697Spaul#include "opt_nfsroot.h" 41697Spaul 42697Spaul#include <sys/param.h> 43697Spaul#include <sys/systm.h> 4436311Sdfr#include <sys/kernel.h> 4536311Sdfr#include <sys/bio.h> 4636311Sdfr#include <sys/buf.h> 4736311Sdfr#include <sys/clock.h> 4836311Sdfr#include <sys/jail.h> 4936311Sdfr#include <sys/limits.h> 5036311Sdfr#include <sys/lock.h> 5136311Sdfr#include <sys/malloc.h> 5236311Sdfr#include <sys/mbuf.h> 5336311Sdfr#include <sys/module.h> 5436311Sdfr#include <sys/mount.h> 5536311Sdfr#include <sys/proc.h> 5636311Sdfr#include <sys/socket.h> 5736311Sdfr#include <sys/socketvar.h> 5836311Sdfr#include <sys/sockio.h> 5936311Sdfr#include <sys/sysctl.h> 6036311Sdfr#include <sys/vnode.h> 6136311Sdfr#include <sys/signalvar.h> 6236311Sdfr 6336311Sdfr#include <vm/vm.h> 6436311Sdfr#include <vm/vm_extern.h> 6536311Sdfr#include <vm/uma.h> 6636311Sdfr 6736311Sdfr#include <net/if.h> 6836311Sdfr#include <net/route.h> 6936311Sdfr#include <netinet/in.h> 7036311Sdfr 7133137Sjdp#include <fs/nfs/nfsport.h> 7233137Sjdp#include <fs/nfsclient/nfsnode.h> 73697Spaul#include <fs/nfsclient/nfsmount.h> 7413771Smpp#include <fs/nfsclient/nfs.h> 75697Spaul#include <nfs/nfsdiskless.h> 761156Sjkh 771156SjkhFEATURE(nfscl, "NFSv4 client"); 78697Spaul 79697Spaulextern int nfscl_ticks; 801156Sjkhextern struct timeval nfsboottime; 811156Sjkhextern struct nfsstats newnfsstats; 821156Sjkhextern int nfsrv_useacl; 831156Sjkh 841156SjkhMALLOC_DEFINE(M_NEWNFSREQ, "newnfsclient_req", "New NFS request header"); 851156SjkhMALLOC_DEFINE(M_NEWNFSMNT, "newnfsmnt", "New NFS mount struct"); 861156Sjkh 87697SpaulSYSCTL_DECL(_vfs_nfs); 88697Spaulstatic int nfs_ip_paranoia = 1; 89697SpaulSYSCTL_INT(_vfs_nfs, OID_AUTO, nfs_ip_paranoia, CTLFLAG_RW, 901156Sjkh &nfs_ip_paranoia, 0, ""); 911156Sjkhstatic int nfs_tprintf_initial_delay = NFS_TPRINTF_INITIAL_DELAY; 92697SpaulSYSCTL_INT(_vfs_nfs, NFS_TPRINTF_INITIAL_DELAY, 93697Spaul downdelayinitial, CTLFLAG_RW, &nfs_tprintf_initial_delay, 0, ""); 94697Spaul/* how long between console messages "nfs server foo not responding" */ 951156Sjkhstatic int nfs_tprintf_delay = NFS_TPRINTF_DELAY; 961156SjkhSYSCTL_INT(_vfs_nfs, NFS_TPRINTF_DELAY, 971156Sjkh downdelayinterval, CTLFLAG_RW, &nfs_tprintf_delay, 0, ""); 981156Sjkh 991156Sjkhstatic int nfs_mountroot(struct mount *); 1001156Sjkhstatic void nfs_sec_name(char *, int *); 1011156Sjkhstatic void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, 1021156Sjkh struct nfs_args *argp, const char *, struct ucred *, 1031156Sjkh struct thread *); 104697Spaulstatic int mountnfs(struct nfs_args *, struct mount *, 105697Spaul struct sockaddr *, char *, u_char *, int, u_char *, int, 106697Spaul u_char *, int, struct vnode **, struct ucred *, 107697Spaul struct thread *, int); 108697Spaulstatic void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *, 109697Spaul struct sockaddr_storage *, int *, off_t *, 110697Spaul struct timeval *); 1111156Sjkhstatic vfs_mount_t nfs_mount; 112697Spaulstatic vfs_cmount_t nfs_cmount; 113697Spaulstatic vfs_unmount_t nfs_unmount; 114697Spaulstatic vfs_root_t nfs_root; 115697Spaulstatic vfs_statfs_t nfs_statfs; 11631584Sjdpstatic vfs_sync_t nfs_sync; 11731584Sjdpstatic vfs_sysctl_t nfs_sysctl; 118697Spaul 119697Spaul/* 120697Spaul * nfs vfs operations. 121697Spaul */ 122697Spaulstatic struct vfsops nfs_vfsops = { 123697Spaul .vfs_init = ncl_init, 124697Spaul .vfs_mount = nfs_mount, 125697Spaul .vfs_cmount = nfs_cmount, 126697Spaul .vfs_root = nfs_root, 1271156Sjkh .vfs_statfs = nfs_statfs, 128697Spaul .vfs_sync = nfs_sync, 129697Spaul .vfs_uninit = ncl_uninit, 1301156Sjkh .vfs_unmount = nfs_unmount, 1311156Sjkh .vfs_sysctl = nfs_sysctl, 1321156Sjkh}; 13318591SpeterVFS_SET(nfs_vfsops, nfs, VFCF_NETWORK); 1341156Sjkh 1351156Sjkh/* So that loader and kldload(2) can find us, wherever we are.. */ 1361156SjkhMODULE_VERSION(nfs, 1); 1371156SjkhMODULE_DEPEND(nfs, nfscommon, 1, 1, 1); 1381156SjkhMODULE_DEPEND(nfs, krpc, 1, 1, 1); 1391156SjkhMODULE_DEPEND(nfs, nfssvc, 1, 1, 1); 1401156SjkhMODULE_DEPEND(nfs, nfslock, 1, 1, 1); 1411156Sjkh 1421156Sjkh/* 1431156Sjkh * This structure is now defined in sys/nfs/nfs_diskless.c so that it 1441156Sjkh * can be shared by both NFS clients. It is declared here so that it 145697Spaul * will be defined for kernels built without NFS_ROOT, although it 146697Spaul * isn't used in that case. 147697Spaul */ 1481156Sjkh#if !defined(NFS_ROOT) && !defined(NFSCLIENT) 149697Spaulstruct nfs_diskless nfs_diskless = { { { 0 } } }; 150697Spaulstruct nfsv3_diskless nfsv3_diskless = { { { 0 } } }; 1511156Sjkhint nfs_diskless_valid = 0; 152697Spaul#endif 153697Spaul 154697SpaulSYSCTL_INT(_vfs_nfs, OID_AUTO, diskless_valid, CTLFLAG_RD, 1551156Sjkh &nfs_diskless_valid, 0, 1561156Sjkh "Has the diskless struct been filled correctly"); 157697Spaul 158697SpaulSYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD, 159697Spaul nfsv3_diskless.root_hostnam, 0, "Path to nfs root"); 160697Spaul 161697SpaulSYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD, 162697Spaul &nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr), 163697Spaul "%Ssockaddr_in", "Diskless root nfs address"); 1641156Sjkh 1651156Sjkh 1661156Sjkhvoid newnfsargs_ntoh(struct nfs_args *); 1671156Sjkhstatic int nfs_mountdiskless(char *, 1681156Sjkh struct sockaddr_in *, struct nfs_args *, 169697Spaul struct thread *, struct vnode **, struct mount *); 170697Spaulstatic void nfs_convert_diskless(void); 171697Spaulstatic void nfs_convert_oargs(struct nfs_args *args, 172697Spaul struct onfs_args *oargs); 173697Spaul 1741156Sjkhint 1751156Sjkhnewnfs_iosize(struct nfsmount *nmp) 1761156Sjkh{ 1771156Sjkh int iosize, maxio; 1781156Sjkh 1791156Sjkh /* First, set the upper limit for iosize */ 1801156Sjkh if (nmp->nm_flag & NFSMNT_NFSV4) { 1811156Sjkh maxio = NFS_MAXBSIZE; 182697Spaul } else if (nmp->nm_flag & NFSMNT_NFSV3) { 183697Spaul if (nmp->nm_sotype == SOCK_DGRAM) 184697Spaul maxio = NFS_MAXDGRAMDATA; 1859335Sdfr else 1869335Sdfr maxio = NFS_MAXBSIZE; 1879335Sdfr } else { 1889335Sdfr maxio = NFS_V2MAXDATA; 18927838Sjdp } 19033137Sjdp if (nmp->nm_rsize > maxio || nmp->nm_rsize == 0) 1919335Sdfr nmp->nm_rsize = maxio; 1929335Sdfr if (nmp->nm_rsize > MAXBSIZE) 193697Spaul nmp->nm_rsize = MAXBSIZE; 1949335Sdfr if (nmp->nm_readdirsize > maxio || nmp->nm_readdirsize == 0) 1959335Sdfr nmp->nm_readdirsize = maxio; 196697Spaul if (nmp->nm_readdirsize > nmp->nm_rsize) 197697Spaul nmp->nm_readdirsize = nmp->nm_rsize; 19831342Sbrian if (nmp->nm_wsize > maxio || nmp->nm_wsize == 0) 1999335Sdfr nmp->nm_wsize = maxio; 20031342Sbrian if (nmp->nm_wsize > MAXBSIZE) 20131342Sbrian nmp->nm_wsize = MAXBSIZE; 2029335Sdfr 20331342Sbrian /* 20433137Sjdp * Calculate the size used for io buffers. Use the larger 20533137Sjdp * of the two sizes to minimise nfs requests but make sure 206697Spaul * that it is at least one VM page to avoid wasting buffer 207697Spaul * space. 208697Spaul */ 209697Spaul iosize = imax(nmp->nm_rsize, nmp->nm_wsize); 210697Spaul iosize = imax(iosize, PAGE_SIZE); 211697Spaul nmp->nm_mountp->mnt_stat.f_iosize = iosize; 212697Spaul return (iosize); 2131156Sjkh} 2141156Sjkh 215697Spaulstatic void 216697Spaulnfs_convert_oargs(struct nfs_args *args, struct onfs_args *oargs) 217697Spaul{ 218697Spaul 219697Spaul args->version = NFS_ARGSVERSION; 2201156Sjkh args->addr = oargs->addr; 2211156Sjkh args->addrlen = oargs->addrlen; 2221156Sjkh args->sotype = oargs->sotype; 223697Spaul args->proto = oargs->proto; 2241156Sjkh args->fh = oargs->fh; 2251156Sjkh args->fhsize = oargs->fhsize; 2266887Snate args->flags = oargs->flags; 227697Spaul args->wsize = oargs->wsize; 228697Spaul args->rsize = oargs->rsize; 229697Spaul args->readdirsize = oargs->readdirsize; 230697Spaul args->timeo = oargs->timeo; 231697Spaul args->retrans = oargs->retrans; 232697Spaul args->readahead = oargs->readahead; 2331156Sjkh args->hostname = oargs->hostname; 2341156Sjkh} 2351156Sjkh 2361156Sjkhstatic void 2371156Sjkhnfs_convert_diskless(void) 2381156Sjkh{ 2391156Sjkh 2401156Sjkh bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif, 24118591Speter sizeof(struct ifaliasreq)); 242697Spaul bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway, 2431156Sjkh sizeof(struct sockaddr_in)); 2441156Sjkh nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args); 2451156Sjkh if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) { 2461156Sjkh nfsv3_diskless.root_fhsize = NFSX_MYFH; 2471156Sjkh bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_MYFH); 2481156Sjkh } else { 2491156Sjkh nfsv3_diskless.root_fhsize = NFSX_V2FH; 250697Spaul bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH); 251697Spaul } 2521156Sjkh bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr, 253697Spaul sizeof(struct sockaddr_in)); 254697Spaul bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN); 255697Spaul nfsv3_diskless.root_time = nfs_diskless.root_time; 25613771Smpp bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam, 257697Spaul MAXHOSTNAMELEN); 2581156Sjkh nfs_diskless_valid = 3; 259697Spaul} 260697Spaul 2616887Snate/* 2626887Snate * nfs statfs call 2636887Snate */ 26433137Sjdpstatic int 265697Spaulnfs_statfs(struct mount *mp, struct statfs *sbp) 266697Spaul{ 267697Spaul struct vnode *vp; 268697Spaul struct thread *td; 269697Spaul struct nfsmount *nmp = VFSTONFS(mp); 270697Spaul struct nfsvattr nfsva; 2711156Sjkh struct nfsfsinfo fs; 2721156Sjkh struct nfsstatfs sb; 2736887Snate int error = 0, attrflag, gotfsinfo = 0, ret; 27433137Sjdp struct nfsnode *np; 275697Spaul 276697Spaul td = curthread; 277697Spaul 278697Spaul error = vfs_busy(mp, MBF_NOWAIT); 279697Spaul if (error) 280697Spaul return (error); 281697Spaul error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE); 282697Spaul if (error) { 283697Spaul vfs_unbusy(mp); 284697Spaul return (error); 285697Spaul } 286697Spaul vp = NFSTOV(np); 287697Spaul mtx_lock(&nmp->nm_mtx); 288697Spaul if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 28918591Speter mtx_unlock(&nmp->nm_mtx); 290697Spaul error = nfsrpc_fsinfo(vp, &fs, td->td_ucred, td, &nfsva, 291697Spaul &attrflag, NULL); 292697Spaul if (!error) 293697Spaul gotfsinfo = 1; 294697Spaul } else 29518591Speter mtx_unlock(&nmp->nm_mtx); 296697Spaul if (!error) 297697Spaul error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, 298697Spaul &attrflag, NULL); 299697Spaul if (attrflag == 0) { 300697Spaul ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 301697Spaul td->td_ucred, td, &nfsva, NULL); 302697Spaul if (ret) { 303697Spaul /* 304697Spaul * Just set default values to get things going. 305697Spaul */ 306697Spaul NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 307697Spaul nfsva.na_vattr.va_type = VDIR; 308697Spaul nfsva.na_vattr.va_mode = 0777; 309697Spaul nfsva.na_vattr.va_nlink = 100; 310697Spaul nfsva.na_vattr.va_uid = (uid_t)0; 311697Spaul nfsva.na_vattr.va_gid = (gid_t)0; 312697Spaul nfsva.na_vattr.va_fileid = 2; 313697Spaul nfsva.na_vattr.va_gen = 1; 314697Spaul nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 315697Spaul nfsva.na_vattr.va_size = 512 * 1024; 31636311Sdfr } 31736311Sdfr } 318697Spaul (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1); 319 if (!error) { 320 mtx_lock(&nmp->nm_mtx); 321 if (gotfsinfo || (nmp->nm_flag & NFSMNT_NFSV4)) 322 nfscl_loadfsinfo(nmp, &fs); 323 nfscl_loadsbinfo(nmp, &sb, sbp); 324 sbp->f_iosize = newnfs_iosize(nmp); 325 mtx_unlock(&nmp->nm_mtx); 326 if (sbp != &mp->mnt_stat) { 327 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 328 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 329 } 330 strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN); 331 } else if (NFS_ISV4(vp)) { 332 error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 333 } 334 vput(vp); 335 vfs_unbusy(mp); 336 return (error); 337} 338 339/* 340 * nfs version 3 fsinfo rpc call 341 */ 342int 343ncl_fsinfo(struct nfsmount *nmp, struct vnode *vp, struct ucred *cred, 344 struct thread *td) 345{ 346 struct nfsfsinfo fs; 347 struct nfsvattr nfsva; 348 int error, attrflag; 349 350 error = nfsrpc_fsinfo(vp, &fs, cred, td, &nfsva, &attrflag, NULL); 351 if (!error) { 352 if (attrflag) 353 (void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 354 1); 355 mtx_lock(&nmp->nm_mtx); 356 nfscl_loadfsinfo(nmp, &fs); 357 mtx_unlock(&nmp->nm_mtx); 358 } 359 return (error); 360} 361 362/* 363 * Mount a remote root fs via. nfs. This depends on the info in the 364 * nfs_diskless structure that has been filled in properly by some primary 365 * bootstrap. 366 * It goes something like this: 367 * - do enough of "ifconfig" by calling ifioctl() so that the system 368 * can talk to the server 369 * - If nfs_diskless.mygateway is filled in, use that address as 370 * a default gateway. 371 * - build the rootfs mount point and call mountnfs() to do the rest. 372 * 373 * It is assumed to be safe to read, modify, and write the nfsv3_diskless 374 * structure, as well as other global NFS client variables here, as 375 * nfs_mountroot() will be called once in the boot before any other NFS 376 * client activity occurs. 377 */ 378static int 379nfs_mountroot(struct mount *mp) 380{ 381 struct thread *td = curthread; 382 struct nfsv3_diskless *nd = &nfsv3_diskless; 383 struct socket *so; 384 struct vnode *vp; 385 struct ifreq ir; 386 int error; 387 u_long l; 388 char buf[128]; 389 char *cp; 390 391#if defined(BOOTP_NFSROOT) && defined(BOOTP) 392 bootpc_init(); /* use bootp to get nfs_diskless filled in */ 393#elif defined(NFS_ROOT) 394 nfs_setup_diskless(); 395#endif 396 397 if (nfs_diskless_valid == 0) 398 return (-1); 399 if (nfs_diskless_valid == 1) 400 nfs_convert_diskless(); 401 402 /* 403 * XXX splnet, so networks will receive... 404 */ 405 splnet(); 406 407 /* 408 * Do enough of ifconfig(8) so that the critical net interface can 409 * talk to the server. 410 */ 411 error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0, 412 td->td_ucred, td); 413 if (error) 414 panic("nfs_mountroot: socreate(%04x): %d", 415 nd->myif.ifra_addr.sa_family, error); 416 417#if 0 /* XXX Bad idea */ 418 /* 419 * We might not have been told the right interface, so we pass 420 * over the first ten interfaces of the same kind, until we get 421 * one of them configured. 422 */ 423 424 for (i = strlen(nd->myif.ifra_name) - 1; 425 nd->myif.ifra_name[i] >= '0' && 426 nd->myif.ifra_name[i] <= '9'; 427 nd->myif.ifra_name[i] ++) { 428 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 429 if(!error) 430 break; 431 } 432#endif 433 error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td); 434 if (error) 435 panic("nfs_mountroot: SIOCAIFADDR: %d", error); 436 if ((cp = getenv("boot.netif.mtu")) != NULL) { 437 ir.ifr_mtu = strtol(cp, NULL, 10); 438 bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ); 439 freeenv(cp); 440 error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td); 441 if (error) 442 printf("nfs_mountroot: SIOCSIFMTU: %d", error); 443 } 444 soclose(so); 445 446 /* 447 * If the gateway field is filled in, set it as the default route. 448 * Note that pxeboot will set a default route of 0 if the route 449 * is not set by the DHCP server. Check also for a value of 0 450 * to avoid panicking inappropriately in that situation. 451 */ 452 if (nd->mygateway.sin_len != 0 && 453 nd->mygateway.sin_addr.s_addr != 0) { 454 struct sockaddr_in mask, sin; 455 456 bzero((caddr_t)&mask, sizeof(mask)); 457 sin = mask; 458 sin.sin_family = AF_INET; 459 sin.sin_len = sizeof(sin); 460 /* XXX MRT use table 0 for this sort of thing */ 461 CURVNET_SET(TD_TO_VNET(td)); 462 error = rtrequest(RTM_ADD, (struct sockaddr *)&sin, 463 (struct sockaddr *)&nd->mygateway, 464 (struct sockaddr *)&mask, 465 RTF_UP | RTF_GATEWAY, NULL); 466 CURVNET_RESTORE(); 467 if (error) 468 panic("nfs_mountroot: RTM_ADD: %d", error); 469 } 470 471 /* 472 * Create the rootfs mount point. 473 */ 474 nd->root_args.fh = nd->root_fh; 475 nd->root_args.fhsize = nd->root_fhsize; 476 l = ntohl(nd->root_saddr.sin_addr.s_addr); 477 snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s", 478 (l >> 24) & 0xff, (l >> 16) & 0xff, 479 (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam); 480 printf("NFS ROOT: %s\n", buf); 481 nd->root_args.hostname = buf; 482 if ((error = nfs_mountdiskless(buf, 483 &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) { 484 return (error); 485 } 486 487 /* 488 * This is not really an nfs issue, but it is much easier to 489 * set hostname here and then let the "/etc/rc.xxx" files 490 * mount the right /var based upon its preset value. 491 */ 492 mtx_lock(&prison0.pr_mtx); 493 strlcpy(prison0.pr_hostname, nd->my_hostnam, 494 sizeof(prison0.pr_hostname)); 495 mtx_unlock(&prison0.pr_mtx); 496 inittodr(ntohl(nd->root_time)); 497 return (0); 498} 499 500/* 501 * Internal version of mount system call for diskless setup. 502 */ 503static int 504nfs_mountdiskless(char *path, 505 struct sockaddr_in *sin, struct nfs_args *args, struct thread *td, 506 struct vnode **vpp, struct mount *mp) 507{ 508 struct sockaddr *nam; 509 int dirlen, error; 510 char *dirpath; 511 512 /* 513 * Find the directory path in "path", which also has the server's 514 * name/ip address in it. 515 */ 516 dirpath = strchr(path, ':'); 517 if (dirpath != NULL) 518 dirlen = strlen(++dirpath); 519 else 520 dirlen = 0; 521 nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK); 522 if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen, 523 NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NEGNAMETIMEO)) != 0) { 524 printf("nfs_mountroot: mount %s on /: %d\n", path, error); 525 return (error); 526 } 527 return (0); 528} 529 530static void 531nfs_sec_name(char *sec, int *flagsp) 532{ 533 if (!strcmp(sec, "krb5")) 534 *flagsp |= NFSMNT_KERB; 535 else if (!strcmp(sec, "krb5i")) 536 *flagsp |= (NFSMNT_KERB | NFSMNT_INTEGRITY); 537 else if (!strcmp(sec, "krb5p")) 538 *flagsp |= (NFSMNT_KERB | NFSMNT_PRIVACY); 539} 540 541static void 542nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, 543 const char *hostname, struct ucred *cred, struct thread *td) 544{ 545 int s; 546 int adjsock; 547 char *p; 548 549 s = splnet(); 550 551 /* 552 * Set read-only flag if requested; otherwise, clear it if this is 553 * an update. If this is not an update, then either the read-only 554 * flag is already clear, or this is a root mount and it was set 555 * intentionally at some previous point. 556 */ 557 if (vfs_getopt(mp->mnt_optnew, "ro", NULL, NULL) == 0) { 558 MNT_ILOCK(mp); 559 mp->mnt_flag |= MNT_RDONLY; 560 MNT_IUNLOCK(mp); 561 } else if (mp->mnt_flag & MNT_UPDATE) { 562 MNT_ILOCK(mp); 563 mp->mnt_flag &= ~MNT_RDONLY; 564 MNT_IUNLOCK(mp); 565 } 566 567 /* 568 * Silently clear NFSMNT_NOCONN if it's a TCP mount, it makes 569 * no sense in that context. Also, set up appropriate retransmit 570 * and soft timeout behavior. 571 */ 572 if (argp->sotype == SOCK_STREAM) { 573 nmp->nm_flag &= ~NFSMNT_NOCONN; 574 nmp->nm_timeo = NFS_MAXTIMEO; 575 if ((argp->flags & NFSMNT_NFSV4) != 0) 576 nmp->nm_retry = INT_MAX; 577 else 578 nmp->nm_retry = NFS_RETRANS_TCP; 579 } 580 581 /* Also clear RDIRPLUS if NFSv2, it crashes some servers */ 582 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 583 argp->flags &= ~NFSMNT_RDIRPLUS; 584 nmp->nm_flag &= ~NFSMNT_RDIRPLUS; 585 } 586 587 /* Clear NFSMNT_RESVPORT for NFSv4, since it is not required. */ 588 if ((argp->flags & NFSMNT_NFSV4) != 0) { 589 argp->flags &= ~NFSMNT_RESVPORT; 590 nmp->nm_flag &= ~NFSMNT_RESVPORT; 591 } 592 593 /* Re-bind if rsrvd port requested and wasn't on one */ 594 adjsock = !(nmp->nm_flag & NFSMNT_RESVPORT) 595 && (argp->flags & NFSMNT_RESVPORT); 596 /* Also re-bind if we're switching to/from a connected UDP socket */ 597 adjsock |= ((nmp->nm_flag & NFSMNT_NOCONN) != 598 (argp->flags & NFSMNT_NOCONN)); 599 600 /* Update flags atomically. Don't change the lock bits. */ 601 nmp->nm_flag = argp->flags | nmp->nm_flag; 602 splx(s); 603 604 if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) { 605 nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10; 606 if (nmp->nm_timeo < NFS_MINTIMEO) 607 nmp->nm_timeo = NFS_MINTIMEO; 608 else if (nmp->nm_timeo > NFS_MAXTIMEO) 609 nmp->nm_timeo = NFS_MAXTIMEO; 610 } 611 612 if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) { 613 nmp->nm_retry = argp->retrans; 614 if (nmp->nm_retry > NFS_MAXREXMIT) 615 nmp->nm_retry = NFS_MAXREXMIT; 616 } 617 618 if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) { 619 nmp->nm_wsize = argp->wsize; 620 /* Round down to multiple of blocksize */ 621 nmp->nm_wsize &= ~(NFS_FABLKSIZE - 1); 622 if (nmp->nm_wsize <= 0) 623 nmp->nm_wsize = NFS_FABLKSIZE; 624 } 625 626 if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) { 627 nmp->nm_rsize = argp->rsize; 628 /* Round down to multiple of blocksize */ 629 nmp->nm_rsize &= ~(NFS_FABLKSIZE - 1); 630 if (nmp->nm_rsize <= 0) 631 nmp->nm_rsize = NFS_FABLKSIZE; 632 } 633 634 if ((argp->flags & NFSMNT_READDIRSIZE) && argp->readdirsize > 0) { 635 nmp->nm_readdirsize = argp->readdirsize; 636 } 637 638 if ((argp->flags & NFSMNT_ACREGMIN) && argp->acregmin >= 0) 639 nmp->nm_acregmin = argp->acregmin; 640 else 641 nmp->nm_acregmin = NFS_MINATTRTIMO; 642 if ((argp->flags & NFSMNT_ACREGMAX) && argp->acregmax >= 0) 643 nmp->nm_acregmax = argp->acregmax; 644 else 645 nmp->nm_acregmax = NFS_MAXATTRTIMO; 646 if ((argp->flags & NFSMNT_ACDIRMIN) && argp->acdirmin >= 0) 647 nmp->nm_acdirmin = argp->acdirmin; 648 else 649 nmp->nm_acdirmin = NFS_MINDIRATTRTIMO; 650 if ((argp->flags & NFSMNT_ACDIRMAX) && argp->acdirmax >= 0) 651 nmp->nm_acdirmax = argp->acdirmax; 652 else 653 nmp->nm_acdirmax = NFS_MAXDIRATTRTIMO; 654 if (nmp->nm_acdirmin > nmp->nm_acdirmax) 655 nmp->nm_acdirmin = nmp->nm_acdirmax; 656 if (nmp->nm_acregmin > nmp->nm_acregmax) 657 nmp->nm_acregmin = nmp->nm_acregmax; 658 659 if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0) { 660 if (argp->readahead <= NFS_MAXRAHEAD) 661 nmp->nm_readahead = argp->readahead; 662 else 663 nmp->nm_readahead = NFS_MAXRAHEAD; 664 } 665 if ((argp->flags & NFSMNT_WCOMMITSIZE) && argp->wcommitsize >= 0) { 666 if (argp->wcommitsize < nmp->nm_wsize) 667 nmp->nm_wcommitsize = nmp->nm_wsize; 668 else 669 nmp->nm_wcommitsize = argp->wcommitsize; 670 } 671 672 adjsock |= ((nmp->nm_sotype != argp->sotype) || 673 (nmp->nm_soproto != argp->proto)); 674 675 if (nmp->nm_client != NULL && adjsock) { 676 int haslock = 0, error = 0; 677 678 if (nmp->nm_sotype == SOCK_STREAM) { 679 error = newnfs_sndlock(&nmp->nm_sockreq.nr_lock); 680 if (!error) 681 haslock = 1; 682 } 683 if (!error) { 684 newnfs_disconnect(&nmp->nm_sockreq); 685 if (haslock) 686 newnfs_sndunlock(&nmp->nm_sockreq.nr_lock); 687 nmp->nm_sotype = argp->sotype; 688 nmp->nm_soproto = argp->proto; 689 if (nmp->nm_sotype == SOCK_DGRAM) 690 while (newnfs_connect(nmp, &nmp->nm_sockreq, 691 cred, td, 0)) { 692 printf("newnfs_args: retrying connect\n"); 693 (void) nfs_catnap(PSOCK, 0, "newnfscon"); 694 } 695 } 696 } else { 697 nmp->nm_sotype = argp->sotype; 698 nmp->nm_soproto = argp->proto; 699 } 700 701 if (hostname != NULL) { 702 strlcpy(nmp->nm_hostname, hostname, 703 sizeof(nmp->nm_hostname)); 704 p = strchr(nmp->nm_hostname, ':'); 705 if (p != NULL) 706 *p = '\0'; 707 } 708} 709 710static const char *nfs_opts[] = { "from", "nfs_args", 711 "noatime", "noexec", "suiddir", "nosuid", "nosymfollow", "union", 712 "noclusterr", "noclusterw", "multilabel", "acls", "force", "update", 713 "async", "noconn", "nolockd", "conn", "lockd", "intr", "rdirplus", 714 "readdirsize", "soft", "hard", "mntudp", "tcp", "udp", "wsize", "rsize", 715 "retrans", "acregmin", "acregmax", "acdirmin", "acdirmax", "resvport", 716 "readahead", "hostname", "timeout", "addr", "fh", "nfsv3", "sec", 717 "principal", "nfsv4", "gssname", "allgssname", "dirpath", 718 "negnametimeo", "nocto", 719 NULL }; 720 721/* 722 * VFS Operations. 723 * 724 * mount system call 725 * It seems a bit dumb to copyinstr() the host and path here and then 726 * bcopy() them in mountnfs(), but I wanted to detect errors before 727 * doing the sockargs() call because sockargs() allocates an mbuf and 728 * an error after that means that I have to release the mbuf. 729 */ 730/* ARGSUSED */ 731static int 732nfs_mount(struct mount *mp) 733{ 734 struct nfs_args args = { 735 .version = NFS_ARGSVERSION, 736 .addr = NULL, 737 .addrlen = sizeof (struct sockaddr_in), 738 .sotype = SOCK_STREAM, 739 .proto = 0, 740 .fh = NULL, 741 .fhsize = 0, 742 .flags = NFSMNT_RESVPORT, 743 .wsize = NFS_WSIZE, 744 .rsize = NFS_RSIZE, 745 .readdirsize = NFS_READDIRSIZE, 746 .timeo = 10, 747 .retrans = NFS_RETRANS, 748 .readahead = NFS_DEFRAHEAD, 749 .wcommitsize = 0, /* was: NQ_DEFLEASE */ 750 .hostname = NULL, 751 .acregmin = NFS_MINATTRTIMO, 752 .acregmax = NFS_MAXATTRTIMO, 753 .acdirmin = NFS_MINDIRATTRTIMO, 754 .acdirmax = NFS_MAXDIRATTRTIMO, 755 }; 756 int error = 0, ret, len; 757 struct sockaddr *nam = NULL; 758 struct vnode *vp; 759 struct thread *td; 760 char hst[MNAMELEN]; 761 u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100]; 762 char *opt, *name, *secname; 763 int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO; 764 int dirlen, has_nfs_args_opt, krbnamelen, srvkrbnamelen; 765 size_t hstlen; 766 767 has_nfs_args_opt = 0; 768 if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) { 769 error = EINVAL; 770 goto out; 771 } 772 773 td = curthread; 774 if ((mp->mnt_flag & (MNT_ROOTFS | MNT_UPDATE)) == MNT_ROOTFS) { 775 error = nfs_mountroot(mp); 776 goto out; 777 } 778 779 nfscl_init(); 780 781 /* 782 * The old mount_nfs program passed the struct nfs_args 783 * from userspace to kernel. The new mount_nfs program 784 * passes string options via nmount() from userspace to kernel 785 * and we populate the struct nfs_args in the kernel. 786 */ 787 if (vfs_getopt(mp->mnt_optnew, "nfs_args", NULL, NULL) == 0) { 788 error = vfs_copyopt(mp->mnt_optnew, "nfs_args", &args, 789 sizeof(args)); 790 if (error != 0) 791 goto out; 792 793 if (args.version != NFS_ARGSVERSION) { 794 error = EPROGMISMATCH; 795 goto out; 796 } 797 has_nfs_args_opt = 1; 798 } 799 800 /* Handle the new style options. */ 801 if (vfs_getopt(mp->mnt_optnew, "noconn", NULL, NULL) == 0) 802 args.flags |= NFSMNT_NOCONN; 803 if (vfs_getopt(mp->mnt_optnew, "conn", NULL, NULL) == 0) 804 args.flags |= NFSMNT_NOCONN; 805 if (vfs_getopt(mp->mnt_optnew, "nolockd", NULL, NULL) == 0) 806 args.flags |= NFSMNT_NOLOCKD; 807 if (vfs_getopt(mp->mnt_optnew, "lockd", NULL, NULL) == 0) 808 args.flags &= ~NFSMNT_NOLOCKD; 809 if (vfs_getopt(mp->mnt_optnew, "intr", NULL, NULL) == 0) 810 args.flags |= NFSMNT_INT; 811 if (vfs_getopt(mp->mnt_optnew, "rdirplus", NULL, NULL) == 0) 812 args.flags |= NFSMNT_RDIRPLUS; 813 if (vfs_getopt(mp->mnt_optnew, "resvport", NULL, NULL) == 0) 814 args.flags |= NFSMNT_RESVPORT; 815 if (vfs_getopt(mp->mnt_optnew, "noresvport", NULL, NULL) == 0) 816 args.flags &= ~NFSMNT_RESVPORT; 817 if (vfs_getopt(mp->mnt_optnew, "soft", NULL, NULL) == 0) 818 args.flags |= NFSMNT_SOFT; 819 if (vfs_getopt(mp->mnt_optnew, "hard", NULL, NULL) == 0) 820 args.flags &= ~NFSMNT_SOFT; 821 if (vfs_getopt(mp->mnt_optnew, "mntudp", NULL, NULL) == 0) 822 args.sotype = SOCK_DGRAM; 823 if (vfs_getopt(mp->mnt_optnew, "udp", NULL, NULL) == 0) 824 args.sotype = SOCK_DGRAM; 825 if (vfs_getopt(mp->mnt_optnew, "tcp", NULL, NULL) == 0) 826 args.sotype = SOCK_STREAM; 827 if (vfs_getopt(mp->mnt_optnew, "nfsv3", NULL, NULL) == 0) 828 args.flags |= NFSMNT_NFSV3; 829 if (vfs_getopt(mp->mnt_optnew, "nfsv4", NULL, NULL) == 0) { 830 args.flags |= NFSMNT_NFSV4; 831 args.sotype = SOCK_STREAM; 832 } 833 if (vfs_getopt(mp->mnt_optnew, "allgssname", NULL, NULL) == 0) 834 args.flags |= NFSMNT_ALLGSSNAME; 835 if (vfs_getopt(mp->mnt_optnew, "nocto", NULL, NULL) == 0) 836 args.flags |= NFSMNT_NOCTO; 837 if (vfs_getopt(mp->mnt_optnew, "readdirsize", (void **)&opt, NULL) == 0) { 838 if (opt == NULL) { 839 vfs_mount_error(mp, "illegal readdirsize"); 840 error = EINVAL; 841 goto out; 842 } 843 ret = sscanf(opt, "%d", &args.readdirsize); 844 if (ret != 1 || args.readdirsize <= 0) { 845 vfs_mount_error(mp, "illegal readdirsize: %s", 846 opt); 847 error = EINVAL; 848 goto out; 849 } 850 args.flags |= NFSMNT_READDIRSIZE; 851 } 852 if (vfs_getopt(mp->mnt_optnew, "readahead", (void **)&opt, NULL) == 0) { 853 if (opt == NULL) { 854 vfs_mount_error(mp, "illegal readahead"); 855 error = EINVAL; 856 goto out; 857 } 858 ret = sscanf(opt, "%d", &args.readahead); 859 if (ret != 1 || args.readahead <= 0) { 860 vfs_mount_error(mp, "illegal readahead: %s", 861 opt); 862 error = EINVAL; 863 goto out; 864 } 865 args.flags |= NFSMNT_READAHEAD; 866 } 867 if (vfs_getopt(mp->mnt_optnew, "wsize", (void **)&opt, NULL) == 0) { 868 if (opt == NULL) { 869 vfs_mount_error(mp, "illegal wsize"); 870 error = EINVAL; 871 goto out; 872 } 873 ret = sscanf(opt, "%d", &args.wsize); 874 if (ret != 1 || args.wsize <= 0) { 875 vfs_mount_error(mp, "illegal wsize: %s", 876 opt); 877 error = EINVAL; 878 goto out; 879 } 880 args.flags |= NFSMNT_WSIZE; 881 } 882 if (vfs_getopt(mp->mnt_optnew, "rsize", (void **)&opt, NULL) == 0) { 883 if (opt == NULL) { 884 vfs_mount_error(mp, "illegal rsize"); 885 error = EINVAL; 886 goto out; 887 } 888 ret = sscanf(opt, "%d", &args.rsize); 889 if (ret != 1 || args.rsize <= 0) { 890 vfs_mount_error(mp, "illegal wsize: %s", 891 opt); 892 error = EINVAL; 893 goto out; 894 } 895 args.flags |= NFSMNT_RSIZE; 896 } 897 if (vfs_getopt(mp->mnt_optnew, "retrans", (void **)&opt, NULL) == 0) { 898 if (opt == NULL) { 899 vfs_mount_error(mp, "illegal retrans"); 900 error = EINVAL; 901 goto out; 902 } 903 ret = sscanf(opt, "%d", &args.retrans); 904 if (ret != 1 || args.retrans <= 0) { 905 vfs_mount_error(mp, "illegal retrans: %s", 906 opt); 907 error = EINVAL; 908 goto out; 909 } 910 args.flags |= NFSMNT_RETRANS; 911 } 912 if (vfs_getopt(mp->mnt_optnew, "acregmin", (void **)&opt, NULL) == 0) { 913 ret = sscanf(opt, "%d", &args.acregmin); 914 if (ret != 1 || args.acregmin < 0) { 915 vfs_mount_error(mp, "illegal acregmin: %s", 916 opt); 917 error = EINVAL; 918 goto out; 919 } 920 args.flags |= NFSMNT_ACREGMIN; 921 } 922 if (vfs_getopt(mp->mnt_optnew, "acregmax", (void **)&opt, NULL) == 0) { 923 ret = sscanf(opt, "%d", &args.acregmax); 924 if (ret != 1 || args.acregmax < 0) { 925 vfs_mount_error(mp, "illegal acregmax: %s", 926 opt); 927 error = EINVAL; 928 goto out; 929 } 930 args.flags |= NFSMNT_ACREGMAX; 931 } 932 if (vfs_getopt(mp->mnt_optnew, "acdirmin", (void **)&opt, NULL) == 0) { 933 ret = sscanf(opt, "%d", &args.acdirmin); 934 if (ret != 1 || args.acdirmin < 0) { 935 vfs_mount_error(mp, "illegal acdirmin: %s", 936 opt); 937 error = EINVAL; 938 goto out; 939 } 940 args.flags |= NFSMNT_ACDIRMIN; 941 } 942 if (vfs_getopt(mp->mnt_optnew, "acdirmax", (void **)&opt, NULL) == 0) { 943 ret = sscanf(opt, "%d", &args.acdirmax); 944 if (ret != 1 || args.acdirmax < 0) { 945 vfs_mount_error(mp, "illegal acdirmax: %s", 946 opt); 947 error = EINVAL; 948 goto out; 949 } 950 args.flags |= NFSMNT_ACDIRMAX; 951 } 952 if (vfs_getopt(mp->mnt_optnew, "timeout", (void **)&opt, NULL) == 0) { 953 ret = sscanf(opt, "%d", &args.timeo); 954 if (ret != 1 || args.timeo <= 0) { 955 vfs_mount_error(mp, "illegal timeout: %s", 956 opt); 957 error = EINVAL; 958 goto out; 959 } 960 args.flags |= NFSMNT_TIMEO; 961 } 962 if (vfs_getopt(mp->mnt_optnew, "negnametimeo", (void **)&opt, NULL) 963 == 0) { 964 ret = sscanf(opt, "%d", &negnametimeo); 965 if (ret != 1 || negnametimeo < 0) { 966 vfs_mount_error(mp, "illegal negnametimeo: %s", 967 opt); 968 error = EINVAL; 969 goto out; 970 } 971 } 972 if (vfs_getopt(mp->mnt_optnew, "sec", 973 (void **) &secname, NULL) == 0) 974 nfs_sec_name(secname, &args.flags); 975 976 if (mp->mnt_flag & MNT_UPDATE) { 977 struct nfsmount *nmp = VFSTONFS(mp); 978 979 if (nmp == NULL) { 980 error = EIO; 981 goto out; 982 } 983 /* 984 * When doing an update, we can't change version, 985 * security, switch lockd strategies or change cookie 986 * translation 987 */ 988 args.flags = (args.flags & 989 ~(NFSMNT_NFSV3 | 990 NFSMNT_NFSV4 | 991 NFSMNT_KERB | 992 NFSMNT_INTEGRITY | 993 NFSMNT_PRIVACY | 994 NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)) | 995 (nmp->nm_flag & 996 (NFSMNT_NFSV3 | 997 NFSMNT_NFSV4 | 998 NFSMNT_KERB | 999 NFSMNT_INTEGRITY | 1000 NFSMNT_PRIVACY | 1001 NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); 1002 nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td); 1003 goto out; 1004 } 1005 1006 /* 1007 * Make the nfs_ip_paranoia sysctl serve as the default connection 1008 * or no-connection mode for those protocols that support 1009 * no-connection mode (the flag will be cleared later for protocols 1010 * that do not support no-connection mode). This will allow a client 1011 * to receive replies from a different IP then the request was 1012 * sent to. Note: default value for nfs_ip_paranoia is 1 (paranoid), 1013 * not 0. 1014 */ 1015 if (nfs_ip_paranoia == 0) 1016 args.flags |= NFSMNT_NOCONN; 1017 1018 if (has_nfs_args_opt != 0) { 1019 /* 1020 * In the 'nfs_args' case, the pointers in the args 1021 * structure are in userland - we copy them in here. 1022 */ 1023 if (args.fhsize < 0 || args.fhsize > NFSX_V3FHMAX) { 1024 vfs_mount_error(mp, "Bad file handle"); 1025 error = EINVAL; 1026 goto out; 1027 } 1028 error = copyin((caddr_t)args.fh, (caddr_t)nfh, 1029 args.fhsize); 1030 if (error != 0) 1031 goto out; 1032 error = copyinstr(args.hostname, hst, MNAMELEN - 1, &hstlen); 1033 if (error != 0) 1034 goto out; 1035 bzero(&hst[hstlen], MNAMELEN - hstlen); 1036 args.hostname = hst; 1037 /* sockargs() call must be after above copyin() calls */ 1038 error = getsockaddr(&nam, (caddr_t)args.addr, 1039 args.addrlen); 1040 if (error != 0) 1041 goto out; 1042 } else { 1043 if (vfs_getopt(mp->mnt_optnew, "fh", (void **)&args.fh, 1044 &args.fhsize) == 0) { 1045 if (args.fhsize < 0 || args.fhsize > NFSX_FHMAX) { 1046 vfs_mount_error(mp, "Bad file handle"); 1047 error = EINVAL; 1048 goto out; 1049 } 1050 bcopy(args.fh, nfh, args.fhsize); 1051 } else { 1052 args.fhsize = 0; 1053 } 1054 (void) vfs_getopt(mp->mnt_optnew, "hostname", 1055 (void **)&args.hostname, &len); 1056 if (args.hostname == NULL) { 1057 vfs_mount_error(mp, "Invalid hostname"); 1058 error = EINVAL; 1059 goto out; 1060 } 1061 bcopy(args.hostname, hst, MNAMELEN); 1062 hst[MNAMELEN - 1] = '\0'; 1063 } 1064 1065 if (vfs_getopt(mp->mnt_optnew, "principal", (void **)&name, NULL) == 0) 1066 strlcpy(srvkrbname, name, sizeof (srvkrbname)); 1067 else 1068 snprintf(srvkrbname, sizeof (srvkrbname), "nfs@%s", hst); 1069 srvkrbnamelen = strlen(srvkrbname); 1070 1071 if (vfs_getopt(mp->mnt_optnew, "gssname", (void **)&name, NULL) == 0) 1072 strlcpy(krbname, name, sizeof (krbname)); 1073 else 1074 krbname[0] = '\0'; 1075 krbnamelen = strlen(krbname); 1076 1077 if (vfs_getopt(mp->mnt_optnew, "dirpath", (void **)&name, NULL) == 0) 1078 strlcpy(dirpath, name, sizeof (dirpath)); 1079 else 1080 dirpath[0] = '\0'; 1081 dirlen = strlen(dirpath); 1082 1083 if (has_nfs_args_opt == 0) { 1084 if (vfs_getopt(mp->mnt_optnew, "addr", 1085 (void **)&args.addr, &args.addrlen) == 0) { 1086 if (args.addrlen > SOCK_MAXADDRLEN) { 1087 error = ENAMETOOLONG; 1088 goto out; 1089 } 1090 nam = malloc(args.addrlen, M_SONAME, M_WAITOK); 1091 bcopy(args.addr, nam, args.addrlen); 1092 nam->sa_len = args.addrlen; 1093 } else { 1094 vfs_mount_error(mp, "No server address"); 1095 error = EINVAL; 1096 goto out; 1097 } 1098 } 1099 1100 args.fh = nfh; 1101 error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath, 1102 dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td, 1103 negnametimeo); 1104out: 1105 if (!error) { 1106 MNT_ILOCK(mp); 1107 mp->mnt_kern_flag |= (MNTK_MPSAFE|MNTK_LOOKUP_SHARED); 1108 MNT_IUNLOCK(mp); 1109 } 1110 return (error); 1111} 1112 1113 1114/* 1115 * VFS Operations. 1116 * 1117 * mount system call 1118 * It seems a bit dumb to copyinstr() the host and path here and then 1119 * bcopy() them in mountnfs(), but I wanted to detect errors before 1120 * doing the sockargs() call because sockargs() allocates an mbuf and 1121 * an error after that means that I have to release the mbuf. 1122 */ 1123/* ARGSUSED */ 1124static int 1125nfs_cmount(struct mntarg *ma, void *data, int flags) 1126{ 1127 int error; 1128 struct nfs_args args; 1129 1130 error = copyin(data, &args, sizeof (struct nfs_args)); 1131 if (error) 1132 return error; 1133 1134 ma = mount_arg(ma, "nfs_args", &args, sizeof args); 1135 1136 error = kernel_mount(ma, flags); 1137 return (error); 1138} 1139 1140/* 1141 * Common code for mount and mountroot 1142 */ 1143static int 1144mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, 1145 char *hst, u_char *krbname, int krbnamelen, u_char *dirpath, int dirlen, 1146 u_char *srvkrbname, int srvkrbnamelen, struct vnode **vpp, 1147 struct ucred *cred, struct thread *td, int negnametimeo) 1148{ 1149 struct nfsmount *nmp; 1150 struct nfsnode *np; 1151 int error, trycnt, ret; 1152 struct nfsvattr nfsva; 1153 static u_int64_t clval = 0; 1154 1155 if (mp->mnt_flag & MNT_UPDATE) { 1156 nmp = VFSTONFS(mp); 1157 printf("%s: MNT_UPDATE is no longer handled here\n", __func__); 1158 FREE(nam, M_SONAME); 1159 return (0); 1160 } else { 1161 MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount) + 1162 krbnamelen + dirlen + srvkrbnamelen + 2, 1163 M_NEWNFSMNT, M_WAITOK | M_ZERO); 1164 TAILQ_INIT(&nmp->nm_bufq); 1165 if (clval == 0) 1166 clval = (u_int64_t)nfsboottime.tv_sec; 1167 nmp->nm_clval = clval++; 1168 nmp->nm_krbnamelen = krbnamelen; 1169 nmp->nm_dirpathlen = dirlen; 1170 nmp->nm_srvkrbnamelen = srvkrbnamelen; 1171 if (td->td_ucred->cr_uid != (uid_t)0) { 1172 /* 1173 * nm_uid is used to get KerberosV credentials for 1174 * the nfsv4 state handling operations if there is 1175 * no host based principal set. Use the uid of 1176 * this user if not root, since they are doing the 1177 * mount. I don't think setting this for root will 1178 * work, since root normally does not have user 1179 * credentials in a credentials cache. 1180 */ 1181 nmp->nm_uid = td->td_ucred->cr_uid; 1182 } else { 1183 /* 1184 * Just set to -1, so it won't be used. 1185 */ 1186 nmp->nm_uid = (uid_t)-1; 1187 } 1188 1189 /* Copy and null terminate all the names */ 1190 if (nmp->nm_krbnamelen > 0) { 1191 bcopy(krbname, nmp->nm_krbname, nmp->nm_krbnamelen); 1192 nmp->nm_name[nmp->nm_krbnamelen] = '\0'; 1193 } 1194 if (nmp->nm_dirpathlen > 0) { 1195 bcopy(dirpath, NFSMNT_DIRPATH(nmp), 1196 nmp->nm_dirpathlen); 1197 nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1198 + 1] = '\0'; 1199 } 1200 if (nmp->nm_srvkrbnamelen > 0) { 1201 bcopy(srvkrbname, NFSMNT_SRVKRBNAME(nmp), 1202 nmp->nm_srvkrbnamelen); 1203 nmp->nm_name[nmp->nm_krbnamelen + nmp->nm_dirpathlen 1204 + nmp->nm_srvkrbnamelen + 2] = '\0'; 1205 } 1206 nmp->nm_sockreq.nr_cred = crhold(cred); 1207 mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF); 1208 mp->mnt_data = nmp; 1209 nmp->nm_getinfo = nfs_getnlminfo; 1210 nmp->nm_vinvalbuf = ncl_vinvalbuf; 1211 } 1212 vfs_getnewfsid(mp); 1213 nmp->nm_mountp = mp; 1214 mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK); 1215 1216 /* 1217 * Since nfs_decode_args() might optionally set them, these need to 1218 * set to defaults before the call, so that the optional settings 1219 * aren't overwritten. 1220 */ 1221 nmp->nm_negnametimeo = negnametimeo; 1222 nmp->nm_timeo = NFS_TIMEO; 1223 nmp->nm_retry = NFS_RETRANS; 1224 nmp->nm_readahead = NFS_DEFRAHEAD; 1225 if (desiredvnodes >= 11000) 1226 nmp->nm_wcommitsize = hibufspace / (desiredvnodes / 1000); 1227 else 1228 nmp->nm_wcommitsize = hibufspace / 10; 1229 1230 nfs_decode_args(mp, nmp, argp, hst, cred, td); 1231 1232 /* 1233 * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too 1234 * high, depending on whether we end up with negative offsets in 1235 * the client or server somewhere. 2GB-1 may be safer. 1236 * 1237 * For V3, ncl_fsinfo will adjust this as necessary. Assume maximum 1238 * that we can handle until we find out otherwise. 1239 * XXX Our "safe" limit on the client is what we can store in our 1240 * buffer cache using signed(!) block numbers. 1241 */ 1242 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) 1243 nmp->nm_maxfilesize = 0xffffffffLL; 1244 else 1245 nmp->nm_maxfilesize = OFF_MAX; 1246 1247 if ((argp->flags & (NFSMNT_NFSV3 | NFSMNT_NFSV4)) == 0) { 1248 nmp->nm_wsize = NFS_WSIZE; 1249 nmp->nm_rsize = NFS_RSIZE; 1250 nmp->nm_readdirsize = NFS_READDIRSIZE; 1251 } 1252 nmp->nm_numgrps = NFS_MAXGRPS; 1253 nmp->nm_tprintf_delay = nfs_tprintf_delay; 1254 if (nmp->nm_tprintf_delay < 0) 1255 nmp->nm_tprintf_delay = 0; 1256 nmp->nm_tprintf_initial_delay = nfs_tprintf_initial_delay; 1257 if (nmp->nm_tprintf_initial_delay < 0) 1258 nmp->nm_tprintf_initial_delay = 0; 1259 nmp->nm_fhsize = argp->fhsize; 1260 if (nmp->nm_fhsize > 0) 1261 bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize); 1262 bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN); 1263 nmp->nm_nam = nam; 1264 /* Set up the sockets and per-host congestion */ 1265 nmp->nm_sotype = argp->sotype; 1266 nmp->nm_soproto = argp->proto; 1267 nmp->nm_sockreq.nr_prog = NFS_PROG; 1268 if ((argp->flags & NFSMNT_NFSV4)) 1269 nmp->nm_sockreq.nr_vers = NFS_VER4; 1270 else if ((argp->flags & NFSMNT_NFSV3)) 1271 nmp->nm_sockreq.nr_vers = NFS_VER3; 1272 else 1273 nmp->nm_sockreq.nr_vers = NFS_VER2; 1274 1275 1276 if ((error = newnfs_connect(nmp, &nmp->nm_sockreq, cred, td, 0))) 1277 goto bad; 1278 1279 /* 1280 * A reference count is needed on the nfsnode representing the 1281 * remote root. If this object is not persistent, then backward 1282 * traversals of the mount point (i.e. "..") will not work if 1283 * the nfsnode gets flushed out of the cache. Ufs does not have 1284 * this problem, because one can identify root inodes by their 1285 * number == ROOTINO (2). 1286 */ 1287 if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) && 1288 nmp->nm_dirpathlen > 0) { 1289 /* 1290 * If the fhsize on the mount point == 0 for V4, the mount 1291 * path needs to be looked up. 1292 */ 1293 trycnt = 3; 1294 do { 1295 error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 1296 cred, td); 1297 if (error) 1298 (void) nfs_catnap(PZERO, error, "nfsgetdirp"); 1299 } while (error && --trycnt > 0); 1300 if (error) { 1301 error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0); 1302 goto bad; 1303 } 1304 } 1305 if (nmp->nm_fhsize > 0) { 1306 /* 1307 * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set 1308 * non-zero for the root vnode. f_iosize will be set correctly 1309 * by nfs_statfs() before any I/O occurs. 1310 */ 1311 mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ; 1312 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, 1313 LK_EXCLUSIVE); 1314 if (error) 1315 goto bad; 1316 *vpp = NFSTOV(np); 1317 1318 /* 1319 * Get file attributes and transfer parameters for the 1320 * mountpoint. This has the side effect of filling in 1321 * (*vpp)->v_type with the correct value. 1322 */ 1323 ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, 1324 cred, td, &nfsva, NULL); 1325 if (ret) { 1326 /* 1327 * Just set default values to get things going. 1328 */ 1329 NFSBZERO((caddr_t)&nfsva, sizeof (struct nfsvattr)); 1330 nfsva.na_vattr.va_type = VDIR; 1331 nfsva.na_vattr.va_mode = 0777; 1332 nfsva.na_vattr.va_nlink = 100; 1333 nfsva.na_vattr.va_uid = (uid_t)0; 1334 nfsva.na_vattr.va_gid = (gid_t)0; 1335 nfsva.na_vattr.va_fileid = 2; 1336 nfsva.na_vattr.va_gen = 1; 1337 nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; 1338 nfsva.na_vattr.va_size = 512 * 1024; 1339 } 1340 (void) nfscl_loadattrcache(vpp, &nfsva, NULL, NULL, 0, 1); 1341 if (argp->flags & NFSMNT_NFSV3) 1342 ncl_fsinfo(nmp, *vpp, cred, td); 1343 1344 /* Mark if the mount point supports NFSv4 ACLs. */ 1345 if ((argp->flags & NFSMNT_NFSV4) != 0 && nfsrv_useacl != 0 && 1346 ret == 0 && 1347 NFSISSET_ATTRBIT(&nfsva.na_suppattr, NFSATTRBIT_ACL)) { 1348 MNT_ILOCK(mp); 1349 mp->mnt_flag |= MNT_NFS4ACLS; 1350 MNT_IUNLOCK(mp); 1351 } 1352 1353 /* 1354 * Lose the lock but keep the ref. 1355 */ 1356 NFSVOPUNLOCK(*vpp, 0); 1357 return (0); 1358 } 1359 error = EIO; 1360 1361bad: 1362 newnfs_disconnect(&nmp->nm_sockreq); 1363 crfree(nmp->nm_sockreq.nr_cred); 1364 mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1365 mtx_destroy(&nmp->nm_mtx); 1366 FREE(nmp, M_NEWNFSMNT); 1367 FREE(nam, M_SONAME); 1368 return (error); 1369} 1370 1371/* 1372 * unmount system call 1373 */ 1374static int 1375nfs_unmount(struct mount *mp, int mntflags) 1376{ 1377 struct thread *td; 1378 struct nfsmount *nmp; 1379 int error, flags = 0, trycnt = 0; 1380 1381 td = curthread; 1382 1383 if (mntflags & MNT_FORCE) 1384 flags |= FORCECLOSE; 1385 nmp = VFSTONFS(mp); 1386 /* 1387 * Goes something like this.. 1388 * - Call vflush() to clear out vnodes for this filesystem 1389 * - Close the socket 1390 * - Free up the data structures 1391 */ 1392 /* In the forced case, cancel any outstanding requests. */ 1393 if (mntflags & MNT_FORCE) { 1394 error = newnfs_nmcancelreqs(nmp); 1395 if (error) 1396 goto out; 1397 /* For a forced close, get rid of the renew thread now */ 1398 nfscl_umount(nmp, td); 1399 } 1400 /* We hold 1 extra ref on the root vnode; see comment in mountnfs(). */ 1401 do { 1402 error = vflush(mp, 1, flags, td); 1403 if ((mntflags & MNT_FORCE) && error != 0 && ++trycnt < 30) 1404 (void) nfs_catnap(PSOCK, error, "newndm"); 1405 } while ((mntflags & MNT_FORCE) && error != 0 && trycnt < 30); 1406 if (error) 1407 goto out; 1408 1409 /* 1410 * We are now committed to the unmount. 1411 */ 1412 if ((mntflags & MNT_FORCE) == 0) 1413 nfscl_umount(nmp, td); 1414 newnfs_disconnect(&nmp->nm_sockreq); 1415 crfree(nmp->nm_sockreq.nr_cred); 1416 FREE(nmp->nm_nam, M_SONAME); 1417 1418 mtx_destroy(&nmp->nm_sockreq.nr_mtx); 1419 mtx_destroy(&nmp->nm_mtx); 1420 FREE(nmp, M_NEWNFSMNT); 1421out: 1422 return (error); 1423} 1424 1425/* 1426 * Return root of a filesystem 1427 */ 1428static int 1429nfs_root(struct mount *mp, int flags, struct vnode **vpp) 1430{ 1431 struct vnode *vp; 1432 struct nfsmount *nmp; 1433 struct nfsnode *np; 1434 int error; 1435 1436 nmp = VFSTONFS(mp); 1437 error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags); 1438 if (error) 1439 return error; 1440 vp = NFSTOV(np); 1441 /* 1442 * Get transfer parameters and attributes for root vnode once. 1443 */ 1444 mtx_lock(&nmp->nm_mtx); 1445 if (NFSHASNFSV3(nmp) && !NFSHASGOTFSINFO(nmp)) { 1446 mtx_unlock(&nmp->nm_mtx); 1447 ncl_fsinfo(nmp, vp, curthread->td_ucred, curthread); 1448 } else 1449 mtx_unlock(&nmp->nm_mtx); 1450 if (vp->v_type == VNON) 1451 vp->v_type = VDIR; 1452 vp->v_vflag |= VV_ROOT; 1453 *vpp = vp; 1454 return (0); 1455} 1456 1457/* 1458 * Flush out the buffer cache 1459 */ 1460/* ARGSUSED */ 1461static int 1462nfs_sync(struct mount *mp, int waitfor) 1463{ 1464 struct vnode *vp, *mvp; 1465 struct thread *td; 1466 int error, allerror = 0; 1467 1468 td = curthread; 1469 1470 MNT_ILOCK(mp); 1471 /* 1472 * If a forced dismount is in progress, return from here so that 1473 * the umount(2) syscall doesn't get stuck in VFS_SYNC() before 1474 * calling VFS_UNMOUNT(). 1475 */ 1476 if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1477 MNT_IUNLOCK(mp); 1478 return (EBADF); 1479 } 1480 1481 /* 1482 * Force stale buffer cache information to be flushed. 1483 */ 1484loop: 1485 MNT_VNODE_FOREACH(vp, mp, mvp) { 1486 VI_LOCK(vp); 1487 MNT_IUNLOCK(mp); 1488 /* XXX Racy bv_cnt check. */ 1489 if (NFSVOPISLOCKED(vp) || vp->v_bufobj.bo_dirty.bv_cnt == 0 || 1490 waitfor == MNT_LAZY) { 1491 VI_UNLOCK(vp); 1492 MNT_ILOCK(mp); 1493 continue; 1494 } 1495 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 1496 MNT_ILOCK(mp); 1497 MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); 1498 goto loop; 1499 } 1500 error = VOP_FSYNC(vp, waitfor, td); 1501 if (error) 1502 allerror = error; 1503 NFSVOPUNLOCK(vp, 0); 1504 vrele(vp); 1505 1506 MNT_ILOCK(mp); 1507 } 1508 MNT_IUNLOCK(mp); 1509 return (allerror); 1510} 1511 1512static int 1513nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) 1514{ 1515 struct nfsmount *nmp = VFSTONFS(mp); 1516 struct vfsquery vq; 1517 int error; 1518 1519 bzero(&vq, sizeof(vq)); 1520 switch (op) { 1521#if 0 1522 case VFS_CTL_NOLOCKS: 1523 val = (nmp->nm_flag & NFSMNT_NOLOCKS) ? 1 : 0; 1524 if (req->oldptr != NULL) { 1525 error = SYSCTL_OUT(req, &val, sizeof(val)); 1526 if (error) 1527 return (error); 1528 } 1529 if (req->newptr != NULL) { 1530 error = SYSCTL_IN(req, &val, sizeof(val)); 1531 if (error) 1532 return (error); 1533 if (val) 1534 nmp->nm_flag |= NFSMNT_NOLOCKS; 1535 else 1536 nmp->nm_flag &= ~NFSMNT_NOLOCKS; 1537 } 1538 break; 1539#endif 1540 case VFS_CTL_QUERY: 1541 mtx_lock(&nmp->nm_mtx); 1542 if (nmp->nm_state & NFSSTA_TIMEO) 1543 vq.vq_flags |= VQ_NOTRESP; 1544 mtx_unlock(&nmp->nm_mtx); 1545#if 0 1546 if (!(nmp->nm_flag & NFSMNT_NOLOCKS) && 1547 (nmp->nm_state & NFSSTA_LOCKTIMEO)) 1548 vq.vq_flags |= VQ_NOTRESPLOCK; 1549#endif 1550 error = SYSCTL_OUT(req, &vq, sizeof(vq)); 1551 break; 1552 case VFS_CTL_TIMEO: 1553 if (req->oldptr != NULL) { 1554 error = SYSCTL_OUT(req, &nmp->nm_tprintf_initial_delay, 1555 sizeof(nmp->nm_tprintf_initial_delay)); 1556 if (error) 1557 return (error); 1558 } 1559 if (req->newptr != NULL) { 1560 error = vfs_suser(mp, req->td); 1561 if (error) 1562 return (error); 1563 error = SYSCTL_IN(req, &nmp->nm_tprintf_initial_delay, 1564 sizeof(nmp->nm_tprintf_initial_delay)); 1565 if (error) 1566 return (error); 1567 if (nmp->nm_tprintf_initial_delay < 0) 1568 nmp->nm_tprintf_initial_delay = 0; 1569 } 1570 break; 1571 default: 1572 return (ENOTSUP); 1573 } 1574 return (0); 1575} 1576 1577/* 1578 * Extract the information needed by the nlm from the nfs vnode. 1579 */ 1580static void 1581nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp, 1582 struct sockaddr_storage *sp, int *is_v3p, off_t *sizep, 1583 struct timeval *timeop) 1584{ 1585 struct nfsmount *nmp; 1586 struct nfsnode *np = VTONFS(vp); 1587 1588 nmp = VFSTONFS(vp->v_mount); 1589 if (fhlenp != NULL) 1590 *fhlenp = (size_t)np->n_fhp->nfh_len; 1591 if (fhp != NULL) 1592 bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len); 1593 if (sp != NULL) 1594 bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp))); 1595 if (is_v3p != NULL) 1596 *is_v3p = NFS_ISV3(vp); 1597 if (sizep != NULL) 1598 *sizep = np->n_size; 1599 if (timeop != NULL) { 1600 timeop->tv_sec = nmp->nm_timeo / NFS_HZ; 1601 timeop->tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ); 1602 } 1603} 1604 1605