]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_vfsops.c
xnu-344.21.73.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_vfsops.c
index 6329bd20785c9074e7ed85242b3624cdf8373ba7..513f49ca6b7fff71fb12bef0f6fb62081b351659 100644 (file)
@@ -1,21 +1,24 @@
 /*
- * Copyright (c) 1999-2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * 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.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
  *      hfs_vfsops.c
  *  derived from       @(#)ufs_vfsops.c        8.8 (Berkeley) 5/20/95
  *
- *      (c) Copyright 1997-1998 Apple Computer, Inc. All rights reserved.
+ *      (c) Copyright 1997-2002 Apple Computer, Inc. All rights reserved.
  *
  *      hfs_vfsops.c -- VFS layer for loadable HFS file system.
  *
- *      HISTORY
- *      9-Nov-1999     Don Brady       Fix error handling in hfs_unmount [2399157].
- *      9-Sep-1999     Don Brady       Clear system file fcbModified flags in hfs_flushvolumeheader/hfs_flushMDB.
- *      5-Aug-1999     Pat Dirks       Moved special HFS flag from f_fsid.val[0][0] to mount flags (#2293117).
- *     23-Jul-1999     Pat Dirks       Added special-case code for root's parent directory in hfs_vget (#2263664).
- *      9-Jun-1999     Don Brady       Fix hfs_mount for reload and read-only downgrade cases.
- *      2-Jun-1999     Don Brady       Fix hfs_statfs to return correct f_files value.
- *      4-May-1999     Don Brady       Remove obsolete loadable module code.
- *     22-Mar-1999     Don Brady       Hide our private meta data in hfs_vget.
- *             18-May-1999     Don Brady       Add hfs_mountroot for HFS Plus rooting.
- *             22-Mar-1999     Don Brady       Hide our private meta data in hfs_vget.
- *              12-Nov-1998     Pat Dirks       Changed hfs_statfs to return volume's actual log. block size (#2286198).
- *             22-Aug-1998     Scott Roberts   Assign uid,gid, and mask for default on objects.
- *             29-Jul-1998     Pat Dirks               Fixed changed hfs_vget() to release complex node when retrying for data fork node.
- *             27-Jul-1998     Scott Roberts   Changes hfs_vget() to return data forks instead of complex.
- *         14-Jul-1998  CHW                    Added check for use count of device node in hfs_mountfs
- *         1-Jul-1998  Don Brady               Always set kHFSVolumeUnmountedMask bit of vcb->vcbAtrb in hfs_unmount.
- *        30-Jun-1998  Don Brady               Removed hard-coded EINVAL error in hfs_mountfs (for radar #2249539).
- *        24-Jun-1998  Don Brady               Added setting of timezone to hfs_mount (radar #2226387).
- *             4-Jun-1998      Don Brady               Use VPUT/VRELE macros instead of vput/vrele.
- *             6-May-1998      Scott Roberts   Updated hfs_vget with kernel changes.
- *             29-Apr-1998     Don Brady               Update hfs_statfs to actually fill in statfs fields (radar #2227092).
- *             23-Apr-1998     Pat Dirks               Cleaned up code to call brelse() on errors from bread().
- *              4/20/1998      Don Brady               Remove course-grained hfs metadata locking.
- *              4/18/1998      Don Brady               Add VCB locking.
- *              4/16/1998      Don Brady       hfs_unmount now flushes the volume bitmap. Add b-tree locking to hfs_vget.
- *               4/8/1998      Don Brady       Replace hfs_mdbupdate with hfs_flushvolumeheader and hfs_flushMDB.
- *               4/8/1998      Don Brady       In hfs_unmount call hfs_mdbupdate before trashing metafiles!
- *               4/3/1998      Don Brady       Call InitCatalogCache instead of PostInitFS.
- *               4/1/1998      Don Brady       Get rid of gHFSFlags, gReqstVol and gFlushOnlyFlag globals (not used).
- *              3/30/1998      Don Brady       In hfs_unmount use SKIPSYSTEM option on first vflush.
- *              3/26/1998      Don Brady       Changed hfs_unmount to call vflush before calling hfsUnmount.
- *                                                             In hfs_mountfs don't mount hfs-wrapper.
- *              3/19/1998      Pat Dirks       Fixed bug in hfs_mount where device vnode was being
- *                                                             released on way out.
- *      11/14/1997     Pat Dirks       Derived from hfs_vfsops.c
  */
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/mount.h>
 #include <sys/malloc.h>
 #include <sys/stat.h>
-#include <dev/disk.h>
 #include <sys/lock.h>
+#include <sys/quota.h>
+#include <sys/disk.h>
+
+// XXXdbg
+#include <vfs/vfs_journal.h>
+
 #include <miscfs/specfs/specdev.h>
 #include <hfs/hfs_mount.h>
 
 #include "hfs.h"
+#include "hfs_catalog.h"
+#include "hfs_cnode.h"
 #include "hfs_dbg.h"
 #include "hfs_endian.h"
+#include "hfs_quota.h"
 
 #include "hfscommon/headers/FileMgrInternal.h"
 #include "hfscommon/headers/BTreesInternal.h"
 
+
 #if    HFS_DIAGNOSTIC
 int hfs_dbg_all = 0;
-int hfs_dbg_vfs = 0;
-int hfs_dbg_vop = 0;
-int hfs_dbg_load = 0;
-int hfs_dbg_io = 0;
-int hfs_dbg_utils = 0;
-int hfs_dbg_rw = 0;
-int hfs_dbg_lookup = 0;
-int hfs_dbg_tree = 0;
 int hfs_dbg_err = 0;
-int hfs_dbg_test = 0;
 #endif
 
-/*
- * HFS File System globals:
- */
-Ptr                                    gBufferAddress[BUFFERPTRLISTSIZE];
-struct buf                     *gBufferHeaderPtr[BUFFERPTRLISTSIZE];
-int                                    gBufferListIndex;
-simple_lock_data_t     gBufferPtrListLock;
-
-//static char hfs_fs_name[MFSNAMELEN] = "hfs";
-
 
-/*
- * Global variables defined in other modules:
- */
 extern struct vnodeopv_desc hfs_vnodeop_opv_desc;
 
-extern struct vnode *hfs_vhashget(dev_t dev, UInt32 nodeID, UInt8 forkType);
-
-extern OSErr HFSPlusToHFSExtents( const HFSPlusExtentRecord    oldExtents, HFSExtentRecord newExtents);
-
+extern void hfs_converterinit(void);
 
 extern void inittodr( time_t base);
-extern OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb);
-extern void CopyCatalogToObjectMeta(struct hfsCatalogInfo *catInfo, struct vnode *vp, struct hfsfilemeta *fm);
-extern void CopyCatalogToFCB(struct hfsCatalogInfo *catInfo, struct vnode *vp);
-extern void hfs_name_CatToMeta(CatalogNodeData *nodeData, struct hfsfilemeta *fm);
 
-int hfs_changefs(struct mount *mp, struct hfs_mount_args *args, struct proc *p);
 
-int hfs_reload(struct mount *mp, struct ucred *cred, struct proc *p);
-int hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mount_args *args);
-int hfs_vget(struct mount *mp, void *objID, struct vnode **vpp);
-void hfs_vhashinit();
-void hfs_converterinit(void);
+static int hfs_changefs __P((struct mount *mp, struct hfs_mount_args *args,
+               struct proc *p));
+static int hfs_reload __P((struct mount *mp, struct ucred *cred, struct proc *p));
 
-
-static int hfs_statfs();
+static int hfs_mountfs __P((struct vnode *devvp, struct mount *mp, struct proc *p,
+               struct hfs_mount_args *args));
+static int hfs_statfs __P((struct mount *mp, register struct statfs *sbp,
+               struct proc *p));
 
 
 /*
@@ -184,6 +130,7 @@ hfs_mountroot()
        struct mount *mp;
        struct proc *p = current_proc();        /* XXX */
        struct hfsmount *hfsmp;
+       ExtendedVCB *vcb;
        int error;
        
        /*
@@ -193,11 +140,14 @@ hfs_mountroot()
                printf("hfs_mountroot: can't setup bdevvp");
                return (error);
        }
-       if ((error = vfs_rootmountalloc("hfs", "root_device", &mp)))
+       if ((error = vfs_rootmountalloc("hfs", "root_device", &mp))) {
+               vrele(rootvp); /* release the reference from bdevvp() */
                return (error);
+       }
        if ((error = hfs_mountfs(rootvp, mp, p, NULL))) {
                mp->mnt_vfc->vfc_refcount--;
                vfs_unbusy(mp, p);
+               vrele(rootvp); /* release the reference from bdevvp() */
                _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
                return (error);
        }
@@ -213,10 +163,15 @@ hfs_mountroot()
        hfsmp->hfs_dir_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
        hfsmp->hfs_file_mask = (S_IRWXU | S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH); /* 0755 */
 
+       /* Establish the free block reserve. */
+       vcb = HFSTOVCB(hfsmp);
+       vcb->reserveBlocks = ((u_int64_t)vcb->totalBlocks * HFS_MINFREE) / 100;
+       vcb->reserveBlocks = MIN(vcb->reserveBlocks, HFS_MAXRESERVE / vcb->blockSize);
+
        (void)hfs_statfs(mp, &mp->mnt_stat, p);
        
        vfs_unbusy(mp, p);
-       inittodr(to_bsd_time(HFSTOVCB(hfsmp)->vcbLsMod));
+       inittodr(HFSTOVCB(hfsmp)->vcbLsMod);
        return (0);
 }
 
@@ -227,8 +182,8 @@ hfs_mountroot()
  * mount system call
  */
 
-int
-hfs_mount (mp, path, data, ndp, p)
+static int
+hfs_mount(mp, path, data, ndp, p)
        register struct mount *mp;
        char *path;
        caddr_t data;
@@ -242,7 +197,6 @@ hfs_mount (mp, path, data, ndp, p)
        int retval = E_NONE;
        int flags;
        mode_t accessmode;
-       int loadconv = 0;
 
        if ((retval = copyin(data, (caddr_t)&args, sizeof(args))))
                goto error_exit;
@@ -265,21 +219,16 @@ hfs_mount (mp, path, data, ndp, p)
                        if (mp->mnt_flag & MNT_FORCE)
                                flags |= FORCECLOSE;
                                
-                       if ((retval = hfs_flushfiles(mp, flags)))
+                       if ((retval = hfs_flushfiles(mp, flags, p)))
                                goto error_exit;
-                       hfsmp->hfs_fs_clean = 1;
                        hfsmp->hfs_fs_ronly = 1;
-                       if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
-                               retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
-                       else
-                               retval = hfs_flushMDB(hfsmp, MNT_WAIT);
+                       retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
 
                        /* also get the volume bitmap blocks */
                        if (!retval)
                                retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p);
 
                        if (retval) {
-                               hfsmp->hfs_fs_clean = 0;
                                hfsmp->hfs_fs_ronly = 0;
                                goto error_exit;
                        }
@@ -303,23 +252,21 @@ hfs_mount (mp, path, data, ndp, p)
                                }
                                VOP_UNLOCK(devvp, 0, p);
                        }
-                       if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
-                               retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
-                       else
-                               retval = hfs_flushMDB(hfsmp, MNT_WAIT);
+                       retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
        
                        if (retval != E_NONE)
                                goto error_exit;
 
                        /* only change hfs_fs_ronly after a successfull write */
                        hfsmp->hfs_fs_ronly = 0;
-                       hfsmp->hfs_fs_clean = 0;
                }
 
                if ((hfsmp->hfs_fs_ronly == 0) &&
                    (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)) {
                        /* setup private/hidden directory for unlinked files */
                        hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(HFSTOVCB(hfsmp));
+                       if (hfsmp->jnl)
+                               hfs_remove_orphans(hfsmp);
                }
 
                if (args.fspec == 0) {
@@ -386,7 +333,6 @@ hfs_mount (mp, path, data, ndp, p)
                goto error_exit;
        }
 
-       
        /* Set the mount flag to indicate that we support volfs  */
        mp->mnt_flag |= MNT_DOVOLFS;
     if (VFSTOVCB(mp)->vcbSigWord == kHFSSigWord) {
@@ -394,6 +340,7 @@ hfs_mount (mp, path, data, ndp, p)
        mp->mnt_flag |= MNT_FIXEDSCRIPTENCODING;
     }
        (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);
@@ -406,23 +353,24 @@ error_exit:
 }
 
 
-/* change fs mount parameters */
-int
+/* Change fs mount parameters */
+static int
 hfs_changefs(mp, args, p)
        struct mount *mp;
        struct hfs_mount_args *args;
        struct proc *p;
 {
-       int retval;
+       int retval = 0;
        int namefix, permfix, permswitch;
        struct hfsmount *hfsmp;
-       struct hfsnode *hp;
-       mode_t hfs_file_mask;
+       struct cnode *cp;
        ExtendedVCB *vcb;
-       hfsCatalogInfo catInfo;
        register struct vnode *vp, *nvp;
        hfs_to_unicode_func_t   get_unicode_func;
        unicode_to_hfs_func_t   get_hfsname_func;
+       struct cat_desc cndesc;
+       struct cat_attr cnattr;
+       u_long old_encoding;
 
        hfsmp = VFSTOHFS(mp);
        vcb = HFSTOVCB(hfsmp);
@@ -436,19 +384,21 @@ hfs_changefs(mp, args, p)
        hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0);
        namefix =  permfix = 0;
 
-       /* change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */
+       /* Change the timezone (Note: this affects all hfs volumes and hfs+ volume create dates) */
        if (args->hfs_timezone.tz_minuteswest != VNOVAL) {
                gTimeZone = args->hfs_timezone;
        }
 
-       /* change the default uid, gid and/or mask */
+       /* Change the default uid, gid and/or mask */
        if ((args->hfs_uid != (uid_t)VNOVAL) && (hfsmp->hfs_uid != args->hfs_uid)) {
                hfsmp->hfs_uid = args->hfs_uid;
-               ++permfix;
+               if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
+                       ++permfix;
        }
        if ((args->hfs_gid != (gid_t)VNOVAL) && (hfsmp->hfs_gid != args->hfs_gid)) {
                hfsmp->hfs_gid = args->hfs_gid;
-               ++permfix;
+               if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
+                       ++permfix;
        }
        if (args->hfs_mask != (mode_t)VNOVAL) {
                if (hfsmp->hfs_dir_mask != (args->hfs_mask & ALLPERMS)) {
@@ -456,17 +406,19 @@ hfs_changefs(mp, args, p)
                        hfsmp->hfs_file_mask = args->hfs_mask & ALLPERMS;
                        if ((args->flags != VNOVAL) && (args->flags & HFSFSMNT_NOXONFILES))
                                hfsmp->hfs_file_mask = (args->hfs_mask & DEFFILEMODE);
-                       ++permfix;
+                       if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
+                               ++permfix;
                }
        }
        
-       /* change the hfs encoding value (hfs only) */
+       /* Change the hfs encoding value (hfs only) */
        if ((HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord)        &&
            (hfsmp->hfs_encoding != (u_long)VNOVAL)             &&
            (hfsmp->hfs_encoding != args->hfs_encoding)) {
 
                retval = hfs_getconverter(args->hfs_encoding, &get_unicode_func, &get_hfsname_func);
-               if (retval) goto error_exit;
+               if (retval)
+                       goto exit;
 
                /*
                 * Connect the new hfs_get_unicode converter but leave
@@ -479,11 +431,13 @@ hfs_changefs(mp, args, p)
                 * in the old converters.
                 */
                hfsmp->hfs_get_unicode = get_unicode_func;
+               old_encoding = hfsmp->hfs_encoding;
+               hfsmp->hfs_encoding = args->hfs_encoding;
                ++namefix;
        }
 
