xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 40120)
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  *
838414Smckusick  * Redistribution and use in source and binary forms are permitted
938414Smckusick  * provided that the above copyright notice and this paragraph are
1038414Smckusick  * duplicated in all such forms and that any documentation,
1138414Smckusick  * advertising materials, and other materials related to such
1238414Smckusick  * distribution and use acknowledge that the software was developed
1338414Smckusick  * by the University of California, Berkeley.  The name of the
1438414Smckusick  * University may not be used to endorse or promote products derived
1538414Smckusick  * from this software without specific prior written permission.
1638414Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1738414Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1838414Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1938414Smckusick  *
20*40120Smckusick  *	@(#)nfs_vfsops.c	7.15 (Berkeley) 02/16/90
2138414Smckusick  */
2238414Smckusick 
2338414Smckusick #include "param.h"
2438414Smckusick #include "signal.h"
2538414Smckusick #include "user.h"
2638414Smckusick #include "proc.h"
2738414Smckusick #include "uio.h"
2838414Smckusick #include "ucred.h"
29*40120Smckusick #include "ufs/dir.h"
3038414Smckusick #include "namei.h"
3138414Smckusick #include "vnode.h"
3238414Smckusick #include "mount.h"
3338414Smckusick #include "errno.h"
3438414Smckusick #include "malloc.h"
35*40120Smckusick #include "buf.h"
3638414Smckusick #include "mbuf.h"
3738414Smckusick #undef	m_data
3838414Smckusick #include "socket.h"
39*40120Smckusick #include "systm.h"
4038414Smckusick #include "nfsv2.h"
4138414Smckusick #include "nfsnode.h"
4238414Smckusick #include "nfsmount.h"
4338414Smckusick #include "nfs.h"
4438414Smckusick 
4538414Smckusick /*
4638414Smckusick  * nfs vfs operations.
4738414Smckusick  */
4838414Smckusick int nfs_mount();
4938874Smckusick int nfs_start();
5038414Smckusick int nfs_unmount();
5138414Smckusick int nfs_root();
5239443Smckusick int nfs_statfs();
5338414Smckusick int nfs_sync();
5438414Smckusick int nfs_fhtovp();
5538414Smckusick int nfs_vptofh();
5639443Smckusick int nfs_init();
5738414Smckusick 
5838414Smckusick struct vfsops nfs_vfsops = {
5938414Smckusick 	nfs_mount,
6038874Smckusick 	nfs_start,
6138414Smckusick 	nfs_unmount,
6238414Smckusick 	nfs_root,
6338414Smckusick 	nfs_statfs,
6438414Smckusick 	nfs_sync,
6538414Smckusick 	nfs_fhtovp,
6638414Smckusick 	nfs_vptofh,
6739443Smckusick 	nfs_init,
6838414Smckusick };
6938414Smckusick 
7039757Smckusick static u_char nfs_mntid;
7138414Smckusick 
7238414Smckusick /*
7338414Smckusick  * Called by vfs_mountroot when nfs is going to be mounted as root
7438414Smckusick  * Not Yet (By a LONG shot)
7538414Smckusick  */
7638414Smckusick nfs_mountroot()
7738414Smckusick {
7838414Smckusick 	return (ENODEV);
7938414Smckusick }
8038414Smckusick 
8138414Smckusick /*
8238414Smckusick  * VFS Operations.
8338414Smckusick  *
8438414Smckusick  * mount system call
8538414Smckusick  * It seems a bit dumb to copyinstr() the host and path here and then
8638414Smckusick  * bcopy() them in mountnfs(), but I wanted to detect errors before
8738414Smckusick  * doing the sockargs() call because sockargs() allocates an mbuf and
8838414Smckusick  * an error after that means that I have to release the mbuf.
8938414Smckusick  */
9039494Smckusick /* ARGSUSED */
9138414Smckusick nfs_mount(mp, path, data, ndp)
9238414Smckusick 	struct mount *mp;
9338414Smckusick 	char *path;
9438414Smckusick 	caddr_t data;
9538414Smckusick 	struct nameidata *ndp;
9638414Smckusick {
9738414Smckusick 	int error;
9838414Smckusick 	struct nfs_args args;
9938414Smckusick 	struct mbuf *saddr;
10038414Smckusick 	char pth[MNAMELEN], hst[MNAMELEN];
10138414Smckusick 	int len;
10238414Smckusick 	nfsv2fh_t nfh;
10338414Smckusick 
10439460Smckusick 	if (mp->m_flag & M_UPDATE)
10539460Smckusick 		return (0);
10638414Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
10738414Smckusick 		return (error);
10838414Smckusick 	if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
10938414Smckusick 		return (error);
11038414Smckusick 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
11138414Smckusick 		return (error);
11238414Smckusick 	bzero(&pth[len], MNAMELEN-len);
11338414Smckusick 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
11438414Smckusick 		return (error);
11538414Smckusick 	bzero(&hst[len], MNAMELEN-len);
11638414Smckusick 	/* sockargs() call must be after above copyin() calls */
11738414Smckusick 	if (error = sockargs(&saddr, (caddr_t)args.addr,
118*40120Smckusick 		sizeof (struct sockaddr), MT_SONAME))
11938414Smckusick 		return (error);
12038414Smckusick 	args.fh = &nfh;
12138414Smckusick 	error = mountnfs(&args, mp, saddr, pth, hst);
12238414Smckusick 	return (error);
12338414Smckusick }
12438414Smckusick 
12538414Smckusick /*
12638414Smckusick  * Common code for mount and mountroot
12738414Smckusick  */
12838414Smckusick mountnfs(argp, mp, saddr, pth, hst)
12938414Smckusick 	register struct nfs_args *argp;
13038414Smckusick 	register struct mount *mp;
13138414Smckusick 	register struct mbuf *saddr;
13238414Smckusick 	char *pth, *hst;
13338414Smckusick {
13438414Smckusick 	register struct nfsmount *nmp;
13540010Smckusick 	struct nfsnode *np;
136*40120Smckusick 	int error;
13739757Smckusick 	fsid_t tfsid;
13838414Smckusick 
139*40120Smckusick 	MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK);
140*40120Smckusick 	bzero((caddr_t)nmp, sizeof *nmp);
14138414Smckusick 	mp->m_data = (qaddr_t)nmp;
14239757Smckusick 	/*
14339757Smckusick 	 * Generate a unique nfs mount id. The problem is that a dev number
14439757Smckusick 	 * is not unique across multiple systems. The techique is as follows:
14539757Smckusick 	 * 1) Set to nblkdev,0 which will never be used otherwise
14639757Smckusick 	 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
14739757Smckusick 	 *	NOT 0
14839757Smckusick 	 * 3) Loop searching the mount list for another one with same id
14939757Smckusick 	 *	If a match, increment val[0] and try again
15039757Smckusick 	 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
15139757Smckusick 	 *	so that nfs is not limited to 255 mount points
15239757Smckusick 	 *     Incrementing the high order bits does no real harm, since it
15339757Smckusick 	 *     simply makes the major dev number tick up. The upper bound is
15439757Smckusick 	 *     set to major dev 127 to avoid any sign extention problems
15539757Smckusick 	 */
15639757Smckusick 	mp->m_fsid.val[0] = makedev(nblkdev, 0);
15738414Smckusick 	mp->m_fsid.val[1] = MOUNT_NFS;
15839757Smckusick 	if (++nfs_mntid == 0)
15939757Smckusick 		++nfs_mntid;
16039757Smckusick 	tfsid.val[0] = makedev(nblkdev, nfs_mntid);
16139757Smckusick 	tfsid.val[1] = MOUNT_NFS;
16239757Smckusick 	while (getvfs(&tfsid)) {
16339757Smckusick 		tfsid.val[0]++;
16439757Smckusick 		nfs_mntid++;
16539757Smckusick 	}
16639757Smckusick 	if (major(tfsid.val[0]) > 127) {
16739757Smckusick 		error = ENOENT;
16839757Smckusick 		goto bad;
16939757Smckusick 	}
17039757Smckusick 	mp->m_fsid.val[0] = tfsid.val[0];
17138414Smckusick 	nmp->nm_mountp = mp;
17238414Smckusick 	nmp->nm_flag = argp->flags;
173*40120Smckusick 	nmp->nm_rto = NFS_TIMEO;
174*40120Smckusick 	nmp->nm_rtt = -1;
175*40120Smckusick 	nmp->nm_rttvar = nmp->nm_rto << 1;
176*40120Smckusick 	nmp->nm_retry = NFS_RETRANS;
177*40120Smckusick 	nmp->nm_wsize = NFS_WSIZE;
178*40120Smckusick 	nmp->nm_rsize = NFS_RSIZE;
179*40120Smckusick 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
180*40120Smckusick 	bcopy(hst, nmp->nm_host, sizeof nmp->nm_host);
181*40120Smckusick 	bcopy(pth, nmp->nm_path, sizeof nmp->nm_path);
182*40120Smckusick 
183*40120Smckusick 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
184*40120Smckusick 		nmp->nm_rto = argp->timeo;
185*40120Smckusick 		/* NFS timeouts are specified in 1/10 sec. */
186*40120Smckusick 		nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ;
187*40120Smckusick 		if (nmp->nm_rto < NFS_MINTIMEO)
188*40120Smckusick 			nmp->nm_rto = NFS_MINTIMEO;
189*40120Smckusick 		else if (nmp->nm_rto > NFS_MAXTIMEO)
190*40120Smckusick 			nmp->nm_rto = NFS_MAXTIMEO;
191*40120Smckusick 		nmp->nm_rttvar = nmp->nm_rto << 1;
192*40120Smckusick 	}
193*40120Smckusick 
194*40120Smckusick 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans >= 0) {
195*40120Smckusick 		nmp->nm_retry = argp->retrans;
196*40120Smckusick 		if (nmp->nm_retry > NFS_MAXREXMIT)
197*40120Smckusick 			nmp->nm_retry = NFS_MAXREXMIT;
198*40120Smckusick 	}
199*40120Smckusick 
200*40120Smckusick 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
20138414Smckusick 		nmp->nm_wsize = argp->wsize;
202*40120Smckusick 		/* Round down to multiple of blocksize */
203*40120Smckusick 		nmp->nm_wsize &= ~0x1ff;
204*40120Smckusick 		if (nmp->nm_wsize <= 0)
205*40120Smckusick 			nmp->nm_wsize = 512;
206*40120Smckusick 		else if (nmp->nm_wsize > NFS_MAXDATA)
207*40120Smckusick 			nmp->nm_wsize = NFS_MAXDATA;
208*40120Smckusick 	}
209*40120Smckusick 
210*40120Smckusick 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
21138414Smckusick 		nmp->nm_rsize = argp->rsize;
212*40120Smckusick 		/* Round down to multiple of blocksize */
213*40120Smckusick 		nmp->nm_rsize &= ~0x1ff;
214*40120Smckusick 		if (nmp->nm_rsize <= 0)
215*40120Smckusick 			nmp->nm_rsize = 512;
216*40120Smckusick 		else if (nmp->nm_rsize > NFS_MAXDATA)
217*40120Smckusick 			nmp->nm_rsize = NFS_MAXDATA;
218*40120Smckusick 	}
219*40120Smckusick 	/* Set up the sockets and per-host congestion */
220*40120Smckusick 	if (error = nfs_connect(nmp, saddr))
221*40120Smckusick 		goto bad;
222*40120Smckusick 
22338414Smckusick 	/*
22438425Smckusick 	 * Set to CLBYTES so that vinifod() doesn't get confused.
22538425Smckusick 	 * Actually any exact multiple of CLBYTES will do
22638425Smckusick 	 */
22738425Smckusick 	mp->m_bsize = mp->m_fsize = CLBYTES;
22840010Smckusick 	/*
22940010Smckusick 	 * A reference count is needed on the nfsnode representing the
23040010Smckusick 	 * remote root.  If this object is not persistent, then backward
23140010Smckusick 	 * traversals of the mount point (i.e. "..") will not work if
23240010Smckusick 	 * the nfsnode gets flushed out of the cache. Ufs does not have
23340010Smckusick 	 * this problem, because one can identify root inodes by their
23440010Smckusick 	 * number == ROOTINO (2).
23540010Smckusick 	 */
23640010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
23740010Smckusick 		goto bad;
23840010Smckusick 	/*
23940010Smckusick 	 * Unlock it, but keep the reference count.
24040010Smckusick 	 */
24140010Smckusick 	nfs_unlock(NFSTOV(np));
242*40120Smckusick 
24338414Smckusick 	return (0);
24438414Smckusick bad:
245*40120Smckusick 	nfs_disconnect(nmp);
246*40120Smckusick 	FREE(nmp, M_NFSMNT);
24738414Smckusick 	m_freem(saddr);
24838414Smckusick 	return (error);
24938414Smckusick }
25038414Smckusick 
25138414Smckusick /*
25238414Smckusick  * unmount system call
25338414Smckusick  */
25438414Smckusick nfs_unmount(mp, flags)
25538414Smckusick 	struct mount *mp;
25638414Smckusick 	int flags;
25738414Smckusick {
25838414Smckusick 	register struct nfsmount *nmp;
25938414Smckusick 	register struct nfsreq *rep;
26038414Smckusick 	struct nfsreq *rep2;
26140010Smckusick 	struct nfsnode *np;
262*40120Smckusick 	struct vnode *vp;
26338414Smckusick 	int error;
26438414Smckusick 	int s;
26538414Smckusick 
26638414Smckusick 	if (flags & MNT_FORCE)
26738414Smckusick 		return (EINVAL);
26838414Smckusick 	nmp = vfs_to_nfs(mp);
26938414Smckusick 	/*
27038884Smacklem 	 * Clear out the buffer cache
27138884Smacklem 	 */
27239669Smckusick 	mntflushbuf(mp, 0);
27339669Smckusick 	if (mntinvalbuf(mp))
27438884Smacklem 		return (EBUSY);
27538884Smacklem 	/*
27638414Smckusick 	 * Goes something like this..
277*40120Smckusick 	 * - Check for activity on the root vnode (other than ourselves).
278*40120Smckusick 	 * - Call vflush() to clear out vnodes for this file system,
279*40120Smckusick 	 *   except for the root vnode.
280*40120Smckusick 	 * - Decrement reference on the vnode representing remote root.
28138414Smckusick 	 * - Close the socket
28238414Smckusick 	 * - Free up the data structures
28338414Smckusick 	 */
28440010Smckusick 	/*
28540010Smckusick 	 * We need to decrement the ref. count on the nfsnode representing
28640010Smckusick 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
28740010Smckusick 	 * has done vput on this vnode, otherwise we would get deadlock!
28840010Smckusick 	 */
28940010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
29040010Smckusick 		return(error);
291*40120Smckusick 	vp = NFSTOV(np);
292*40120Smckusick 	if (vp->v_usecount > 2) {
293*40120Smckusick 		vput(vp);
294*40120Smckusick 		return (EBUSY);
295*40120Smckusick 	}
296*40120Smckusick 	if (error = vflush(mp, vp, flags)) {
297*40120Smckusick 		vput(vp);
298*40120Smckusick 		return (error);
299*40120Smckusick 	}
30040010Smckusick 	/*
30140010Smckusick 	 * Get rid of two reference counts, and unlock it on the second.
30240010Smckusick 	 */
303*40120Smckusick 	vrele(vp);
304*40120Smckusick 	vput(vp);
305*40120Smckusick 	nfs_disconnect(nmp);
30638414Smckusick 	free((caddr_t)nmp, M_NFSMNT);
30738414Smckusick 	return (0);
30838414Smckusick }
30938414Smckusick 
31038414Smckusick /*
31138414Smckusick  * Return root of a filesystem
31238414Smckusick  */
31338414Smckusick nfs_root(mp, vpp)
31438414Smckusick 	struct mount *mp;
31538414Smckusick 	struct vnode **vpp;
31638414Smckusick {
31738414Smckusick 	register struct vnode *vp;
31838414Smckusick 	struct nfsmount *nmp;
31938414Smckusick 	struct nfsnode *np;
32038414Smckusick 	int error;
32138414Smckusick 
32238414Smckusick 	nmp = vfs_to_nfs(mp);
32338414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
32438414Smckusick 		return (error);
32538414Smckusick 	vp = NFSTOV(np);
32638414Smckusick 	vp->v_type = VDIR;
32738414Smckusick 	vp->v_flag = VROOT;
32838414Smckusick 	*vpp = vp;
32938414Smckusick 	return (0);
33038414Smckusick }
33138414Smckusick 
33238884Smacklem extern int syncprt;
33338884Smacklem 
33438414Smckusick /*
33538884Smacklem  * Flush out the buffer cache
33638414Smckusick  */
33739494Smckusick /* ARGSUSED */
33838414Smckusick nfs_sync(mp, waitfor)
33938414Smckusick 	struct mount *mp;
34038414Smckusick 	int waitfor;
34138414Smckusick {
34238884Smacklem 	if (syncprt)
34338884Smacklem 		bufstats();
34438884Smacklem 	/*
34538884Smacklem 	 * Force stale buffer cache information to be flushed.
34638884Smacklem 	 */
34740035Smckusick 	mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0);
34838414Smckusick 	return (0);
34938414Smckusick }
35038414Smckusick 
35138414Smckusick /*
35238414Smckusick  * At this point, this should never happen
35338414Smckusick  */
35439494Smckusick /* ARGSUSED */
35538414Smckusick nfs_fhtovp(mp, fhp, vpp)
35638414Smckusick 	struct mount *mp;
35738414Smckusick 	struct fid *fhp;
35838414Smckusick 	struct vnode **vpp;
35938414Smckusick {
36039494Smckusick 
36138414Smckusick 	return (EINVAL);
36238414Smckusick }
36338414Smckusick 
36438414Smckusick /*
36538414Smckusick  * Vnode pointer to File handle, should never happen either
36638414Smckusick  */
36739494Smckusick /* ARGSUSED */
36838414Smckusick nfs_vptofh(mp, fhp, vpp)
36938414Smckusick 	struct mount *mp;
37038414Smckusick 	struct fid *fhp;
37138414Smckusick 	struct vnode **vpp;
37238414Smckusick {
37339494Smckusick 
37438414Smckusick 	return (EINVAL);
37538414Smckusick }
37638884Smacklem 
37738884Smacklem /*
37838884Smacklem  * Vfs start routine, a no-op.
37938884Smacklem  */
38039494Smckusick /* ARGSUSED */
38138884Smacklem nfs_start(mp, flags)
38238884Smacklem 	struct mount *mp;
38338884Smacklem 	int flags;
38438884Smacklem {
38539494Smckusick 
38638884Smacklem 	return (0);
38738884Smacklem }
388