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