-
-       if (!(namefix || permfix || permswitch)) goto exit;
+       if (!(namefix || permfix || permswitch))
+               goto exit;
 
        /*
         * For each active vnode fix things that changed
@@ -516,12 +470,9 @@ loop:
                    continue;
                }
        
-               hp = VTOH(vp);
+               cp = VTOC(vp);
 
-               INIT_CATALOGDATA(&catInfo.nodeData, 0);
-               
-               catInfo.hint = kNoHint;
-               retval = hfs_getcatalog(vcb, H_DIRID(hp), H_NAME(hp), hp->h_meta->h_namelen, &catInfo);
+               retval = cat_lookup(hfsmp, &cp->c_desc, 0, &cndesc, &cnattr, NULL);
                /* If we couldn't find this guy skip to the next one */
                if (retval) {
                        if (namefix)
@@ -531,45 +482,11 @@ loop:
                        continue;
                }
 
-               H_HINT(hp) = catInfo.hint;
-               if (permswitch || (permfix && (hp->h_meta->h_metaflags & IN_UNSETACCESS))) {
-                       if ((vcb->vcbSigWord == kHFSPlusSigWord) && (catInfo.nodeData.cnd_mode & IFMT)) {
-                               if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
-                                       /*
-                                        *      Override the permissions as determined by the mount auguments
-                                        *  in ALMOST the same way unset permissions are treated but keep
-                                        *      track of whether or not the file or folder is hfs locked
-                                        *  by leaving the h_pflags field unchanged from what was unpacked
-                                        *  out of the catalog.
-                                        */ 
-                                       hp->h_meta->h_metaflags |= IN_UNSETACCESS;                      
-                                       hp->h_meta->h_uid = VTOHFS(vp)->hfs_uid;
-                                       hp->h_meta->h_gid = VTOHFS(vp)->hfs_gid;
-                               } else {
-                                       hp->h_meta->h_uid = catInfo.nodeData.cnd_ownerID;
-                                       hp->h_meta->h_gid = catInfo.nodeData.cnd_groupID;
-                               };
-                               hp->h_meta->h_mode = (mode_t)catInfo.nodeData.cnd_mode;
-                       } else {
-                               /*
-                                *      Set the permissions as determined by the mount auguments
-                                *      but keep in account if the file or folder is hfs locked
-                                */ 
-                               hp->h_meta->h_metaflags |= IN_UNSETACCESS;                      
-                               hp->h_meta->h_uid = VTOHFS(vp)->hfs_uid;
-                               hp->h_meta->h_gid = VTOHFS(vp)->hfs_gid;
-                                
-                               /* Default access is full read/write/execute: */
-                               hp->h_meta->h_mode &= IFMT;
-                               hp->h_meta->h_mode |= ACCESSPERMS;      /* 0777: rwxrwxrwx */
-                               /* ... but no more than that permitted by the mount point's: */
-                               if ((hp->h_meta->h_mode & IFMT) == IFDIR) {
-                                       hp->h_meta->h_mode &= IFMT | VTOHFS(vp)->hfs_dir_mask;
-                               } else {
-                                       hp->h_meta->h_mode &= IFMT | VTOHFS(vp)->hfs_file_mask;
-                               }
-                       };
-               };
+               if (permswitch || permfix) {
+                       cp->c_uid = cnattr.ca_uid;
+                       cp->c_gid = cnattr.ca_gid;
+                       cp->c_mode = cnattr.ca_mode;
+               }
                
                /*
                 * If we're switching name converters then...
@@ -578,41 +495,31 @@ loop:
                 */
                if (namefix) {
                        cache_purge(vp);
-                       hfs_name_CatToMeta(&catInfo.nodeData, hp->h_meta);
+                       replace_desc(cp, &cndesc);
 
-                       if (catInfo.nodeData.cnd_nodeID == kHFSRootFolderID)
-                               strncpy(vcb->vcbVN, H_NAME(hp), NAME_MAX);
+                       if (cndesc.cd_cnid == kHFSRootFolderID) {
+                               strncpy(vcb->vcbVN, cp->c_desc.cd_nameptr, NAME_MAX);
+                               cp->c_desc.cd_encoding = hfsmp->hfs_encoding;
+                       }
+               } else {
+                       cat_releasedesc(&cndesc);
                }
-
-               CLEAN_CATALOGDATA(&catInfo.nodeData);
-
                vput(vp);
                simple_lock(&mntvnode_slock);
 
-               } /* end for (vp...) */
-               simple_unlock(&mntvnode_slock);
-
-
-exit:  
+       } /* end for (vp...) */
+       simple_unlock(&mntvnode_slock);
        /*
         * If we're switching name converters we can now
         * connect the new hfs_get_hfsname converter and
         * release our interest in the old converters.
         */
        if (namefix) {
-               u_long old_encoding = hfsmp->hfs_encoding;
-
                hfsmp->hfs_get_hfsname = get_hfsname_func;
-               hfsmp->hfs_encoding = args->hfs_encoding;
                vcb->volumeNameEncodingHint = args->hfs_encoding;
-
                (void) hfs_relconverter(old_encoding);
        }
-
-       return (0);
-
-error_exit:
-
+exit:
        return (retval);
 }
 
@@ -623,28 +530,30 @@ error_exit:
  * be mounted read-only.
  *
  * Things to do to update the mount:
- *     1) invalidate all cached meta-data.
- *     2) re-read volume header from disk.
- *     3) re-load meta-file info (extents, file size).
- *     4) re-load B-tree header data.
- *     5) invalidate all inactive vnodes.
- *     6) invalidate all cached file data.
- *     7) re-read hfsnode data for all active vnodes.
+ *     invalidate all cached meta-data.
+ *     invalidate all inactive vnodes.
+ *     invalidate all cached file data.
+ *     re-read volume header from disk.
+ *     re-load meta-file info (extents, file size).
+ *     re-load B-tree header data.
+ *     re-read cnode data for all active vnodes.
  */
-int
+static int
 hfs_reload(mountp, cred, p)
        register struct mount *mountp;
        struct ucred *cred;
        struct proc *p;
 {
        register struct vnode *vp, *nvp, *devvp;
-       struct hfsnode *hp;
+       struct cnode *cp;
        struct buf *bp;
-       int     size, error, i;
+       int sectorsize;
+       int error, i;
        struct hfsmount *hfsmp;
        struct HFSPlusVolumeHeader *vhp;
        ExtendedVCB *vcb;
-       FCB *fcb;
+       struct filefork *forkp;
+       struct cat_desc cndesc;
 
        if ((mountp->mnt_flag & MNT_RDONLY) == 0)
                return (EINVAL);
@@ -663,41 +572,93 @@ hfs_reload(mountp, cred, p)
                panic("hfs_reload: dirty1");
        InvalidateCatalogCache(vcb);
 
+loop:
+       simple_lock(&mntvnode_slock);
+       for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
+               if (vp->v_mount != mountp) {
+                       simple_unlock(&mntvnode_slock);
+                       goto loop;
+               }
+               nvp = vp->v_mntvnodes.le_next;
+
+               /*
+                * Invalidate all inactive vnodes.
+                */
+               if (vrecycle(vp, &mntvnode_slock, p))
+                       goto loop;
+
+               /*
+                * Invalidate all cached file data.
+                */
+               simple_lock(&vp->v_interlock);
+               simple_unlock(&mntvnode_slock);
+               if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
+                       goto loop;
+               }
+               if (vinvalbuf(vp, 0, cred, p, 0, 0))
+                       panic("hfs_reload: dirty2");
+
+               /*
+                * Re-read cnode data for all active vnodes (non-metadata files).
+                */
+               cp = VTOC(vp);
+               if ((vp->v_flag & VSYSTEM) == 0 && !VNODE_IS_RSRC(vp)) {
+                       struct cat_fork *datafork;
+                       struct cat_desc desc;
+
+                       datafork = cp->c_datafork ? &cp->c_datafork->ff_data : NULL;
+
+                       /* lookup by fileID since name could have changed */
+                       if ((error = cat_idlookup(hfsmp, cp->c_fileid, &desc, &cp->c_attr, datafork))) {
+                               vput(vp);
+                               return (error);
+                       }
+
+
+                       /* update cnode's catalog descriptor */
+                       (void) replace_desc(cp, &desc);
+               }
+               vput(vp);
+               simple_lock(&mntvnode_slock);
+       }
+       simple_unlock(&mntvnode_slock);
+
        /*
         * Re-read VolumeHeader from disk.
         */
-       size = kMDBSize;
-       error = bread(  hfsmp->hfs_devvp,
-                       IOBLKNOFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size),
-                       IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size),
-                       NOCRED,
-                       &bp);
+       sectorsize = hfsmp->hfs_phys_block_size;
+
+       error = meta_bread(hfsmp->hfs_devvp,
+                       (vcb->hfsPlusIOPosOffset / sectorsize) + HFS_PRI_SECTOR(sectorsize),
+                       sectorsize, NOCRED, &bp);
        if (error) {
                if (bp != NULL)
                        brelse(bp);
                return (error);
        }
 
-       vhp = (HFSPlusVolumeHeader *) ((char *)bp->b_data +
-                       IOBYTEOFFSETFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size));
+       vhp = (HFSPlusVolumeHeader *) (bp->b_data + HFS_PRI_OFFSET(sectorsize));
 
-       if ((ValidVolumeHeader(vhp) != 0) || (vcb->blockSize != SWAP_BE32 (vhp->blockSize))) {
+       /* Do a quick sanity check */
+       if (SWAP_BE16(vhp->signature) != kHFSPlusSigWord ||
+           SWAP_BE16(vhp->version) != kHFSPlusVersion   ||
+           SWAP_BE32(vhp->blockSize) != vcb->blockSize) {
                brelse(bp);
-               return (EIO);           /* XXX needs translation */
+               return (EIO);
        }
 
-       vcb->vcbLsMod                   = SWAP_BE32 (vhp->modifyDate);
-       vcb->vcbAtrb                    = (UInt16) SWAP_BE32 (vhp->attributes); /* VCB only uses lower 16 bits */
-       vcb->vcbClpSiz                  = SWAP_BE32 (vhp->rsrcClumpSize);
-       vcb->vcbNxtCNID                 = SWAP_BE32 (vhp->nextCatalogID);
-       vcb->vcbVolBkUp                 = SWAP_BE32 (vhp->backupDate);
-       vcb->vcbWrCnt                   = SWAP_BE32 (vhp->writeCount);
-       vcb->vcbFilCnt                  = SWAP_BE32 (vhp->fileCount);
-       vcb->vcbDirCnt                  = SWAP_BE32 (vhp->folderCount);
+       vcb->vcbLsMod           = to_bsd_time(SWAP_BE32(vhp->modifyDate));
+       vcb->vcbAtrb            = (UInt16) SWAP_BE32 (vhp->attributes); /* VCB only uses lower 16 bits */
+       vcb->vcbJinfoBlock  = SWAP_BE32(vhp->journalInfoBlock);
+       vcb->vcbClpSiz          = SWAP_BE32 (vhp->rsrcClumpSize);
+       vcb->vcbNxtCNID         = SWAP_BE32 (vhp->nextCatalogID);
+       vcb->vcbVolBkUp         = to_bsd_time(SWAP_BE32(vhp->backupDate));
+       vcb->vcbWrCnt           = SWAP_BE32 (vhp->writeCount);
+       vcb->vcbFilCnt          = SWAP_BE32 (vhp->fileCount);
+       vcb->vcbDirCnt          = SWAP_BE32 (vhp->folderCount);
        vcb->nextAllocation     = SWAP_BE32 (vhp->nextAllocation);
-       vcb->totalBlocks                = SWAP_BE32 (vhp->totalBlocks);
-       vcb->freeBlocks                 = SWAP_BE32 (vhp->freeBlocks);
-       vcb->checkedDate                = SWAP_BE32 (vhp->checkedDate);
+       vcb->totalBlocks        = SWAP_BE32 (vhp->totalBlocks);
+       vcb->freeBlocks         = SWAP_BE32 (vhp->freeBlocks);
        vcb->encodingsBitmap    = SWAP_BE64 (vhp->encodingsBitmap);
        bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo));    
        vcb->localCreateDate    = SWAP_BE32 (vhp->createDate); /* hfs+ create date is in local time */ 
@@ -705,35 +666,40 @@ hfs_reload(mountp, cred, p)
        /*
         * Re-load meta-file vnode data (extent info, file size, etc).
         */
-       fcb = VTOFCB((struct vnode *)vcb->extentsRefNum);
-       /* bcopy(vhp->extentsFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
-    for (i = 0; i < kHFSPlusExtentDensity; i++) {
-        fcb->fcbExtents[i].startBlock  = SWAP_BE32 (vhp->extentsFile.extents[i].startBlock);
-        fcb->fcbExtents[i].blockCount  = SWAP_BE32 (vhp->extentsFile.extents[i].blockCount);
-    }
-       fcb->fcbEOF                     = SWAP_BE64 (vhp->extentsFile.logicalSize);
-       fcb->fcbPLen            = SWAP_BE32 (vhp->extentsFile.totalBlocks) * vcb->blockSize;
-       fcb->fcbClmpSize        = SWAP_BE32 (vhp->extentsFile.clumpSize);
-
-       fcb = VTOFCB((struct vnode *)vcb->catalogRefNum);
-       /* bcopy(vhp->catalogFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
-    for (i = 0; i < kHFSPlusExtentDensity; i++) {
-        fcb->fcbExtents[i].startBlock  = SWAP_BE32 (vhp->catalogFile.extents[i].startBlock);
-        fcb->fcbExtents[i].blockCount  = SWAP_BE32 (vhp->catalogFile.extents[i].blockCount);
-    }
-       fcb->fcbPLen            = SWAP_BE64 (vhp->catalogFile.logicalSize);
-       fcb->fcbPLen            = SWAP_BE32 (vhp->catalogFile.totalBlocks) * vcb->blockSize;
-       fcb->fcbClmpSize        = SWAP_BE32 (vhp->catalogFile.clumpSize);
-
-       fcb = VTOFCB((struct vnode *)vcb->allocationsRefNum);
-       /* bcopy(vhp->allocationFile.extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); */
-    for (i = 0; i < kHFSPlusExtentDensity; i++) {
-        fcb->fcbExtents[i].startBlock  = SWAP_BE32 (vhp->allocationFile.extents[i].startBlock);
-        fcb->fcbExtents[i].blockCount  = SWAP_BE32 (vhp->allocationFile.extents[i].blockCount);
-    }
-       fcb->fcbEOF                     = SWAP_BE64 (vhp->allocationFile.logicalSize);
-       fcb->fcbPLen            = SWAP_BE32 (vhp->allocationFile.totalBlocks) * vcb->blockSize;
-       fcb->fcbClmpSize        = SWAP_BE32 (vhp->allocationFile.clumpSize);
+       forkp = VTOF((struct vnode *)vcb->extentsRefNum);
+       for (i = 0; i < kHFSPlusExtentDensity; i++) {
+               forkp->ff_extents[i].startBlock =
+                       SWAP_BE32 (vhp->extentsFile.extents[i].startBlock);
+               forkp->ff_extents[i].blockCount =
+                       SWAP_BE32 (vhp->extentsFile.extents[i].blockCount);
+       }
+       forkp->ff_size      = SWAP_BE64 (vhp->extentsFile.logicalSize);
+       forkp->ff_blocks    = SWAP_BE32 (vhp->extentsFile.totalBlocks);
+       forkp->ff_clumpsize = SWAP_BE32 (vhp->extentsFile.clumpSize);
+
+
+       forkp = VTOF((struct vnode *)vcb->catalogRefNum);
+       for (i = 0; i < kHFSPlusExtentDensity; i++) {
+               forkp->ff_extents[i].startBlock =
+                       SWAP_BE32 (vhp->catalogFile.extents[i].startBlock);
+               forkp->ff_extents[i].blockCount =
+                       SWAP_BE32 (vhp->catalogFile.extents[i].blockCount);
+       }
+       forkp->ff_size      = SWAP_BE64 (vhp->catalogFile.logicalSize);
+       forkp->ff_blocks    = SWAP_BE32 (vhp->catalogFile.totalBlocks);
+       forkp->ff_clumpsize = SWAP_BE32 (vhp->catalogFile.clumpSize);
+
+
+       forkp = VTOF((struct vnode *)vcb->allocationsRefNum);
+       for (i = 0; i < kHFSPlusExtentDensity; i++) {
+               forkp->ff_extents[i].startBlock =
+                       SWAP_BE32 (vhp->allocationFile.extents[i].startBlock);
+               forkp->ff_extents[i].blockCount =
+                       SWAP_BE32 (vhp->allocationFile.extents[i].blockCount);
+       }
+       forkp->ff_size      = SWAP_BE64 (vhp->allocationFile.logicalSize);
+       forkp->ff_blocks    = SWAP_BE32 (vhp->allocationFile.totalBlocks);
+       forkp->ff_clumpsize = SWAP_BE32 (vhp->allocationFile.clumpSize);
 
        brelse(bp);
        vhp = NULL;
