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