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