@@ -741,104 +707,132 @@ hfs_reload(mountp, cred, p)
        /*
         * Re-load B-tree header data
         */
-       fcb = VTOFCB((struct vnode *)vcb->extentsRefNum);
-       if (error = MacToVFSError( BTReloadData(fcb) ))
+       forkp = VTOF((struct vnode *)vcb->extentsRefNum);
+       if (error = MacToVFSError( BTReloadData((FCB*)forkp) ))
                return (error);
 
-       fcb = VTOFCB((struct vnode *)vcb->catalogRefNum);
-       if (error = MacToVFSError( BTReloadData(fcb) ))
+       forkp = VTOF((struct vnode *)vcb->catalogRefNum);
+       if (error = MacToVFSError( BTReloadData((FCB*)forkp) ))
                return (error);
 
-       /* Now that the catalog is ready, get the volume name */
-       /* also picks up the create date in GMT */
-       if ((error = MacToVFSError( GetVolumeNameFromCatalog(vcb) )))
+       /* Reload the volume name */
+       if ((error = cat_idlookup(hfsmp, kHFSRootFolderID, &cndesc, NULL, NULL)))
                return (error);
+       vcb->volumeNameEncodingHint = cndesc.cd_encoding;
+       bcopy(cndesc.cd_nameptr, vcb->vcbVN, min(255, cndesc.cd_namelen));
+       cat_releasedesc(&cndesc);
 
        /* Re-establish private/hidden directory for unlinked files */
        hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb);
 
-loop:
-       simple_lock(&mntvnode_slock);
-       for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
-               if (vp->v_mount != mountp) {
-                       simple_unlock(&mntvnode_slock);
-                       goto loop;
-               }
-               nvp = vp->v_mntvnodes.le_next;
+       return (0);
+}
 
-               /*
-                * Invalidate all inactive vnodes.
-                */
-               if (vrecycle(vp, &mntvnode_slock, p))
-                       goto loop;
 
-               /*
-                * Invalidate all cached file data.
-                */
-               simple_lock(&vp->v_interlock);
-               simple_unlock(&mntvnode_slock);
-               if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
-                       goto loop;
-               }
-               if (vinvalbuf(vp, 0, cred, p, 0, 0))
-                       panic("hfs_reload: dirty2");
+static int
+get_raw_device(char *fspec, int is_user, int ronly, struct vnode **rvp, struct ucred *cred, struct proc *p)
+{
+       char            *rawbuf;
+       char            *dp;
+       size_t           namelen;
+       struct nameidata nd;
+       int               retval;
 
-               /*
-                * Re-read hfsnode data for all active vnodes (non-metadata files).
-                */
-               hp = VTOH(vp);
-               if ((vp->v_flag & VSYSTEM) == 0) {
-                       hfsCatalogInfo catInfo;
+       *rvp = NULL;
 
-                       /* lookup by fileID since name could have changed */
-                       catInfo.hint = kNoHint;
-                       INIT_CATALOGDATA(&catInfo.nodeData, 0);
+       MALLOC(rawbuf, char *, MAXPATHLEN, M_HFSMNT, M_WAITOK);
+       if (rawbuf == NULL) {
+               retval = ENOMEM;
+               goto error_exit;
+       }
 
-                       if ((error = hfs_getcatalog(vcb, H_FILEID(hp), NULL, -1, &catInfo))) {
-                               vput(vp);
-                               CLEAN_CATALOGDATA(&catInfo.nodeData);
-                               return (error);
-                       }
+       if (is_user) {
+               retval = copyinstr(fspec, rawbuf, MAXPATHLEN - 1, &namelen);
+               if (retval != E_NONE) {
+                       FREE(rawbuf, M_HFSMNT);
+                       goto error_exit;
+               }
+       } else {
+               strcpy(rawbuf, fspec);
+               namelen = strlen(rawbuf);
+       }
+
+       /* make sure it's null terminated */
+       rawbuf[MAXPATHLEN-1] = '\0';   
 
-                       H_HINT(hp) = catInfo.hint;
-            if (hp->h_meta->h_metaflags & IN_LONGNAME)
-                               FREE(H_NAME(hp), M_TEMP);
-                       H_NAME(hp) = NULL;
-            hp->h_meta->h_namelen = 0;
-                       CopyCatalogToObjectMeta(&catInfo, vp, hp->h_meta);
-                       CopyCatalogToFCB(&catInfo, vp);
+       dp = &rawbuf[namelen-1];
+       while(dp >= rawbuf && *dp != '/') {
+               dp--;
+       }
                        
-                       CLEAN_CATALOGDATA(&catInfo.nodeData);
-               }
+       if (dp != NULL) {
+               dp++;
+       } else {
+               dp = rawbuf;
+       }
+                       
+       /* make room for and insert the 'r' for the raw device */
+       memmove(dp+1, dp, strlen(dp)+1);
+       *dp = 'r';
 
-               vput(vp);
-               simple_lock(&mntvnode_slock);
+       NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, rawbuf, p);
+       retval = namei(&nd);
+       if (retval != E_NONE) {
+               DBG_ERR(("hfs_mountfs: can't open raw device for journal: %s, %x\n", rawbuf, nd.ni_vp->v_rdev));
+               FREE(rawbuf, M_HFSMNT);
+               goto error_exit;
        }
-       simple_unlock(&mntvnode_slock);
 
-       return (0);
+       *rvp = nd.ni_vp;
+       if ((retval = VOP_OPEN(*rvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))) {
+               *rvp = NULL;
+               goto error_exit;
+       }
+
+       // don't need this any more
+       FREE(rawbuf, M_HFSMNT);
+
+       return 0;
+
+  error_exit:
+       if (*rvp) {
+           (void)VOP_CLOSE(*rvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
+       }
+
+       if (rawbuf) {
+               FREE(rawbuf, M_HFSMNT);
+       }
+       return retval;
 }
 
 
+
 /*
  * Common code for mount and mountroot
  */
-int
-hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mount_args *args)
+static int
+hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p,
+       struct hfs_mount_args *args)
 {
-    int                         retval = E_NONE;
-    register struct hfsmount   *hfsmp;
-    struct buf                                 *bp;
-    dev_t                       dev;
-    HFSMasterDirectoryBlock            *mdbp;
-    int                         ronly;
-    struct ucred                               *cred;
-       u_long diskBlks;
-       u_long blksize;
-    DBG_VFS(("hfs_mountfs: mp = 0x%lX\n", (u_long)mp));
-
-    dev = devvp->v_rdev;
-    cred = p ? p->p_ucred : NOCRED;
+       int retval = E_NONE;
+       struct hfsmount *hfsmp;
+       struct buf *bp;
+       dev_t dev;
+       HFSMasterDirectoryBlock *mdbp;
+       int ronly;
+       int i;
+       int mntwrapper;
+       struct ucred *cred;
+       u_int64_t disksize;
+       u_int64_t blkcnt;
+       u_int32_t blksize;
+       u_int32_t minblksize;
+       u_int32_t iswritable;
+       daddr_t   mdb_offset;
+
+       dev = devvp->v_rdev;
+       cred = p ? p->p_ucred : NOCRED;
+       mntwrapper = 0;
     /*
      * Disallow multiple mounts of the same device.
      * Disallow mounting of a device that is currently in use
@@ -853,29 +847,63 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo
         return (retval);
 
     ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
-    DBG_VFS(("hfs_mountfs: opening device...\n"));
     if ((retval = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)))
         return (retval);
 
-    blksize = kHFSBlockSize;
-    DBG_VFS(("hfs_mountfs: size = %d (DEV_BSIZE = %d).\n", blksize, DEV_BSIZE));
+       bp = NULL;
+       hfsmp = NULL;
+       mdbp = NULL;
+       minblksize = kHFSBlockSize;
+
+       /* Get the real physical block size. */
+       if (VOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, (caddr_t)&blksize, 0, cred, p)) {
+               retval = ENXIO;
+               goto error_exit;
+       }
+       /* Switch to 512 byte sectors (temporarily) */
+       if (blksize > 512) {
+               u_int32_t size512 = 512;
 
-    bp = NULL;
-    hfsmp = NULL;
+               if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&size512, FWRITE, cred, p)) {
+                       retval = ENXIO;
+                       goto error_exit;
+               }
+       }
+       /* Get the number of 512 byte physical blocks. */
+       if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
+               retval = ENXIO;
+               goto error_exit;
+       }
+       /* Compute an accurate disk size (i.e. within 512 bytes) */
+       disksize = blkcnt * (u_int64_t)512;
 
-       /*      
-        * XXX SER Currently we only support 512 block size systems. This might change
-        * So this is a place holder to remind us that the mdb might not be 512 aligned
-        * retval = VOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, &blksize, FWRITE, cred, p);
-        * if (retval) return retval;
+       /*
+        * There are only 31 bits worth of block count in
+        * the buffer cache.  So for large volumes a 4K
+        * physical block size is needed.
         */
+       if (blkcnt > (u_int64_t)0x000000007fffffff) {
+               minblksize = blksize = 4096;
+       }
+       /* Now switch to our prefered physical block size. */
+       if (blksize > 512) {
+               if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, cred, p)) {
+                       retval = ENXIO;
+                       goto error_exit;
+               }
+               /* Get the count of physical blocks. */
+               if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
+                       retval = ENXIO;
+                       goto error_exit;
+               }
+       }
 
-    /*
-        * the next three lines should probably be replaced
-        * with a call to the yet unimplemented function VOP_SETBLOCKSIZE
+       /*
+        * At this point:
+        *   minblksize is the minimum physical block size
+        *   blksize has our prefered physical block size
+        *   blkcnt has the total number of physical blocks
         */
-       retval = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, &blksize, FWRITE, cred, p);
-       if (retval) return retval;
        devvp->v_specsize = blksize;
 
        /* cache the IO attributes */
@@ -885,37 +913,36 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo
                return (retval);
        }
 
-    DBG_VFS(("hfs_mountfs: reading MDB [block no. %d + %d bytes, size %d bytes]...\n",
-             IOBLKNOFORBLK(kMasterDirectoryBlock, blksize),
-             IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize),
-             IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, blksize)));
-
-    if ((retval = bread(devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, blksize),
-                                                  IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, blksize), cred, &bp))) {
-        goto error_exit;
-       };
-    mdbp = (HFSMasterDirectoryBlock*) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize));
+       mdb_offset = HFS_PRI_SECTOR(blksize);
+       if ((retval = meta_bread(devvp, HFS_PRI_SECTOR(blksize), blksize, cred, &bp))) {
+               goto error_exit;
+       }
+       MALLOC(mdbp, HFSMasterDirectoryBlock *, kMDBSize, M_TEMP, M_WAITOK);
+       bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, kMDBSize);
+       brelse(bp);
+       bp = NULL;
 
-    MALLOC(hfsmp, struct hfsmount *, sizeof(struct hfsmount), M_HFSMNT, M_WAITOK);
-    bzero(hfsmp, sizeof(struct hfsmount));
+       MALLOC(hfsmp, struct hfsmount *, sizeof(struct hfsmount), M_HFSMNT, M_WAITOK);
+       bzero(hfsmp, sizeof(struct hfsmount));
 
        simple_lock_init(&hfsmp->hfs_renamelock);
+       
+       /*
+       *  Init the volume information structure
+       */
+       mp->mnt_data = (qaddr_t)hfsmp;
+       hfsmp->hfs_mp = mp;                     /* Make VFSTOHFS work */
+       hfsmp->hfs_vcb.vcb_hfsmp = hfsmp;       /* Make VCBTOHFS work */
+       hfsmp->hfs_raw_dev = devvp->v_rdev;
+       hfsmp->hfs_devvp = devvp;
+       hfsmp->hfs_phys_block_size = blksize;
+       hfsmp->hfs_phys_block_count = blkcnt;
+       hfsmp->hfs_media_writeable = 1;
+       hfsmp->hfs_fs_ronly = ronly;
+       hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0);
+       for (i = 0; i < MAXQUOTAS; i++)
+               hfsmp->hfs_qfiles[i].qf_vp = NULLVP;
 
-    DBG_VFS(("hfs_mountfs: Initializing hfsmount structure at 0x%lX...\n", (u_long)hfsmp));
-    /*
-     *  Init the volume information structure
-     */
-    mp->mnt_data = (qaddr_t)hfsmp;
-    hfsmp->hfs_mp = mp;                                                /* Make VFSTOHFS work */
-    hfsmp->hfs_vcb.vcb_hfsmp = hfsmp;          /* Make VCBTOHFS work */
-    hfsmp->hfs_raw_dev = devvp->v_rdev;
-    hfsmp->hfs_devvp = devvp;
-    hfsmp->hfs_phys_block_size = blksize;
-    
-    /* The hfs_log_block_size field is updated in the respective hfs_MountHFS[Plus]Volume routine */
-    hfsmp->hfs_logBlockSize = BestBlockSizeFit(SWAP_BE32 (mdbp->drAlBlkSiz), MAXBSIZE, hfsmp->hfs_phys_block_size);
-    hfsmp->hfs_fs_ronly = ronly;
-    hfsmp->hfs_unknownpermissions = ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) != 0);
        if (args) {
                hfsmp->hfs_uid = (args->hfs_uid == (uid_t)VNOVAL) ? UNKNOWNUID : args->hfs_uid;
                if (hfsmp->hfs_uid == 0xfffffffd) hfsmp->hfs_uid = UNKNOWNUID;
@@ -931,7 +958,9 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo
                } else {
                        hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS;            /* 0777: rwx---rwx */
                        hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE;        /* 0666: no --x by default? */
-               };
+               }
+               if ((args->flags != (int)VNOVAL) && (args->flags & HFSFSMNT_WRAPPER))
+                       mntwrapper = 1;
        } else {
                /* Even w/o explicit mount arguments, MNT_UNKNOWNPERMISSIONS requires setting up uid, gid, and mask: */
                if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
@@ -939,118 +968,208 @@ hfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p, struct hfs_mo
                        hfsmp->hfs_gid = UNKNOWNGID;
                        hfsmp->hfs_dir_mask = UNKNOWNPERMISSIONS & ALLPERMS;            /* 0777: rwx---rwx */
                        hfsmp->hfs_file_mask = UNKNOWNPERMISSIONS & DEFFILEMODE;        /* 0666: no --x by default? */
-               };
-       };
-       
-       /*      See above comment for DKIOCGETBLOCKSIZE
-        * retval = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, &blksize, FWRITE, cred, p);
-        * if (retval) return retval;
-        */
-
-       retval = VOP_IOCTL(devvp, DKIOCNUMBLKS, (caddr_t)&diskBlks, 0, cred, p);
-       if (retval) return retval;
-
-       if (SWAP_BE16 (mdbp->drSigWord) == kHFSPlusSigWord) {
-        /* Enidan swap volume header in place */
-        /* SWAP_HFS_PLUS_VOLUME_HEADER ((HFSPlusVolumeHeader *)bp->b_data); */
-
-               /* mount wrapper-less HFS-Plus volume */
-               (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
-               retval = hfs_MountHFSPlusVolume(hfsmp, (HFSPlusVolumeHeader*) bp->b_data, 0, diskBlks, p);
-
-        /* Enidan un-swap volume header in place */
-        /* SWAP_HFS_PLUS_VOLUME_HEADER ((HFSPlusVolumeHeader *)bp->b_data); */
-
-       } else if (SWAP_BE16 (mdbp->drEmbedSigWord) == kHFSPlusSigWord) {
-               u_long embBlkOffset;
-               HFSPlusVolumeHeader     *vhp;
+               }
+       }
 
