xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 55082)
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*55082Storek  *	@(#)nfs_vfsops.c	7.44 (Berkeley) 07/12/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,
5254667Smckusick 	nfs_vget,
5338414Smckusick 	nfs_fhtovp,
5438414Smckusick 	nfs_vptofh,
5539443Smckusick 	nfs_init,
5638414Smckusick };
5738414Smckusick 
5852196Smckusick /*
5952196Smckusick  * This structure must be filled in by a primary bootstrap or bootstrap
6052196Smckusick  * server for a diskless/dataless machine. It is initialized below just
6152196Smckusick  * to ensure that it is allocated to initialized data (.data not .bss).
6252196Smckusick  */
6352196Smckusick struct nfs_diskless nfs_diskless = { 0 };
6452196Smckusick 
6539757Smckusick static u_char nfs_mntid;
6641904Smckusick extern u_long nfs_procids[NFS_NPROCS];
6741904Smckusick extern u_long nfs_prog, nfs_vers;
68*55082Storek void nfs_disconnect __P((struct nfsmount *));
69*55082Storek void nfsargs_ntoh __P((struct nfs_args *));
70*55082Storek static struct mount *nfs_mountdiskless __P((char *, char *, int,
71*55082Storek     struct sockaddr_in *, struct nfs_args *, register struct vnode **));
7238414Smckusick 
7341904Smckusick #define TRUE	1
7441904Smckusick #define	FALSE	0
7541904Smckusick 
7638414Smckusick /*
7741904Smckusick  * nfs statfs call
7841904Smckusick  */
79*55082Storek int
8048055Smckusick nfs_statfs(mp, sbp, p)
8141904Smckusick 	struct mount *mp;
8241904Smckusick 	register struct statfs *sbp;
8348055Smckusick 	struct proc *p;
8441904Smckusick {
8541904Smckusick 	register struct vnode *vp;
8641904Smckusick 	register struct nfsv2_statfs *sfp;
8741904Smckusick 	register caddr_t cp;
8841904Smckusick 	register long t1;
8941904Smckusick 	caddr_t bpos, dpos, cp2;
9041904Smckusick 	int error = 0;
9141904Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
9241904Smckusick 	struct nfsmount *nmp;
9341904Smckusick 	struct ucred *cred;
9441904Smckusick 	struct nfsnode *np;
9541904Smckusick 
9641904Smckusick 	nmp = VFSTONFS(mp);
9741904Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
9841904Smckusick 		return (error);
9941904Smckusick 	vp = NFSTOV(np);
10041904Smckusick 	nfsstats.rpccnt[NFSPROC_STATFS]++;
10141904Smckusick 	cred = crget();
10241904Smckusick 	cred->cr_ngroups = 1;
10352196Smckusick 	nfsm_reqhead(vp, NFSPROC_STATFS, NFSX_FH);
10441904Smckusick 	nfsm_fhtom(vp);
10552196Smckusick 	nfsm_request(vp, NFSPROC_STATFS, p, cred);
10652196Smckusick 	nfsm_dissect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
10741904Smckusick 	sbp->f_type = MOUNT_NFS;
10841904Smckusick 	sbp->f_flags = nmp->nm_flag;
10952196Smckusick 	sbp->f_iosize = NFS_MAXDGRAMDATA;
11051940Smckusick 	sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
11141904Smckusick 	sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
11241904Smckusick 	sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
11341904Smckusick 	sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
11441904Smckusick 	sbp->f_files = 0;
11541904Smckusick 	sbp->f_ffree = 0;
11641904Smckusick 	if (sbp != &mp->mnt_stat) {
11741904Smckusick 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
11841904Smckusick 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
11941904Smckusick 	}
12041904Smckusick 	nfsm_reqdone;
12152196Smckusick 	vrele(vp);
12241904Smckusick 	crfree(cred);
12341904Smckusick 	return (error);
12441904Smckusick }
12541904Smckusick 
12641904Smckusick /*
12746988Smckusick  * Mount a remote root fs via. nfs. This depends on the info in the
12846988Smckusick  * nfs_diskless structure that has been filled in properly by some primary
12946988Smckusick  * bootstrap.
13046988Smckusick  * It goes something like this:
13146988Smckusick  * - do enough of "ifconfig" by calling ifioctl() so that the system
13246988Smckusick  *   can talk to the server
13346988Smckusick  * - If nfs_diskless.mygateway is filled in, use that address as
13446988Smckusick  *   a default gateway.
13546988Smckusick  * - hand craft the swap nfs vnode hanging off a fake mount point
13652196Smckusick  *	if swdevt[0].sw_dev == NODEV
13746988Smckusick  * - build the rootfs mount point and call mountnfs() to do the rest.
13838414Smckusick  */
139*55082Storek int
14038414Smckusick nfs_mountroot()
14138414Smckusick {
14246988Smckusick 	register struct mount *mp;
143*55082Storek 	register struct nfs_diskless *nd = &nfs_diskless;
14446988Smckusick 	struct socket *so;
14546988Smckusick 	struct vnode *vp;
146*55082Storek 	struct proc *p = curproc;		/* XXX */
14752445Smckusick 	int error, i;
14846988Smckusick 
14946988Smckusick 	/*
150*55082Storek 	 * XXX time must be non-zero when we init the interface or else
151*55082Storek 	 * the arp code will wedge...
152*55082Storek 	 */
153*55082Storek 	if (time.tv_sec == 0)
154*55082Storek 		time.tv_sec = 1;
155*55082Storek 
156*55082Storek #ifdef notyet
157*55082Storek 	/* Set up swap credentials. */
158*55082Storek 	*proc0.p_ucred = nfs_diskless.swap_ucred;
159*55082Storek #endif
160*55082Storek 
161*55082Storek 	/*
16252196Smckusick 	 * Do enough of ifconfig(8) so that the critical net interface can
16346988Smckusick 	 * talk to the server.
16446988Smckusick 	 */
165*55082Storek 	if (error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
166*55082Storek 		panic("nfs_mountroot: socreate: %d", error);
167*55082Storek 	if (error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, p))
168*55082Storek 		panic("nfs_mountroot: SIOCAIFADDR: %d", error);
16946988Smckusick 	soclose(so);
17046988Smckusick 
17146988Smckusick 	/*
17246988Smckusick 	 * If the gateway field is filled in, set it as the default route.
17346988Smckusick 	 */
174*55082Storek 	if (nd->mygateway.sin_len != 0) {
17552196Smckusick 		struct sockaddr_in sin;
17652196Smckusick 		extern struct sockaddr_in icmpmask;
17746988Smckusick 
17852196Smckusick 		sin.sin_len = sizeof (struct sockaddr_in);
17952196Smckusick 		sin.sin_family = AF_INET;
18052196Smckusick 		sin.sin_addr.s_addr = 0;	/* default */
18152196Smckusick 		in_sockmaskof(sin.sin_addr, &icmpmask);
182*55082Storek 		if (error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
183*55082Storek 		    (struct sockaddr *)&nd->mygateway,
184*55082Storek 		    (struct sockaddr *)&icmpmask,
185*55082Storek 		    RTF_UP | RTF_GATEWAY, (struct rtentry **)0))
186*55082Storek 			panic("nfs_mountroot: RTM_ADD: %d", error);
18746988Smckusick 	}
18846988Smckusick 
18946988Smckusick 	/*
19046988Smckusick 	 * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
19146988Smckusick 	 * Create a fake mount point just for the swap vnode so that the
19246988Smckusick 	 * swap file can be on a different server from the rootfs.
19346988Smckusick 	 */
19446988Smckusick 	if (swdevt[0].sw_dev == NODEV) {
195*55082Storek 		nd->swap_args.fh = (nfsv2fh_t *)nd->swap_fh;
196*55082Storek 		(void) nfs_mountdiskless(nd->swap_hostnam, "/swap", 0,
197*55082Storek 		    &nd->swap_saddr, &nd->swap_args, &vp);
19846988Smckusick 
19946988Smckusick 		/*
20046988Smckusick 		 * Since the swap file is not the root dir of a file system,
20146988Smckusick 		 * hack it to a regular file.
20246988Smckusick 		 */
20346988Smckusick 		vp->v_type = VREG;
20446988Smckusick 		vp->v_flag = 0;
20546988Smckusick 		swapdev_vp = vp;
20646988Smckusick 		VREF(vp);
20746988Smckusick 		swdevt[0].sw_vp = vp;
208*55082Storek 		swdevt[0].sw_nblks = ntohl(nd->swap_nblks);
20946988Smckusick 	}
21046988Smckusick 
21146988Smckusick 	/*
21246988Smckusick 	 * Create the rootfs mount point.
21346988Smckusick 	 */
214*55082Storek 	nd->root_args.fh = (nfsv2fh_t *)nd->root_fh;
215*55082Storek 	mp = nfs_mountdiskless(nd->root_hostnam, "/", MNT_RDONLY,
216*55082Storek 	    &nd->root_saddr, &nd->root_args, &vp);
21746988Smckusick 
21846988Smckusick 	if (vfs_lock(mp))
219*55082Storek 		panic("nfs_mountroot: vfs_lock");
22046988Smckusick 	rootfs = mp;
22146988Smckusick 	mp->mnt_next = mp;
22246988Smckusick 	mp->mnt_prev = mp;
22346988Smckusick 	mp->mnt_vnodecovered = NULLVP;
22446988Smckusick 	vfs_unlock(mp);
22546988Smckusick 	rootvp = vp;
22652445Smckusick 
22752445Smckusick 	/*
22852445Smckusick 	 * This is not really an nfs issue, but it is much easier to
22952445Smckusick 	 * set hostname here and then let the "/etc/rc.xxx" files
23052445Smckusick 	 * mount the right /var based upon its preset value.
23152445Smckusick 	 */
232*55082Storek 	bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
23352445Smckusick 	hostname[MAXHOSTNAMELEN - 1] = '\0';
23452445Smckusick 	for (i = 0; i < MAXHOSTNAMELEN; i++)
23552445Smckusick 		if (hostname[i] == '\0')
23652445Smckusick 			break;
23752445Smckusick 	hostnamelen = i;
238*55082Storek 	inittodr(nfs_diskless.root_time);
23946988Smckusick 	return (0);
24038414Smckusick }
24138414Smckusick 
24238414Smckusick /*
243*55082Storek  * Internal version of mount system call for diskless setup.
244*55082Storek  */
245*55082Storek static struct mount *
246*55082Storek nfs_mountdiskless(path, which, mountflag, sin, args, vpp)
247*55082Storek 	char *path;
248*55082Storek 	char *which;
249*55082Storek 	int mountflag;
250*55082Storek 	struct sockaddr_in *sin;
251*55082Storek 	struct nfs_args *args;
252*55082Storek 	register struct vnode **vpp;
253*55082Storek {
254*55082Storek 	register struct mount *mp;
255*55082Storek 	register struct mbuf *m;
256*55082Storek 	register int error;
257*55082Storek 
258*55082Storek 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
259*55082Storek 	    M_MOUNT, M_NOWAIT);
260*55082Storek 	if (mp == NULL)
261*55082Storek 		panic("nfs_mountroot: %s mount malloc", which);
262*55082Storek 	mp->mnt_op = &nfs_vfsops;
263*55082Storek 	mp->mnt_flag = mountflag;
264*55082Storek 	mp->mnt_mounth = NULLVP;
265*55082Storek 
266*55082Storek 	MGET(m, MT_SONAME, M_DONTWAIT);
267*55082Storek 	if (m == NULL)
268*55082Storek 		panic("nfs_mountroot: %s mount mbuf", which);
269*55082Storek 	bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len);
270*55082Storek 	m->m_len = sin->sin_len;
271*55082Storek 	nfsargs_ntoh(args);
272*55082Storek 	if (error = mountnfs(args, mp, m, which, path, vpp))
273*55082Storek 		panic("nfs_mountroot: mount %s on %s: %d", path, which, error);
274*55082Storek 
275*55082Storek 	return (mp);
276*55082Storek }
277*55082Storek 
278*55082Storek /*
27952196Smckusick  * Convert the integer fields of the nfs_args structure from net byte order
28052196Smckusick  * to host byte order. Called by nfs_mountroot() above.
28152196Smckusick  */
28252196Smckusick void
28352196Smckusick nfsargs_ntoh(nfsp)
28452196Smckusick 	register struct nfs_args *nfsp;
28552196Smckusick {
28652196Smckusick 
28752196Smckusick 	NTOHL(nfsp->sotype);
28852196Smckusick 	NTOHL(nfsp->proto);
28952196Smckusick 	NTOHL(nfsp->flags);
29052196Smckusick 	NTOHL(nfsp->wsize);
29152196Smckusick 	NTOHL(nfsp->rsize);
29252196Smckusick 	NTOHL(nfsp->timeo);
29352196Smckusick 	NTOHL(nfsp->retrans);
29452196Smckusick 	NTOHL(nfsp->maxgrouplist);
29552196Smckusick 	NTOHL(nfsp->readahead);
29652196Smckusick 	NTOHL(nfsp->leaseterm);
29752196Smckusick 	NTOHL(nfsp->deadthresh);
29852196Smckusick }
29952196Smckusick 
30052196Smckusick /*
30138414Smckusick  * VFS Operations.
30238414Smckusick  *
30338414Smckusick  * mount system call
30438414Smckusick  * It seems a bit dumb to copyinstr() the host and path here and then
30538414Smckusick  * bcopy() them in mountnfs(), but I wanted to detect errors before
30638414Smckusick  * doing the sockargs() call because sockargs() allocates an mbuf and
30738414Smckusick  * an error after that means that I have to release the mbuf.
30838414Smckusick  */
30939494Smckusick /* ARGSUSED */
310*55082Storek int
31148055Smckusick nfs_mount(mp, path, data, ndp, p)
31238414Smckusick 	struct mount *mp;
31338414Smckusick 	char *path;
31438414Smckusick 	caddr_t data;
31538414Smckusick 	struct nameidata *ndp;
31648055Smckusick 	struct proc *p;
31738414Smckusick {
31838414Smckusick 	int error;
31938414Smckusick 	struct nfs_args args;
32041904Smckusick 	struct mbuf *nam;
32146988Smckusick 	struct vnode *vp;
32238414Smckusick 	char pth[MNAMELEN], hst[MNAMELEN];
32349108Skarels 	u_int len;
32438414Smckusick 	nfsv2fh_t nfh;
32538414Smckusick 
32638414Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
32738414Smckusick 		return (error);
32849108Skarels 	if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
32938414Smckusick 		return (error);
33038414Smckusick 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
33138414Smckusick 		return (error);
33249108Skarels 	bzero(&pth[len], MNAMELEN - len);
33338414Smckusick 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
33438414Smckusick 		return (error);
33549108Skarels 	bzero(&hst[len], MNAMELEN - len);
33638414Smckusick 	/* sockargs() call must be after above copyin() calls */
33741904Smckusick 	if (error = sockargs(&nam, (caddr_t)args.addr,
33852196Smckusick 		args.addrlen, MT_SONAME))
33938414Smckusick 		return (error);
34038414Smckusick 	args.fh = &nfh;
34146988Smckusick 	error = mountnfs(&args, mp, nam, pth, hst, &vp);
34238414Smckusick 	return (error);
34338414Smckusick }
34438414Smckusick 
34538414Smckusick /*
34638414Smckusick  * Common code for mount and mountroot
34738414Smckusick  */
348*55082Storek int
34946988Smckusick mountnfs(argp, mp, nam, pth, hst, vpp)
35038414Smckusick 	register struct nfs_args *argp;
35138414Smckusick 	register struct mount *mp;
35241904Smckusick 	struct mbuf *nam;
35338414Smckusick 	char *pth, *hst;
35446988Smckusick 	struct vnode **vpp;
35538414Smckusick {
35638414Smckusick 	register struct nfsmount *nmp;
35740010Smckusick 	struct nfsnode *np;
35840120Smckusick 	int error;
35939757Smckusick 	fsid_t tfsid;
36038414Smckusick 
361*55082Storek 	if (mp->mnt_flag & MNT_UPDATE) {
362*55082Storek 		nmp = VFSTONFS(mp);
363*55082Storek 		/* update paths, file handles, etc, here	XXX */
364*55082Storek 		m_freem(nam);
365*55082Storek 		return (0);
366*55082Storek 	} else {
367*55082Storek 		MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
368*55082Storek 		    M_NFSMNT, M_WAITOK);
369*55082Storek 		bzero((caddr_t)nmp, sizeof (struct nfsmount));
370*55082Storek 		mp->mnt_data = (qaddr_t)nmp;
371*55082Storek 	}
37253937Spendry 	getnewfsid(mp, MOUNT_NFS);
37338414Smckusick 	nmp->nm_mountp = mp;
37438414Smckusick 	nmp->nm_flag = argp->flags;
37552196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) ==
37652196Smckusick 		(NFSMNT_NQNFS | NFSMNT_MYWRITE)) {
37752196Smckusick 		error = EPERM;
37852196Smckusick 		goto bad;
37952196Smckusick 	}
38054985Smckusick 	if (nmp->nm_flag & (NFSMNT_RDIRALOOK | NFSMNT_LEASETERM)) {
38154985Smckusick 		if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) {
38254985Smckusick 			error = EPERM;
38354985Smckusick 			goto bad;
38454985Smckusick 		}
38554985Smckusick 		/*
38654985Smckusick 		 * We have to set mnt_maxsymlink to a non-zero value so
38754985Smckusick 		 * that COMPAT_43 routines will know that we are setting
38854985Smckusick 		 * the d_type field in directories (and can zero it for
38954985Smckusick 		 * unsuspecting binaries).
39054985Smckusick 		 */
39154985Smckusick 		mp->mnt_maxsymlinklen = 1;
39252196Smckusick 	}
39352196Smckusick 	nmp->nm_timeo = NFS_TIMEO;
39440120Smckusick 	nmp->nm_retry = NFS_RETRANS;
39540120Smckusick 	nmp->nm_wsize = NFS_WSIZE;
39640120Smckusick 	nmp->nm_rsize = NFS_RSIZE;
39752196Smckusick 	nmp->nm_numgrps = NFS_MAXGRPS;
39852196Smckusick 	nmp->nm_readahead = NFS_DEFRAHEAD;
39952196Smckusick 	nmp->nm_leaseterm = NQ_DEFLEASE;
40052196Smckusick 	nmp->nm_deadthresh = NQ_DEADTHRESH;
40152196Smckusick 	nmp->nm_tnext = (struct nfsnode *)nmp;
40252196Smckusick 	nmp->nm_tprev = (struct nfsnode *)nmp;
40352196Smckusick 	nmp->nm_inprog = NULLVP;
40440120Smckusick 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
40541398Smckusick 	mp->mnt_stat.f_type = MOUNT_NFS;
40641398Smckusick 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
40741398Smckusick 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
40841904Smckusick 	nmp->nm_nam = nam;
40940120Smckusick 
41040120Smckusick 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
41152196Smckusick 		nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
41252196Smckusick 		if (nmp->nm_timeo < NFS_MINTIMEO)
41352196Smckusick 			nmp->nm_timeo = NFS_MINTIMEO;
41452196Smckusick 		else if (nmp->nm_timeo > NFS_MAXTIMEO)
41552196Smckusick 			nmp->nm_timeo = NFS_MAXTIMEO;
41640120Smckusick 	}
41740120Smckusick 
41843355Smckusick 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
41940120Smckusick 		nmp->nm_retry = argp->retrans;
42040120Smckusick 		if (nmp->nm_retry > NFS_MAXREXMIT)
42140120Smckusick 			nmp->nm_retry = NFS_MAXREXMIT;
42240120Smckusick 	}
42340120Smckusick 
42440120Smckusick 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
42538414Smckusick 		nmp->nm_wsize = argp->wsize;
42640120Smckusick 		/* Round down to multiple of blocksize */
42740120Smckusick 		nmp->nm_wsize &= ~0x1ff;
42840120Smckusick 		if (nmp->nm_wsize <= 0)
42940120Smckusick 			nmp->nm_wsize = 512;
43040120Smckusick 		else if (nmp->nm_wsize > NFS_MAXDATA)
43140120Smckusick 			nmp->nm_wsize = NFS_MAXDATA;
43240120Smckusick 	}
43343355Smckusick 	if (nmp->nm_wsize > MAXBSIZE)
43443355Smckusick 		nmp->nm_wsize = MAXBSIZE;
43540120Smckusick 
43640120Smckusick 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
43738414Smckusick 		nmp->nm_rsize = argp->rsize;
43840120Smckusick 		/* Round down to multiple of blocksize */
43940120Smckusick 		nmp->nm_rsize &= ~0x1ff;
44040120Smckusick 		if (nmp->nm_rsize <= 0)
44140120Smckusick 			nmp->nm_rsize = 512;
44240120Smckusick 		else if (nmp->nm_rsize > NFS_MAXDATA)
44340120Smckusick 			nmp->nm_rsize = NFS_MAXDATA;
44440120Smckusick 	}
44543355Smckusick 	if (nmp->nm_rsize > MAXBSIZE)
44643355Smckusick 		nmp->nm_rsize = MAXBSIZE;
44752196Smckusick 	if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
44852196Smckusick 		argp->maxgrouplist <= NFS_MAXGRPS)
44952196Smckusick 		nmp->nm_numgrps = argp->maxgrouplist;
45052196Smckusick 	if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
45152196Smckusick 		argp->readahead <= NFS_MAXRAHEAD)
45252196Smckusick 		nmp->nm_readahead = argp->readahead;
45352196Smckusick 	if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
45452196Smckusick 		argp->leaseterm <= NQ_MAXLEASE)
45552196Smckusick 		nmp->nm_leaseterm = argp->leaseterm;
45652196Smckusick 	if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
45752196Smckusick 		argp->deadthresh <= NQ_NEVERDEAD)
45852196Smckusick 		nmp->nm_deadthresh = argp->deadthresh;
45940120Smckusick 	/* Set up the sockets and per-host congestion */
46041904Smckusick 	nmp->nm_sotype = argp->sotype;
46141904Smckusick 	nmp->nm_soproto = argp->proto;
46252196Smckusick 
46352196Smckusick 	/*
46452196Smckusick 	 * For Connection based sockets (TCP,...) defer the connect until
46552196Smckusick 	 * the first request, in case the server is not responding.
46652196Smckusick 	 */
46752196Smckusick 	if (nmp->nm_sotype == SOCK_DGRAM &&
46852196Smckusick 		(error = nfs_connect(nmp, (struct nfsreq *)0)))
46940120Smckusick 		goto bad;
47040120Smckusick 
47138414Smckusick 	/*
47252196Smckusick 	 * This is silly, but it has to be set so that vinifod() works.
47352196Smckusick 	 * We do not want to do an nfs_statfs() here since we can get
47452196Smckusick 	 * stuck on a dead server and we are holding a lock on the mount
47552196Smckusick 	 * point.
47652196Smckusick 	 */
47752196Smckusick 	mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
47852196Smckusick 	/*
47940010Smckusick 	 * A reference count is needed on the nfsnode representing the
48040010Smckusick 	 * remote root.  If this object is not persistent, then backward
48140010Smckusick 	 * traversals of the mount point (i.e. "..") will not work if
48240010Smckusick 	 * the nfsnode gets flushed out of the cache. Ufs does not have
48340010Smckusick 	 * this problem, because one can identify root inodes by their
48440010Smckusick 	 * number == ROOTINO (2).
48540010Smckusick 	 */
48640010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
48740010Smckusick 		goto bad;
48846988Smckusick 	*vpp = NFSTOV(np);
48941904Smckusick 
49040353Smckusick 	return (0);
49138414Smckusick bad:
49240120Smckusick 	nfs_disconnect(nmp);
49352196Smckusick 	free((caddr_t)nmp, M_NFSMNT);
49441904Smckusick 	m_freem(nam);
49538414Smckusick 	return (error);
49638414Smckusick }
49738414Smckusick 
49838414Smckusick /*
49938414Smckusick  * unmount system call
50038414Smckusick  */
501*55082Storek int
50248055Smckusick nfs_unmount(mp, mntflags, p)
50338414Smckusick 	struct mount *mp;
50441294Smckusick 	int mntflags;
50548055Smckusick 	struct proc *p;
50638414Smckusick {
50738414Smckusick 	register struct nfsmount *nmp;
50840010Smckusick 	struct nfsnode *np;
50940120Smckusick 	struct vnode *vp;
51048361Smckusick 	int error, flags = 0;
51148361Smckusick 	extern int doforce;
51238414Smckusick 
51348066Smckusick 	if (mntflags & MNT_FORCE) {
51448361Smckusick 		if (!doforce || mp == rootfs)
51548066Smckusick 			return (EINVAL);
51641294Smckusick 		flags |= FORCECLOSE;
51748066Smckusick 	}
51841398Smckusick 	nmp = VFSTONFS(mp);
51938414Smckusick 	/*
52038414Smckusick 	 * Goes something like this..
52140120Smckusick 	 * - Check for activity on the root vnode (other than ourselves).
52240120Smckusick 	 * - Call vflush() to clear out vnodes for this file system,
52340120Smckusick 	 *   except for the root vnode.
52440120Smckusick 	 * - Decrement reference on the vnode representing remote root.
52538414Smckusick 	 * - Close the socket
52638414Smckusick 	 * - Free up the data structures
52738414Smckusick 	 */
52840010Smckusick 	/*
52940010Smckusick 	 * We need to decrement the ref. count on the nfsnode representing
53040010Smckusick 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
53140010Smckusick 	 * has done vput on this vnode, otherwise we would get deadlock!
53240010Smckusick 	 */
53340010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
53440010Smckusick 		return(error);
53540120Smckusick 	vp = NFSTOV(np);
53640120Smckusick 	if (vp->v_usecount > 2) {
53740120Smckusick 		vput(vp);
53840120Smckusick 		return (EBUSY);
53940120Smckusick 	}
54052196Smckusick 
54152196Smckusick 	/*
54252196Smckusick 	 * Must handshake with nqnfs_clientd() if it is active.
54352196Smckusick 	 */
54452196Smckusick 	nmp->nm_flag |= NFSMNT_DISMINPROG;
54552196Smckusick 	while (nmp->nm_inprog != NULLVP)
54652196Smckusick 		(void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
54740120Smckusick 	if (error = vflush(mp, vp, flags)) {
54840120Smckusick 		vput(vp);
54952196Smckusick 		nmp->nm_flag &= ~NFSMNT_DISMINPROG;
55040120Smckusick 		return (error);
55140120Smckusick 	}
55252196Smckusick 
55340010Smckusick 	/*
55452196Smckusick 	 * We are now committed to the unmount.
55552196Smckusick 	 * For NQNFS, let the server daemon free the nfsmount structure.
55640010Smckusick 	 */
55752196Smckusick 	if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
55852196Smckusick 		nmp->nm_flag |= NFSMNT_DISMNT;
55952196Smckusick 
56052196Smckusick 	/*
56152196Smckusick 	 * There are two reference counts to get rid of here.
56252196Smckusick 	 */
56340120Smckusick 	vrele(vp);
56452196Smckusick 	vrele(vp);
56552288Smckusick 	vgone(vp);
56640120Smckusick 	nfs_disconnect(nmp);
56741904Smckusick 	m_freem(nmp->nm_nam);
56852196Smckusick 
56952196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
57052196Smckusick 		free((caddr_t)nmp, M_NFSMNT);
57138414Smckusick 	return (0);
57238414Smckusick }
57338414Smckusick 
57438414Smckusick /*
57538414Smckusick  * Return root of a filesystem
57638414Smckusick  */
577*55082Storek int
57838414Smckusick nfs_root(mp, vpp)
57938414Smckusick 	struct mount *mp;
58038414Smckusick 	struct vnode **vpp;
58138414Smckusick {
58238414Smckusick 	register struct vnode *vp;
58338414Smckusick 	struct nfsmount *nmp;
58438414Smckusick 	struct nfsnode *np;
58538414Smckusick 	int error;
58638414Smckusick 
58741398Smckusick 	nmp = VFSTONFS(mp);
58838414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
58938414Smckusick 		return (error);
59038414Smckusick 	vp = NFSTOV(np);
59138414Smckusick 	vp->v_type = VDIR;
59238414Smckusick 	vp->v_flag = VROOT;
59338414Smckusick 	*vpp = vp;
59438414Smckusick 	return (0);
59538414Smckusick }
59638414Smckusick 
59738884Smacklem extern int syncprt;
59838884Smacklem 
59938414Smckusick /*
60038884Smacklem  * Flush out the buffer cache
60138414Smckusick  */
60239494Smckusick /* ARGSUSED */
603*55082Storek int
60454450Smckusick nfs_sync(mp, waitfor, cred, p)
60538414Smckusick 	struct mount *mp;
60638414Smckusick 	int waitfor;
60754450Smckusick 	struct ucred *cred;
60854450Smckusick 	struct proc *p;
60938414Smckusick {
61054450Smckusick 	register struct vnode *vp;
61154450Smckusick 	int error, allerror = 0;
61254450Smckusick 
61338884Smacklem 	/*
61438884Smacklem 	 * Force stale buffer cache information to be flushed.
61538884Smacklem 	 */
61654450Smckusick loop:
61754450Smckusick 	for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
61854450Smckusick 		/*
61954450Smckusick 		 * If the vnode that we are about to sync is no longer
62054450Smckusick 		 * associated with this mount point, start over.
62154450Smckusick 		 */
62254450Smckusick 		if (vp->v_mount != mp)
62354450Smckusick 			goto loop;
62454450Smckusick 		if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd == NULL)
62554450Smckusick 			continue;
62654450Smckusick 		if (vget(vp))
62754450Smckusick 			goto loop;
62854450Smckusick 		if (error = VOP_FSYNC(vp, cred, waitfor, p))
62954450Smckusick 			allerror = error;
63054450Smckusick 		vput(vp);
63154450Smckusick 	}
63254450Smckusick 	return (allerror);
63338414Smckusick }
63438414Smckusick 
63538414Smckusick /*
63654667Smckusick  * NFS flat namespace lookup.
63754667Smckusick  * Currently unsupported.
63854667Smckusick  */
63954667Smckusick /* ARGSUSED */
64054667Smckusick int
64154667Smckusick nfs_vget(mp, ino, vpp)
64254667Smckusick 	struct mount *mp;
64354667Smckusick 	ino_t ino;
64454667Smckusick 	struct vnode **vpp;
64554667Smckusick {
64654667Smckusick 
64754667Smckusick 	return (EOPNOTSUPP);
64854667Smckusick }
64954667Smckusick 
65054667Smckusick /*
65138414Smckusick  * At this point, this should never happen
65238414Smckusick  */
65339494Smckusick /* ARGSUSED */
654*55082Storek int
65554737Smckusick nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
65654737Smckusick 	register struct mount *mp;
65738414Smckusick 	struct fid *fhp;
65854737Smckusick 	struct mbuf *nam;
65938414Smckusick 	struct vnode **vpp;
66054737Smckusick 	int *exflagsp;
66154737Smckusick 	struct ucred **credanonp;
66238414Smckusick {
66339494Smckusick 
66438414Smckusick 	return (EINVAL);
66538414Smckusick }
66638414Smckusick 
66738414Smckusick /*
66838414Smckusick  * Vnode pointer to File handle, should never happen either
66938414Smckusick  */
67039494Smckusick /* ARGSUSED */
671*55082Storek int
67248055Smckusick nfs_vptofh(vp, fhp)
67348055Smckusick 	struct vnode *vp;
67438414Smckusick 	struct fid *fhp;
67538414Smckusick {
67639494Smckusick 
67738414Smckusick 	return (EINVAL);
67838414Smckusick }
67938884Smacklem 
68038884Smacklem /*
68138884Smacklem  * Vfs start routine, a no-op.
68238884Smacklem  */
68339494Smckusick /* ARGSUSED */
684*55082Storek int
68548055Smckusick nfs_start(mp, flags, p)
68638884Smacklem 	struct mount *mp;
68738884Smacklem 	int flags;
68848055Smckusick 	struct proc *p;
68938884Smacklem {
69039494Smckusick 
69138884Smacklem 	return (0);
69238884Smacklem }
69341294Smckusick 
69441294Smckusick /*
69541294Smckusick  * Do operations associated with quotas, not supported
69641294Smckusick  */
69751574Smckusick /* ARGSUSED */
698*55082Storek int
69948055Smckusick nfs_quotactl(mp, cmd, uid, arg, p)
70041294Smckusick 	struct mount *mp;
70141294Smckusick 	int cmd;
70254450Smckusick 	uid_t uid;
70341294Smckusick 	caddr_t arg;
70448055Smckusick 	struct proc *p;
70541294Smckusick {
70651574Smckusick 
70741294Smckusick 	return (EOPNOTSUPP);
70841294Smckusick }
709