xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 54737)
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*54737Smckusick  *	@(#)nfs_vfsops.c	7.42 (Berkeley) 07/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,
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;
6852196Smckusick void nfs_disconnect(), nfsargs_ntoh();
6938414Smckusick 
7041904Smckusick #define TRUE	1
7141904Smckusick #define	FALSE	0
7241904Smckusick 
7338414Smckusick /*
7441904Smckusick  * nfs statfs call
7541904Smckusick  */
7648055Smckusick nfs_statfs(mp, sbp, p)
7741904Smckusick 	struct mount *mp;
7841904Smckusick 	register struct statfs *sbp;
7948055Smckusick 	struct proc *p;
8041904Smckusick {
8141904Smckusick 	register struct vnode *vp;
8241904Smckusick 	register struct nfsv2_statfs *sfp;
8341904Smckusick 	register caddr_t cp;
8441904Smckusick 	register long t1;
8541904Smckusick 	caddr_t bpos, dpos, cp2;
8641904Smckusick 	u_long xid;
8741904Smckusick 	int error = 0;
8841904Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
8941904Smckusick 	struct nfsmount *nmp;
9041904Smckusick 	struct ucred *cred;
9141904Smckusick 	struct nfsnode *np;
9241904Smckusick 
9341904Smckusick 	nmp = VFSTONFS(mp);
9441904Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
9541904Smckusick 		return (error);
9641904Smckusick 	vp = NFSTOV(np);
9741904Smckusick 	nfsstats.rpccnt[NFSPROC_STATFS]++;
9841904Smckusick 	cred = crget();
9941904Smckusick 	cred->cr_ngroups = 1;
10052196Smckusick 	nfsm_reqhead(vp, NFSPROC_STATFS, NFSX_FH);
10141904Smckusick 	nfsm_fhtom(vp);
10252196Smckusick 	nfsm_request(vp, NFSPROC_STATFS, p, cred);
10352196Smckusick 	nfsm_dissect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
10441904Smckusick 	sbp->f_type = MOUNT_NFS;
10541904Smckusick 	sbp->f_flags = nmp->nm_flag;
10652196Smckusick 	sbp->f_iosize = NFS_MAXDGRAMDATA;
10751940Smckusick 	sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
10841904Smckusick 	sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
10941904Smckusick 	sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
11041904Smckusick 	sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
11141904Smckusick 	sbp->f_files = 0;
11241904Smckusick 	sbp->f_ffree = 0;
11341904Smckusick 	if (sbp != &mp->mnt_stat) {
11441904Smckusick 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
11541904Smckusick 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
11641904Smckusick 	}
11741904Smckusick 	nfsm_reqdone;
11852196Smckusick 	vrele(vp);
11941904Smckusick 	crfree(cred);
12041904Smckusick 	return (error);
12141904Smckusick }
12241904Smckusick 
12341904Smckusick /*
12446988Smckusick  * Mount a remote root fs via. nfs. This depends on the info in the
12546988Smckusick  * nfs_diskless structure that has been filled in properly by some primary
12646988Smckusick  * bootstrap.
12746988Smckusick  * It goes something like this:
12846988Smckusick  * - do enough of "ifconfig" by calling ifioctl() so that the system
12946988Smckusick  *   can talk to the server
13046988Smckusick  * - If nfs_diskless.mygateway is filled in, use that address as
13146988Smckusick  *   a default gateway.
13246988Smckusick  * - hand craft the swap nfs vnode hanging off a fake mount point
13352196Smckusick  *	if swdevt[0].sw_dev == NODEV
13446988Smckusick  * - build the rootfs mount point and call mountnfs() to do the rest.
13538414Smckusick  */
13638414Smckusick nfs_mountroot()
13738414Smckusick {
13846988Smckusick 	register struct mount *mp;
13946988Smckusick 	register struct mbuf *m;
14046988Smckusick 	struct socket *so;
14146988Smckusick 	struct vnode *vp;
14252445Smckusick 	int error, i;
14346988Smckusick 
14446988Smckusick 	/*
14552196Smckusick 	 * Do enough of ifconfig(8) so that the critical net interface can
14646988Smckusick 	 * talk to the server.
14746988Smckusick 	 */
14846988Smckusick 	if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
14946988Smckusick 		panic("nfs ifconf");
15052445Smckusick 	if (ifioctl(so, SIOCAIFADDR, &nfs_diskless.myif, curproc)) /* XXX */
15146988Smckusick 		panic("nfs ifconf2");
15246988Smckusick 	soclose(so);
15346988Smckusick 
15446988Smckusick 	/*
15546988Smckusick 	 * If the gateway field is filled in, set it as the default route.
15646988Smckusick 	 */
15752196Smckusick 	if (nfs_diskless.mygateway.sin_len != 0) {
15852196Smckusick 		struct sockaddr_in sin;
15952196Smckusick 		extern struct sockaddr_in icmpmask;
16046988Smckusick 
16152196Smckusick 		sin.sin_len = sizeof (struct sockaddr_in);
16252196Smckusick 		sin.sin_family = AF_INET;
16352196Smckusick 		sin.sin_addr.s_addr = 0;	/* default */
16452196Smckusick 		in_sockmaskof(sin.sin_addr, &icmpmask);
16552196Smckusick 		if (rtrequest(RTM_ADD, (struct sockaddr *)&sin,
16652196Smckusick 			(struct sockaddr *)&nfs_diskless.mygateway,
16752196Smckusick 			(struct sockaddr *)&icmpmask,
16852196Smckusick 			RTF_UP | RTF_GATEWAY, (struct rtentry **)0))
16946988Smckusick 			panic("nfs root route");
17046988Smckusick 	}
17146988Smckusick 
17246988Smckusick 	/*
17346988Smckusick 	 * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
17446988Smckusick 	 * Create a fake mount point just for the swap vnode so that the
17546988Smckusick 	 * swap file can be on a different server from the rootfs.
17646988Smckusick 	 */
17746988Smckusick 	if (swdevt[0].sw_dev == NODEV) {
17846988Smckusick 		mp = (struct mount *)malloc((u_long)sizeof(struct mount),
17946988Smckusick 			M_MOUNT, M_NOWAIT);
18046988Smckusick 		if (mp == NULL)
18146988Smckusick 			panic("nfs root mount");
18246988Smckusick 		mp->mnt_op = &nfs_vfsops;
18346988Smckusick 		mp->mnt_flag = 0;
18446988Smckusick 		mp->mnt_mounth = NULLVP;
18546988Smckusick 
18646988Smckusick 		/*
18746988Smckusick 		 * Set up the diskless nfs_args for the swap mount point
18846988Smckusick 		 * and then call mountnfs() to mount it.
18946988Smckusick 		 * Since the swap file is not the root dir of a file system,
19046988Smckusick 		 * hack it to a regular file.
19146988Smckusick 		 */
19246988Smckusick 		nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh;
19346988Smckusick 		MGET(m, MT_SONAME, M_DONTWAIT);
19446988Smckusick 		if (m == NULL)
19546988Smckusick 			panic("nfs root mbuf");
19646988Smckusick 		bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t),
19752196Smckusick 			nfs_diskless.swap_saddr.sin_len);
19852196Smckusick 		m->m_len = (int)nfs_diskless.swap_saddr.sin_len;
19952196Smckusick 		nfsargs_ntoh(&nfs_diskless.swap_args);
20046988Smckusick 		if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap",
20146988Smckusick 			nfs_diskless.swap_hostnam, &vp))
20246988Smckusick 			panic("nfs swap");
20346988Smckusick 		vp->v_type = VREG;
20446988Smckusick 		vp->v_flag = 0;
20546988Smckusick 		swapdev_vp = vp;
20646988Smckusick 		VREF(vp);
20746988Smckusick 		swdevt[0].sw_vp = vp;
20852196Smckusick 		swdevt[0].sw_nblks = ntohl(nfs_diskless.swap_nblks);
20946988Smckusick 	}
21046988Smckusick 
21146988Smckusick 	/*
21246988Smckusick 	 * Create the rootfs mount point.
21346988Smckusick 	 */
21446988Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
21546988Smckusick 		M_MOUNT, M_NOWAIT);
21646988Smckusick 	if (mp == NULL)
21746988Smckusick 		panic("nfs root mount2");
21846988Smckusick 	mp->mnt_op = &nfs_vfsops;
21946988Smckusick 	mp->mnt_flag = MNT_RDONLY;
22046988Smckusick 	mp->mnt_mounth = NULLVP;
22146988Smckusick 
22246988Smckusick 	/*
22346988Smckusick 	 * Set up the root fs args and call mountnfs() to do the rest.
22446988Smckusick 	 */
22546988Smckusick 	nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh;
22646988Smckusick 	MGET(m, MT_SONAME, M_DONTWAIT);
22746988Smckusick 	if (m == NULL)
22846988Smckusick 		panic("nfs root mbuf2");
22946988Smckusick 	bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t),
23052196Smckusick 		nfs_diskless.root_saddr.sin_len);
23152196Smckusick 	m->m_len = (int)nfs_diskless.root_saddr.sin_len;
23252196Smckusick 	nfsargs_ntoh(&nfs_diskless.root_args);
23346988Smckusick 	if (mountnfs(&nfs_diskless.root_args, mp, m, "/",
23446988Smckusick 		nfs_diskless.root_hostnam, &vp))
23546988Smckusick 		panic("nfs root");
23646988Smckusick 	if (vfs_lock(mp))
23746988Smckusick 		panic("nfs root2");
23846988Smckusick 	rootfs = mp;
23946988Smckusick 	mp->mnt_next = mp;
24046988Smckusick 	mp->mnt_prev = mp;
24146988Smckusick 	mp->mnt_vnodecovered = NULLVP;
24246988Smckusick 	vfs_unlock(mp);
24346988Smckusick 	rootvp = vp;
24452445Smckusick 
24552445Smckusick 	/*
24652445Smckusick 	 * This is not really an nfs issue, but it is much easier to
24752445Smckusick 	 * set hostname here and then let the "/etc/rc.xxx" files
24852445Smckusick 	 * mount the right /var based upon its preset value.
24952445Smckusick 	 */
25052445Smckusick 	bcopy(nfs_diskless.my_hostnam, hostname, MAXHOSTNAMELEN);
25152445Smckusick 	hostname[MAXHOSTNAMELEN - 1] = '\0';
25252445Smckusick 	for (i = 0; i < MAXHOSTNAMELEN; i++)
25352445Smckusick 		if (hostname[i] == '\0')
25452445Smckusick 			break;
25552445Smckusick 	hostnamelen = i;
25646988Smckusick 	inittodr((time_t)0);	/* There is no time in the nfs fsstat so ?? */
25746988Smckusick 	return (0);
25838414Smckusick }
25938414Smckusick 
26038414Smckusick /*
26152196Smckusick  * Convert the integer fields of the nfs_args structure from net byte order
26252196Smckusick  * to host byte order. Called by nfs_mountroot() above.
26352196Smckusick  */
26452196Smckusick void
26552196Smckusick nfsargs_ntoh(nfsp)
26652196Smckusick 	register struct nfs_args *nfsp;
26752196Smckusick {
26852196Smckusick 
26952196Smckusick 	NTOHL(nfsp->sotype);
27052196Smckusick 	NTOHL(nfsp->proto);
27152196Smckusick 	NTOHL(nfsp->flags);
27252196Smckusick 	NTOHL(nfsp->wsize);
27352196Smckusick 	NTOHL(nfsp->rsize);
27452196Smckusick 	NTOHL(nfsp->timeo);
27552196Smckusick 	NTOHL(nfsp->retrans);
27652196Smckusick 	NTOHL(nfsp->maxgrouplist);
27752196Smckusick 	NTOHL(nfsp->readahead);
27852196Smckusick 	NTOHL(nfsp->leaseterm);
27952196Smckusick 	NTOHL(nfsp->deadthresh);
28052196Smckusick }
28152196Smckusick 
28252196Smckusick /*
28338414Smckusick  * VFS Operations.
28438414Smckusick  *
28538414Smckusick  * mount system call
28638414Smckusick  * It seems a bit dumb to copyinstr() the host and path here and then
28738414Smckusick  * bcopy() them in mountnfs(), but I wanted to detect errors before
28838414Smckusick  * doing the sockargs() call because sockargs() allocates an mbuf and
28938414Smckusick  * an error after that means that I have to release the mbuf.
29038414Smckusick  */
29139494Smckusick /* ARGSUSED */
29248055Smckusick nfs_mount(mp, path, data, ndp, p)
29338414Smckusick 	struct mount *mp;
29438414Smckusick 	char *path;
29538414Smckusick 	caddr_t data;
29638414Smckusick 	struct nameidata *ndp;
29748055Smckusick 	struct proc *p;
29838414Smckusick {
29938414Smckusick 	int error;
30038414Smckusick 	struct nfs_args args;
30141904Smckusick 	struct mbuf *nam;
30246988Smckusick 	struct vnode *vp;
30338414Smckusick 	char pth[MNAMELEN], hst[MNAMELEN];
30449108Skarels 	u_int len;
30538414Smckusick 	nfsv2fh_t nfh;
30638414Smckusick 
30741398Smckusick 	if (mp->mnt_flag & MNT_UPDATE)
30839460Smckusick 		return (0);
30938414Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
31038414Smckusick 		return (error);
31149108Skarels 	if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
31238414Smckusick 		return (error);
31338414Smckusick 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
31438414Smckusick 		return (error);
31549108Skarels 	bzero(&pth[len], MNAMELEN - len);
31638414Smckusick 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
31738414Smckusick 		return (error);
31849108Skarels 	bzero(&hst[len], MNAMELEN - len);
31938414Smckusick 	/* sockargs() call must be after above copyin() calls */
32041904Smckusick 	if (error = sockargs(&nam, (caddr_t)args.addr,
32152196Smckusick 		args.addrlen, MT_SONAME))
32238414Smckusick 		return (error);
32338414Smckusick 	args.fh = &nfh;
32446988Smckusick 	error = mountnfs(&args, mp, nam, pth, hst, &vp);
32538414Smckusick 	return (error);
32638414Smckusick }
32738414Smckusick 
32838414Smckusick /*
32938414Smckusick  * Common code for mount and mountroot
33038414Smckusick  */
33146988Smckusick mountnfs(argp, mp, nam, pth, hst, vpp)
33238414Smckusick 	register struct nfs_args *argp;
33338414Smckusick 	register struct mount *mp;
33441904Smckusick 	struct mbuf *nam;
33538414Smckusick 	char *pth, *hst;
33646988Smckusick 	struct vnode **vpp;
33738414Smckusick {
33838414Smckusick 	register struct nfsmount *nmp;
33940010Smckusick 	struct nfsnode *np;
34040120Smckusick 	int error;
34139757Smckusick 	fsid_t tfsid;
34238414Smckusick 
34352196Smckusick 	MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount), M_NFSMNT,
34452196Smckusick 		M_WAITOK);
34552196Smckusick 	bzero((caddr_t)nmp, sizeof (struct nfsmount));
34641398Smckusick 	mp->mnt_data = (qaddr_t)nmp;
34753937Spendry 	getnewfsid(mp, MOUNT_NFS);
34838414Smckusick 	nmp->nm_mountp = mp;
34938414Smckusick 	nmp->nm_flag = argp->flags;
35052196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) ==
35152196Smckusick 		(NFSMNT_NQNFS | NFSMNT_MYWRITE)) {
35252196Smckusick 		error = EPERM;
35352196Smckusick 		goto bad;
35452196Smckusick 	}
35552196Smckusick 	if ((nmp->nm_flag & (NFSMNT_RDIRALOOK | NFSMNT_LEASETERM)) &&
35652196Smckusick 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0) {
35752196Smckusick 		error = EPERM;
35852196Smckusick 		goto bad;
35952196Smckusick 	}
36052196Smckusick 	nmp->nm_timeo = NFS_TIMEO;
36140120Smckusick 	nmp->nm_retry = NFS_RETRANS;
36240120Smckusick 	nmp->nm_wsize = NFS_WSIZE;
36340120Smckusick 	nmp->nm_rsize = NFS_RSIZE;
36452196Smckusick 	nmp->nm_numgrps = NFS_MAXGRPS;
36552196Smckusick 	nmp->nm_readahead = NFS_DEFRAHEAD;
36652196Smckusick 	nmp->nm_leaseterm = NQ_DEFLEASE;
36752196Smckusick 	nmp->nm_deadthresh = NQ_DEADTHRESH;
36852196Smckusick 	nmp->nm_tnext = (struct nfsnode *)nmp;
36952196Smckusick 	nmp->nm_tprev = (struct nfsnode *)nmp;
37052196Smckusick 	nmp->nm_inprog = NULLVP;
37140120Smckusick 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
37241398Smckusick 	mp->mnt_stat.f_type = MOUNT_NFS;
37341398Smckusick 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
37441398Smckusick 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
37541904Smckusick 	nmp->nm_nam = nam;
37640120Smckusick 
37740120Smckusick 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
37852196Smckusick 		nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
37952196Smckusick 		if (nmp->nm_timeo < NFS_MINTIMEO)
38052196Smckusick 			nmp->nm_timeo = NFS_MINTIMEO;
38152196Smckusick 		else if (nmp->nm_timeo > NFS_MAXTIMEO)
38252196Smckusick 			nmp->nm_timeo = NFS_MAXTIMEO;
38340120Smckusick 	}
38440120Smckusick 
38543355Smckusick 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
38640120Smckusick 		nmp->nm_retry = argp->retrans;
38740120Smckusick 		if (nmp->nm_retry > NFS_MAXREXMIT)
38840120Smckusick 			nmp->nm_retry = NFS_MAXREXMIT;
38940120Smckusick 	}
39040120Smckusick 
39140120Smckusick 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
39238414Smckusick 		nmp->nm_wsize = argp->wsize;
39340120Smckusick 		/* Round down to multiple of blocksize */
39440120Smckusick 		nmp->nm_wsize &= ~0x1ff;
39540120Smckusick 		if (nmp->nm_wsize <= 0)
39640120Smckusick 			nmp->nm_wsize = 512;
39740120Smckusick 		else if (nmp->nm_wsize > NFS_MAXDATA)
39840120Smckusick 			nmp->nm_wsize = NFS_MAXDATA;
39940120Smckusick 	}
40043355Smckusick 	if (nmp->nm_wsize > MAXBSIZE)
40143355Smckusick 		nmp->nm_wsize = MAXBSIZE;
40240120Smckusick 
40340120Smckusick 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
40438414Smckusick 		nmp->nm_rsize = argp->rsize;
40540120Smckusick 		/* Round down to multiple of blocksize */
40640120Smckusick 		nmp->nm_rsize &= ~0x1ff;
40740120Smckusick 		if (nmp->nm_rsize <= 0)
40840120Smckusick 			nmp->nm_rsize = 512;
40940120Smckusick 		else if (nmp->nm_rsize > NFS_MAXDATA)
41040120Smckusick 			nmp->nm_rsize = NFS_MAXDATA;
41140120Smckusick 	}
41243355Smckusick 	if (nmp->nm_rsize > MAXBSIZE)
41343355Smckusick 		nmp->nm_rsize = MAXBSIZE;
41452196Smckusick 	if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
41552196Smckusick 		argp->maxgrouplist <= NFS_MAXGRPS)
41652196Smckusick 		nmp->nm_numgrps = argp->maxgrouplist;
41752196Smckusick 	if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
41852196Smckusick 		argp->readahead <= NFS_MAXRAHEAD)
41952196Smckusick 		nmp->nm_readahead = argp->readahead;
42052196Smckusick 	if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
42152196Smckusick 		argp->leaseterm <= NQ_MAXLEASE)
42252196Smckusick 		nmp->nm_leaseterm = argp->leaseterm;
42352196Smckusick 	if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
42452196Smckusick 		argp->deadthresh <= NQ_NEVERDEAD)
42552196Smckusick 		nmp->nm_deadthresh = argp->deadthresh;
42640120Smckusick 	/* Set up the sockets and per-host congestion */
42741904Smckusick 	nmp->nm_sotype = argp->sotype;
42841904Smckusick 	nmp->nm_soproto = argp->proto;
42952196Smckusick 
43052196Smckusick 	/*
43152196Smckusick 	 * For Connection based sockets (TCP,...) defer the connect until
43252196Smckusick 	 * the first request, in case the server is not responding.
43352196Smckusick 	 */
43452196Smckusick 	if (nmp->nm_sotype == SOCK_DGRAM &&
43552196Smckusick 		(error = nfs_connect(nmp, (struct nfsreq *)0)))
43640120Smckusick 		goto bad;
43740120Smckusick 
43838414Smckusick 	/*
43952196Smckusick 	 * This is silly, but it has to be set so that vinifod() works.
44052196Smckusick 	 * We do not want to do an nfs_statfs() here since we can get
44152196Smckusick 	 * stuck on a dead server and we are holding a lock on the mount
44252196Smckusick 	 * point.
44352196Smckusick 	 */
44452196Smckusick 	mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
44552196Smckusick 	/*
44640010Smckusick 	 * A reference count is needed on the nfsnode representing the
44740010Smckusick 	 * remote root.  If this object is not persistent, then backward
44840010Smckusick 	 * traversals of the mount point (i.e. "..") will not work if
44940010Smckusick 	 * the nfsnode gets flushed out of the cache. Ufs does not have
45040010Smckusick 	 * this problem, because one can identify root inodes by their
45140010Smckusick 	 * number == ROOTINO (2).
45240010Smckusick 	 */
45340010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
45440010Smckusick 		goto bad;
45546988Smckusick 	*vpp = NFSTOV(np);
45641904Smckusick 
45740353Smckusick 	return (0);
45838414Smckusick bad:
45940120Smckusick 	nfs_disconnect(nmp);
46052196Smckusick 	free((caddr_t)nmp, M_NFSMNT);
46141904Smckusick 	m_freem(nam);
46238414Smckusick 	return (error);
46338414Smckusick }
46438414Smckusick 
46538414Smckusick /*
46638414Smckusick  * unmount system call
46738414Smckusick  */
46848055Smckusick nfs_unmount(mp, mntflags, p)
46938414Smckusick 	struct mount *mp;
47041294Smckusick 	int mntflags;
47148055Smckusick 	struct proc *p;
47238414Smckusick {
47338414Smckusick 	register struct nfsmount *nmp;
47440010Smckusick 	struct nfsnode *np;
47540120Smckusick 	struct vnode *vp;
47648361Smckusick 	int error, flags = 0;
47748361Smckusick 	extern int doforce;
47838414Smckusick 
47948066Smckusick 	if (mntflags & MNT_FORCE) {
48048361Smckusick 		if (!doforce || mp == rootfs)
48148066Smckusick 			return (EINVAL);
48241294Smckusick 		flags |= FORCECLOSE;
48348066Smckusick 	}
48441398Smckusick 	nmp = VFSTONFS(mp);
48538414Smckusick 	/*
48638414Smckusick 	 * Goes something like this..
48740120Smckusick 	 * - Check for activity on the root vnode (other than ourselves).
48840120Smckusick 	 * - Call vflush() to clear out vnodes for this file system,
48940120Smckusick 	 *   except for the root vnode.
49040120Smckusick 	 * - Decrement reference on the vnode representing remote root.
49138414Smckusick 	 * - Close the socket
49238414Smckusick 	 * - Free up the data structures
49338414Smckusick 	 */
49440010Smckusick 	/*
49540010Smckusick 	 * We need to decrement the ref. count on the nfsnode representing
49640010Smckusick 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
49740010Smckusick 	 * has done vput on this vnode, otherwise we would get deadlock!
49840010Smckusick 	 */
49940010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
50040010Smckusick 		return(error);
50140120Smckusick 	vp = NFSTOV(np);
50240120Smckusick 	if (vp->v_usecount > 2) {
50340120Smckusick 		vput(vp);
50440120Smckusick 		return (EBUSY);
50540120Smckusick 	}
50652196Smckusick 
50752196Smckusick 	/*
50852196Smckusick 	 * Must handshake with nqnfs_clientd() if it is active.
50952196Smckusick 	 */
51052196Smckusick 	nmp->nm_flag |= NFSMNT_DISMINPROG;
51152196Smckusick 	while (nmp->nm_inprog != NULLVP)
51252196Smckusick 		(void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
51340120Smckusick 	if (error = vflush(mp, vp, flags)) {
51440120Smckusick 		vput(vp);
51552196Smckusick 		nmp->nm_flag &= ~NFSMNT_DISMINPROG;
51640120Smckusick 		return (error);
51740120Smckusick 	}
51852196Smckusick 
51940010Smckusick 	/*
52052196Smckusick 	 * We are now committed to the unmount.
52152196Smckusick 	 * For NQNFS, let the server daemon free the nfsmount structure.
52240010Smckusick 	 */
52352196Smckusick 	if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
52452196Smckusick 		nmp->nm_flag |= NFSMNT_DISMNT;
52552196Smckusick 
52652196Smckusick 	/*
52752196Smckusick 	 * There are two reference counts to get rid of here.
52852196Smckusick 	 */
52940120Smckusick 	vrele(vp);
53052196Smckusick 	vrele(vp);
53152288Smckusick 	vgone(vp);
53240120Smckusick 	nfs_disconnect(nmp);
53341904Smckusick 	m_freem(nmp->nm_nam);
53452196Smckusick 
53552196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
53652196Smckusick 		free((caddr_t)nmp, M_NFSMNT);
53738414Smckusick 	return (0);
53838414Smckusick }
53938414Smckusick 
54038414Smckusick /*
54138414Smckusick  * Return root of a filesystem
54238414Smckusick  */
54338414Smckusick nfs_root(mp, vpp)
54438414Smckusick 	struct mount *mp;
54538414Smckusick 	struct vnode **vpp;
54638414Smckusick {
54738414Smckusick 	register struct vnode *vp;
54838414Smckusick 	struct nfsmount *nmp;
54938414Smckusick 	struct nfsnode *np;
55038414Smckusick 	int error;
55138414Smckusick 
55241398Smckusick 	nmp = VFSTONFS(mp);
55338414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
55438414Smckusick 		return (error);
55538414Smckusick 	vp = NFSTOV(np);
55638414Smckusick 	vp->v_type = VDIR;
55738414Smckusick 	vp->v_flag = VROOT;
55838414Smckusick 	*vpp = vp;
55938414Smckusick 	return (0);
56038414Smckusick }
56138414Smckusick 
56238884Smacklem extern int syncprt;
56338884Smacklem 
56438414Smckusick /*
56538884Smacklem  * Flush out the buffer cache
56638414Smckusick  */
56739494Smckusick /* ARGSUSED */
56854450Smckusick nfs_sync(mp, waitfor, cred, p)
56938414Smckusick 	struct mount *mp;
57038414Smckusick 	int waitfor;
57154450Smckusick 	struct ucred *cred;
57254450Smckusick 	struct proc *p;
57338414Smckusick {
57454450Smckusick 	register struct vnode *vp;
57554450Smckusick 	int error, allerror = 0;
57654450Smckusick 
57738884Smacklem 	/*
57838884Smacklem 	 * Force stale buffer cache information to be flushed.
57938884Smacklem 	 */
58054450Smckusick loop:
58154450Smckusick 	for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
58254450Smckusick 		/*
58354450Smckusick 		 * If the vnode that we are about to sync is no longer
58454450Smckusick 		 * associated with this mount point, start over.
58554450Smckusick 		 */
58654450Smckusick 		if (vp->v_mount != mp)
58754450Smckusick 			goto loop;
58854450Smckusick 		if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd == NULL)
58954450Smckusick 			continue;
59054450Smckusick 		if (vget(vp))
59154450Smckusick 			goto loop;
59254450Smckusick 		if (error = VOP_FSYNC(vp, cred, waitfor, p))
59354450Smckusick 			allerror = error;
59454450Smckusick 		vput(vp);
59554450Smckusick 	}
59654450Smckusick 	return (allerror);
59738414Smckusick }
59838414Smckusick 
59938414Smckusick /*
60054667Smckusick  * NFS flat namespace lookup.
60154667Smckusick  * Currently unsupported.
60254667Smckusick  */
60354667Smckusick /* ARGSUSED */
60454667Smckusick int
60554667Smckusick nfs_vget(mp, ino, vpp)
60654667Smckusick 	struct mount *mp;
60754667Smckusick 	ino_t ino;
60854667Smckusick 	struct vnode **vpp;
60954667Smckusick {
61054667Smckusick 
61154667Smckusick 	return (EOPNOTSUPP);
61254667Smckusick }
61354667Smckusick 
61454667Smckusick /*
61538414Smckusick  * At this point, this should never happen
61638414Smckusick  */
61739494Smckusick /* ARGSUSED */
618*54737Smckusick nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
619*54737Smckusick 	register struct mount *mp;
62038414Smckusick 	struct fid *fhp;
621*54737Smckusick 	struct mbuf *nam;
62238414Smckusick 	struct vnode **vpp;
623*54737Smckusick 	int *exflagsp;
624*54737Smckusick 	struct ucred **credanonp;
62538414Smckusick {
62639494Smckusick 
62738414Smckusick 	return (EINVAL);
62838414Smckusick }
62938414Smckusick 
63038414Smckusick /*
63138414Smckusick  * Vnode pointer to File handle, should never happen either
63238414Smckusick  */
63339494Smckusick /* ARGSUSED */
63448055Smckusick nfs_vptofh(vp, fhp)
63548055Smckusick 	struct vnode *vp;
63638414Smckusick 	struct fid *fhp;
63738414Smckusick {
63839494Smckusick 
63938414Smckusick 	return (EINVAL);
64038414Smckusick }
64138884Smacklem 
64238884Smacklem /*
64338884Smacklem  * Vfs start routine, a no-op.
64438884Smacklem  */
64539494Smckusick /* ARGSUSED */
64648055Smckusick nfs_start(mp, flags, p)
64738884Smacklem 	struct mount *mp;
64838884Smacklem 	int flags;
64948055Smckusick 	struct proc *p;
65038884Smacklem {
65139494Smckusick 
65238884Smacklem 	return (0);
65338884Smacklem }
65441294Smckusick 
65541294Smckusick /*
65641294Smckusick  * Do operations associated with quotas, not supported
65741294Smckusick  */
65851574Smckusick /* ARGSUSED */
65948055Smckusick nfs_quotactl(mp, cmd, uid, arg, p)
66041294Smckusick 	struct mount *mp;
66141294Smckusick 	int cmd;
66254450Smckusick 	uid_t uid;
66341294Smckusick 	caddr_t arg;
66448055Smckusick 	struct proc *p;
66541294Smckusick {
66651574Smckusick 
66741294Smckusick 	return (EOPNOTSUPP);
66841294Smckusick }
669