-               embBlkOffset = SWAP_BE16 (mdbp->drAlBlSt) +
-                   (SWAP_BE16 (mdbp->drEmbedExtent.startBlock) * (SWAP_BE32 (mdbp->drAlBlkSiz)/kHFSBlockSize));
-               /* calculate virtual number of 512-byte sectors */
-               diskBlks = SWAP_BE16 (mdbp->drEmbedExtent.blockCount) * (SWAP_BE32 (mdbp->drAlBlkSiz)/kHFSBlockSize);
+       /* Find out if disk media is writable. */
+       if (VOP_IOCTL(devvp, DKIOCISWRITABLE, (caddr_t)&iswritable, 0, cred, p) == 0) {
+               if (iswritable)
+                       hfsmp->hfs_media_writeable = 1;
+               else
+                       hfsmp->hfs_media_writeable = 0;
+       }
 
-               brelse(bp);
-               bp = NULL;              /* done with MDB, go grab Volume Header */
-               mdbp = NULL;
-
-               retval = bread( devvp,
-                               IOBLKNOFORBLK(kMasterDirectoryBlock+embBlkOffset, blksize),
-                               IOBYTECCNTFORBLK(kMasterDirectoryBlock+embBlkOffset, kMDBSize, blksize),
-                               cred,
-                               &bp);
-               if (retval) {
+       /* Mount a standard HFS disk */
+       if ((SWAP_BE16(mdbp->drSigWord) == kHFSSigWord) &&
+           (mntwrapper || (SWAP_BE16(mdbp->drEmbedSigWord) != kHFSPlusSigWord))) {
+               if (devvp == rootvp) {
+                       retval = EINVAL;  /* Cannot root from HFS standard disks */
                        goto error_exit;
-               };
-               vhp = (HFSPlusVolumeHeader*) ((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, blksize));
-
-        /* Enidan swap volume header in place */
-        /* SWAP_HFS_PLUS_VOLUME_HEADER (vhp); */
-
-               /* mount embedded HFS Plus volume */
-               (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
-               retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embBlkOffset, diskBlks, p);
-
-        /* Enidan un-swap volume header in place */
-        /* SWAP_HFS_PLUS_VOLUME_HEADER (vhp); */
-
-       } else if (devvp != rootvp) {
+               }
+               /* HFS disks can only use 512 byte physical blocks */
+               if (blksize > kHFSBlockSize) {
+                       blksize = kHFSBlockSize;
+                       if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, cred, p)) {
+                               retval = ENXIO;
+                               goto error_exit;
+                       }
+                       if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
+                               retval = ENXIO;
+                               goto error_exit;
+                       }
+                       devvp->v_specsize = blksize;
+                       hfsmp->hfs_phys_block_size = blksize;
+                       hfsmp->hfs_phys_block_count = blkcnt;
+               }
                if (args) {
                        hfsmp->hfs_encoding = args->hfs_encoding;
                        HFSTOVCB(hfsmp)->volumeNameEncodingHint = args->hfs_encoding;
 
-
                        /* establish the timezone */
                        gTimeZone = args->hfs_timezone;
                }
 
-               retval = hfs_getconverter(hfsmp->hfs_encoding, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
-               if (retval) goto error_exit;
+               retval = hfs_getconverter(hfsmp->hfs_encoding, &hfsmp->hfs_get_unicode,
+                                       &hfsmp->hfs_get_hfsname);
+               if (retval)
+                       goto error_exit;
 
-               /* mount HFS volume */
-               retval = hfs_MountHFSVolume( hfsmp, mdbp, diskBlks, p);
-               
+               retval = hfs_MountHFSVolume(hfsmp, mdbp, p);
                if (retval)
                        (void) hfs_relconverter(hfsmp->hfs_encoding);
 
-       } else {
-               /* sorry, we cannot root from HFS */
-               retval = EINVAL;
-    }
-
-       if ( retval ) {
-               goto error_exit;
-       }
-
-    brelse(bp);
-    bp = NULL;
+       } else /* Mount an HFS Plus disk */ {
+               HFSPlusVolumeHeader *vhp;
+               off_t embeddedOffset;
+               int   jnl_disable = 0;
        
-    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;
-    devvp->v_specflags |= SI_MOUNTEDON;
-
-    if (ronly == 0) {
-        hfsmp->hfs_fs_clean = 0;
-        if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
-               (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT);
-        else
-               (void) hfs_flushMDB(hfsmp, MNT_WAIT);
-    }
-    goto std_exit;
+               /* Get the embedded Volume Header */
+               if (SWAP_BE16(mdbp->drEmbedSigWord) == kHFSPlusSigWord) {
+                       embeddedOffset = SWAP_BE16(mdbp->drAlBlSt) * kHFSBlockSize;
+                       embeddedOffset += (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.startBlock) *
+                                         (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
 
-error_exit:
-        DBG_VFS(("hfs_mountfs: exiting with error %d...\n", retval));
-
-    if (bp)
-        brelse(bp);
-    (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
-    if (hfsmp) {
-        FREE(hfsmp, M_HFSMNT);
-        mp->mnt_data = (qaddr_t)0;
-    }
+                       /*
+                        * If the embedded volume doesn't start on a block
+                        * boundary, then switch the device to a 512-byte
+                        * block size so everything will line up on a block
+                        * boundary.
+                        */
+                       if ((embeddedOffset % blksize) != 0) {
+                               printf("HFS Mount: embedded volume offset not"
+                                   " a multiple of physical block size (%d);"
+                                   " switching to 512\n", blksize);
+                               blksize = 512;
+                               if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
+                                   (caddr_t)&blksize, FWRITE, cred, p)) {
+                                       retval = ENXIO;
+                                       goto error_exit;
+                               }
+                               if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT,
+                                   (caddr_t)&blkcnt, 0, cred, p)) {
+                                       retval = ENXIO;
+                                       goto error_exit;
+                               }
+                               /* XXX do we need to call vfs_init_io_attributes again? */
+                               devvp->v_specsize = blksize;
+                               /* Note: relative block count adjustment */
+                               hfsmp->hfs_phys_block_count *=
+                                   hfsmp->hfs_phys_block_size / blksize;
+                               hfsmp->hfs_phys_block_size = blksize;
+                       }
+
+                       disksize = (u_int64_t)SWAP_BE16(mdbp->drEmbedExtent.blockCount) *
+                                  (u_int64_t)SWAP_BE32(mdbp->drAlBlkSiz);
+
+                       hfsmp->hfs_phys_block_count = disksize / blksize;
+       
+                       mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
+                       retval = meta_bread(devvp, mdb_offset, blksize, cred, &bp);
+                       if (retval)
+                               goto error_exit;
+                       bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, 512);
+                       brelse(bp);
+                       bp = NULL;
+                       vhp = (HFSPlusVolumeHeader*) mdbp;
+
+               } else /* pure HFS+ */ {
+                       embeddedOffset = 0;
+                       vhp = (HFSPlusVolumeHeader*) mdbp;
+               }
+
+               // XXXdbg
+               //
+               hfsmp->jnl = NULL;
+               hfsmp->jvp = NULL;
+               if (args != NULL && (args->flags & HFSFSMNT_EXTENDED_ARGS) && args->journal_disable) {
+                   jnl_disable = 1;
+               }
+                               
+               //
+               // We only initialize the journal here if the last person
+               // to mount this volume was journaling aware.  Otherwise
+               // we delay journal initialization until later at the end
+               // of hfs_MountHFSPlusVolume() because the last person who
+               // mounted it could have messed things up behind our back
+               // (so we need to go find the .journal file, make sure it's
+               // the right size, re-sync up if it was moved, etc).
+               //
+               if (   (SWAP_BE32(vhp->lastMountedVersion) == kHFSJMountVersion)
+                       && (SWAP_BE32(vhp->attributes) & kHFSVolumeJournaledMask)
+                       && !jnl_disable) {
+                       
+                       // if we're able to init the journal, mark the mount
+                       // point as journaled.
+                       //
+                       if (hfs_early_journal_init(hfsmp, vhp, args, embeddedOffset, mdb_offset, mdbp, cred) == 0) {
+                               mp->mnt_flag |= MNT_JOURNALED;
+                       } else {
+                               retval = EINVAL;
+                               goto error_exit;
+                       }
+               }
+               // XXXdbg
+       
+               (void) hfs_getconverter(0, &hfsmp->hfs_get_unicode, &hfsmp->hfs_get_hfsname);
+
+               retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embeddedOffset, disksize, p, args);
+               /*
+                * If the backend didn't like our physical blocksize
+                * then retry with physical blocksize of 512.
+                */
+               if ((retval == ENXIO) && (blksize > 512) && (blksize != minblksize)) {
+                       printf("HFS Mount: could not use physical block size "
+                               "(%d) switching to 512\n", blksize);
+                       blksize = 512;
+                       if (VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, cred, p)) {
+                               retval = ENXIO;
+                               goto error_exit;
+                       }
+                       if (VOP_IOCTL(devvp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, cred, p)) {
+                               retval = ENXIO;
+                               goto error_exit;
+                       }
+                       devvp->v_specsize = blksize;
+                       /* Note: relative block count adjustment (in case this is an embedded volume). */
+                       hfsmp->hfs_phys_block_count *= hfsmp->hfs_phys_block_size / blksize;
+                       hfsmp->hfs_phys_block_size = blksize;
+                       /* Try again with a smaller block size... */
+                       retval = hfs_MountHFSPlusVolume(hfsmp, vhp, embeddedOffset, disksize, p, args);
+               }
+               if (retval)
+                       (void) hfs_relconverter(0);
+       }
 
-std_exit:
+       if ( retval ) {
+               goto error_exit;
+       }
+
+       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;
+       devvp->v_specflags |= SI_MOUNTEDON;
+
+       if (ronly == 0) {
+               (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
+       }
+       FREE(mdbp, M_TEMP);
+       return (0);
+
+error_exit:
+       if (bp)
+               brelse(bp);
+       if (mdbp)
+               FREE(mdbp, M_TEMP);
+       (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
+       if (hfsmp && hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) {
+           (void)VOP_CLOSE(hfsmp->jvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
+               hfsmp->jvp = NULL;
+       }
+       if (hfsmp) {
+               FREE(hfsmp, M_HFSMNT);
+               mp->mnt_data = (qaddr_t)0;
+       }
         return (retval);
 }
 
@@ -1060,22 +1179,20 @@ std_exit:
  * Nothing to do at the moment.
  */
 /* ARGSUSED */
-int hfs_start(mp, flags, p)
-struct mount *mp;
-int flags;
-struct proc *p;
+static int
+hfs_start(mp, flags, p)
+       struct mount *mp;
+       int flags;
+       struct proc *p;
 {
-    DBG_FUNC_NAME("hfs_start");
-    DBG_PRINT_FUNC_NAME();
-
-    return (0);
+       return (0);
 }
 
 
 /*
  * unmount system call
  */
-int
+static int
 hfs_unmount(mp, mntflags, p)
        struct mount *mp;
        int mntflags;
@@ -1084,52 +1201,80 @@ hfs_unmount(mp, mntflags, p)
        struct hfsmount *hfsmp = VFSTOHFS(mp);
        int retval = E_NONE;
        int flags;
+       int force;
+       int started_tr = 0, grabbed_lock = 0;
 
        flags = 0;
-       if (mntflags & MNT_FORCE)
+       force = 0;
+       if (mntflags & MNT_FORCE) {
                flags |= FORCECLOSE;
+               force = 1;
+       }
 
-       if ((retval = hfs_flushfiles(mp, flags)))
+       if ((retval = hfs_flushfiles(mp, flags, p)) && !force)
                return (retval);
 
        /*
         * Flush out the b-trees, volume bitmap and Volume Header
         */
        if (hfsmp->hfs_fs_ronly == 0) {
+               hfs_global_shared_lock_acquire(hfsmp);
+               grabbed_lock = 1;
+           if (hfsmp->jnl) {
+                       journal_start_transaction(hfsmp->jnl);
+                       started_tr = 1;
+               }
+               
                retval = VOP_FSYNC(HFSTOVCB(hfsmp)->catalogRefNum, NOCRED, MNT_WAIT, p);
-               if (retval && ((mntflags & MNT_FORCE) == 0))
-                       return (retval);
-
+               if (retval && !force)
+                       goto err_exit;
+               
                retval = VOP_FSYNC(HFSTOVCB(hfsmp)->extentsRefNum, NOCRED, MNT_WAIT, p);
-               if (retval && ((mntflags & MNT_FORCE) == 0))
-                       return (retval);
+               if (retval && !force)
+                       goto err_exit;
+                       
+               // if we have an allocation file, sync it too so we don't leave dirty
+               // blocks around
+               if (HFSTOVCB(hfsmp)->allocationsRefNum) {
+                   if (retval = VOP_FSYNC(HFSTOVCB(hfsmp)->allocationsRefNum, NOCRED, MNT_WAIT, p)) {
+                       if (!force)
+                           goto err_exit;
+                   }
+               }
 
                if (retval = VOP_FSYNC(hfsmp->hfs_devvp, NOCRED, MNT_WAIT, p)) {
-                       if ((mntflags & MNT_FORCE) == 0)
-                               return (retval);
+                       if (!force)
+                               goto err_exit;
                }
                
                /* See if this volume is damaged, is so do not unmount cleanly */
                if (HFSTOVCB(hfsmp)->vcbFlags & kHFS_DamagedVolume) {
-                       hfsmp->hfs_fs_clean = 0;
                        HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
                } else {
-            hfsmp->hfs_fs_clean = 1;
-            HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
+                       HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeUnmountedMask;
                }
-               if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord)
-                       retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT);
-               else
-                       retval = hfs_flushMDB(hfsmp, MNT_WAIT);
-       
+
+               retval = hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
                if (retval) {
-                       hfsmp->hfs_fs_clean = 0;
                        HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeUnmountedMask;
-                       if ((mntflags & MNT_FORCE) == 0)
-                               return (retval);        /* could not flush everything */
+                       if (!force)
+                               goto err_exit;  /* could not flush everything */
+               }
+
+               if (hfsmp->jnl) {
+                       journal_end_transaction(hfsmp->jnl);
+                       started_tr = 0;
+               }
+               if (grabbed_lock) {
+                       hfs_global_shared_lock_release(hfsmp);
+                       grabbed_lock = 0;
                }
        }
 
+       if (hfsmp->jnl) {
+               journal_flush(hfsmp->jnl);
+       }
+       
        /*
         *      Invalidate our caches and release metadata vnodes
         */
@@ -1138,15 +1283,39 @@ hfs_unmount(mp, mntflags, p)
        if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord)
                (void) hfs_relconverter(hfsmp->hfs_encoding);
 
