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