]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/isofs/cd9660/cd9660_vfsops.c
xnu-1228.tar.gz
[apple/xnu.git] / bsd / isofs / cd9660 / cd9660_vfsops.c
index 929eb5446d26c34df89dfab56a0765798371bd55..acdb699a2f2a090c534419c5a77f78d32eb43931 100644 (file)
@@ -1,16 +1,19 @@
 /*
- * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
  * 
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
@@ -20,7 +23,7 @@
  * Please see the License for the specific language governing rights and
  * limitations under the License.
  * 
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*     $NetBSD: cd9660_vfsops.c,v 1.18 1995/03/09 12:05:36 mycroft Exp $       */
 
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/vnode.h>
+#include <sys/vnode_internal.h>
 #include <sys/mount.h>
 #include <sys/namei.h>
 #include <sys/proc.h>
+#include <sys/kauth.h>
 #include <sys/kernel.h>
 #include <miscfs/specfs/specdev.h>
 #include <sys/buf.h>
 #include <sys/file.h>
 #include <sys/ioctl.h>
-#include <dev/disk.h>
+#include <sys/disk.h>
 #include <sys/errno.h>
 #include <sys/malloc.h>
 #include <sys/stat.h>
 #include <sys/ubc.h>
 #include <sys/utfconv.h>
-#include <architecture/byte_order.h>
 
 #include <isofs/cd9660/iso.h>
 #include <isofs/cd9660/iso_rrip.h>
 #include <isofs/cd9660/cd9660_node.h>
 #include <isofs/cd9660/cd9660_mount.h>
 
-u_char isonullname[] = "\0";
+/*
+ * Minutes, Seconds, Frames (M:S:F)
+ */
+struct CDMSF {
+       u_char   minute;
+       u_char   second;
+       u_char   frame;
+};
+
+/*
+ * Table Of Contents
+ */
+struct CDTOC_Desc {
+       u_char        session;
+       u_char        ctrl_adr;  /* typed to be machine and compiler independent */
+       u_char        tno;
+       u_char        point;
+       struct CDMSF  address;
+       u_char        zero;
+       struct CDMSF  p;
+};
+
+struct CDTOC {
+       u_short            length;  /* in native cpu endian */
+       u_char             first_session;
+       u_char             last_session;
+       struct CDTOC_Desc  trackdesc[1];
+};
 
-extern int enodev ();
+#define MSF_TO_LBA(msf)                \
+       (((((msf).minute * 60UL) + (msf).second) * 75UL) + (msf).frame - 150)
+
+u_char isonullname[] = "\0";
 
 struct vfsops cd9660_vfsops = {
        cd9660_mount,
        cd9660_start,
        cd9660_unmount,
        cd9660_root,
-       cd9660_quotactl,
-       cd9660_statfs,
+       NULL,                   /* quotactl */
+       cd9660_vfs_getattr,
        cd9660_sync,
        cd9660_vget,
        cd9660_fhtovp,
        cd9660_vptofh,
        cd9660_init,
-       cd9660_sysctl
+       cd9660_sysctl,
+       NULL,
+       {NULL}
 };
 
 /*
@@ -114,8 +149,8 @@ struct vfsops cd9660_vfsops = {
  */
 #define ROOTNAME       "root_device"
 
