xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 57790)
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*57790Smckusick  *	@(#)nfs_vfsops.c	7.49 (Berkeley) 02/02/93
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 
6539757Smckusick static u_char nfs_mntid;
6641904Smckusick extern u_long nfs_procids[NFS_NPROCS];
6741904Smckusick extern u_long nfs_prog, nfs_vers;
6855082Storek void nfs_disconnect __P((struct nfsmount *));
6955082Storek void nfsargs_ntoh __P((struct nfs_args *));
7055082Storek static struct mount *nfs_mountdiskless __P((char *, char *, int,
7155082Storek     struct sockaddr_in *, struct nfs_args *, register struct vnode **));
7238414Smckusick 
7341904Smckusick #define TRUE	1
7441904Smckusick #define	FALSE	0
7541904Smckusick 
7638414Smckusick /*
7741904Smckusick  * nfs statfs call
7841904Smckusick  */
7955082Storek int
8048055Smckusick nfs_statfs(mp, sbp, p)
8141904Smckusick 	struct mount *mp;
8241904Smckusick 	register struct statfs *sbp;
8348055Smckusick 	struct proc *p;
8441904Smckusick {
8541904Smckusick 	register struct vnode *vp;
8641904Smckusick 	register struct nfsv2_statfs *sfp;
8741904Smckusick 	register caddr_t cp;
8841904Smckusick 	register long t1;
8941904Smckusick 	caddr_t bpos, dpos, cp2;
9056288Smckusick 	int error = 0, isnq;
9141904Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
9241904Smckusick 	struct nfsmount *nmp;
9341904Smckusick 	struct ucred *cred;
9441904Smckusick 	struct nfsnode *np;
9541904Smckusick 
9641904Smckusick 	nmp = VFSTONFS(mp);
9756288Smckusick 	isnq = (nmp->nm_flag & NFSMNT_NQNFS);
9841904Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
9941904Smckusick 		return (error);
10041904Smckusick 	vp = NFSTOV(np);
10141904Smckusick 	nfsstats.rpccnt[NFSPROC_STATFS]++;
10241904Smckusick 	cred = crget();
10341904Smckusick 	cred->cr_ngroups = 1;
10452196Smckusick 	nfsm_reqhead(vp, NFSPROC_STATFS, NFSX_FH);
10541904Smckusick 	nfsm_fhtom(vp);
10652196Smckusick 	nfsm_request(vp, NFSPROC_STATFS, p, cred);
10756288Smckusick 	nfsm_dissect(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq));
10841904Smckusick 	sbp->f_type = MOUNT_NFS;
10941904Smckusick 	sbp->f_flags = nmp->nm_flag;
11052196Smckusick 	sbp->f_iosize = NFS_MAXDGRAMDATA;
11151940Smckusick 	sbp->f_bsize = fxdr_unsigned(long, sfp->sf_bsize);
11241904Smckusick 	sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
11341904Smckusick 	sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
11441904Smckusick 	sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
11556288Smckusick 	if (isnq) {
11656288Smckusick 		sbp->f_files = fxdr_unsigned(long, sfp->sf_files);
11756288Smckusick 		sbp->f_ffree = fxdr_unsigned(long, sfp->sf_ffree);
11856288Smckusick 	} else {
11956288Smckusick 		sbp->f_files = 0;
12056288Smckusick 		sbp->f_ffree = 0;
12156288Smckusick 	}
12241904Smckusick 	if (sbp != &mp->mnt_stat) {
12341904Smckusick 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
12441904Smckusick 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
12541904Smckusick 	}
12641904Smckusick 	nfsm_reqdone;
12752196Smckusick 	vrele(vp);
12841904Smckusick 	crfree(cred);
12941904Smckusick 	return (error);
13041904Smckusick }
13141904Smckusick 
13241904Smckusick /*
13346988Smckusick  * Mount a remote root fs via. nfs. This depends on the info in the
13446988Smckusick  * nfs_diskless structure that has been filled in properly by some primary
13546988Smckusick  * bootstrap.
13646988Smckusick  * It goes something like this:
13746988Smckusick  * - do enough of "ifconfig" by calling ifioctl() so that the system
13846988Smckusick  *   can talk to the server
13946988Smckusick  * - If nfs_diskless.mygateway is filled in, use that address as
14046988Smckusick  *   a default gateway.
14146988Smckusick  * - hand craft the swap nfs vnode hanging off a fake mount point
14252196Smckusick  *	if swdevt[0].sw_dev == NODEV
14346988Smckusick  * - build the rootfs mount point and call mountnfs() to do the rest.
14438414Smckusick  */
14555082Storek int
14638414Smckusick nfs_mountroot()
14738414Smckusick {
14846988Smckusick 	register struct mount *mp;
14955082Storek 	register struct nfs_diskless *nd = &nfs_diskless;
15046988Smckusick 	struct socket *so;
15146988Smckusick 	struct vnode *vp;
15255082Storek 	struct proc *p = curproc;		/* XXX */
15352445Smckusick 	int error, i;
15446988Smckusick 
15546988Smckusick 	/*
15655082Storek 	 * XXX time must be non-zero when we init the interface or else
15755082Storek 	 * the arp code will wedge...
15855082Storek 	 */
15955082Storek 	if (time.tv_sec == 0)
16055082Storek 		time.tv_sec = 1;
16155082Storek 
16255082Storek #ifdef notyet
16355082Storek 	/* Set up swap credentials. */
164*57790Smckusick 	proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid);
165*57790Smckusick 	proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid);
166*57790Smckusick 	if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) >
167*57790Smckusick 		NGROUPS)
168*57790Smckusick 		proc0.p_ucred->cr_ngroups = NGROUPS;
169*57790Smckusick 	for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
170*57790Smckusick 	    proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]);
17155082Storek #endif
17255082Storek 
17355082Storek 	/*
17452196Smckusick 	 * Do enough of ifconfig(8) so that the critical net interface can
17546988Smckusick 	 * talk to the server.
17646988Smckusick 	 */
17755082Storek 	if (error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
17855082Storek 		panic("nfs_mountroot: socreate: %d", error);
17955082Storek 	if (error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, p))
18055082Storek 		panic("nfs_mountroot: SIOCAIFADDR: %d", error);
18146988Smckusick 	soclose(so);
18246988Smckusick 
18346988Smckusick 	/*
18446988Smckusick 	 * If the gateway field is filled in, set it as the default route.
18546988Smckusick 	 */
18655082Storek 	if (nd->mygateway.sin_len != 0) {
18752196Smckusick 		struct sockaddr_in sin;
18852196Smckusick 		extern struct sockaddr_in icmpmask;
18946988Smckusick 
19052196Smckusick 		sin.sin_len = sizeof (struct sockaddr_in);
19152196Smckusick 		sin.sin_family = AF_INET;
19252196Smckusick 		sin.sin_addr.s_addr = 0;	/* default */
19352196Smckusick 		in_sockmaskof(sin.sin_addr, &icmpmask);
19455082Storek 		if (error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
19555082Storek 		    (struct sockaddr *)&nd->mygateway,
19655082Storek 		    (struct sockaddr *)&icmpmask,
19755082Storek 		    RTF_UP | RTF_GATEWAY, (struct rtentry **)0))
19855082Storek 			panic("nfs_mountroot: RTM_ADD: %d", error);
19946988Smckusick 	}
20046988Smckusick 
20146988Smckusick 	/*
20246988Smckusick 	 * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
20346988Smckusick 	 * Create a fake mount point just for the swap vnode so that the
20446988Smckusick 	 * swap file can be on a different server from the rootfs.
20546988Smckusick 	 */
20646988Smckusick 	if (swdevt[0].sw_dev == NODEV) {
20755082Storek 		nd->swap_args.fh = (nfsv2fh_t *)nd->swap_fh;
20855082Storek 		(void) nfs_mountdiskless(nd->swap_hostnam, "/swap", 0,
20955082Storek 		    &nd->swap_saddr, &nd->swap_args, &vp);
21046988Smckusick 
21146988Smckusick 		/*
21246988Smckusick 		 * Since the swap file is not the root dir of a file system,
21346988Smckusick 		 * hack it to a regular file.
21446988Smckusick 		 */
21546988Smckusick 		vp->v_type = VREG;
21646988Smckusick 		vp->v_flag = 0;
21746988Smckusick 		swapdev_vp = vp;
21846988Smckusick 		VREF(vp);
21946988Smckusick 		swdevt[0].sw_vp = vp;
22055082Storek 		swdevt[0].sw_nblks = ntohl(nd->swap_nblks);
22156331Smckusick 	} else if (bdevvp(swapdev, &swapdev_vp))
22256331Smckusick 		panic("nfs_mountroot: can't setup swapdev_vp");
22346988Smckusick 
22446988Smckusick 	/*
22546988Smckusick 	 * Create the rootfs mount point.
22646988Smckusick 	 */
22755082Storek 	nd->root_args.fh = (nfsv2fh_t *)nd->root_fh;
22855082Storek 	mp = nfs_mountdiskless(nd->root_hostnam, "/", MNT_RDONLY,
22955082Storek 	    &nd->root_saddr, &nd->root_args, &vp);
23046988Smckusick 
23146988Smckusick 	if (vfs_lock(mp))
23255082Storek 		panic("nfs_mountroot: vfs_lock");
23346988Smckusick 	rootfs = mp;
23446988Smckusick 	mp->mnt_next = mp;
23546988Smckusick 	mp->mnt_prev = mp;
23646988Smckusick 	mp->mnt_vnodecovered = NULLVP;
23746988Smckusick 	vfs_unlock(mp);
23846988Smckusick 	rootvp = vp;
23952445Smckusick 
24052445Smckusick 	/*
24152445Smckusick 	 * This is not really an nfs issue, but it is much easier to
24252445Smckusick 	 * set hostname here and then let the "/etc/rc.xxx" files
24352445Smckusick 	 * mount the right /var based upon its preset value.
24452445Smckusick 	 */
24555082Storek 	bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
24652445Smckusick 	hostname[MAXHOSTNAMELEN - 1] = '\0';
24752445Smckusick 	for (i = 0; i < MAXHOSTNAMELEN; i++)
24852445Smckusick 		if (hostname[i] == '\0')
24952445Smckusick 			break;
25052445Smckusick 	hostnamelen = i;
251*57790Smckusick 	inittodr(ntohl(nd->root_time));
25246988Smckusick 	return (0);
25338414Smckusick }
25438414Smckusick 
25538414Smckusick /*
25655082Storek  * Internal version of mount system call for diskless setup.
25755082Storek  */
25855082Storek static struct mount *
25955082Storek nfs_mountdiskless(path, which, mountflag, sin, args, vpp)
26055082Storek 	char *path;
26155082Storek 	char *which;
26255082Storek 	int mountflag;
26355082Storek 	struct sockaddr_in *sin;
26455082Storek 	struct nfs_args *args;
26555082Storek 	register struct vnode **vpp;
26655082Storek {
26755082Storek 	register struct mount *mp;
26855082Storek 	register struct mbuf *m;
26955082Storek 	register int error;
27055082Storek 
27155082Storek 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
27255082Storek 	    M_MOUNT, M_NOWAIT);
27355082Storek 	if (mp == NULL)
27455082Storek 		panic("nfs_mountroot: %s mount malloc", which);
27555082Storek 	mp->mnt_op = &nfs_vfsops;
27655082Storek 	mp->mnt_flag = mountflag;
27755082Storek 	mp->mnt_mounth = NULLVP;
27855082Storek 
27955082Storek 	MGET(m, MT_SONAME, M_DONTWAIT);
28055082Storek 	if (m == NULL)
28155082Storek 		panic("nfs_mountroot: %s mount mbuf", which);
28255082Storek 	bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len);
28355082Storek 	m->m_len = sin->sin_len;
28455082Storek 	nfsargs_ntoh(args);
28555082Storek 	if (error = mountnfs(args, mp, m, which, path, vpp))
28655082Storek 		panic("nfs_mountroot: mount %s on %s: %d", path, which, error);
28755082Storek 
28855082Storek 	return (mp);
28955082Storek }
29055082Storek 
29155082Storek /*
29252196Smckusick  * Convert the integer fields of the nfs_args structure from net byte order
29352196Smckusick  * to host byte order. Called by nfs_mountroot() above.
29452196Smckusick  */
29552196Smckusick void
29652196Smckusick nfsargs_ntoh(nfsp)
29752196Smckusick 	register struct nfs_args *nfsp;
29852196Smckusick {
29952196Smckusick 
30052196Smckusick 	NTOHL(nfsp->sotype);
30152196Smckusick 	NTOHL(nfsp->proto);
30252196Smckusick 	NTOHL(nfsp->flags);
30352196Smckusick 	NTOHL(nfsp->wsize);
30452196Smckusick 	NTOHL(nfsp->rsize);
30552196Smckusick 	NTOHL(nfsp->timeo);
30652196Smckusick 	NTOHL(nfsp->retrans);
30752196Smckusick 	NTOHL(nfsp->maxgrouplist);
30852196Smckusick 	NTOHL(nfsp->readahead);
30952196Smckusick 	NTOHL(nfsp->leaseterm);
31052196Smckusick 	NTOHL(nfsp->deadthresh);
31152196Smckusick }
31252196Smckusick 
31352196Smckusick /*
31438414Smckusick  * VFS Operations.
31538414Smckusick  *
31638414Smckusick  * mount system call
31738414Smckusick  * It seems a bit dumb to copyinstr() the host and path here and then
31838414Smckusick  * bcopy() them in mountnfs(), but I wanted to detect errors before
31938414Smckusick  * doing the sockargs() call because sockargs() allocates an mbuf and
32038414Smckusick  * an error after that means that I have to release the mbuf.
32138414Smckusick  */
32239494Smckusick /* ARGSUSED */
32355082Storek int
32448055Smckusick nfs_mount(mp, path, data, ndp, p)
32538414Smckusick 	struct mount *mp;
32638414Smckusick 	char *path;
32738414Smckusick 	caddr_t data;
32838414Smckusick 	struct nameidata *ndp;
32948055Smckusick 	struct proc *p;
33038414Smckusick {
33138414Smckusick 	int error;
33238414Smckusick 	struct nfs_args args;
33341904Smckusick 	struct mbuf *nam;
33446988Smckusick 	struct vnode *vp;
33538414Smckusick 	char pth[MNAMELEN], hst[MNAMELEN];
33649108Skarels 	u_int len;
33738414Smckusick 	nfsv2fh_t nfh;
33838414Smckusick 
33938414Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
34038414Smckusick 		return (error);
34149108Skarels 	if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
34238414Smckusick 		return (error);
34338414Smckusick 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
34438414Smckusick 		return (error);
34549108Skarels 	bzero(&pth[len], MNAMELEN - len);
34638414Smckusick 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
34738414Smckusick 		return (error);
34849108Skarels 	bzero(&hst[len], MNAMELEN - len);
34938414Smckusick 	/* sockargs() call must be after above copyin() calls */
35041904Smckusick 	if (error = sockargs(&nam, (caddr_t)args.addr,
35152196Smckusick 		args.addrlen, MT_SONAME))
35238414Smckusick 		return (error);
35338414Smckusick 	args.fh = &nfh;
35446988Smckusick 	error = mountnfs(&args, mp, nam, pth, hst, &vp);
35538414Smckusick 	return (error);
35638414Smckusick }
35738414Smckusick 
35838414Smckusick /*
35938414Smckusick  * Common code for mount and mountroot
36038414Smckusick  */
36155082Storek int
36246988Smckusick mountnfs(argp, mp, nam, pth, hst, vpp)
36338414Smckusick 	register struct nfs_args *argp;
36438414Smckusick 	register struct mount *mp;
36541904Smckusick 	struct mbuf *nam;
36638414Smckusick 	char *pth, *hst;
36746988Smckusick 	struct vnode **vpp;
36838414Smckusick {
36938414Smckusick 	register struct nfsmount *nmp;
37040010Smckusick 	struct nfsnode *np;
37140120Smckusick 	int error;
37239757Smckusick 	fsid_t tfsid;
37338414Smckusick 
37455082Storek 	if (mp->mnt_flag & MNT_UPDATE) {
37555082Storek 		nmp = VFSTONFS(mp);
37655082Storek 		/* update paths, file handles, etc, here	XXX */
37755082Storek 		m_freem(nam);
37855082Storek 		return (0);
37955082Storek 	} else {
38055082Storek 		MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
38155082Storek 		    M_NFSMNT, M_WAITOK);
38255082Storek 		bzero((caddr_t)nmp, sizeof (struct nfsmount));
38355082Storek 		mp->mnt_data = (qaddr_t)nmp;
38455082Storek 	}
38553937Spendry 	getnewfsid(mp, MOUNT_NFS);
38638414Smckusick 	nmp->nm_mountp = mp;
38738414Smckusick 	nmp->nm_flag = argp->flags;
38852196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) ==
38952196Smckusick 		(NFSMNT_NQNFS | NFSMNT_MYWRITE)) {
39052196Smckusick 		error = EPERM;
39152196Smckusick 		goto bad;
39252196Smckusick 	}
39354985Smckusick 	if (nmp->nm_flag & (NFSMNT_RDIRALOOK | NFSMNT_LEASETERM)) {
39454985Smckusick 		if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) {
39554985Smckusick 			error = EPERM;
39654985Smckusick 			goto bad;
39754985Smckusick 		}
39854985Smckusick 		/*
39954985Smckusick 		 * We have to set mnt_maxsymlink to a non-zero value so
40054985Smckusick 		 * that COMPAT_43 routines will know that we are setting
40154985Smckusick 		 * the d_type field in directories (and can zero it for
40254985Smckusick 		 * unsuspecting binaries).
40354985Smckusick 		 */
40454985Smckusick 		mp->mnt_maxsymlinklen = 1;
40552196Smckusick 	}
40652196Smckusick 	nmp->nm_timeo = NFS_TIMEO;
40740120Smckusick 	nmp->nm_retry = NFS_RETRANS;
40840120Smckusick 	nmp->nm_wsize = NFS_WSIZE;
40940120Smckusick 	nmp->nm_rsize = NFS_RSIZE;
41052196Smckusick 	nmp->nm_numgrps = NFS_MAXGRPS;
41152196Smckusick 	nmp->nm_readahead = NFS_DEFRAHEAD;
41252196Smckusick 	nmp->nm_leaseterm = NQ_DEFLEASE;
41352196Smckusick 	nmp->nm_deadthresh = NQ_DEADTHRESH;
41452196Smckusick 	nmp->nm_tnext = (struct nfsnode *)nmp;
41552196Smckusick 	nmp->nm_tprev = (struct nfsnode *)nmp;
41652196Smckusick 	nmp->nm_inprog = NULLVP;
41740120Smckusick 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
41841398Smckusick 	mp->mnt_stat.f_type = MOUNT_NFS;
41941398Smckusick 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
42041398Smckusick 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
42141904Smckusick 	nmp->nm_nam = nam;
42240120Smckusick 
42340120Smckusick 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
42452196Smckusick 		nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
42552196Smckusick 		if (nmp->nm_timeo < NFS_MINTIMEO)
42652196Smckusick 			nmp->nm_timeo = NFS_MINTIMEO;
42752196Smckusick 		else if (nmp->nm_timeo > NFS_MAXTIMEO)
42852196Smckusick 			nmp->nm_timeo = NFS_MAXTIMEO;
42940120Smckusick 	}
43040120Smckusick 
43143355Smckusick 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
43240120Smckusick 		nmp->nm_retry = argp->retrans;
43340120Smckusick 		if (nmp->nm_retry > NFS_MAXREXMIT)
43440120Smckusick 			nmp->nm_retry = NFS_MAXREXMIT;
43540120Smckusick 	}
43640120Smckusick 
43740120Smckusick 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
43838414Smckusick 		nmp->nm_wsize = argp->wsize;
43940120Smckusick 		/* Round down to multiple of blocksize */
44040120Smckusick 		nmp->nm_wsize &= ~0x1ff;
44140120Smckusick 		if (nmp->nm_wsize <= 0)
44240120Smckusick 			nmp->nm_wsize = 512;
44340120Smckusick 		else if (nmp->nm_wsize > NFS_MAXDATA)
44440120Smckusick 			nmp->nm_wsize = NFS_MAXDATA;
44540120Smckusick 	}
44643355Smckusick 	if (nmp->nm_wsize > MAXBSIZE)
44743355Smckusick 		nmp->nm_wsize = MAXBSIZE;
44840120Smckusick 
44940120Smckusick 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
45038414Smckusick 		nmp->nm_rsize = argp->rsize;
45140120Smckusick 		/* Round down to multiple of blocksize */
45240120Smckusick 		nmp->nm_rsize &= ~0x1ff;
45340120Smckusick 		if (nmp->nm_rsize <= 0)
45440120Smckusick 			nmp->nm_rsize = 512;
45540120Smckusick 		else if (nmp->nm_rsize > NFS_MAXDATA)
45640120Smckusick 			nmp->nm_rsize = NFS_MAXDATA;
45740120Smckusick 	}
45843355Smckusick 	if (nmp->nm_rsize > MAXBSIZE)
45943355Smckusick 		nmp->nm_rsize = MAXBSIZE;
46052196Smckusick 	if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
46152196Smckusick 		argp->maxgrouplist <= NFS_MAXGRPS)
46252196Smckusick 		nmp->nm_numgrps = argp->maxgrouplist;
46352196Smckusick 	if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
46452196Smckusick 		argp->readahead <= NFS_MAXRAHEAD)
46552196Smckusick 		nmp->nm_readahead = argp->readahead;
46652196Smckusick 	if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
46752196Smckusick 		argp->leaseterm <= NQ_MAXLEASE)
46852196Smckusick 		nmp->nm_leaseterm = argp->leaseterm;
46952196Smckusick 	if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
47052196Smckusick 		argp->deadthresh <= NQ_NEVERDEAD)
47152196Smckusick 		nmp->nm_deadthresh = argp->deadthresh;
47240120Smckusick 	/* Set up the sockets and per-host congestion */
47341904Smckusick 	nmp->nm_sotype = argp->sotype;
47441904Smckusick 	nmp->nm_soproto = argp->proto;
47552196Smckusick 
47652196Smckusick 	/*
47752196Smckusick 	 * For Connection based sockets (TCP,...) defer the connect until
47852196Smckusick 	 * the first request, in case the server is not responding.
47952196Smckusick 	 */
48052196Smckusick 	if (nmp->nm_sotype == SOCK_DGRAM &&
48152196Smckusick 		(error = nfs_connect(nmp, (struct nfsreq *)0)))
48240120Smckusick 		goto bad;
48340120Smckusick 
48438414Smckusick 	/*
48552196Smckusick 	 * This is silly, but it has to be set so that vinifod() works.
48652196Smckusick 	 * We do not want to do an nfs_statfs() here since we can get
48752196Smckusick 	 * stuck on a dead server and we are holding a lock on the mount
48852196Smckusick 	 * point.
48952196Smckusick 	 */
49052196Smckusick 	mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
49152196Smckusick 	/*
49240010Smckusick 	 * A reference count is needed on the nfsnode representing the
49340010Smckusick 	 * remote root.  If this object is not persistent, then backward
49440010Smckusick 	 * traversals of the mount point (i.e. "..") will not work if
49540010Smckusick 	 * the nfsnode gets flushed out of the cache. Ufs does not have
49640010Smckusick 	 * this problem, because one can identify root inodes by their
49740010Smckusick 	 * number == ROOTINO (2).
49840010Smckusick 	 */
49940010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
50040010Smckusick 		goto bad;
50146988Smckusick 	*vpp = NFSTOV(np);
50241904Smckusick 
50340353Smckusick 	return (0);
50438414Smckusick bad:
50540120Smckusick 	nfs_disconnect(nmp);
50652196Smckusick 	free((caddr_t)nmp, M_NFSMNT);
50741904Smckusick 	m_freem(nam);
50838414Smckusick 	return (error);
50938414Smckusick }
51038414Smckusick 
51138414Smckusick /*
51238414Smckusick  * unmount system call
51338414Smckusick  */
51455082Storek int
51548055Smckusick nfs_unmount(mp, mntflags, p)
51638414Smckusick 	struct mount *mp;
51741294Smckusick 	int mntflags;
51848055Smckusick 	struct proc *p;
51938414Smckusick {
52038414Smckusick 	register struct nfsmount *nmp;
52140010Smckusick 	struct nfsnode *np;
52240120Smckusick 	struct vnode *vp;
52348361Smckusick 	int error, flags = 0;
52448361Smckusick 	extern int doforce;
52538414Smckusick 
52648066Smckusick 	if (mntflags & MNT_FORCE) {
52748361Smckusick 		if (!doforce || mp == rootfs)
52848066Smckusick 			return (EINVAL);
52941294Smckusick 		flags |= FORCECLOSE;
53048066Smckusick 	}
53141398Smckusick 	nmp = VFSTONFS(mp);
53238414Smckusick 	/*
53338414Smckusick 	 * Goes something like this..
53440120Smckusick 	 * - Check for activity on the root vnode (other than ourselves).
53540120Smckusick 	 * - Call vflush() to clear out vnodes for this file system,
53640120Smckusick 	 *   except for the root vnode.
53740120Smckusick 	 * - Decrement reference on the vnode representing remote root.
53838414Smckusick 	 * - Close the socket
53938414Smckusick 	 * - Free up the data structures
54038414Smckusick 	 */
54140010Smckusick 	/*
54240010Smckusick 	 * We need to decrement the ref. count on the nfsnode representing
54340010Smckusick 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
54440010Smckusick 	 * has done vput on this vnode, otherwise we would get deadlock!
54540010Smckusick 	 */
54640010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
54740010Smckusick 		return(error);
54840120Smckusick 	vp = NFSTOV(np);
54940120Smckusick 	if (vp->v_usecount > 2) {
55040120Smckusick 		vput(vp);
55140120Smckusick 		return (EBUSY);
55240120Smckusick 	}
55352196Smckusick 
55452196Smckusick 	/*
55552196Smckusick 	 * Must handshake with nqnfs_clientd() if it is active.
55652196Smckusick 	 */
55752196Smckusick 	nmp->nm_flag |= NFSMNT_DISMINPROG;
55852196Smckusick 	while (nmp->nm_inprog != NULLVP)
55952196Smckusick 		(void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
56040120Smckusick 	if (error = vflush(mp, vp, flags)) {
56140120Smckusick 		vput(vp);
56252196Smckusick 		nmp->nm_flag &= ~NFSMNT_DISMINPROG;
56340120Smckusick 		return (error);
56440120Smckusick 	}
56552196Smckusick 
56640010Smckusick 	/*
56752196Smckusick 	 * We are now committed to the unmount.
56852196Smckusick 	 * For NQNFS, let the server daemon free the nfsmount structure.
56940010Smckusick 	 */
57052196Smckusick 	if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
57152196Smckusick 		nmp->nm_flag |= NFSMNT_DISMNT;
57252196Smckusick 
57352196Smckusick 	/*
57452196Smckusick 	 * There are two reference counts to get rid of here.
57552196Smckusick 	 */
57640120Smckusick 	vrele(vp);
57752196Smckusick 	vrele(vp);
57852288Smckusick 	vgone(vp);
57940120Smckusick 	nfs_disconnect(nmp);
58041904Smckusick 	m_freem(nmp->nm_nam);
58152196Smckusick 
58252196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
58352196Smckusick 		free((caddr_t)nmp, M_NFSMNT);
58438414Smckusick 	return (0);
58538414Smckusick }
58638414Smckusick 
58738414Smckusick /*
58838414Smckusick  * Return root of a filesystem
58938414Smckusick  */
59055082Storek int
59138414Smckusick nfs_root(mp, vpp)
59238414Smckusick 	struct mount *mp;
59338414Smckusick 	struct vnode **vpp;
59438414Smckusick {
59538414Smckusick 	register struct vnode *vp;
59638414Smckusick 	struct nfsmount *nmp;
59738414Smckusick 	struct nfsnode *np;
59838414Smckusick 	int error;
59938414Smckusick 
60041398Smckusick 	nmp = VFSTONFS(mp);
60138414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
60238414Smckusick 		return (error);
60338414Smckusick 	vp = NFSTOV(np);
60438414Smckusick 	vp->v_type = VDIR;
60538414Smckusick 	vp->v_flag = VROOT;
60638414Smckusick 	*vpp = vp;
60738414Smckusick 	return (0);
60838414Smckusick }
60938414Smckusick 
61038884Smacklem extern int syncprt;
61138884Smacklem 
61238414Smckusick /*
61338884Smacklem  * Flush out the buffer cache
61438414Smckusick  */
61539494Smckusick /* ARGSUSED */
61655082Storek int
61754450Smckusick nfs_sync(mp, waitfor, cred, p)
61838414Smckusick 	struct mount *mp;
61938414Smckusick 	int waitfor;
62054450Smckusick 	struct ucred *cred;
62154450Smckusick 	struct proc *p;
62238414Smckusick {
62354450Smckusick 	register struct vnode *vp;
62454450Smckusick 	int error, allerror = 0;
62554450Smckusick 
62638884Smacklem 	/*
62738884Smacklem 	 * Force stale buffer cache information to be flushed.
62838884Smacklem 	 */
62954450Smckusick loop:
63054450Smckusick 	for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
63154450Smckusick 		/*
63254450Smckusick 		 * If the vnode that we are about to sync is no longer
63354450Smckusick 		 * associated with this mount point, start over.
63454450Smckusick 		 */
63554450Smckusick 		if (vp->v_mount != mp)
63654450Smckusick 			goto loop;
63756467Smckusick 		if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.le_next == NULL)
63854450Smckusick 			continue;
63954450Smckusick 		if (vget(vp))
64054450Smckusick 			goto loop;
64154450Smckusick 		if (error = VOP_FSYNC(vp, cred, waitfor, p))
64254450Smckusick 			allerror = error;
64354450Smckusick 		vput(vp);
64454450Smckusick 	}
64554450Smckusick 	return (allerror);
64638414Smckusick }
64738414Smckusick 
64838414Smckusick /*
64954667Smckusick  * NFS flat namespace lookup.
65054667Smckusick  * Currently unsupported.
65154667Smckusick  */
65254667Smckusick /* ARGSUSED */
65354667Smckusick int
65454667Smckusick nfs_vget(mp, ino, vpp)
65554667Smckusick 	struct mount *mp;
65654667Smckusick 	ino_t ino;
65754667Smckusick 	struct vnode **vpp;
65854667Smckusick {
65954667Smckusick 
66054667Smckusick 	return (EOPNOTSUPP);
66154667Smckusick }
66254667Smckusick 
66354667Smckusick /*
66438414Smckusick  * At this point, this should never happen
66538414Smckusick  */
66639494Smckusick /* ARGSUSED */
66755082Storek int
66854737Smckusick nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
66954737Smckusick 	register struct mount *mp;
67038414Smckusick 	struct fid *fhp;
67154737Smckusick 	struct mbuf *nam;
67238414Smckusick 	struct vnode **vpp;
67354737Smckusick 	int *exflagsp;
67454737Smckusick 	struct ucred **credanonp;
67538414Smckusick {
67639494Smckusick 
67738414Smckusick 	return (EINVAL);
67838414Smckusick }
67938414Smckusick 
68038414Smckusick /*
68138414Smckusick  * Vnode pointer to File handle, should never happen either
68238414Smckusick  */
68339494Smckusick /* ARGSUSED */
68455082Storek int
68548055Smckusick nfs_vptofh(vp, fhp)
68648055Smckusick 	struct vnode *vp;
68738414Smckusick 	struct fid *fhp;
68838414Smckusick {
68939494Smckusick 
69038414Smckusick 	return (EINVAL);
69138414Smckusick }
69238884Smacklem 
69338884Smacklem /*
69438884Smacklem  * Vfs start routine, a no-op.
69538884Smacklem  */
69639494Smckusick /* ARGSUSED */
69755082Storek int
69848055Smckusick nfs_start(mp, flags, p)
69938884Smacklem 	struct mount *mp;
70038884Smacklem 	int flags;
70148055Smckusick 	struct proc *p;
70238884Smacklem {
70339494Smckusick 
70438884Smacklem 	return (0);
70538884Smacklem }
70641294Smckusick 
70741294Smckusick /*
70841294Smckusick  * Do operations associated with quotas, not supported
70941294Smckusick  */
71051574Smckusick /* ARGSUSED */
71155082Storek int
71248055Smckusick nfs_quotactl(mp, cmd, uid, arg, p)
71341294Smckusick 	struct mount *mp;
71441294Smckusick 	int cmd;
71554450Smckusick 	uid_t uid;
71641294Smckusick 	caddr_t arg;
71748055Smckusick 	struct proc *p;
71841294Smckusick {
71951574Smckusick 
72041294Smckusick 	return (EOPNOTSUPP);
72141294Smckusick }
722