+       // XXXdbg
+       if (hfsmp->jnl) {
+           journal_close(hfsmp->jnl);
+       }
+
+       if (hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) {
+           retval = VOP_CLOSE(hfsmp->jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE,
+                              NOCRED, p);
+           vrele(hfsmp->jvp);
+               hfsmp->jvp = NULL;
+       }
+       // XXXdbg
+
        hfsmp->hfs_devvp->v_specflags &= ~SI_MOUNTEDON;
-       retval = VOP_CLOSE(hfsmp->hfs_devvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE,
-                       NOCRED, p);
-       vrele(hfsmp->hfs_devvp);
+       retval = VOP_CLOSE(hfsmp->hfs_devvp,
+                   hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE,
+                   NOCRED, p);
+       if (retval && !force)
+               return(retval);
 
+       vrele(hfsmp->hfs_devvp);
        FREE(hfsmp, M_HFSMNT);
        mp->mnt_data = (qaddr_t)0;
+       return (0);
 
-       return (retval);
+  err_exit:
+       if (hfsmp->jnl && started_tr) {
+               journal_end_transaction(hfsmp->jnl);
+       }
+       if (grabbed_lock) {
+               hfs_global_shared_lock_release(hfsmp);
+       }
+       return retval;
 }
 
 
@@ -1155,42 +1324,104 @@ hfs_unmount(mp, mntflags, p)
  *
  *              OUT - vpp, should be locked and vget()'d (to increment usecount and lock)
  */
-int hfs_root(mp, vpp)
-struct mount *mp;
-struct vnode **vpp;
+static int
+hfs_root(mp, vpp)
+       struct mount *mp;
+       struct vnode **vpp;
 {
-    struct vnode *nvp;
-    int retval;
-    UInt32 rootObjID = kRootDirID;
-
-    DBG_FUNC_NAME("hfs_root");
-    DBG_PRINT_FUNC_NAME();
+       struct vnode *nvp;
+       int retval;
+       UInt32 rootObjID = kRootDirID;
 
-    if ((retval = VFS_VGET(mp, &rootObjID, &nvp)))
-        return (retval);
+       if ((retval = VFS_VGET(mp, &rootObjID, &nvp)))
+               return (retval);
 
-    *vpp = nvp;
-    return (0);
+       *vpp = nvp;
+       return (0);
 }
 
 
 /*
  * Do operations associated with quotas
  */
-int hfs_quotactl(mp, cmds, uid, arg, p)
-struct mount *mp;
-int cmds;
-uid_t uid;
-caddr_t arg;
-struct proc *p;
+int
+hfs_quotactl(mp, cmds, uid, arg, p)
+       struct mount *mp;
+       int cmds;
+       uid_t uid;
+       caddr_t arg;
+       struct proc *p;
 {
-    DBG_FUNC_NAME("hfs_quotactl");
-    DBG_PRINT_FUNC_NAME();
+       int cmd, type, error;
+
+#if !QUOTA
+       return (EOPNOTSUPP);
+#else
+       if (uid == -1)
+               uid = p->p_cred->p_ruid;
+       cmd = cmds >> SUBCMDSHIFT;
+
+       switch (cmd) {
+       case Q_SYNC:
+       case Q_QUOTASTAT:
+               break;
+       case Q_GETQUOTA:
+               if (uid == p->p_cred->p_ruid)
+                       break;
+               /* fall through */
+       default:
+               if (error = suser(p->p_ucred, &p->p_acflag))
+                       return (error);
+       }
 
-    return (EOPNOTSUPP);
+       type = cmds & SUBCMDMASK;
+       if ((u_int)type >= MAXQUOTAS)
+               return (EINVAL);
+       if (vfs_busy(mp, LK_NOWAIT, 0, p))
+               return (0);
+
+       switch (cmd) {
+
+       case Q_QUOTAON:
+               error = hfs_quotaon(p, mp, type, arg, UIO_USERSPACE);
+               break;
+
+       case Q_QUOTAOFF:
+               error = hfs_quotaoff(p, mp, type);
+               break;
+
+       case Q_SETQUOTA:
+               error = hfs_setquota(mp, uid, type, arg);
+               break;
+
+       case Q_SETUSE:
+               error = hfs_setuse(mp, uid, type, arg);
+               break;
+
+       case Q_GETQUOTA:
+               error = hfs_getquota(mp, uid, type, arg);
+               break;
+
+       case Q_SYNC:
+               error = hfs_qsync(mp);
+               break;
+
+       case Q_QUOTASTAT:
+               error = hfs_quotastat(mp, type, arg);
+               break;
+
+       default:
+               error = EINVAL;
+               break;
+       }
+       vfs_unbusy(mp, p);
+       return (error);
+#endif /* QUOTA */
 }
 
 
+
+
 /*
  * Get file system statistics.
  */
@@ -1204,18 +1435,15 @@ hfs_statfs(mp, sbp, p)
        struct hfsmount *hfsmp = VFSTOHFS(mp);
        u_long freeCNIDs;
 
-       DBG_FUNC_NAME("hfs_statfs");
-       DBG_PRINT_FUNC_NAME();
-
        freeCNIDs = (u_long)0xFFFFFFFF - (u_long)vcb->vcbNxtCNID;
 
        sbp->f_bsize = vcb->blockSize;
        sbp->f_iosize = hfsmp->hfs_logBlockSize;
        sbp->f_blocks = vcb->totalBlocks;
-       sbp->f_bfree = vcb->freeBlocks;
-       sbp->f_bavail = vcb->freeBlocks;
+       sbp->f_bfree = hfs_freeblks(hfsmp, 0);
+       sbp->f_bavail = hfs_freeblks(hfsmp, 1);
        sbp->f_files = vcb->totalBlocks - 2;  /* max files is constrained by total blocks */
-       sbp->f_ffree = MIN(freeCNIDs, vcb->freeBlocks);
+       sbp->f_ffree = MIN(freeCNIDs, sbp->f_bavail);
        
        sbp->f_type = 0;
        if (sbp != &mp->mnt_stat) {
@@ -1229,6 +1457,70 @@ hfs_statfs(mp, sbp, p)
 }
 
 
+//
+// XXXdbg -- this is a callback to be used by the journal to
+//           get meta data blocks flushed out to disk.
+//
+// XXXdbg -- be smarter and don't flush *every* block on each
+//           call.  try to only flush some so we don't wind up
+//           being too synchronous.
+//
+__private_extern__
+void
+hfs_sync_metadata(void *arg)
+{
+       struct mount *mp = (struct mount *)arg;
+       struct cnode *cp;
+       struct hfsmount *hfsmp;
+       ExtendedVCB *vcb;
+       struct vnode *meta_vp[3];
+       struct buf *bp;
+       int i, sectorsize, priIDSector, altIDSector, retval;
+       int error, allerror = 0;
+
+       hfsmp = VFSTOHFS(mp);
+       vcb = HFSTOVCB(hfsmp);
+
+       bflushq(BQ_META, mp);
+
+
+#if 1     // XXXdbg - I do not believe this is necessary...
+          //          but if I pull it out, then the journal
+             //          does not seem to get flushed properly
+             //          when it is closed....
+       
+       // now make sure the super block is flushed
+       sectorsize = hfsmp->hfs_phys_block_size;
+       priIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
+                  HFS_PRI_SECTOR(sectorsize);
+       retval = meta_bread(hfsmp->hfs_devvp, priIDSector, sectorsize, NOCRED, &bp);
+       if (retval != 0) {
+               panic("hfs: sync_metadata: can't read super-block?! (retval 0x%x, priIDSector)\n",
+                         retval, priIDSector);
+       }
+
+       if (retval == 0 && (bp->b_flags & B_DELWRI) && (bp->b_flags & B_LOCKED) == 0) {
+           bwrite(bp);
+       } else if (bp) {
+           brelse(bp);
+       }
+
+       // the alternate super block...
+       // XXXdbg - we probably don't need to do this each and every time.
+       //          hfs_btreeio.c:FlushAlternate() should flag when it was
+       //          written...
+       altIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
+                       HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
+       retval = meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &bp);
+       if (retval == 0 && (bp->b_flags & B_DELWRI) && (bp->b_flags & B_LOCKED) == 0) {
+           bwrite(bp);
+       } else if (bp) {
+           brelse(bp);
+       }
+#endif
+       
+}
+
 /*
  * Go through the disk queues to initiate sandbagged IO;
  * go through the inodes to write those that have been modified;
@@ -1236,22 +1528,20 @@ hfs_statfs(mp, sbp, p)
  *
  * Note: we are always called with the filesystem marked `MPBUSY'.
  */
