xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 63235)
138414Smckusick /*
2*63235Sbostic  * Copyright (c) 1989, 1993
3*63235Sbostic  *	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*63235Sbostic  *	@(#)nfs_vfsops.c	8.1 (Berkeley) 06/10/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");
23246988Smckusick 	rootfs = mp;
23346988Smckusick 	mp->mnt_next = mp;
23446988Smckusick 	mp->mnt_prev = mp;
23546988Smckusick 	mp->mnt_vnodecovered = NULLVP;
23646988Smckusick 	vfs_unlock(mp);
23746988Smckusick 	rootvp = vp;
23852445Smckusick 
23952445Smckusick 	/*
24052445Smckusick 	 * This is not really an nfs issue, but it is much easier to
24152445Smckusick 	 * set hostname here and then let the "/etc/rc.xxx" files
24252445Smckusick 	 * mount the right /var based upon its preset value.
24352445Smckusick 	 */
24455082Storek 	bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
24552445Smckusick 	hostname[MAXHOSTNAMELEN - 1] = '\0';
24652445Smckusick 	for (i = 0; i < MAXHOSTNAMELEN; i++)
24752445Smckusick 		if (hostname[i] == '\0')
24852445Smckusick 			break;
24952445Smckusick 	hostnamelen = i;
25057790Smckusick 	inittodr(ntohl(nd->root_time));
25146988Smckusick 	return (0);
25238414Smckusick }
25338414Smckusick 
25438414Smckusick /*
25555082Storek  * Internal version of mount system call for diskless setup.
25655082Storek  */
25755082Storek static struct mount *
25855082Storek nfs_mountdiskless(path, which, mountflag, sin, args, vpp)
25955082Storek 	char *path;
26055082Storek 	char *which;
26155082Storek 	int mountflag;
26255082Storek 	struct sockaddr_in *sin;
26355082Storek 	struct nfs_args *args;
26455082Storek 	register struct vnode **vpp;
26555082Storek {
26655082Storek 	register struct mount *mp;
26755082Storek 	register struct mbuf *m;
26855082Storek 	register int error;
26955082Storek 
27055082Storek 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
27155082Storek 	    M_MOUNT, M_NOWAIT);
27255082Storek 	if (mp == NULL)
27355082Storek 		panic("nfs_mountroot: %s mount malloc", which);
27455082Storek 	mp->mnt_op = &nfs_vfsops;
27555082Storek 	mp->mnt_flag = mountflag;
27655082Storek 	mp->mnt_mounth = NULLVP;
27755082Storek 
27855082Storek 	MGET(m, MT_SONAME, M_DONTWAIT);
27955082Storek 	if (m == NULL)
28055082Storek 		panic("nfs_mountroot: %s mount mbuf", which);
28155082Storek 	bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len);
28255082Storek 	m->m_len = sin->sin_len;
28355082Storek 	nfsargs_ntoh(args);
28455082Storek 	if (error = mountnfs(args, mp, m, which, path, vpp))
28555082Storek 		panic("nfs_mountroot: mount %s on %s: %d", path, which, error);
28655082Storek 
28755082Storek 	return (mp);
28855082Storek }
28955082Storek 
29055082Storek /*
29152196Smckusick  * Convert the integer fields of the nfs_args structure from net byte order
29252196Smckusick  * to host byte order. Called by nfs_mountroot() above.
29352196Smckusick  */
29452196Smckusick void
29552196Smckusick nfsargs_ntoh(nfsp)
29652196Smckusick 	register struct nfs_args *nfsp;
29752196Smckusick {
29852196Smckusick 
29952196Smckusick 	NTOHL(nfsp->sotype);
30052196Smckusick 	NTOHL(nfsp->proto);
30152196Smckusick 	NTOHL(nfsp->flags);
30252196Smckusick 	NTOHL(nfsp->wsize);
30352196Smckusick 	NTOHL(nfsp->rsize);
30452196Smckusick 	NTOHL(nfsp->timeo);
30552196Smckusick 	NTOHL(nfsp->retrans);
30652196Smckusick 	NTOHL(nfsp->maxgrouplist);
30752196Smckusick 	NTOHL(nfsp->readahead);
30852196Smckusick 	NTOHL(nfsp->leaseterm);
30952196Smckusick 	NTOHL(nfsp->deadthresh);
31052196Smckusick }
31152196Smckusick 
31252196Smckusick /*
31338414Smckusick  * VFS Operations.
31438414Smckusick  *
31538414Smckusick  * mount system call
31638414Smckusick  * It seems a bit dumb to copyinstr() the host and path here and then
31738414Smckusick  * bcopy() them in mountnfs(), but I wanted to detect errors before
31838414Smckusick  * doing the sockargs() call because sockargs() allocates an mbuf and
31938414Smckusick  * an error after that means that I have to release the mbuf.
32038414Smckusick  */
32139494Smckusick /* ARGSUSED */
32255082Storek int
32348055Smckusick nfs_mount(mp, path, data, ndp, p)
32438414Smckusick 	struct mount *mp;
32538414Smckusick 	char *path;
32638414Smckusick 	caddr_t data;
32738414Smckusick 	struct nameidata *ndp;
32848055Smckusick 	struct proc *p;
32938414Smckusick {
33038414Smckusick 	int error;
33138414Smckusick 	struct nfs_args args;
33241904Smckusick 	struct mbuf *nam;
33346988Smckusick 	struct vnode *vp;
33438414Smckusick 	char pth[MNAMELEN], hst[MNAMELEN];
33549108Skarels 	u_int len;
33638414Smckusick 	nfsv2fh_t nfh;
33738414Smckusick 
33838414Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
33938414Smckusick 		return (error);
34049108Skarels 	if (error = copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
34138414Smckusick 		return (error);
34238414Smckusick 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
34338414Smckusick 		return (error);
34449108Skarels 	bzero(&pth[len], MNAMELEN - len);
34538414Smckusick 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
34638414Smckusick 		return (error);
34749108Skarels 	bzero(&hst[len], MNAMELEN - len);
34838414Smckusick 	/* sockargs() call must be after above copyin() calls */
34941904Smckusick 	if (error = sockargs(&nam, (caddr_t)args.addr,
35052196Smckusick 		args.addrlen, MT_SONAME))
35138414Smckusick 		return (error);
35238414Smckusick 	args.fh = &nfh;
35346988Smckusick 	error = mountnfs(&args, mp, nam, pth, hst, &vp);
35438414Smckusick 	return (error);
35538414Smckusick }
35638414Smckusick 
35738414Smckusick /*
35838414Smckusick  * Common code for mount and mountroot
35938414Smckusick  */
36055082Storek int
36146988Smckusick mountnfs(argp, mp, nam, pth, hst, vpp)
36238414Smckusick 	register struct nfs_args *argp;
36338414Smckusick 	register struct mount *mp;
36441904Smckusick 	struct mbuf *nam;
36538414Smckusick 	char *pth, *hst;
36646988Smckusick 	struct vnode **vpp;
36738414Smckusick {
36838414Smckusick 	register struct nfsmount *nmp;
36940010Smckusick 	struct nfsnode *np;
37040120Smckusick 	int error;
37139757Smckusick 	fsid_t tfsid;
37238414Smckusick 
37355082Storek 	if (mp->mnt_flag & MNT_UPDATE) {
37455082Storek 		nmp = VFSTONFS(mp);
37555082Storek 		/* update paths, file handles, etc, here	XXX */
37655082Storek 		m_freem(nam);
37755082Storek 		return (0);
37855082Storek 	} else {
37955082Storek 		MALLOC(nmp, struct nfsmount *, sizeof (struct nfsmount),
38055082Storek 		    M_NFSMNT, M_WAITOK);
38155082Storek 		bzero((caddr_t)nmp, sizeof (struct nfsmount));
38255082Storek 		mp->mnt_data = (qaddr_t)nmp;
38355082Storek 	}
38453937Spendry 	getnewfsid(mp, MOUNT_NFS);
38538414Smckusick 	nmp->nm_mountp = mp;
38638414Smckusick 	nmp->nm_flag = argp->flags;
38752196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_MYWRITE)) ==
38852196Smckusick 		(NFSMNT_NQNFS | NFSMNT_MYWRITE)) {
38952196Smckusick 		error = EPERM;
39052196Smckusick 		goto bad;
39152196Smckusick 	}
39259759Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS)
39354985Smckusick 		/*
39454985Smckusick 		 * We have to set mnt_maxsymlink to a non-zero value so
39554985Smckusick 		 * that COMPAT_43 routines will know that we are setting
39654985Smckusick 		 * the d_type field in directories (and can zero it for
39754985Smckusick 		 * unsuspecting binaries).
39854985Smckusick 		 */
39954985Smckusick 		mp->mnt_maxsymlinklen = 1;
40052196Smckusick 	nmp->nm_timeo = NFS_TIMEO;
40140120Smckusick 	nmp->nm_retry = NFS_RETRANS;
40240120Smckusick 	nmp->nm_wsize = NFS_WSIZE;
40340120Smckusick 	nmp->nm_rsize = NFS_RSIZE;
40452196Smckusick 	nmp->nm_numgrps = NFS_MAXGRPS;
40552196Smckusick 	nmp->nm_readahead = NFS_DEFRAHEAD;
40652196Smckusick 	nmp->nm_leaseterm = NQ_DEFLEASE;
40752196Smckusick 	nmp->nm_deadthresh = NQ_DEADTHRESH;
40852196Smckusick 	nmp->nm_tnext = (struct nfsnode *)nmp;
40952196Smckusick 	nmp->nm_tprev = (struct nfsnode *)nmp;
41052196Smckusick 	nmp->nm_inprog = NULLVP;
41140120Smckusick 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
41241398Smckusick 	mp->mnt_stat.f_type = MOUNT_NFS;
41341398Smckusick 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
41441398Smckusick 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
41541904Smckusick 	nmp->nm_nam = nam;
41640120Smckusick 
41740120Smckusick 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
41852196Smckusick 		nmp->nm_timeo = (argp->timeo * NFS_HZ + 5) / 10;
41952196Smckusick 		if (nmp->nm_timeo < NFS_MINTIMEO)
42052196Smckusick 			nmp->nm_timeo = NFS_MINTIMEO;
42152196Smckusick 		else if (nmp->nm_timeo > NFS_MAXTIMEO)
42252196Smckusick 			nmp->nm_timeo = NFS_MAXTIMEO;
42340120Smckusick 	}
42440120Smckusick 
42543355Smckusick 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
42640120Smckusick 		nmp->nm_retry = argp->retrans;
42740120Smckusick 		if (nmp->nm_retry > NFS_MAXREXMIT)
42840120Smckusick 			nmp->nm_retry = NFS_MAXREXMIT;
42940120Smckusick 	}
43040120Smckusick 
43140120Smckusick 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
43238414Smckusick 		nmp->nm_wsize = argp->wsize;
43340120Smckusick 		/* Round down to multiple of blocksize */
43440120Smckusick 		nmp->nm_wsize &= ~0x1ff;
43540120Smckusick 		if (nmp->nm_wsize <= 0)
43640120Smckusick 			nmp->nm_wsize = 512;
43740120Smckusick 		else if (nmp->nm_wsize > NFS_MAXDATA)
43840120Smckusick 			nmp->nm_wsize = NFS_MAXDATA;
43940120Smckusick 	}
44043355Smckusick 	if (nmp->nm_wsize > MAXBSIZE)
44143355Smckusick 		nmp->nm_wsize = MAXBSIZE;
44240120Smckusick 
44340120Smckusick 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
44438414Smckusick 		nmp->nm_rsize = argp->rsize;
44540120Smckusick 		/* Round down to multiple of blocksize */
44640120Smckusick 		nmp->nm_rsize &= ~0x1ff;
44740120Smckusick 		if (nmp->nm_rsize <= 0)
44840120Smckusick 			nmp->nm_rsize = 512;
44940120Smckusick 		else if (nmp->nm_rsize > NFS_MAXDATA)
45040120Smckusick 			nmp->nm_rsize = NFS_MAXDATA;
45140120Smckusick 	}
45243355Smckusick 	if (nmp->nm_rsize > MAXBSIZE)
45343355Smckusick 		nmp->nm_rsize = MAXBSIZE;
45452196Smckusick 	if ((argp->flags & NFSMNT_MAXGRPS) && argp->maxgrouplist >= 0 &&
45552196Smckusick 		argp->maxgrouplist <= NFS_MAXGRPS)
45652196Smckusick 		nmp->nm_numgrps = argp->maxgrouplist;
45752196Smckusick 	if ((argp->flags & NFSMNT_READAHEAD) && argp->readahead >= 0 &&
45852196Smckusick 		argp->readahead <= NFS_MAXRAHEAD)
45952196Smckusick 		nmp->nm_readahead = argp->readahead;
46052196Smckusick 	if ((argp->flags & NFSMNT_LEASETERM) && argp->leaseterm >= 2 &&
46152196Smckusick 		argp->leaseterm <= NQ_MAXLEASE)
46252196Smckusick 		nmp->nm_leaseterm = argp->leaseterm;
46352196Smckusick 	if ((argp->flags & NFSMNT_DEADTHRESH) && argp->deadthresh >= 1 &&
46452196Smckusick 		argp->deadthresh <= NQ_NEVERDEAD)
46552196Smckusick 		nmp->nm_deadthresh = argp->deadthresh;
46640120Smckusick 	/* Set up the sockets and per-host congestion */
46741904Smckusick 	nmp->nm_sotype = argp->sotype;
46841904Smckusick 	nmp->nm_soproto = argp->proto;
46952196Smckusick 
47052196Smckusick 	/*
47152196Smckusick 	 * For Connection based sockets (TCP,...) defer the connect until
47252196Smckusick 	 * the first request, in case the server is not responding.
47352196Smckusick 	 */
47452196Smckusick 	if (nmp->nm_sotype == SOCK_DGRAM &&
47552196Smckusick 		(error = nfs_connect(nmp, (struct nfsreq *)0)))
47640120Smckusick 		goto bad;
47740120Smckusick 
47838414Smckusick 	/*
47952196Smckusick 	 * This is silly, but it has to be set so that vinifod() works.
48052196Smckusick 	 * We do not want to do an nfs_statfs() here since we can get
48152196Smckusick 	 * stuck on a dead server and we are holding a lock on the mount
48252196Smckusick 	 * point.
48352196Smckusick 	 */
48452196Smckusick 	mp->mnt_stat.f_iosize = NFS_MAXDGRAMDATA;
48552196Smckusick 	/*
48640010Smckusick 	 * A reference count is needed on the nfsnode representing the
48740010Smckusick 	 * remote root.  If this object is not persistent, then backward
48840010Smckusick 	 * traversals of the mount point (i.e. "..") will not work if
48940010Smckusick 	 * the nfsnode gets flushed out of the cache. Ufs does not have
49040010Smckusick 	 * this problem, because one can identify root inodes by their
49140010Smckusick 	 * number == ROOTINO (2).
49240010Smckusick 	 */
49340010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
49440010Smckusick 		goto bad;
49546988Smckusick 	*vpp = NFSTOV(np);
49641904Smckusick 
49740353Smckusick 	return (0);
49838414Smckusick bad:
49940120Smckusick 	nfs_disconnect(nmp);
50052196Smckusick 	free((caddr_t)nmp, M_NFSMNT);
50141904Smckusick 	m_freem(nam);
50238414Smckusick 	return (error);
50338414Smckusick }
50438414Smckusick 
50538414Smckusick /*
50638414Smckusick  * unmount system call
50738414Smckusick  */
50855082Storek int
50948055Smckusick nfs_unmount(mp, mntflags, p)
51038414Smckusick 	struct mount *mp;
51141294Smckusick 	int mntflags;
51248055Smckusick 	struct proc *p;
51338414Smckusick {
51438414Smckusick 	register struct nfsmount *nmp;
51540010Smckusick 	struct nfsnode *np;
51640120Smckusick 	struct vnode *vp;
51748361Smckusick 	int error, flags = 0;
51848361Smckusick 	extern int doforce;
51938414Smckusick 
52048066Smckusick 	if (mntflags & MNT_FORCE) {
52148361Smckusick 		if (!doforce || mp == rootfs)
52248066Smckusick 			return (EINVAL);
52341294Smckusick 		flags |= FORCECLOSE;
52448066Smckusick 	}
52541398Smckusick 	nmp = VFSTONFS(mp);
52638414Smckusick 	/*
52738414Smckusick 	 * Goes something like this..
52840120Smckusick 	 * - Check for activity on the root vnode (other than ourselves).
52940120Smckusick 	 * - Call vflush() to clear out vnodes for this file system,
53040120Smckusick 	 *   except for the root vnode.
53140120Smckusick 	 * - Decrement reference on the vnode representing remote root.
53238414Smckusick 	 * - Close the socket
53338414Smckusick 	 * - Free up the data structures
53438414Smckusick 	 */
53540010Smckusick 	/*
53640010Smckusick 	 * We need to decrement the ref. count on the nfsnode representing
53740010Smckusick 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
53840010Smckusick 	 * has done vput on this vnode, otherwise we would get deadlock!
53940010Smckusick 	 */
54040010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
54140010Smckusick 		return(error);
54240120Smckusick 	vp = NFSTOV(np);
54340120Smckusick 	if (vp->v_usecount > 2) {
54440120Smckusick 		vput(vp);
54540120Smckusick 		return (EBUSY);
54640120Smckusick 	}
54752196Smckusick 
54852196Smckusick 	/*
54952196Smckusick 	 * Must handshake with nqnfs_clientd() if it is active.
55052196Smckusick 	 */
55152196Smckusick 	nmp->nm_flag |= NFSMNT_DISMINPROG;
55252196Smckusick 	while (nmp->nm_inprog != NULLVP)
55352196Smckusick 		(void) tsleep((caddr_t)&lbolt, PSOCK, "nfsdism", 0);
55440120Smckusick 	if (error = vflush(mp, vp, flags)) {
55540120Smckusick 		vput(vp);
55652196Smckusick 		nmp->nm_flag &= ~NFSMNT_DISMINPROG;
55740120Smckusick 		return (error);
55840120Smckusick 	}
55952196Smckusick 
56040010Smckusick 	/*
56152196Smckusick 	 * We are now committed to the unmount.
56252196Smckusick 	 * For NQNFS, let the server daemon free the nfsmount structure.
56340010Smckusick 	 */
56452196Smckusick 	if (nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB))
56552196Smckusick 		nmp->nm_flag |= NFSMNT_DISMNT;
56652196Smckusick 
56752196Smckusick 	/*
56852196Smckusick 	 * There are two reference counts to get rid of here.
56952196Smckusick 	 */
57040120Smckusick 	vrele(vp);
57152196Smckusick 	vrele(vp);
57252288Smckusick 	vgone(vp);
57340120Smckusick 	nfs_disconnect(nmp);
57441904Smckusick 	m_freem(nmp->nm_nam);
57552196Smckusick 
57652196Smckusick 	if ((nmp->nm_flag & (NFSMNT_NQNFS | NFSMNT_KERB)) == 0)
57752196Smckusick 		free((caddr_t)nmp, M_NFSMNT);
57838414Smckusick 	return (0);
57938414Smckusick }
58038414Smckusick 
58138414Smckusick /*
58238414Smckusick  * Return root of a filesystem
58338414Smckusick  */
58455082Storek int
58538414Smckusick nfs_root(mp, vpp)
58638414Smckusick 	struct mount *mp;
58738414Smckusick 	struct vnode **vpp;
58838414Smckusick {
58938414Smckusick 	register struct vnode *vp;
59038414Smckusick 	struct nfsmount *nmp;
59138414Smckusick 	struct nfsnode *np;
59238414Smckusick 	int error;
59338414Smckusick 
59441398Smckusick 	nmp = VFSTONFS(mp);
59538414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
59638414Smckusick 		return (error);
59738414Smckusick 	vp = NFSTOV(np);
59838414Smckusick 	vp->v_type = VDIR;
59938414Smckusick 	vp->v_flag = VROOT;
60038414Smckusick 	*vpp = vp;
60138414Smckusick 	return (0);
60238414Smckusick }
60338414Smckusick 
60438884Smacklem extern int syncprt;
60538884Smacklem 
60638414Smckusick /*
60738884Smacklem  * Flush out the buffer cache
60838414Smckusick  */
60939494Smckusick /* ARGSUSED */
61055082Storek int
61154450Smckusick nfs_sync(mp, waitfor, cred, p)
61238414Smckusick 	struct mount *mp;
61338414Smckusick 	int waitfor;
61454450Smckusick 	struct ucred *cred;
61554450Smckusick 	struct proc *p;
61638414Smckusick {
61754450Smckusick 	register struct vnode *vp;
61854450Smckusick 	int error, allerror = 0;
61954450Smckusick 
62038884Smacklem 	/*
62138884Smacklem 	 * Force stale buffer cache information to be flushed.
62238884Smacklem 	 */
62354450Smckusick loop:
62454450Smckusick 	for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
62554450Smckusick 		/*
62654450Smckusick 		 * If the vnode that we are about to sync is no longer
62754450Smckusick 		 * associated with this mount point, start over.
62854450Smckusick 		 */
62954450Smckusick 		if (vp->v_mount != mp)
63054450Smckusick 			goto loop;
63156467Smckusick 		if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.le_next == NULL)
63254450Smckusick 			continue;
63354450Smckusick 		if (vget(vp))
63454450Smckusick 			goto loop;
63554450Smckusick 		if (error = VOP_FSYNC(vp, cred, waitfor, p))
63654450Smckusick 			allerror = error;
63754450Smckusick 		vput(vp);
63854450Smckusick 	}
63954450Smckusick 	return (allerror);
64038414Smckusick }
64138414Smckusick 
64238414Smckusick /*
64354667Smckusick  * NFS flat namespace lookup.
64454667Smckusick  * Currently unsupported.
64554667Smckusick  */
64654667Smckusick /* ARGSUSED */
64754667Smckusick int
64854667Smckusick nfs_vget(mp, ino, vpp)
64954667Smckusick 	struct mount *mp;
65054667Smckusick 	ino_t ino;
65154667Smckusick 	struct vnode **vpp;
65254667Smckusick {
65354667Smckusick 
65454667Smckusick 	return (EOPNOTSUPP);
65554667Smckusick }
65654667Smckusick 
65754667Smckusick /*
65838414Smckusick  * At this point, this should never happen
65938414Smckusick  */
66039494Smckusick /* ARGSUSED */
66155082Storek int
66254737Smckusick nfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
66354737Smckusick 	register struct mount *mp;
66438414Smckusick 	struct fid *fhp;
66554737Smckusick 	struct mbuf *nam;
66638414Smckusick 	struct vnode **vpp;
66754737Smckusick 	int *exflagsp;
66854737Smckusick 	struct ucred **credanonp;
66938414Smckusick {
67039494Smckusick 
67138414Smckusick 	return (EINVAL);
67238414Smckusick }
67338414Smckusick 
67438414Smckusick /*
67538414Smckusick  * Vnode pointer to File handle, should never happen either
67638414Smckusick  */
67739494Smckusick /* ARGSUSED */
67855082Storek int
67948055Smckusick nfs_vptofh(vp, fhp)
68048055Smckusick 	struct vnode *vp;
68138414Smckusick 	struct fid *fhp;
68238414Smckusick {
68339494Smckusick 
68438414Smckusick 	return (EINVAL);
68538414Smckusick }
68638884Smacklem 
68738884Smacklem /*
68838884Smacklem  * Vfs start routine, a no-op.
68938884Smacklem  */
69039494Smckusick /* ARGSUSED */
69155082Storek int
69248055Smckusick nfs_start(mp, flags, p)
69338884Smacklem 	struct mount *mp;
69438884Smacklem 	int flags;
69548055Smckusick 	struct proc *p;
69638884Smacklem {
69739494Smckusick 
69838884Smacklem 	return (0);
69938884Smacklem }
70041294Smckusick 
70141294Smckusick /*
70241294Smckusick  * Do operations associated with quotas, not supported
70341294Smckusick  */
70451574Smckusick /* ARGSUSED */
70555082Storek int
70648055Smckusick nfs_quotactl(mp, cmd, uid, arg, p)
70741294Smckusick 	struct mount *mp;
70841294Smckusick 	int cmd;
70954450Smckusick 	uid_t uid;
71041294Smckusick 	caddr_t arg;
71148055Smckusick 	struct proc *p;
71241294Smckusick {
71351574Smckusick 
71441294Smckusick 	return (EOPNOTSUPP);
71541294Smckusick }
716