xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 65251)
138414Smckusick /*
263235Sbostic  * Copyright (c) 1989, 1993
363235Sbostic  *	The Regents of the University of California.  All rights reserved.
438414Smckusick  *
538414Smckusick  * This code is derived from software contributed to Berkeley by
638414Smckusick  * Rick Macklem at The University of Guelph.
738414Smckusick  *
844513Sbostic  * %sccs.include.redist.c%
938414Smckusick  *
10*65251Smckusick  *	@(#)nfs_vfsops.c	8.2 (Berkeley) 12/30/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 */
15359005Ssklower 	int error, i, s;
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. */
16457790Smckusick 	proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid);
16557790Smckusick 	proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid);
16657790Smckusick 	if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) >
16757790Smckusick 		NGROUPS)
16857790Smckusick 		proc0.p_ucred->cr_ngroups = NGROUPS;
16957790Smckusick 	for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
17057790Smckusick 	    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) {
18759005Ssklower 		struct sockaddr_in mask, sin;
18846988Smckusick 
18959005Ssklower 		bzero((caddr_t)&mask, sizeof(mask));
19059005Ssklower 		sin = mask;
19152196Smckusick 		sin.sin_family = AF_INET;
19259005Ssklower 		sin.sin_len = sizeof(sin);
19355082Storek 		if (error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
19455082Storek 		    (struct sockaddr *)&nd->mygateway,
19559005Ssklower 		    (struct sockaddr *)&mask,
19655082Storek 		    RTF_UP | RTF_GATEWAY, (struct rtentry **)0))
19755082Storek 			panic("nfs_mountroot: RTM_ADD: %d", error);
19846988Smckusick 	}
19946988Smckusick 
20046988Smckusick 	/*
20146988Smckusick 	 * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
20246988Smckusick 	 * Create a fake mount point just for the swap vnode so that the
20346988Smckusick 	 * swap file can be on a different server from the rootfs.
20446988Smckusick 	 */
20546988Smckusick 	if (swdevt[0].sw_dev == NODEV) {
20655082Storek 		nd->swap_args.fh = (nfsv2fh_t *)nd->swap_fh;
20755082Storek 		(void) nfs_mountdiskless(nd->swap_hostnam, "/swap", 0,
20855082Storek 		    &nd->swap_saddr, &nd->swap_args, &vp);
20946988Smckusick 
21046988Smckusick 		/*
21146988Smckusick 		 * Since the swap file is not the root dir of a file system,
21246988Smckusick 		 * hack it to a regular file.
21346988Smckusick 		 */
21446988Smckusick 		vp->v_type = VREG;
21546988Smckusick 		vp->v_flag = 0;
21646988Smckusick 		swapdev_vp = vp;
21746988Smckusick 		VREF(vp);
21846988Smckusick 		swdevt[0].sw_vp = vp;
21955082Storek 		swdevt[0].sw_nblks = ntohl(nd->swap_nblks);
22056331Smckusick 	} else if (bdevvp(swapdev, &swapdev_vp))
22156331Smckusick 		panic("nfs_mountroot: can't setup swapdev_vp");
22246988Smckusick 
22346988Smckusick 	/*
22446988Smckusick 	 * Create the rootfs mount point.
22546988Smckusick 	 */
22655082Storek 	nd->root_args.fh = (nfsv2fh_t *)nd->root_fh;
22755082Storek 	mp = nfs_mountdiskless(nd->root_hostnam, "/", MNT_RDONLY,
22855082Storek 	    &nd->root_saddr, &nd->root_args, &vp);
22946988Smckusick 
23046988Smckusick 	if (vfs_lock(mp))
23155082Storek 		panic("nfs_mountroot: vfs_lock");
232*65251Smckusick 	TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
233*65251Smckusick 	mp->mnt_flag |= MNT_ROOTFS;
23446988Smckusick 	mp->mnt_vnodecovered = NULLVP;
23546988Smckusick 	vfs_unlock(mp);
23646988Smckusick 	rootvp = vp;
23752445Smckusick 
23852445Smckusick 	/*
23952445Smckusick 	 * This is not really an nfs issue, but it is much easier to
24052445Smckusick 	 * set hostname here and then let the "/etc/rc.xxx" files
24152445Smckusick 	 * mount the right /var based upon its preset value.
24252445Smckusick 	 */
24355082Storek 	bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
24452445Smckusick 	hostname[MAXHOSTNAMELEN - 1] = '\0';
24552445Smckusick 	for (i = 0; i < MAXHOSTNAMELEN; i++)
24652445Smckusick 		if (hostname[i] == '\0')
24752445Smckusick 			break;
24852445Smckusick 	hostnamelen = i;
24957790Smckusick 	inittodr(ntohl(nd->root_time));
25046988Smckusick 	return (0);
25138414Smckusick }
25238414Smckusick 
25338414Smckusick /*
25455082Storek  * Internal version of mount system call for diskless setup.
25555082Storek  */
25655082Storek static struct mount *
25755082Storek nfs_mountdiskless(path, which, mountflag, sin, args, vpp)
25855082Storek 	char *path;
25955082Storek 	char *which;
26055082Storek 	int mountflag;
26155082Storek 	struct sockaddr_in *sin;
26255082Storek 	struct nfs_args *args;
26355082Storek 	register struct vnode **vpp;
26455082Storek {
26555082Storek 	register struct mount *mp;
26655082Storek 	register struct mbuf *m;
26755082Storek 	register int error;
26855082Storek 
26955082Storek 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
27055082Storek 	    M_MOUNT, M_NOWAIT);
27155082Storek 	if (mp == NULL)
27255082Storek 		panic("nfs_mountroot: %s mount malloc", which);
273*65251Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
27455082Storek 	mp->mnt_op = &nfs_vfsops;
27555082Storek 	mp->mnt_flag = mountflag;
27655082Storek 
27755082Storek 	MGET(m, MT_SONAME, M_DONTWAIT);
27855082Storek 	if (m == NULL)
27955082Storek 		panic("nfs_mountroot: %s mount mbuf", which);
28055082Storek 	bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len);
28155082Storek 	m->m_len = sin->sin_len;
28255082Storek 	nfsargs_ntoh(args);
28355082Storek 	if (error = mountnfs(args, mp, m, which, path, vpp))
28455082Storek 		panic("nfs_mountroot: mount %s on %s: %d", path, which, error);
28555082Storek 
28655082Storek 	return (mp);
28755082Storek }
28855082Storek 
28955082Storek /*
29052196Smckusick  * Convert the integer fields of the nfs_args structure from net byte order
29152196Smckusick  * to host byte order. Called by nfs_mountroot() above.
29252196Smckusick  */
29352196Smckusick void
29452196Smckusick nfsargs_ntoh(nfsp)
29552196Smckusick 	register struct nfs_args *nfsp;
29652196Smckusick {
29752196Smckusick 
29852196Smckusick 	NTOHL(nfsp->sotype);
29952196Smckusick 	NTOHL(nfsp->proto);
30052196Smckusick 	NTOHL(nfsp->flags);
30152196Smckusick 	NTOHL(nfsp->wsize);
30252196Smckusick 	NTOHL(nfsp->rsize);
30352196Smckusick 	NTOHL(nfsp->timeo);
30452196Smckusick 	NTOHL(nfsp->retrans);
30552196Smckusick 	NTOHL(nfsp->maxgrouplist);
30652196Smckusick 	NTOHL(nfsp->readahead);
30752196Smckusick 	NTOHL(nfsp->leaseterm);
30852196Smckusick 	NTOHL(nfsp->deadthresh);
30952196Smckusick }
31052196Smckusick 
31152196Smckusick /*
31238414Smckusick  * VFS Operations.
31338414Smckusick  *
31438414Smckusick  * mount system call
31538414Smckusick  * It seems a bit dumb to copyinstr() the host and path here and then
31638414Smckusick  * bcopy() them in mountnfs(), but I wanted to detect errors before
31738414Smckusick  * doing the sockargs() call because sockargs() allocates an mbuf and
31838414Smckusick  * an error after that means that I have to release the mbuf.
31938414Smckusick  */
32039494Smckusick /* ARGSUSED */
32155082Storek int
32248055Smckusick nfs_mount(mp, path, data, ndp, p)
32338414Smckusick 	struct mount *mp;
32438414Smckusick 	char *path;
32538414Smckusick 	caddr_t data;
32638414Smckusick 	struct nameidata *ndp;
32748055Smckusick 	struct proc *p;
32838414Smckusick {
32938414Smckusick 	int error;
33038414Smckusick 	struct nfs_args args;
33141904Smckusick 	struct mbuf *nam;
33246988Smckusick 	struct vnode *vp;
33338414Smckusick 	char pth[MNAMELEN], hst[MNAMELEN];
33449108Skarels 	u_int len;
33538414Smckusick 	nfsv2fh_t nfh;
33638414Smckusick 
33738414Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
33838414Smckusick 		return (error);
33949108Skarels 	if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
34038414Smckusick 		return (error);
34138414Smckusick 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
34238414Smckusick 		return (error);
34349108Skarels 	bzero(&pth[len], MNAMELEN - len);
34438414Smckusick 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
34538414Smckusick 		return (error);
34649108Skarels 	bzero(&hst[len], MNAMELEN - len);
34738414Smckusick 	/* sockargs() call must be after above copyin() calls */
34841904Smckusick 	if (error = sockargs(&nam, (caddr_t)args.addr,
34952196Smckusick 		args.addrlen, MT_SONAME))
35038414Smckusick 		return (error);
35138414Smckusick 	args.fh = &nfh;
35246988Smckusick 	error = mountnfs(&args, mp, nam, pth, hst, &vp);
35338414Smckusick 	return (error);
35438414Smckusick }
35538414Smckusick 
35638414Smckusick /*
35738414Smckusick  * Common code for mount and mountroot
35838414Smckusick  */
35955082Storek int
36046988Smckusick mountnfs(argp, mp, nam, pth, hst, vpp)
36138414Smckusick 	register struct nfs_args *argp;
36238414Smckusick 	register struct mount *mp;
36341904Smckusick 	struct mbuf *nam;
36438414Smckusick 	char *pth, *hst;
36546988Smckusick 	struct vnode **vpp;
36638414Smckusick {
36738414Smckusick 	register struct nfsmount *nmp;
36840010Smckusick 	struct nfsnode *np;
36940120Smckusick 	int error;
37039757Smckusick 	fsid_t tfsid;
37138414Smckusick 
37255082Storek 	if (mp->mnt_flag & MNT_UPDATE) {
37355082Storek 		nmp = VFSTONFS(mp);
37455082Storek 		/* update paths, file handles, etc, here	XXX */
37555082Storek 		m_freem(nam);
37655082Storek 		return (0);
37755082Storek 	} else {
37855082Storek 		MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
37955082Storek 		    M_NFSMNT, M_WAITOK);
38055082Storek 		bzero((caddr_t)nmp, sizeof (struct nfsmount));
38155082Storek 		mp->mnt_data = (qaddr_t)nmp;
38255082Storek 	}
38353937Spendry 	getnewfsid(mp, MOUNT_NFS);
38438414Smckusick 	nmp->nm_mountp = mp;
38538414Smckusick 	nmp->nm_flag = argp->flags;
38652196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) ==
38752196Smckusick 		(NFSMNT_NQNFS | NFSMNT_MYWRITE)) {
38852196Smckusick 		error = EPERM;
38952196Smckusick 		goto bad;
39052196Smckusick 	}
39159759Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS)
39254985Smckusick 		/*
39354985Smckusick 		 * We have to set mnt_maxsymlink to a non-zero value so
39454985Smckusick 		 * that COMPAT_43 routines will know that we are setting
39554985Smckusick 		 * the d_type field in directories (and can zero it for
39654985Smckusick 		 * unsuspecting binaries).
39754985Smckusick 		 */
39854985Smckusick 		mp->mnt_maxsymlinklen = 1;
39952196Smckusick 	nmp->nm_timeo = NFS_TIMEO;
40040120Smckusick 	nmp->nm_retry = NFS_RETRANS;
40140120Smckusick 	nmp->nm_wsize = NFS_WSIZE;
40240120Smckusick 	nmp->nm_rsize = NFS_RSIZE;
40352196Smckusick 	nmp->nm_numgrps = NFS_MAXGRPS;
40452196Smckusick 	nmp->nm_readahead = NFS_DEFRAHEAD;
40552196Smckusick 	nmp->nm_leaseterm = NQ_DEFLEASE;
40652196Smckusick 	nmp->nm_deadthresh = NQ_DEADTHRESH;
40752196Smckusick 	nmp->nm_tnext = (struct nfsnode *)nmp;
40852196Smckusick 	nmp->nm_tprev = (struct nfsnode *)nmp;
40952196Smckusick 	nmp->nm_inprog = NULLVP;
41040120Smckusick 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
41141398Smckusick 	mp->mnt_stat.f_type = MOUNT_NFS;
41241398Smckusick 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
41341398Smckusick 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
41441904Smckusick 	nmp->nm_nam = nam;
41540120Smckusick 
41640120Smckusick 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
41752196Smckusick 		nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
41852196Smckusick 		if (nmp->nm_timeo < NFS_MINTIMEO)
41952196Smckusick 			nmp->nm_timeo = NFS_MINTIMEO;
42052196Smckusick 		else if (nmp->nm_timeo > NFS_MAXTIMEO)
42152196Smckusick 			nmp->nm_timeo = NFS_MAXTIMEO;
42240120Smckusick 	}
42340120Smckusick 
42443355Smckusick 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
42540120Smckusick 		nmp->nm_retry = argp->retrans;
42640120Smckusick 		if (nmp->nm_retry > NFS_MAXREXMIT)
42740120Smckusick 			nmp->nm_retry = NFS_MAXREXMIT;
42840120Smckusick 	}
42940120Smckusick 
43040120Smckusick 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
43138414Smckusick 		nmp->nm_wsize = argp->wsize;
43240120Smckusick 		/* Round down to multiple of blocksize */
43340120Smckusick 		nmp->nm_wsize &= ~0x1ff;
43440120Smckusick 		if (nmp->nm_wsize <= 0)
43540120Smckusick 			nmp->nm_wsize = 512;
43640120Smckusick 		else if (nmp->nm_wsize > NFS_MAXDATA)
43740120Smckusick 			nmp->nm_wsize = NFS_MAXDATA;
43840120Smckusick 	}
43943355Smckusick 	if (nmp->nm_wsize > MAXBSIZE)
44043355Smckusick 		nmp->nm_wsize = MAXBSIZE;
44140120Smckusick 
44240120Smckusick 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
44338414Smckusick 		nmp->nm_rsize = argp->rsize;
44440120Smckusick 		/* Round down to multiple of blocksize */
44540120Smckusick 		nmp->nm_rsize &= ~0x1ff;
44640120Smckusick 		if (nmp->nm_rsize <= 0)
44740120Smckusick 			nmp->nm_rsize = 512;
44840120Smckusick 		else if (nmp->nm_rsize > NFS_MAXDATA)
44940120Smckusick 			nmp->nm_rsize = NFS_MAXDATA;
45040120Smckusick 	}
45143355Smckusick 	if (nmp->nm_rsize > MAXBSIZE)
45243355Smckusick 		nmp->nm_rsize = MAXBSIZE;
45352196Smckusick 	if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
45452196Smckusick 		argp->maxgrouplist <= NFS_MAXGRPS)
45552196Smckusick 		nmp->nm_numgrps = argp->maxgrouplist;
45652196Smckusick 	if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
45752196Smckusick 		argp->readahead <= NFS_MAXRAHEAD)
45852196Smckusick 		nmp->nm_readahead = argp->readahead;
45952196Smckusick 	if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
46052196Smckusick 		argp->leaseterm <= NQ_MAXLEASE)
46152196Smckusick 		nmp->nm_leaseterm = argp->leaseterm;
46252196Smckusick 	if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
46352196Smckusick 		argp->deadthresh <= NQ_NEVERDEAD)
46452196Smckusick 		nmp->nm_deadthresh = argp->deadthresh;
46540120Smckusick 	/* Set up the sockets and per-host congestion */
46641904Smckusick 	nmp->nm_sotype = argp->sotype;
46741904Smckusick 	nmp->nm_soproto = argp->proto;
46852196Smckusick 
46952196Smckusick 	/*
47052196Smckusick 	 * For Connection based sockets (TCP,...) defer the connect until
47152196Smckusick 	 * the first request, in case the server is not responding.
47252196Smckusick 	 */
47352196Smckusick 	if (nmp->nm_sotype == SOCK_DGRAM &&
47452196Smckusick 		(error = nfs_connect(nmp, (struct nfsreq *)0)))
47540120Smckusick 		goto bad;
47640120Smckusick 
47738414Smckusick 	/*
47852196Smckusick 	 * This is silly, but it has to be set so that vinifod() works.
47952196Smckusick 	 * We do not want to do an nfs_statfs() here since we can get
48052196Smckusick 	 * stuck on a dead server and we are holding a lock on the mount
48152196Smckusick 	 * point.
48252196Smckusick 	 */
48352196Smckusick 	mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
48452196Smckusick 	/*
48540010Smckusick 	 * A reference count is needed on the nfsnode representing the
48640010Smckusick 	 * remote root.  If this object is not persistent, then backward
48740010Smckusick 	 * traversals of the mount point (i.e. "..") will not work if
48840010Smckusick 	 * the nfsnode gets flushed out of the cache. Ufs does not have
48940010Smckusick 	 * this problem, because one can identify root inodes by their
49040010Smckusick 	 * number == ROOTINO (2).
49140010Smckusick 	 */
49240010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
49340010Smckusick 		goto bad;
49446988Smckusick 	*vpp = NFSTOV(np);
49541904Smckusick 
49640353Smckusick 	return (0);
49738414Smckusick bad:
49840120Smckusick 	nfs_disconnect(nmp);
49952196Smckusick 	free((caddr_t)nmp, M_NFSMNT);
50041904Smckusick 	m_freem(nam);
50138414Smckusick 	return (error);
50238414Smckusick }
50338414Smckusick 
50438414Smckusick /*
50538414Smckusick  * unmount system call
50638414Smckusick  */
50755082Storek int
50848055Smckusick nfs_unmount(mp, mntflags, p)
50938414Smckusick 	struct mount *mp;
51041294Smckusick 	int mntflags;
51148055Smckusick 	struct proc *p;
51238414Smckusick {
51338414Smckusick 	register struct nfsmount *nmp;
51440010Smckusick 	struct nfsnode *np;
51540120Smckusick 	struct vnode *vp;
51648361Smckusick 	int error, flags = 0;
51748361Smckusick 	extern int doforce;
51838414Smckusick 
51948066Smckusick 	if (mntflags & MNT_FORCE) {
520*65251Smckusick 		if (!doforce || (mp->mnt_flag & MNT_ROOTFS))
52148066Smckusick 			return (EINVAL);
52241294Smckusick 		flags |= FORCECLOSE;
52348066Smckusick 	}
52441398Smckusick 	nmp = VFSTONFS(mp);
52538414Smckusick 	/*
52638414Smckusick 	 * Goes something like this..
52740120Smckusick 	 * - Check for activity on the root vnode (other than ourselves).
52840120Smckusick 	 * - Call vflush() to clear out vnodes for this file system,
52940120Smckusick 	 *   except for the root vnode.
53040120Smckusick 	 * - Decrement reference on the vnode representing remote root.
53138414Smckusick 	 * - Close the socket
53238414Smckusick 	 * - Free up the data structures
53338414Smckusick 	 */
53440010Smckusick 	/*
53540010Smckusick 	 * We need to decrement the ref. count on the nfsnode representing
53640010Smckusick 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
53740010Smckusick 	 * has done vput on this vnode, otherwise we would get deadlock!
53840010Smckusick 	 */
53940010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
54040010Smckusick 		return(error);
54140120Smckusick 	vp = NFSTOV(np);
54240120Smckusick 	if (vp->v_usecount > 2) {
54340120Smckusick 		vput(vp);
54440120Smckusick 		return (EBUSY);
54540120Smckusick 	}
54652196Smckusick 
54752196Smckusick 	/*
54852196Smckusick 	 * Must handshake with nqnfs_clientd() if it is active.
54952196Smckusick 	 */
55052196Smckusick 	nmp->nm_flag |= NFSMNT_DISMINPROG;
55152196Smckusick 	while (nmp->nm_inprog != NULLVP)
55252196Smckusick 		(void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
55340120Smckusick 	if (error = vflush(mp, vp, flags)) {
55440120Smckusick 		vput(vp);
55552196Smckusick 		nmp->nm_flag &= ~NFSMNT_DISMINPROG;
55640120Smckusick 		return (error);
55740120Smckusick 	}
55852196Smckusick 
55940010Smckusick 	/*
56052196Smckusick 	 * We are now committed to the unmount.
56152196Smckusick 	 * For NQNFS, let the server daemon free the nfsmount structure.
56240010Smckusick 	 */
56352196Smckusick 	if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
56452196Smckusick 		nmp->nm_flag |= NFSMNT_DISMNT;
56552196Smckusick 
56652196Smckusick 	/*
56752196Smckusick 	 * There are two reference counts to get rid of here.
56852196Smckusick 	 */
56940120Smckusick 	vrele(vp);
57052196Smckusick 	vrele(vp);
57152288Smckusick 	vgone(vp);
57240120Smckusick 	nfs_disconnect(nmp);
57341904Smckusick 	m_freem(nmp->nm_nam);
57452196Smckusick 
57552196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
57652196Smckusick 		free((caddr_t)nmp, M_NFSMNT);
57738414Smckusick 	return (0);
57838414Smckusick }
57938414Smckusick 
58038414Smckusick /*
58138414Smckusick  * Return root of a filesystem
58238414Smckusick  */
58355082Storek int
58438414Smckusick nfs_root(mp, vpp)
58538414Smckusick 	struct mount *mp;
58638414Smckusick 	struct vnode **vpp;
58738414Smckusick {
58838414Smckusick 	register struct vnode *vp;
58938414Smckusick 	struct nfsmount *nmp;
59038414Smckusick 	struct nfsnode *np;
59138414Smckusick 	int error;
59238414Smckusick 
59341398Smckusick 	nmp = VFSTONFS(mp);
59438414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
59538414Smckusick 		return (error);
59638414Smckusick 	vp = NFSTOV(np);
59738414Smckusick 	vp->v_type = VDIR;
59838414Smckusick 	vp->v_flag = VROOT;
59938414Smckusick 	*vpp = vp;
60038414Smckusick 	return (0);
60138414Smckusick }
60238414Smckusick 
60338884Smacklem extern int syncprt;
60438884Smacklem 
60538414Smckusick /*
60638884Smacklem  * Flush out the buffer cache
60738414Smckusick  */
60839494Smckusick /* ARGSUSED */
60955082Storek int
61054450Smckusick nfs_sync(mp, waitfor, cred, p)
61138414Smckusick 	struct mount *mp;
61238414Smckusick 	int waitfor;
61354450Smckusick 	struct ucred *cred;
61454450Smckusick 	struct proc *p;
61538414Smckusick {
61654450Smckusick 	register struct vnode *vp;
61754450Smckusick 	int error, allerror = 0;
61854450Smckusick 
61938884Smacklem 	/*
62038884Smacklem 	 * Force stale buffer cache information to be flushed.
62138884Smacklem 	 */
62254450Smckusick loop:
623*65251Smckusick 	for (vp = mp->mnt_vnodelist.lh_first;
624*65251Smckusick 	     vp != NULL;
625*65251Smckusick 	     vp = vp->v_mntvnodes.le_next) {
62654450Smckusick 		/*
62754450Smckusick 		 * If the vnode that we are about to sync is no longer
62854450Smckusick 		 * associated with this mount point, start over.
62954450Smckusick 		 */
63054450Smckusick 		if (vp->v_mount != mp)
63154450Smckusick 			goto loop;
632*65251Smckusick 		if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL)
63354450Smckusick 			continue;
634*65251Smckusick 		if (vget(vp, 1))
63554450Smckusick 			goto loop;
63654450Smckusick 		if (error = VOP_FSYNC(vp, cred, waitfor, p))
63754450Smckusick 			allerror = error;
63854450Smckusick 		vput(vp);
63954450Smckusick 	}
64054450Smckusick 	return (allerror);
64138414Smckusick }
64238414Smckusick 
64338414Smckusick /*
64454667Smckusick  * NFS flat namespace lookup.
64554667Smckusick  * Currently unsupported.
64654667Smckusick  */
64754667Smckusick /* ARGSUSED */
64854667Smckusick int
64954667Smckusick nfs_vget(mp, ino, vpp)
65054667Smckusick 	struct mount *mp;
65154667Smckusick 	ino_t ino;
65254667Smckusick 	struct vnode **vpp;
65354667Smckusick {
65454667Smckusick 
65554667Smckusick 	return (EOPNOTSUPP);
65654667Smckusick }
65754667Smckusick 
65854667Smckusick /*
65938414Smckusick  * At this point, this should never happen
66038414Smckusick  */
66139494Smckusick /* ARGSUSED */
66255082Storek int
66354737Smckusick nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
66454737Smckusick 	register struct mount *mp;
66538414Smckusick 	struct fid *fhp;
66654737Smckusick 	struct mbuf *nam;
66738414Smckusick 	struct vnode **vpp;
66854737Smckusick 	int *exflagsp;
66954737Smckusick 	struct ucred **credanonp;
67038414Smckusick {
67139494Smckusick 
67238414Smckusick 	return (EINVAL);
67338414Smckusick }
67438414Smckusick 
67538414Smckusick /*
67638414Smckusick  * Vnode pointer to File handle, should never happen either
67738414Smckusick  */
67839494Smckusick /* ARGSUSED */
67955082Storek int
68048055Smckusick nfs_vptofh(vp, fhp)
68148055Smckusick 	struct vnode *vp;
68238414Smckusick 	struct fid *fhp;
68338414Smckusick {
68439494Smckusick 
68538414Smckusick 	return (EINVAL);
68638414Smckusick }
68738884Smacklem 
68838884Smacklem /*
68938884Smacklem  * Vfs start routine, a no-op.
69038884Smacklem  */
69139494Smckusick /* ARGSUSED */
69255082Storek int
69348055Smckusick nfs_start(mp, flags, p)
69438884Smacklem 	struct mount *mp;
69538884Smacklem 	int flags;
69648055Smckusick 	struct proc *p;
69738884Smacklem {
69839494Smckusick 
69938884Smacklem 	return (0);
70038884Smacklem }
70141294Smckusick 
70241294Smckusick /*
70341294Smckusick  * Do operations associated with quotas, not supported
70441294Smckusick  */
70551574Smckusick /* ARGSUSED */
70655082Storek int
70748055Smckusick nfs_quotactl(mp, cmd, uid, arg, p)
70841294Smckusick 	struct mount *mp;
70941294Smckusick 	int cmd;
71054450Smckusick 	uid_t uid;
71141294Smckusick 	caddr_t arg;
71248055Smckusick 	struct proc *p;
71341294Smckusick {
71451574Smckusick 
71541294Smckusick 	return (EOPNOTSUPP);
71641294Smckusick }
717