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