xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 65467)
138414Smckusick /*
263235Sbostic  * Copyright (c) 1989, 1993
363235Sbostic  *	The Regents of the University of California.  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*65467Sbostic  *	@(#)nfs_vfsops.c	8.3 (Berkeley) 01/04/94
1138414Smckusick  */
1238414Smckusick 
1356535Sbostic #include <sys/param.h>
1456535Sbostic #include <sys/conf.h>
1556535Sbostic #include <sys/ioctl.h>
1656535Sbostic #include <sys/signal.h>
1756535Sbostic #include <sys/proc.h>
1856535Sbostic #include <sys/namei.h>
1956535Sbostic #include <sys/vnode.h>
2056535Sbostic #include <sys/kernel.h>
2156535Sbostic #include <sys/mount.h>
2256535Sbostic #include <sys/buf.h>
2356535Sbostic #include <sys/mbuf.h>
2456535Sbostic #include <sys/socket.h>
2556535Sbostic #include <sys/systm.h>
2647573Skarels 
2756535Sbostic #include <net/if.h>
2856535Sbostic #include <net/route.h>
2956535Sbostic #include <netinet/in.h>
3047573Skarels 
3156535Sbostic #include <nfs/rpcv2.h>
3256535Sbostic #include <nfs/nfsv2.h>
3356535Sbostic #include <nfs/nfsnode.h>
3456535Sbostic #include <nfs/nfsmount.h>
3556535Sbostic #include <nfs/nfs.h>
3656535Sbostic #include <nfs/xdr_subs.h>
3756535Sbostic #include <nfs/nfsm_subs.h>
3856535Sbostic #include <nfs/nfsdiskless.h>
3956535Sbostic #include <nfs/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 
6541904Smckusick extern u_long nfs_procids[NFS_NPROCS];
6641904Smckusick extern u_long nfs_prog, nfs_vers;
6755082Storek void nfs_disconnect __P((struct nfsmount *));
6855082Storek void nfsargs_ntoh __P((struct nfs_args *));
6955082Storek static struct mount *nfs_mountdiskless __P((char *, char *, int,
7055082Storek     struct sockaddr_in *, struct nfs_args *, register struct vnode **));
7138414Smckusick 
7241904Smckusick #define TRUE	1
7341904Smckusick #define	FALSE	0
7441904Smckusick 
7538414Smckusick /*
7641904Smckusick  * nfs statfs call
7741904Smckusick  */
7855082Storek int
7948055Smckusick nfs_statfs(mp, sbp, p)
8041904Smckusick 	struct mount *mp;
8141904Smckusick 	register struct statfs *sbp;
8248055Smckusick 	struct proc *p;
8341904Smckusick {
8441904Smckusick 	register struct vnode *vp;
8541904Smckusick 	register struct nfsv2_statfs *sfp;
8641904Smckusick 	register caddr_t cp;
8741904Smckusick 	register long t1;
8841904Smckusick 	caddr_t bpos, dpos, cp2;
8956288Smckusick 	int error = 0, isnq;
9041904Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
9141904Smckusick 	struct nfsmount *nmp;
9241904Smckusick 	struct ucred *cred;
9341904Smckusick 	struct nfsnode *np;
9441904Smckusick 
9541904Smckusick 	nmp = VFSTONFS(mp);
9656288Smckusick 	isnq = (nmp->nm_flag & NFSMNT_NQNFS);
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);
10656288Smckusick 	nfsm_dissect(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq));
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);
11456288Smckusick 	if (isnq) {
11556288Smckusick 		sbp->f_files = fxdr_unsigned(long, sfp->sf_files);
11656288Smckusick 		sbp->f_ffree = fxdr_unsigned(long, sfp->sf_ffree);
11756288Smckusick 	} else {
11856288Smckusick 		sbp->f_files = 0;
11956288Smckusick 		sbp->f_ffree = 0;
12056288Smckusick 	}
12141904Smckusick 	if (sbp != &mp->mnt_stat) {
12241904Smckusick 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
12341904Smckusick 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
12441904Smckusick 	}
12541904Smckusick 	nfsm_reqdone;
12652196Smckusick 	vrele(vp);
12741904Smckusick 	crfree(cred);
12841904Smckusick 	return (error);
12941904Smckusick }
13041904Smckusick 
13141904Smckusick /*
13246988Smckusick  * Mount a remote root fs via. nfs. This depends on the info in the
13346988Smckusick  * nfs_diskless structure that has been filled in properly by some primary
13446988Smckusick  * bootstrap.
13546988Smckusick  * It goes something like this:
13646988Smckusick  * - do enough of "ifconfig" by calling ifioctl() so that the system
13746988Smckusick  *   can talk to the server
13846988Smckusick  * - If nfs_diskless.mygateway is filled in, use that address as
13946988Smckusick  *   a default gateway.
14046988Smckusick  * - hand craft the swap nfs vnode hanging off a fake mount point
14152196Smckusick  *	if swdevt[0].sw_dev == NODEV
14246988Smckusick  * - build the rootfs mount point and call mountnfs() to do the rest.
14338414Smckusick  */
14455082Storek int
14538414Smckusick nfs_mountroot()
14638414Smckusick {
14746988Smckusick 	register struct mount *mp;
14855082Storek 	register struct nfs_diskless *nd = &nfs_diskless;
14946988Smckusick 	struct socket *so;
15046988Smckusick 	struct vnode *vp;
15155082Storek 	struct proc *p = curproc;		/* XXX */
152*65467Sbostic 	int error, i;
15346988Smckusick 
15446988Smckusick 	/*
15555082Storek 	 * XXX time must be non-zero when we init the interface or else
15655082Storek 	 * the arp code will wedge...
15755082Storek 	 */
15855082Storek 	if (time.tv_sec == 0)
15955082Storek 		time.tv_sec = 1;
16055082Storek 
16155082Storek #ifdef notyet
16255082Storek 	/* Set up swap credentials. */
16357790Smckusick 	proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid);
16457790Smckusick 	proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid);
16557790Smckusick 	if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) >
16657790Smckusick 		NGROUPS)
16757790Smckusick 		proc0.p_ucred->cr_ngroups = NGROUPS;
16857790Smckusick 	for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
16957790Smckusick 	    proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]);
17055082Storek #endif
17155082Storek 
17255082Storek 	/*
17352196Smckusick 	 * Do enough of ifconfig(8) so that the critical net interface can
17446988Smckusick 	 * talk to the server.
17546988Smckusick 	 */
17655082Storek 	if (error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
17755082Storek 		panic("nfs_mountroot: socreate: %d", error);
17855082Storek 	if (error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, p))
17955082Storek 		panic("nfs_mountroot: SIOCAIFADDR: %d", error);
18046988Smckusick 	soclose(so);
18146988Smckusick 
18246988Smckusick 	/*
18346988Smckusick 	 * If the gateway field is filled in, set it as the default route.
18446988Smckusick 	 */
18555082Storek 	if (nd->mygateway.sin_len != 0) {
18659005Ssklower 		struct sockaddr_in mask, sin;
18746988Smckusick 
18859005Ssklower 		bzero((caddr_t)&mask, sizeof(mask));
18959005Ssklower 		sin = mask;
19052196Smckusick 		sin.sin_family = AF_INET;
19159005Ssklower 		sin.sin_len = sizeof(sin);
19255082Storek 		if (error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
19355082Storek 		    (struct sockaddr *)&nd->mygateway,
19459005Ssklower 		    (struct sockaddr *)&mask,
19555082Storek 		    RTF_UP | RTF_GATEWAY, (struct rtentry **)0))
19655082Storek 			panic("nfs_mountroot: RTM_ADD: %d", error);
19746988Smckusick 	}
19846988Smckusick 
19946988Smckusick 	/*
20046988Smckusick 	 * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
20146988Smckusick 	 * Create a fake mount point just for the swap vnode so that the
20246988Smckusick 	 * swap file can be on a different server from the rootfs.
20346988Smckusick 	 */
20446988Smckusick 	if (swdevt[0].sw_dev == NODEV) {
20555082Storek 		nd->swap_args.fh = (nfsv2fh_t *)nd->swap_fh;
20655082Storek 		(void) nfs_mountdiskless(nd->swap_hostnam, "/swap", 0,
20755082Storek 		    &nd->swap_saddr, &nd->swap_args, &vp);
20846988Smckusick 
20946988Smckusick 		/*
21046988Smckusick 		 * Since the swap file is not the root dir of a file system,
21146988Smckusick 		 * hack it to a regular file.
21246988Smckusick 		 */
21346988Smckusick 		vp->v_type = VREG;
21446988Smckusick 		vp->v_flag = 0;
21546988Smckusick 		swapdev_vp = vp;
21646988Smckusick 		VREF(vp);
21746988Smckusick 		swdevt[0].sw_vp = vp;
21855082Storek 		swdevt[0].sw_nblks = ntohl(nd->swap_nblks);
21956331Smckusick 	} else if (bdevvp(swapdev, &swapdev_vp))
22056331Smckusick 		panic("nfs_mountroot: can't setup swapdev_vp");
22146988Smckusick 
22246988Smckusick 	/*
22346988Smckusick 	 * Create the rootfs mount point.
22446988Smckusick 	 */
22555082Storek 	nd->root_args.fh = (nfsv2fh_t *)nd->root_fh;
22655082Storek 	mp = nfs_mountdiskless(nd->root_hostnam, "/", MNT_RDONLY,
22755082Storek 	    &nd->root_saddr, &nd->root_args, &vp);
22846988Smckusick 
22946988Smckusick 	if (vfs_lock(mp))
23055082Storek 		panic("nfs_mountroot: vfs_lock");
23165251Smckusick 	TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
23265251Smckusick 	mp->mnt_flag |= MNT_ROOTFS;
23346988Smckusick 	mp->mnt_vnodecovered = NULLVP;
23446988Smckusick 	vfs_unlock(mp);
23546988Smckusick 	rootvp = vp;
23652445Smckusick 
23752445Smckusick 	/*
23852445Smckusick 	 * This is not really an nfs issue, but it is much easier to
23952445Smckusick 	 * set hostname here and then let the "/etc/rc.xxx" files
24052445Smckusick 	 * mount the right /var based upon its preset value.
24152445Smckusick 	 */
24255082Storek 	bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
24352445Smckusick 	hostname[MAXHOSTNAMELEN - 1] = '\0';
24452445Smckusick 	for (i = 0; i < MAXHOSTNAMELEN; i++)
24552445Smckusick 		if (hostname[i] == '\0')
24652445Smckusick 			break;
24752445Smckusick 	hostnamelen = i;
24857790Smckusick 	inittodr(ntohl(nd->root_time));
24946988Smckusick 	return (0);
25038414Smckusick }
25138414Smckusick 
25238414Smckusick /*
25355082Storek  * Internal version of mount system call for diskless setup.
25455082Storek  */
25555082Storek static struct mount *
25655082Storek nfs_mountdiskless(path, which, mountflag, sin, args, vpp)
25755082Storek 	char *path;
25855082Storek 	char *which;
25955082Storek 	int mountflag;
26055082Storek 	struct sockaddr_in *sin;
26155082Storek 	struct nfs_args *args;
26255082Storek 	register struct vnode **vpp;
26355082Storek {
26455082Storek 	register struct mount *mp;
26555082Storek 	register struct mbuf *m;
26655082Storek 	register int error;
26755082Storek 
26855082Storek 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
26955082Storek 	    M_MOUNT, M_NOWAIT);
27055082Storek 	if (mp == NULL)
27155082Storek 		panic("nfs_mountroot: %s mount malloc", which);
27265251Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
27355082Storek 	mp->mnt_op = &nfs_vfsops;
27455082Storek 	mp->mnt_flag = mountflag;
27555082Storek 
27655082Storek 	MGET(m, MT_SONAME, M_DONTWAIT);
27755082Storek 	if (m == NULL)
27855082Storek 		panic("nfs_mountroot: %s mount mbuf", which);
27955082Storek 	bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len);
28055082Storek 	m->m_len = sin->sin_len;
28155082Storek 	nfsargs_ntoh(args);
28255082Storek 	if (error = mountnfs(args, mp, m, which, path, vpp))
28355082Storek 		panic("nfs_mountroot: mount %s on %s: %d", path, which, error);
28455082Storek 
28555082Storek 	return (mp);
28655082Storek }
28755082Storek 
28855082Storek /*
28952196Smckusick  * Convert the integer fields of the nfs_args structure from net byte order
29052196Smckusick  * to host byte order. Called by nfs_mountroot() above.
29152196Smckusick  */
29252196Smckusick void
29352196Smckusick nfsargs_ntoh(nfsp)
29452196Smckusick 	register struct nfs_args *nfsp;
29552196Smckusick {
29652196Smckusick 
29752196Smckusick 	NTOHL(nfsp->sotype);
29852196Smckusick 	NTOHL(nfsp->proto);
29952196Smckusick 	NTOHL(nfsp->flags);
30052196Smckusick 	NTOHL(nfsp->wsize);
30152196Smckusick 	NTOHL(nfsp->rsize);
30252196Smckusick 	NTOHL(nfsp->timeo);
30352196Smckusick 	NTOHL(nfsp->retrans);
30452196Smckusick 	NTOHL(nfsp->maxgrouplist);
30552196Smckusick 	NTOHL(nfsp->readahead);
30652196Smckusick 	NTOHL(nfsp->leaseterm);
30752196Smckusick 	NTOHL(nfsp->deadthresh);
30852196Smckusick }
30952196Smckusick 
31052196Smckusick /*
31138414Smckusick  * VFS Operations.
31238414Smckusick  *
31338414Smckusick  * mount system call
31438414Smckusick  * It seems a bit dumb to copyinstr() the host and path here and then
31538414Smckusick  * bcopy() them in mountnfs(), but I wanted to detect errors before
31638414Smckusick  * doing the sockargs() call because sockargs() allocates an mbuf and
31738414Smckusick  * an error after that means that I have to release the mbuf.
31838414Smckusick  */
31939494Smckusick /* ARGSUSED */
32055082Storek int
32148055Smckusick nfs_mount(mp, path, data, ndp, p)
32238414Smckusick 	struct mount *mp;
32338414Smckusick 	char *path;
32438414Smckusick 	caddr_t data;
32538414Smckusick 	struct nameidata *ndp;
32648055Smckusick 	struct proc *p;
32738414Smckusick {
32838414Smckusick 	int error;
32938414Smckusick 	struct nfs_args args;
33041904Smckusick 	struct mbuf *nam;
33146988Smckusick 	struct vnode *vp;
33238414Smckusick 	char pth[MNAMELEN], hst[MNAMELEN];
33349108Skarels 	u_int len;
33438414Smckusick 	nfsv2fh_t nfh;
33538414Smckusick 
33638414Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
33738414Smckusick 		return (error);
33849108Skarels 	if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
33938414Smckusick 		return (error);
34038414Smckusick 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
34138414Smckusick 		return (error);
34249108Skarels 	bzero(&pth[len], MNAMELEN - len);
34338414Smckusick 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
34438414Smckusick 		return (error);
34549108Skarels 	bzero(&hst[len], MNAMELEN - len);
34638414Smckusick 	/* sockargs() call must be after above copyin() calls */
34741904Smckusick 	if (error = sockargs(&nam, (caddr_t)args.addr,
34852196Smckusick 		args.addrlen, MT_SONAME))
34938414Smckusick 		return (error);
35038414Smckusick 	args.fh = &nfh;
35146988Smckusick 	error = mountnfs(&args, mp, nam, pth, hst, &vp);
35238414Smckusick 	return (error);
35338414Smckusick }
35438414Smckusick 
35538414Smckusick /*
35638414Smckusick  * Common code for mount and mountroot
35738414Smckusick  */
35855082Storek int
35946988Smckusick mountnfs(argp, mp, nam, pth, hst, vpp)
36038414Smckusick 	register struct nfs_args *argp;
36138414Smckusick 	register struct mount *mp;
36241904Smckusick 	struct mbuf *nam;
36338414Smckusick 	char *pth, *hst;
36446988Smckusick 	struct vnode **vpp;
36538414Smckusick {
36638414Smckusick 	register struct nfsmount *nmp;
36740010Smckusick 	struct nfsnode *np;
36840120Smckusick 	int error;
36938414Smckusick 
37055082Storek 	if (mp->mnt_flag & MNT_UPDATE) {
37155082Storek 		nmp = VFSTONFS(mp);
37255082Storek 		/* update paths, file handles, etc, here	XXX */
37355082Storek 		m_freem(nam);
37455082Storek 		return (0);
37555082Storek 	} else {
37655082Storek 		MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
37755082Storek 		    M_NFSMNT, M_WAITOK);
37855082Storek 		bzero((caddr_t)nmp, sizeof (struct nfsmount));
37955082Storek 		mp->mnt_data = (qaddr_t)nmp;
38055082Storek 	}
38153937Spendry 	getnewfsid(mp, MOUNT_NFS);
38238414Smckusick 	nmp->nm_mountp = mp;
38338414Smckusick 	nmp->nm_flag = argp->flags;
38452196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) ==
38552196Smckusick 		(NFSMNT_NQNFS | NFSMNT_MYWRITE)) {
38652196Smckusick 		error = EPERM;
38752196Smckusick 		goto bad;
38852196Smckusick 	}
38959759Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS)
39054985Smckusick 		/*
39154985Smckusick 		 * We have to set mnt_maxsymlink to a non-zero value so
39254985Smckusick 		 * that COMPAT_43 routines will know that we are setting
39354985Smckusick 		 * the d_type field in directories (and can zero it for
39454985Smckusick 		 * unsuspecting binaries).
39554985Smckusick 		 */
39654985Smckusick 		mp->mnt_maxsymlinklen = 1;
39752196Smckusick 	nmp->nm_timeo = NFS_TIMEO;
39840120Smckusick 	nmp->nm_retry = NFS_RETRANS;
39940120Smckusick 	nmp->nm_wsize = NFS_WSIZE;
40040120Smckusick 	nmp->nm_rsize = NFS_RSIZE;
40152196Smckusick 	nmp->nm_numgrps = NFS_MAXGRPS;
40252196Smckusick 	nmp->nm_readahead = NFS_DEFRAHEAD;
40352196Smckusick 	nmp->nm_leaseterm = NQ_DEFLEASE;
40452196Smckusick 	nmp->nm_deadthresh = NQ_DEADTHRESH;
40552196Smckusick 	nmp->nm_tnext = (struct nfsnode *)nmp;
40652196Smckusick 	nmp->nm_tprev = (struct nfsnode *)nmp;
40752196Smckusick 	nmp->nm_inprog = NULLVP;
40840120Smckusick 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
40941398Smckusick 	mp->mnt_stat.f_type = MOUNT_NFS;
41041398Smckusick 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
41141398Smckusick 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
41241904Smckusick 	nmp->nm_nam = nam;
41340120Smckusick 
41440120Smckusick 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
41552196Smckusick 		nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
41652196Smckusick 		if (nmp->nm_timeo < NFS_MINTIMEO)
41752196Smckusick 			nmp->nm_timeo = NFS_MINTIMEO;
41852196Smckusick 		else if (nmp->nm_timeo > NFS_MAXTIMEO)
41952196Smckusick 			nmp->nm_timeo = NFS_MAXTIMEO;
42040120Smckusick 	}
42140120Smckusick 
42243355Smckusick 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
42340120Smckusick 		nmp->nm_retry = argp->retrans;
42440120Smckusick 		if (nmp->nm_retry > NFS_MAXREXMIT)
42540120Smckusick 			nmp->nm_retry = NFS_MAXREXMIT;
42640120Smckusick 	}
42740120Smckusick 
42840120Smckusick 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
42938414Smckusick 		nmp->nm_wsize = argp->wsize;
43040120Smckusick 		/* Round down to multiple of blocksize */
43140120Smckusick 		nmp->nm_wsize &= ~0x1ff;
43240120Smckusick 		if (nmp->nm_wsize <= 0)
43340120Smckusick 			nmp->nm_wsize = 512;
43440120Smckusick 		else if (nmp->nm_wsize > NFS_MAXDATA)
43540120Smckusick 			nmp->nm_wsize = NFS_MAXDATA;
43640120Smckusick 	}
43743355Smckusick 	if (nmp->nm_wsize > MAXBSIZE)
43843355Smckusick 		nmp->nm_wsize = MAXBSIZE;
43940120Smckusick 
44040120Smckusick 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
44138414Smckusick 		nmp->nm_rsize = argp->rsize;
44240120Smckusick 		/* Round down to multiple of blocksize */
44340120Smckusick 		nmp->nm_rsize &= ~0x1ff;
44440120Smckusick 		if (nmp->nm_rsize <= 0)
44540120Smckusick 			nmp->nm_rsize = 512;
44640120Smckusick 		else if (nmp->nm_rsize > NFS_MAXDATA)
44740120Smckusick 			nmp->nm_rsize = NFS_MAXDATA;
44840120Smckusick 	}
44943355Smckusick 	if (nmp->nm_rsize > MAXBSIZE)
45043355Smckusick 		nmp->nm_rsize = MAXBSIZE;
45152196Smckusick 	if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
45252196Smckusick 		argp->maxgrouplist <= NFS_MAXGRPS)
45352196Smckusick 		nmp->nm_numgrps = argp->maxgrouplist;
45452196Smckusick 	if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
45552196Smckusick 		argp->readahead <= NFS_MAXRAHEAD)
45652196Smckusick 		nmp->nm_readahead = argp->readahead;
45752196Smckusick 	if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
45852196Smckusick 		argp->leaseterm <= NQ_MAXLEASE)
45952196Smckusick 		nmp->nm_leaseterm = argp->leaseterm;
46052196Smckusick 	if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
46152196Smckusick 		argp->deadthresh <= NQ_NEVERDEAD)
46252196Smckusick 		nmp->nm_deadthresh = argp->deadthresh;
46340120Smckusick 	/* Set up the sockets and per-host congestion */
46441904Smckusick 	nmp->nm_sotype = argp->sotype;
46541904Smckusick 	nmp->nm_soproto = argp->proto;
46652196Smckusick 
46752196Smckusick 	/*
46852196Smckusick 	 * For Connection based sockets (TCP,...) defer the connect until
46952196Smckusick 	 * the first request, in case the server is not responding.
47052196Smckusick 	 */
47152196Smckusick 	if (nmp->nm_sotype == SOCK_DGRAM &&
47252196Smckusick 		(error = nfs_connect(nmp, (struct nfsreq *)0)))
47340120Smckusick 		goto bad;
47440120Smckusick 
47538414Smckusick 	/*
47652196Smckusick 	 * This is silly, but it has to be set so that vinifod() works.
47752196Smckusick 	 * We do not want to do an nfs_statfs() here since we can get
47852196Smckusick 	 * stuck on a dead server and we are holding a lock on the mount
47952196Smckusick 	 * point.
48052196Smckusick 	 */
48152196Smckusick 	mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
48252196Smckusick 	/*
48340010Smckusick 	 * A reference count is needed on the nfsnode representing the
48440010Smckusick 	 * remote root.  If this object is not persistent, then backward
48540010Smckusick 	 * traversals of the mount point (i.e. "..") will not work if
48640010Smckusick 	 * the nfsnode gets flushed out of the cache. Ufs does not have
48740010Smckusick 	 * this problem, because one can identify root inodes by their
48840010Smckusick 	 * number == ROOTINO (2).
48940010Smckusick 	 */
49040010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
49140010Smckusick 		goto bad;
49246988Smckusick 	*vpp = NFSTOV(np);
49341904Smckusick 
49440353Smckusick 	return (0);
49538414Smckusick bad:
49640120Smckusick 	nfs_disconnect(nmp);
49752196Smckusick 	free((caddr_t)nmp, M_NFSMNT);
49841904Smckusick 	m_freem(nam);
49938414Smckusick 	return (error);
50038414Smckusick }
50138414Smckusick 
50238414Smckusick /*
50338414Smckusick  * unmount system call
50438414Smckusick  */
50555082Storek int
50648055Smckusick nfs_unmount(mp, mntflags, p)
50738414Smckusick 	struct mount *mp;
50841294Smckusick 	int mntflags;
50948055Smckusick 	struct proc *p;
51038414Smckusick {
51138414Smckusick 	register struct nfsmount *nmp;
51240010Smckusick 	struct nfsnode *np;
51340120Smckusick 	struct vnode *vp;
51448361Smckusick 	int error, flags = 0;
51548361Smckusick 	extern int doforce;
51638414Smckusick 
51748066Smckusick 	if (mntflags & MNT_FORCE) {
51865251Smckusick 		if (!doforce || (mp->mnt_flag & MNT_ROOTFS))
51948066Smckusick 			return (EINVAL);
52041294Smckusick 		flags |= FORCECLOSE;
52148066Smckusick 	}
52241398Smckusick 	nmp = VFSTONFS(mp);
52338414Smckusick 	/*
52438414Smckusick 	 * Goes something like this..
52540120Smckusick 	 * - Check for activity on the root vnode (other than ourselves).
52640120Smckusick 	 * - Call vflush() to clear out vnodes for this file system,
52740120Smckusick 	 *   except for the root vnode.
52840120Smckusick 	 * - Decrement reference on the vnode representing remote root.
52938414Smckusick 	 * - Close the socket
53038414Smckusick 	 * - Free up the data structures
53138414Smckusick 	 */
53240010Smckusick 	/*
53340010Smckusick 	 * We need to decrement the ref. count on the nfsnode representing
53440010Smckusick 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
53540010Smckusick 	 * has done vput on this vnode, otherwise we would get deadlock!
53640010Smckusick 	 */
53740010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
53840010Smckusick 		return(error);
53940120Smckusick 	vp = NFSTOV(np);
54040120Smckusick 	if (vp->v_usecount > 2) {
54140120Smckusick 		vput(vp);
54240120Smckusick 		return (EBUSY);
54340120Smckusick 	}
54452196Smckusick 
54552196Smckusick 	/*
54652196Smckusick 	 * Must handshake with nqnfs_clientd() if it is active.
54752196Smckusick 	 */
54852196Smckusick 	nmp->nm_flag |= NFSMNT_DISMINPROG;
54952196Smckusick 	while (nmp->nm_inprog != NULLVP)
55052196Smckusick 		(void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
55140120Smckusick 	if (error = vflush(mp, vp, flags)) {
55240120Smckusick 		vput(vp);
55352196Smckusick 		nmp->nm_flag &= ~NFSMNT_DISMINPROG;
55440120Smckusick 		return (error);
55540120Smckusick 	}
55652196Smckusick 
55740010Smckusick 	/*
55852196Smckusick 	 * We are now committed to the unmount.
55952196Smckusick 	 * For NQNFS, let the server daemon free the nfsmount structure.
56040010Smckusick 	 */
56152196Smckusick 	if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
56252196Smckusick 		nmp->nm_flag |= NFSMNT_DISMNT;
56352196Smckusick 
56452196Smckusick 	/*
56552196Smckusick 	 * There are two reference counts to get rid of here.
56652196Smckusick 	 */
56740120Smckusick 	vrele(vp);
56852196Smckusick 	vrele(vp);
56952288Smckusick 	vgone(vp);
57040120Smckusick 	nfs_disconnect(nmp);
57141904Smckusick 	m_freem(nmp->nm_nam);
57252196Smckusick 
57352196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
57452196Smckusick 		free((caddr_t)nmp, M_NFSMNT);
57538414Smckusick 	return (0);
57638414Smckusick }
57738414Smckusick 
57838414Smckusick /*
57938414Smckusick  * Return root of a filesystem
58038414Smckusick  */
58155082Storek int
58238414Smckusick nfs_root(mp, vpp)
58338414Smckusick 	struct mount *mp;
58438414Smckusick 	struct vnode **vpp;
58538414Smckusick {
58638414Smckusick 	register struct vnode *vp;
58738414Smckusick 	struct nfsmount *nmp;
58838414Smckusick 	struct nfsnode *np;
58938414Smckusick 	int error;
59038414Smckusick 
59141398Smckusick 	nmp = VFSTONFS(mp);
59238414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
59338414Smckusick 		return (error);
59438414Smckusick 	vp = NFSTOV(np);
59538414Smckusick 	vp->v_type = VDIR;
59638414Smckusick 	vp->v_flag = VROOT;
59738414Smckusick 	*vpp = vp;
59838414Smckusick 	return (0);
59938414Smckusick }
60038414Smckusick 
60138884Smacklem extern int syncprt;
60238884Smacklem 
60338414Smckusick /*
60438884Smacklem  * Flush out the buffer cache
60538414Smckusick  */
60639494Smckusick /* ARGSUSED */
60755082Storek int
60854450Smckusick nfs_sync(mp, waitfor, cred, p)
60938414Smckusick 	struct mount *mp;
61038414Smckusick 	int waitfor;
61154450Smckusick 	struct ucred *cred;
61254450Smckusick 	struct proc *p;
61338414Smckusick {
61454450Smckusick 	register struct vnode *vp;
61554450Smckusick 	int error, allerror = 0;
61654450Smckusick 
61738884Smacklem 	/*
61838884Smacklem 	 * Force stale buffer cache information to be flushed.
61938884Smacklem 	 */
62054450Smckusick loop:
62165251Smckusick 	for (vp = mp->mnt_vnodelist.lh_first;
62265251Smckusick 	     vp != NULL;
62365251Smckusick 	     vp = vp->v_mntvnodes.le_next) {
62454450Smckusick 		/*
62554450Smckusick 		 * If the vnode that we are about to sync is no longer
62654450Smckusick 		 * associated with this mount point, start over.
62754450Smckusick 		 */
62854450Smckusick 		if (vp->v_mount != mp)
62954450Smckusick 			goto loop;
63065251Smckusick 		if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL)
63154450Smckusick 			continue;
63265251Smckusick 		if (vget(vp, 1))
63354450Smckusick 			goto loop;
63454450Smckusick 		if (error = VOP_FSYNC(vp, cred, waitfor, p))
63554450Smckusick 			allerror = error;
63654450Smckusick 		vput(vp);
63754450Smckusick 	}
63854450Smckusick 	return (allerror);
63938414Smckusick }
64038414Smckusick 
64138414Smckusick /*
64254667Smckusick  * NFS flat namespace lookup.
64354667Smckusick  * Currently unsupported.
64454667Smckusick  */
64554667Smckusick /* ARGSUSED */
64654667Smckusick int
64754667Smckusick nfs_vget(mp, ino, vpp)
64854667Smckusick 	struct mount *mp;
64954667Smckusick 	ino_t ino;
65054667Smckusick 	struct vnode **vpp;
65154667Smckusick {
65254667Smckusick 
65354667Smckusick 	return (EOPNOTSUPP);
65454667Smckusick }
65554667Smckusick 
65654667Smckusick /*
65738414Smckusick  * At this point, this should never happen
65838414Smckusick  */
65939494Smckusick /* ARGSUSED */
66055082Storek int
66154737Smckusick nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
66254737Smckusick 	register struct mount *mp;
66338414Smckusick 	struct fid *fhp;
66454737Smckusick 	struct mbuf *nam;
66538414Smckusick 	struct vnode **vpp;
66654737Smckusick 	int *exflagsp;
66754737Smckusick 	struct ucred **credanonp;
66838414Smckusick {
66939494Smckusick 
67038414Smckusick 	return (EINVAL);
67138414Smckusick }
67238414Smckusick 
67338414Smckusick /*
67438414Smckusick  * Vnode pointer to File handle, should never happen either
67538414Smckusick  */
67639494Smckusick /* ARGSUSED */
67755082Storek int
67848055Smckusick nfs_vptofh(vp, fhp)
67948055Smckusick 	struct vnode *vp;
68038414Smckusick 	struct fid *fhp;
68138414Smckusick {
68239494Smckusick 
68338414Smckusick 	return (EINVAL);
68438414Smckusick }
68538884Smacklem 
68638884Smacklem /*
68738884Smacklem  * Vfs start routine, a no-op.
68838884Smacklem  */
68939494Smckusick /* ARGSUSED */
69055082Storek int
69148055Smckusick nfs_start(mp, flags, p)
69238884Smacklem 	struct mount *mp;
69338884Smacklem 	int flags;
69448055Smckusick 	struct proc *p;
69538884Smacklem {
69639494Smckusick 
69738884Smacklem 	return (0);
69838884Smacklem }
69941294Smckusick 
70041294Smckusick /*
70141294Smckusick  * Do operations associated with quotas, not supported
70241294Smckusick  */
70351574Smckusick /* ARGSUSED */
70455082Storek int
70548055Smckusick nfs_quotactl(mp, cmd, uid, arg, p)
70641294Smckusick 	struct mount *mp;
70741294Smckusick 	int cmd;
70854450Smckusick 	uid_t uid;
70941294Smckusick 	caddr_t arg;
71048055Smckusick 	struct proc *p;
71141294Smckusick {
71251574Smckusick 
71341294Smckusick 	return (EOPNOTSUPP);
71441294Smckusick }
715