-static int iso_mountfs __P((struct vnode *devvp, struct mount *mp,
-               struct proc *p, struct iso_args *argp));
+static int iso_mountfs(struct vnode *devvp, struct mount *mp, struct user_iso_args *argp,
+                       vfs_context_t context);
 
 static void DRGetTypeCreatorAndFlags(
                                struct iso_mnt * theMountPointPtr,
@@ -124,61 +159,22 @@ static void DRGetTypeCreatorAndFlags(
                                u_int32_t * theCreatorPtr, 
                                u_int16_t * theFlagsPtr);
 
-int    cd9660_vget_internal(
-               struct mount *mp, 
-               ino_t ino, 
-               struct vnode **vpp, 
-               int relocated, 
-               struct iso_directory_record *isodir, 
-               struct proc *p);
-
 int
-cd9660_mountroot()
+cd9660_mountroot(mount_t mp, vnode_t rvp, vfs_context_t context)
 {
-       register struct mount *mp;
-       extern struct vnode *rootvp;
-       struct proc *p = current_proc();        /* XXX */
-       struct iso_mnt *imp;
-       size_t size;
-       int error;
-       struct iso_args args;
-       
-       /*
-        * Get vnodes for swapdev and rootdev.
-        */
-       if ( bdevvp(rootdev, &rootvp))
-               panic("cd9660_mountroot: can't setup bdevvp's");
-
-       MALLOC_ZONE(mp, struct mount *,
-                       sizeof(struct mount), M_MOUNT, M_WAITOK);
-       bzero((char *)mp, (u_long)sizeof(struct mount));
+       int     error;
+       struct user_iso_args args;
 
-    /* Initialize the default IO constraints */
-    mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS;
-    mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32;
-
-       mp->mnt_op = &cd9660_vfsops;
-       mp->mnt_flag = MNT_RDONLY;
-       LIST_INIT(&mp->mnt_vnodelist);
        args.flags = ISOFSMNT_ROOT;
        args.ssector = 0;
-       if ((error = iso_mountfs(rootvp, mp, p, &args))) {
-               vrele(rootvp); /* release the reference from bdevvp() */
-               FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
+       args.toc_length = 0;
+       args.toc = USER_ADDR_NULL;
+
+       if ((error = iso_mountfs(rvp, mp, &args, context)))
                return (error);
-       }
-       simple_lock(&mountlist_slock);
-       CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
-       simple_unlock(&mountlist_slock);
-       mp->mnt_vnodecovered = NULLVP;
-       imp = VFSTOISOFS(mp);
-       (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1,
-               &size);
-       bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
-       (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
-               &size);
-       bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
-       (void)cd9660_statfs(mp, &mp->mnt_stat, p);
+
+       (void)cd9660_statfs(mp, vfs_statfs(mp), context);
+
        return (0);
 }
 
@@ -188,94 +184,176 @@ cd9660_mountroot()
  * mount system call
  */
 int
-cd9660_mount(mp, path, data, ndp, p)
-       register struct mount *mp;
-       char *path;
-       caddr_t data;
-       struct nameidata *ndp;
-       struct proc *p;
+cd9660_mount(mount_t mp, vnode_t devvp, user_addr_t data, vfs_context_t context)
 {
-       struct vnode *devvp;
-       struct iso_args args;
-       size_t size;
+       struct user_iso_args args;
        int error;
        struct iso_mnt *imp = NULL;
-       
-       if ((error = copyin(data, (caddr_t)&args, sizeof (struct iso_args))))
+
+       if (vfs_context_is64bit(context)) {
+               error = copyin(data, (caddr_t)&args, sizeof(args));
+       }
+       else {
+               struct iso_args temp;
+               error = copyin(data, (caddr_t)&temp, sizeof(temp));
+               args.flags = temp.flags;
+               args.ssector = temp.ssector;
+               args.toc_length = temp.toc_length;
+               args.toc = CAST_USER_ADDR_T(temp.toc);
+       }
+       if (error)
                return (error);
        
-       if ((mp->mnt_flag & MNT_RDONLY) == 0)
+       if (vfs_isrdwr(mp))
                return (EROFS);
 
        /*
         * If updating, check whether changing from read-only to
         * read/write; if there is no device name, that's all we do.
         */
-       if (mp->mnt_flag & MNT_UPDATE) {
+       if (vfs_isupdate(mp)) {
                imp = VFSTOISOFS(mp);
-               if (args.fspec == 0)
-                       return (vfs_export(mp, &imp->im_export, &args.export));
+               if (devvp == 0)
+                       return (0);
        }
-       /*
-        * Not an update, or updating the name: look up the name
-        * and verify that it refers to a sensible block device.
-        */
-       NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
-       if ((error = namei(ndp)))
-               return (error);
-       devvp = ndp->ni_vp;
-
-       if (devvp->v_type != VBLK) {
-               vrele(devvp);
-               return (ENOTBLK);
-       }
-       if (major(devvp->v_rdev) >= nblkdev) {
-               vrele(devvp);
-               return (ENXIO);
-       }
-       if ((mp->mnt_flag & MNT_UPDATE) == 0)
-               error = iso_mountfs(devvp, mp, p, &args);
+       if ( !vfs_isupdate(mp))
+               error = iso_mountfs(devvp, mp, &args, context);
        else {
                if (devvp != imp->im_devvp)
                        error = EINVAL; /* needs translation */
-               else
-                       vrele(devvp);
        }
        if (error) {
-               vrele(devvp);
                return (error);
        }
 
-       /* Set the mount flag to indicate that we support volfs  */
-       mp->mnt_flag |= MNT_DOVOLFS;
+       /* Indicate that we don't support volfs */
+       vfs_clearflags(mp, MNT_DOVOLFS);
 
-       (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
-       bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
-       (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
-               &size);
-       bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
        return (0);
 }
 
+/*
+ * Find the BSD device for the physical disk corresponding to the
+ * mount point's device.  We use this physical device to read whole
+ * (2352 byte) sectors from the CD to get the content for the video
+ * files (tracks).
+ *
+ * The "path" argument is the path to the block device that the volume
+ * is being mounted on (args.fspec).  It should be of the form:
+ *     /dev/disk1s0
+ * where the last "s0" part is stripped off to determine the physical
+ * device's path.  It is assumed to be in user memory.
+ */
+static struct vnode *
+cd9660_phys_device(mount_t mp, vfs_context_t context)
+{
+       int err;
+       char whole_path[64];    // path to "whole" device
+       char *s, *saved;
+       struct nameidata nd;
+       struct vnode *result;
+       struct vfsstatfs * sfs;
+       
+       sfs = vfs_statfs(mp);
+       result = NULL;
+
+       if (strlen(sfs->f_mntfromname) >= sizeof(whole_path))
+               return (NULL);
+
+       /* Make a copy of the mount from name, then remove trailing "s...". */
+       strlcpy(whole_path, sfs->f_mntfromname, sizeof(whole_path)); 
+       
+       /*
+        * I would use strrchr or rindex here, but those are declared __private_extern__,
+        * and can't be used across component boundaries at this time.
+        */
+       for (s=whole_path, saved=NULL; *s; ++s)
+               if (*s == 's')
+                       saved = s;
+       *saved = '\0';
+
+       /* Lookup the "whole" device. */
+       NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, CAST_USER_ADDR_T(whole_path), context);
+       err = namei(&nd);
+       if (err) {
+               printf("isofs: Cannot find physical device: %s\n", whole_path);
+               goto done;
+       }
+       nameidone(&nd);
+
+       /* Open the "whole" device. */
+       err = VNOP_OPEN(nd.ni_vp, FREAD, context);
+       if (err) {
+               vnode_put(nd.ni_vp);
+               printf("isofs: Cannot open physical device: %s\n", whole_path);
+               goto done;
+       }
+       result = nd.ni_vp;
+done:
+       return result;
+}
+
+
+/*
+ * See if the given CD-ROM XA disc appears to be a Video CD
+ * (version < 2.0; so, not SVCD).  If so, fill in the extent
+ * information for the MPEGAV directory, set the VCD flag,
+ * and return true.
+ */
+static int
+cd9660_find_video_dir(struct iso_mnt *isomp)
+{
+       int result, err;
+       struct vnode *rvp = NULL;
+       struct vnode *videovp = NULL;
+       struct componentname cn;
+       char dirname[] = "MPEGAV";
+       
+       result = 0;             /* Assume not a video CD */
+       
+       err = cd9660_root(isomp->im_mountp, &rvp, NULL);
+       if (err) {
+               printf("cd9660_find_video_dir: cd9660_root failed (%d)\n", err);
+               return 0;       /* couldn't find video dir */
+       }
+       
+       cn.cn_nameiop = LOOKUP;
+       cn.cn_flags = ISLASTCN;
+       cn.cn_context = vfs_context_current();
+       cn.cn_pnbuf = dirname;
+       cn.cn_pnlen = sizeof(dirname)-1;
+       cn.cn_nameptr = cn.cn_pnbuf;
+       cn.cn_namelen = cn.cn_pnlen;
+       
+       err = VNOP_LOOKUP(rvp, &videovp, &cn, cn.cn_context);
+       if (err == 0) {
+               struct iso_node *ip = VTOI(videovp);
+               result = 1;             /* Looks like video CD */
+               isomp->video_dir_start = ip->iso_start;
+               isomp->video_dir_end = ip->iso_start + (ip->i_size >> isomp->im_bshift);
+               isomp->im_flags2 |= IMF2_IS_VCD;
+
+               vnode_put(videovp);
+       }
+       vnode_put(rvp);
+       
+       return result;
+}
+
 /*
  * Common code for mount and mountroot
  */
 static int
-iso_mountfs(devvp, mp, p, argp)
-       register struct vnode *devvp;
-       struct mount *mp;
-       struct proc *p;
-       struct iso_args *argp;
+iso_mountfs(struct vnode *devvp, struct mount *mp, struct user_iso_args *argp,
+           vfs_context_t context)
 {
-       register struct iso_mnt *isomp = (struct iso_mnt *)0;
+       struct iso_mnt *isomp = (struct iso_mnt *)0;
        struct buf *bp = NULL;
        struct buf *pribp = NULL, *supbp = NULL;
-       dev_t dev = devvp->v_rdev;
+       dev_t dev = vnode_specrdev(devvp);
        int error = EINVAL;
        int breaderr = 0;
-       int needclose = 0;
-       extern struct vnode *rootvp;
-       u_long iso_bsize;
+       u_long iso_bsize, orig_bsize;
        int iso_blknum;
        int joliet_level;
        struct iso_volume_descriptor *vdp = NULL;
@@ -286,25 +364,18 @@ iso_mountfs(devvp, mp, p, argp)
        u_int8_t vdtype;
        int blkoff = argp->ssector;
        
-       if (!(mp->mnt_flag & MNT_RDONLY))
+       if (vfs_isrdwr(mp))
                return (EROFS);
 
-       /*
-        * Disallow multiple mounts of the same device.
-        * Disallow mounting of a device that is currently in use
-        * (except for root, which might share swap device for miniroot).
-        * Flush out any old buffers remaining from a previous use.
-        */
-       if ((error = vfs_mountedon(devvp)))
-               return (error);
-       if (vcount(devvp) > 1 && devvp != rootvp)
-               return (EBUSY);
-       if ((error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)))
-               return (error);
+       /* Advisory locking should be handled at the VFS layer */
+       vfs_setlocklocal(mp);
+
+       /* Finish initializing hash tables */
+       cd9660_hashinit();
 
-       if ((error = VOP_OPEN(devvp, FREAD, FSCRED, p)))
+       if ((error = VNOP_IOCTL(devvp, DKIOCGETBLOCKSIZE,
+            (caddr_t)&orig_bsize, 0, context)))
                return (error);
-       needclose = 1;
        
        /* This is the "logical sector size".  The standard says this
         * should be 2048 or the physical sector size on the device,
@@ -313,29 +384,39 @@ iso_mountfs(devvp, mp, p, argp)
        iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
 
        /* tell IOKit that we're assuming 2K sectors */
-       if ((error = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
-            (caddr_t)&iso_bsize, FWRITE, p->p_ucred, p)))
+       if ((error = VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
+            (caddr_t)&iso_bsize, FWRITE, context)))
                return (error);
