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