xref: /csrg-svn/sys/nfs/nfs_vfsops.c (revision 38414)
1*38414Smckusick /*
2*38414Smckusick  * Copyright (c) 1989 The Regents of the University of California.
3*38414Smckusick  * All rights reserved.
4*38414Smckusick  *
5*38414Smckusick  * This code is derived from software contributed to Berkeley by
6*38414Smckusick  * Rick Macklem at The University of Guelph.
7*38414Smckusick  *
8*38414Smckusick  * Redistribution and use in source and binary forms are permitted
9*38414Smckusick  * provided that the above copyright notice and this paragraph are
10*38414Smckusick  * duplicated in all such forms and that any documentation,
11*38414Smckusick  * advertising materials, and other materials related to such
12*38414Smckusick  * distribution and use acknowledge that the software was developed
13*38414Smckusick  * by the University of California, Berkeley.  The name of the
14*38414Smckusick  * University may not be used to endorse or promote products derived
15*38414Smckusick  * from this software without specific prior written permission.
16*38414Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17*38414Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18*38414Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19*38414Smckusick  *
20*38414Smckusick  *	@(#)nfs_vfsops.c	7.1 (Berkeley) 07/05/89
21*38414Smckusick  */
22*38414Smckusick 
23*38414Smckusick #include "param.h"
24*38414Smckusick #include "signal.h"
25*38414Smckusick #include "user.h"
26*38414Smckusick #include "proc.h"
27*38414Smckusick #include "uio.h"
28*38414Smckusick #include "ucred.h"
29*38414Smckusick #include "dir.h"
30*38414Smckusick #include "namei.h"
31*38414Smckusick #include "vnode.h"
32*38414Smckusick #include "mount.h"
33*38414Smckusick #include "errno.h"
34*38414Smckusick #include "malloc.h"
35*38414Smckusick #include "mbuf.h"
36*38414Smckusick #undef	m_data
37*38414Smckusick #include "socket.h"
38*38414Smckusick #include "socketvar.h"
39*38414Smckusick #include "../netinet/in.h"
40*38414Smckusick #include "nfsv2.h"
41*38414Smckusick #include "nfsnode.h"
42*38414Smckusick #include "nfsmount.h"
43*38414Smckusick #include "nfs.h"
44*38414Smckusick 
45*38414Smckusick #ifndef shouldbe
46*38414Smckusick #include "conf.h"
47*38414Smckusick #endif
48*38414Smckusick 
49*38414Smckusick /*
50*38414Smckusick  * nfs vfs operations.
51*38414Smckusick  */
52*38414Smckusick int nfs_mount();
53*38414Smckusick int nfs_unmount();
54*38414Smckusick int nfs_root();
55*38414Smckusick extern int nfs_statfs();
56*38414Smckusick int nfs_sync();
57*38414Smckusick int nfs_fhtovp();
58*38414Smckusick int nfs_vptofh();
59*38414Smckusick 
60*38414Smckusick struct vfsops nfs_vfsops = {
61*38414Smckusick 	nfs_mount,
62*38414Smckusick 	nfs_unmount,
63*38414Smckusick 	nfs_root,
64*38414Smckusick 	nfs_statfs,
65*38414Smckusick 	nfs_sync,
66*38414Smckusick 	nfs_fhtovp,
67*38414Smckusick 	nfs_vptofh,
68*38414Smckusick };
69*38414Smckusick 
70*38414Smckusick extern struct nfsreq nfsreqh;
71*38414Smckusick static long nfs_mntid;
72*38414Smckusick 
73*38414Smckusick /*
74*38414Smckusick  * Called by vfs_mountroot when nfs is going to be mounted as root
75*38414Smckusick  * Not Yet (By a LONG shot)
76*38414Smckusick  */
77*38414Smckusick nfs_mountroot()
78*38414Smckusick {
79*38414Smckusick 	return (ENODEV);
80*38414Smckusick }
81*38414Smckusick 
82*38414Smckusick /*
83*38414Smckusick  * VFS Operations.
84*38414Smckusick  *
85*38414Smckusick  * mount system call
86*38414Smckusick  * It seems a bit dumb to copyinstr() the host and path here and then
87*38414Smckusick  * bcopy() them in mountnfs(), but I wanted to detect errors before
88*38414Smckusick  * doing the sockargs() call because sockargs() allocates an mbuf and
89*38414Smckusick  * an error after that means that I have to release the mbuf.
90*38414Smckusick  */
91*38414Smckusick nfs_mount(mp, path, data, ndp)
92*38414Smckusick 	struct mount *mp;
93*38414Smckusick 	char *path;
94*38414Smckusick 	caddr_t data;
95*38414Smckusick 	struct nameidata *ndp;
96*38414Smckusick {
97*38414Smckusick 	int error;
98*38414Smckusick 	struct nfs_args args;
99*38414Smckusick 	struct mbuf *saddr;
100*38414Smckusick 	char pth[MNAMELEN], hst[MNAMELEN];
101*38414Smckusick 	int len;
102*38414Smckusick 	nfsv2fh_t nfh;
103*38414Smckusick 
104*38414Smckusick 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
105*38414Smckusick 		return (error);
106*38414Smckusick 	if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
107*38414Smckusick 		return (error);
108*38414Smckusick 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
109*38414Smckusick 		return (error);
110*38414Smckusick 	bzero(&pth[len], MNAMELEN-len);
111*38414Smckusick 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
112*38414Smckusick 		return (error);
113*38414Smckusick 	bzero(&hst[len], MNAMELEN-len);
114*38414Smckusick 	/* sockargs() call must be after above copyin() calls */
115*38414Smckusick 	if (error = sockargs(&saddr, (caddr_t)args.addr,
116*38414Smckusick 		sizeof (struct sockaddr_in), MT_SONAME))
117*38414Smckusick 		return (error);
118*38414Smckusick 	args.fh = &nfh;
119*38414Smckusick 	error = mountnfs(&args, mp, saddr, pth, hst);
120*38414Smckusick 	return (error);
121*38414Smckusick }
122*38414Smckusick 
123*38414Smckusick /*
124*38414Smckusick  * Common code for mount and mountroot
125*38414Smckusick  */
126*38414Smckusick mountnfs(argp, mp, saddr, pth, hst)
127*38414Smckusick 	register struct nfs_args *argp;
128*38414Smckusick 	register struct mount *mp;
129*38414Smckusick 	register struct mbuf *saddr;
130*38414Smckusick 	char *pth, *hst;
131*38414Smckusick {
132*38414Smckusick 	register struct nfsmount *nmp;
133*38414Smckusick 	struct nfsnode *np;
134*38414Smckusick 	struct statfs statf, *sbp;
135*38414Smckusick 	int error;
136*38414Smckusick 
137*38414Smckusick 	nmp = (struct nfsmount *)malloc(sizeof (struct nfsmount), M_NFSMNT,
138*38414Smckusick 	    M_WAITOK);
139*38414Smckusick 	mp->m_data = (qaddr_t)nmp;
140*38414Smckusick 	mp->m_fsid.val[0] = ++nfs_mntid;
141*38414Smckusick 	mp->m_fsid.val[1] = MOUNT_NFS;
142*38414Smckusick 	nmp->nm_mountp = mp;
143*38414Smckusick 	nmp->nm_flag = argp->flags;
144*38414Smckusick 	nmp->nm_sockaddr = saddr;
145*38414Smckusick 	/* Set up the sockets */
146*38414Smckusick 	if (error = socreate(AF_INET, &nmp->nm_so, SOCK_DGRAM, 0))
147*38414Smckusick 		goto bad;
148*38414Smckusick 	if (error = soconnect(nmp->nm_so, saddr))
149*38414Smckusick 		goto bad;
150*38414Smckusick 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo >= 1)
151*38414Smckusick 		nmp->nm_timeo = argp->timeo;
152*38414Smckusick 	else
153*38414Smckusick 		nmp->nm_timeo = NFS_TIMEO;
154*38414Smckusick 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 0)
155*38414Smckusick 		nmp->nm_retrans = argp->retrans;
156*38414Smckusick 	else
157*38414Smckusick 		nmp->nm_retrans = NFS_RETRANS;
158*38414Smckusick 	if ((argp->flags & NFSMNT_WSIZE) &&
159*38414Smckusick 	    argp->wsize <= NFS_MAXDATA && argp->wsize > 0 &&
160*38414Smckusick 	   (argp->wsize & 0x1ff) == 0)
161*38414Smckusick 		nmp->nm_wsize = argp->wsize;
162*38414Smckusick 	else
163*38414Smckusick 		nmp->nm_wsize = NFS_WSIZE;
164*38414Smckusick 	if ((argp->flags & NFSMNT_RSIZE) &&
165*38414Smckusick 	    argp->rsize <= NFS_MAXDATA && argp->rsize > 0 &&
166*38414Smckusick 	   (argp->rsize & 0x1ff) == 0)
167*38414Smckusick 		nmp->nm_rsize = argp->rsize;
168*38414Smckusick 	else
169*38414Smckusick 		nmp->nm_rsize = NFS_RSIZE;
170*38414Smckusick 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
171*38414Smckusick 	bcopy(pth, nmp->nm_path, MNAMELEN);
172*38414Smckusick 	bcopy(hst, nmp->nm_host, MNAMELEN);
173*38414Smckusick 	sbp = &statf;
174*38414Smckusick 	/*
175*38414Smckusick 	 * Kludge City...
176*38414Smckusick 	 * To do an interruptable hard mount, turn it into a soft mount
177*38414Smckusick 	 * with a retry limit of one and then repeat it so long as it
178*38414Smckusick 	 * times out and there is no pending signal for the process.
179*38414Smckusick 	 * It is tempting to just let nfs_statfs() sleep at positive
180*38414Smckusick 	 * prio, but then you would long jump out without taking the
181*38414Smckusick 	 * mount structure back out of the list.
182*38414Smckusick 	 * NB: NFSMNT_INT must NEVER be set for nfs_mountroot(), since
183*38414Smckusick 	 * the process context is not yet built!!
184*38414Smckusick 	 */
185*38414Smckusick 	if ((argp->flags && NFSMNT_INT) && (argp->flags & NFSMNT_SOFT) == 0) {
186*38414Smckusick 		int savretrans;
187*38414Smckusick 
188*38414Smckusick 		nmp->nm_flag |= NFSMNT_SOFT;
189*38414Smckusick 		savretrans = nmp->nm_retrans;
190*38414Smckusick 		nmp->nm_retrans = 1;
191*38414Smckusick 		do {
192*38414Smckusick 			error = nfs_statfs(mp, sbp);
193*38414Smckusick 		} while (error == ETIMEDOUT && (u.u_procp->p_sig &
194*38414Smckusick 			(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)|
195*38414Smckusick 			 sigmask(SIGKILL))) == 0);
196*38414Smckusick 		nmp->nm_retrans = savretrans;
197*38414Smckusick 		nmp->nm_flag &= ~NFSMNT_SOFT;
198*38414Smckusick 		if (error)
199*38414Smckusick 			goto bad;
200*38414Smckusick 	} else if (error = nfs_statfs(mp, sbp))
201*38414Smckusick 		goto bad;
202*38414Smckusick 	mp->m_fsize = sbp->f_fsize;
203*38414Smckusick 
204*38414Smckusick 	/*
205*38414Smckusick 	 * If the block size is not an exact multiple of CLBYTES
206*38414Smckusick 	 * use CLBYTES so that paging in ZMAGIC executables doesn't
207*38414Smckusick 	 * get sick. (It is used by vinitfod())
208*38414Smckusick 	 */
209*38414Smckusick 	if (sbp->f_bsize >= CLBYTES && claligned(sbp->f_bsize))
210*38414Smckusick 		mp->m_bsize = sbp->f_bsize;
211*38414Smckusick 	else
212*38414Smckusick 		mp->m_bsize = CLBYTES;
213*38414Smckusick 	return (0);
214*38414Smckusick bad:
215*38414Smckusick 	m_freem(saddr);
216*38414Smckusick 	free((caddr_t)nmp, M_NFSMNT);
217*38414Smckusick 	return (error);
218*38414Smckusick }
219*38414Smckusick 
220*38414Smckusick /*
221*38414Smckusick  * unmount system call
222*38414Smckusick  */
223*38414Smckusick nfs_unmount(mp, flags)
224*38414Smckusick 	struct mount *mp;
225*38414Smckusick 	int flags;
226*38414Smckusick {
227*38414Smckusick 	register struct nfsmount *nmp;
228*38414Smckusick 	register struct nfsreq *rep;
229*38414Smckusick 	struct nfsreq *rep2;
230*38414Smckusick 	int error;
231*38414Smckusick 	int s;
232*38414Smckusick 
233*38414Smckusick 	if (flags & MNT_FORCE)
234*38414Smckusick 		return (EINVAL);
235*38414Smckusick 	nmp = vfs_to_nfs(mp);
236*38414Smckusick 	/*
237*38414Smckusick 	 * Goes something like this..
238*38414Smckusick 	 * - Call nfs_nflush() to clear out the nfsnode table
239*38414Smckusick 	 * - Flush out lookup cache
240*38414Smckusick 	 * - Close the socket
241*38414Smckusick 	 * - Free up the data structures
242*38414Smckusick 	 */
243*38414Smckusick 	if (error = nfs_nflush(mp)) {
244*38414Smckusick 		return (error);
245*38414Smckusick 	}
246*38414Smckusick 	/*
247*38414Smckusick 	 * Scan the request list for any requests left hanging about
248*38414Smckusick 	 */
249*38414Smckusick 	s = splnet();
250*38414Smckusick 	rep = nfsreqh.r_next;
251*38414Smckusick 	while (rep) {
252*38414Smckusick 		if (rep->r_mntp == nmp) {
253*38414Smckusick 			rep->r_prev->r_next = rep2 = rep->r_next;
254*38414Smckusick 			if (rep->r_next != NULL)
255*38414Smckusick 				rep->r_next->r_prev = rep->r_prev;
256*38414Smckusick 			m_freem(rep->r_mreq);
257*38414Smckusick 			if (rep->r_mrep != NULL)
258*38414Smckusick 				m_freem(rep->r_mrep);
259*38414Smckusick 			free((caddr_t)rep, M_NFSREQ);
260*38414Smckusick 			rep = rep2;
261*38414Smckusick 		} else
262*38414Smckusick 			rep = rep->r_next;
263*38414Smckusick 	}
264*38414Smckusick 	splx(s);
265*38414Smckusick 	soclose(nmp->nm_so);
266*38414Smckusick 	m_freem(nmp->nm_sockaddr);
267*38414Smckusick 	free((caddr_t)nmp, M_NFSMNT);
268*38414Smckusick 	return (0);
269*38414Smckusick }
270*38414Smckusick 
271*38414Smckusick /*
272*38414Smckusick  * Return root of a filesystem
273*38414Smckusick  */
274*38414Smckusick nfs_root(mp, vpp)
275*38414Smckusick 	struct mount *mp;
276*38414Smckusick 	struct vnode **vpp;
277*38414Smckusick {
278*38414Smckusick 	register struct vnode *vp;
279*38414Smckusick 	struct nfsmount *nmp;
280*38414Smckusick 	struct nfsnode *np;
281*38414Smckusick 	int error;
282*38414Smckusick 
283*38414Smckusick 	nmp = vfs_to_nfs(mp);
284*38414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
285*38414Smckusick 		return (error);
286*38414Smckusick 	vp = NFSTOV(np);
287*38414Smckusick 	vp->v_type = VDIR;
288*38414Smckusick 	vp->v_flag = VROOT;
289*38414Smckusick 	*vpp = vp;
290*38414Smckusick 	return (0);
291*38414Smckusick }
292*38414Smckusick 
293*38414Smckusick /*
294*38414Smckusick  * Since writes are synchronous, I think this is a no-op
295*38414Smckusick  * Maybe write cache on nfs version 3 will require something ??
296*38414Smckusick  */
297*38414Smckusick nfs_sync(mp, waitfor)
298*38414Smckusick 	struct mount *mp;
299*38414Smckusick 	int waitfor;
300*38414Smckusick {
301*38414Smckusick 	return (0);
302*38414Smckusick }
303*38414Smckusick 
304*38414Smckusick /*
305*38414Smckusick  * At this point, this should never happen
306*38414Smckusick  */
307*38414Smckusick nfs_fhtovp(mp, fhp, vpp)
308*38414Smckusick 	struct mount *mp;
309*38414Smckusick 	struct fid *fhp;
310*38414Smckusick 	struct vnode **vpp;
311*38414Smckusick {
312*38414Smckusick 	return (EINVAL);
313*38414Smckusick }
314*38414Smckusick 
315*38414Smckusick /*
316*38414Smckusick  * Vnode pointer to File handle, should never happen either
317*38414Smckusick  */
318*38414Smckusick nfs_vptofh(mp, fhp, vpp)
319*38414Smckusick 	struct mount *mp;
320*38414Smckusick 	struct fid *fhp;
321*38414Smckusick 	struct vnode **vpp;
322*38414Smckusick {
323*38414Smckusick 	return (EINVAL);
324*38414Smckusick }
325