-       devvp->v_specsize = iso_bsize;
+
        joliet_level = 0;
        for (iso_blknum = 16 + blkoff; iso_blknum < (100 + blkoff); iso_blknum++) {
-               if ((error = bread(devvp, iso_blknum, iso_bsize, NOCRED, &bp))) {
+               if ((error = (int)buf_bread(devvp, (daddr64_t)((unsigned)iso_blknum), iso_bsize, NOCRED, &bp))) {
                        if (bp) {
-                               bp->b_flags |= B_AGE;
-                               brelse(bp);
+                               buf_markaged(bp);
+                               buf_brelse(bp);
                                bp = NULL;
                        }
                        breaderr = error;
-                       printf("iso_mountfs: bread error %d reading block %d\n", error, iso_blknum);
+                       printf("iso_mountfs: buf_bread error %d reading block %d\n", error, iso_blknum);
                        continue;
                }
 
-               vdp = (struct iso_volume_descriptor *)bp->b_data;
+               vdp = (struct iso_volume_descriptor *)((char *)0 + buf_dataptr(bp));
                if (bcmp (vdp->volume_desc_id, ISO_STANDARD_ID, sizeof(vdp->volume_desc_id)) != 0) {
 #ifdef DEBUG
                        printf("cd9660_vfsops.c: iso_mountfs: "
                                        "Invalid ID in volume desciptor.\n");
 #endif
+                       /* There should be a primary volume descriptor followed by any
+                        * secondary volume descriptors, then an end volume descriptor.
+                        * Some discs are mastered without an end volume descriptor or
+                        * they have the type field set and the volume descriptor ID is
+                        * not set. If we at least found a primary volume descriptor,
+                        * mount the disc.
+                        */
+                       if (pri != NULL)
+                               break;
+                       
                        error = EINVAL;
                        goto out;
                }
@@ -373,15 +454,15 @@ iso_mountfs(devvp, mp, p, argp)
                }
 
                if (bp) {
-                       bp->b_flags |= B_AGE;
-                       brelse(bp);
+                       buf_markaged(bp);
+                       buf_brelse(bp);
                        bp = NULL;
                }
        }
 
        if (bp) {
-               bp->b_flags |= B_AGE;
-               brelse(bp);
+               buf_markaged(bp);
+               buf_brelse(bp);
                bp = NULL;
        }
        
@@ -403,8 +484,9 @@ iso_mountfs(devvp, mp, p, argp)
        
        rootp = (struct iso_directory_record *)pri->root_directory_record;
        
-       MALLOC(isomp, struct iso_mnt *, sizeof *isomp, M_ISOFSMNT, M_WAITOK);
-       bzero((caddr_t)isomp, sizeof *isomp);
+       MALLOC(isomp, struct iso_mnt *, sizeof(*isomp), M_ISOFSMNT, M_WAITOK);
+       bzero((caddr_t)isomp, sizeof(*isomp));
+       isomp->im_sector_size = ISO_DEFAULT_BLOCK_SIZE;
        isomp->logical_block_size = logical_block_size;
        isomp->volume_space_size = isonum_733 (pri->volume_space_size);
        /*
@@ -416,7 +498,7 @@ iso_mountfs(devvp, mp, p, argp)
         * filehandle validation.
         */
        isomp->volume_space_size += blkoff;
-       bcopy (rootp, isomp->root, sizeof isomp->root);
+       bcopy (rootp, isomp->root, sizeof(isomp->root));
        isomp->root_extent = isonum_733 (rootp->extent);
        isomp->root_size = isonum_733 (rootp->size);
 
@@ -436,7 +518,7 @@ iso_mountfs(devvp, mp, p, argp)
        }
 
        if (pri->volume_id[0] == 0)
-               strcpy(isomp->volume_id, ISO_DFLT_VOLUME_ID);
+               strlcpy(isomp->volume_id, ISO_DFLT_VOLUME_ID, sizeof(isomp->volume_id));
        else
                bcopy(pri->volume_id, isomp->volume_id, sizeof(isomp->volume_id));
        cd9660_tstamp_conv17(pri->creation_date, &isomp->creation_date);
@@ -444,42 +526,54 @@ iso_mountfs(devvp, mp, p, argp)
 
        /* See if this is a CD-XA volume */
        if (bcmp( pri->CDXASignature, ISO_XA_ID,
-                       sizeof(pri->CDXASignature) ) == 0 ) 
+                       sizeof(pri->CDXASignature) ) == 0 ) {
                isomp->im_flags2 |= IMF2_IS_CDXA;
+       }
 
        isomp->im_bmask = logical_block_size - 1;
        isomp->im_bshift = 0;
        while ((1 << isomp->im_bshift) < isomp->logical_block_size)
                isomp->im_bshift++;
 
-       pribp->b_flags |= B_AGE;
-       brelse(pribp);
+       buf_markaged(pribp);
+       buf_brelse(pribp);
        pribp = NULL;
 
-       mp->mnt_data = (qaddr_t)isomp;
-       mp->mnt_stat.f_fsid.val[0] = (long)dev;
-       mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
-       mp->mnt_maxsymlinklen = 0;
-       mp->mnt_flag |= MNT_LOCAL;
+       vfs_setfsprivate(mp, (void *)isomp);
+       vfs_statfs(mp)->f_fsid.val[0] = (long)dev;
+       vfs_statfs(mp)->f_fsid.val[1] = vfs_typenum(mp);
+       vfs_setmaxsymlen(mp, 0);
+       vfs_setflags(mp, MNT_LOCAL);
 
        isomp->im_mountp = mp;
        isomp->im_dev = dev;
        isomp->im_devvp = devvp;        
 
-       devvp->v_specflags |= SI_MOUNTEDON;
+       /*
+        * If the logical block size is not 2K then we must
+        * set the block device's physical block size to this
+        * disc's logical block size.
+        *
+        */
+       if (logical_block_size != iso_bsize) {
+               iso_bsize = logical_block_size;
+               if ((error = VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
+                    (caddr_t)&iso_bsize, FWRITE, context)))
+                       goto out;
+       }
        
        /* Check the Rock Ridge Extention support */
        if (!(argp->flags & ISOFSMNT_NORRIP)) {
-               if ( (error = bread(isomp->im_devvp,
-                                 (isomp->root_extent + isonum_711(rootp->ext_attr_length)),
-                                 isomp->logical_block_size, NOCRED, &bp)) ) {
+               if ( (error = (int)buf_bread(isomp->im_devvp,
+                                            (daddr64_t)((unsigned)((isomp->root_extent + isonum_711(rootp->ext_attr_length)))),
+                                            isomp->logical_block_size, NOCRED, &bp)) ) {
 
-                       printf("iso_mountfs: bread error %d reading block %d\n",
+                       printf("iso_mountfs: buf_bread error %d reading block %d\n",
                           error, isomp->root_extent + isonum_711(rootp->ext_attr_length));
                        argp->flags |= ISOFSMNT_NORRIP;
                        goto skipRRIP;
                }
-               rootp = (struct iso_directory_record *)bp->b_data;
+               rootp = (struct iso_directory_record *)((char *)0 + buf_dataptr(bp));
                
                if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
                        argp->flags  |= ISOFSMNT_NORRIP;
@@ -491,8 +585,8 @@ iso_mountfs(devvp, mp, p, argp)
                 * The contents are valid,
                 * but they will get reread as part of another vnode, so...
                 */
-               bp->b_flags |= B_AGE;
-               brelse(bp);
+               buf_markaged(bp);
+               buf_brelse(bp);
                bp = NULL;
        }
 skipRRIP:
@@ -523,13 +617,11 @@ skipRRIP:
                /*
                 * On Joliet CDs use the UCS-2 volume identifier.
                 *
-                * This name can have up to 15 UCS-2 chars and is
-                * terminated with 0x0000 or padded with 0x0020.
+                * This name can have up to 16 UCS-2 chars.
                 */
-               convflags = UTF_DECOMPOSED;
-               if (BYTE_ORDER != BIG_ENDIAN)
-                       convflags |= UTF_REVERSE_ENDIAN;
-               for (i = 0, uchp = (u_int16_t *)sup->volume_id; i < 15 && uchp[i]; ++i);
+               convflags = UTF_DECOMPOSED | UTF_BIG_ENDIAN;
+               uchp = (u_int16_t *)sup->volume_id;
+               for (i = 0; i < 16 && uchp[i]; ++i);
                if ((utf8_encodestr((u_int16_t *)sup->volume_id, (i * 2), vol_id,
                        &convbytes, sizeof(vol_id), 0, convflags) == 0)
                        && convbytes && (vol_id[0] != ' ')) {
@@ -539,46 +631,60 @@ skipRRIP:
                        strp = vol_id + convbytes - 1;
                        while (strp > vol_id && *strp == ' ')
                                *strp-- = '\0';
-                       bcopy(vol_id, isomp->volume_id, convbytes);
+                       bcopy(vol_id, isomp->volume_id, convbytes + 1);
                }
 
                rootp = (struct iso_directory_record *)
                        sup->root_directory_record;
-               bcopy (rootp, isomp->root, sizeof isomp->root);
+               bcopy (rootp, isomp->root, sizeof(isomp->root));
                isomp->root_extent = isonum_733 (rootp->extent);
                isomp->root_size = isonum_733 (rootp->size);
-               supbp->b_flags |= B_AGE;
+               buf_markaged(supbp);
                isomp->iso_ftype = ISO_FTYPE_JOLIET;
        }
 
        if (supbp) {
-               brelse(supbp);
+               buf_brelse(supbp);
                supbp = NULL;
        }
 
+       /* If there was a TOC in the arguments, copy it in. */
+       if (argp->flags & ISOFSMNT_TOC) {
+               MALLOC(isomp->toc, struct CDTOC *, argp->toc_length, M_ISOFSMNT, M_WAITOK);
+               if ((error = copyin(argp->toc, isomp->toc, argp->toc_length)))
+                       goto out;
+       }
+
+       /* See if this could be a Video CD */
+       if ((isomp->im_flags2 & IMF2_IS_CDXA) && cd9660_find_video_dir(isomp)) {
+               /* Get the 2352-bytes-per-block device. */
+               isomp->phys_devvp = cd9660_phys_device(mp, context);
+       }
+
+       /* Fill the default statfs information */
+       (void) cd9660_statfs(mp, vfs_statfs(mp), context);
+
        return (0);
 out:
+       if (orig_bsize != iso_bsize) {
+               (void)VNOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
+                       (caddr_t)&orig_bsize, FWRITE, context);
+       }
+
        if (bp)
