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