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