This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sys / ufs / ufs_vfsops.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1989, 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)ufs_vfsops.c 7.56 (Berkeley) 6/28/91
34 */
35
36#include "param.h"
37#include "systm.h"
38#include "namei.h"
39#include "proc.h"
40#include "kernel.h"
41#include "vnode.h"
42#include "specdev.h"
43#include "mount.h"
44#include "buf.h"
45#include "file.h"
46#include "dkbad.h" /* XXX */
47#include "disklabel.h"
48#include "ioctl.h"
49#include "errno.h"
50#include "malloc.h"
51
52#include "quota.h"
53#include "fs.h"
54#include "ufsmount.h"
55#include "inode.h"
56
57struct vfsops ufs_vfsops = {
58 ufs_mount,
59 ufs_start,
60 ufs_unmount,
61 ufs_root,
62 ufs_quotactl,
63 ufs_statfs,
64 ufs_sync,
65 ufs_fhtovp,
66 ufs_vptofh,
67 ufs_init
68};
69
70/*
71 * Flag to allow forcible unmounting.
72 */
73int doforce = 1;
74
75/*
76 * Called by vfs_mountroot when ufs is going to be mounted as root.
77 *
78 * Name is updated by mount(8) after booting.
79 */
80#define ROOTNAME "root_device"
81
82ufs_mountroot()
83{
84 register struct mount *mp;
85 extern struct vnode *rootvp;
86 struct proc *p = curproc; /* XXX */
87 struct ufsmount *ump;
88 register struct fs *fs;
89 u_int size;
90 int error;
91
92 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
93 M_MOUNT, M_WAITOK);
94 mp->mnt_op = &ufs_vfsops;
95 mp->mnt_flag = MNT_RDONLY;
96 mp->mnt_exroot = 0;
97 mp->mnt_mounth = NULLVP;
98 error = mountfs(rootvp, mp, p);
99 if (error) {
100 free((caddr_t)mp, M_MOUNT);
101 return (error);
102 }
103 if (error = vfs_lock(mp)) {
104 (void)ufs_unmount(mp, 0, p);
105 free((caddr_t)mp, M_MOUNT);
106 return (error);
107 }
108 rootfs = mp;
109 mp->mnt_next = mp;
110 mp->mnt_prev = mp;
111 mp->mnt_vnodecovered = NULLVP;
112 ump = VFSTOUFS(mp);
113 fs = ump->um_fs;
114 bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
115 fs->fs_fsmnt[0] = '/';
116 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
117 MNAMELEN);
118 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
119 &size);
120 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
121 (void) ufs_statfs(mp, &mp->mnt_stat, p);
122 vfs_unlock(mp);
123 inittodr(fs->fs_time);
124 return (0);
125}
126
127/*
128 * VFS Operations.
129 *
130 * mount system call
131 */
132ufs_mount(mp, path, data, ndp, p)
133 register struct mount *mp;
134 char *path;
135 caddr_t data;
136 struct nameidata *ndp;
137 struct proc *p;
138{
139 struct vnode *devvp;
140 struct ufs_args args;
141 struct ufsmount *ump;
142 register struct fs *fs;
143 u_int size;
144 int error;
145
146 if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
147 return (error);
148 /*
149 * Process export requests.
150 */
151 if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) {
152 if (args.exflags & MNT_EXPORTED)
153 mp->mnt_flag |= MNT_EXPORTED;
154 else
155 mp->mnt_flag &= ~MNT_EXPORTED;
156 if (args.exflags & MNT_EXRDONLY)
157 mp->mnt_flag |= MNT_EXRDONLY;
158 else
159 mp->mnt_flag &= ~MNT_EXRDONLY;
160 mp->mnt_exroot = args.exroot;
161 }
162 /*
163 * If updating, check whether changing from read-only to
164 * read/write; if there is no device name, that's all we do.
165 */
166 if (mp->mnt_flag & MNT_UPDATE) {
167 ump = VFSTOUFS(mp);
168 fs = ump->um_fs;
169 if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
170 fs->fs_ronly = 0;
171 if (args.fspec == 0)
172 return (0);
173 }
174 /*
175 * Not an update, or updating the name: look up the name
176 * and verify that it refers to a sensible block device.
177 */
178 ndp->ni_nameiop = LOOKUP | FOLLOW;
179 ndp->ni_segflg = UIO_USERSPACE;
180 ndp->ni_dirp = args.fspec;
181 if (error = namei(ndp, p))
182 return (error);
183 devvp = ndp->ni_vp;
184 if (devvp->v_type != VBLK) {
185 vrele(devvp);
186 return (ENOTBLK);
187 }
188 if (major(devvp->v_rdev) >= nblkdev) {
189 vrele(devvp);
190 return (ENXIO);
191 }
192 if ((mp->mnt_flag & MNT_UPDATE) == 0)
193 error = mountfs(devvp, mp, p);
194 else {
195 if (devvp != ump->um_devvp)
196 error = EINVAL; /* needs translation */
197 else
198 vrele(devvp);
199 }
200 if (error) {
201 vrele(devvp);
202 return (error);
203 }
204 ump = VFSTOUFS(mp);
205 fs = ump->um_fs;
206 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
207 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
208 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
209 MNAMELEN);
210 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
211 &size);
212 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
213 (void) ufs_statfs(mp, &mp->mnt_stat, p);
214 return (0);
215}
216
217/*
218 * Common code for mount and mountroot
219 */
220mountfs(devvp, mp, p)
221 register struct vnode *devvp;
222 struct mount *mp;
223 struct proc *p;
224{
225 register struct ufsmount *ump = (struct ufsmount *)0;
226 struct buf *bp = NULL;
227 register struct fs *fs;
228 dev_t dev = devvp->v_rdev;
229 struct partinfo dpart;
230 caddr_t base, space;
231 int havepart = 0, blks;
232 int error, i, size;
233 int needclose = 0;
234 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
235 extern struct vnode *rootvp;
236
237 /*
238 * Disallow multiple mounts of the same device.
239 * Disallow mounting of a device that is currently in use
240 * (except for root, which might share swap device for miniroot).
241 * Flush out any old buffers remaining from a previous use.
242 */
243 if (error = mountedon(devvp))
244 return (error);
245 if (vcount(devvp) > 1 && devvp != rootvp)
246 return (EBUSY);
247 vinvalbuf(devvp, 1);
248 if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p))
249 return (error);
250 needclose = 1;
251 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
252 size = DEV_BSIZE;
253 else {
254 havepart = 1;
255 size = dpart.disklab->d_secsize;
256 }
257 if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp))
258 goto out;
259 fs = bp->b_un.b_fs;
260 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
261 fs->fs_bsize < sizeof(struct fs)) {
262 error = EINVAL; /* XXX needs translation */
263 goto out;
264 }
265 ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
266 ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
267 M_WAITOK);
268 bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs,
269 (u_int)fs->fs_sbsize);
270 if (fs->fs_sbsize < SBSIZE)
271 bp->b_flags |= B_INVAL;
272 brelse(bp);
273 bp = NULL;
274 fs = ump->um_fs;
275 fs->fs_ronly = ronly;
276 if (ronly == 0)
277 fs->fs_fmod = 1;
278 if (havepart) {
279 dpart.part->p_fstype = FS_BSDFFS;
280 dpart.part->p_fsize = fs->fs_fsize;
281 dpart.part->p_frag = fs->fs_frag;
282 dpart.part->p_cpg = fs->fs_cpg;
283 }
284 blks = howmany(fs->fs_cssize, fs->fs_fsize);
285 base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK,
286 M_WAITOK);
287 for (i = 0; i < blks; i += fs->fs_frag) {
288 size = fs->fs_bsize;
289 if (i + fs->fs_frag > blks)
290 size = (blks - i) * fs->fs_fsize;
291 error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
292 NOCRED, &bp);
293 if (error) {
294 free((caddr_t)base, M_SUPERBLK);
295 goto out;
296 }
297 bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size);
298 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
299 space += size;
300 brelse(bp);
301 bp = NULL;
302 }
303 mp->mnt_data = (qaddr_t)ump;
304 mp->mnt_stat.f_fsid.val[0] = (long)dev;
305 mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS;
306 mp->mnt_flag |= MNT_LOCAL;
307 ump->um_mountp = mp;
308 ump->um_dev = dev;
309 ump->um_devvp = devvp;
310 for (i = 0; i < MAXQUOTAS; i++)
311 ump->um_quotas[i] = NULLVP;
312 devvp->v_specflags |= SI_MOUNTEDON;
313
314 /* Sanity checks for old file systems. XXX */
315 fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */
316 fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */
317 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
318 fs->fs_nrpos = 8; /* XXX */
319 return (0);
320out:
321 if (bp)
322 brelse(bp);
323 if (needclose)
324 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
325 if (ump) {
326 free((caddr_t)ump->um_fs, M_SUPERBLK);
327 free((caddr_t)ump, M_UFSMNT);
328 mp->mnt_data = (qaddr_t)0;
329 }
330 return (error);
331}
332
333/*
334 * Make a filesystem operational.
335 * Nothing to do at the moment.
336 */
337/* ARGSUSED */
338ufs_start(mp, flags, p)
339 struct mount *mp;
340 int flags;
341 struct proc *p;
342{
343
344 return (0);
345}
346
347/*
348 * unmount system call
349 */
350ufs_unmount(mp, mntflags, p)
351 struct mount *mp;
352 int mntflags;
353 struct proc *p;
354{
355 register struct ufsmount *ump;
356 register struct fs *fs;
357 int i, error, ronly, flags = 0;
358
359 if (mntflags & MNT_FORCE) {
360 if (!doforce || mp == rootfs)
361 return (EINVAL);
362 flags |= FORCECLOSE;
363 }
364 mntflushbuf(mp, 0);
365 if (mntinvalbuf(mp))
366 return (EBUSY);
367 ump = VFSTOUFS(mp);
368#ifdef QUOTA
369 if (mp->mnt_flag & MNT_QUOTA) {
370 if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
371 return (error);
372 for (i = 0; i < MAXQUOTAS; i++) {
373 if (ump->um_quotas[i] == NULLVP)
374 continue;
375 quotaoff(p, mp, i);
376 }
377 /*
378 * Here we fall through to vflush again to ensure
379 * that we have gotten rid of all the system vnodes.
380 */
381 }
382#endif
383 if (error = vflush(mp, NULLVP, flags))
384 return (error);
385 fs = ump->um_fs;
386 ronly = !fs->fs_ronly;
387 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
388 error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE,
389 NOCRED, p);
390 vrele(ump->um_devvp);
391 free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
392 free((caddr_t)fs, M_SUPERBLK);
393 free((caddr_t)ump, M_UFSMNT);
394 mp->mnt_data = (qaddr_t)0;
395 mp->mnt_flag &= ~MNT_LOCAL;
396 return (error);
397}
398
399/*
400 * Check to see if a filesystem is mounted on a block device.
401 */
402mountedon(vp)
403 register struct vnode *vp;
404{
405 register struct vnode *vq;
406
407 if (vp->v_specflags & SI_MOUNTEDON)
408 return (EBUSY);
409 if (vp->v_flag & VALIASED) {
410 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
411 if (vq->v_rdev != vp->v_rdev ||
412 vq->v_type != vp->v_type)
413 continue;
414 if (vq->v_specflags & SI_MOUNTEDON)
415 return (EBUSY);
416 }
417 }
418 return (0);
419}
420
421/*
422 * Return root of a filesystem
423 */
424ufs_root(mp, vpp)
425 struct mount *mp;
426 struct vnode **vpp;
427{
428 register struct inode *ip;
429 struct inode *nip;
430 struct vnode tvp;
431 int error;
432
433 tvp.v_mount = mp;
434 ip = VTOI(&tvp);
435 ip->i_vnode = &tvp;
436 ip->i_dev = VFSTOUFS(mp)->um_dev;
437 error = iget(ip, (ino_t)ROOTINO, &nip);
438 if (error)
439 return (error);
440 *vpp = ITOV(nip);
441 return (0);
442}
443
444/*
445 * Do operations associated with quotas
446 */
447ufs_quotactl(mp, cmds, uid, arg, p)
448 struct mount *mp;
449 int cmds;
450 uid_t uid;
451 caddr_t arg;
452 struct proc *p;
453{
454 struct ufsmount *ump = VFSTOUFS(mp);
455 int cmd, type, error;
456
457#ifndef QUOTA
458 return (EOPNOTSUPP);
459#else
460 if (uid == -1)
461 uid = p->p_cred->p_ruid;
462 cmd = cmds >> SUBCMDSHIFT;
463
464 switch (cmd) {
465 case Q_GETQUOTA:
466 case Q_SYNC:
467 if (uid == p->p_cred->p_ruid)
468 break;
469 /* fall through */
470 default:
471 if (error = suser(p->p_ucred, &p->p_acflag))
472 return (error);
473 }
474
475 type = cmd & SUBCMDMASK;
476 if ((u_int)type >= MAXQUOTAS)
477 return (EINVAL);
478
479 switch (cmd) {
480
481 case Q_QUOTAON:
482 return (quotaon(p, mp, type, arg));
483
484 case Q_QUOTAOFF:
485 if (vfs_busy(mp))
486 return (0);
487 error = quotaoff(p, mp, type);
488 vfs_unbusy(mp);
489 return (error);
490
491 case Q_SETQUOTA:
492 return (setquota(mp, uid, type, arg));
493
494 case Q_SETUSE:
495 return (setuse(mp, uid, type, arg));
496
497 case Q_GETQUOTA:
498 return (getquota(mp, uid, type, arg));
499
500 case Q_SYNC:
501 if (vfs_busy(mp))
502 return (0);
503 error = qsync(mp);
504 vfs_unbusy(mp);
505 return (error);
506
507 default:
508 return (EINVAL);
509 }
510 /* NOTREACHED */
511#endif
512}
513
514/*
515 * Get file system statistics.
516 */
517ufs_statfs(mp, sbp, p)
518 struct mount *mp;
519 register struct statfs *sbp;
520 struct proc *p;
521{
522 register struct ufsmount *ump;
523 register struct fs *fs;
524
525 ump = VFSTOUFS(mp);
526 fs = ump->um_fs;
527 if (fs->fs_magic != FS_MAGIC)
528 panic("ufs_statfs");
529 sbp->f_type = MOUNT_UFS;
530 sbp->f_fsize = fs->fs_fsize;
531 sbp->f_bsize = fs->fs_bsize;
532 sbp->f_blocks = fs->fs_dsize;
533 sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
534 fs->fs_cstotal.cs_nffree;
535 sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
536 (fs->fs_dsize - sbp->f_bfree);
537 sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
538 sbp->f_ffree = fs->fs_cstotal.cs_nifree;
539 if (sbp != &mp->mnt_stat) {
540 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
541 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
542 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
543 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
544 }
545 return (0);
546}
547
548int syncprt = 0;
549
550/*
551 * Go through the disk queues to initiate sandbagged IO;
552 * go through the inodes to write those that have been modified;
553 * initiate the writing of the super block if it has been modified.
554 *
555 * Note: we are always called with the filesystem marked `MPBUSY'.
556 */
557ufs_sync(mp, waitfor)
558 struct mount *mp;
559 int waitfor;
560{
561 register struct vnode *vp;
562 register struct inode *ip;
563 register struct ufsmount *ump = VFSTOUFS(mp);
564 register struct fs *fs;
565 int error, allerror = 0;
566
567 if (syncprt)
568 bufstats();
569 fs = ump->um_fs;
570 /*
571 * Write back modified superblock.
572 * Consistency check that the superblock
573 * is still in the buffer cache.
574 */
575 if (fs->fs_fmod != 0) {
576 if (fs->fs_ronly != 0) { /* XXX */
577 printf("fs = %s\n", fs->fs_fsmnt);
578 panic("update: rofs mod");
579 }
580 fs->fs_fmod = 0;
581 fs->fs_time = time.tv_sec;
582 allerror = sbupdate(ump, waitfor);
583 }
584 /*
585 * Write back each (modified) inode.
586 */
587loop:
588 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
589 /*
590 * If the vnode that we are about to sync is no longer
591 * associated with this mount point, start over.
592 */
593 if (vp->v_mount != mp)
594 goto loop;
595 if (VOP_ISLOCKED(vp))
596 continue;
597 ip = VTOI(vp);
598 if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 &&
599 vp->v_dirtyblkhd == NULL)
600 continue;
601 if (vget(vp))
602 goto loop;
603 if (vp->v_dirtyblkhd)
604 vflushbuf(vp, 0);
605 if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) &&
606 (error = iupdat(ip, &time, &time, 0)))
607 allerror = error;
608 vput(vp);
609 }
610 /*
611 * Force stale file system control information to be flushed.
612 */
613 vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0);
614#ifdef QUOTA
615 qsync(mp);
616#endif
617 return (allerror);
618}
619
620/*
621 * Write a superblock and associated information back to disk.
622 */
623sbupdate(mp, waitfor)
624 struct ufsmount *mp;
625 int waitfor;
626{
627 register struct fs *fs = mp->um_fs;
628 register struct buf *bp;
629 int blks;
630 caddr_t space;
631 int i, size, error = 0;
632
633 bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize);
634 bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
635 /* Restore compatibility to old file systems. XXX */
636 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
637 bp->b_un.b_fs->fs_nrpos = -1; /* XXX */
638 if (waitfor == MNT_WAIT)
639 error = bwrite(bp);
640 else
641 bawrite(bp);
642 blks = howmany(fs->fs_cssize, fs->fs_fsize);
643 space = (caddr_t)fs->fs_csp[0];
644 for (i = 0; i < blks; i += fs->fs_frag) {
645 size = fs->fs_bsize;
646 if (i + fs->fs_frag > blks)
647 size = (blks - i) * fs->fs_fsize;
648 bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size);
649 bcopy(space, bp->b_un.b_addr, (u_int)size);
650 space += size;
651 if (waitfor == MNT_WAIT)
652 error = bwrite(bp);
653 else
654 bawrite(bp);
655 }
656 return (error);
657}
658
659/*
660 * Print out statistics on the current allocation of the buffer pool.
661 * Can be enabled to print out on every ``sync'' by setting "syncprt"
662 * above.
663 */
664bufstats()
665{
666 int s, i, j, count;
667 register struct buf *bp, *dp;
668 int counts[MAXBSIZE/CLBYTES+1];
669 static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
670
671 for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) {
672 count = 0;
673 for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
674 counts[j] = 0;
675 s = splbio();
676 for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) {
677 counts[dp->b_bufsize/CLBYTES]++;
678 count++;
679 }
680 splx(s);
681 printf("%s: total-%d", bname[i], count);
682 for (j = 0; j <= MAXBSIZE/CLBYTES; j++)
683 if (counts[j] != 0)
684 printf(", %d-%d", j * CLBYTES, counts[j]);
685 printf("\n");
686 }
687}
688
689/*
690 * File handle to vnode
691 *
692 * Have to be really careful about stale file handles:
693 * - check that the inode number is in range
694 * - call iget() to get the locked inode
695 * - check for an unallocated inode (i_mode == 0)
696 * - check that the generation number matches
697 */
698ufs_fhtovp(mp, fhp, vpp)
699 register struct mount *mp;
700 struct fid *fhp;
701 struct vnode **vpp;
702{
703 register struct ufid *ufhp;
704 register struct fs *fs;
705 register struct inode *ip;
706 struct inode *nip;
707 struct vnode tvp;
708 int error;
709
710 ufhp = (struct ufid *)fhp;
711 fs = VFSTOUFS(mp)->um_fs;
712 if (ufhp->ufid_ino < ROOTINO ||
713 ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) {
714 *vpp = NULLVP;
715 return (EINVAL);
716 }
717 tvp.v_mount = mp;
718 ip = VTOI(&tvp);
719 ip->i_vnode = &tvp;
720 ip->i_dev = VFSTOUFS(mp)->um_dev;
721 if (error = iget(ip, ufhp->ufid_ino, &nip)) {
722 *vpp = NULLVP;
723 return (error);
724 }
725 ip = nip;
726 if (ip->i_mode == 0) {
727 iput(ip);
728 *vpp = NULLVP;
729 return (EINVAL);
730 }
731 if (ip->i_gen != ufhp->ufid_gen) {
732 iput(ip);
733 *vpp = NULLVP;
734 return (EINVAL);
735 }
736 *vpp = ITOV(ip);
737 return (0);
738}
739
740/*
741 * Vnode pointer to File handle
742 */
743/* ARGSUSED */
744ufs_vptofh(vp, fhp)
745 struct vnode *vp;
746 struct fid *fhp;
747{
748 register struct inode *ip = VTOI(vp);
749 register struct ufid *ufhp;
750
751 ufhp = (struct ufid *)fhp;
752 ufhp->ufid_len = sizeof(struct ufid);
753 ufhp->ufid_ino = ip->i_number;
754 ufhp->ufid_gen = ip->i_gen;
755 return (0);
756}