-               brelse(bp);
+               buf_brelse(bp);
        if (pribp)
-               brelse(pribp);
+               buf_brelse(pribp);
        if (supbp)
-               brelse(supbp);
-       if (needclose)
-               (void)VOP_CLOSE(devvp, FREAD, NOCRED, p);
+               buf_brelse(supbp);
+
        if (isomp) {
+               if (isomp->toc)
+                       FREE((caddr_t)isomp->toc, M_ISOFSMNT);
                FREE((caddr_t)isomp, M_ISOFSMNT);
-               mp->mnt_data = (qaddr_t)0;
-       }
-
-       /* Clear the mounted on bit in the devvp If it   */
-       /* not set, this is a nop and there is no way to */
-       /* get here with it set unless we did it.  If you*/
-       /* are making code changes which makes the above */
-       /* assumption not true, change this code.        */
-
-       devvp->v_specflags &= ~SI_MOUNTEDON;
 
+               vfs_setfsprivate(mp, (void *)0);
+       }
        return (error);
 }
 
@@ -588,10 +694,8 @@ out:
  */
 /* ARGSUSED */
 int
-cd9660_start(mp, flags, p)
-       struct mount *mp;
-       int flags;
-       struct proc *p;
+cd9660_start(__unused struct mount *mp, __unused int flags,
+            __unused vfs_context_t context)
 {
        return (0);
 }
@@ -600,12 +704,9 @@ cd9660_start(mp, flags, p)
  * unmount system call
  */
 int
-cd9660_unmount(mp, mntflags, p)
-       struct mount *mp;
-       int mntflags;
-       struct proc *p;
+cd9660_unmount(struct mount *mp, int mntflags, vfs_context_t context)
 {
-       register struct iso_mnt *isomp;
+       struct iso_mnt *isomp;
        int error, flags = 0;
        int force = 0;
        
@@ -623,16 +724,17 @@ cd9660_unmount(mp, mntflags, p)
        if (isomp->iso_ftype == ISO_FTYPE_RRIP)
                iso_dunmap(isomp->im_dev);
 #endif
-       
-       isomp->im_devvp->v_specflags &= ~SI_MOUNTEDON;
-       error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, p);
-       if (error && !force )
-               return(error);
+       if (isomp->phys_devvp) {
+               error = VNOP_CLOSE(isomp->phys_devvp, FREAD, context);
+               if (error && !force)
+                       return error;
+               vnode_put(isomp->phys_devvp);
+       }
 
-       vrele(isomp->im_devvp);
+       if (isomp->toc)
+               FREE((caddr_t)isomp->toc, M_ISOFSMNT);
        FREE((caddr_t)isomp, M_ISOFSMNT);
-       mp->mnt_data = (qaddr_t)0;
-       mp->mnt_flag &= ~MNT_LOCAL;
+
        return (0);
 }
 
@@ -640,9 +742,7 @@ cd9660_unmount(mp, mntflags, p)
  * Return root of a filesystem
  */
 int
