xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 47573)
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*47573Skarels  *	@(#)nfs_vfsops.c	7.26 (Berkeley) 03/19/91
1138414Smckusick  */
1238414Smckusick 
1338414Smckusick #include "param.h"
1446988Smckusick #include "conf.h"
1546988Smckusick #include "ioctl.h"
1638414Smckusick #include "signal.h"
1738414Smckusick #include "proc.h"
1838414Smckusick #include "vnode.h"
1938414Smckusick #include "mount.h"
2040120Smckusick #include "buf.h"
2138414Smckusick #include "mbuf.h"
2238414Smckusick #include "socket.h"
2340120Smckusick #include "systm.h"
24*47573Skarels 
2546988Smckusick #include "../net/if.h"
2646988Smckusick #include "../net/route.h"
2746988Smckusick #include "../netinet/in.h"
28*47573Skarels 
2938414Smckusick #include "nfsv2.h"
3038414Smckusick #include "nfsnode.h"
3138414Smckusick #include "nfsmount.h"
3238414Smckusick #include "nfs.h"
3341904Smckusick #include "xdr_subs.h"
3441904Smckusick #include "nfsm_subs.h"
3546988Smckusick #include "nfsdiskless.h"
3638414Smckusick 
3738414Smckusick /*
3838414Smckusick  * nfs vfs operations.
3938414Smckusick  */
4038414Smckusick int nfs_mount();
4138874Smckusick int nfs_start();
4238414Smckusick int nfs_unmount();
4338414Smckusick int nfs_root();
4441294Smckusick int nfs_quotactl();
4539443Smckusick int nfs_statfs();
4638414Smckusick int nfs_sync();
4738414Smckusick int nfs_fhtovp();
4838414Smckusick int nfs_vptofh();
4939443Smckusick int nfs_init();
5038414Smckusick 
5138414Smckusick struct vfsops nfs_vfsops = {
5238414Smckusick 	nfs_mount,
5338874Smckusick 	nfs_start,
5438414Smckusick 	nfs_unmount,
5538414Smckusick 	nfs_root,
5641294Smckusick 	nfs_quotactl,
5738414Smckusick 	nfs_statfs,
5838414Smckusick 	nfs_sync,
5938414Smckusick 	nfs_fhtovp,
6038414Smckusick 	nfs_vptofh,
6139443Smckusick 	nfs_init,
6238414Smckusick };
6338414Smckusick 
6439757Smckusick static u_char nfs_mntid;
6541904Smckusick extern u_long nfs_procids[NFS_NPROCS];
6641904Smckusick extern u_long nfs_prog, nfs_vers;
6746988Smckusick struct nfs_diskless nfs_diskless;
6841904Smckusick void nfs_disconnect();
6938414Smckusick 
7041904Smckusick #define TRUE	1
7141904Smckusick #define	FALSE	0
7241904Smckusick 
7338414Smckusick /*
7441904Smckusick  * nfs statfs call
7541904Smckusick  */
7641904Smckusick nfs_statfs(mp, sbp)
7741904Smckusick 	struct mount *mp;
7841904Smckusick 	register struct statfs *sbp;
7941904Smckusick {
8041904Smckusick 	register struct vnode *vp;
8141904Smckusick 	register struct nfsv2_statfs *sfp;
8241904Smckusick 	register caddr_t cp;
8341904Smckusick 	register long t1;
8441904Smckusick 	caddr_t bpos, dpos, cp2;
8541904Smckusick 	u_long xid;
8641904Smckusick 	int error = 0;
8741904Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
8841904Smckusick 	struct nfsmount *nmp;
8941904Smckusick 	struct ucred *cred;
9041904Smckusick 	struct nfsnode *np;
9141904Smckusick 
9241904Smckusick 	nmp = VFSTONFS(mp);
9341904Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
9441904Smckusick 		return (error);
9541904Smckusick 	vp = NFSTOV(np);
9641904Smckusick 	nfsstats.rpccnt[NFSPROC_STATFS]++;
9741904Smckusick 	cred = crget();
9841904Smckusick 	cred->cr_ngroups = 1;
9941904Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH);
10041904Smckusick 	nfsm_fhtom(vp);
101*47573Skarels 	nfsm_request(vp, NFSPROC_STATFS, curproc, 0);
10241904Smckusick 	nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
10341904Smckusick 	sbp->f_type = MOUNT_NFS;
10441904Smckusick 	sbp->f_flags = nmp->nm_flag;
10541904Smckusick 	sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize);
10641904Smckusick 	sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize);
10741904Smckusick 	sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
10841904Smckusick 	sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
10941904Smckusick 	sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
11041904Smckusick 	sbp->f_files = 0;
11141904Smckusick 	sbp->f_ffree = 0;
11241904Smckusick 	if (sbp != &mp->mnt_stat) {
11341904Smckusick 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
11441904Smckusick 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
11541904Smckusick 	}
11641904Smckusick 	nfsm_reqdone;
11741904Smckusick 	nfs_nput(vp);
11841904Smckusick 	crfree(cred);
11941904Smckusick 	return (error);
12041904Smckusick }
12141904Smckusick 
12241904Smckusick /*
12346988Smckusick  * Mount a remote root fs via. nfs. This depends on the info in the
12446988Smckusick  * nfs_diskless structure that has been filled in properly by some primary
12546988Smckusick  * bootstrap.
12646988Smckusick  * It goes something like this:
12746988Smckusick  * - do enough of "ifconfig" by calling ifioctl() so that the system
12846988Smckusick  *   can talk to the server
12946988Smckusick  * - If nfs_diskless.mygateway is filled in, use that address as
13046988Smckusick  *   a default gateway.
13146988Smckusick  *   (This is done the 4.3 way with rtioctl() and should be changed)
13246988Smckusick  * - hand craft the swap nfs vnode hanging off a fake mount point
13346988Smckusick  * - build the rootfs mount point and call mountnfs() to do the rest.
13438414Smckusick  */
13538414Smckusick nfs_mountroot()
13638414Smckusick {
13746988Smckusick 	register struct mount *mp;
13846988Smckusick 	register struct mbuf *m;
13946988Smckusick 	struct socket *so;
14046988Smckusick 	struct vnode *vp;
14146988Smckusick 	int error;
14246988Smckusick 
14346988Smckusick 	/*
14446988Smckusick 	 * Do enough of ifconfig(8) so that critical net interface can
14546988Smckusick 	 * talk to the server.
14646988Smckusick 	 */
14746988Smckusick 	if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
14846988Smckusick 		panic("nfs ifconf");
14946988Smckusick 	if (ifioctl(so, SIOCAIFADDR, &nfs_diskless.myif))
15046988Smckusick 		panic("nfs ifconf2");
15146988Smckusick 	soclose(so);
15246988Smckusick 
15346988Smckusick 	/*
15446988Smckusick 	 * If the gateway field is filled in, set it as the default route.
15546988Smckusick 	 */
15646988Smckusick #ifdef COMPAT_43
15746988Smckusick 	if (nfs_diskless.mygateway.sa_family == AF_INET) {
15846988Smckusick 		struct ortentry rt;
15946988Smckusick 		struct sockaddr_in *sin;
16046988Smckusick 
16146988Smckusick 		sin = (struct sockaddr_in *) &rt.rt_dst;
16246988Smckusick 		sin->sin_len = sizeof (struct sockaddr_in);
16346988Smckusick 		sin->sin_family = AF_INET;
16446988Smckusick 		sin->sin_addr.s_addr = 0;	/* default */
16546988Smckusick 		bcopy((caddr_t)&nfs_diskless.mygateway, (caddr_t)&rt.rt_gateway,
16646988Smckusick 			sizeof (struct sockaddr_in));
16746988Smckusick 		rt.rt_flags = (RTF_UP | RTF_GATEWAY);
16846988Smckusick 		if (rtioctl(SIOCADDRT, (caddr_t)&rt))
16946988Smckusick 			panic("nfs root route");
17046988Smckusick 	}
17146988Smckusick #endif	/* COMPAT_43 */
17246988Smckusick 
17346988Smckusick 	/*
17446988Smckusick 	 * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
17546988Smckusick 	 * Create a fake mount point just for the swap vnode so that the
17646988Smckusick 	 * swap file can be on a different server from the rootfs.
17746988Smckusick 	 */
17846988Smckusick 	if (swdevt[0].sw_dev == NODEV) {
17946988Smckusick 		mp = (struct mount *)malloc((u_long)sizeof(struct mount),
18046988Smckusick 			M_MOUNT, M_NOWAIT);
18146988Smckusick 		if (mp == NULL)
18246988Smckusick 			panic("nfs root mount");
18346988Smckusick 		mp->mnt_op = &nfs_vfsops;
18446988Smckusick 		mp->mnt_flag = 0;
18546988Smckusick 		mp->mnt_exroot = 0;
18646988Smckusick 		mp->mnt_mounth = NULLVP;
18746988Smckusick 
18846988Smckusick 		/*
18946988Smckusick 		 * Set up the diskless nfs_args for the swap mount point
19046988Smckusick 		 * and then call mountnfs() to mount it.
19146988Smckusick 		 * Since the swap file is not the root dir of a file system,
19246988Smckusick 		 * hack it to a regular file.
19346988Smckusick 		 */
19446988Smckusick 		nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh;
19546988Smckusick 		MGET(m, MT_SONAME, M_DONTWAIT);
19646988Smckusick 		if (m == NULL)
19746988Smckusick 			panic("nfs root mbuf");
19846988Smckusick 		bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t),
19946988Smckusick 			nfs_diskless.swap_saddr.sa_len);
20046988Smckusick 		m->m_len = nfs_diskless.swap_saddr.sa_len;
20146988Smckusick 		if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap",
20246988Smckusick 			nfs_diskless.swap_hostnam, &vp))
20346988Smckusick 			panic("nfs swap");
20446988Smckusick 		vp->v_type = VREG;
20546988Smckusick 		vp->v_flag = 0;
20646988Smckusick 		swapdev_vp = vp;
20746988Smckusick 		VREF(vp);
20846988Smckusick 		swdevt[0].sw_vp = vp;
20946988Smckusick 		VREF(vp);
21046988Smckusick 		argdev_vp = vp;
21146988Smckusick 	}
21246988Smckusick 
21346988Smckusick 	/*
21446988Smckusick 	 * Create the rootfs mount point.
21546988Smckusick 	 */
21646988Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
21746988Smckusick 		M_MOUNT, M_NOWAIT);
21846988Smckusick 	if (mp == NULL)
21946988Smckusick 		panic("nfs root mount2");
22046988Smckusick 	mp->mnt_op = &nfs_vfsops;
22146988Smckusick 	mp->mnt_flag = MNT_RDONLY;
22246988Smckusick 	mp->mnt_exroot = 0;
22346988Smckusick 	mp->mnt_mounth = NULLVP;
22446988Smckusick 
22546988Smckusick 	/*
22646988Smckusick 	 * Set up the root fs args and call mountnfs() to do the rest.
22746988Smckusick 	 */
22846988Smckusick 	nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh;
22946988Smckusick 	MGET(m, MT_SONAME, M_DONTWAIT);
23046988Smckusick 	if (m == NULL)
23146988Smckusick 		panic("nfs root mbuf2");
23246988Smckusick 	bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t),
23346988Smckusick 		nfs_diskless.root_saddr.sa_len);
23446988Smckusick 	m->m_len = nfs_diskless.root_saddr.sa_len;
23546988Smckusick 	if (mountnfs(&nfs_diskless.root_args, mp, m, "/",
23646988Smckusick 		nfs_diskless.root_hostnam, &vp))
23746988Smckusick 		panic("nfs root");
23846988Smckusick 	if (vfs_lock(mp))
23946988Smckusick 		panic("nfs root2");
24046988Smckusick 	rootfs = mp;
24146988Smckusick 	mp->mnt_next = mp;
24246988Smckusick 	mp->mnt_prev = mp;
24346988Smckusick 	mp->mnt_vnodecovered = NULLVP;
24446988Smckusick 	vfs_unlock(mp);
24546988Smckusick 	rootvp = vp;
24646988Smckusick 	inittodr((time_t)0);	/* There is no time in the nfs fsstat so ?? */
24746988Smckusick 	return (0);
24838414Smckusick }
24938414Smckusick 
25038414Smckusick /*
25138414Smckusick  * VFS Operations.
25238414Smckusick  *
25338414Smckusick  * mount system call
25438414Smckusick  * It seems a bit dumb to copyinstr() the host and path here and then
25538414Smckusick  * bcopy() them in mountnfs(), but I wanted to detect errors before
25638414Smckusick  * doing the sockargs() call because sockargs() allocates an mbuf and
25738414Smckusick  * an error after that means that I have to release the mbuf.
25838414Smckusick  */
25939494Smckusick /* ARGSUSED */
26038414Smckusick nfs_mount(mp, path, data, ndp)
26138414Smckusick 	struct mount *mp;
26238414Smckusick 	char *path;
26338414Smckusick 	caddr_t data;
26438414Smckusick 	struct nameidata *ndp;
26538414Smckusick {
26638414Smckusick 	int error;
26738414Smckusick 	struct nfs_args args;
26841904Smckusick 	struct mbuf *nam;
26946988Smckusick 	struct vnode *vp;
27038414Smckusick 	char pth[MNAMELEN], hst[MNAMELEN];
27138414Smckusick 	int len;
27238414Smckusick 	nfsv2fh_t nfh;
27338414Smckusick 
27441398Smckusick 	if (mp->mnt_flag & MNT_UPDATE)
27539460Smckusick 		return (0);
27638414Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
27738414Smckusick 		return (error);
27838414Smckusick 	if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
27938414Smckusick 		return (error);
28038414Smckusick 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
28138414Smckusick 		return (error);
28238414Smckusick 	bzero(&pth[len], MNAMELEN-len);
28338414Smckusick 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
28438414Smckusick 		return (error);
28538414Smckusick 	bzero(&hst[len], MNAMELEN-len);
28638414Smckusick 	/* sockargs() call must be after above copyin() calls */
28741904Smckusick 	if (error = sockargs(&nam, (caddr_t)args.addr,
28840120Smckusick 		sizeof (struct sockaddr), MT_SONAME))
28938414Smckusick 		return (error);
29038414Smckusick 	args.fh = &nfh;
29146988Smckusick 	error = mountnfs(&args, mp, nam, pth, hst, &vp);
29238414Smckusick 	return (error);
29338414Smckusick }
29438414Smckusick 
29538414Smckusick /*
29638414Smckusick  * Common code for mount and mountroot
29738414Smckusick  */
29846988Smckusick mountnfs(argp, mp, nam, pth, hst, vpp)
29938414Smckusick 	register struct nfs_args *argp;
30038414Smckusick 	register struct mount *mp;
30141904Smckusick 	struct mbuf *nam;
30238414Smckusick 	char *pth, *hst;
30346988Smckusick 	struct vnode **vpp;
30438414Smckusick {
30538414Smckusick 	register struct nfsmount *nmp;
30640010Smckusick 	struct nfsnode *np;
30740120Smckusick 	int error;
30839757Smckusick 	fsid_t tfsid;
30938414Smckusick 
31040120Smckusick 	MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK);
31140120Smckusick 	bzero((caddr_t)nmp, sizeof *nmp);
31241398Smckusick 	mp->mnt_data = (qaddr_t)nmp;
31339757Smckusick 	/*
31439757Smckusick 	 * Generate a unique nfs mount id. The problem is that a dev number
31539757Smckusick 	 * is not unique across multiple systems. The techique is as follows:
31639757Smckusick 	 * 1) Set to nblkdev,0 which will never be used otherwise
31739757Smckusick 	 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
31839757Smckusick 	 *	NOT 0
31939757Smckusick 	 * 3) Loop searching the mount list for another one with same id
32039757Smckusick 	 *	If a match, increment val[0] and try again
32139757Smckusick 	 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
32239757Smckusick 	 *	so that nfs is not limited to 255 mount points
32339757Smckusick 	 *     Incrementing the high order bits does no real harm, since it
32439757Smckusick 	 *     simply makes the major dev number tick up. The upper bound is
32539757Smckusick 	 *     set to major dev 127 to avoid any sign extention problems
32639757Smckusick 	 */
32741398Smckusick 	mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0);
32841398Smckusick 	mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS;
32939757Smckusick 	if (++nfs_mntid == 0)
33039757Smckusick 		++nfs_mntid;
33139757Smckusick 	tfsid.val[0] = makedev(nblkdev, nfs_mntid);
33239757Smckusick 	tfsid.val[1] = MOUNT_NFS;
33346988Smckusick 	while (rootfs && getvfs(&tfsid)) {
33439757Smckusick 		tfsid.val[0]++;
33539757Smckusick 		nfs_mntid++;
33639757Smckusick 	}
33739757Smckusick 	if (major(tfsid.val[0]) > 127) {
33839757Smckusick 		error = ENOENT;
33939757Smckusick 		goto bad;
34039757Smckusick 	}
34141398Smckusick 	mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
34238414Smckusick 	nmp->nm_mountp = mp;
34338414Smckusick 	nmp->nm_flag = argp->flags;
34440120Smckusick 	nmp->nm_rto = NFS_TIMEO;
34540120Smckusick 	nmp->nm_rtt = -1;
34640120Smckusick 	nmp->nm_rttvar = nmp->nm_rto << 1;
34740120Smckusick 	nmp->nm_retry = NFS_RETRANS;
34840120Smckusick 	nmp->nm_wsize = NFS_WSIZE;
34940120Smckusick 	nmp->nm_rsize = NFS_RSIZE;
35040120Smckusick 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
35141398Smckusick 	mp->mnt_stat.f_type = MOUNT_NFS;
35241398Smckusick 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
35341398Smckusick 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
35441904Smckusick 	nmp->nm_nam = nam;
35540120Smckusick 
35640120Smckusick 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
35740120Smckusick 		nmp->nm_rto = argp->timeo;
35840120Smckusick 		/* NFS timeouts are specified in 1/10 sec. */
35940120Smckusick 		nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ;
36040120Smckusick 		if (nmp->nm_rto < NFS_MINTIMEO)
36140120Smckusick 			nmp->nm_rto = NFS_MINTIMEO;
36240120Smckusick 		else if (nmp->nm_rto > NFS_MAXTIMEO)
36340120Smckusick 			nmp->nm_rto = NFS_MAXTIMEO;
36440120Smckusick 		nmp->nm_rttvar = nmp->nm_rto << 1;
36540120Smckusick 	}
36640120Smckusick 
36743355Smckusick 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
36840120Smckusick 		nmp->nm_retry = argp->retrans;
36940120Smckusick 		if (nmp->nm_retry > NFS_MAXREXMIT)
37040120Smckusick 			nmp->nm_retry = NFS_MAXREXMIT;
37140120Smckusick 	}
37240120Smckusick 
37340120Smckusick 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
37438414Smckusick 		nmp->nm_wsize = argp->wsize;
37540120Smckusick 		/* Round down to multiple of blocksize */
37640120Smckusick 		nmp->nm_wsize &= ~0x1ff;
37740120Smckusick 		if (nmp->nm_wsize <= 0)
37840120Smckusick 			nmp->nm_wsize = 512;
37940120Smckusick 		else if (nmp->nm_wsize > NFS_MAXDATA)
38040120Smckusick 			nmp->nm_wsize = NFS_MAXDATA;
38140120Smckusick 	}
38243355Smckusick 	if (nmp->nm_wsize > MAXBSIZE)
38343355Smckusick 		nmp->nm_wsize = MAXBSIZE;
38440120Smckusick 
38540120Smckusick 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
38638414Smckusick 		nmp->nm_rsize = argp->rsize;
38740120Smckusick 		/* Round down to multiple of blocksize */
38840120Smckusick 		nmp->nm_rsize &= ~0x1ff;
38940120Smckusick 		if (nmp->nm_rsize <= 0)
39040120Smckusick 			nmp->nm_rsize = 512;
39140120Smckusick 		else if (nmp->nm_rsize > NFS_MAXDATA)
39240120Smckusick 			nmp->nm_rsize = NFS_MAXDATA;
39340120Smckusick 	}
39443355Smckusick 	if (nmp->nm_rsize > MAXBSIZE)
39543355Smckusick 		nmp->nm_rsize = MAXBSIZE;
39640120Smckusick 	/* Set up the sockets and per-host congestion */
39741904Smckusick 	nmp->nm_sotype = argp->sotype;
39841904Smckusick 	nmp->nm_soproto = argp->proto;
39941904Smckusick 	if (error = nfs_connect(nmp))
40040120Smckusick 		goto bad;
40140120Smckusick 
40241398Smckusick 	if (error = nfs_statfs(mp, &mp->mnt_stat))
40340353Smckusick 		goto bad;
40438414Smckusick 	/*
40540010Smckusick 	 * A reference count is needed on the nfsnode representing the
40640010Smckusick 	 * remote root.  If this object is not persistent, then backward
40740010Smckusick 	 * traversals of the mount point (i.e. "..") will not work if
40840010Smckusick 	 * the nfsnode gets flushed out of the cache. Ufs does not have
40940010Smckusick 	 * this problem, because one can identify root inodes by their
41040010Smckusick 	 * number == ROOTINO (2).
41140010Smckusick 	 */
41240010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
41340010Smckusick 		goto bad;
41440010Smckusick 	/*
41540010Smckusick 	 * Unlock it, but keep the reference count.
41640010Smckusick 	 */
41740010Smckusick 	nfs_unlock(NFSTOV(np));
41846988Smckusick 	*vpp = NFSTOV(np);
41941904Smckusick 
42040353Smckusick 	return (0);
42138414Smckusick bad:
42240120Smckusick 	nfs_disconnect(nmp);
42340120Smckusick 	FREE(nmp, M_NFSMNT);
42441904Smckusick 	m_freem(nam);
42538414Smckusick 	return (error);
42638414Smckusick }
42738414Smckusick 
42838414Smckusick /*
42938414Smckusick  * unmount system call
43038414Smckusick  */
43141294Smckusick nfs_unmount(mp, mntflags)
43238414Smckusick 	struct mount *mp;
43341294Smckusick 	int mntflags;
43438414Smckusick {
43538414Smckusick 	register struct nfsmount *nmp;
43640010Smckusick 	struct nfsnode *np;
43740120Smckusick 	struct vnode *vp;
43841294Smckusick 	int flags = 0;
43938414Smckusick 	int error;
44038414Smckusick 
44141294Smckusick 	if (mntflags & MNT_FORCE)
44238414Smckusick 		return (EINVAL);
44341294Smckusick 	if (mntflags & MNT_FORCE)
44441294Smckusick 		flags |= FORCECLOSE;
44541398Smckusick 	nmp = VFSTONFS(mp);
44638414Smckusick 	/*
44738884Smacklem 	 * Clear out the buffer cache
44838884Smacklem 	 */
44939669Smckusick 	mntflushbuf(mp, 0);
45039669Smckusick 	if (mntinvalbuf(mp))
45138884Smacklem 		return (EBUSY);
45238884Smacklem 	/*
45338414Smckusick 	 * Goes something like this..
45440120Smckusick 	 * - Check for activity on the root vnode (other than ourselves).
45540120Smckusick 	 * - Call vflush() to clear out vnodes for this file system,
45640120Smckusick 	 *   except for the root vnode.
45740120Smckusick 	 * - Decrement reference on the vnode representing remote root.
45838414Smckusick 	 * - Close the socket
45938414Smckusick 	 * - Free up the data structures
46038414Smckusick 	 */
46140010Smckusick 	/*
46240010Smckusick 	 * We need to decrement the ref. count on the nfsnode representing
46340010Smckusick 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
46440010Smckusick 	 * has done vput on this vnode, otherwise we would get deadlock!
46540010Smckusick 	 */
46640010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
46740010Smckusick 		return(error);
46840120Smckusick 	vp = NFSTOV(np);
46940120Smckusick 	if (vp->v_usecount > 2) {
47040120Smckusick 		vput(vp);
47140120Smckusick 		return (EBUSY);
47240120Smckusick 	}
47340120Smckusick 	if (error = vflush(mp, vp, flags)) {
47440120Smckusick 		vput(vp);
47540120Smckusick 		return (error);
47640120Smckusick 	}
47740010Smckusick 	/*
47840010Smckusick 	 * Get rid of two reference counts, and unlock it on the second.
47940010Smckusick 	 */
48040120Smckusick 	vrele(vp);
48140120Smckusick 	vput(vp);
48240120Smckusick 	nfs_disconnect(nmp);
48341904Smckusick 	m_freem(nmp->nm_nam);
48438414Smckusick 	free((caddr_t)nmp, M_NFSMNT);
48538414Smckusick 	return (0);
48638414Smckusick }
48738414Smckusick 
48838414Smckusick /*
48938414Smckusick  * Return root of a filesystem
49038414Smckusick  */
49138414Smckusick nfs_root(mp, vpp)
49238414Smckusick 	struct mount *mp;
49338414Smckusick 	struct vnode **vpp;
49438414Smckusick {
49538414Smckusick 	register struct vnode *vp;
49638414Smckusick 	struct nfsmount *nmp;
49738414Smckusick 	struct nfsnode *np;
49838414Smckusick 	int error;
49938414Smckusick 
50041398Smckusick 	nmp = VFSTONFS(mp);
50138414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
50238414Smckusick 		return (error);
50338414Smckusick 	vp = NFSTOV(np);
50438414Smckusick 	vp->v_type = VDIR;
50538414Smckusick 	vp->v_flag = VROOT;
50638414Smckusick 	*vpp = vp;
50738414Smckusick 	return (0);
50838414Smckusick }
50938414Smckusick 
51038884Smacklem extern int syncprt;
51138884Smacklem 
51238414Smckusick /*
51338884Smacklem  * Flush out the buffer cache
51438414Smckusick  */
51539494Smckusick /* ARGSUSED */
51638414Smckusick nfs_sync(mp, waitfor)
51738414Smckusick 	struct mount *mp;
51838414Smckusick 	int waitfor;
51938414Smckusick {
52038884Smacklem 	if (syncprt)
52138884Smacklem 		bufstats();
52238884Smacklem 	/*
52338884Smacklem 	 * Force stale buffer cache information to be flushed.
52438884Smacklem 	 */
52540035Smckusick 	mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0);
52638414Smckusick 	return (0);
52738414Smckusick }
52838414Smckusick 
52938414Smckusick /*
53038414Smckusick  * At this point, this should never happen
53138414Smckusick  */
53239494Smckusick /* ARGSUSED */
53338414Smckusick nfs_fhtovp(mp, fhp, vpp)
53438414Smckusick 	struct mount *mp;
53538414Smckusick 	struct fid *fhp;
53638414Smckusick 	struct vnode **vpp;
53738414Smckusick {
53839494Smckusick 
53938414Smckusick 	return (EINVAL);
54038414Smckusick }
54138414Smckusick 
54238414Smckusick /*
54338414Smckusick  * Vnode pointer to File handle, should never happen either
54438414Smckusick  */
54539494Smckusick /* ARGSUSED */
54638414Smckusick nfs_vptofh(mp, fhp, vpp)
54738414Smckusick 	struct mount *mp;
54838414Smckusick 	struct fid *fhp;
54938414Smckusick 	struct vnode **vpp;
55038414Smckusick {
55139494Smckusick 
55238414Smckusick 	return (EINVAL);
55338414Smckusick }
55438884Smacklem 
55538884Smacklem /*
55638884Smacklem  * Vfs start routine, a no-op.
55738884Smacklem  */
55839494Smckusick /* ARGSUSED */
55938884Smacklem nfs_start(mp, flags)
56038884Smacklem 	struct mount *mp;
56138884Smacklem 	int flags;
56238884Smacklem {
56339494Smckusick 
56438884Smacklem 	return (0);
56538884Smacklem }
56641294Smckusick 
56741294Smckusick /*
56841294Smckusick  * Do operations associated with quotas, not supported
56941294Smckusick  */
57041294Smckusick nfs_quotactl(mp, cmd, uid, arg)
57141294Smckusick 	struct mount *mp;
57241294Smckusick 	int cmd;
57341294Smckusick 	uid_t uid;
57441294Smckusick 	caddr_t arg;
57541294Smckusick {
57642245Smckusick #ifdef lint
57742245Smckusick 	mp = mp; cmd = cmd; uid = uid; arg = arg;
57842245Smckusick #endif /* lint */
57941294Smckusick 	return (EOPNOTSUPP);
58041294Smckusick }
581