xref: /original-bsd/sys/nfs/nfs_vfsops.c (revision 95a66346)
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  * %sccs.include.redist.c%
9  *
10  *	@(#)nfs_vfsops.c	7.26 (Berkeley) 03/19/91
11  */
12 
13 #include "param.h"
14 #include "conf.h"
15 #include "ioctl.h"
16 #include "signal.h"
17 #include "proc.h"
18 #include "vnode.h"
19 #include "mount.h"
20 #include "buf.h"
21 #include "mbuf.h"
22 #include "socket.h"
23 #include "systm.h"
24 
25 #include "../net/if.h"
26 #include "../net/route.h"
27 #include "../netinet/in.h"
28 
29 #include "nfsv2.h"
30 #include "nfsnode.h"
31 #include "nfsmount.h"
32 #include "nfs.h"
33 #include "xdr_subs.h"
34 #include "nfsm_subs.h"
35 #include "nfsdiskless.h"
36 
37 /*
38  * nfs vfs operations.
39  */
40 int nfs_mount();
41 int nfs_start();
42 int nfs_unmount();
43 int nfs_root();
44 int nfs_quotactl();
45 int nfs_statfs();
46 int nfs_sync();
47 int nfs_fhtovp();
48 int nfs_vptofh();
49 int nfs_init();
50 
51 struct vfsops nfs_vfsops = {
52 	nfs_mount,
53 	nfs_start,
54 	nfs_unmount,
55 	nfs_root,
56 	nfs_quotactl,
57 	nfs_statfs,
58 	nfs_sync,
59 	nfs_fhtovp,
60 	nfs_vptofh,
61 	nfs_init,
62 };
63 
64 static u_char nfs_mntid;
65 extern u_long nfs_procids[NFS_NPROCS];
66 extern u_long nfs_prog, nfs_vers;
67 struct nfs_diskless nfs_diskless;
68 void nfs_disconnect();
69 
70 #define TRUE	1
71 #define	FALSE	0
72 
73 /*
74  * nfs statfs call
75  */
76 nfs_statfs(mp, sbp)
77 	struct mount *mp;
78 	register struct statfs *sbp;
79 {
80 	register struct vnode *vp;
81 	register struct nfsv2_statfs *sfp;
82 	register caddr_t cp;
83 	register long t1;
84 	caddr_t bpos, dpos, cp2;
85 	u_long xid;
86 	int error = 0;
87 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
88 	struct nfsmount *nmp;
89 	struct ucred *cred;
90 	struct nfsnode *np;
91 
92 	nmp = VFSTONFS(mp);
93 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
94 		return (error);
95 	vp = NFSTOV(np);
96 	nfsstats.rpccnt[NFSPROC_STATFS]++;
97 	cred = crget();
98 	cred->cr_ngroups = 1;
99 	nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH);
100 	nfsm_fhtom(vp);
101 	nfsm_request(vp, NFSPROC_STATFS, curproc, 0);
102 	nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
103 	sbp->f_type = MOUNT_NFS;
104 	sbp->f_flags = nmp->nm_flag;
105 	sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize);
106 	sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize);
107 	sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
108 	sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
109 	sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
110 	sbp->f_files = 0;
111 	sbp->f_ffree = 0;
112 	if (sbp != &mp->mnt_stat) {
113 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
114 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
115 	}
116 	nfsm_reqdone;
117 	nfs_nput(vp);
118 	crfree(cred);
119 	return (error);
120 }
121 
122 /*
123  * Mount a remote root fs via. nfs. This depends on the info in the
124  * nfs_diskless structure that has been filled in properly by some primary
125  * bootstrap.
126  * It goes something like this:
127  * - do enough of "ifconfig" by calling ifioctl() so that the system
128  *   can talk to the server
129  * - If nfs_diskless.mygateway is filled in, use that address as
130  *   a default gateway.
131  *   (This is done the 4.3 way with rtioctl() and should be changed)
132  * - hand craft the swap nfs vnode hanging off a fake mount point
133  * - build the rootfs mount point and call mountnfs() to do the rest.
134  */
135 nfs_mountroot()
136 {
137 	register struct mount *mp;
138 	register struct mbuf *m;
139 	struct socket *so;
140 	struct vnode *vp;
141 	int error;
142 
143 	/*
144 	 * Do enough of ifconfig(8) so that critical net interface can
145 	 * talk to the server.
146 	 */
147 	if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
148 		panic("nfs ifconf");
149 	if (ifioctl(so, SIOCAIFADDR, &nfs_diskless.myif))
150 		panic("nfs ifconf2");
151 	soclose(so);
152 
153 	/*
154 	 * If the gateway field is filled in, set it as the default route.
155 	 */
156 #ifdef COMPAT_43
157 	if (nfs_diskless.mygateway.sa_family == AF_INET) {
158 		struct ortentry rt;
159 		struct sockaddr_in *sin;
160 
161 		sin = (struct sockaddr_in *) &rt.rt_dst;
162 		sin->sin_len = sizeof (struct sockaddr_in);
163 		sin->sin_family = AF_INET;
164 		sin->sin_addr.s_addr = 0;	/* default */
165 		bcopy((caddr_t)&nfs_diskless.mygateway, (caddr_t)&rt.rt_gateway,
166 			sizeof (struct sockaddr_in));
167 		rt.rt_flags = (RTF_UP | RTF_GATEWAY);
168 		if (rtioctl(SIOCADDRT, (caddr_t)&rt))
169 			panic("nfs root route");
170 	}
171 #endif	/* COMPAT_43 */
172 
173 	/*
174 	 * If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
175 	 * Create a fake mount point just for the swap vnode so that the
176 	 * swap file can be on a different server from the rootfs.
177 	 */
178 	if (swdevt[0].sw_dev == NODEV) {
179 		mp = (struct mount *)malloc((u_long)sizeof(struct mount),
180 			M_MOUNT, M_NOWAIT);
181 		if (mp == NULL)
182 			panic("nfs root mount");
183 		mp->mnt_op = &nfs_vfsops;
184 		mp->mnt_flag = 0;
185 		mp->mnt_exroot = 0;
186 		mp->mnt_mounth = NULLVP;
187 
188 		/*
189 		 * Set up the diskless nfs_args for the swap mount point
190 		 * and then call mountnfs() to mount it.
191 		 * Since the swap file is not the root dir of a file system,
192 		 * hack it to a regular file.
193 		 */
194 		nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh;
195 		MGET(m, MT_SONAME, M_DONTWAIT);
196 		if (m == NULL)
197 			panic("nfs root mbuf");
198 		bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t),
199 			nfs_diskless.swap_saddr.sa_len);
200 		m->m_len = nfs_diskless.swap_saddr.sa_len;
201 		if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap",
202 			nfs_diskless.swap_hostnam, &vp))
203 			panic("nfs swap");
204 		vp->v_type = VREG;
205 		vp->v_flag = 0;
206 		swapdev_vp = vp;
207 		VREF(vp);
208 		swdevt[0].sw_vp = vp;
209 		VREF(vp);
210 		argdev_vp = vp;
211 	}
212 
213 	/*
214 	 * Create the rootfs mount point.
215 	 */
216 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
217 		M_MOUNT, M_NOWAIT);
218 	if (mp == NULL)
219 		panic("nfs root mount2");
220 	mp->mnt_op = &nfs_vfsops;
221 	mp->mnt_flag = MNT_RDONLY;
222 	mp->mnt_exroot = 0;
223 	mp->mnt_mounth = NULLVP;
224 
225 	/*
226 	 * Set up the root fs args and call mountnfs() to do the rest.
227 	 */
228 	nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh;
229 	MGET(m, MT_SONAME, M_DONTWAIT);
230 	if (m == NULL)
231 		panic("nfs root mbuf2");
232 	bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t),
233 		nfs_diskless.root_saddr.sa_len);
234 	m->m_len = nfs_diskless.root_saddr.sa_len;
235 	if (mountnfs(&nfs_diskless.root_args, mp, m, "/",
236 		nfs_diskless.root_hostnam, &vp))
237 		panic("nfs root");
238 	if (vfs_lock(mp))
239 		panic("nfs root2");
240 	rootfs = mp;
241 	mp->mnt_next = mp;
242 	mp->mnt_prev = mp;
243 	mp->mnt_vnodecovered = NULLVP;
244 	vfs_unlock(mp);
245 	rootvp = vp;
246 	inittodr((time_t)0);	/* There is no time in the nfs fsstat so ?? */
247 	return (0);
248 }
249 
250 /*
251  * VFS Operations.
252  *
253  * mount system call
254  * It seems a bit dumb to copyinstr() the host and path here and then
255  * bcopy() them in mountnfs(), but I wanted to detect errors before
256  * doing the sockargs() call because sockargs() allocates an mbuf and
257  * an error after that means that I have to release the mbuf.
258  */
259 /* ARGSUSED */
260 nfs_mount(mp, path, data, ndp)
261 	struct mount *mp;
262 	char *path;
263 	caddr_t data;
264 	struct nameidata *ndp;
265 {
266 	int error;
267 	struct nfs_args args;
268 	struct mbuf *nam;
269 	struct vnode *vp;
270 	char pth[MNAMELEN], hst[MNAMELEN];
271 	int len;
272 	nfsv2fh_t nfh;
273 
274 	if (mp->mnt_flag & MNT_UPDATE)
275 		return (0);
276 	if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
277 		return (error);
278 	if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
279 		return (error);
280 	if (error = copyinstr(path, pth, MNAMELEN-1, &len))
281 		return (error);
282 	bzero(&pth[len], MNAMELEN-len);
283 	if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
284 		return (error);
285 	bzero(&hst[len], MNAMELEN-len);
286 	/* sockargs() call must be after above copyin() calls */
287 	if (error = sockargs(&nam, (caddr_t)args.addr,
288 		sizeof (struct sockaddr), MT_SONAME))
289 		return (error);
290 	args.fh = &nfh;
291 	error = mountnfs(&args, mp, nam, pth, hst, &vp);
292 	return (error);
293 }
294 
295 /*
296  * Common code for mount and mountroot
297  */
298 mountnfs(argp, mp, nam, pth, hst, vpp)
299 	register struct nfs_args *argp;
300 	register struct mount *mp;
301 	struct mbuf *nam;
302 	char *pth, *hst;
303 	struct vnode **vpp;
304 {
305 	register struct nfsmount *nmp;
306 	struct nfsnode *np;
307 	int error;
308 	fsid_t tfsid;
309 
310 	MALLOC(nmp, struct nfsmount *, sizeof *nmp, M_NFSMNT, M_WAITOK);
311 	bzero((caddr_t)nmp, sizeof *nmp);
312 	mp->mnt_data = (qaddr_t)nmp;
313 	/*
314 	 * Generate a unique nfs mount id. The problem is that a dev number
315 	 * is not unique across multiple systems. The techique is as follows:
316 	 * 1) Set to nblkdev,0 which will never be used otherwise
317 	 * 2) Generate a first guess as nblkdev,nfs_mntid where nfs_mntid is
318 	 *	NOT 0
319 	 * 3) Loop searching the mount list for another one with same id
320 	 *	If a match, increment val[0] and try again
321 	 * NB: I increment val[0] { a long } instead of nfs_mntid { a u_char }
322 	 *	so that nfs is not limited to 255 mount points
323 	 *     Incrementing the high order bits does no real harm, since it
324 	 *     simply makes the major dev number tick up. The upper bound is
325 	 *     set to major dev 127 to avoid any sign extention problems
326 	 */
327 	mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev, 0);
328 	mp->mnt_stat.f_fsid.val[1] = MOUNT_NFS;
329 	if (++nfs_mntid == 0)
330 		++nfs_mntid;
331 	tfsid.val[0] = makedev(nblkdev, nfs_mntid);
332 	tfsid.val[1] = MOUNT_NFS;
333 	while (rootfs && getvfs(&tfsid)) {
334 		tfsid.val[0]++;
335 		nfs_mntid++;
336 	}
337 	if (major(tfsid.val[0]) > 127) {
338 		error = ENOENT;
339 		goto bad;
340 	}
341 	mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
342 	nmp->nm_mountp = mp;
343 	nmp->nm_flag = argp->flags;
344 	nmp->nm_rto = NFS_TIMEO;
345 	nmp->nm_rtt = -1;
346 	nmp->nm_rttvar = nmp->nm_rto << 1;
347 	nmp->nm_retry = NFS_RETRANS;
348 	nmp->nm_wsize = NFS_WSIZE;
349 	nmp->nm_rsize = NFS_RSIZE;
350 	bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
351 	mp->mnt_stat.f_type = MOUNT_NFS;
352 	bcopy(hst, mp->mnt_stat.f_mntfromname, MNAMELEN);
353 	bcopy(pth, mp->mnt_stat.f_mntonname, MNAMELEN);
354 	nmp->nm_nam = nam;
355 
356 	if ((argp->flags & NFSMNT_TIMEO) && argp->timeo > 0) {
357 		nmp->nm_rto = argp->timeo;
358 		/* NFS timeouts are specified in 1/10 sec. */
359 		nmp->nm_rto = (nmp->nm_rto * 10) / NFS_HZ;
360 		if (nmp->nm_rto < NFS_MINTIMEO)
361 			nmp->nm_rto = NFS_MINTIMEO;
362 		else if (nmp->nm_rto > NFS_MAXTIMEO)
363 			nmp->nm_rto = NFS_MAXTIMEO;
364 		nmp->nm_rttvar = nmp->nm_rto << 1;
365 	}
366 
367 	if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 1) {
368 		nmp->nm_retry = argp->retrans;
369 		if (nmp->nm_retry > NFS_MAXREXMIT)
370 			nmp->nm_retry = NFS_MAXREXMIT;
371 	}
372 
373 	if ((argp->flags & NFSMNT_WSIZE) && argp->wsize > 0) {
374 		nmp->nm_wsize = argp->wsize;
375 		/* Round down to multiple of blocksize */
376 		nmp->nm_wsize &= ~0x1ff;
377 		if (nmp->nm_wsize <= 0)
378 			nmp->nm_wsize = 512;
379 		else if (nmp->nm_wsize > NFS_MAXDATA)
380 			nmp->nm_wsize = NFS_MAXDATA;
381 	}
382 	if (nmp->nm_wsize > MAXBSIZE)
383 		nmp->nm_wsize = MAXBSIZE;
384 
385 	if ((argp->flags & NFSMNT_RSIZE) && argp->rsize > 0) {
386 		nmp->nm_rsize = argp->rsize;
387 		/* Round down to multiple of blocksize */
388 		nmp->nm_rsize &= ~0x1ff;
389 		if (nmp->nm_rsize <= 0)
390 			nmp->nm_rsize = 512;
391 		else if (nmp->nm_rsize > NFS_MAXDATA)
392 			nmp->nm_rsize = NFS_MAXDATA;
393 	}
394 	if (nmp->nm_rsize > MAXBSIZE)
395 		nmp->nm_rsize = MAXBSIZE;
396 	/* Set up the sockets and per-host congestion */
397 	nmp->nm_sotype = argp->sotype;
398 	nmp->nm_soproto = argp->proto;
399 	if (error = nfs_connect(nmp))
400 		goto bad;
401 
402 	if (error = nfs_statfs(mp, &mp->mnt_stat))
403 		goto bad;
404 	/*
405 	 * A reference count is needed on the nfsnode representing the
406 	 * remote root.  If this object is not persistent, then backward
407 	 * traversals of the mount point (i.e. "..") will not work if
408 	 * the nfsnode gets flushed out of the cache. Ufs does not have
409 	 * this problem, because one can identify root inodes by their
410 	 * number == ROOTINO (2).
411 	 */
412 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
413 		goto bad;
414 	/*
415 	 * Unlock it, but keep the reference count.
416 	 */
417 	nfs_unlock(NFSTOV(np));
418 	*vpp = NFSTOV(np);
419 
420 	return (0);
421 bad:
422 	nfs_disconnect(nmp);
423 	FREE(nmp, M_NFSMNT);
424 	m_freem(nam);
425 	return (error);
426 }
427 
428 /*
429  * unmount system call
430  */
431 nfs_unmount(mp, mntflags)
432 	struct mount *mp;
433 	int mntflags;
434 {
435 	register struct nfsmount *nmp;
436 	struct nfsnode *np;
437 	struct vnode *vp;
438 	int flags = 0;
439 	int error;
440 
441 	if (mntflags & MNT_FORCE)
442 		return (EINVAL);
443 	if (mntflags & MNT_FORCE)
444 		flags |= FORCECLOSE;
445 	nmp = VFSTONFS(mp);
446 	/*
447 	 * Clear out the buffer cache
448 	 */
449 	mntflushbuf(mp, 0);
450 	if (mntinvalbuf(mp))
451 		return (EBUSY);
452 	/*
453 	 * Goes something like this..
454 	 * - Check for activity on the root vnode (other than ourselves).
455 	 * - Call vflush() to clear out vnodes for this file system,
456 	 *   except for the root vnode.
457 	 * - Decrement reference on the vnode representing remote root.
458 	 * - Close the socket
459 	 * - Free up the data structures
460 	 */
461 	/*
462 	 * We need to decrement the ref. count on the nfsnode representing
463 	 * the remote root.  See comment in mountnfs().  The VFS unmount()
464 	 * has done vput on this vnode, otherwise we would get deadlock!
465 	 */
466 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
467 		return(error);
468 	vp = NFSTOV(np);
469 	if (vp->v_usecount > 2) {
470 		vput(vp);
471 		return (EBUSY);
472 	}
473 	if (error = vflush(mp, vp, flags)) {
474 		vput(vp);
475 		return (error);
476 	}
477 	/*
478 	 * Get rid of two reference counts, and unlock it on the second.
479 	 */
480 	vrele(vp);
481 	vput(vp);
482 	nfs_disconnect(nmp);
483 	m_freem(nmp->nm_nam);
484 	free((caddr_t)nmp, M_NFSMNT);
485 	return (0);
486 }
487 
488 /*
489  * Return root of a filesystem
490  */
491 nfs_root(mp, vpp)
492 	struct mount *mp;
493 	struct vnode **vpp;
494 {
495 	register struct vnode *vp;
496 	struct nfsmount *nmp;
497 	struct nfsnode *np;
498 	int error;
499 
500 	nmp = VFSTONFS(mp);
501 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
502 		return (error);
503 	vp = NFSTOV(np);
504 	vp->v_type = VDIR;
505 	vp->v_flag = VROOT;
506 	*vpp = vp;
507 	return (0);
508 }
509 
510 extern int syncprt;
511 
512 /*
513  * Flush out the buffer cache
514  */
515 /* ARGSUSED */
516 nfs_sync(mp, waitfor)
517 	struct mount *mp;
518 	int waitfor;
519 {
520 	if (syncprt)
521 		bufstats();
522 	/*
523 	 * Force stale buffer cache information to be flushed.
524 	 */
525 	mntflushbuf(mp, waitfor == MNT_WAIT ? B_SYNC : 0);
526 	return (0);
527 }
528 
529 /*
530  * At this point, this should never happen
531  */
532 /* ARGSUSED */
533 nfs_fhtovp(mp, fhp, vpp)
534 	struct mount *mp;
535 	struct fid *fhp;
536 	struct vnode **vpp;
537 {
538 
539 	return (EINVAL);
540 }
541 
542 /*
543  * Vnode pointer to File handle, should never happen either
544  */
545 /* ARGSUSED */
546 nfs_vptofh(mp, fhp, vpp)
547 	struct mount *mp;
548 	struct fid *fhp;
549 	struct vnode **vpp;
550 {
551 
552 	return (EINVAL);
553 }
554 
555 /*
556  * Vfs start routine, a no-op.
557  */
558 /* ARGSUSED */
559 nfs_start(mp, flags)
560 	struct mount *mp;
561 	int flags;
562 {
563 
564 	return (0);
565 }
566 
567 /*
568  * Do operations associated with quotas, not supported
569  */
570 nfs_quotactl(mp, cmd, uid, arg)
571 	struct mount *mp;
572 	int cmd;
573 	uid_t uid;
574 	caddr_t arg;
575 {
576 #ifdef lint
577 	mp = mp; cmd = cmd; uid = uid; arg = arg;
578 #endif /* lint */
579 	return (EOPNOTSUPP);
580 }
581