-cd9660_root(mp, vpp)
-       struct mount *mp;
-       struct vnode **vpp;
+cd9660_root(struct mount *mp, struct vnode **vpp, __unused vfs_context_t context)
 {
        struct iso_mnt *imp = VFSTOISOFS(mp);
        struct iso_directory_record *dp =
@@ -653,58 +753,50 @@ cd9660_root(mp, vpp)
         * With RRIP we must use the `.' entry of the root directory.
         * Simply tell vget, that it's a relocated directory.
         */
-       return (cd9660_vget_internal(mp, ino, vpp,
+       return (cd9660_vget_internal(mp, ino, vpp, NULL, NULL,
                imp->iso_ftype == ISO_FTYPE_RRIP, dp, current_proc()));
 }
 
-/*
- * Do operations associated with quotas, not supported
- */
-/* ARGSUSED */
-int
-cd9660_quotactl(mp, cmd, uid, arg, p)
-       struct mount *mp;
-       int cmd;
-       uid_t uid;
-       caddr_t arg;
-       struct proc *p;
-{
-
-       return (EOPNOTSUPP);
-}
-
 /*
  * Get file system statistics.
  */
+/* ARGSUSED */
 int
-cd9660_statfs(mp, sbp, p)
-       struct mount *mp;
-       register struct statfs *sbp;
-       struct proc *p;
+cd9660_statfs(struct mount *mp, struct vfsstatfs *sbp,
+             __unused vfs_context_t context)
 {
-       register struct iso_mnt *isomp;
+       struct iso_mnt *isomp;
        
        isomp = VFSTOISOFS(mp);
 
+#if 0
 #ifdef COMPAT_09
        sbp->f_type = 5;
 #else
        sbp->f_type = 0;
 #endif
-       sbp->f_bsize = isomp->logical_block_size;
-       sbp->f_iosize = sbp->f_bsize;   /* XXX */
-       sbp->f_blocks = isomp->volume_space_size;
-       sbp->f_bfree = 0; /* total free blocks */
-       sbp->f_bavail = 0; /* blocks free for non superuser */
-       sbp->f_files =  0; /* total files */
-       sbp->f_ffree = 0; /* free file nodes */
-       if (sbp != &mp->mnt_stat) {
-               bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
-               bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
-       }
+#endif
+       sbp->f_bsize = (uint32_t)isomp->logical_block_size;
+       sbp->f_iosize = (size_t)sbp->f_bsize;   /* XXX */
+       sbp->f_blocks = (uint64_t)((unsigned long)isomp->volume_space_size);
+       sbp->f_bfree = (uint64_t)0; /* total free blocks */
+       sbp->f_bavail = (uint64_t)0; /* blocks free for non superuser */
+       sbp->f_files =  (uint64_t)0; /* total files */
+       sbp->f_ffree = (uint64_t)0; /* free file nodes */
+       sbp->f_fstypename[(MFSTYPENAMELEN - 1)] = '\0';
 
-       strncpy( sbp->f_fstypename, mp->mnt_vfc->vfc_name, (MFSNAMELEN - 1) );
-       sbp->f_fstypename[(MFSNAMELEN - 1)] = '\0';
+       /*
+        * Subtypes (flavors) for ISO 9660
+        *   0:   ISO-9660
+        *   1:   ISO-9660 (Joliet) 
+        *   2:   ISO-9660 (Rockridge) 
+        */
+       if (isomp->iso_ftype == ISO_FTYPE_JOLIET)
+               sbp->f_fssubtype = 1;
+       else if (isomp->iso_ftype == ISO_FTYPE_RRIP)
+               sbp->f_fssubtype = 2;
+       else
+               sbp->f_fssubtype = 0;
 
        /* DO NOT use the first spare for flags; it's been reassigned for another use: */
        /* sbp->f_spare[0] = isomp->im_flags; */
@@ -712,13 +804,109 @@ cd9660_statfs(mp, sbp, p)
        return (0);
 }
 
+int cd9660_vfs_getattr(struct mount *mp, struct vfs_attr *fsap, __unused vfs_context_t context)
+{
+       struct iso_mnt *imp;
+       struct vfsstatfs *stats = vfs_statfs(mp);
+
+       imp = VFSTOISOFS(mp);
+
+       /*
+        * We don't know reasonable values for f_objcount, f_filecount,
+        * f_dircount, f_maxobjcount so don't bother making up (poor)
+        * numbers like 10.3.x and earlier did.
+        */
+       
+       VFSATTR_RETURN(fsap, f_iosize, stats->f_iosize);
+       VFSATTR_RETURN(fsap, f_blocks, stats->f_blocks);
+       VFSATTR_RETURN(fsap, f_bfree,  stats->f_bfree);
+       VFSATTR_RETURN(fsap, f_bavail, stats->f_bavail);
+       VFSATTR_RETURN(fsap, f_bused,  stats->f_blocks);
+       
+       /* We don't have file counts, so don't return them */
+       
+       /* f_fsid and f_owner should be handled by VFS */
+       
+       /* We don't have a value for f_uuid */
+       
+       if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) {
+               fsap->f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] =
+                       (imp->iso_ftype == ISO_FTYPE_RRIP ? VOL_CAP_FMT_SYMBOLICLINKS : 0) |
+                       (imp->iso_ftype == ISO_FTYPE_RRIP ? VOL_CAP_FMT_HARDLINKS : 0) |
+                       (imp->iso_ftype == ISO_FTYPE_RRIP || imp->iso_ftype == ISO_FTYPE_JOLIET
+                               ? VOL_CAP_FMT_CASE_SENSITIVE : 0) |
+                       VOL_CAP_FMT_CASE_PRESERVING |
+                       VOL_CAP_FMT_FAST_STATFS;
+               fsap->f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] =
+                       VOL_CAP_INT_ATTRLIST |
+                       VOL_CAP_INT_NFSEXPORT;
+               fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
+               fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
+               
+               fsap->f_capabilities.valid[VOL_CAPABILITIES_FORMAT] =
+                       VOL_CAP_FMT_PERSISTENTOBJECTIDS |
+                       VOL_CAP_FMT_SYMBOLICLINKS |
+                       VOL_CAP_FMT_HARDLINKS |
+                       VOL_CAP_FMT_JOURNAL |
+                       VOL_CAP_FMT_JOURNAL_ACTIVE |
+                       VOL_CAP_FMT_NO_ROOT_TIMES |
+                       VOL_CAP_FMT_SPARSE_FILES |
+                       VOL_CAP_FMT_ZERO_RUNS |
+                       VOL_CAP_FMT_CASE_SENSITIVE |
+                       VOL_CAP_FMT_CASE_PRESERVING |
+                       VOL_CAP_FMT_FAST_STATFS | 
+                       VOL_CAP_FMT_2TB_FILESIZE;
+               fsap->f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] =
+                       VOL_CAP_INT_SEARCHFS |
+                       VOL_CAP_INT_ATTRLIST |
+                       VOL_CAP_INT_NFSEXPORT |
+                       VOL_CAP_INT_ALLOCATE |
+                       VOL_CAP_INT_ADVLOCK |
+                       VOL_CAP_INT_FLOCK;
+               fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED1] = 0;
+               fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED2] = 0;
+               
+               VFSATTR_SET_SUPPORTED(fsap, f_capabilities);
+       }
+       
+       if (VFSATTR_IS_ACTIVE(fsap, f_attributes)) {
+               /*
+                * VFS should really set these based on the vfs_attr and vnop_attr
+                * fields the file system supports, combined with the conversions
+                * VFS has implemented.
+                */
+
+#define ISOFS_ATTR_CMN_VALIDMASK       (ATTR_CMN_VALIDMASK & ~(ATTR_CMN_PAROBJID | ATTR_CMN_CRTIME | ATTR_CMN_BKUPTIME | ATTR_CMN_PARENTID))
+#define ISOFS_ATTR_VOL_VALIDMASK       (ATTR_VOL_VALIDMASK & ~(ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | ATTR_VOL_MAXOBJCOUNT | ATTR_VOL_NAME))
+#define ISOFS_ATTR_DIR_VALIDMASK       (ATTR_DIR_VALIDMASK & ~(ATTR_DIR_ENTRYCOUNT))
+
+               fsap->f_attributes.validattr.commonattr = ISOFS_ATTR_CMN_VALIDMASK;
+        fsap->f_attributes.validattr.volattr = ISOFS_ATTR_VOL_VALIDMASK;
+        fsap->f_attributes.validattr.dirattr = ISOFS_ATTR_DIR_VALIDMASK;
+        fsap->f_attributes.validattr.fileattr = ATTR_FILE_VALIDMASK;
+        fsap->f_attributes.validattr.forkattr = ATTR_FORK_VALIDMASK;
+
+               fsap->f_attributes.nativeattr.commonattr = ISOFS_ATTR_CMN_VALIDMASK;
+        fsap->f_attributes.nativeattr.volattr = ISOFS_ATTR_VOL_VALIDMASK;
+        fsap->f_attributes.nativeattr.dirattr = ISOFS_ATTR_DIR_VALIDMASK;
+        fsap->f_attributes.nativeattr.fileattr = ATTR_FILE_VALIDMASK;
+        fsap->f_attributes.nativeattr.forkattr = ATTR_FORK_VALIDMASK;
+
+               VFSATTR_SET_SUPPORTED(fsap, f_attributes);
+       }
+       
+       VFSATTR_RETURN(fsap, f_create_time, imp->creation_date);
+       VFSATTR_RETURN(fsap, f_modify_time, imp->modification_date);
+       /* No explicit access time, so let VFS pick a default value */
+       /* No explicit backup time, so let VFS pick a default value */
+       
+       return 0;
+}
+
 /* ARGSUSED */
 int
-cd9660_sync(mp, waitfor, cred, p)
-       struct mount *mp;
-       int waitfor;
-       struct ucred *cred;
-       struct proc *p;
+cd9660_sync(__unused struct mount *mp, __unused int waitfor,
+           __unused vfs_context_t context)
 {
 
        return (0);
@@ -735,62 +923,129 @@ cd9660_sync(mp, waitfor, cred, p)
  */
 
 struct ifid {
-       ushort  ifid_len;
-       ushort  ifid_pad;
        int     ifid_ino;
        long    ifid_start;
 };
 
 /* ARGSUSED */
 int
-cd9660_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
-       register struct mount *mp;
-       struct fid *fhp;
-       struct mbuf *nam;
-       struct vnode **vpp;
-       int *exflagsp;
-       struct ucred **credanonp;
+cd9660_fhtovp(mount_t mp, int fhlen, unsigned char *fhp, vnode_t *vpp, vfs_context_t context)
 {
        struct ifid *ifhp = (struct ifid *)fhp;
-       register struct iso_node *ip;
-       register struct netcred *np;
-       register struct iso_mnt *imp = VFSTOISOFS(mp);
+       struct iso_node *ip;
        struct vnode *nvp;
        int error;
        
+       if (fhlen < (int)sizeof(struct ifid))
+               return (EINVAL);
+
 #ifdef ISOFS_DBG
        printf("fhtovp: ino %d, start %ld\n",
               ifhp->ifid_ino, ifhp->ifid_start);
 #endif
        
-       /*
-        * Get the export permission structure for this <mp, client> tuple.
-        */
-       np = vfs_export_lookup(mp, &imp->im_export, nam);
-       if (np == NULL)
-               return (EACCES);
-
-       if ( (error = VFS_VGET(mp, &ifhp->ifid_ino, &nvp)) ) {
+       if ( (error = VFS_VGET(mp, (ino64_t)ntohl(ifhp->ifid_ino), &nvp, context)) ) {
                *vpp = NULLVP;
                return (error);
        }
        ip = VTOI(nvp);
        if (ip->inode.iso_mode == 0) {
-               vput(nvp);
+               vnode_put(nvp);
                *vpp = NULLVP;
                return (ESTALE);
        }
        *vpp = nvp;
-       *exflagsp = np->netc_exflags;
-       *credanonp = &np->netc_anon;
        return (0);
 }
 
+/*
+ * Scan the TOC for the track which contains the given sector.
+ *
+ * If there is no matching track, or no TOC, then return -1.
+ */
+static int
+cd9660_track_for_sector(struct CDTOC *toc, u_int sector)
+{
+       int i, tracks, result;
+       
+       if (toc == NULL)
+               return -1;
+
+       tracks = toc->length / sizeof(struct CDTOC_Desc);
+       
+       result = -1;            /* Sentinel in case we don't find the right track. */
+       for (i=0; i<tracks; ++i) {
+               if (toc->trackdesc[i].point < 100 && MSF_TO_LBA(toc->trackdesc[i].p) <= sector) {
+                       result = toc->trackdesc[i].point;
+               }
+       }
+       
+       return result;
+}
+
+/*
+ * Determine whether the given node is really a video CD video
+ * file.  Return non-zero if it appears to be a video file.
+ */
+static int
+cd9660_is_video_file(struct iso_node *ip, struct iso_mnt *imp)
+{
+       int lbn;
+       int track;
+       
+       /* Check whether this could really be a Video CD at all */
+       if (((imp->im_flags2 & IMF2_IS_VCD) == 0) ||
+               imp->phys_devvp == NULL ||
+               imp->toc == NULL)
+       {
+               return 0;       /* Doesn't even look like VCD... */
+       }
+
+       /* Make sure it is a file */
+       if ((ip->inode.iso_mode & S_IFMT) != S_IFREG)
+               return 0;       /* Not even a file... */
+
+       /*
+        * And in the right directory.  This assumes the same inode
+        * number convention that cd9660_vget_internal uses (that
+        * part of the inode number is the block containing the
+        * file's directory entry).
+        */
+       lbn = lblkno(imp, ip->i_number);
+       if (lbn < imp->video_dir_start || lbn >= imp->video_dir_end)
+               return 0;       /* Not in the correct directory */
+       
+       /*
+        * If we get here, the file should be a video file, but
+        * do a couple of extra sanity checks just to be sure.
+        * First, verify the form of the name
+        */
+       if (strlen(ip->i_namep) != 11 ||                /* Wrong length? */
+               bcmp(ip->i_namep+7, ".DAT", 4) ||       /* Wrong extension? */
+               (bcmp(ip->i_namep, "AVSEQ", 5) &&       /* Wrong beginning? */
+                bcmp(ip->i_namep, "MUSIC", 5)))
+       {
+               return 0;       /* Invalid name format */
+       }
+       
+       /*
+        * Verify that AVSEQnn.DAT is in track #(nn+1).  This would
+        * not be appropriate for Super Video CD, which allows
+        * multiple sessions, so the track numbers might not
+        * match up like this. 
+        */
+       track = (ip->i_namep[5] - '0') * 10 + ip->i_namep[6] - '0';
+       if (track != (cd9660_track_for_sector(imp->toc, ip->iso_start) - 1))
+       {
+               return 0;       /* Wrong number in name */
+       }
+
+       /* It must be a video file if we got here. */
+       return 1;
+}
+
 int
-cd9660_vget(mp, ino, vpp)
-       struct mount *mp;
-       void *ino;
-       struct vnode **vpp;
+cd9660_vget(struct mount *mp, ino64_t ino, struct vnode **vpp, __unused vfs_context_t context)
 {
        /*
         * XXXX
@@ -799,55 +1054,56 @@ cd9660_vget(mp, ino, vpp)
         * that right now.
         */
 
-       return ( cd9660_vget_internal( mp, *(ino_t*)ino, vpp, 0, 
-                                                                  (struct iso_directory_record *) 0,
-                                                                  current_proc()) );
+       return ( cd9660_vget_internal( mp, (ino_t)ino, vpp, NULL, NULL,
+                                      0, (struct iso_directory_record *) 0, current_proc()) );
 }
 
 int
-cd9660_vget_internal(mp, ino, vpp, relocated, isodir, p)
-       struct mount *mp;
-       ino_t ino;
-       struct vnode **vpp;
-       int relocated;
-       struct iso_directory_record *isodir;
-    struct proc *p;
+cd9660_vget_internal(mount_t mp, ino_t ino, vnode_t *vpp, vnode_t dvp,
+                    struct componentname *cnp, int relocated,
+                    struct iso_directory_record *isodir, proc_t p)
 {
-       register struct iso_mnt *imp;
+       struct iso_mnt *imp;
        struct iso_node *ip;
-       struct buf *bp;
-       struct vnode *vp, *nvp;
-       dev_t dev;
-       int error;
-
-       imp = VFSTOISOFS(mp);
-       dev = imp->im_dev;
-
+       buf_t   bp = NULL;
+       vnode_t vp;
+       dev_t   dev;
+       int     error;
+       struct vnode_fsparam vfsp;
+       enum vtype vtype;
+       int is_video_file = 0;
+
+       *vpp = NULLVP;
+       imp  = VFSTOISOFS(mp);
+       dev  = imp->im_dev;
+#if 0
        /* Check for unmount in progress */
-    if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
-        *vpp = NULLVP;
-        return (EPERM);
-    }
-
-       if ((*vpp = cd9660_ihashget(dev, ino, p)) != NULLVP)
-               return (0);
+       if (mp->mnt_kern_flag & MNTK_UNMOUNT)
+               return (EPERM);
+#endif
 
        MALLOC_ZONE(ip, struct iso_node *, sizeof(struct iso_node),
-           M_ISOFSNODE, M_WAITOK);
-       /* Allocate a new vnode/iso_node. */
-       if ( (error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, &vp)) ) {
-               FREE_ZONE(ip,sizeof(struct iso_node), M_ISOFSNODE);
-               *vpp = NULLVP;
-               return (error);
+                   M_ISOFSNODE, M_WAITOK);
+       /*
+        * MALLOC_ZONE may block, so check for the inode being 
+        * present in the hash after we get back...
+        * we also assume that we're under a filesystem lock
+        * so that we're not reentered between the ihashget and
+        * the ihashins...
+        */
+       if ((*vpp = cd9660_ihashget(dev, ino, p)) != NULLVP) {
+               FREE_ZONE(ip, sizeof(struct iso_node), M_ISOFSNODE);
+               return (0);
        }
        bzero((caddr_t)ip, sizeof(struct iso_node));
-       lockinit(&ip->i_lock, PINOD,"isonode",0,0);
-       vp->v_data = ip;
-       ip->i_vnode = vp;
+
        ip->i_dev = dev;
        ip->i_number = ino;
        ip->i_namep = &isonullname[0];
+       ip->i_mnt = imp;
+       ip->i_devvp = imp->im_devvp;
 
+       SET(ip->i_flag, ISO_INALLOC);
        /*
         * Put it onto its hash chain and lock it so that other requests for
         * this inode will block if they arrive while we are sleeping waiting
@@ -860,40 +1116,36 @@ cd9660_vget_internal(mp, ino, vpp, relocated, isodir, p)
                int lbn, off;
 
                lbn = lblkno(imp, ino);
+
                if (lbn >= imp->volume_space_size) {
-                       vput(vp);
                        printf("fhtovp: lbn exceed volume space %d\n", lbn);
-                       return (ESTALE);
+                       error = ESTALE;
+                       goto errout;
                }
-       
                off = blkoff(imp, ino);
+
                if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
-                       vput(vp);
                        printf("fhtovp: crosses block boundary %d\n",
                                off + ISO_DIRECTORY_RECORD_SIZE);
-                       return (ESTALE);
+                       error = ESTALE;
+                       goto errout;
                }
        
-               error = bread(imp->im_devvp, lbn,
-                                       imp->logical_block_size, NOCRED, &bp);
+               error = (int)buf_bread(imp->im_devvp, (daddr64_t)((unsigned)lbn),
+                                      imp->logical_block_size, NOCRED, &bp);
                if (error) {
-                       vput(vp);
-                       brelse(bp);
-                       printf("fhtovp: bread error %d\n",error);
-                       return (error);
+                       printf("fhtovp: buf_bread error %d\n",error);
+                       goto errout;
                }
-               isodir = (struct iso_directory_record *)(bp->b_data + off);
+               isodir = (struct iso_directory_record *)(buf_dataptr(bp) + off);
 
-               if (off + isonum_711(isodir->length) >
-                       imp->logical_block_size) {
-                       vput(vp);
-                       if (bp != 0)
-                               brelse(bp);
+               if (off + isonum_711(isodir->length) > imp->logical_block_size) {
                        printf("fhtovp: directory crosses block boundary "
                                "%d[off=%d/len=%d]\n",
                                off +isonum_711(isodir->length), off,
                                isonum_711(isodir->length));
-                       return (ESTALE);
+                       error = ESTALE;
+                       goto errout;
                }
 
                /*
@@ -905,46 +1157,71 @@ cd9660_vget_internal(mp, ino, vpp, relocated, isodir, p)
                        struct iso_directory_record *pdp;
 
                        pdp = (struct iso_directory_record *)
-                                       ((char *)bp->b_data + isonum_711(isodir->length));
+                                       ((char *)0 + buf_dataptr(bp) + isonum_711(isodir->length));
                        if ((isonum_711(pdp->flags) & directoryBit)
                                        && (pdp->name[0] == 1))
                                ip->i_parent = isodirino(pdp, imp);
                }
-       } else
-               bp = 0;
-
-       ip->i_mnt = imp;
-       ip->i_devvp = imp->im_devvp;
-       VREF(ip->i_devvp);
-
+       }
        if (relocated) {
+               daddr64_t lbn;
+
+               if (bp) {
+                       buf_brelse(bp);
+                       bp = NULL;
+               }
                /*
                 * On relocated directories we must
                 * read the `.' entry out of a dir.
                 */
                ip->iso_start = ino >> imp->im_bshift;
-               if (bp != 0)
-                       brelse(bp);
-               if ( (error = VOP_BLKATOFF(vp, (off_t)0, NULL, &bp)) ) {
-                       vput(vp);
-                       return (error);
-               }
-               isodir = (struct iso_directory_record *)bp->b_data;
+               /*
+                * caclulate the correct lbn to read block 0
+                * of this node... this used to be a cd9660_blkatoff, but
+                * that requires the vnode to already be 'cooked'... in
+                * the new world, we don't create a vnode until the inode
+                * has been fully initialized... cd9660_blkatoff generates
+                * a buf_bread for im_sector_size associated with the node's vp
+                * I'm replacing it with a buf_bread for the same size and from
+                * the same location on the disk, but associated with the devvp
+                */
+               lbn = (daddr64_t)((unsigned)ip->iso_start) + 0;
+
+               if ((error = (int)buf_bread(imp->im_devvp, lbn, imp->im_sector_size, NOCRED, &bp)))
+                       goto errout;
+
+               isodir = (struct iso_directory_record *)((char *)0 + buf_dataptr(bp));
        }
 
        /*
         * go get apple extensions to ISO directory record or use
         * defaults when there are no apple extensions.
         */
