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