xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 39757)
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*39757Smckusick  *	@(#)nfs_vfsops.c	7.11 (Berkeley) 12/20/89
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*39757Smckusick #include "systm.h"
3038425Smckusick #include "../ufs/dir.h"
3138414Smckusick #include "namei.h"
3238414Smckusick #include "vnode.h"
3338414Smckusick #include "mount.h"
3438414Smckusick #include "errno.h"
3538414Smckusick #include "malloc.h"
3638414Smckusick #include "mbuf.h"
3738414Smckusick #undef	m_data
3838414Smckusick #include "socket.h"
3938414Smckusick #include "socketvar.h"
4038414Smckusick #include "../netinet/in.h"
4138414Smckusick #include "nfsv2.h"
4238414Smckusick #include "nfsnode.h"
4338414Smckusick #include "nfsmount.h"
4438414Smckusick #include "nfs.h"
4538414Smckusick 
4638414Smckusick #ifndef shouldbe
4738414Smckusick #include "conf.h"
4838414Smckusick #endif
4938414Smckusick 
5038414Smckusick /*
5138414Smckusick  * nfs vfs operations.
5238414Smckusick  */
5338414Smckusick int nfs_mount();
5438874Smckusick int nfs_start();
5538414Smckusick int nfs_unmount();
5638414Smckusick int nfs_root();
5739443Smckusick int nfs_statfs();
5838414Smckusick int nfs_sync();
5938414Smckusick int nfs_fhtovp();
6038414Smckusick int nfs_vptofh();
6139443Smckusick int nfs_init();
6238414Smckusick 
6338414Smckusick struct vfsops nfs_vfsops = {
6438414Smckusick 	nfs_mount,
6538874Smckusick 	nfs_start,
6638414Smckusick 	nfs_unmount,
6738414Smckusick 	nfs_root,
6838414Smckusick 	nfs_statfs,
6938414Smckusick 	nfs_sync,
7038414Smckusick 	nfs_fhtovp,
7138414Smckusick 	nfs_vptofh,
7239443Smckusick 	nfs_init,
7338414Smckusick };
7438414Smckusick 
7538414Smckusick extern struct nfsreq nfsreqh;
76*39757Smckusick static u_char nfs_mntid;
7738414Smckusick 
7838414Smckusick /*
7938414Smckusick  * Called by vfs_mountroot when nfs is going to be mounted as root
8038414Smckusick  * Not Yet (By a LONG shot)
8138414Smckusick  */
8238414Smckusick nfs_mountroot()
8338414Smckusick {
8438414Smckusick 	return (ENODEV);
8538414Smckusick }
8638414Smckusick 
8738414Smckusick /*
8838414Smckusick  * VFS Operations.
8938414Smckusick  *
9038414Smckusick  * mount system call
9138414Smckusick  * It seems a bit dumb to copyinstr() the host and path here and then
9238414Smckusick  * bcopy() them in mountnfs(), but I wanted to detect errors before
9338414Smckusick  * doing the sockargs() call because sockargs() allocates an mbuf and
9438414Smckusick  * an error after that means that I have to release the mbuf.
9538414Smckusick  */
9639494Smckusick /* ARGSUSED */
9738414Smckusick nfs_mount(mp, path, data, ndp)
9838414Smckusick 	struct mount *mp;
9938414Smckusick 	char *path;
10038414Smckusick 	caddr_t data;
10138414Smckusick 	struct nameidata *ndp;
10238414Smckusick {
10338414Smckusick 	int error;
10438414Smckusick 	struct nfs_args args;
10538414Smckusick 	struct mbuf *saddr;
10638414Smckusick 	char pth[MNAMELEN], hst[MNAMELEN];
10738414Smckusick 	int len;
10838414Smckusick 	nfsv2fh_t nfh;
10938414Smckusick 
11039460Smckusick 	if (mp->m_flag & M_UPDATE)
11139460Smckusick 		return (0);
11238414Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
11338414Smckusick 		return (error);
11438414Smckusick 	if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
11538414Smckusick 		return (error);
11638414Smckusick 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
11738414Smckusick 		return (error);
11838414Smckusick 	bzero(&pth[len], MNAMELEN-len);
11938414Smckusick 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
12038414Smckusick 		return (error);
12138414Smckusick 	bzero(&hst[len], MNAMELEN-len);
12238414Smckusick 	/* sockargs() call must be after above copyin() calls */
12338414Smckusick 	if (error = sockargs(&saddr, (caddr_t)args.addr,
12438414Smckusick 		sizeof (struct sockaddr_in), MT_SONAME))
12538414Smckusick 		return (error);
12638414Smckusick 	args.fh = &nfh;
12738414Smckusick 	error = mountnfs(&args, mp, saddr, pth, hst);
12838414Smckusick 	return (error);
12938414Smckusick }
13038414Smckusick 
13138414Smckusick /*
13238414Smckusick  * Common code for mount and mountroot
13338414Smckusick  */
13438414Smckusick mountnfs(argp, mp, saddr, pth, hst)
13538414Smckusick 	register struct nfs_args *argp;
13638414Smckusick 	register struct mount *mp;
13738414Smckusick 	register struct mbuf *saddr;
13838414Smckusick 	char *pth, *hst;
13938414Smckusick {
14038414Smckusick 	register struct nfsmount *nmp;
141*39757Smckusick 	fsid_t tfsid;
14238414Smckusick 	int error;
14338414Smckusick 
14438414Smckusick 	nmp = (struct nfsmount *)malloc(sizeof (struct nfsmount), M_NFSMNT,
14538414Smckusick 	    M_WAITOK);
14638414Smckusick 	mp->m_data = (qaddr_t)nmp;
147*39757Smckusick 	/*
148*39757Smckusick 	 * Generate a unique nfs mount id. The problem is that a dev number
149*39757Smckusick 	 * is not unique across multiple systems. The techique is as follows:
150*39757Smckusick 	 * 1) Set to nblkdev,0 which will never be used otherwise
151*39757Smckusick 	 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
152*39757Smckusick 	 *	NOT 0
153*39757Smckusick 	 * 3) Loop searching the mount list for another one with same id
154*39757Smckusick 	 *	If a match, increment val[0] and try again
155*39757Smckusick 	 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
156*39757Smckusick 	 *	so that nfs is not limited to 255 mount points
157*39757Smckusick 	 *     Incrementing the high order bits does no real harm, since it
158*39757Smckusick 	 *     simply makes the major dev number tick up. The upper bound is
159*39757Smckusick 	 *     set to major dev 127 to avoid any sign extention problems
160*39757Smckusick 	 */
161*39757Smckusick 	mp->m_fsid.val[0] = makedev(nblkdev, 0);
16238414Smckusick 	mp->m_fsid.val[1] = MOUNT_NFS;
163*39757Smckusick 	if (++nfs_mntid == 0)
164*39757Smckusick 		++nfs_mntid;
165*39757Smckusick 	tfsid.val[0] = makedev(nblkdev, nfs_mntid);
166*39757Smckusick 	tfsid.val[1] = MOUNT_NFS;
167*39757Smckusick 	while (getvfs(&tfsid)) {
168*39757Smckusick 		tfsid.val[0]++;
169*39757Smckusick 		nfs_mntid++;
170*39757Smckusick 	}
171*39757Smckusick 	if (major(tfsid.val[0]) > 127) {
172*39757Smckusick 		error = ENOENT;
173*39757Smckusick 		goto bad;
174*39757Smckusick 	}
175*39757Smckusick 	mp->m_fsid.val[0] = tfsid.val[0];
17638414Smckusick 	nmp->nm_mountp = mp;
17738414Smckusick 	nmp->nm_flag = argp->flags;
17838414Smckusick 	nmp->nm_sockaddr = saddr;
17938414Smckusick 	/* Set up the sockets */
18038414Smckusick 	if (error = socreate(AF_INET, &nmp->nm_so, SOCK_DGRAM, 0))
18138414Smckusick 		goto bad;
18238414Smckusick 	if (error = soconnect(nmp->nm_so, saddr))
18338414Smckusick 		goto bad;
18438414Smckusick 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo >= 1)
18538414Smckusick 		nmp->nm_timeo = argp->timeo;
18638414Smckusick 	else
18738414Smckusick 		nmp->nm_timeo = NFS_TIMEO;
18838414Smckusick 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 0)
18938414Smckusick 		nmp->nm_retrans = argp->retrans;
19038414Smckusick 	else
19138414Smckusick 		nmp->nm_retrans = NFS_RETRANS;
19238414Smckusick 	if ((argp->flags & NFSMNT_WSIZE) &&
19338414Smckusick 	    argp->wsize <= NFS_MAXDATA && argp->wsize > 0 &&
19438414Smckusick 	   (argp->wsize & 0x1ff) == 0)
19538414Smckusick 		nmp->nm_wsize = argp->wsize;
19638414Smckusick 	else
19738414Smckusick 		nmp->nm_wsize = NFS_WSIZE;
19838414Smckusick 	if ((argp->flags & NFSMNT_RSIZE) &&
19938414Smckusick 	    argp->rsize <= NFS_MAXDATA && argp->rsize > 0 &&
20038414Smckusick 	   (argp->rsize & 0x1ff) == 0)
20138414Smckusick 		nmp->nm_rsize = argp->rsize;
20238414Smckusick 	else
20338414Smckusick 		nmp->nm_rsize = NFS_RSIZE;
20438414Smckusick 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
20538414Smckusick 	bcopy(pth, nmp->nm_path, MNAMELEN);
20638414Smckusick 	bcopy(hst, nmp->nm_host, MNAMELEN);
20738414Smckusick 	/*
20838425Smckusick 	 * Set to CLBYTES so that vinifod() doesn't get confused.
20938425Smckusick 	 * Actually any exact multiple of CLBYTES will do
21038425Smckusick 	 */
21138425Smckusick 	mp->m_bsize = mp->m_fsize = CLBYTES;
21238414Smckusick 	return (0);
21338414Smckusick bad:
21438414Smckusick 	m_freem(saddr);
21538414Smckusick 	free((caddr_t)nmp, M_NFSMNT);
21638414Smckusick 	return (error);
21738414Smckusick }
21838414Smckusick 
21938414Smckusick /*
22038414Smckusick  * unmount system call
22138414Smckusick  */
22238414Smckusick nfs_unmount(mp, flags)
22338414Smckusick 	struct mount *mp;
22438414Smckusick 	int flags;
22538414Smckusick {
22638414Smckusick 	register struct nfsmount *nmp;
22738414Smckusick 	register struct nfsreq *rep;
22838414Smckusick 	struct nfsreq *rep2;
22938414Smckusick 	int error;
23038414Smckusick 	int s;
23138414Smckusick 
23238414Smckusick 	if (flags & MNT_FORCE)
23338414Smckusick 		return (EINVAL);
23438414Smckusick 	nmp = vfs_to_nfs(mp);
23538414Smckusick 	/*
23638884Smacklem 	 * Clear out the buffer cache
23738884Smacklem 	 */
23839669Smckusick 	mntflushbuf(mp, 0);
23939669Smckusick 	if (mntinvalbuf(mp))
24038884Smacklem 		return (EBUSY);
24138884Smacklem 	/*
24238414Smckusick 	 * Goes something like this..
24339510Smckusick 	 * - Call vflush() to clear out vnodes for this file system
24438414Smckusick 	 * - Flush out lookup cache
24538414Smckusick 	 * - Close the socket
24638414Smckusick 	 * - Free up the data structures
24738414Smckusick 	 */
24839510Smckusick 	if (error = vflush(mp, (struct vnode *)0, flags))
24938414Smckusick 		return (error);
25038414Smckusick 	/*
25138414Smckusick 	 * Scan the request list for any requests left hanging about
25238414Smckusick 	 */
25338414Smckusick 	s = splnet();
25438414Smckusick 	rep = nfsreqh.r_next;
25539347Smckusick 	while (rep && rep != &nfsreqh) {
25638414Smckusick 		if (rep->r_mntp == nmp) {
25738414Smckusick 			rep->r_prev->r_next = rep2 = rep->r_next;
25839347Smckusick 			rep->r_next->r_prev = rep->r_prev;
25938414Smckusick 			m_freem(rep->r_mreq);
26038414Smckusick 			if (rep->r_mrep != NULL)
26138414Smckusick 				m_freem(rep->r_mrep);
26238414Smckusick 			free((caddr_t)rep, M_NFSREQ);
26338414Smckusick 			rep = rep2;
26438414Smckusick 		} else
26538414Smckusick 			rep = rep->r_next;
26638414Smckusick 	}
26738414Smckusick 	splx(s);
26838414Smckusick 	soclose(nmp->nm_so);
26938414Smckusick 	m_freem(nmp->nm_sockaddr);
27038414Smckusick 	free((caddr_t)nmp, M_NFSMNT);
27138414Smckusick 	return (0);
27238414Smckusick }
27338414Smckusick 
27438414Smckusick /*
27538414Smckusick  * Return root of a filesystem
27638414Smckusick  */
27738414Smckusick nfs_root(mp, vpp)
27838414Smckusick 	struct mount *mp;
27938414Smckusick 	struct vnode **vpp;
28038414Smckusick {
28138414Smckusick 	register struct vnode *vp;
28238414Smckusick 	struct nfsmount *nmp;
28338414Smckusick 	struct nfsnode *np;
28438414Smckusick 	int error;
28538414Smckusick 
28638414Smckusick 	nmp = vfs_to_nfs(mp);
28738414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
28838414Smckusick 		return (error);
28938414Smckusick 	vp = NFSTOV(np);
29038414Smckusick 	vp->v_type = VDIR;
29138414Smckusick 	vp->v_flag = VROOT;
29238414Smckusick 	*vpp = vp;
29338414Smckusick 	return (0);
29438414Smckusick }
29538414Smckusick 
29638884Smacklem extern int syncprt;
29738884Smacklem 
29838414Smckusick /*
29938884Smacklem  * Flush out the buffer cache
30038414Smckusick  */
30139494Smckusick /* ARGSUSED */
30238414Smckusick nfs_sync(mp, waitfor)
30338414Smckusick 	struct mount *mp;
30438414Smckusick 	int waitfor;
30538414Smckusick {
30638884Smacklem 	if (syncprt)
30738884Smacklem 		bufstats();
30838884Smacklem 	/*
30938884Smacklem 	 * Force stale buffer cache information to be flushed.
31038884Smacklem 	 */
31139669Smckusick 	mntflushbuf(mp);
31238414Smckusick 	return (0);
31338414Smckusick }
31438414Smckusick 
31538414Smckusick /*
31638414Smckusick  * At this point, this should never happen
31738414Smckusick  */
31839494Smckusick /* ARGSUSED */
31938414Smckusick nfs_fhtovp(mp, fhp, vpp)
32038414Smckusick 	struct mount *mp;
32138414Smckusick 	struct fid *fhp;
32238414Smckusick 	struct vnode **vpp;
32338414Smckusick {
32439494Smckusick 
32538414Smckusick 	return (EINVAL);
32638414Smckusick }
32738414Smckusick 
32838414Smckusick /*
32938414Smckusick  * Vnode pointer to File handle, should never happen either
33038414Smckusick  */
33139494Smckusick /* ARGSUSED */
33238414Smckusick nfs_vptofh(mp, fhp, vpp)
33338414Smckusick 	struct mount *mp;
33438414Smckusick 	struct fid *fhp;
33538414Smckusick 	struct vnode **vpp;
33638414Smckusick {
33739494Smckusick 
33838414Smckusick 	return (EINVAL);
33938414Smckusick }
34038884Smacklem 
34138884Smacklem /*
34238884Smacklem  * Vfs start routine, a no-op.
34338884Smacklem  */
34439494Smckusick /* ARGSUSED */
34538884Smacklem nfs_start(mp, flags)
34638884Smacklem 	struct mount *mp;
34738884Smacklem 	int flags;
34838884Smacklem {
34939494Smckusick 
35038884Smacklem 	return (0);
35138884Smacklem }
352