-       if ( (isonum_711( isodir->flags ) & directoryBit) == 0 ) {
+       if ( ((isonum_711( isodir->flags ) & directoryBit) == 0) &&
+            (imp->iso_ftype != ISO_FTYPE_RRIP) ) {
                /* This is an ISO directory record for a file */
-               DRGetTypeCreatorAndFlags( imp, isodir, &ip->i_FileType, 
-                                                                 &ip->i_Creator, &ip->i_FinderFlags );
+               DRGetTypeCreatorAndFlags(imp, isodir, &ip->i_FileType, 
+                                        &ip->i_Creator, &ip->i_FinderFlags);
+
+               if (isonum_711(isodir->flags) & associatedBit)
+                       ip->i_flag |= ISO_ASSOCIATED;
+       }
+
+       /*
+        * Shadow the ISO 9660 invisible state to the FinderInfo
+        */
+       if (isonum_711(isodir->flags) & existenceBit) {
+               ip->i_FinderFlags |= fInvisibleBit;
        }
 
        ip->iso_extent = isonum_733(isodir->extent);
        ip->i_size = isonum_733(isodir->size);
        ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
+       /*
+        * account for AppleDouble header
+        */
+       if (ip->i_flag & ISO_ASSOCIATED)
+               ip->i_size += ADH_SIZE;
 
        /*
         * if we have a valid name, fill in i_namep with UTF-8 name
@@ -965,13 +1242,13 @@ cd9660_vget_internal(mp, ino, vpp, relocated, isodir, p)
                case ISO_FTYPE_JOLIET:
                        ucsfntrans((u_int16_t *)isodir->name, namelen,
                                   utf8namep, &namelen,
-                                  isonum_711(isodir->flags) & directoryBit);
+                                  isonum_711(isodir->flags) & directoryBit, ip->i_flag & ISO_ASSOCIATED);
                        break;
 
                default:
                        isofntrans (isodir->name, namelen,
                                        utf8namep, &namelen,
-                                       imp->iso_ftype == ISO_FTYPE_9660);
+                                       imp->iso_ftype == ISO_FTYPE_9660, ip->i_flag & ISO_ASSOCIATED);
                }
 
                utf8namep[namelen] = '\0';
@@ -983,94 +1260,144 @@ cd9660_vget_internal(mp, ino, vpp, relocated, isodir, p)
        /*
         * Setup time stamp, attribute
         */
-       vp->v_type = VNON;
        switch (imp->iso_ftype) {
        default:        /* ISO_FTYPE_9660 */
                {
-               struct buf *bp2;
-               int off;
-               if ((imp->im_flags & ISOFSMNT_EXTATT)
-                               && (off = isonum_711(isodir->ext_attr_length)))
-                       VOP_BLKATOFF(vp, (off_t)-(off << imp->im_bshift), NULL, &bp2);
-               else
+               buf_t   bp2 = NULL;
+               daddr64_t lbn;
+               int     off;
+
+               if ((imp->im_flags & ISOFSMNT_EXTATT) && (off = isonum_711(isodir->ext_attr_length))) {
+
+                       lbn = (daddr64_t)((unsigned)ip->iso_start - off);
+
+                       if ((error = (int)buf_bread(imp->im_devvp, lbn, imp->im_sector_size, NOCRED, &bp2))) {
+                               if (bp2)
+                                       buf_brelse(bp2);
+                               goto errout;
+                       }
+               } else
                        bp2 = NULL;
+
                cd9660_defattr(isodir, ip, bp2);
                cd9660_deftstamp(isodir, ip, bp2);
+
                if (bp2)
-                       brelse(bp2);
+                       buf_brelse(bp2);
                break;
                }
        case ISO_FTYPE_RRIP:
                cd9660_rrip_analyze(isodir, ip, imp);
                break;
        }
-
-       if (bp != 0)
-               brelse(bp);
-
        /*
-        * Initialize the associated vnode
+        * See if this is a Video CD file.  If so, we must adjust the
+        * length to account for larger sectors plus the RIFF header.
+        * We also must substitute the vnop_read and vnop_pagein functions.
+        *
+        * The cd9660_is_video_file routine assumes that the inode has
+        * been completely set up; it refers to several fields.
+        *
+        * This must be done before we release bp, because isodir
+        * points into bp's data.
         */
-        
+       if (cd9660_is_video_file(ip, imp))
+       {
+               cd9660_xa_init(ip, isodir);
+               
+               is_video_file = 1;
+       }
        if (ip->iso_extent == imp->root_extent) {
-               vp->v_flag |= VROOT;
                ip->i_parent = 1;       /* root's parent is always 1 by convention */
                /* mode type must be S_IFDIR */
                ip->inode.iso_mode = (ip->inode.iso_mode & ~S_IFMT) | S_IFDIR;
        }
-
-       switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) {
-       case VFIFO:
-#if    FIFO
-               vp->v_op = cd9660_fifoop_p;
-               break;
-#else
-               vput(vp);
-               return (EOPNOTSUPP);
-#endif /* FIFO */
-       case VCHR:
-       case VBLK:
-               /*
-                * if device, look at device number table for translation
-                */
-#ifdef ISODEVMAP
-               if (dp = iso_dmap(dev, ino, 0))
-                       ip->inode.iso_rdev = dp->d_dev;
+       vtype = IFTOVT(ip->inode.iso_mode);
+#if !FIFO
+       if (vtype == VFIFO) {
+               error = ENOTSUP;
+               goto errout;
+       }
 #endif
-               vp->v_op = cd9660_specop_p;
-               if ( (nvp = checkalias(vp, ip->inode.iso_rdev, mp)) ) {
-                       /*
-                        * Discard unneeded vnode, but save its iso_node.
-                        */
-                       cd9660_ihashrem(ip);
-                       VOP_UNLOCK(vp, 0, p);
-                       nvp->v_data = vp->v_data;
-                       vp->v_data = NULL;
-                       vp->v_op = spec_vnodeop_p;
-                       vrele(vp);
-                       vgone(vp);
-                       /*
-                        * Reinitialize aliased inode.
-                        */
-                       vp = nvp;
-                       ip->i_vnode = vp;
-                       cd9660_ihashins(ip);
-               }
-               break;
-       case VREG:
-               ubc_info_init(vp);
-               break;
-       default:
-               break;
+#ifdef  ISODEVMAP
+       if (vtype == VCHR || vtype == VBLK) {
+               struct iso_dnode *dp;
+
+               if (dp = iso_dmap(dev, ino, 0))
+                       ip->inode.iso_rdev = dp->d_dev;
        }
-       
+#endif
        /*
-        * XXX need generation number?
+        * create the associated vnode
         */
+       //bzero(&vfsp, sizeof(struct vnode_fsparam));
+       vfsp.vnfs_mp = mp;
+       vfsp.vnfs_vtype = vtype;
+       vfsp.vnfs_str = "cd9660";
+       vfsp.vnfs_dvp = dvp;
+       vfsp.vnfs_fsnode = ip;
+       vfsp.vnfs_cnp = cnp;
+
+       if (is_video_file)
+               vfsp.vnfs_vops = cd9660_cdxaop_p;
+       else if (vtype == VFIFO )
+               vfsp.vnfs_vops = cd9660_fifoop_p;
+       else if (vtype == VBLK || vtype == VCHR)
+               vfsp.vnfs_vops = cd9660_specop_p;
+       else
+               vfsp.vnfs_vops = cd9660_vnodeop_p;
+               
+       if (vtype == VBLK || vtype == VCHR)
+               vfsp.vnfs_rdev = ip->inode.iso_rdev;
+       else
+               vfsp.vnfs_rdev = 0;
+
+       vfsp.vnfs_filesize = ip->i_size;
+
+       if (dvp && cnp && (cnp->cn_flags & MAKEENTRY))
+               vfsp.vnfs_flags = 0;
+       else
+               vfsp.vnfs_flags = VNFS_NOCACHE;
+
+       /* Tag root directory */
+       if (ip->iso_extent == imp->root_extent)
+               vfsp.vnfs_markroot = 1;
+       else    
+               vfsp.vnfs_markroot = 0;
+
+       vfsp.vnfs_marksystem = 0;
+
+       if ( (error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &vp)) )
+               goto errout;
 
