xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 52445)
138414Smckusick /*
238414Smckusick  * Copyright (c) 1989 The Regents of the University of California.
338414Smckusick  * All rights reserved.
438414Smckusick  *
538414Smckusick  * This code is derived from software contributed to Berkeley by
638414Smckusick  * Rick Macklem at The University of Guelph.
738414Smckusick  *
844513Sbostic  * %sccs.include.redist.c%
938414Smckusick  *
10*52445Smckusick  *	@(#)nfs_vfsops.c	7.38 (Berkeley) 02/06/92
1138414Smckusick  */
1238414Smckusick 
1338414Smckusick #include "param.h"
1446988Smckusick #include "conf.h"
1546988Smckusick #include "ioctl.h"
1638414Smckusick #include "signal.h"
1738414Smckusick #include "proc.h"
1848055Smckusick #include "namei.h"
1938414Smckusick #include "vnode.h"
2052196Smckusick #include "kernel.h"
2138414Smckusick #include "mount.h"
2240120Smckusick #include "buf.h"
2338414Smckusick #include "mbuf.h"
2438414Smckusick #include "socket.h"
2540120Smckusick #include "systm.h"
2647573Skarels 
2752196Smckusick #include "net/if.h"
2852196Smckusick #include "net/route.h"
2952196Smckusick #include "netinet/in.h"
3047573Skarels 
3152196Smckusick #include "rpcv2.h"
3238414Smckusick #include "nfsv2.h"
3352196Smckusick #include "nfsnode.h"
3438414Smckusick #include "nfsmount.h"
3538414Smckusick #include "nfs.h"
3641904Smckusick #include "xdr_subs.h"
3741904Smckusick #include "nfsm_subs.h"
3846988Smckusick #include "nfsdiskless.h"
3952196Smckusick #include "nqnfs.h"
4038414Smckusick 
4138414Smckusick /*
4238414Smckusick  * nfs vfs operations.
4338414Smckusick  */
4438414Smckusick struct vfsops nfs_vfsops = {
4538414Smckusick 	nfs_mount,
4638874Smckusick 	nfs_start,
4738414Smckusick 	nfs_unmount,
4838414Smckusick 	nfs_root,
4941294Smckusick 	nfs_quotactl,
5038414Smckusick 	nfs_statfs,
5138414Smckusick 	nfs_sync,
5238414Smckusick 	nfs_fhtovp,
5338414Smckusick 	nfs_vptofh,
5439443Smckusick 	nfs_init,
5538414Smckusick };
5638414Smckusick 
5752196Smckusick /*
5852196Smckusick  * This structure must be filled in by a primary bootstrap or bootstrap
5952196Smckusick  * server for a diskless/dataless machine. It is initialized below just
6052196Smckusick  * to ensure that it is allocated to initialized data (.data not .bss).
6152196Smckusick  */
6252196Smckusick struct nfs_diskless nfs_diskless = { 0 };
6352196Smckusick 
6439757Smckusick static u_char nfs_mntid;
6541904Smckusick extern u_long nfs_procids[NFS_NPROCS];
6641904Smckusick extern u_long nfs_prog, nfs_vers;
6752196Smckusick void nfs_disconnect(), nfsargs_ntoh();
6838414Smckusick 
6941904Smckusick #define TRUE	1
7041904Smckusick #define	FALSE	0
7141904Smckusick 
7238414Smckusick /*
7341904Smckusick  * nfs statfs call
7441904Smckusick  */
7548055Smckusick nfs_statfs(mp, sbp, p)
7641904Smckusick 	struct mount *mp;
7741904Smckusick 	register struct statfs *sbp;
7848055Smckusick 	struct proc *p;
7941904Smckusick {
8041904Smckusick 	register struct vnode *vp;
8141904Smckusick 	register struct nfsv2_statfs *sfp;
8241904Smckusick 	register caddr_t cp;
8341904Smckusick 	register long t1;
8441904Smckusick 	caddr_t bpos, dpos, cp2;
8541904Smckusick 	u_long xid;
8641904Smckusick 	int error = 0;
8741904Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
8841904Smckusick 	struct nfsmount *nmp;
8941904Smckusick 	struct ucred *cred;
9041904Smckusick 	struct nfsnode *np;
9141904Smckusick 
9241904Smckusick 	nmp = VFSTONFS(mp);
9341904Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
9441904Smckusick 		return (error);
9541904Smckusick 	vp = NFSTOV(np);
9641904Smckusick 	nfsstats.rpccnt[NFSPROC_STATFS]++;
9741904Smckusick 	cred = crget();
9841904Smckusick 	cred->cr_ngroups = 1;
9952196Smckusick 	nfsm_reqhead(vp, NFSPROC_STATFS, NFSX_FH);
10041904Smckusick 	nfsm_fhtom(vp);
10152196Smckusick 	nfsm_request(vp, NFSPROC_STATFS, p, cred);
10252196Smckusick 	nfsm_dissect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
10341904Smckusick 	sbp->f_type = MOUNT_NFS;
10441904Smckusick 	sbp->f_flags = nmp->nm_flag;
10552196Smckusick 	sbp->f_iosize = NFS_MAXDGRAMDATA;
10651940Smckusick 	sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
10741904Smckusick 	sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
10841904Smckusick 	sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
10941904Smckusick 	sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
11041904Smckusick 	sbp->f_files = 0;
11141904Smckusick 	sbp->f_ffree = 0;
11241904Smckusick 	if (sbp != &mp->mnt_stat) {
11341904Smckusick 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
11441904Smckusick 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
11541904Smckusick 	}
11641904Smckusick 	nfsm_reqdone;
11752196Smckusick 	vrele(vp);
11841904Smckusick 	crfree(cred);
11941904Smckusick 	return (error);
12041904Smckusick }
12141904Smckusick 
12241904Smckusick /*
12346988Smckusick  * Mount a remote root fs via. nfs. This depends on the info in the
12446988Smckusick  * nfs_diskless structure that has been filled in properly by some primary
12546988Smckusick  * bootstrap.
12646988Smckusick  * It goes something like this:
12746988Smckusick  * - do enough of "ifconfig" by calling ifioctl() so that the system
12846988Smckusick  *   can talk to the server
12946988Smckusick  * - If nfs_diskless.mygateway is filled in, use that address as
13046988Smckusick  *   a default gateway.
13146988Smckusick  * - hand craft the swap nfs vnode hanging off a fake mount point
13252196Smckusick  *	if swdevt[0].sw_dev == NODEV
13346988Smckusick  * - build the rootfs mount point and call mountnfs() to do the rest.
13438414Smckusick  */
13538414Smckusick nfs_mountroot()
13638414Smckusick {
13746988Smckusick 	register struct mount *mp;
13846988Smckusick 	register struct mbuf *m;
13946988Smckusick 	struct socket *so;
14046988Smckusick 	struct vnode *vp;
141*52445Smckusick 	int error, i;
14246988Smckusick 
14346988Smckusick 	/*
14452196Smckusick 	 * Do enough of ifconfig(8) so that the critical net interface can
14546988Smckusick 	 * talk to the server.
14646988Smckusick 	 */
14746988Smckusick 	if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
14846988Smckusick 		panic("nfs ifconf");
149*52445Smckusick 	if (ifioctl(so, SIOCAIFADDR, &nfs_diskless.myif, curproc)) /* XXX */
15046988Smckusick 		panic("nfs ifconf2");
15146988Smckusick 	soclose(so);
15246988Smckusick 
15346988Smckusick 	/*
15446988Smckusick 	 * If the gateway field is filled in, set it as the default route.
15546988Smckusick 	 */
15652196Smckusick 	if (nfs_diskless.mygateway.sin_len != 0) {
15752196Smckusick 		struct sockaddr_in sin;
15852196Smckusick 		extern struct sockaddr_in icmpmask;
15946988Smckusick 
16052196Smckusick 		sin.sin_len = sizeof (struct sockaddr_in);
16152196Smckusick 		sin.sin_family = AF_INET;
16252196Smckusick 		sin.sin_addr.s_addr = 0;	/* default */
16352196Smckusick 		in_sockmaskof(sin.sin_addr, &icmpmask);
16452196Smckusick 		if (rtrequest(RTM_ADD, (struct sockaddr *)&sin,
16552196Smckusick 			(struct sockaddr *)&nfs_diskless.mygateway,
16652196Smckusick 			(struct sockaddr *)&icmpmask,
16752196Smckusick 			RTF_UP | RTF_GATEWAY, (struct rtentry **)0))
16846988Smckusick 			panic("nfs root route");
16946988Smckusick 	}
17046988Smckusick 
17146988Smckusick 	/*
17246988Smckusick 	 * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
17346988Smckusick 	 * Create a fake mount point just for the swap vnode so that the
17446988Smckusick 	 * swap file can be on a different server from the rootfs.
17546988Smckusick 	 */
17646988Smckusick 	if (swdevt[0].sw_dev == NODEV) {
17746988Smckusick 		mp = (struct mount *)malloc((u_long)sizeof(struct mount),
17846988Smckusick 			M_MOUNT, M_NOWAIT);
17946988Smckusick 		if (mp == NULL)
18046988Smckusick 			panic("nfs root mount");
18146988Smckusick 		mp->mnt_op = &nfs_vfsops;
18246988Smckusick 		mp->mnt_flag = 0;
18346988Smckusick 		mp->mnt_mounth = NULLVP;
18446988Smckusick 
18546988Smckusick 		/*
18646988Smckusick 		 * Set up the diskless nfs_args for the swap mount point
18746988Smckusick 		 * and then call mountnfs() to mount it.
18846988Smckusick 		 * Since the swap file is not the root dir of a file system,
18946988Smckusick 		 * hack it to a regular file.
19046988Smckusick 		 */
19146988Smckusick 		nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh;
19246988Smckusick 		MGET(m, MT_SONAME, M_DONTWAIT);
19346988Smckusick 		if (m == NULL)
19446988Smckusick 			panic("nfs root mbuf");
19546988Smckusick 		bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t),
19652196Smckusick 			nfs_diskless.swap_saddr.sin_len);
19752196Smckusick 		m->m_len = (int)nfs_diskless.swap_saddr.sin_len;
19852196Smckusick 		nfsargs_ntoh(&nfs_diskless.swap_args);
19946988Smckusick 		if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap",
20046988Smckusick 			nfs_diskless.swap_hostnam, &vp))
20146988Smckusick 			panic("nfs swap");
20246988Smckusick 		vp->v_type = VREG;
20346988Smckusick 		vp->v_flag = 0;
20446988Smckusick 		swapdev_vp = vp;
20546988Smckusick 		VREF(vp);
20646988Smckusick 		swdevt[0].sw_vp = vp;
20752196Smckusick 		swdevt[0].sw_nblks = ntohl(nfs_diskless.swap_nblks);
20846988Smckusick 	}
20946988Smckusick 
21046988Smckusick 	/*
21146988Smckusick 	 * Create the rootfs mount point.
21246988Smckusick 	 */
21346988Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
21446988Smckusick 		M_MOUNT, M_NOWAIT);
21546988Smckusick 	if (mp == NULL)
21646988Smckusick 		panic("nfs root mount2");
21746988Smckusick 	mp->mnt_op = &nfs_vfsops;
21846988Smckusick 	mp->mnt_flag = MNT_RDONLY;
21946988Smckusick 	mp->mnt_mounth = NULLVP;
22046988Smckusick 
22146988Smckusick 	/*
22246988Smckusick 	 * Set up the root fs args and call mountnfs() to do the rest.
22346988Smckusick 	 */
22446988Smckusick 	nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh;
22546988Smckusick 	MGET(m, MT_SONAME, M_DONTWAIT);
22646988Smckusick 	if (m == NULL)
22746988Smckusick 		panic("nfs root mbuf2");
22846988Smckusick 	bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t),
22952196Smckusick 		nfs_diskless.root_saddr.sin_len);
23052196Smckusick 	m->m_len = (int)nfs_diskless.root_saddr.sin_len;
23152196Smckusick 	nfsargs_ntoh(&nfs_diskless.root_args);
23246988Smckusick 	if (mountnfs(&nfs_diskless.root_args, mp, m, "/",
23346988Smckusick 		nfs_diskless.root_hostnam, &vp))
23446988Smckusick 		panic("nfs root");
23546988Smckusick 	if (vfs_lock(mp))
23646988Smckusick 		panic("nfs root2");
23746988Smckusick 	rootfs = mp;
23846988Smckusick 	mp->mnt_next = mp;
23946988Smckusick 	mp->mnt_prev = mp;
24046988Smckusick 	mp->mnt_vnodecovered = NULLVP;
24146988Smckusick 	vfs_unlock(mp);
24246988Smckusick 	rootvp = vp;
243*52445Smckusick 
244*52445Smckusick 	/*
245*52445Smckusick 	 * This is not really an nfs issue, but it is much easier to
246*52445Smckusick 	 * set hostname here and then let the "/etc/rc.xxx" files
247*52445Smckusick 	 * mount the right /var based upon its preset value.
248*52445Smckusick 	 */
249*52445Smckusick 	bcopy(nfs_diskless.my_hostnam, hostname, MAXHOSTNAMELEN);
250*52445Smckusick 	hostname[MAXHOSTNAMELEN - 1] = '\0';
251*52445Smckusick 	for (i = 0; i < MAXHOSTNAMELEN; i++)
252*52445Smckusick 		if (hostname[i] == '\0')
253*52445Smckusick 			break;
254*52445Smckusick 	hostnamelen = i;
25546988Smckusick 	inittodr((time_t)0);	/* There is no time in the nfs fsstat so ?? */
25646988Smckusick 	return (0);
25738414Smckusick }
25838414Smckusick 
25938414Smckusick /*
26052196Smckusick  * Convert the integer fields of the nfs_args structure from net byte order
26152196Smckusick  * to host byte order. Called by nfs_mountroot() above.
26252196Smckusick  */
26352196Smckusick void
26452196Smckusick nfsargs_ntoh(nfsp)
26552196Smckusick 	register struct nfs_args *nfsp;
26652196Smckusick {
26752196Smckusick 
26852196Smckusick 	NTOHL(nfsp->sotype);
26952196Smckusick 	NTOHL(nfsp->proto);
27052196Smckusick 	NTOHL(nfsp->flags);
27152196Smckusick 	NTOHL(nfsp->wsize);
27252196Smckusick 	NTOHL(nfsp->rsize);
27352196Smckusick 	NTOHL(nfsp->timeo);
27452196Smckusick 	NTOHL(nfsp->retrans);
27552196Smckusick 	NTOHL(nfsp->maxgrouplist);
27652196Smckusick 	NTOHL(nfsp->readahead);
27752196Smckusick 	NTOHL(nfsp->leaseterm);
27852196Smckusick 	NTOHL(nfsp->deadthresh);
27952196Smckusick }
28052196Smckusick 
28152196Smckusick /*
28238414Smckusick  * VFS Operations.
28338414Smckusick  *
28438414Smckusick  * mount system call
28538414Smckusick  * It seems a bit dumb to copyinstr() the host and path here and then
28638414Smckusick  * bcopy() them in mountnfs(), but I wanted to detect errors before
28738414Smckusick  * doing the sockargs() call because sockargs() allocates an mbuf and
28838414Smckusick  * an error after that means that I have to release the mbuf.
28938414Smckusick  */
29039494Smckusick /* ARGSUSED */
29148055Smckusick nfs_mount(mp, path, data, ndp, p)
29238414Smckusick 	struct mount *mp;
29338414Smckusick 	char *path;
29438414Smckusick 	caddr_t data;
29538414Smckusick 	struct nameidata *ndp;
29648055Smckusick 	struct proc *p;
29738414Smckusick {
29838414Smckusick 	int error;
29938414Smckusick 	struct nfs_args args;
30041904Smckusick 	struct mbuf *nam;
30146988Smckusick 	struct vnode *vp;
30238414Smckusick 	char pth[MNAMELEN], hst[MNAMELEN];
30349108Skarels 	u_int len;
30438414Smckusick 	nfsv2fh_t nfh;
30538414Smckusick 
30641398Smckusick 	if (mp->mnt_flag & MNT_UPDATE)
30739460Smckusick 		return (0);
30838414Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
30938414Smckusick 		return (error);
31049108Skarels 	if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
31138414Smckusick 		return (error);
31238414Smckusick 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
31338414Smckusick 		return (error);
31449108Skarels 	bzero(&pth[len], MNAMELEN - len);
31538414Smckusick 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
31638414Smckusick 		return (error);
31749108Skarels 	bzero(&hst[len], MNAMELEN - len);
31838414Smckusick 	/* sockargs() call must be after above copyin() calls */
31941904Smckusick 	if (error = sockargs(&nam, (caddr_t)args.addr,
32052196Smckusick 		args.addrlen, MT_SONAME))
32138414Smckusick 		return (error);
32238414Smckusick 	args.fh = &nfh;
32346988Smckusick 	error = mountnfs(&args, mp, nam, pth, hst, &vp);
32438414Smckusick 	return (error);
32538414Smckusick }
32638414Smckusick 
32738414Smckusick /*
32838414Smckusick  * Common code for mount and mountroot
32938414Smckusick  */
33046988Smckusick mountnfs(argp, mp, nam, pth, hst, vpp)
33138414Smckusick 	register struct nfs_args *argp;
33238414Smckusick 	register struct mount *mp;
33341904Smckusick 	struct mbuf *nam;
33438414Smckusick 	char *pth, *hst;
33546988Smckusick 	struct vnode **vpp;
33638414Smckusick {
33738414Smckusick 	register struct nfsmount *nmp;
33840010Smckusick 	struct nfsnode *np;
33940120Smckusick 	int error;
34039757Smckusick 	fsid_t tfsid;
34138414Smckusick 
34252196Smckusick 	MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount), M_NFSMNT,
34352196Smckusick 		M_WAITOK);
34452196Smckusick 	bzero((caddr_t)nmp, sizeof (struct nfsmount));
34541398Smckusick 	mp->mnt_data = (qaddr_t)nmp;
34639757Smckusick 	/*
34739757Smckusick 	 * Generate a unique nfs mount id. The problem is that a dev number
34839757Smckusick 	 * is not unique across multiple systems. The techique is as follows:
34939757Smckusick 	 * 1) Set to nblkdev,0 which will never be used otherwise
35039757Smckusick 	 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
35139757Smckusick 	 *	NOT 0
35239757Smckusick 	 * 3) Loop searching the mount list for another one with same id
35339757Smckusick 	 *	If a match, increment val[0] and try again
35439757Smckusick 	 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
35539757Smckusick 	 *	so that nfs is not limited to 255 mount points
35639757Smckusick 	 *     Incrementing the high order bits does no real harm, since it
35739757Smckusick 	 *     simply makes the major dev number tick up. The upper bound is
35839757Smckusick 	 *     set to major dev 127 to avoid any sign extention problems
35939757Smckusick 	 */
36041398Smckusick 	mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0);
36141398Smckusick 	mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS;
36239757Smckusick 	if (++nfs_mntid == 0)
36339757Smckusick 		++nfs_mntid;
36439757Smckusick 	tfsid.val[0] = makedev(nblkdev, nfs_mntid);
36539757Smckusick 	tfsid.val[1] = MOUNT_NFS;
36646988Smckusick 	while (rootfs && getvfs(&tfsid)) {
36739757Smckusick 		tfsid.val[0]++;
36839757Smckusick 		nfs_mntid++;
36939757Smckusick 	}
37039757Smckusick 	if (major(tfsid.val[0]) > 127) {
37139757Smckusick 		error = ENOENT;
37239757Smckusick 		goto bad;
37339757Smckusick 	}
37441398Smckusick 	mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
37538414Smckusick 	nmp->nm_mountp = mp;
37638414Smckusick 	nmp->nm_flag = argp->flags;
37752196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) ==
37852196Smckusick 		(NFSMNT_NQNFS | NFSMNT_MYWRITE)) {
37952196Smckusick 		error = EPERM;
38052196Smckusick 		goto bad;
38152196Smckusick 	}
38252196Smckusick 	if ((nmp->nm_flag & (NFSMNT_RDIRALOOK | NFSMNT_LEASETERM)) &&
38352196Smckusick 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0) {
38452196Smckusick 		error = EPERM;
38552196Smckusick 		goto bad;
38652196Smckusick 	}
38752196Smckusick 	nmp->nm_timeo = NFS_TIMEO;
38840120Smckusick 	nmp->nm_retry = NFS_RETRANS;
38940120Smckusick 	nmp->nm_wsize = NFS_WSIZE;
39040120Smckusick 	nmp->nm_rsize = NFS_RSIZE;
39152196Smckusick 	nmp->nm_numgrps = NFS_MAXGRPS;
39252196Smckusick 	nmp->nm_readahead = NFS_DEFRAHEAD;
39352196Smckusick 	nmp->nm_leaseterm = NQ_DEFLEASE;
39452196Smckusick 	nmp->nm_deadthresh = NQ_DEADTHRESH;
39552196Smckusick 	nmp->nm_tnext = (struct nfsnode *)nmp;
39652196Smckusick 	nmp->nm_tprev = (struct nfsnode *)nmp;
39752196Smckusick 	nmp->nm_inprog = NULLVP;
39840120Smckusick 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
39941398Smckusick 	mp->mnt_stat.f_type = MOUNT_NFS;
40041398Smckusick 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
40141398Smckusick 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
40241904Smckusick 	nmp->nm_nam = nam;
40340120Smckusick 
40440120Smckusick 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
40552196Smckusick 		nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
40652196Smckusick 		if (nmp->nm_timeo < NFS_MINTIMEO)
40752196Smckusick 			nmp->nm_timeo = NFS_MINTIMEO;
40852196Smckusick 		else if (nmp->nm_timeo > NFS_MAXTIMEO)
40952196Smckusick 			nmp->nm_timeo = NFS_MAXTIMEO;
41040120Smckusick 	}
41140120Smckusick 
41243355Smckusick 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
41340120Smckusick 		nmp->nm_retry = argp->retrans;
41440120Smckusick 		if (nmp->nm_retry > NFS_MAXREXMIT)
41540120Smckusick 			nmp->nm_retry = NFS_MAXREXMIT;
41640120Smckusick 	}
41740120Smckusick 
41840120Smckusick 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
41938414Smckusick 		nmp->nm_wsize = argp->wsize;
42040120Smckusick 		/* Round down to multiple of blocksize */
42140120Smckusick 		nmp->nm_wsize &= ~0x1ff;
42240120Smckusick 		if (nmp->nm_wsize <= 0)
42340120Smckusick 			nmp->nm_wsize = 512;
42440120Smckusick 		else if (nmp->nm_wsize > NFS_MAXDATA)
42540120Smckusick 			nmp->nm_wsize = NFS_MAXDATA;
42640120Smckusick 	}
42743355Smckusick 	if (nmp->nm_wsize > MAXBSIZE)
42843355Smckusick 		nmp->nm_wsize = MAXBSIZE;
42940120Smckusick 
43040120Smckusick 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
43138414Smckusick 		nmp->nm_rsize = argp->rsize;
43240120Smckusick 		/* Round down to multiple of blocksize */
43340120Smckusick 		nmp->nm_rsize &= ~0x1ff;
43440120Smckusick 		if (nmp->nm_rsize <= 0)
43540120Smckusick 			nmp->nm_rsize = 512;
43640120Smckusick 		else if (nmp->nm_rsize > NFS_MAXDATA)
43740120Smckusick 			nmp->nm_rsize = NFS_MAXDATA;
43840120Smckusick 	}
43943355Smckusick 	if (nmp->nm_rsize > MAXBSIZE)
44043355Smckusick 		nmp->nm_rsize = MAXBSIZE;
44152196Smckusick 	if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
44252196Smckusick 		argp->maxgrouplist <= NFS_MAXGRPS)
44352196Smckusick 		nmp->nm_numgrps = argp->maxgrouplist;
44452196Smckusick 	if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
44552196Smckusick 		argp->readahead <= NFS_MAXRAHEAD)
44652196Smckusick 		nmp->nm_readahead = argp->readahead;
44752196Smckusick 	if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
44852196Smckusick 		argp->leaseterm <= NQ_MAXLEASE)
44952196Smckusick 		nmp->nm_leaseterm = argp->leaseterm;
45052196Smckusick 	if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
45152196Smckusick 		argp->deadthresh <= NQ_NEVERDEAD)
45252196Smckusick 		nmp->nm_deadthresh = argp->deadthresh;
45340120Smckusick 	/* Set up the sockets and per-host congestion */
45441904Smckusick 	nmp->nm_sotype = argp->sotype;
45541904Smckusick 	nmp->nm_soproto = argp->proto;
45652196Smckusick 
45752196Smckusick 	/*
45852196Smckusick 	 * For Connection based sockets (TCP,...) defer the connect until
45952196Smckusick 	 * the first request, in case the server is not responding.
46052196Smckusick 	 */
46152196Smckusick 	if (nmp->nm_sotype == SOCK_DGRAM &&
46252196Smckusick 		(error = nfs_connect(nmp, (struct nfsreq *)0)))
46340120Smckusick 		goto bad;
46440120Smckusick 
46538414Smckusick 	/*
46652196Smckusick 	 * This is silly, but it has to be set so that vinifod() works.
46752196Smckusick 	 * We do not want to do an nfs_statfs() here since we can get
46852196Smckusick 	 * stuck on a dead server and we are holding a lock on the mount
46952196Smckusick 	 * point.
47052196Smckusick 	 */
47152196Smckusick 	mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
47252196Smckusick 	/*
47340010Smckusick 	 * A reference count is needed on the nfsnode representing the
47440010Smckusick 	 * remote root.  If this object is not persistent, then backward
47540010Smckusick 	 * traversals of the mount point (i.e. "..") will not work if
47640010Smckusick 	 * the nfsnode gets flushed out of the cache. Ufs does not have
47740010Smckusick 	 * this problem, because one can identify root inodes by their
47840010Smckusick 	 * number == ROOTINO (2).
47940010Smckusick 	 */
48040010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
48140010Smckusick 		goto bad;
48246988Smckusick 	*vpp = NFSTOV(np);
48341904Smckusick 
48440353Smckusick 	return (0);
48538414Smckusick bad:
48640120Smckusick 	nfs_disconnect(nmp);
48752196Smckusick 	free((caddr_t)nmp, M_NFSMNT);
48841904Smckusick 	m_freem(nam);
48938414Smckusick 	return (error);
49038414Smckusick }
49138414Smckusick 
49238414Smckusick /*
49338414Smckusick  * unmount system call
49438414Smckusick  */
49548055Smckusick nfs_unmount(mp, mntflags, p)
49638414Smckusick 	struct mount *mp;
49741294Smckusick 	int mntflags;
49848055Smckusick 	struct proc *p;
49938414Smckusick {
50038414Smckusick 	register struct nfsmount *nmp;
50140010Smckusick 	struct nfsnode *np;
50240120Smckusick 	struct vnode *vp;
50348361Smckusick 	int error, flags = 0;
50448361Smckusick 	extern int doforce;
50538414Smckusick 
50648066Smckusick 	if (mntflags & MNT_FORCE) {
50748361Smckusick 		if (!doforce || mp == rootfs)
50848066Smckusick 			return (EINVAL);
50941294Smckusick 		flags |= FORCECLOSE;
51048066Smckusick 	}
51141398Smckusick 	nmp = VFSTONFS(mp);
51238414Smckusick 	/*
51338884Smacklem 	 * Clear out the buffer cache
51438884Smacklem 	 */
51539669Smckusick 	mntflushbuf(mp, 0);
51639669Smckusick 	if (mntinvalbuf(mp))
51738884Smacklem 		return (EBUSY);
51838884Smacklem 	/*
51938414Smckusick 	 * Goes something like this..
52040120Smckusick 	 * - Check for activity on the root vnode (other than ourselves).
52140120Smckusick 	 * - Call vflush() to clear out vnodes for this file system,
52240120Smckusick 	 *   except for the root vnode.
52340120Smckusick 	 * - Decrement reference on the vnode representing remote root.
52438414Smckusick 	 * - Close the socket
52538414Smckusick 	 * - Free up the data structures
52638414Smckusick 	 */
52740010Smckusick 	/*
52840010Smckusick 	 * We need to decrement the ref. count on the nfsnode representing
52940010Smckusick 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
53040010Smckusick 	 * has done vput on this vnode, otherwise we would get deadlock!
53140010Smckusick 	 */
53240010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
53340010Smckusick 		return(error);
53440120Smckusick 	vp = NFSTOV(np);
53540120Smckusick 	if (vp->v_usecount > 2) {
53640120Smckusick 		vput(vp);
53740120Smckusick 		return (EBUSY);
53840120Smckusick 	}
53952196Smckusick 
54052196Smckusick 	/*
54152196Smckusick 	 * Must handshake with nqnfs_clientd() if it is active.
54252196Smckusick 	 */
54352196Smckusick 	nmp->nm_flag |= NFSMNT_DISMINPROG;
54452196Smckusick 	while (nmp->nm_inprog != NULLVP)
54552196Smckusick 		(void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
54640120Smckusick 	if (error = vflush(mp, vp, flags)) {
54740120Smckusick 		vput(vp);
54852196Smckusick 		nmp->nm_flag &= ~NFSMNT_DISMINPROG;
54940120Smckusick 		return (error);
55040120Smckusick 	}
55152196Smckusick 
55240010Smckusick 	/*
55352196Smckusick 	 * We are now committed to the unmount.
55452196Smckusick 	 * For NQNFS, let the server daemon free the nfsmount structure.
55540010Smckusick 	 */
55652196Smckusick 	if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
55752196Smckusick 		nmp->nm_flag |= NFSMNT_DISMNT;
55852196Smckusick 
55952196Smckusick 	/*
56052196Smckusick 	 * There are two reference counts to get rid of here.
56152196Smckusick 	 */
56240120Smckusick 	vrele(vp);
56352196Smckusick 	vrele(vp);
56452288Smckusick 	vgone(vp);
56540120Smckusick 	nfs_disconnect(nmp);
56641904Smckusick 	m_freem(nmp->nm_nam);
56752196Smckusick 
56852196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
56952196Smckusick 		free((caddr_t)nmp, M_NFSMNT);
57038414Smckusick 	return (0);
57138414Smckusick }
57238414Smckusick 
57338414Smckusick /*
57438414Smckusick  * Return root of a filesystem
57538414Smckusick  */
57638414Smckusick nfs_root(mp, vpp)
57738414Smckusick 	struct mount *mp;
57838414Smckusick 	struct vnode **vpp;
57938414Smckusick {
58038414Smckusick 	register struct vnode *vp;
58138414Smckusick 	struct nfsmount *nmp;
58238414Smckusick 	struct nfsnode *np;
58338414Smckusick 	int error;
58438414Smckusick 
58541398Smckusick 	nmp = VFSTONFS(mp);
58638414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
58738414Smckusick 		return (error);
58838414Smckusick 	vp = NFSTOV(np);
58938414Smckusick 	vp->v_type = VDIR;
59038414Smckusick 	vp->v_flag = VROOT;
59138414Smckusick 	*vpp = vp;
59238414Smckusick 	return (0);
59338414Smckusick }
59438414Smckusick 
59538884Smacklem extern int syncprt;
59638884Smacklem 
59738414Smckusick /*
59838884Smacklem  * Flush out the buffer cache
59938414Smckusick  */
60039494Smckusick /* ARGSUSED */
60138414Smckusick nfs_sync(mp, waitfor)
60238414Smckusick 	struct mount *mp;
60338414Smckusick 	int waitfor;
60438414Smckusick {
60538884Smacklem 	if (syncprt)
60651465Sbostic 		ufs_bufstats();
60738884Smacklem 	/*
60838884Smacklem 	 * Force stale buffer cache information to be flushed.
60938884Smacklem 	 */
61040035Smckusick 	mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0);
61138414Smckusick 	return (0);
61238414Smckusick }
61338414Smckusick 
61438414Smckusick /*
61538414Smckusick  * At this point, this should never happen
61638414Smckusick  */
61739494Smckusick /* ARGSUSED */
61852196Smckusick nfs_fhtovp(mp, fhp, setgen, vpp)
61938414Smckusick 	struct mount *mp;
62038414Smckusick 	struct fid *fhp;
62152196Smckusick 	int setgen;
62238414Smckusick 	struct vnode **vpp;
62338414Smckusick {
62439494Smckusick 
62538414Smckusick 	return (EINVAL);
62638414Smckusick }
62738414Smckusick 
62838414Smckusick /*
62938414Smckusick  * Vnode pointer to File handle, should never happen either
63038414Smckusick  */
63139494Smckusick /* ARGSUSED */
63248055Smckusick nfs_vptofh(vp, fhp)
63348055Smckusick 	struct vnode *vp;
63438414Smckusick 	struct fid *fhp;
63538414Smckusick {
63639494Smckusick 
63738414Smckusick 	return (EINVAL);
63838414Smckusick }
63938884Smacklem 
64038884Smacklem /*
64138884Smacklem  * Vfs start routine, a no-op.
64238884Smacklem  */
64339494Smckusick /* ARGSUSED */
64448055Smckusick nfs_start(mp, flags, p)
64538884Smacklem 	struct mount *mp;
64638884Smacklem 	int flags;
64748055Smckusick 	struct proc *p;
64838884Smacklem {
64939494Smckusick 
65038884Smacklem 	return (0);
65138884Smacklem }
65241294Smckusick 
65341294Smckusick /*
65441294Smckusick  * Do operations associated with quotas, not supported
65541294Smckusick  */
65651574Smckusick /* ARGSUSED */
65748055Smckusick nfs_quotactl(mp, cmd, uid, arg, p)
65841294Smckusick 	struct mount *mp;
65941294Smckusick 	int cmd;
66051574Smckusick 	u_int uid;
66141294Smckusick 	caddr_t arg;
66248055Smckusick 	struct proc *p;
66341294Smckusick {
66451574Smckusick 
66541294Smckusick 	return (EOPNOTSUPP);
66641294Smckusick }
667