xref: /netbsd-src/sys/fs/adosfs/advfsops.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
1 /*	$NetBSD: advfsops.c,v 1.56 2009/03/15 17:15:57 cegger Exp $	*/
2 
3 /*
4  * Copyright (c) 1994 Christian E. Hopps
5  * Copyright (c) 1996 Matthias Scheler
6  * All rights reserved.
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 Christian E. Hopps.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: advfsops.c,v 1.56 2009/03/15 17:15:57 cegger Exp $");
36 
37 #if defined(_KERNEL_OPT)
38 #include "opt_compat_netbsd.h"
39 #endif
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/sysctl.h>
44 #include <sys/vnode.h>
45 #include <sys/mount.h>
46 #include <sys/proc.h>
47 #include <sys/time.h>
48 #include <sys/malloc.h>
49 #include <sys/pool.h>
50 #include <sys/disklabel.h>
51 #include <miscfs/genfs/genfs.h>
52 #include <miscfs/specfs/specdev.h> /* XXX */
53 #include <sys/fcntl.h>
54 #include <sys/namei.h>
55 #include <sys/ioctl.h>
56 #include <sys/queue.h>
57 #include <sys/buf.h>
58 #include <sys/conf.h>
59 #include <sys/kauth.h>
60 #include <sys/simplelock.h>
61 #include <sys/module.h>
62 #include <fs/adosfs/adosfs.h>
63 
64 MODULE(MODULE_CLASS_VFS, adosfs, NULL);
65 
66 VFS_PROTOS(adosfs);
67 
68 static struct sysctllog *adosfs_sysctl_log;
69 
70 int adosfs_mountfs(struct vnode *, struct mount *, struct lwp *);
71 int adosfs_loadbitmap(struct adosfsmount *);
72 
73 struct simplelock adosfs_hashlock;
74 
75 struct pool adosfs_node_pool;
76 
77 MALLOC_JUSTDEFINE(M_ADOSFSMNT, "adosfs mount", "adosfs mount structures");
78 MALLOC_JUSTDEFINE(M_ANODE, "adosfs anode","adosfs anode structures and tables");
79 MALLOC_JUSTDEFINE(M_ADOSFSBITMAP, "adosfs bitmap", "adosfs bitmap");
80 
81 static const struct genfs_ops adosfs_genfsops = {
82 	.gop_size = genfs_size,
83 };
84 
85 int (**adosfs_vnodeop_p)(void *);
86 
87 int
88 adosfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
89 {
90 	struct lwp *l = curlwp;
91 	struct nameidata nd;
92 	struct vnode *devvp;
93 	struct adosfs_args *args = data;
94 	struct adosfsmount *amp;
95 	int error;
96 	mode_t accessmode;
97 
98 	if (*data_len < sizeof *args)
99 		return EINVAL;
100 
101 	if (mp->mnt_flag & MNT_GETARGS) {
102 		amp = VFSTOADOSFS(mp);
103 		if (amp == NULL)
104 			return EIO;
105 		args->uid = amp->uid;
106 		args->gid = amp->gid;
107 		args->mask = amp->mask;
108 		args->fspec = NULL;
109 		*data_len = sizeof *args;
110 		return 0;
111 	}
112 
113 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
114 		return (EROFS);
115 
116 	if ((mp->mnt_flag & MNT_UPDATE) && args->fspec == NULL)
117 		return EOPNOTSUPP;
118 
119 	/*
120 	 * Not an update, or updating the name: look up the name
121 	 * and verify that it refers to a sensible block device.
122 	 */
123 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, args->fspec);
124 	if ((error = namei(&nd)) != 0)
125 		return (error);
126 	devvp = nd.ni_vp;
127 
128 	if (devvp->v_type != VBLK) {
129 		vrele(devvp);
130 		return (ENOTBLK);
131 	}
132 	if (bdevsw_lookup(devvp->v_rdev) == NULL) {
133 		vrele(devvp);
134 		return (ENXIO);
135 	}
136 	/*
137 	 * If mount by non-root, then verify that user has necessary
138 	 * permissions on the device.
139 	 */
140 	if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) {
141 		accessmode = VREAD;
142 		if ((mp->mnt_flag & MNT_RDONLY) == 0)
143 			accessmode |= VWRITE;
144 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
145 		error = VOP_ACCESS(devvp, accessmode, l->l_cred);
146 		if (error) {
147 			vput(devvp);
148 			return (error);
149 		}
150 		VOP_UNLOCK(devvp, 0);
151 	}
152 /* MNT_UPDATE? */
153 	if ((error = adosfs_mountfs(devvp, mp, l)) != 0) {
154 		vrele(devvp);
155 		return (error);
156 	}
157 	amp = VFSTOADOSFS(mp);
158 	amp->uid = args->uid;
159 	amp->gid = args->gid;
160 	amp->mask = args->mask;
161 	return set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
162 	    mp->mnt_op->vfs_name, mp, l);
163 }
164 
165 int
166 adosfs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
167 {
168 	struct disklabel dl;
169 	struct partition *parp;
170 	struct adosfsmount *amp;
171 	struct buf *bp;
172 	struct vnode *rvp;
173 	int error, part, i;
174 
175 	part = DISKPART(devvp->v_rdev);
176 	amp = NULL;
177 
178 	if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)) != 0)
179 		return (error);
180 
181 	/*
182 	 * open blkdev and read root block
183 	 */
184 	if ((error = VOP_OPEN(devvp, FREAD, NOCRED)) != 0)
185 		return (error);
186 	error = VOP_IOCTL(devvp, DIOCGDINFO, &dl, FREAD, NOCRED);
187 	if (error)
188 		goto fail;
189 
190 	parp = &dl.d_partitions[part];
191 	amp = malloc(sizeof(struct adosfsmount), M_ADOSFSMNT, M_WAITOK);
192 	memset((char *)amp, 0, (u_long)sizeof(struct adosfsmount));
193 	amp->mp = mp;
194 	if (dl.d_type == DTYPE_FLOPPY) {
195 		amp->bsize = dl.d_secsize;
196 		amp->secsperblk = 1;
197 	}
198 	else {
199 		amp->bsize = parp->p_fsize * parp->p_frag;
200 		amp->secsperblk = parp->p_frag;
201 	}
202 
203 	/* invalid fs ? */
204 	if (amp->secsperblk == 0) {
205 		error = EINVAL;
206 		goto fail;
207 	}
208 
209 	bp = NULL;
210 	if ((error = bread(devvp, (daddr_t)BBOFF,
211 			   amp->bsize, NOCRED, 0, &bp)) != 0) {
212 		brelse(bp, 0);
213 		goto fail;
214 	}
215 	amp->dostype = adoswordn(bp, 0);
216 	brelse(bp, 0);
217 
218 	/* basic sanity checks */
219 	if (amp->dostype < 0x444f5300 || amp->dostype > 0x444f5305) {
220 		error = EINVAL;
221 		goto fail;
222 	}
223 
224 	amp->rootb = (parp->p_size / amp->secsperblk - 1 + parp->p_cpg) >> 1;
225 	amp->numblks = parp->p_size / amp->secsperblk - parp->p_cpg;
226 
227 	amp->nwords = amp->bsize >> 2;
228 	amp->dbsize = amp->bsize - (IS_FFS(amp) ? 0 : OFS_DATA_OFFSET);
229 	amp->devvp = devvp;
230 
231 	mp->mnt_data = amp;
232 	mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)devvp->v_rdev;
233 	mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_ADOSFS);
234 	mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
235 	mp->mnt_stat.f_namemax = ADMAXNAMELEN;
236 	mp->mnt_fs_bshift = ffs(amp->bsize) - 1;
237 	mp->mnt_dev_bshift = DEV_BSHIFT;	/* XXX */
238 	mp->mnt_flag |= MNT_LOCAL;
239 
240 	/*
241 	 * init anode table.
242 	 */
243 	for (i = 0; i < ANODEHASHSZ; i++)
244 		LIST_INIT(&amp->anodetab[i]);
245 
246 	/*
247 	 * get the root anode, if not a valid fs this will fail.
248 	 */
249 	if ((error = VFS_ROOT(mp, &rvp)) != 0)
250 		goto fail;
251 	/* allocate and load bitmap, set free space */
252 	amp->bitmap = malloc(((amp->numblks + 31) / 32) * sizeof(*amp->bitmap),
253 	    M_ADOSFSBITMAP, M_WAITOK);
254 	if (amp->bitmap)
255 		adosfs_loadbitmap(amp);
256 	if (mp->mnt_flag & MNT_RDONLY && amp->bitmap) {
257 		/*
258 		 * Don't need the bitmap any more if it's read-only.
259 		 */
260 		free(amp->bitmap, M_ADOSFSBITMAP);
261 		amp->bitmap = NULL;
262 	}
263 	vput(rvp);
264 
265 	return(0);
266 
267 fail:
268 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
269 	(void) VOP_CLOSE(devvp, FREAD, NOCRED);
270 	VOP_UNLOCK(devvp, 0);
271 	if (amp && amp->bitmap)
272 		free(amp->bitmap, M_ADOSFSBITMAP);
273 	if (amp)
274 		free(amp, M_ADOSFSMNT);
275 	return (error);
276 }
277 
278 int
279 adosfs_start(struct mount *mp, int flags)
280 {
281 
282 	return (0);
283 }
284 
285 int
286 adosfs_unmount(struct mount *mp, int mntflags)
287 {
288 	struct adosfsmount *amp;
289 	int error, flags;
290 
291 	flags = 0;
292 	if (mntflags & MNT_FORCE)
293 		flags |= FORCECLOSE;
294 	if ((error = vflush(mp, NULLVP, flags)) != 0)
295 		return (error);
296 	amp = VFSTOADOSFS(mp);
297 	if (amp->devvp->v_type != VBAD)
298 		amp->devvp->v_specmountpoint = NULL;
299 	vn_lock(amp->devvp, LK_EXCLUSIVE | LK_RETRY);
300 	error = VOP_CLOSE(amp->devvp, FREAD, NOCRED);
301 	vput(amp->devvp);
302 	if (amp->bitmap)
303 		free(amp->bitmap, M_ADOSFSBITMAP);
304 	free(amp, M_ADOSFSMNT);
305 	mp->mnt_data = NULL;
306 	mp->mnt_flag &= ~MNT_LOCAL;
307 	return (error);
308 }
309 
310 int
311 adosfs_root(struct mount *mp, struct vnode **vpp)
312 {
313 	struct vnode *nvp;
314 	int error;
315 
316 	if ((error = VFS_VGET(mp, (ino_t)VFSTOADOSFS(mp)->rootb, &nvp)) != 0)
317 		return (error);
318 	/* XXX verify it's a root block? */
319 	*vpp = nvp;
320 	return (0);
321 }
322 
323 int
324 adosfs_statvfs(struct mount *mp, struct statvfs *sbp)
325 {
326 	struct adosfsmount *amp;
327 
328 	amp = VFSTOADOSFS(mp);
329 	sbp->f_bsize = amp->bsize;
330 	sbp->f_frsize = amp->bsize;
331 	sbp->f_iosize = amp->dbsize;
332 	sbp->f_blocks = amp->numblks;
333 	sbp->f_bfree = amp->freeblks;
334 	sbp->f_bavail = amp->freeblks;
335 	sbp->f_bresvd = 0;
336 	sbp->f_files = 0;		/* who knows */
337 	sbp->f_ffree = 0;		/* " " */
338 	sbp->f_favail = 0;		/* " " */
339 	sbp->f_fresvd = 0;
340 	copy_statvfs_info(sbp, mp);
341 	return (0);
342 }
343 
344 /*
345  * lookup an anode, check mount's hash table if not found, create
346  * return locked and referenced al la vget(vp, 1);
347  */
348 int
349 adosfs_vget(struct mount *mp, ino_t an, struct vnode **vpp)
350 {
351 	struct adosfsmount *amp;
352 	struct vnode *vp;
353 	struct anode *ap;
354 	struct buf *bp;
355 	char *nam, *tmp;
356 	int namlen, error;
357 
358 	error = 0;
359 	amp = VFSTOADOSFS(mp);
360 	bp = NULL;
361 
362 	/*
363 	 * check hash table. we are done if found
364 	 */
365 	if ((*vpp = adosfs_ahashget(mp, an)) != NULL)
366 		return (0);
367 
368 	error = getnewvnode(VT_ADOSFS, mp, adosfs_vnodeop_p, &vp);
369 	if (error)
370 		return (error);
371 
372 	/*
373 	 * setup, insert in hash, and lock before io.
374 	 */
375 	vp->v_data = ap = pool_get(&adosfs_node_pool, PR_WAITOK);
376 	memset(ap, 0, sizeof(struct anode));
377 	ap->vp = vp;
378 	ap->amp = amp;
379 	ap->block = an;
380 	ap->nwords = amp->nwords;
381 	genfs_node_init(vp, &adosfs_genfsops);
382 	adosfs_ainshash(amp, ap);
383 
384 	if ((error = bread(amp->devvp, an * amp->bsize / DEV_BSIZE,
385 			   amp->bsize, NOCRED, 0, &bp)) != 0) {
386 		brelse(bp, 0);
387 		vput(vp);
388 		return (error);
389 	}
390 
391 	/*
392 	 * get type and fill rest in based on that.
393 	 */
394 	switch (ap->type = adosfs_getblktype(amp, bp)) {
395 	case AROOT:
396 		vp->v_type = VDIR;
397 		vp->v_vflag |= VV_ROOT;
398 		ap->mtimev.days = adoswordn(bp, ap->nwords - 10);
399 		ap->mtimev.mins = adoswordn(bp, ap->nwords - 9);
400 		ap->mtimev.ticks = adoswordn(bp, ap->nwords - 8);
401 		ap->created.days = adoswordn(bp, ap->nwords - 7);
402 		ap->created.mins = adoswordn(bp, ap->nwords - 6);
403 		ap->created.ticks = adoswordn(bp, ap->nwords - 5);
404 		break;
405 	case ALDIR:
406 	case ADIR:
407 		vp->v_type = VDIR;
408 		break;
409 	case ALFILE:
410 	case AFILE:
411 		vp->v_type = VREG;
412 		ap->fsize = adoswordn(bp, ap->nwords - 47);
413 		break;
414 	case ASLINK:		/* XXX soft link */
415 		vp->v_type = VLNK;
416 		/*
417 		 * convert from BCPL string and
418 		 * from: "part:dir/file" to: "/part/dir/file"
419 		 */
420 		nam = (char *)bp->b_data + (6 * sizeof(long));
421 		namlen = strlen(nam);
422 		tmp = nam;
423 		while (*tmp && *tmp != ':')
424 			tmp++;
425 		if (*tmp == 0) {
426 			ap->slinkto = malloc(namlen + 1, M_ANODE, M_WAITOK);
427 			memcpy(ap->slinkto, nam, namlen);
428 		} else if (*nam == ':') {
429 			ap->slinkto = malloc(namlen + 1, M_ANODE, M_WAITOK);
430 			memcpy(ap->slinkto, nam, namlen);
431 			ap->slinkto[0] = '/';
432 		} else {
433 			ap->slinkto = malloc(namlen + 2, M_ANODE, M_WAITOK);
434 			ap->slinkto[0] = '/';
435 			memcpy(&ap->slinkto[1], nam, namlen);
436 			ap->slinkto[tmp - nam + 1] = '/';
437 			namlen++;
438 		}
439 		ap->slinkto[namlen] = 0;
440 		ap->fsize = namlen;
441 		break;
442 	default:
443 		brelse(bp, 0);
444 		vput(vp);
445 		return (EINVAL);
446 	}
447 
448 	/*
449 	 * Get appropriate data from this block;  hard link needs
450 	 * to get other data from the "real" block.
451 	 */
452 
453 	/*
454 	 * copy in name (from original block)
455 	 */
456 	nam = (char *)bp->b_data + (ap->nwords - 20) * sizeof(u_int32_t);
457 	namlen = *(u_char *)nam++;
458 	if (namlen > 30) {
459 #ifdef DIAGNOSTIC
460 		printf("adosfs: aget: name length too long blk %llu\n",
461 		    (unsigned long long)an);
462 #endif
463 		brelse(bp, 0);
464 		vput(vp);
465 		return (EINVAL);
466 	}
467 	memcpy(ap->name, nam, namlen);
468 	ap->name[namlen] = 0;
469 
470 	/*
471 	 * if dir alloc hash table and copy it in
472 	 */
473 	if (vp->v_type == VDIR) {
474 		int i;
475 
476 		ap->tab = malloc(ANODETABSZ(ap) * 2, M_ANODE, M_WAITOK);
477 		ap->ntabent = ANODETABENT(ap);
478 		ap->tabi = (int *)&ap->tab[ap->ntabent];
479 		memset(ap->tabi, 0, ANODETABSZ(ap));
480 		for (i = 0; i < ap->ntabent; i++)
481 			ap->tab[i] = adoswordn(bp, i + 6);
482 	}
483 
484 	/*
485 	 * misc.
486 	 */
487 	ap->pblock = adoswordn(bp, ap->nwords - 3);
488 	ap->hashf = adoswordn(bp, ap->nwords - 4);
489 	ap->linknext = adoswordn(bp, ap->nwords - 10);
490 	ap->linkto = adoswordn(bp, ap->nwords - 11);
491 
492 	/*
493 	 * setup last indirect block cache.
494 	 */
495 	ap->lastlindblk = 0;
496 	if (ap->type == AFILE)  {
497 		ap->lastindblk = ap->block;
498 		if (adoswordn(bp, ap->nwords - 10))
499 			ap->linkto = ap->block;
500 	} else if (ap->type == ALFILE) {
501 		ap->lastindblk = ap->linkto;
502 		brelse(bp, 0);
503 		bp = NULL;
504 		error = bread(amp->devvp, ap->linkto * amp->bsize / DEV_BSIZE,
505 		    amp->bsize, NOCRED, 0, &bp);
506 		if (error) {
507 			brelse(bp, 0);
508 			vput(vp);
509 			return (error);
510 		}
511 		ap->fsize = adoswordn(bp, ap->nwords - 47);
512 		/*
513 		 * Should ap->block be set to the real file header block?
514 		 */
515 		ap->block = ap->linkto;
516 	}
517 
518 	if (ap->type == AROOT) {
519 		ap->adprot = 15;
520 		ap->uid = amp->uid;
521 		ap->gid = amp->gid;
522 	} else {
523 		ap->adprot = adoswordn(bp, ap->nwords - 48) ^ 15;
524 		/*
525 		 * ADOS directories do not have a `x' protection bit as
526 		 * it is known in VFS; this functionality is fulfilled
527 		 * by the ADOS `r' bit.
528 		 *
529 		 * To retain the ADOS behaviour, fake execute permissions
530 		 * in that case.
531 		 */
532 		if ((ap->type == ADIR || ap->type == ALDIR) &&
533 		    (ap->adprot & 0x00000008) == 0)
534 			ap->adprot &= ~0x00000002;
535 
536 		/*
537 		 * Get uid/gid from extensions in file header
538 		 * (really need to know if this is a muFS partition)
539 		 */
540 		ap->uid = (adoswordn(bp, ap->nwords - 49) >> 16) & 0xffff;
541 		ap->gid = adoswordn(bp, ap->nwords - 49) & 0xffff;
542 		if (ap->uid || ap->gid) {
543 			if (ap->uid == 0xffff)
544 				ap->uid = 0;
545 			if (ap->gid == 0xffff)
546 				ap->gid = 0;
547 			ap->adprot |= 0x40000000;	/* Kludge */
548 		}
549 		else {
550 			/*
551 			 * uid & gid extension don't exist,
552 			 * so use the mount-point uid/gid
553 			 */
554 			ap->uid = amp->uid;
555 			ap->gid = amp->gid;
556 		}
557 	}
558 	ap->mtime.days = adoswordn(bp, ap->nwords - 23);
559 	ap->mtime.mins = adoswordn(bp, ap->nwords - 22);
560 	ap->mtime.ticks = adoswordn(bp, ap->nwords - 21);
561 
562 	*vpp = vp;
563 	brelse(bp, 0);
564 	uvm_vnp_setsize(vp, ap->fsize);
565 	return (0);
566 }
567 
568 /*
569  * Load the bitmap into memory, and count the number of available
570  * blocks.
571  * The bitmap will be released if the filesystem is read-only;  it's
572  * only needed to find the free space.
573  */
574 int
575 adosfs_loadbitmap(struct adosfsmount *amp)
576 {
577 	struct buf *bp, *mapbp;
578 	u_long bn;
579 	int blkix, endix, mapix;
580 	int bmsize;
581 	int error;
582 
583 	bp = mapbp = NULL;
584 	bn = amp->rootb;
585 	if ((error = bread(amp->devvp, bn * amp->bsize / DEV_BSIZE, amp->bsize,
586 	    NOCRED, 0, &bp)) != 0) {
587 		brelse(bp, 0);
588 		return (error);
589 	}
590 	blkix = amp->nwords - 49;
591 	endix = amp->nwords - 24;
592 	mapix = 0;
593 	bmsize = (amp->numblks + 31) / 32;
594 	while (mapix < bmsize) {
595 		int n;
596 		u_long bits;
597 
598 		if (adoswordn(bp, blkix) == 0)
599 			break;
600 		if (mapbp != NULL)
601 			brelse(mapbp, 0);
602 		if ((error = bread(amp->devvp,
603 		    adoswordn(bp, blkix) * amp->bsize / DEV_BSIZE, amp->bsize,
604 		     NOCRED, 0, &mapbp)) != 0)
605 			break;
606 		if (adoscksum(mapbp, amp->nwords)) {
607 #ifdef DIAGNOSTIC
608 			printf("adosfs: loadbitmap - cksum of blk %d failed\n",
609 			    adoswordn(bp, blkix));
610 #endif
611 			/* XXX Force read-only?  Set free space 0? */
612 			break;
613 		}
614 		n = 1;
615 		while (n < amp->nwords && mapix < bmsize) {
616 			amp->bitmap[mapix++] = bits = adoswordn(mapbp, n);
617 			++n;
618 			if (mapix == bmsize && amp->numblks & 31)
619 				bits &= ~(0xffffffff << (amp->numblks & 31));
620 			while (bits) {
621 				if (bits & 1)
622 					++amp->freeblks;
623 				bits >>= 1;
624 			}
625 		}
626 		++blkix;
627 		if (mapix < bmsize && blkix == endix) {
628 			bn = adoswordn(bp, blkix);
629 			brelse(bp, 0);
630 			if ((error = bread(amp->devvp, bn * amp->bsize / DEV_BSIZE,
631 			    amp->bsize, NOCRED, 0, &bp)) != 0)
632 				break;
633 			/*
634 			 * Why is there no checksum on these blocks?
635 			 */
636 			blkix = 0;
637 			endix = amp->nwords - 1;
638 		}
639 	}
640 	if (bp)
641 		brelse(bp, 0);
642 	if (mapbp)
643 		brelse(mapbp, 0);
644 	return (error);
645 }
646 
647 
648 /*
649  * File handle to vnode
650  *
651  * Have to be really careful about stale file handles:
652  * - check that the inode number is in range
653  * - call iget() to get the locked inode
654  * - check for an unallocated inode (i_mode == 0)
655  * - check that the generation number matches
656  */
657 
658 struct ifid {
659 	ushort	ifid_len;
660 	ushort	ifid_pad;
661 	int	ifid_ino;
662 	long	ifid_start;
663 };
664 
665 int
666 adosfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
667 {
668 	struct ifid ifh;
669 #if 0
670 	struct anode *ap;
671 #endif
672 	struct vnode *nvp;
673 	int error;
674 
675 	if (fhp->fid_len != sizeof(struct ifid))
676 		return EINVAL;
677 
678 #ifdef ADOSFS_DIAGNOSTIC
679 	printf("adfhtovp(%x, %x, %x)\n", mp, fhp, vpp);
680 #endif
681 
682 	memcpy(&ifh, fhp, sizeof(ifh));
683 
684 	if ((error = VFS_VGET(mp, ifh.ifid_ino, &nvp)) != 0) {
685 		*vpp = NULLVP;
686 		return (error);
687 	}
688 #if 0
689 	ap = VTOA(nvp);
690 	if (ap->inode.iso_mode == 0) {
691 		vput(nvp);
692 		*vpp = NULLVP;
693 		return (ESTALE);
694 	}
695 #endif
696 	*vpp = nvp;
697 	return(0);
698 }
699 
700 int
701 adosfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
702 {
703 	struct anode *ap = VTOA(vp);
704 	struct ifid ifh;
705 
706 	if (*fh_size < sizeof(struct ifid)) {
707 		*fh_size = sizeof(struct ifid);
708 		return E2BIG;
709 	}
710 	*fh_size = sizeof(struct ifid);
711 
712 	memset(&ifh, 0, sizeof(ifh));
713 	ifh.ifid_len = sizeof(struct ifid);
714 	ifh.ifid_ino = ap->block;
715 	ifh.ifid_start = ap->block;
716 	memcpy(fhp, &ifh, sizeof(ifh));
717 
718 #ifdef ADOSFS_DIAGNOSTIC
719 	printf("advptofh(%x, %x)\n", vp, fhp);
720 #endif
721 	return(0);
722 }
723 
724 int
725 adosfs_sync(struct mount *mp, int waitfor, kauth_cred_t uc)
726 {
727 #ifdef ADOSFS_DIAGNOSTIC
728 	printf("ad_sync(%x, %x)\n", mp, waitfor);
729 #endif
730 	return(0);
731 }
732 
733 void
734 adosfs_init(void)
735 {
736 
737 	malloc_type_attach(M_ADOSFSMNT);
738 	malloc_type_attach(M_ANODE);
739 	malloc_type_attach(M_ADOSFSBITMAP);
740 	pool_init(&adosfs_node_pool, sizeof(struct anode), 0, 0, 0, "adosndpl",
741 	    &pool_allocator_nointr, IPL_NONE);
742 	simple_lock_init(&adosfs_hashlock);
743 }
744 
745 void
746 adosfs_done(void)
747 {
748 
749 	pool_destroy(&adosfs_node_pool);
750 	malloc_type_detach(M_ADOSFSBITMAP);
751 	malloc_type_detach(M_ANODE);
752 	malloc_type_detach(M_ADOSFSMNT);
753 }
754 
755 /*
756  * vfs generic function call table
757  */
758 
759 extern const struct vnodeopv_desc adosfs_vnodeop_opv_desc;
760 
761 const struct vnodeopv_desc *adosfs_vnodeopv_descs[] = {
762 	&adosfs_vnodeop_opv_desc,
763 	NULL,
764 };
765 
766 struct vfsops adosfs_vfsops = {
767 	MOUNT_ADOSFS,
768 	sizeof (struct adosfs_args),
769 	adosfs_mount,
770 	adosfs_start,
771 	adosfs_unmount,
772 	adosfs_root,
773 	(void *)eopnotsupp,		/* vfs_quotactl */
774 	adosfs_statvfs,
775 	adosfs_sync,
776 	adosfs_vget,
777 	adosfs_fhtovp,
778 	adosfs_vptofh,
779 	adosfs_init,
780 	NULL,
781 	adosfs_done,
782 	NULL,				/* vfs_mountroot */
783 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
784 	vfs_stdextattrctl,
785 	(void *)eopnotsupp,		/* vfs_suspendctl */
786 	genfs_renamelock_enter,
787 	genfs_renamelock_exit,
788 	(void *)eopnotsupp,
789 	adosfs_vnodeopv_descs,
790 	0,
791 	{ NULL, NULL },
792 };
793 
794 static int
795 adosfs_modcmd(modcmd_t cmd, void *arg)
796 {
797 	int error;
798 
799 	switch (cmd) {
800 	case MODULE_CMD_INIT:
801 		error = vfs_attach(&adosfs_vfsops);
802 		if (error != 0)
803 			break;
804 		sysctl_createv(&adosfs_sysctl_log, 0, NULL, NULL,
805 			       CTLFLAG_PERMANENT,
806 			       CTLTYPE_NODE, "vfs", NULL,
807 			       NULL, 0, NULL, 0,
808 			       CTL_VFS, CTL_EOL);
809 		sysctl_createv(&adosfs_sysctl_log, 0, NULL, NULL,
810 			       CTLFLAG_PERMANENT,
811 			       CTLTYPE_NODE, "adosfs",
812 			       SYSCTL_DESCR("AmigaDOS file system"),
813 			       NULL, 0, NULL, 0,
814 			       CTL_VFS, 16, CTL_EOL);
815 		/*
816 		 * XXX the "16" above could be dynamic, thereby eliminating
817 		 * one more instance of the "number to vfs" mapping problem,
818 		 * but "16" is the order as taken from sys/mount.h
819 		 */
820 		break;
821 	case MODULE_CMD_FINI:
822 		error = vfs_detach(&adosfs_vfsops);
823 		if (error != 0)
824 			break;
825 		sysctl_teardown(&adosfs_sysctl_log);
826 		break;
827 	default:
828 		error = ENOTTY;
829 		break;
830 	}
831 
832 	return (error);
833 }
834