+       ip->i_vnode = vp;
+
+       vnode_ref(ip->i_devvp);
+       vnode_addfsref(vp);
+       vnode_settag(vp, VT_ISOFS);
+
+       if (bp)
+               buf_brelse(bp);
        *vpp = vp;
 
+       CLR(ip->i_flag, ISO_INALLOC);
+
+       if (ISSET(ip->i_flag, ISO_INWALLOC))
+               wakeup(ip);
+
        return (0);
+
+errout:
+       if (bp)
+               buf_brelse(bp);
+       cd9660_ihashrem(ip);
+
+       if (ISSET(ip->i_flag, ISO_INWALLOC))
+               wakeup(ip);
+
+       FREE_ZONE(ip, sizeof(struct iso_node), M_ISOFSNODE);
+
+       return (error);
 }
 
 
@@ -1158,8 +1485,14 @@ DRGetTypeCreatorAndFlags(        struct iso_mnt * theMountPointPtr,
                myPtr += 14;/* add in CD-XA fixed record offset (tnx, Phillips) */
        myNewAppleExtPtr = (NewAppleExtension *) myPtr;
 
-       /* calculate the "real" end of the directory record information */
+       /*
+        * Calculate the "real" end of the directory record information.
+        *
+        * Note: We always read the first 4 bytes of the System-Use data, so
+        * adjust myPtr down so we don't read off the end of the directory!
+        */
        myPtr = ((char *) theDirRecPtr) + (isonum_711(theDirRecPtr->length));
+       myPtr -= sizeof(NewAppleExtension) - 1;
        while( (char *) myNewAppleExtPtr < myPtr )      /* end of directory buffer */
        {
                /*
@@ -1169,8 +1502,8 @@ DRGetTypeCreatorAndFlags( struct iso_mnt * theMountPointPtr,
                 *              struct OptionalSystemUse
                 *              {
                 *                      byte    Signature[2];
-                *                      byte    systemUseID;
                 *                      byte    OSULength;
+                *                      byte    systemUseID;
                 *                      byte    fileType[4];            # only if HFS
                 *                      byte    fileCreator[4];         # only if HFS
                 *                      byte    finderFlags[2];         # only if HFS
@@ -1261,18 +1594,19 @@ DoneLooking:
  */
 /* ARGSUSED */
 int
-cd9660_vptofh(vp, fhp)
-       struct vnode *vp;
-       struct fid *fhp;
+cd9660_vptofh(struct vnode *vp, int *fhlenp, unsigned char *fhp, __unused vfs_context_t context)
 {
-       register struct iso_node *ip = VTOI(vp);
-       register struct ifid *ifhp;
+       struct iso_node *ip = VTOI(vp);
+       struct ifid *ifhp;
+
+       if (*fhlenp < (int)sizeof(struct ifid))
+               return (EOVERFLOW);
        
        ifhp = (struct ifid *)fhp;
-       ifhp->ifid_len = sizeof(struct ifid);
        
-       ifhp->ifid_ino = ip->i_number;
-       ifhp->ifid_start = ip->iso_start;
+       ifhp->ifid_ino = htonl(ip->i_number);
+       ifhp->ifid_start = htonl(ip->iso_start);
+       *fhlenp = sizeof(struct ifid);
        
 #ifdef ISOFS_DBG
        printf("vptofh: ino %d, start %ld\n",
@@ -1285,15 +1619,10 @@ cd9660_vptofh(vp, fhp)
  * Fast-FileSystem only?
  */
 int
-cd9660_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
-     int * name;
-     u_int namelen;
-     void* oldp;
-     size_t * oldlenp;
-     void * newp;
-     size_t newlen;
-     struct proc * p;
+cd9660_sysctl(__unused int *name, __unused u_int namelen, __unused user_addr_t oldp,
+             __unused size_t *oldlenp, __unused user_addr_t newp,
+             __unused size_t newlen, __unused vfs_context_t context)
 {
-     return (EOPNOTSUPP);
+     return (ENOTSUP);
 }