xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 54985)
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*54985Smckusick  *	@(#)nfs_vfsops.c	7.43 (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;
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 	}
355*54985Smckusick 	if (nmp->nm_flag & (NFSMNT_RDIRALOOK | NFSMNT_LEASETERM)) {
356*54985Smckusick 		if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) {
357*54985Smckusick 			error = EPERM;
358*54985Smckusick 			goto bad;
359*54985Smckusick 		}
360*54985Smckusick 		/*
361*54985Smckusick 		 * We have to set mnt_maxsymlink to a non-zero value so
362*54985Smckusick 		 * that COMPAT_43 routines will know that we are setting
363*54985Smckusick 		 * the d_type field in directories (and can zero it for
364*54985Smckusick 		 * unsuspecting binaries).
365*54985Smckusick 		 */
366*54985Smckusick 		mp->mnt_maxsymlinklen = 1;
36752196Smckusick 	}
36852196Smckusick 	nmp->nm_timeo = NFS_TIMEO;
36940120Smckusick 	nmp->nm_retry = NFS_RETRANS;
37040120Smckusick 	nmp->nm_wsize = NFS_WSIZE;
37140120Smckusick 	nmp->nm_rsize = NFS_RSIZE;
37252196Smckusick 	nmp->nm_numgrps = NFS_MAXGRPS;
37352196Smckusick 	nmp->nm_readahead = NFS_DEFRAHEAD;
37452196Smckusick 	nmp->nm_leaseterm = NQ_DEFLEASE;
37552196Smckusick 	nmp->nm_deadthresh = NQ_DEADTHRESH;
37652196Smckusick 	nmp->nm_tnext = (struct nfsnode *)nmp;
37752196Smckusick 	nmp->nm_tprev = (struct nfsnode *)nmp;
37852196Smckusick 	nmp->nm_inprog = NULLVP;
37940120Smckusick 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
38041398Smckusick 	mp->mnt_stat.f_type = MOUNT_NFS;
38141398Smckusick 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
38241398Smckusick 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
38341904Smckusick 	nmp->nm_nam = nam;
38440120Smckusick 
38540120Smckusick 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
38652196Smckusick 		nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
38752196Smckusick 		if (nmp->nm_timeo < NFS_MINTIMEO)
38852196Smckusick 			nmp->nm_timeo = NFS_MINTIMEO;
38952196Smckusick 		else if (nmp->nm_timeo > NFS_MAXTIMEO)
39052196Smckusick 			nmp->nm_timeo = NFS_MAXTIMEO;
39140120Smckusick 	}
39240120Smckusick 
39343355Smckusick 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
39440120Smckusick 		nmp->nm_retry = argp->retrans;
39540120Smckusick 		if (nmp->nm_retry > NFS_MAXREXMIT)
39640120Smckusick 			nmp->nm_retry = NFS_MAXREXMIT;
39740120Smckusick 	}
39840120Smckusick 
39940120Smckusick 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
40038414Smckusick 		nmp->nm_wsize = argp->wsize;
40140120Smckusick 		/* Round down to multiple of blocksize */
40240120Smckusick 		nmp->nm_wsize &= ~0x1ff;
40340120Smckusick 		if (nmp->nm_wsize <= 0)
40440120Smckusick 			nmp->nm_wsize = 512;
40540120Smckusick 		else if (nmp->nm_wsize > NFS_MAXDATA)
40640120Smckusick 			nmp->nm_wsize = NFS_MAXDATA;
40740120Smckusick 	}
40843355Smckusick 	if (nmp->nm_wsize > MAXBSIZE)
40943355Smckusick 		nmp->nm_wsize = MAXBSIZE;
41040120Smckusick 
41140120Smckusick 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
41238414Smckusick 		nmp->nm_rsize = argp->rsize;
41340120Smckusick 		/* Round down to multiple of blocksize */
41440120Smckusick 		nmp->nm_rsize &= ~0x1ff;
41540120Smckusick 		if (nmp->nm_rsize <= 0)
41640120Smckusick 			nmp->nm_rsize = 512;
41740120Smckusick 		else if (nmp->nm_rsize > NFS_MAXDATA)
41840120Smckusick 			nmp->nm_rsize = NFS_MAXDATA;
41940120Smckusick 	}
42043355Smckusick 	if (nmp->nm_rsize > MAXBSIZE)
42143355Smckusick 		nmp->nm_rsize = MAXBSIZE;
42252196Smckusick 	if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
42352196Smckusick 		argp->maxgrouplist <= NFS_MAXGRPS)
42452196Smckusick 		nmp->nm_numgrps = argp->maxgrouplist;
42552196Smckusick 	if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
42652196Smckusick 		argp->readahead <= NFS_MAXRAHEAD)
42752196Smckusick 		nmp->nm_readahead = argp->readahead;
42852196Smckusick 	if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
42952196Smckusick 		argp->leaseterm <= NQ_MAXLEASE)
43052196Smckusick 		nmp->nm_leaseterm = argp->leaseterm;
43152196Smckusick 	if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
43252196Smckusick 		argp->deadthresh <= NQ_NEVERDEAD)
43352196Smckusick 		nmp->nm_deadthresh = argp->deadthresh;
43440120Smckusick 	/* Set up the sockets and per-host congestion */
43541904Smckusick 	nmp->nm_sotype = argp->sotype;
43641904Smckusick 	nmp->nm_soproto = argp->proto;
43752196Smckusick 
43852196Smckusick 	/*
43952196Smckusick 	 * For Connection based sockets (TCP,...) defer the connect until
44052196Smckusick 	 * the first request, in case the server is not responding.
44152196Smckusick 	 */
44252196Smckusick 	if (nmp->nm_sotype == SOCK_DGRAM &&
44352196Smckusick 		(error = nfs_connect(nmp, (struct nfsreq *)0)))
44440120Smckusick 		goto bad;
44540120Smckusick 
44638414Smckusick 	/*
44752196Smckusick 	 * This is silly, but it has to be set so that vinifod() works.
44852196Smckusick 	 * We do not want to do an nfs_statfs() here since we can get
44952196Smckusick 	 * stuck on a dead server and we are holding a lock on the mount
45052196Smckusick 	 * point.
45152196Smckusick 	 */
45252196Smckusick 	mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
45352196Smckusick 	/*
45440010Smckusick 	 * A reference count is needed on the nfsnode representing the
45540010Smckusick 	 * remote root.  If this object is not persistent, then backward
45640010Smckusick 	 * traversals of the mount point (i.e. "..") will not work if
45740010Smckusick 	 * the nfsnode gets flushed out of the cache. Ufs does not have
45840010Smckusick 	 * this problem, because one can identify root inodes by their
45940010Smckusick 	 * number == ROOTINO (2).
46040010Smckusick 	 */
46140010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
46240010Smckusick 		goto bad;
46346988Smckusick 	*vpp = NFSTOV(np);
46441904Smckusick 
46540353Smckusick 	return (0);
46638414Smckusick bad:
46740120Smckusick 	nfs_disconnect(nmp);
46852196Smckusick 	free((caddr_t)nmp, M_NFSMNT);
46941904Smckusick 	m_freem(nam);
47038414Smckusick 	return (error);
47138414Smckusick }
47238414Smckusick 
47338414Smckusick /*
47438414Smckusick  * unmount system call
47538414Smckusick  */
47648055Smckusick nfs_unmount(mp, mntflags, p)
47738414Smckusick 	struct mount *mp;
47841294Smckusick 	int mntflags;
47948055Smckusick 	struct proc *p;
48038414Smckusick {
48138414Smckusick 	register struct nfsmount *nmp;
48240010Smckusick 	struct nfsnode *np;
48340120Smckusick 	struct vnode *vp;
48448361Smckusick 	int error, flags = 0;
48548361Smckusick 	extern int doforce;
48638414Smckusick 
48748066Smckusick 	if (mntflags & MNT_FORCE) {
48848361Smckusick 		if (!doforce || mp == rootfs)
48948066Smckusick 			return (EINVAL);
49041294Smckusick 		flags |= FORCECLOSE;
49148066Smckusick 	}
49241398Smckusick 	nmp = VFSTONFS(mp);
49338414Smckusick 	/*
49438414Smckusick 	 * Goes something like this..
49540120Smckusick 	 * - Check for activity on the root vnode (other than ourselves).
49640120Smckusick 	 * - Call vflush() to clear out vnodes for this file system,
49740120Smckusick 	 *   except for the root vnode.
49840120Smckusick 	 * - Decrement reference on the vnode representing remote root.
49938414Smckusick 	 * - Close the socket
50038414Smckusick 	 * - Free up the data structures
50138414Smckusick 	 */
50240010Smckusick 	/*
50340010Smckusick 	 * We need to decrement the ref. count on the nfsnode representing
50440010Smckusick 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
50540010Smckusick 	 * has done vput on this vnode, otherwise we would get deadlock!
50640010Smckusick 	 */
50740010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
50840010Smckusick 		return(error);
50940120Smckusick 	vp = NFSTOV(np);
51040120Smckusick 	if (vp->v_usecount > 2) {
51140120Smckusick 		vput(vp);
51240120Smckusick 		return (EBUSY);
51340120Smckusick 	}
51452196Smckusick 
51552196Smckusick 	/*
51652196Smckusick 	 * Must handshake with nqnfs_clientd() if it is active.
51752196Smckusick 	 */
51852196Smckusick 	nmp->nm_flag |= NFSMNT_DISMINPROG;
51952196Smckusick 	while (nmp->nm_inprog != NULLVP)
52052196Smckusick 		(void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
52140120Smckusick 	if (error = vflush(mp, vp, flags)) {
52240120Smckusick 		vput(vp);
52352196Smckusick 		nmp->nm_flag &= ~NFSMNT_DISMINPROG;
52440120Smckusick 		return (error);
52540120Smckusick 	}
52652196Smckusick 
52740010Smckusick 	/*
52852196Smckusick 	 * We are now committed to the unmount.
52952196Smckusick 	 * For NQNFS, let the server daemon free the nfsmount structure.
53040010Smckusick 	 */
53152196Smckusick 	if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
53252196Smckusick 		nmp->nm_flag |= NFSMNT_DISMNT;
53352196Smckusick 
53452196Smckusick 	/*
53552196Smckusick 	 * There are two reference counts to get rid of here.
53652196Smckusick 	 */
53740120Smckusick 	vrele(vp);
53852196Smckusick 	vrele(vp);
53952288Smckusick 	vgone(vp);
54040120Smckusick 	nfs_disconnect(nmp);
54141904Smckusick 	m_freem(nmp->nm_nam);
54252196Smckusick 
54352196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
54452196Smckusick 		free((caddr_t)nmp, M_NFSMNT);
54538414Smckusick 	return (0);
54638414Smckusick }
54738414Smckusick 
54838414Smckusick /*
54938414Smckusick  * Return root of a filesystem
55038414Smckusick  */
55138414Smckusick nfs_root(mp, vpp)
55238414Smckusick 	struct mount *mp;
55338414Smckusick 	struct vnode **vpp;
55438414Smckusick {
55538414Smckusick 	register struct vnode *vp;
55638414Smckusick 	struct nfsmount *nmp;
55738414Smckusick 	struct nfsnode *np;
55838414Smckusick 	int error;
55938414Smckusick 
56041398Smckusick 	nmp = VFSTONFS(mp);
56138414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
56238414Smckusick 		return (error);
56338414Smckusick 	vp = NFSTOV(np);
56438414Smckusick 	vp->v_type = VDIR;
56538414Smckusick 	vp->v_flag = VROOT;
56638414Smckusick 	*vpp = vp;
56738414Smckusick 	return (0);
56838414Smckusick }
56938414Smckusick 
57038884Smacklem extern int syncprt;
57138884Smacklem 
57238414Smckusick /*
57338884Smacklem  * Flush out the buffer cache
57438414Smckusick  */
57539494Smckusick /* ARGSUSED */
57654450Smckusick nfs_sync(mp, waitfor, cred, p)
57738414Smckusick 	struct mount *mp;
57838414Smckusick 	int waitfor;
57954450Smckusick 	struct ucred *cred;
58054450Smckusick 	struct proc *p;
58138414Smckusick {
58254450Smckusick 	register struct vnode *vp;
58354450Smckusick 	int error, allerror = 0;
58454450Smckusick 
58538884Smacklem 	/*
58638884Smacklem 	 * Force stale buffer cache information to be flushed.
58738884Smacklem 	 */
58854450Smckusick loop:
58954450Smckusick 	for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
59054450Smckusick 		/*
59154450Smckusick 		 * If the vnode that we are about to sync is no longer
59254450Smckusick 		 * associated with this mount point, start over.
59354450Smckusick 		 */
59454450Smckusick 		if (vp->v_mount != mp)
59554450Smckusick 			goto loop;
59654450Smckusick 		if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd == NULL)
59754450Smckusick 			continue;
59854450Smckusick 		if (vget(vp))
59954450Smckusick 			goto loop;
60054450Smckusick 		if (error = VOP_FSYNC(vp, cred, waitfor, p))
60154450Smckusick 			allerror = error;
60254450Smckusick 		vput(vp);
60354450Smckusick 	}
60454450Smckusick 	return (allerror);
60538414Smckusick }
60638414Smckusick 
60738414Smckusick /*
60854667Smckusick  * NFS flat namespace lookup.
60954667Smckusick  * Currently unsupported.
61054667Smckusick  */
61154667Smckusick /* ARGSUSED */
61254667Smckusick int
61354667Smckusick nfs_vget(mp, ino, vpp)
61454667Smckusick 	struct mount *mp;
61554667Smckusick 	ino_t ino;
61654667Smckusick 	struct vnode **vpp;
61754667Smckusick {
61854667Smckusick 
61954667Smckusick 	return (EOPNOTSUPP);
62054667Smckusick }
62154667Smckusick 
62254667Smckusick /*
62338414Smckusick  * At this point, this should never happen
62438414Smckusick  */
62539494Smckusick /* ARGSUSED */
62654737Smckusick nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
62754737Smckusick 	register struct mount *mp;
62838414Smckusick 	struct fid *fhp;
62954737Smckusick 	struct mbuf *nam;
63038414Smckusick 	struct vnode **vpp;
63154737Smckusick 	int *exflagsp;
63254737Smckusick 	struct ucred **credanonp;
63338414Smckusick {
63439494Smckusick 
63538414Smckusick 	return (EINVAL);
63638414Smckusick }
63738414Smckusick 
63838414Smckusick /*
63938414Smckusick  * Vnode pointer to File handle, should never happen either
64038414Smckusick  */
64139494Smckusick /* ARGSUSED */
64248055Smckusick nfs_vptofh(vp, fhp)
64348055Smckusick 	struct vnode *vp;
64438414Smckusick 	struct fid *fhp;
64538414Smckusick {
64639494Smckusick 
64738414Smckusick 	return (EINVAL);
64838414Smckusick }
64938884Smacklem 
65038884Smacklem /*
65138884Smacklem  * Vfs start routine, a no-op.
65238884Smacklem  */
65339494Smckusick /* ARGSUSED */
65448055Smckusick nfs_start(mp, flags, p)
65538884Smacklem 	struct mount *mp;
65638884Smacklem 	int flags;
65748055Smckusick 	struct proc *p;
65838884Smacklem {
65939494Smckusick 
66038884Smacklem 	return (0);
66138884Smacklem }
66241294Smckusick 
66341294Smckusick /*
66441294Smckusick  * Do operations associated with quotas, not supported
66541294Smckusick  */
66651574Smckusick /* ARGSUSED */
66748055Smckusick nfs_quotactl(mp, cmd, uid, arg, p)
66841294Smckusick 	struct mount *mp;
66941294Smckusick 	int cmd;
67054450Smckusick 	uid_t uid;
67141294Smckusick 	caddr_t arg;
67248055Smckusick 	struct proc *p;
67341294Smckusick {
67451574Smckusick 
67541294Smckusick 	return (EOPNOTSUPP);
67641294Smckusick }
677