1 /* $NetBSD: cd9660_vfsops.c,v 1.16 2004/07/05 07:28:45 pk Exp $ */ 2 3 /*- 4 * Copyright (c) 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley 8 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension 9 * Support code is derived from software contributed to Berkeley 10 * by Atsushi Murai (amurai@spec.co.jp). 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)cd9660_vfsops.c 8.18 (Berkeley) 5/22/95 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: cd9660_vfsops.c,v 1.16 2004/07/05 07:28:45 pk Exp $"); 41 42 #if defined(_KERNEL_OPT) 43 #include "opt_compat_netbsd.h" 44 #endif 45 46 #include <sys/param.h> 47 #include <sys/sysctl.h> 48 #include <sys/systm.h> 49 #include <sys/namei.h> 50 #include <sys/proc.h> 51 #include <sys/kernel.h> 52 #include <sys/vnode.h> 53 #include <miscfs/specfs/specdev.h> 54 #include <sys/mount.h> 55 #include <sys/buf.h> 56 #include <sys/file.h> 57 #include <sys/disklabel.h> 58 #include <sys/device.h> 59 #include <sys/ioctl.h> 60 #include <sys/cdio.h> 61 #include <sys/errno.h> 62 #include <sys/malloc.h> 63 #include <sys/pool.h> 64 #include <sys/stat.h> 65 #include <sys/conf.h> 66 67 #include <fs/cd9660/iso.h> 68 #include <fs/cd9660/cd9660_extern.h> 69 #include <fs/cd9660/iso_rrip.h> 70 #include <fs/cd9660/cd9660_node.h> 71 #include <fs/cd9660/cd9660_mount.h> 72 73 MALLOC_DEFINE(M_ISOFSMNT, "ISOFS mount", "ISOFS mount structure"); 74 75 extern const struct vnodeopv_desc cd9660_vnodeop_opv_desc; 76 extern const struct vnodeopv_desc cd9660_specop_opv_desc; 77 extern const struct vnodeopv_desc cd9660_fifoop_opv_desc; 78 79 const struct vnodeopv_desc * const cd9660_vnodeopv_descs[] = { 80 &cd9660_vnodeop_opv_desc, 81 &cd9660_specop_opv_desc, 82 &cd9660_fifoop_opv_desc, 83 NULL, 84 }; 85 86 struct vfsops cd9660_vfsops = { 87 MOUNT_CD9660, 88 cd9660_mount, 89 cd9660_start, 90 cd9660_unmount, 91 cd9660_root, 92 cd9660_quotactl, 93 cd9660_statvfs, 94 cd9660_sync, 95 cd9660_vget, 96 cd9660_fhtovp, 97 cd9660_vptofh, 98 cd9660_init, 99 cd9660_reinit, 100 cd9660_done, 101 NULL, 102 cd9660_mountroot, 103 cd9660_check_export, 104 (int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp, 105 cd9660_vnodeopv_descs, 106 }; 107 108 struct genfs_ops cd9660_genfsops = { 109 genfs_size, 110 }; 111 112 /* 113 * Called by vfs_mountroot when iso is going to be mounted as root. 114 * 115 * Name is updated by mount(8) after booting. 116 */ 117 #define ROOTNAME "root_device" 118 119 static int iso_makemp __P((struct iso_mnt *isomp, struct buf *bp, int *ea_len)); 120 static int iso_mountfs __P((struct vnode *devvp, struct mount *mp, 121 struct proc *p, struct iso_args *argp)); 122 123 int 124 cd9660_mountroot() 125 { 126 struct mount *mp; 127 struct proc *p = curproc; /* XXX */ 128 int error; 129 struct iso_args args; 130 131 if (root_device->dv_class != DV_DISK) 132 return (ENODEV); 133 134 /* 135 * Get vnodes for swapdev and rootdev. 136 */ 137 if (bdevvp(rootdev, &rootvp)) 138 panic("cd9660_mountroot: can't setup rootvp"); 139 140 if ((error = vfs_rootmountalloc(MOUNT_CD9660, "root_device", &mp)) 141 != 0) { 142 vrele(rootvp); 143 return (error); 144 } 145 146 args.flags = ISOFSMNT_ROOT; 147 if ((error = iso_mountfs(rootvp, mp, p, &args)) != 0) { 148 mp->mnt_op->vfs_refcount--; 149 vfs_unbusy(mp); 150 free(mp, M_MOUNT); 151 vrele(rootvp); 152 return (error); 153 } 154 simple_lock(&mountlist_slock); 155 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 156 simple_unlock(&mountlist_slock); 157 (void)cd9660_statvfs(mp, &mp->mnt_stat, p); 158 vfs_unbusy(mp); 159 return (0); 160 } 161 162 /* 163 * VFS Operations. 164 * 165 * mount system call 166 */ 167 int 168 cd9660_mount(mp, path, data, ndp, p) 169 struct mount *mp; 170 const char *path; 171 void *data; 172 struct nameidata *ndp; 173 struct proc *p; 174 { 175 struct vnode *devvp; 176 struct iso_args args; 177 int error; 178 struct iso_mnt *imp = NULL; 179 180 if (mp->mnt_flag & MNT_GETARGS) { 181 imp = VFSTOISOFS(mp); 182 if (imp == NULL) 183 return EIO; 184 args.fspec = NULL; 185 args.flags = imp->im_flags; 186 vfs_showexport(mp, &args.export, &imp->im_export); 187 return copyout(&args, data, sizeof(args)); 188 } 189 error = copyin(data, &args, sizeof (struct iso_args)); 190 if (error) 191 return (error); 192 193 if ((mp->mnt_flag & MNT_RDONLY) == 0) 194 return (EROFS); 195 196 /* 197 * If updating, check whether changing from read-only to 198 * read/write; if there is no device name, that's all we do. 199 */ 200 if (mp->mnt_flag & MNT_UPDATE) { 201 imp = VFSTOISOFS(mp); 202 if (args.fspec == 0) 203 return (vfs_export(mp, &imp->im_export, &args.export)); 204 } 205 /* 206 * Not an update, or updating the name: look up the name 207 * and verify that it refers to a sensible block device. 208 */ 209 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 210 if ((error = namei(ndp)) != 0) 211 return (error); 212 devvp = ndp->ni_vp; 213 214 if (devvp->v_type != VBLK) { 215 vrele(devvp); 216 return ENOTBLK; 217 } 218 if (bdevsw_lookup(devvp->v_rdev) == NULL) { 219 vrele(devvp); 220 return ENXIO; 221 } 222 /* 223 * If mount by non-root, then verify that user has necessary 224 * permissions on the device. 225 */ 226 if (p->p_ucred->cr_uid != 0) { 227 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 228 error = VOP_ACCESS(devvp, VREAD, p->p_ucred, p); 229 VOP_UNLOCK(devvp, 0); 230 if (error) { 231 vrele(devvp); 232 return (error); 233 } 234 } 235 if ((mp->mnt_flag & MNT_UPDATE) == 0) 236 error = iso_mountfs(devvp, mp, p, &args); 237 else { 238 if (devvp != imp->im_devvp) 239 error = EINVAL; /* needs translation */ 240 else 241 vrele(devvp); 242 } 243 if (error) { 244 vrele(devvp); 245 return error; 246 } 247 imp = VFSTOISOFS(mp); 248 return set_statvfs_info(path, UIO_USERSPACE, args.fspec, UIO_USERSPACE, 249 mp, p); 250 } 251 252 /* 253 * Make a mount point from a volume descriptor 254 */ 255 static int 256 iso_makemp(isomp, bp, ea_len) 257 struct iso_mnt *isomp; 258 struct buf *bp; 259 int *ea_len; 260 { 261 struct iso_primary_descriptor *pri; 262 int logical_block_size; 263 struct iso_directory_record *rootp; 264 265 pri = (struct iso_primary_descriptor *)bp->b_data; 266 267 logical_block_size = isonum_723 (pri->logical_block_size); 268 269 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE 270 || (logical_block_size & (logical_block_size - 1)) != 0) 271 return -1; 272 273 rootp = (struct iso_directory_record *)pri->root_directory_record; 274 275 isomp->logical_block_size = logical_block_size; 276 isomp->volume_space_size = isonum_733 (pri->volume_space_size); 277 memcpy(isomp->root, rootp, sizeof(isomp->root)); 278 isomp->root_extent = isonum_733 (rootp->extent); 279 isomp->root_size = isonum_733 (rootp->size); 280 isomp->im_joliet_level = 0; 281 282 isomp->im_bmask = logical_block_size - 1; 283 isomp->im_bshift = 0; 284 while ((1 << isomp->im_bshift) < isomp->logical_block_size) 285 isomp->im_bshift++; 286 287 if (ea_len != NULL) 288 *ea_len = isonum_711(rootp->ext_attr_length); 289 290 return 0; 291 } 292 293 /* 294 * Common code for mount and mountroot 295 */ 296 static int 297 iso_mountfs(devvp, mp, p, argp) 298 struct vnode *devvp; 299 struct mount *mp; 300 struct proc *p; 301 struct iso_args *argp; 302 { 303 struct iso_mnt *isomp = (struct iso_mnt *)0; 304 struct buf *bp = NULL, *pribp = NULL, *supbp = NULL; 305 dev_t dev = devvp->v_rdev; 306 int error = EINVAL; 307 int needclose = 0; 308 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 309 int iso_bsize; 310 int iso_blknum; 311 int joliet_level; 312 struct iso_volume_descriptor *vdp; 313 struct iso_supplementary_descriptor *sup; 314 int sess = 0; 315 int ext_attr_length; 316 struct disklabel label; 317 318 if (!ronly) 319 return EROFS; 320 321 /* 322 * Disallow multiple mounts of the same device. 323 * Disallow mounting of a device that is currently in use 324 * (except for root, which might share swap device for miniroot). 325 * Flush out any old buffers remaining from a previous use. 326 */ 327 if ((error = vfs_mountedon(devvp)) != 0) 328 return error; 329 if (vcount(devvp) > 1 && devvp != rootvp) 330 return EBUSY; 331 if ((error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) 332 return (error); 333 334 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 335 if (error) 336 return error; 337 needclose = 1; 338 339 /* This is the "logical sector size". The standard says this 340 * should be 2048 or the physical sector size on the device, 341 * whichever is greater. For now, we'll just use a constant. 342 */ 343 iso_bsize = ISO_DEFAULT_BLOCK_SIZE; 344 345 error = VOP_IOCTL(devvp, DIOCGDINFO, &label, FREAD, FSCRED, p); 346 if (!error && 347 label.d_partitions[DISKPART(dev)].p_fstype == FS_ISO9660) { 348 /* XXX more sanity checks? */ 349 sess = label.d_partitions[DISKPART(dev)].p_cdsession; 350 } else { 351 /* fallback to old method */ 352 error = VOP_IOCTL(devvp, CDIOREADMSADDR, &sess, 0, FSCRED, p); 353 if (error) 354 sess = 0; /* never mind */ 355 } 356 #ifdef ISO_DEBUG 357 printf("isofs: session offset (part %d) %d\n", DISKPART(dev), sess); 358 #endif 359 360 for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) { 361 if ((error = bread(devvp, (iso_blknum+sess) * btodb(iso_bsize), 362 iso_bsize, NOCRED, &bp)) != 0) 363 goto out; 364 365 vdp = (struct iso_volume_descriptor *)bp->b_data; 366 if (memcmp(vdp->id, ISO_STANDARD_ID, sizeof(vdp->id)) != 0) { 367 error = EINVAL; 368 goto out; 369 } 370 371 switch (isonum_711(vdp->type)) { 372 case ISO_VD_PRIMARY: 373 if (pribp == NULL) { 374 pribp = bp; 375 bp = NULL; 376 } 377 break; 378 379 case ISO_VD_SUPPLEMENTARY: 380 if (supbp == NULL) { 381 supbp = bp; 382 bp = NULL; 383 } 384 break; 385 386 default: 387 break; 388 } 389 390 if (isonum_711 (vdp->type) == ISO_VD_END) { 391 brelse(bp); 392 bp = NULL; 393 break; 394 } 395 396 if (bp != NULL) { 397 brelse(bp); 398 bp = NULL; 399 } 400 } 401 402 if (pribp == NULL) { 403 error = EINVAL; 404 goto out; 405 } 406 407 isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK); 408 memset(isomp, 0, sizeof *isomp); 409 if (iso_makemp(isomp, pribp, &ext_attr_length) == -1) { 410 error = EINVAL; 411 goto out; 412 } 413 414 isomp->volume_space_size += sess; 415 416 pribp->b_flags |= B_AGE; 417 brelse(pribp); 418 pribp = NULL; 419 420 mp->mnt_data = isomp; 421 mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev; 422 mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_CD9660); 423 mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; 424 mp->mnt_maxsymlinklen = 0; 425 mp->mnt_flag |= MNT_LOCAL; 426 mp->mnt_dev_bshift = iso_bsize; 427 mp->mnt_fs_bshift = isomp->im_bshift; 428 isomp->im_mountp = mp; 429 isomp->im_dev = dev; 430 isomp->im_devvp = devvp; 431 432 devvp->v_specmountpoint = mp; 433 434 /* Check the Rock Ridge Extension support */ 435 if (!(argp->flags & ISOFSMNT_NORRIP)) { 436 struct iso_directory_record *rootp; 437 438 if ((error = bread(isomp->im_devvp, 439 (isomp->root_extent + ext_attr_length) << 440 (isomp->im_bshift - DEV_BSHIFT), 441 isomp->logical_block_size, NOCRED, 442 &bp)) != 0) 443 goto out; 444 445 rootp = (struct iso_directory_record *)bp->b_data; 446 447 if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) { 448 argp->flags |= ISOFSMNT_NORRIP; 449 } else { 450 argp->flags &= ~ISOFSMNT_GENS; 451 } 452 453 /* 454 * The contents are valid, 455 * but they will get reread as part of another vnode, so... 456 */ 457 bp->b_flags |= B_AGE; 458 brelse(bp); 459 bp = NULL; 460 } 461 isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS | 462 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET | ISOFSMNT_RRCASEINS); 463 464 if (isomp->im_flags & ISOFSMNT_GENS) 465 isomp->iso_ftype = ISO_FTYPE_9660; 466 else if (isomp->im_flags & ISOFSMNT_NORRIP) { 467 isomp->iso_ftype = ISO_FTYPE_DEFAULT; 468 if (argp->flags & ISOFSMNT_NOCASETRANS) 469 isomp->im_flags |= ISOFSMNT_NOCASETRANS; 470 } else 471 isomp->iso_ftype = ISO_FTYPE_RRIP; 472 473 /* Check the Joliet Extension support */ 474 if ((argp->flags & ISOFSMNT_NORRIP) != 0 && 475 (argp->flags & ISOFSMNT_NOJOLIET) == 0 && 476 supbp != NULL) { 477 joliet_level = 0; 478 sup = (struct iso_supplementary_descriptor *)supbp->b_data; 479 480 if ((isonum_711(sup->flags) & 1) == 0) { 481 if (memcmp(sup->escape, "%/@", 3) == 0) 482 joliet_level = 1; 483 if (memcmp(sup->escape, "%/C", 3) == 0) 484 joliet_level = 2; 485 if (memcmp(sup->escape, "%/E", 3) == 0) 486 joliet_level = 3; 487 } 488 if (joliet_level != 0) { 489 if (iso_makemp(isomp, supbp, NULL) == -1) { 490 error = EINVAL; 491 goto out; 492 } 493 isomp->im_joliet_level = joliet_level; 494 } 495 } 496 497 if (supbp != NULL) { 498 brelse(supbp); 499 supbp = NULL; 500 } 501 502 return 0; 503 out: 504 if (bp) 505 brelse(bp); 506 if (pribp) 507 brelse(pribp); 508 if (supbp) 509 brelse(supbp); 510 if (needclose) { 511 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 512 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 513 VOP_UNLOCK(devvp, 0); 514 } 515 if (isomp) { 516 free(isomp, M_ISOFSMNT); 517 mp->mnt_data = NULL; 518 } 519 return error; 520 } 521 522 /* 523 * Make a filesystem operational. 524 * Nothing to do at the moment. 525 */ 526 /* ARGSUSED */ 527 int 528 cd9660_start(mp, flags, p) 529 struct mount *mp; 530 int flags; 531 struct proc *p; 532 { 533 return 0; 534 } 535 536 /* 537 * unmount system call 538 */ 539 int 540 cd9660_unmount(mp, mntflags, p) 541 struct mount *mp; 542 int mntflags; 543 struct proc *p; 544 { 545 struct iso_mnt *isomp; 546 int error, flags = 0; 547 548 if (mntflags & MNT_FORCE) 549 flags |= FORCECLOSE; 550 #if 0 551 mntflushbuf(mp, 0); 552 if (mntinvalbuf(mp)) 553 return EBUSY; 554 #endif 555 if ((error = vflush(mp, NULLVP, flags)) != 0) 556 return (error); 557 558 isomp = VFSTOISOFS(mp); 559 560 #ifdef ISODEVMAP 561 if (isomp->iso_ftype == ISO_FTYPE_RRIP) 562 iso_dunmap(isomp->im_dev); 563 #endif 564 565 if (isomp->im_devvp->v_type != VBAD) 566 isomp->im_devvp->v_specmountpoint = NULL; 567 568 vn_lock(isomp->im_devvp, LK_EXCLUSIVE | LK_RETRY); 569 error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, p); 570 vput(isomp->im_devvp); 571 free(isomp, M_ISOFSMNT); 572 mp->mnt_data = NULL; 573 mp->mnt_flag &= ~MNT_LOCAL; 574 return (error); 575 } 576 577 /* 578 * Return root of a filesystem 579 */ 580 int 581 cd9660_root(mp, vpp) 582 struct mount *mp; 583 struct vnode **vpp; 584 { 585 struct iso_mnt *imp = VFSTOISOFS(mp); 586 struct iso_directory_record *dp = 587 (struct iso_directory_record *)imp->root; 588 ino_t ino = isodirino(dp, imp); 589 590 /* 591 * With RRIP we must use the `.' entry of the root directory. 592 * Simply tell vget, that it's a relocated directory. 593 */ 594 return (cd9660_vget_internal(mp, ino, vpp, 595 imp->iso_ftype == ISO_FTYPE_RRIP, dp)); 596 } 597 598 /* 599 * Do operations associated with quotas, not supported 600 */ 601 /* ARGSUSED */ 602 int 603 cd9660_quotactl(mp, cmd, uid, arg, p) 604 struct mount *mp; 605 int cmd; 606 uid_t uid; 607 void *arg; 608 struct proc *p; 609 { 610 611 return (EOPNOTSUPP); 612 } 613 614 /* 615 * Get file system statistics. 616 */ 617 int 618 cd9660_statvfs(mp, sbp, p) 619 struct mount *mp; 620 struct statvfs *sbp; 621 struct proc *p; 622 { 623 struct iso_mnt *isomp; 624 625 isomp = VFSTOISOFS(mp); 626 627 sbp->f_bsize = isomp->logical_block_size; 628 sbp->f_frsize = sbp->f_bsize; 629 sbp->f_iosize = sbp->f_bsize; /* XXX */ 630 sbp->f_blocks = isomp->volume_space_size; 631 sbp->f_bfree = 0; /* total free blocks */ 632 sbp->f_bavail = 0; /* blocks free for non superuser */ 633 sbp->f_bresvd = 0; /* total reserved blocks */ 634 sbp->f_files = 0; /* total files */ 635 sbp->f_ffree = 0; /* free file nodes */ 636 sbp->f_favail = 0; /* free file nodes */ 637 sbp->f_fresvd = 0; /* reserved file nodes */ 638 copy_statvfs_info(sbp, mp); 639 /* Use the first spare for flags: */ 640 sbp->f_spare[0] = isomp->im_flags; 641 return 0; 642 } 643 644 /* ARGSUSED */ 645 int 646 cd9660_sync(mp, waitfor, cred, p) 647 struct mount *mp; 648 int waitfor; 649 struct ucred *cred; 650 struct proc *p; 651 { 652 return (0); 653 } 654 655 /* 656 * File handle to vnode 657 * 658 * Have to be really careful about stale file handles: 659 * - check that the inode number is in range 660 * - call iget() to get the locked inode 661 * - check for an unallocated inode (i_mode == 0) 662 * - check that the generation number matches 663 */ 664 665 struct ifid { 666 ushort ifid_len; 667 ushort ifid_pad; 668 int ifid_ino; 669 long ifid_start; 670 }; 671 672 /* ARGSUSED */ 673 int 674 cd9660_fhtovp(mp, fhp, vpp) 675 struct mount *mp; 676 struct fid *fhp; 677 struct vnode **vpp; 678 { 679 struct ifid *ifhp = (struct ifid *)fhp; 680 struct iso_node *ip; 681 struct vnode *nvp; 682 int error; 683 684 #ifdef ISOFS_DBG 685 printf("fhtovp: ino %d, start %ld\n", 686 ifhp->ifid_ino, ifhp->ifid_start); 687 #endif 688 689 if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) { 690 *vpp = NULLVP; 691 return (error); 692 } 693 ip = VTOI(nvp); 694 if (ip->inode.iso_mode == 0) { 695 vput(nvp); 696 *vpp = NULLVP; 697 return (ESTALE); 698 } 699 *vpp = nvp; 700 return (0); 701 } 702 703 /* ARGSUSED */ 704 int 705 cd9660_check_export(mp, nam, exflagsp, credanonp) 706 struct mount *mp; 707 struct mbuf *nam; 708 int *exflagsp; 709 struct ucred **credanonp; 710 { 711 struct netcred *np; 712 struct iso_mnt *imp = VFSTOISOFS(mp); 713 714 #ifdef ISOFS_DBG 715 printf("check_export: ino %d, start %ld\n", 716 ifhp->ifid_ino, ifhp->ifid_start); 717 #endif 718 719 /* 720 * Get the export permission structure for this <mp, client> tuple. 721 */ 722 np = vfs_export_lookup(mp, &imp->im_export, nam); 723 if (np == NULL) 724 return (EACCES); 725 726 *exflagsp = np->netc_exflags; 727 *credanonp = &np->netc_anon; 728 return (0); 729 } 730 731 int 732 cd9660_vget(mp, ino, vpp) 733 struct mount *mp; 734 ino_t ino; 735 struct vnode **vpp; 736 { 737 738 /* 739 * XXXX 740 * It would be nice if we didn't always set the `relocated' flag 741 * and force the extra read, but I don't want to think about fixing 742 * that right now. 743 */ 744 return (cd9660_vget_internal(mp, ino, vpp, 745 #if 0 746 VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP, 747 #else 748 0, 749 #endif 750 NULL)); 751 } 752 753 int 754 cd9660_vget_internal(mp, ino, vpp, relocated, isodir) 755 struct mount *mp; 756 ino_t ino; 757 struct vnode **vpp; 758 int relocated; 759 struct iso_directory_record *isodir; 760 { 761 struct iso_mnt *imp; 762 struct iso_node *ip; 763 #ifdef ISODEVMAP 764 struct iso_dnode *dp; 765 #endif 766 struct buf *bp; 767 struct vnode *vp, *nvp; 768 dev_t dev; 769 int error; 770 771 imp = VFSTOISOFS(mp); 772 dev = imp->im_dev; 773 if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP) 774 return (0); 775 776 /* Allocate a new vnode/iso_node. */ 777 if ((error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, &vp)) != 0) { 778 *vpp = NULLVP; 779 return (error); 780 } 781 ip = pool_get(&cd9660_node_pool, PR_WAITOK); 782 memset(ip, 0, sizeof(struct iso_node)); 783 vp->v_data = ip; 784 ip->i_vnode = vp; 785 ip->i_dev = dev; 786 ip->i_number = ino; 787 788 /* 789 * Put it onto its hash chain and lock it so that other requests for 790 * this inode will block if they arrive while we are sleeping waiting 791 * for old data structures to be purged or for the contents of the 792 * disk portion of this inode to be read. 793 */ 794 cd9660_ihashins(ip); 795 796 if (isodir == 0) { 797 int lbn, off; 798 799 lbn = lblkno(imp, ino); 800 if (lbn >= imp->volume_space_size) { 801 vput(vp); 802 printf("fhtovp: lbn exceed volume space %d\n", lbn); 803 return (ESTALE); 804 } 805 806 off = blkoff(imp, ino); 807 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) { 808 vput(vp); 809 printf("fhtovp: crosses block boundary %d\n", 810 off + ISO_DIRECTORY_RECORD_SIZE); 811 return (ESTALE); 812 } 813 814 error = bread(imp->im_devvp, 815 lbn << (imp->im_bshift - DEV_BSHIFT), 816 imp->logical_block_size, NOCRED, &bp); 817 if (error) { 818 vput(vp); 819 brelse(bp); 820 printf("fhtovp: bread error %d\n",error); 821 return (error); 822 } 823 isodir = (struct iso_directory_record *)(bp->b_data + off); 824 825 if (off + isonum_711(isodir->length) > 826 imp->logical_block_size) { 827 vput(vp); 828 if (bp != 0) 829 brelse(bp); 830 printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n", 831 off +isonum_711(isodir->length), off, 832 isonum_711(isodir->length)); 833 return (ESTALE); 834 } 835 836 #if 0 837 if (isonum_733(isodir->extent) + 838 isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) { 839 if (bp != 0) 840 brelse(bp); 841 printf("fhtovp: file start miss %d vs %d\n", 842 isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length), 843 ifhp->ifid_start); 844 return (ESTALE); 845 } 846 #endif 847 } else 848 bp = 0; 849 850 ip->i_mnt = imp; 851 ip->i_devvp = imp->im_devvp; 852 VREF(ip->i_devvp); 853 854 if (relocated) { 855 /* 856 * On relocated directories we must 857 * read the `.' entry out of a dir. 858 */ 859 ip->iso_start = ino >> imp->im_bshift; 860 if (bp != 0) 861 brelse(bp); 862 if ((error = VOP_BLKATOFF(vp, (off_t)0, NULL, &bp)) != 0) { 863 vput(vp); 864 return (error); 865 } 866 isodir = (struct iso_directory_record *)bp->b_data; 867 } 868 869 ip->iso_extent = isonum_733(isodir->extent); 870 ip->i_size = isonum_733(isodir->size); 871 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent; 872 873 /* 874 * Setup time stamp, attribute 875 */ 876 vp->v_type = VNON; 877 switch (imp->iso_ftype) { 878 default: /* ISO_FTYPE_9660 */ 879 { 880 struct buf *bp2; 881 int off; 882 if ((imp->im_flags & ISOFSMNT_EXTATT) 883 && (off = isonum_711(isodir->ext_attr_length))) 884 VOP_BLKATOFF(vp, (off_t)-(off << imp->im_bshift), NULL, 885 &bp2); 886 else 887 bp2 = NULL; 888 cd9660_defattr(isodir, ip, bp2); 889 cd9660_deftstamp(isodir, ip, bp2); 890 if (bp2) 891 brelse(bp2); 892 break; 893 } 894 case ISO_FTYPE_RRIP: 895 cd9660_rrip_analyze(isodir, ip, imp); 896 break; 897 } 898 899 if (bp != 0) 900 brelse(bp); 901 902 /* 903 * Initialize the associated vnode 904 */ 905 switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) { 906 case VFIFO: 907 vp->v_op = cd9660_fifoop_p; 908 break; 909 case VCHR: 910 case VBLK: 911 /* 912 * if device, look at device number table for translation 913 */ 914 #ifdef ISODEVMAP 915 if ((dp = iso_dmap(dev, ino, 0)) != NULL) 916 ip->inode.iso_rdev = dp->d_dev; 917 #endif 918 vp->v_op = cd9660_specop_p; 919 if ((nvp = checkalias(vp, ip->inode.iso_rdev, mp)) != NULL) { 920 /* 921 * Discard unneeded vnode, but save its iso_node. 922 * Note that the lock is carried over in the iso_node 923 * to the replacement vnode. 924 */ 925 nvp->v_data = vp->v_data; 926 vp->v_data = NULL; 927 VOP_UNLOCK(vp, 0); 928 vp->v_op = spec_vnodeop_p; 929 vrele(vp); 930 vgone(vp); 931 lockmgr(&nvp->v_lock, LK_EXCLUSIVE, &nvp->v_interlock); 932 /* 933 * Reinitialize aliased inode. 934 */ 935 vp = nvp; 936 ip->i_vnode = vp; 937 } 938 break; 939 case VLNK: 940 case VNON: 941 case VSOCK: 942 case VDIR: 943 case VBAD: 944 break; 945 case VREG: 946 uvm_vnp_setsize(vp, ip->i_size); 947 break; 948 } 949 950 if (ip->iso_extent == imp->root_extent) 951 vp->v_flag |= VROOT; 952 953 /* 954 * XXX need generation number? 955 */ 956 957 genfs_node_init(vp, &cd9660_genfsops); 958 *vpp = vp; 959 return (0); 960 } 961 962 /* 963 * Vnode pointer to File handle 964 */ 965 /* ARGSUSED */ 966 int 967 cd9660_vptofh(vp, fhp) 968 struct vnode *vp; 969 struct fid *fhp; 970 { 971 struct iso_node *ip = VTOI(vp); 972 struct ifid *ifhp; 973 974 ifhp = (struct ifid *)fhp; 975 ifhp->ifid_len = sizeof(struct ifid); 976 977 ifhp->ifid_ino = ip->i_number; 978 ifhp->ifid_start = ip->iso_start; 979 980 #ifdef ISOFS_DBG 981 printf("vptofh: ino %d, start %ld\n", 982 ifhp->ifid_ino,ifhp->ifid_start); 983 #endif 984 return 0; 985 } 986 987 SYSCTL_SETUP(sysctl_vfs_cd9660_setup, "sysctl vfs.cd9660 subtree setup") 988 { 989 990 sysctl_createv(clog, 0, NULL, NULL, 991 CTLFLAG_PERMANENT, CTLTYPE_NODE, "vfs", NULL, 992 NULL, 0, NULL, 0, 993 CTL_VFS, CTL_EOL); 994 sysctl_createv(clog, 0, NULL, NULL, 995 CTLFLAG_PERMANENT, CTLTYPE_NODE, "cd9660", 996 SYSCTL_DESCR("ISO-9660 file system"), 997 NULL, 0, NULL, 0, 998 CTL_VFS, 14, CTL_EOL); 999 /* 1000 * XXX the "14" above could be dynamic, thereby eliminating 1001 * one more instance of the "number to vfs" mapping problem, 1002 * but "14" is the order as taken from sys/mount.h 1003 */ 1004 } 1005