-static int hfs_sync(mp, waitfor, cred, p)
-struct mount *mp;
-int waitfor;
-struct ucred *cred;
-struct proc *p;
+static int
+hfs_sync(mp, waitfor, cred, p)
+       struct mount *mp;
+       int waitfor;
+       struct ucred *cred;
+       struct proc *p;
 {
-    struct vnode               *nvp, *vp;
-    struct hfsnode             *hp;
-    struct hfsmount            *hfsmp = VFSTOHFS(mp);
-    ExtendedVCB                        *vcb;
-    struct vnode               *meta_vp[3];
-    int i;
-    int error, allerror = 0;
-
-    DBG_FUNC_NAME("hfs_sync");
-    DBG_PRINT_FUNC_NAME();
+       struct vnode *nvp, *vp;
+       struct cnode *cp;
+       struct hfsmount *hfsmp;
+       ExtendedVCB *vcb;
+       struct vnode *meta_vp[3];
+       int i;
+       int error, allerror = 0;
 
        /*
         * During MNT_UPDATE hfs_changefs might be manipulating
@@ -1260,121 +1550,153 @@ struct proc *p;
        if (mp->mnt_flag & MNT_UPDATE)
                return (0);
 
-    hfsmp = VFSTOHFS(mp);
-    if (hfsmp->hfs_fs_ronly != 0) {
-        panic("update: rofs mod");
-    };
+       hfsmp = VFSTOHFS(mp);
+       if (hfsmp->hfs_fs_ronly != 0) {
+               panic("update: rofs mod");
+       };
 
-    /*
-     * Write back each 'modified' vnode
-     */
+#if 0
+       // XXXdbg first go through and flush out any modified
+       //        meta data blocks so they go out in order...
+       bflushq(BQ_META, mp);
+       bflushq(BQ_LRU,  mp);
+       // only flush locked blocks if we're not doing journaling
+       if (hfsmp->jnl == NULL) {
+           bflushq(BQ_LOCKED, mp);
+       }
+#endif
+
+       /*
+        * Write back each 'modified' vnode
+        */
 
-loop:;
-    simple_lock(&mntvnode_slock);
-    for (vp = mp->mnt_vnodelist.lh_first;
-         vp != NULL;
-         vp = nvp) {
+loop:
+       simple_lock(&mntvnode_slock);
+       for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
                 int didhold;
-        /*
-         * If the vnode that we are about to sync is no longer
-         * associated with this mount point, start over.
-         */
-        if (vp->v_mount != mp) {
-           simple_unlock(&mntvnode_slock);
-            goto loop;
-       }
-        simple_lock(&vp->v_interlock);
-        nvp = vp->v_mntvnodes.le_next;
-        hp = VTOH(vp);
-
-        if ((vp->v_flag & VSYSTEM) || (vp->v_type == VNON) ||
-            (((hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) &&
-            (vp->v_dirtyblkhd.lh_first == NULL) && !(vp->v_flag & VHASDIRTY))) {
-            simple_unlock(&vp->v_interlock);
-           simple_unlock(&mntvnode_slock);
-           simple_lock(&mntvnode_slock);
-            continue;
-        }
-
-        simple_unlock(&mntvnode_slock);
-        error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
-        if (error) {
-            if (error == ENOENT)
-                goto loop;
-            simple_lock(&mntvnode_slock);
-            continue;
-        }
+               /*
+                * If the vnode that we are about to sync is no longer
+                * associated with this mount point, start over.
+                */
+               if (vp->v_mount != mp) {
+                       simple_unlock(&mntvnode_slock);
+                       goto loop;
+               }
+
+               simple_lock(&vp->v_interlock);
+               nvp = vp->v_mntvnodes.le_next;
+
+               cp = VTOC(vp);
+
+               // restart our whole search if this guy is locked
+               // or being reclaimed.
+               // XXXdbg - at some point this should go away or we
+               //          need to change all file systems to have
+               //          this same code.  vget() should never return
+               //          success if either of these conditions is
+               //          true.
+               if (vp->v_tag != VT_HFS || cp == NULL) {
+                       simple_unlock(&vp->v_interlock);
+                       continue;
+               }
+
+               if ((vp->v_flag & VSYSTEM) || (vp->v_type == VNON) ||
+                   (((cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) == 0) &&
+                   (vp->v_dirtyblkhd.lh_first == NULL) && !(vp->v_flag & VHASDIRTY))) {
+                       simple_unlock(&vp->v_interlock);
+                       simple_unlock(&mntvnode_slock);
+                       simple_lock(&mntvnode_slock);
+                       continue;
+               }
+
+               simple_unlock(&mntvnode_slock);
+               error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
+               if (error) {
+                       if (error == ENOENT)
+                               goto loop;
+                       simple_lock(&mntvnode_slock);
+                       continue;
+               }
                
                didhold = ubc_hold(vp);
-        if ((error = VOP_FSYNC(vp, cred, waitfor, p))) {
-            DBG_ERR(("hfs_sync: error %d calling fsync on vnode 0x%X.\n", error, (u_int)vp));
-            allerror = error;
-        };
-        DBG_ASSERT(*((volatile int *)(&(vp)->v_interlock))==0);
-        VOP_UNLOCK(vp, 0, p);
+               if ((error = VOP_FSYNC(vp, cred, waitfor, p))) {
+                       allerror = error;
+               };
+               VOP_UNLOCK(vp, 0, p);
                if (didhold)
                        ubc_rele(vp);
-        vrele(vp);
-        simple_lock(&mntvnode_slock);
-    };
-
-    vcb = HFSTOVCB(hfsmp);
-    meta_vp[0] = vcb->extentsRefNum;
-    meta_vp[1] = vcb->catalogRefNum;
-    meta_vp[2] = vcb->allocationsRefNum;  /* This is NULL for standard HFS */
-
-    /* Now sync our three metadata files */
-    for (i = 0; i < 3; ++i) {
-       struct vnode *btvp;
-  
-        btvp = meta_vp[i];
-
-        if ((btvp==0) || (btvp->v_type == VNON) || (btvp->v_mount != mp))
-            continue;
-        simple_lock(&btvp->v_interlock);
-        hp = VTOH(btvp);
-        if (((hp->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) &&
-            (btvp->v_dirtyblkhd.lh_first == NULL) && !(btvp->v_flag & VHASDIRTY)) {
-            simple_unlock(&btvp->v_interlock);
-            continue;
-        }
-        simple_unlock(&mntvnode_slock);
-        error = vget(btvp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
-        if (error) {
-            simple_lock(&mntvnode_slock);
-            continue;
-        }
-        if ((error = VOP_FSYNC(btvp, cred, waitfor, p)))
-            allerror = error;
-        VOP_UNLOCK(btvp, 0, p);
-        vrele(btvp);
-        simple_lock(&mntvnode_slock);
-    };
-
-    simple_unlock(&mntvnode_slock);
+               vrele(vp);
+               simple_lock(&mntvnode_slock);
+       };
 
-    /*
-     * Force stale file system control information to be flushed.
-     */
-    if (vcb->vcbSigWord == kHFSSigWord) {
-        if ((error = VOP_FSYNC(hfsmp->hfs_devvp, cred, waitfor, p)))
-            allerror = error;
-    }
-    /*
-     * Write back modified superblock.
-     */
+       vcb = HFSTOVCB(hfsmp);
+
+       meta_vp[0] = vcb->extentsRefNum;
+       meta_vp[1] = vcb->catalogRefNum;
+       meta_vp[2] = vcb->allocationsRefNum;  /* This is NULL for standard HFS */
+
+       /* Now sync our three metadata files */
+       for (i = 0; i < 3; ++i) {
+               struct vnode *btvp;
 
-    if (IsVCBDirty(vcb)) {
-       if (vcb->vcbSigWord == kHFSPlusSigWord)
-               error = hfs_flushvolumeheader(hfsmp, waitfor);
-       else
-               error = hfs_flushMDB(hfsmp, waitfor);
-       
-        if (error)
-            allerror = error;
-    };
-
-    return (allerror);
+               btvp = btvp = meta_vp[i];;
+               if ((btvp==0) || (btvp->v_type == VNON) || (btvp->v_mount != mp))
+                       continue;
+
+               simple_lock(&btvp->v_interlock);
+               cp = VTOC(btvp);
+               if (((cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) == 0) &&
+                   (btvp->v_dirtyblkhd.lh_first == NULL) && !(btvp->v_flag & VHASDIRTY)) {
+                       simple_unlock(&btvp->v_interlock);
+                       continue;
+               }
+               simple_unlock(&mntvnode_slock);
+               error = vget(btvp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p);
+               if (error) {
+                       simple_lock(&mntvnode_slock);
+                       continue;
+               }
+               if ((error = VOP_FSYNC(btvp, cred, waitfor, p)))
+                       allerror = error;
+               VOP_UNLOCK(btvp, 0, p);
+               vrele(btvp);
+               simple_lock(&mntvnode_slock);
+       };
+
+       simple_unlock(&mntvnode_slock);
+
+       /*
+        * Force stale file system control information to be flushed.
+        */
+       if (vcb->vcbSigWord == kHFSSigWord) {
+               if ((error = VOP_FSYNC(hfsmp->hfs_devvp, cred, waitfor, p)))
+                       allerror = error;
+       }
+#if QUOTA
+       hfs_qsync(mp);
+#endif /* QUOTA */
+       /*
+        * Write back modified superblock.
+        */
+
+       if (IsVCBDirty(vcb)) {
+               // XXXdbg - debugging, remove
+               if (hfsmp->jnl) {
+                       //printf("hfs: sync: strange, a journaled volume w/dirty VCB? jnl 0x%x hfsmp 0x%x\n",
+                       //        hfsmp->jnl, hfsmp);
+               }
+
+               error = hfs_flushvolumeheader(hfsmp, waitfor, 0);
+               if (error)
+                       allerror = error;
+       }
+
+       if (hfsmp->jnl) {
+           journal_flush(hfsmp->jnl);
+       }
+       
+  err_exit:
+       return (allerror);
 }
 
 
@@ -1382,27 +1704,25 @@ loop:;
  * File handle to vnode
  *
  * Have to be really careful about stale file handles:
- * - check that the hfsnode number is valid
- * - call hfs_vget() to get the locked hfsnode
- * - check for an unallocated hfsnode (i_mode == 0)
+ * - check that the cnode id is valid
+ * - call hfs_vget() to get the locked cnode
+ * - check for an unallocated cnode (i_mode == 0)
  * - check that the given client host has export rights and return
  *   those rights via. exflagsp and credanonp
  */
-int
+static int
 hfs_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;
+       register struct mount *mp;
+       struct fid *fhp;
+       struct mbuf *nam;
+       struct vnode **vpp;
+       int *exflagsp;
+       struct ucred **credanonp;
 {
        struct hfsfid *hfsfhp;
        struct vnode *nvp;
        int result;
        struct netcred *np;
-    DBG_FUNC_NAME("hfs_fhtovp");
-    DBG_PRINT_FUNC_NAME();
 
        *vpp = NULL;
        hfsfhp = (struct hfsfid *)fhp;
@@ -1430,16 +1750,16 @@ struct ucred **credanonp;
         * error prone. Future, would be change the "wrap bit" to a unique
         * wrap number and use that for generation number. For now do this.
         */  
-       if ((hfsfhp->hfsfid_gen < VTOH(nvp)->h_meta->h_crtime)) {
+       if ((hfsfhp->hfsfid_gen < VTOC(nvp)->c_itime)) {
                vput(nvp);
-               return ESTALE;
+               return (ESTALE);
        };
        
        *vpp = nvp;
        *exflagsp = np->netc_exflags;
        *credanonp = &np->netc_anon;
        
-    return 0;
+       return (0);
 }
 
 
@@ -1447,251 +1767,383 @@ struct ucred **credanonp;
  * Vnode pointer to File handle
  */
 /* ARGSUSED */
-static int hfs_vptofh(vp, fhp)
-struct vnode *vp;
-struct fid *fhp;
+static int
+hfs_vptofh(vp, fhp)
+       struct vnode *vp;
+       struct fid *fhp;
 {
-       struct hfsnode *hp;
+       struct cnode *cp;
        struct hfsfid *hfsfhp;
-       struct proc *p = current_proc();
-       int result;
-    u_int32_t fileID;
-    DBG_FUNC_NAME("hfs_vptofh");
-    DBG_PRINT_FUNC_NAME();
 
-       hp = VTOH(vp);
-       hfsfhp = (struct hfsfid *)fhp;
-       
-       /* If a file handle is requested for a file on an HFS volume we must be sure
-               to create the thread record before returning the object id in the filehandle
-               to make sure the file can be retrieved by fileid if necessary:
-        */
-       if ((vp->v_type == VREG) && ISHFS(VTOVCB(vp))) {
-               /* Create a thread record and return the FileID [which is the file's fileNumber] */
-               /* lock catalog b-tree */
-               if ((result = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p)) != 0) return result;
-               result = hfsCreateFileID(VTOVCB(vp), H_DIRID(hp), H_NAME(hp), H_HINT(hp), &fileID);
-               (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
-               if (result) {
-                       DBG_ERR(("hfs_vptofh: error %d on CreateFileIDRef.\n", result));
-                       return result;
-               };
-               DBG_ASSERT(fileID == H_FILEID(hp));
-       };
+       if (ISHFS(VTOVCB(vp)))
+               return (EOPNOTSUPP);    /* hfs standard is not exportable */
 
+       cp = VTOC(vp);
+       hfsfhp = (struct hfsfid *)fhp;
        hfsfhp->hfsfid_len = sizeof(struct hfsfid);
        hfsfhp->hfsfid_pad = 0;
-       hfsfhp->hfsfid_cnid = H_FILEID(hp);
-       hfsfhp->hfsfid_gen = hp->h_meta->h_crtime;
+       hfsfhp->hfsfid_cnid = cp->c_cnid;
+       hfsfhp->hfsfid_gen = cp->c_itime;
        
-       return 0;
+       return (0);
 }
 
 
 /*
  * Initial HFS filesystems, done only once.
  */
-int
+static int
 hfs_init(vfsp)
-struct vfsconf *vfsp;
+       struct vfsconf *vfsp;
 {
-    int i;
-    static int done = 0;
-    OSErr err;
+       static int done = 0;
 
-    DBG_FUNC_NAME("hfs_init");
-    DBG_PRINT_FUNC_NAME();
-
-    if (done)
-        return (0);
-    done = 1;
-    hfs_vhashinit();
-    hfs_converterinit();
-
-    simple_lock_init (&gBufferPtrListLock);
-
-    for (i = BUFFERPTRLISTSIZE - 1; i >= 0; --i) {
-        gBufferAddress[i] = NULL;
-        gBufferHeaderPtr[i] = NULL;
-    };
-    gBufferListIndex = 0;
+       if (done)
+               return (0);
+       done = 1;
+       hfs_chashinit();
+       hfs_converterinit();
+#if QUOTA
+       dqinit();
+#endif /* QUOTA */
 
        /*
         * Allocate Catalog Iterator cache...
         */
-       err = InitCatalogCache();
+       (void) InitCatalogCache();
 
-    return E_NONE;
+       return (0);
 }
 
 
+// XXXdbg
+#include <sys/filedesc.h>
+
+
 /*
- * fast filesystem related variables.
+ * HFS filesystem related variables.
  */
-static int hfs_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;
+static int
+hfs_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;
 {
-    DBG_FUNC_NAME("hfs_sysctl");
-    DBG_PRINT_FUNC_NAME();
+       extern u_int32_t hfs_encodingbias;
+
+       /* all sysctl names at this level are terminal */
+
+       if (name[0] == HFS_ENCODINGBIAS)
+               return (sysctl_int(oldp, oldlenp, newp, newlen,
+                               &hfs_encodingbias));
+       else if (name[0] == 0x082969) {
+               // make the file system journaled...
+               struct vnode *vp = p->p_fd->fd_cdir, *jvp;
+               struct hfsmount *hfsmp;
+               ExtendedVCB *vcb;
+               int retval;
+               struct cat_attr jnl_attr, jinfo_attr;
+               struct cat_fork jnl_fork, jinfo_fork;
+               void *jnl = NULL;
+
+               /* Only root can enable journaling */
+        if (current_proc()->p_ucred->cr_uid != 0) {
+                       return (EPERM);
+               }
+               hfsmp = VTOHFS(vp);
+               if (hfsmp->hfs_fs_ronly) {
+                       return EROFS;
+               }
+               if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) {
+                       printf("hfs: can't make a plain hfs volume journaled.\n");
+                       return EINVAL;
+               }
 
-    return (EOPNOTSUPP);
-}
+               if (hfsmp->jnl) {
+                   printf("hfs: volume @ mp 0x%x is already journaled!\n", vp->v_mount);
+                   return EAGAIN;
+               }
 
+               vcb = HFSTOVCB(hfsmp);
+               if (BTHasContiguousNodes(VTOF(vcb->catalogRefNum)) == 0 ||
+                       BTHasContiguousNodes(VTOF(vcb->extentsRefNum)) == 0) {
 
-/*     This will return a vnode of either a directory or a data vnode based on an object id. If
- *  it is a file id, its data fork will be returned.
- */
-int
-hfs_vget(struct mount *mp,
-         void *ino,
-         struct vnode **vpp)
-{
-    struct hfsmount    *hfsmp;
-    dev_t                              dev;
-    int                                retval = E_NONE;
+                       printf("hfs: volume has a btree w/non-contiguous nodes.  can not enable journaling.\n");
+                       return EINVAL;
+               }
 
-    DBG_VFS(("hfs_vget: ino = %ld\n", *(UInt32 *)ino));
+               // make sure these both exist!
+               if (   GetFileInfo(vcb, kRootDirID, ".journal_info_block", &jinfo_attr, &jinfo_fork) == 0
+                       || GetFileInfo(vcb, kRootDirID, ".journal", &jnl_attr, &jnl_fork) == 0) {
 
-       /* Check if unmount in progress */
-       if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
-               *vpp = NULL;
-               return (EPERM);
-       }
+                       return EINVAL;
+               }
 
-    hfsmp = VFSTOHFS(mp);
-    dev = hfsmp->hfs_raw_dev;
-       
-       /* First check to see if it is in the cache */
-    *vpp = hfs_vhashget(dev, *(UInt32 *)ino, kDefault);
-
-       /* hide open files that have been deleted */
-    if (*vpp != NULL) {
-            if ((VTOH(*vpp)->h_meta->h_metaflags & IN_NOEXISTS) ||
-                (hfsmp->hfs_private_metadata_dir != 0) &&
-                (H_DIRID(VTOH(*vpp)) == hfsmp->hfs_private_metadata_dir)) {
-                    vput(*vpp);
-                    retval = ENOENT;
-                    goto Err_Exit;
-            }
-    }
-    
-       /* The vnode is not in the cache, so lets make it */
-    if (*vpp == NULL)
-      {
-       hfsCatalogInfo          catInfo;
-        struct proc                    *p = current_proc();
-        UInt8                          forkType;
-
-               INIT_CATALOGDATA(&catInfo.nodeData, 0);
-               catInfo.hint = kNoHint;
-               /* Special-case the root's parent directory (DirID = 1) because
-                  it doesn't actually exist in the catalog: */
-               if ((*vpp == NULL) && (*(UInt32 *)ino == kRootParID)) {
-                       bzero(&catInfo, sizeof(catInfo));
-                       catInfo.nodeData.cnd_type = kCatalogFolderNode;
-                       catInfo.nodeData.cnm_nameptr = catInfo.nodeData.cnm_namespace;
-                       catInfo.nodeData.cnm_namespace[0] = '/';
-                       catInfo.nodeData.cnm_length = 1;
-                       catInfo.nodeData.cnd_nodeID = kRootParID;
-                       catInfo.nodeData.cnm_parID = kRootParID;
-                       catInfo.nodeData.cnd_valence = 1;
-                       catInfo.nodeData.cnd_ownerID = 0;
-                       catInfo.nodeData.cnd_groupID = 0;
-                       catInfo.nodeData.cnd_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
-            } else {
-
-            /* lock catalog b-tree */
-            retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p);
-            if (retval != E_NONE) goto Lookup_Err_Exit;
-
-            retval = hfs_getcatalog(VFSTOVCB(mp), *(UInt32 *)ino, NULL, -1, &catInfo);
-
-            /* unlock catalog b-tree */
-            (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
-
-            if (retval != E_NONE) goto Lookup_Err_Exit;
-
-            /* hide open files that have been deleted */
-            if ((hfsmp->hfs_private_metadata_dir != 0) &&
-               (catInfo.nodeData.cnm_parID == hfsmp->hfs_private_metadata_dir)) {
-                retval = ENOENT;
-                goto Lookup_Err_Exit;
-                };
-            };
-
-        forkType = (catInfo.nodeData.cnd_type == kCatalogFolderNode) ? kDirectory : kDataFork;
-        retval = hfs_vcreate(VFSTOVCB(mp), &catInfo, forkType, vpp);
+               hfs_sync(hfsmp->hfs_mp, MNT_WAIT, FSCRED, p);
+               bflushq(BQ_META);
+
+               printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n",
+                          (off_t)name[2], (off_t)name[3]);
+
+               jvp = hfsmp->hfs_devvp;
+               jnl = journal_create(jvp,
+                                                        (off_t)name[2] * (off_t)HFSTOVCB(hfsmp)->blockSize
+                                                        + HFSTOVCB(hfsmp)->hfsPlusIOPosOffset,
+                                                        (off_t)name[3],
+                                                        hfsmp->hfs_devvp,
+                                                        hfsmp->hfs_phys_block_size,
+                                                        0,
+                                                        0,
+                                                        hfs_sync_metadata, hfsmp->hfs_mp);
+
+               if (jnl == NULL) {
+                       printf("hfs: FAILED to create the journal!\n");
+                       if (jvp && jvp != hfsmp->hfs_devvp) {
+                               VOP_CLOSE(jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
+                       }
+                       jvp = NULL;
+
+                       return EINVAL;
+               } 
+
+               hfs_global_exclusive_lock_acquire(hfsmp);
                
-Lookup_Err_Exit:
-               CLEAN_CATALOGDATA(&catInfo.nodeData);
-      };
+               HFSTOVCB(hfsmp)->vcbJinfoBlock = name[1];
+               HFSTOVCB(hfsmp)->vcbAtrb |= kHFSVolumeJournaledMask;
+               hfsmp->jvp = jvp;
+               hfsmp->jnl = jnl;
+
+               // save this off for the hack-y check in hfs_remove()
+               hfsmp->jnl_start        = (u_int32_t)name[2];
+               hfsmp->hfs_jnlinfoblkid = jinfo_attr.ca_fileid;
+               hfsmp->hfs_jnlfileid    = jnl_attr.ca_fileid;
+
+               hfsmp->hfs_mp->mnt_flag |= MNT_JOURNALED;
+
+               hfs_global_exclusive_lock_release(hfsmp);
+               hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
+
+               return 0;
+       } else if (name[0] == 0x031272) {
+               // clear the journaling bit 
+               struct vnode *vp = p->p_fd->fd_cdir;
+               struct hfsmount *hfsmp;
+               void *jnl;
+               int retval;
+               
+               /* Only root can disable journaling */
+        if (current_proc()->p_ucred->cr_uid != 0) {
+                       return (EPERM);
+               }
+               hfsmp = VTOHFS(vp);
+               if (hfsmp->jnl == NULL) {
+                       return EINVAL;
+               }
+
+               printf("hfs: disabling journaling for mount @ 0x%x\n", vp->v_mount);
+
+               jnl = hfsmp->jnl;
+               
+               hfs_global_exclusive_lock_acquire(hfsmp);
 
-       UBCINFOCHECK("hfs_vget", *vpp);
+               // Lights out for you buddy!
+               hfsmp->jnl = NULL;
+               journal_close(jnl);
 
-Err_Exit:
+               if (hfsmp->jvp && hfsmp->jvp != hfsmp->hfs_devvp) {
+                       VOP_CLOSE(hfsmp->jvp, hfsmp->hfs_fs_ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
+               }
+               hfsmp->jnl = NULL;
+               hfsmp->jvp = NULL;
+               hfsmp->hfs_mp->mnt_flag &= ~MNT_JOURNALED;
+               hfsmp->jnl_start        = 0;
+               hfsmp->hfs_jnlinfoblkid = 0;
+               hfsmp->hfs_jnlfileid    = 0;
+               
+               HFSTOVCB(hfsmp)->vcbAtrb &= ~kHFSVolumeJournaledMask;
+               
+               hfs_global_exclusive_lock_release(hfsmp);
+               hfs_flushvolumeheader(hfsmp, MNT_WAIT, 1);
+
+               return 0;
+       }
 
-       /* rember if a parent directory was looked up by CNID */
-       if (retval == 0 && ((*vpp)->v_type == VDIR)
-           && lockstatus(&mp->mnt_lock) != LK_SHARED)
-               VTOH(*vpp)->h_nodeflags |= IN_BYCNID;
+       return (EOPNOTSUPP);
+}
 
-    return (retval);
 
+/*     This will return a vnode of either a directory or a data vnode based on an object id. If
+ *  it is a file id, its data fork will be returned.
+ */
+static int
+hfs_vget(mp, ino, vpp)
+       struct mount *mp;
+       void *ino;
+       struct vnode **vpp;
+{
+       cnid_t cnid = *(cnid_t *)ino;
+       
+       /* Check for cnids that should't be exported. */
+       if ((cnid < kHFSFirstUserCatalogNodeID)
+       &&  (cnid != kHFSRootFolderID && cnid != kHFSRootParentID))
+               return (ENOENT);
+       /* Don't export HFS Private Data dir. */
+       if (cnid == VFSTOHFS(mp)->hfs_privdir_desc.cd_cnid)
+               return (ENOENT);
+
+       return (hfs_getcnode(VFSTOHFS(mp), cnid, NULL, 0, NULL, NULL, vpp));
 }
 
 /*
  * Flush out all the files in a filesystem.
  */
 int
-hfs_flushfiles(struct mount *mp, int flags)
+hfs_flushfiles(struct mount *mp, int flags, struct proc *p)
 {
+       register struct hfsmount *hfsmp;
+       int i;
        int error;
 
+#if QUOTA
+       hfsmp = VFSTOHFS(mp);
+
+       if (mp->mnt_flag & MNT_QUOTA) {
+               if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
+                       return (error);
+               for (i = 0; i < MAXQUOTAS; i++) {
+                       if (hfsmp->hfs_qfiles[i].qf_vp == NULLVP)
+                               continue;
+                       hfs_quotaoff(p, mp, i);
+               }
+               /*
+                * Here we fall through to vflush again to ensure
+                * that we have gotten rid of all the system vnodes.
+                */
+       }
+#endif /* QUOTA */
+
        error = vflush(mp, NULLVP, (SKIPSYSTEM | SKIPSWAP | flags));
        error = vflush(mp, NULLVP, (SKIPSYSTEM | flags));
 
        return (error);
 }
 
-short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor)
+/*
+ * Update volume encoding bitmap (HFS Plus only)
+ */
+__private_extern__
+void
+hfs_setencodingbits(struct hfsmount *hfsmp, u_int32_t encoding)
 {
-       ExtendedVCB                     *vcb = HFSTOVCB(hfsmp);
-       FCB                                             *fcb;
-       HFSMasterDirectoryBlock *mdb;
-       struct buf                              *bp;
-       int                                             retval;
-       int                     size = kMDBSize;        /* 512 */
-       ByteCount                               namelen;
+#define  kIndexMacUkrainian    48  /* MacUkrainian encoding is 152 */
+#define  kIndexMacFarsi                49  /* MacFarsi encoding is 140 */
+
+       UInt32  index;
+
+       switch (encoding) {
+       case kTextEncodingMacUkrainian:
+               index = kIndexMacUkrainian;
+               break;
+       case kTextEncodingMacFarsi:
+               index = kIndexMacFarsi;
+               break;
+       default:
+               index = encoding;
+               break;
+       }
+
+       if (index < 128) {
+               HFSTOVCB(hfsmp)->encodingsBitmap |= (1 << index);
+               HFSTOVCB(hfsmp)->vcbFlags |= 0xFF00;
+       }
+}
+
+/*
+ * Update volume stats
+ */
+__private_extern__
+int
+hfs_volupdate(struct hfsmount *hfsmp, enum volop op, int inroot)
+{
+       ExtendedVCB *vcb;
+
+       vcb = HFSTOVCB(hfsmp);
+       vcb->vcbFlags |= 0xFF00;
+       vcb->vcbLsMod = time.tv_sec;
+
+       switch (op) {
+       case VOL_UPDATE:
+               break;
+       case VOL_MKDIR:
+               if (vcb->vcbDirCnt != 0xFFFFFFFF)
+                       ++vcb->vcbDirCnt;
+               if (inroot && vcb->vcbNmRtDirs != 0xFFFF)
+                       ++vcb->vcbNmRtDirs;
+               break;
+       case VOL_RMDIR:
+               if (vcb->vcbDirCnt != 0)
+                       --vcb->vcbDirCnt;
+               if (inroot && vcb->vcbNmRtDirs != 0xFFFF)
+                       --vcb->vcbNmRtDirs;
+               break;
+       case VOL_MKFILE:
+               if (vcb->vcbFilCnt != 0xFFFFFFFF)
+                       ++vcb->vcbFilCnt;
+               if (inroot && vcb->vcbNmFls != 0xFFFF)
+                       ++vcb->vcbNmFls;
+               break;
+       case VOL_RMFILE:
+               if (vcb->vcbFilCnt != 0)
+                       --vcb->vcbFilCnt;
+               if (inroot && vcb->vcbNmFls != 0xFFFF)
+                       --vcb->vcbNmFls;
+               break;
+       }
+
+       if (hfsmp->jnl) {
+               hfs_flushvolumeheader(hfsmp, 0, 0);
+       }
+
+       return (0);
+}
 
-       if (vcb->vcbSigWord != kHFSSigWord)
-               return EINVAL;
 
-    DBG_ASSERT(hfsmp->hfs_devvp != NULL);
+static int
+hfs_flushMDB(struct hfsmount *hfsmp, int waitfor, int altflush)
+{
+       ExtendedVCB *vcb = HFSTOVCB(hfsmp);
+       struct filefork *fp;
+       HFSMasterDirectoryBlock *mdb;
+       struct buf *bp = NULL;
+       int retval;
+       int sectorsize;
+       ByteCount namelen;
 
-       retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, size),
-                                       IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp);
+       sectorsize = hfsmp->hfs_phys_block_size;
+       retval = bread(hfsmp->hfs_devvp, HFS_PRI_SECTOR(sectorsize), sectorsize, NOCRED, &bp);
        if (retval) {
-           DBG_VFS((" hfs_flushMDB bread return error! (%d)\n", retval));
-               if (bp) brelse(bp);
+               if (bp)
+                       brelse(bp);
                return retval;
        }
 
