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