xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 41398)
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*41398Smckusick  *	@(#)nfs_vfsops.c	7.20 (Berkeley) 05/04/90
2138414Smckusick  */
2238414Smckusick 
2338414Smckusick #include "param.h"
2438414Smckusick #include "signal.h"
2538414Smckusick #include "user.h"
2638414Smckusick #include "proc.h"
2738414Smckusick #include "vnode.h"
2838414Smckusick #include "mount.h"
2938414Smckusick #include "errno.h"
3040120Smckusick #include "buf.h"
3138414Smckusick #include "mbuf.h"
3238414Smckusick #include "socket.h"
3340120Smckusick #include "systm.h"
3438414Smckusick #include "nfsv2.h"
3538414Smckusick #include "nfsnode.h"
3638414Smckusick #include "nfsmount.h"
3738414Smckusick #include "nfs.h"
3838414Smckusick 
3938414Smckusick /*
4038414Smckusick  * nfs vfs operations.
4138414Smckusick  */
4238414Smckusick int nfs_mount();
4338874Smckusick int nfs_start();
4438414Smckusick int nfs_unmount();
4538414Smckusick int nfs_root();
4641294Smckusick int nfs_quotactl();
4739443Smckusick int nfs_statfs();
4838414Smckusick int nfs_sync();
4938414Smckusick int nfs_fhtovp();
5038414Smckusick int nfs_vptofh();
5139443Smckusick int nfs_init();
5238414Smckusick 
5338414Smckusick struct vfsops nfs_vfsops = {
5438414Smckusick 	nfs_mount,
5538874Smckusick 	nfs_start,
5638414Smckusick 	nfs_unmount,
5738414Smckusick 	nfs_root,
5841294Smckusick 	nfs_quotactl,
5938414Smckusick 	nfs_statfs,
6038414Smckusick 	nfs_sync,
6138414Smckusick 	nfs_fhtovp,
6238414Smckusick 	nfs_vptofh,
6339443Smckusick 	nfs_init,
6438414Smckusick };
6538414Smckusick 
6639757Smckusick static u_char nfs_mntid;
6738414Smckusick 
6838414Smckusick /*
6938414Smckusick  * Called by vfs_mountroot when nfs is going to be mounted as root
7038414Smckusick  * Not Yet (By a LONG shot)
7138414Smckusick  */
7238414Smckusick nfs_mountroot()
7338414Smckusick {
7438414Smckusick 	return (ENODEV);
7538414Smckusick }
7638414Smckusick 
7738414Smckusick /*
7838414Smckusick  * VFS Operations.
7938414Smckusick  *
8038414Smckusick  * mount system call
8138414Smckusick  * It seems a bit dumb to copyinstr() the host and path here and then
8238414Smckusick  * bcopy() them in mountnfs(), but I wanted to detect errors before
8338414Smckusick  * doing the sockargs() call because sockargs() allocates an mbuf and
8438414Smckusick  * an error after that means that I have to release the mbuf.
8538414Smckusick  */
8639494Smckusick /* ARGSUSED */
8738414Smckusick nfs_mount(mp, path, data, ndp)
8838414Smckusick 	struct mount *mp;
8938414Smckusick 	char *path;
9038414Smckusick 	caddr_t data;
9138414Smckusick 	struct nameidata *ndp;
9238414Smckusick {
9338414Smckusick 	int error;
9438414Smckusick 	struct nfs_args args;
9538414Smckusick 	struct mbuf *saddr;
9638414Smckusick 	char pth[MNAMELEN], hst[MNAMELEN];
9738414Smckusick 	int len;
9838414Smckusick 	nfsv2fh_t nfh;
9938414Smckusick 
100*41398Smckusick 	if (mp->mnt_flag & MNT_UPDATE)
10139460Smckusick 		return (0);
10238414Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
10338414Smckusick 		return (error);
10438414Smckusick 	if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
10538414Smckusick 		return (error);
10638414Smckusick 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
10738414Smckusick 		return (error);
10838414Smckusick 	bzero(&pth[len], MNAMELEN-len);
10938414Smckusick 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
11038414Smckusick 		return (error);
11138414Smckusick 	bzero(&hst[len], MNAMELEN-len);
11238414Smckusick 	/* sockargs() call must be after above copyin() calls */
11338414Smckusick 	if (error = sockargs(&saddr, (caddr_t)args.addr,
11440120Smckusick 		sizeof (struct sockaddr), MT_SONAME))
11538414Smckusick 		return (error);
11638414Smckusick 	args.fh = &nfh;
11738414Smckusick 	error = mountnfs(&args, mp, saddr, pth, hst);
11838414Smckusick 	return (error);
11938414Smckusick }
12038414Smckusick 
12138414Smckusick /*
12238414Smckusick  * Common code for mount and mountroot
12338414Smckusick  */
12438414Smckusick mountnfs(argp, mp, saddr, pth, hst)
12538414Smckusick 	register struct nfs_args *argp;
12638414Smckusick 	register struct mount *mp;
12738414Smckusick 	register struct mbuf *saddr;
12838414Smckusick 	char *pth, *hst;
12938414Smckusick {
13038414Smckusick 	register struct nfsmount *nmp;
13140010Smckusick 	struct nfsnode *np;
13240120Smckusick 	int error;
13339757Smckusick 	fsid_t tfsid;
13438414Smckusick 
13540120Smckusick 	MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK);
13640120Smckusick 	bzero((caddr_t)nmp, sizeof *nmp);
137*41398Smckusick 	mp->mnt_data = (qaddr_t)nmp;
13839757Smckusick 	/*
13939757Smckusick 	 * Generate a unique nfs mount id. The problem is that a dev number
14039757Smckusick 	 * is not unique across multiple systems. The techique is as follows:
14139757Smckusick 	 * 1) Set to nblkdev,0 which will never be used otherwise
14239757Smckusick 	 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
14339757Smckusick 	 *	NOT 0
14439757Smckusick 	 * 3) Loop searching the mount list for another one with same id
14539757Smckusick 	 *	If a match, increment val[0] and try again
14639757Smckusick 	 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
14739757Smckusick 	 *	so that nfs is not limited to 255 mount points
14839757Smckusick 	 *     Incrementing the high order bits does no real harm, since it
14939757Smckusick 	 *     simply makes the major dev number tick up. The upper bound is
15039757Smckusick 	 *     set to major dev 127 to avoid any sign extention problems
15139757Smckusick 	 */
152*41398Smckusick 	mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0);
153*41398Smckusick 	mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS;
15439757Smckusick 	if (++nfs_mntid == 0)
15539757Smckusick 		++nfs_mntid;
15639757Smckusick 	tfsid.val[0] = makedev(nblkdev, nfs_mntid);
15739757Smckusick 	tfsid.val[1] = MOUNT_NFS;
15839757Smckusick 	while (getvfs(&tfsid)) {
15939757Smckusick 		tfsid.val[0]++;
16039757Smckusick 		nfs_mntid++;
16139757Smckusick 	}
16239757Smckusick 	if (major(tfsid.val[0]) > 127) {
16339757Smckusick 		error = ENOENT;
16440553Smckusick 		m_freem(saddr);
16539757Smckusick 		goto bad;
16639757Smckusick 	}
167*41398Smckusick 	mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
16838414Smckusick 	nmp->nm_mountp = mp;
16938414Smckusick 	nmp->nm_flag = argp->flags;
17040120Smckusick 	nmp->nm_rto = NFS_TIMEO;
17140120Smckusick 	nmp->nm_rtt = -1;
17240120Smckusick 	nmp->nm_rttvar = nmp->nm_rto << 1;
17340120Smckusick 	nmp->nm_retry = NFS_RETRANS;
17440120Smckusick 	nmp->nm_wsize = NFS_WSIZE;
17540120Smckusick 	nmp->nm_rsize = NFS_RSIZE;
17640120Smckusick 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
177*41398Smckusick 	mp->mnt_stat.f_type = MOUNT_NFS;
178*41398Smckusick 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
179*41398Smckusick 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
18040120Smckusick 
18140120Smckusick 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
18240120Smckusick 		nmp->nm_rto = argp->timeo;
18340120Smckusick 		/* NFS timeouts are specified in 1/10 sec. */
18440120Smckusick 		nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ;
18540120Smckusick 		if (nmp->nm_rto < NFS_MINTIMEO)
18640120Smckusick 			nmp->nm_rto = NFS_MINTIMEO;
18740120Smckusick 		else if (nmp->nm_rto > NFS_MAXTIMEO)
18840120Smckusick 			nmp->nm_rto = NFS_MAXTIMEO;
18940120Smckusick 		nmp->nm_rttvar = nmp->nm_rto << 1;
19040120Smckusick 	}
19140120Smckusick 
19240120Smckusick 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans >= 0) {
19340120Smckusick 		nmp->nm_retry = argp->retrans;
19440120Smckusick 		if (nmp->nm_retry > NFS_MAXREXMIT)
19540120Smckusick 			nmp->nm_retry = NFS_MAXREXMIT;
19640120Smckusick 	}
19740120Smckusick 
19840120Smckusick 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
19938414Smckusick 		nmp->nm_wsize = argp->wsize;
20040120Smckusick 		/* Round down to multiple of blocksize */
20140120Smckusick 		nmp->nm_wsize &= ~0x1ff;
20240120Smckusick 		if (nmp->nm_wsize <= 0)
20340120Smckusick 			nmp->nm_wsize = 512;
20440120Smckusick 		else if (nmp->nm_wsize > NFS_MAXDATA)
20540120Smckusick 			nmp->nm_wsize = NFS_MAXDATA;
20640120Smckusick 	}
20740120Smckusick 
20840120Smckusick 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
20938414Smckusick 		nmp->nm_rsize = argp->rsize;
21040120Smckusick 		/* Round down to multiple of blocksize */
21140120Smckusick 		nmp->nm_rsize &= ~0x1ff;
21240120Smckusick 		if (nmp->nm_rsize <= 0)
21340120Smckusick 			nmp->nm_rsize = 512;
21440120Smckusick 		else if (nmp->nm_rsize > NFS_MAXDATA)
21540120Smckusick 			nmp->nm_rsize = NFS_MAXDATA;
21640120Smckusick 	}
21740120Smckusick 	/* Set up the sockets and per-host congestion */
21840553Smckusick 	if (error = nfs_connect(nmp, saddr)) {
21940553Smckusick 		m_freem(saddr);
22040120Smckusick 		goto bad;
22140553Smckusick 	}
22240120Smckusick 
223*41398Smckusick 	if (error = nfs_statfs(mp, &mp->mnt_stat))
22440353Smckusick 		goto bad;
22538414Smckusick 	/*
22640010Smckusick 	 * A reference count is needed on the nfsnode representing the
22740010Smckusick 	 * remote root.  If this object is not persistent, then backward
22840010Smckusick 	 * traversals of the mount point (i.e. "..") will not work if
22940010Smckusick 	 * the nfsnode gets flushed out of the cache. Ufs does not have
23040010Smckusick 	 * this problem, because one can identify root inodes by their
23140010Smckusick 	 * number == ROOTINO (2).
23240010Smckusick 	 */
23340010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
23440010Smckusick 		goto bad;
23540010Smckusick 	/*
23640010Smckusick 	 * Unlock it, but keep the reference count.
23740010Smckusick 	 */
23840010Smckusick 	nfs_unlock(NFSTOV(np));
23940353Smckusick 	return (0);
24040120Smckusick 
24138414Smckusick bad:
24240120Smckusick 	nfs_disconnect(nmp);
24340120Smckusick 	FREE(nmp, M_NFSMNT);
24438414Smckusick 	return (error);
24538414Smckusick }
24638414Smckusick 
24738414Smckusick /*
24838414Smckusick  * unmount system call
24938414Smckusick  */
25041294Smckusick nfs_unmount(mp, mntflags)
25138414Smckusick 	struct mount *mp;
25241294Smckusick 	int mntflags;
25338414Smckusick {
25438414Smckusick 	register struct nfsmount *nmp;
25538414Smckusick 	register struct nfsreq *rep;
25638414Smckusick 	struct nfsreq *rep2;
25740010Smckusick 	struct nfsnode *np;
25840120Smckusick 	struct vnode *vp;
25941294Smckusick 	int flags = 0;
26038414Smckusick 	int error;
26138414Smckusick 	int s;
26238414Smckusick 
26341294Smckusick 	if (mntflags & MNT_FORCE)
26438414Smckusick 		return (EINVAL);
26541294Smckusick 	if (mntflags & MNT_FORCE)
26641294Smckusick 		flags |= FORCECLOSE;
267*41398Smckusick 	nmp = VFSTONFS(mp);
26838414Smckusick 	/*
26938884Smacklem 	 * Clear out the buffer cache
27038884Smacklem 	 */
27139669Smckusick 	mntflushbuf(mp, 0);
27239669Smckusick 	if (mntinvalbuf(mp))
27338884Smacklem 		return (EBUSY);
27438884Smacklem 	/*
27538414Smckusick 	 * Goes something like this..
27640120Smckusick 	 * - Check for activity on the root vnode (other than ourselves).
27740120Smckusick 	 * - Call vflush() to clear out vnodes for this file system,
27840120Smckusick 	 *   except for the root vnode.
27940120Smckusick 	 * - Decrement reference on the vnode representing remote root.
28038414Smckusick 	 * - Close the socket
28138414Smckusick 	 * - Free up the data structures
28238414Smckusick 	 */
28340010Smckusick 	/*
28440010Smckusick 	 * We need to decrement the ref. count on the nfsnode representing
28540010Smckusick 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
28640010Smckusick 	 * has done vput on this vnode, otherwise we would get deadlock!
28740010Smckusick 	 */
28840010Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
28940010Smckusick 		return(error);
29040120Smckusick 	vp = NFSTOV(np);
29140120Smckusick 	if (vp->v_usecount > 2) {
29240120Smckusick 		vput(vp);
29340120Smckusick 		return (EBUSY);
29440120Smckusick 	}
29540120Smckusick 	if (error = vflush(mp, vp, flags)) {
29640120Smckusick 		vput(vp);
29740120Smckusick 		return (error);
29840120Smckusick 	}
29940010Smckusick 	/*
30040010Smckusick 	 * Get rid of two reference counts, and unlock it on the second.
30140010Smckusick 	 */
30240120Smckusick 	vrele(vp);
30340120Smckusick 	vput(vp);
30440120Smckusick 	nfs_disconnect(nmp);
30538414Smckusick 	free((caddr_t)nmp, M_NFSMNT);
30638414Smckusick 	return (0);
30738414Smckusick }
30838414Smckusick 
30938414Smckusick /*
31038414Smckusick  * Return root of a filesystem
31138414Smckusick  */
31238414Smckusick nfs_root(mp, vpp)
31338414Smckusick 	struct mount *mp;
31438414Smckusick 	struct vnode **vpp;
31538414Smckusick {
31638414Smckusick 	register struct vnode *vp;
31738414Smckusick 	struct nfsmount *nmp;
31838414Smckusick 	struct nfsnode *np;
31938414Smckusick 	int error;
32038414Smckusick 
321*41398Smckusick 	nmp = VFSTONFS(mp);
32238414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
32338414Smckusick 		return (error);
32438414Smckusick 	vp = NFSTOV(np);
32538414Smckusick 	vp->v_type = VDIR;
32638414Smckusick 	vp->v_flag = VROOT;
32738414Smckusick 	*vpp = vp;
32838414Smckusick 	return (0);
32938414Smckusick }
33038414Smckusick 
33138884Smacklem extern int syncprt;
33238884Smacklem 
33338414Smckusick /*
33438884Smacklem  * Flush out the buffer cache
33538414Smckusick  */
33639494Smckusick /* ARGSUSED */
33738414Smckusick nfs_sync(mp, waitfor)
33838414Smckusick 	struct mount *mp;
33938414Smckusick 	int waitfor;
34038414Smckusick {
34138884Smacklem 	if (syncprt)
34238884Smacklem 		bufstats();
34338884Smacklem 	/*
34438884Smacklem 	 * Force stale buffer cache information to be flushed.
34538884Smacklem 	 */
34640035Smckusick 	mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0);
34738414Smckusick 	return (0);
34838414Smckusick }
34938414Smckusick 
35038414Smckusick /*
35138414Smckusick  * At this point, this should never happen
35238414Smckusick  */
35339494Smckusick /* ARGSUSED */
35438414Smckusick nfs_fhtovp(mp, fhp, vpp)
35538414Smckusick 	struct mount *mp;
35638414Smckusick 	struct fid *fhp;
35738414Smckusick 	struct vnode **vpp;
35838414Smckusick {
35939494Smckusick 
36038414Smckusick 	return (EINVAL);
36138414Smckusick }
36238414Smckusick 
36338414Smckusick /*
36438414Smckusick  * Vnode pointer to File handle, should never happen either
36538414Smckusick  */
36639494Smckusick /* ARGSUSED */
36738414Smckusick nfs_vptofh(mp, fhp, vpp)
36838414Smckusick 	struct mount *mp;
36938414Smckusick 	struct fid *fhp;
37038414Smckusick 	struct vnode **vpp;
37138414Smckusick {
37239494Smckusick 
37338414Smckusick 	return (EINVAL);
37438414Smckusick }
37538884Smacklem 
37638884Smacklem /*
37738884Smacklem  * Vfs start routine, a no-op.
37838884Smacklem  */
37939494Smckusick /* ARGSUSED */
38038884Smacklem nfs_start(mp, flags)
38138884Smacklem 	struct mount *mp;
38238884Smacklem 	int flags;
38338884Smacklem {
38439494Smckusick 
38538884Smacklem 	return (0);
38638884Smacklem }
38741294Smckusick 
38841294Smckusick /*
38941294Smckusick  * Do operations associated with quotas, not supported
39041294Smckusick  */
39141294Smckusick /* ARGSUSED */
39241294Smckusick nfs_quotactl(mp, cmd, uid, arg)
39341294Smckusick 	struct mount *mp;
39441294Smckusick 	int cmd;
39541294Smckusick 	uid_t uid;
39641294Smckusick 	caddr_t arg;
39741294Smckusick {
39841294Smckusick 
39941294Smckusick 	return (EOPNOTSUPP);
40041294Smckusick }
401