-    DBG_ASSERT(bp != NULL);
-    DBG_ASSERT(bp->b_data != NULL);
-    DBG_ASSERT(bp->b_bcount == size);
+       DBG_ASSERT(bp != NULL);
+       DBG_ASSERT(bp->b_data != NULL);
+       DBG_ASSERT(bp->b_bcount == size);
+
+       if (hfsmp->jnl) {
+               panic("hfs: standard hfs volumes should not be journaled!\n");
+       }
 
-       mdb = (HFSMasterDirectoryBlock *)((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size));
+       mdb = (HFSMasterDirectoryBlock *)(bp->b_data + HFS_PRI_OFFSET(sectorsize));
     
-       VCB_LOCK(vcb);
-       mdb->drCrDate   = SWAP_BE32 (UTCToLocal(vcb->vcbCrDate));
-       mdb->drLsMod    = SWAP_BE32 (UTCToLocal(vcb->vcbLsMod));
-       mdb->drAtrb             = SWAP_BE16 (vcb->vcbAtrb);
+       mdb->drCrDate   = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbCrDate)));
+       mdb->drLsMod    = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbLsMod)));
+       mdb->drAtrb     = SWAP_BE16 (vcb->vcbAtrb);
        mdb->drNmFls    = SWAP_BE16 (vcb->vcbNmFls);
        mdb->drAllocPtr = SWAP_BE16 (vcb->nextAllocation);
        mdb->drClpSiz   = SWAP_BE32 (vcb->vcbClpSiz);
@@ -1704,7 +2156,7 @@ short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor)
        if (retval)
                retval = utf8_to_mac_roman(namelen, vcb->vcbVN, mdb->drVN);
        
-       mdb->drVolBkUp  = SWAP_BE32 (UTCToLocal(vcb->vcbVolBkUp));
+       mdb->drVolBkUp  = SWAP_BE32 (UTCToLocal(to_hfs_time(vcb->vcbVolBkUp)));
        mdb->drWrCnt    = SWAP_BE32 (vcb->vcbWrCnt);
        mdb->drNmRtDirs = SWAP_BE16 (vcb->vcbNmRtDirs);
        mdb->drFilCnt   = SWAP_BE32 (vcb->vcbFilCnt);
@@ -1712,34 +2164,44 @@ short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor)
        
        bcopy(vcb->vcbFndrInfo, mdb->drFndrInfo, sizeof(mdb->drFndrInfo));
 
-       fcb = VTOFCB(vcb->extentsRefNum);
-       /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drXTExtRec); */
-       mdb->drXTExtRec[0].startBlock = SWAP_BE16 (fcb->fcbExtents[0].startBlock);
-       mdb->drXTExtRec[0].blockCount = SWAP_BE16 (fcb->fcbExtents[0].blockCount);
-       mdb->drXTExtRec[1].startBlock = SWAP_BE16 (fcb->fcbExtents[1].startBlock);
-       mdb->drXTExtRec[1].blockCount = SWAP_BE16 (fcb->fcbExtents[1].blockCount);
-       mdb->drXTExtRec[2].startBlock = SWAP_BE16 (fcb->fcbExtents[2].startBlock);
-       mdb->drXTExtRec[2].blockCount = SWAP_BE16 (fcb->fcbExtents[2].blockCount);
-    
-       mdb->drXTFlSize = SWAP_BE32 (fcb->fcbPLen);
-       mdb->drXTClpSiz = SWAP_BE32 (fcb->fcbClmpSize);
+       fp = VTOF(vcb->extentsRefNum);
+       mdb->drXTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock);
+       mdb->drXTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount);
+       mdb->drXTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock);
+       mdb->drXTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount);
+       mdb->drXTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock);
+       mdb->drXTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount);
+       mdb->drXTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize);
+       mdb->drXTClpSiz = SWAP_BE32 (fp->ff_clumpsize);
        
-       fcb = VTOFCB(vcb->catalogRefNum);
-       /* HFSPlusToHFSExtents(fcb->fcbExtents, mdb->drCTExtRec); */
-       mdb->drCTExtRec[0].startBlock = SWAP_BE16 (fcb->fcbExtents[0].startBlock);
-       mdb->drCTExtRec[0].blockCount = SWAP_BE16 (fcb->fcbExtents[0].blockCount);
-       mdb->drCTExtRec[1].startBlock = SWAP_BE16 (fcb->fcbExtents[1].startBlock);
-       mdb->drCTExtRec[1].blockCount = SWAP_BE16 (fcb->fcbExtents[1].blockCount);
-       mdb->drCTExtRec[2].startBlock = SWAP_BE16 (fcb->fcbExtents[2].startBlock);
-       mdb->drCTExtRec[2].blockCount = SWAP_BE16 (fcb->fcbExtents[2].blockCount);
-    
-       mdb->drCTFlSize = SWAP_BE32 (fcb->fcbPLen);
-       mdb->drCTClpSiz = SWAP_BE32 (fcb->fcbClmpSize);
-       VCB_UNLOCK(vcb);
+       fp = VTOF(vcb->catalogRefNum);
+       mdb->drCTExtRec[0].startBlock = SWAP_BE16 (fp->ff_extents[0].startBlock);
+       mdb->drCTExtRec[0].blockCount = SWAP_BE16 (fp->ff_extents[0].blockCount);
+       mdb->drCTExtRec[1].startBlock = SWAP_BE16 (fp->ff_extents[1].startBlock);
+       mdb->drCTExtRec[1].blockCount = SWAP_BE16 (fp->ff_extents[1].blockCount);
+       mdb->drCTExtRec[2].startBlock = SWAP_BE16 (fp->ff_extents[2].startBlock);
+       mdb->drCTExtRec[2].blockCount = SWAP_BE16 (fp->ff_extents[2].blockCount);
+       mdb->drCTFlSize = SWAP_BE32 (fp->ff_blocks * vcb->blockSize);
+       mdb->drCTClpSiz = SWAP_BE32 (fp->ff_clumpsize);
+
+       /* If requested, flush out the alternate MDB */
+       if (altflush) {
+               struct buf *alt_bp = NULL;
+               u_long altIDSector;
+
+               altIDSector = HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
+
+               if (meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &alt_bp) == 0) {
+                       bcopy(mdb, alt_bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize);
+
+                       (void) VOP_BWRITE(alt_bp);
+               } else if (alt_bp)
+                       brelse(alt_bp);
+       }
 
-    if (waitfor != MNT_WAIT)
+       if (waitfor != MNT_WAIT)
                bawrite(bp);
-    else 
+       else 
                retval = VOP_BWRITE(bp);
  
        MarkVCBClean( vcb );
@@ -1748,150 +2210,246 @@ short hfs_flushMDB(struct hfsmount *hfsmp, int waitfor)
 }
 
 
-short hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor)
+__private_extern__
+int
+hfs_flushvolumeheader(struct hfsmount *hfsmp, int waitfor, int altflush)
 {
-    ExtendedVCB                        *vcb = HFSTOVCB(hfsmp);
-    FCB                                                *fcb;
-    HFSPlusVolumeHeader                *volumeHeader;
-    int                                                retval;
-    int                     size = sizeof(HFSPlusVolumeHeader);
-    struct buf                                 *bp;
-    int                                                i;
-
-       if (vcb->vcbSigWord != kHFSPlusSigWord)
-               return EINVAL;
+       ExtendedVCB *vcb = HFSTOVCB(hfsmp);
+       struct filefork *fp;
+       HFSPlusVolumeHeader *volumeHeader;
+       int retval;
+       struct buf *bp;
+       int i;
+       int sectorsize;
+       int priIDSector;
+       int critical = 0;
 
-       retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size),
-                                       IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp);
+       if (vcb->vcbSigWord == kHFSSigWord)
+               return hfs_flushMDB(hfsmp, waitfor, altflush);
+
+       if (altflush)
+               critical = 1;
+       sectorsize = hfsmp->hfs_phys_block_size;
+       priIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
+                       HFS_PRI_SECTOR(sectorsize);
+
+       // XXXdbg
+       hfs_global_shared_lock_acquire(hfsmp);
+       if (hfsmp->jnl) {
+               if (journal_start_transaction(hfsmp->jnl) != 0) {
+                       hfs_global_shared_lock_release(hfsmp);
+                   return EINVAL;
+           }
+       }
+
+       retval = meta_bread(hfsmp->hfs_devvp, priIDSector, sectorsize, NOCRED, &bp);
        if (retval) {
-           DBG_VFS((" hfs_flushvolumeheader bread return error! (%d)\n", retval));
-               if (bp) brelse(bp);
-               return retval;
+               if (bp)
+                       brelse(bp);
+
+               if (hfsmp->jnl) {
+                       journal_end_transaction(hfsmp->jnl);
+               }
+               hfs_global_shared_lock_release(hfsmp);
+
+               return (retval);
        }
 
