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