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