-    DBG_ASSERT(bp != NULL);
-    DBG_ASSERT(bp->b_data != NULL);
-    DBG_ASSERT(bp->b_bcount == size);
+       if (hfsmp->jnl) {
+               journal_modify_block_start(hfsmp->jnl, bp);
+       }
 
-       volumeHeader = (HFSPlusVolumeHeader *)((char *)bp->b_data +
-                                       IOBYTEOFFSETFORBLK((vcb->hfsPlusIOPosOffset / 512) + kMasterDirectoryBlock, size));
+       volumeHeader = (HFSPlusVolumeHeader *)((char *)bp->b_data + HFS_PRI_OFFSET(sectorsize));
 
        /*
         * For embedded HFS+ volumes, update create date if it changed
         * (ie from a setattrlist call)
         */
-       if ((vcb->hfsPlusIOPosOffset != 0) && (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate))
-         {
-               struct buf                              *bp2;
+       if ((vcb->hfsPlusIOPosOffset != 0) &&
+           (SWAP_BE32 (volumeHeader->createDate) != vcb->localCreateDate)) {
+               struct buf *bp2;
                HFSMasterDirectoryBlock *mdb;
 
-               retval = bread(hfsmp->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, kMDBSize),
-                                               IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, kMDBSize), NOCRED, &bp2);
-               if (retval != E_NONE) {
-                       if (bp2) brelse(bp2);
+               retval = meta_bread(hfsmp->hfs_devvp, HFS_PRI_SECTOR(sectorsize),
+                               sectorsize, NOCRED, &bp2);
+               if (retval) {
+                       if (bp2)
+                               brelse(bp2);
+                       retval = 0;
                } else {
-                       mdb = (HFSMasterDirectoryBlock *)((char *)bp2->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, kMDBSize));
+                       mdb = (HFSMasterDirectoryBlock *)(bp2->b_data +
+                               HFS_PRI_OFFSET(sectorsize));
 
                        if ( SWAP_BE32 (mdb->drCrDate) != vcb->localCreateDate )
                          {
+                               // XXXdbg
+                               if (hfsmp->jnl) {
+                                   journal_modify_block_start(hfsmp->jnl, bp2);
+                               }
+
                                mdb->drCrDate = SWAP_BE32 (vcb->localCreateDate);       /* pick up the new create date */
 
-                               (void) VOP_BWRITE(bp2);         /* write out the changes */
+                               // XXXdbg
+                               if (hfsmp->jnl) {
+                                       journal_modify_block_end(hfsmp->jnl, bp2);
+                               } else {
+                                       (void) VOP_BWRITE(bp2);         /* write out the changes */
+                               }
                          }
                        else
                          {
                                brelse(bp2);                                            /* just release it */
                          }
                  }     
-         }
+       }
+
+// XXXdbg - only monkey around with the volume signature on non-root volumes
+//
+#if 0
+       if (hfsmp->jnl &&
+               hfsmp->hfs_fs_ronly == 0 &&
+               (HFSTOVFS(hfsmp)->mnt_flag & MNT_ROOTFS) == 0) {
+               
+               int old_sig = volumeHeader->signature;
+
+               if (vcb->vcbAtrb & kHFSVolumeUnmountedMask) {
+                       volumeHeader->signature = kHFSPlusSigWord;
+               } else {
+                       volumeHeader->signature = kHFSJSigWord;
+               }
+
+               if (old_sig != volumeHeader->signature) {
+                       altflush = 1;
+               }
+       }
+#endif
+// XXXdbg
 
-       VCB_LOCK(vcb);
        /* Note: only update the lower 16 bits worth of attributes */
-       volumeHeader->attributes                 =      SWAP_BE32 ((SWAP_BE32 (volumeHeader->attributes) & 0xFFFF0000) + (UInt16) vcb->vcbAtrb);
-       volumeHeader->lastMountedVersion =  SWAP_BE32 (kHFSPlusMountVersion);
-       volumeHeader->createDate                 =  SWAP_BE32 (vcb->localCreateDate);  /* volume create date is in local time */
-       volumeHeader->modifyDate                 =  SWAP_BE32 (vcb->vcbLsMod);
-       volumeHeader->backupDate                 =  SWAP_BE32 (vcb->vcbVolBkUp);
-       volumeHeader->checkedDate                =  SWAP_BE32 (vcb->checkedDate);
-       volumeHeader->fileCount                  =      SWAP_BE32 (vcb->vcbFilCnt);
-       volumeHeader->folderCount                =      SWAP_BE32 (vcb->vcbDirCnt);
-       volumeHeader->freeBlocks                 =      SWAP_BE32 (vcb->freeBlocks);
-       volumeHeader->nextAllocation     =      SWAP_BE32 (vcb->nextAllocation);
-       volumeHeader->rsrcClumpSize              =      SWAP_BE32 (vcb->vcbClpSiz);
-       volumeHeader->dataClumpSize              =      SWAP_BE32 (vcb->vcbClpSiz);
-       volumeHeader->nextCatalogID              =      SWAP_BE32 (vcb->vcbNxtCNID);
-       volumeHeader->writeCount                 =      SWAP_BE32 (vcb->vcbWrCnt);
-       volumeHeader->encodingsBitmap    =      SWAP_BE64 (vcb->encodingsBitmap);
-
-       bcopy( vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo) );
-
-       VCB_UNLOCK(vcb);
-
-       fcb = VTOFCB(vcb->extentsRefNum);
-       /* bcopy( fcb->fcbExtents, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) ); */
-    for (i = 0; i < kHFSPlusExtentDensity; i++) {
-        volumeHeader->extentsFile.extents[i].startBlock        = SWAP_BE32 (fcb->fcbExtents[i].startBlock);
-        volumeHeader->extentsFile.extents[i].blockCount        = SWAP_BE32 (fcb->fcbExtents[i].blockCount);
-    }
-    
-       fcb->fcbFlags &= ~fcbModifiedMask;
-       volumeHeader->extentsFile.logicalSize = SWAP_BE64 (fcb->fcbEOF);
-       volumeHeader->extentsFile.totalBlocks = SWAP_BE32 (fcb->fcbPLen / vcb->blockSize);
-       volumeHeader->extentsFile.clumpSize   = SWAP_BE32 (fcb->fcbClmpSize);
-
-       fcb = VTOFCB(vcb->catalogRefNum);
-       /* bcopy( fcb->fcbExtents, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) ); */
-    for (i = 0; i < kHFSPlusExtentDensity; i++) {
-        volumeHeader->catalogFile.extents[i].startBlock        = SWAP_BE32 (fcb->fcbExtents[i].startBlock);
-        volumeHeader->catalogFile.extents[i].blockCount        = SWAP_BE32 (fcb->fcbExtents[i].blockCount);
-    }
-    
-       fcb->fcbFlags &= ~fcbModifiedMask;
-       volumeHeader->catalogFile.logicalSize = SWAP_BE64 (fcb->fcbEOF);
-       volumeHeader->catalogFile.totalBlocks = SWAP_BE32 (fcb->fcbPLen / vcb->blockSize);
-       volumeHeader->catalogFile.clumpSize   = SWAP_BE32 (fcb->fcbClmpSize);
-
-       fcb = VTOFCB(vcb->allocationsRefNum);
-       /* bcopy( fcb->fcbExtents, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) ); */
-    for (i = 0; i < kHFSPlusExtentDensity; i++) {
-        volumeHeader->allocationFile.extents[i].startBlock     = SWAP_BE32 (fcb->fcbExtents[i].startBlock);
-        volumeHeader->allocationFile.extents[i].blockCount     = SWAP_BE32 (fcb->fcbExtents[i].blockCount);
-    }
-    
-       fcb->fcbFlags &= ~fcbModifiedMask;
-       volumeHeader->allocationFile.logicalSize = SWAP_BE64 (fcb->fcbEOF);
-       volumeHeader->allocationFile.totalBlocks = SWAP_BE32 (fcb->fcbPLen / vcb->blockSize);
-       volumeHeader->allocationFile.clumpSize   = SWAP_BE32 (fcb->fcbClmpSize);
-
-    if (waitfor != MNT_WAIT)
-        bawrite(bp);
-    else 
-               retval = VOP_BWRITE(bp);
-       MarkVCBClean( vcb );
+       volumeHeader->attributes        = SWAP_BE32 ((SWAP_BE32 (volumeHeader->attributes) & 0xFFFF0000) + (UInt16) vcb->vcbAtrb);
+       volumeHeader->journalInfoBlock = SWAP_BE32(vcb->vcbJinfoBlock);
+       if (hfsmp->jnl) {
+               volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSJMountVersion);
+       } else {
+               volumeHeader->lastMountedVersion = SWAP_BE32 (kHFSPlusMountVersion);
+       }
+       volumeHeader->createDate        = SWAP_BE32 (vcb->localCreateDate);  /* volume create date is in local time */
+       volumeHeader->modifyDate        = SWAP_BE32 (to_hfs_time(vcb->vcbLsMod));
+       volumeHeader->backupDate        = SWAP_BE32 (to_hfs_time(vcb->vcbVolBkUp));
+       volumeHeader->fileCount         = SWAP_BE32 (vcb->vcbFilCnt);
+       volumeHeader->folderCount       = SWAP_BE32 (vcb->vcbDirCnt);
+       volumeHeader->freeBlocks        = SWAP_BE32 (vcb->freeBlocks);
+       volumeHeader->nextAllocation    = SWAP_BE32 (vcb->nextAllocation);
+       volumeHeader->rsrcClumpSize     = SWAP_BE32 (vcb->vcbClpSiz);
+       volumeHeader->dataClumpSize     = SWAP_BE32 (vcb->vcbClpSiz);
+       volumeHeader->nextCatalogID     = SWAP_BE32 (vcb->vcbNxtCNID);
+       volumeHeader->writeCount        = SWAP_BE32 (vcb->vcbWrCnt);
+       volumeHeader->encodingsBitmap   = SWAP_BE64 (vcb->encodingsBitmap);
+
+       if (bcmp(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo)) != 0)
+               critical = 1;
+       bcopy(vcb->vcbFndrInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo));
+
+       /* Sync Extents over-flow file meta data */
+       fp = VTOF(vcb->extentsRefNum);
+       for (i = 0; i < kHFSPlusExtentDensity; i++) {
+               volumeHeader->extentsFile.extents[i].startBlock =
+                       SWAP_BE32 (fp->ff_extents[i].startBlock);
+               volumeHeader->extentsFile.extents[i].blockCount =
+                       SWAP_BE32 (fp->ff_extents[i].blockCount);
+       }
+       FTOC(fp)->c_flag &= ~C_MODIFIED;
+       volumeHeader->extentsFile.logicalSize = SWAP_BE64 (fp->ff_size);
+       volumeHeader->extentsFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
+       volumeHeader->extentsFile.clumpSize   = SWAP_BE32 (fp->ff_clumpsize);
+
+       /* Sync Catalog file meta data */
+       fp = VTOF(vcb->catalogRefNum);
+       for (i = 0; i < kHFSPlusExtentDensity; i++) {
+               volumeHeader->catalogFile.extents[i].startBlock =
+                       SWAP_BE32 (fp->ff_extents[i].startBlock);
+               volumeHeader->catalogFile.extents[i].blockCount =
+                       SWAP_BE32 (fp->ff_extents[i].blockCount);
+       }
+       FTOC(fp)->c_flag &= ~C_MODIFIED;
+       volumeHeader->catalogFile.logicalSize = SWAP_BE64 (fp->ff_size);
+       volumeHeader->catalogFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
+       volumeHeader->catalogFile.clumpSize   = SWAP_BE32 (fp->ff_clumpsize);
+
+       /* Sync Allocation file meta data */
+       fp = VTOF(vcb->allocationsRefNum);
+       for (i = 0; i < kHFSPlusExtentDensity; i++) {
+               volumeHeader->allocationFile.extents[i].startBlock =
+                       SWAP_BE32 (fp->ff_extents[i].startBlock);
+               volumeHeader->allocationFile.extents[i].blockCount =
+                       SWAP_BE32 (fp->ff_extents[i].blockCount);
+       }
+       FTOC(fp)->c_flag &= ~C_MODIFIED;
+       volumeHeader->allocationFile.logicalSize = SWAP_BE64 (fp->ff_size);
+       volumeHeader->allocationFile.totalBlocks = SWAP_BE32 (fp->ff_blocks);
+       volumeHeader->allocationFile.clumpSize   = SWAP_BE32 (fp->ff_clumpsize);
+
+       /* If requested, flush out the alternate volume header */
+       if (altflush) {
+               struct buf *alt_bp = NULL;
+               u_long altIDSector;
+
+               altIDSector = (vcb->hfsPlusIOPosOffset / sectorsize) +
+                       HFS_ALT_SECTOR(sectorsize, hfsmp->hfs_phys_block_count);
+
+               if (meta_bread(hfsmp->hfs_devvp, altIDSector, sectorsize, NOCRED, &alt_bp) == 0) {
+                       if (hfsmp->jnl) {
+                               journal_modify_block_start(hfsmp->jnl, alt_bp);
+                       }
+
+                       bcopy(volumeHeader, alt_bp->b_data + HFS_ALT_OFFSET(sectorsize), kMDBSize);
 
+                       if (hfsmp->jnl) {
+                               journal_modify_block_end(hfsmp->jnl, alt_bp);
+                       } else {
+                               (void) VOP_BWRITE(alt_bp);
+                       }
+               } else if (alt_bp)
+                       brelse(alt_bp);
+       }
+
+       // XXXdbg
+       if (hfsmp->jnl) {
+               journal_modify_block_end(hfsmp->jnl, bp);
+               journal_end_transaction(hfsmp->jnl);
+       } else {
+               if (waitfor != MNT_WAIT)
+                       bawrite(bp);
+               else {
+                   retval = VOP_BWRITE(bp);
+                   /* When critical data changes, flush the device cache */
+                   if (critical && (retval == 0)) {
+                       (void) VOP_IOCTL(hfsmp->hfs_devvp, DKIOCSYNCHRONIZECACHE,
+                                        NULL, FWRITE, NOCRED, current_proc());
+                   }
+               }
+       }
+       hfs_global_shared_lock_release(hfsmp);
+       vcb->vcbFlags &= 0x00FF;
        return (retval);
 }
 
 
-/*
- *      Moved here to avoid having to define prototypes
- */
-
 /*
  * hfs vfs operations.
  */
 struct vfsops hfs_vfsops = {
-    hfs_mount,
-    hfs_start,
-    hfs_unmount,
-    hfs_root,
-    hfs_quotactl,
-    hfs_statfs,
-    hfs_sync,
-    hfs_vget,
-    hfs_fhtovp,
-    hfs_vptofh,
-    hfs_init,
-    hfs_sysctl
+       hfs_mount,
+       hfs_start,
+       hfs_unmount,
+       hfs_root,
+       hfs_quotactl,
+       hfs_statfs,
+       hfs_sync,
+       hfs_vget,
+       hfs_fhtovp,
+       hfs_vptofh,
+       hfs_init,
+       hfs_sysctl
 };