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