xref: /original-bsd/sys/nfs/nfs_vfsops.c (revision 23cd6db2)
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.18 (Berkeley) 03/20/90
21  */
22 
23 #include "param.h"
24 #include "signal.h"
25 #include "user.h"
26 #include "proc.h"
27 #include "vnode.h"
28 #include "mount.h"
29 #include "errno.h"
30 #include "buf.h"
31 #include "mbuf.h"
32 #undef	m_data
33 #include "socket.h"
34 #include "systm.h"
35 #include "nfsv2.h"
36 #include "nfsnode.h"
37 #include "nfsmount.h"
38 #include "nfs.h"
39 
40 /*
41  * nfs vfs operations.
42  */
43 int nfs_mount();
44 int nfs_start();
45 int nfs_unmount();
46 int nfs_root();
47 int nfs_statfs();
48 int nfs_sync();
49 int nfs_fhtovp();
50 int nfs_vptofh();
51 int nfs_init();
52 
53 struct vfsops nfs_vfsops = {
54 	nfs_mount,
55 	nfs_start,
56 	nfs_unmount,
57 	nfs_root,
58 	nfs_statfs,
59 	nfs_sync,
60 	nfs_fhtovp,
61 	nfs_vptofh,
62 	nfs_init,
63 };
64 
65 static u_char nfs_mntid;
66 
67 /*
68  * Called by vfs_mountroot when nfs is going to be mounted as root
69  * Not Yet (By a LONG shot)
70  */
71 nfs_mountroot()
72 {
73 	return (ENODEV);
74 }
75 
76 /*
77  * VFS Operations.
78  *
79  * mount system call
80  * It seems a bit dumb to copyinstr() the host and path here and then
81  * bcopy() them in mountnfs(), but I wanted to detect errors before
82  * doing the sockargs() call because sockargs() allocates an mbuf and
83  * an error after that means that I have to release the mbuf.
84  */
85 /* ARGSUSED */
86 nfs_mount(mp, path, data, ndp)
87 	struct mount *mp;
88 	char *path;
89 	caddr_t data;
90 	struct nameidata *ndp;
91 {
92 	int error;
93 	struct nfs_args args;
94 	struct mbuf *saddr;
95 	char pth[MNAMELEN], hst[MNAMELEN];
96 	int len;
97 	nfsv2fh_t nfh;
98 
99 	if (mp->m_flag & M_UPDATE)
100 		return (0);
101 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
102 		return (error);
103 	if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
104 		return (error);
105 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
106 		return (error);
107 	bzero(&pth[len], MNAMELEN-len);
108 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
109 		return (error);
110 	bzero(&hst[len], MNAMELEN-len);
111 	/* sockargs() call must be after above copyin() calls */
112 	if (error = sockargs(&saddr, (caddr_t)args.addr,
113 		sizeof (struct sockaddr), MT_SONAME))
114 		return (error);
115 	args.fh = &nfh;
116 	error = mountnfs(&args, mp, saddr, pth, hst);
117 	return (error);
118 }
119 
120 /*
121  * Common code for mount and mountroot
122  */
123 mountnfs(argp, mp, saddr, pth, hst)
124 	register struct nfs_args *argp;
125 	register struct mount *mp;
126 	register struct mbuf *saddr;
127 	char *pth, *hst;
128 {
129 	register struct nfsmount *nmp;
130 	struct nfsnode *np;
131 	int error;
132 	fsid_t tfsid;
133 
134 	MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK);
135 	bzero((caddr_t)nmp, sizeof *nmp);
136 	mp->m_data = (qaddr_t)nmp;
137 	/*
138 	 * Generate a unique nfs mount id. The problem is that a dev number
139 	 * is not unique across multiple systems. The techique is as follows:
140 	 * 1) Set to nblkdev,0 which will never be used otherwise
141 	 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
142 	 *	NOT 0
143 	 * 3) Loop searching the mount list for another one with same id
144 	 *	If a match, increment val[0] and try again
145 	 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
146 	 *	so that nfs is not limited to 255 mount points
147 	 *     Incrementing the high order bits does no real harm, since it
148 	 *     simply makes the major dev number tick up. The upper bound is
149 	 *     set to major dev 127 to avoid any sign extention problems
150 	 */
151 	mp->m_stat.f_fsid.val[0] = makedev(nblkdev, 0);
152 	mp->m_stat.f_fsid.val[1] = MOUNT_NFS;
153 	if (++nfs_mntid == 0)
154 		++nfs_mntid;
155 	tfsid.val[0] = makedev(nblkdev, nfs_mntid);
156 	tfsid.val[1] = MOUNT_NFS;
157 	while (getvfs(&tfsid)) {
158 		tfsid.val[0]++;
159 		nfs_mntid++;
160 	}
161 	if (major(tfsid.val[0]) > 127) {
162 		error = ENOENT;
163 		m_freem(saddr);
164 		goto bad;
165 	}
166 	mp->m_stat.f_fsid.val[0] = tfsid.val[0];
167 	nmp->nm_mountp = mp;
168 	nmp->nm_flag = argp->flags;
169 	nmp->nm_rto = NFS_TIMEO;
170 	nmp->nm_rtt = -1;
171 	nmp->nm_rttvar = nmp->nm_rto << 1;
172 	nmp->nm_retry = NFS_RETRANS;
173 	nmp->nm_wsize = NFS_WSIZE;
174 	nmp->nm_rsize = NFS_RSIZE;
175 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
176 	bcopy(hst, mp->m_stat.f_mntfromname, MNAMELEN);
177 	bcopy(pth, mp->m_stat.f_mntonname, MNAMELEN);
178 
179 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
180 		nmp->nm_rto = argp->timeo;
181 		/* NFS timeouts are specified in 1/10 sec. */
182 		nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ;
183 		if (nmp->nm_rto < NFS_MINTIMEO)
184 			nmp->nm_rto = NFS_MINTIMEO;
185 		else if (nmp->nm_rto > NFS_MAXTIMEO)
186 			nmp->nm_rto = NFS_MAXTIMEO;
187 		nmp->nm_rttvar = nmp->nm_rto << 1;
188 	}
189 
190 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans >= 0) {
191 		nmp->nm_retry = argp->retrans;
192 		if (nmp->nm_retry > NFS_MAXREXMIT)
193 			nmp->nm_retry = NFS_MAXREXMIT;
194 	}
195 
196 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
197 		nmp->nm_wsize = argp->wsize;
198 		/* Round down to multiple of blocksize */
199 		nmp->nm_wsize &= ~0x1ff;
200 		if (nmp->nm_wsize <= 0)
201 			nmp->nm_wsize = 512;
202 		else if (nmp->nm_wsize > NFS_MAXDATA)
203 			nmp->nm_wsize = NFS_MAXDATA;
204 	}
205 
206 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
207 		nmp->nm_rsize = argp->rsize;
208 		/* Round down to multiple of blocksize */
209 		nmp->nm_rsize &= ~0x1ff;
210 		if (nmp->nm_rsize <= 0)
211 			nmp->nm_rsize = 512;
212 		else if (nmp->nm_rsize > NFS_MAXDATA)
213 			nmp->nm_rsize = NFS_MAXDATA;
214 	}
215 	/* Set up the sockets and per-host congestion */
216 	if (error = nfs_connect(nmp, saddr)) {
217 		m_freem(saddr);
218 		goto bad;
219 	}
220 
221 	if (error = nfs_statfs(mp, &mp->m_stat))
222 		goto bad;
223 	/*
224 	 * A reference count is needed on the nfsnode representing the
225 	 * remote root.  If this object is not persistent, then backward
226 	 * traversals of the mount point (i.e. "..") will not work if
227 	 * the nfsnode gets flushed out of the cache. Ufs does not have
228 	 * this problem, because one can identify root inodes by their
229 	 * number == ROOTINO (2).
230 	 */
231 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
232 		goto bad;
233 	/*
234 	 * Unlock it, but keep the reference count.
235 	 */
236 	nfs_unlock(NFSTOV(np));
237 	return (0);
238 
239 bad:
240 	nfs_disconnect(nmp);
241 	FREE(nmp, M_NFSMNT);
242 	return (error);
243 }
244 
245 /*
246  * unmount system call
247  */
248 nfs_unmount(mp, flags)
249 	struct mount *mp;
250 	int flags;
251 {
252 	register struct nfsmount *nmp;
253 	register struct nfsreq *rep;
254 	struct nfsreq *rep2;
255 	struct nfsnode *np;
256 	struct vnode *vp;
257 	int error;
258 	int s;
259 
260 	if (flags & MNT_FORCE)
261 		return (EINVAL);
262 	nmp = vfs_to_nfs(mp);
263 	/*
264 	 * Clear out the buffer cache
265 	 */
266 	mntflushbuf(mp, 0);
267 	if (mntinvalbuf(mp))
268 		return (EBUSY);
269 	/*
270 	 * Goes something like this..
271 	 * - Check for activity on the root vnode (other than ourselves).
272 	 * - Call vflush() to clear out vnodes for this file system,
273 	 *   except for the root vnode.
274 	 * - Decrement reference on the vnode representing remote root.
275 	 * - Close the socket
276 	 * - Free up the data structures
277 	 */
278 	/*
279 	 * We need to decrement the ref. count on the nfsnode representing
280 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
281 	 * has done vput on this vnode, otherwise we would get deadlock!
282 	 */
283 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
284 		return(error);
285 	vp = NFSTOV(np);
286 	if (vp->v_usecount > 2) {
287 		vput(vp);
288 		return (EBUSY);
289 	}
290 	if (error = vflush(mp, vp, flags)) {
291 		vput(vp);
292 		return (error);
293 	}
294 	/*
295 	 * Get rid of two reference counts, and unlock it on the second.
296 	 */
297 	vrele(vp);
298 	vput(vp);
299 	nfs_disconnect(nmp);
300 	free((caddr_t)nmp, M_NFSMNT);
301 	return (0);
302 }
303 
304 /*
305  * Return root of a filesystem
306  */
307 nfs_root(mp, vpp)
308 	struct mount *mp;
309 	struct vnode **vpp;
310 {
311 	register struct vnode *vp;
312 	struct nfsmount *nmp;
313 	struct nfsnode *np;
314 	int error;
315 
316 	nmp = vfs_to_nfs(mp);
317 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
318 		return (error);
319 	vp = NFSTOV(np);
320 	vp->v_type = VDIR;
321 	vp->v_flag = VROOT;
322 	*vpp = vp;
323 	return (0);
324 }
325 
326 extern int syncprt;
327 
328 /*
329  * Flush out the buffer cache
330  */
331 /* ARGSUSED */
332 nfs_sync(mp, waitfor)
333 	struct mount *mp;
334 	int waitfor;
335 {
336 	if (syncprt)
337 		bufstats();
338 	/*
339 	 * Force stale buffer cache information to be flushed.
340 	 */
341 	mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0);
342 	return (0);
343 }
344 
345 /*
346  * At this point, this should never happen
347  */
348 /* ARGSUSED */
349 nfs_fhtovp(mp, fhp, vpp)
350 	struct mount *mp;
351 	struct fid *fhp;
352 	struct vnode **vpp;
353 {
354 
355 	return (EINVAL);
356 }
357 
358 /*
359  * Vnode pointer to File handle, should never happen either
360  */
361 /* ARGSUSED */
362 nfs_vptofh(mp, fhp, vpp)
363 	struct mount *mp;
364 	struct fid *fhp;
365 	struct vnode **vpp;
366 {
367 
368 	return (EINVAL);
369 }
370 
371 /*
372  * Vfs start routine, a no-op.
373  */
374 /* ARGSUSED */
375 nfs_start(mp, flags)
376 	struct mount *mp;
377 	int flags;
378 {
379 
380 	return (0);
381 }
382