]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfscommon/Misc/FileExtentMapping.c
xnu-3247.10.11.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / Misc / FileExtentMapping.c
index 998f97fa930b04bf808cd011b091c16ec0b80988..31249e05bff3d738cf63b0ae974d31dbcddafb21 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2014 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -35,6 +35,7 @@
 #include "../headers/BTreesInternal.h"
 
 #include <sys/malloc.h>
+#include <sys/vnode_internal.h>
  
 /*
 ============================================================
@@ -66,7 +67,9 @@ Public (Exported) Routines:
        FlushExtentFile
                                        Flush the extents file for a given volume.
 
-
+       SearchExtentFile
+                                       Search the FCB and extents file for an extent record that
+                                       contains a given file position (in bytes).
 
 
 ============================================================
@@ -74,9 +77,6 @@ Internal Routines:
 ============================================================
        FindExtentRecord
                                        Search the extents BTree for a particular extent record.
-       SearchExtentFile
-                                       Search the FCB and extents file for an extent record that
-                                       contains a given file position (in bytes).
        SearchExtentRecord
                                        Search a given extent record to see if it contains a given
                                        file position (in bytes).  Used by SearchExtentFile.
@@ -97,7 +97,9 @@ Internal Routines:
                                        and was in the extents file, then delete the record instead.
 */
 
+#if CONFIG_HFS_STD
 static const int64_t kTwoGigabytes = 0x80000000LL;
+#endif
 
 enum
 {
@@ -108,9 +110,11 @@ enum
 };
 
 
+#if CONFIG_HFS_STD
 static OSErr HFSPlusToHFSExtents(
        const HFSPlusExtentRecord       oldExtents,
        HFSExtentRecord                         newExtents);
+#endif
 
 static OSErr FindExtentRecord(
        const ExtendedVCB               *vcb,
@@ -139,16 +143,6 @@ static OSErr GetFCBExtentRecord(
        const FCB                               *fcb,
        HFSPlusExtentRecord             extents);
 
-static OSErr SearchExtentFile(
-       ExtendedVCB             *vcb,
-       const FCB                               *fcb,
-       int64_t                                 filePosition,
-       HFSPlusExtentKey                *foundExtentKey,
-       HFSPlusExtentRecord             foundExtentData,
-       u_int32_t                               *foundExtentDataIndex,
-       u_int32_t                               *extentBTreeHint,
-       u_int32_t                               *endingFABNPlusOne );
-
 static OSErr SearchExtentRecord(
        ExtendedVCB             *vcb,
        u_int32_t                               searchFABN,
@@ -225,7 +219,7 @@ static OSErr FindExtentRecord(
        u_int32_t                       *foundHint)
 {
        FCB *                           fcb;
-       BTreeIterator           btIterator;
+       struct BTreeIterator *btIterator = NULL;
        FSBufferDescriptor      btRecord;
        OSErr                           err;
        u_int16_t                       btRecordSize;
@@ -234,14 +228,60 @@ static OSErr FindExtentRecord(
        if (foundHint)
                *foundHint = 0;
        fcb = GetFileControlBlock(vcb->extentsRefNum);
-       
-       bzero(&btIterator, sizeof(btIterator));
 
-       if (vcb->vcbSigWord == kHFSSigWord) {
+       MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
+       if (btIterator == NULL) {
+               return memFullErr;  // translates to ENOMEM
+       }
+       bzero(btIterator, sizeof(*btIterator));
+
+       /* HFS Plus / HFSX */
+       if (vcb->vcbSigWord != kHFSSigWord) {
+               HFSPlusExtentKey *      extentKeyPtr;
+               HFSPlusExtentRecord     extentData;
+
+               extentKeyPtr = (HFSPlusExtentKey*) &btIterator->key;
+               extentKeyPtr->keyLength  = kHFSPlusExtentKeyMaximumLength;
+               extentKeyPtr->forkType   = forkType;
+               extentKeyPtr->pad                = 0;
+               extentKeyPtr->fileID     = fileID;
+               extentKeyPtr->startBlock = startBlock;
+               
+               btRecord.bufferAddress = &extentData;
+               btRecord.itemSize = sizeof(HFSPlusExtentRecord);
+               btRecord.itemCount = 1;
+
+               err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator);
+
+               if (err == btNotFound && allowPrevious) {
+                       err = BTIterateRecord(fcb, kBTreePrevRecord, btIterator, &btRecord, &btRecordSize);
+
+                       //      A previous record may not exist, so just return btNotFound (like we would if
+                       //      it was for the wrong file/fork).
+                       if (err == (OSErr) fsBTStartOfIterationErr)             //¥¥ fsBTStartOfIterationErr is type unsigned long
+                               err = btNotFound;
+
+                       if (err == noErr) {
+                               //      Found a previous record.  Does it belong to the same fork of the same file?
+                               if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType)
+                                       err = btNotFound;
+                       }
+               }
+
+               if (err == noErr) {
+                       // Copy the found key back for the caller
+                       if (foundKey)
+                               BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey));
+                       // Copy the found data back for the caller
+                       BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord));
+               }
+       }
+#if CONFIG_HFS_STD
+       else { 
                HFSExtentKey *          extentKeyPtr;
                HFSExtentRecord         extentData;
 
-               extentKeyPtr = (HFSExtentKey*) &btIterator.key;
+               extentKeyPtr = (HFSExtentKey*) &btIterator->key;
                extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength;
                extentKeyPtr->forkType = forkType;
                extentKeyPtr->fileID = fileID;
@@ -251,10 +291,10 @@ static OSErr FindExtentRecord(
                btRecord.itemSize = sizeof(HFSExtentRecord);
                btRecord.itemCount = 1;
 
-               err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator);
+               err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator);
 
                if (err == btNotFound && allowPrevious) {
-                       err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize);
+                       err = BTIterateRecord(fcb, kBTreePrevRecord, btIterator, &btRecord, &btRecordSize);
 
                        //      A previous record may not exist, so just return btNotFound (like we would if
                        //      it was for the wrong file/fork).
@@ -294,49 +334,12 @@ static OSErr FindExtentRecord(
                        }
                }
        }
-       else {          // HFS Plus volume
-               HFSPlusExtentKey *      extentKeyPtr;
-               HFSPlusExtentRecord     extentData;
-
-               extentKeyPtr = (HFSPlusExtentKey*) &btIterator.key;
-               extentKeyPtr->keyLength  = kHFSPlusExtentKeyMaximumLength;
-               extentKeyPtr->forkType   = forkType;
-               extentKeyPtr->pad                = 0;
-               extentKeyPtr->fileID     = fileID;
-               extentKeyPtr->startBlock = startBlock;
-               
-               btRecord.bufferAddress = &extentData;
-               btRecord.itemSize = sizeof(HFSPlusExtentRecord);
-               btRecord.itemCount = 1;
-
-               err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator);
-
-               if (err == btNotFound && allowPrevious) {
-                       err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize);
-
-                       //      A previous record may not exist, so just return btNotFound (like we would if
-                       //      it was for the wrong file/fork).
-                       if (err == (OSErr) fsBTStartOfIterationErr)             //¥¥ fsBTStartOfIterationErr is type unsigned long
-                               err = btNotFound;
-
-                       if (err == noErr) {
-                               //      Found a previous record.  Does it belong to the same fork of the same file?
-                               if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType)
-                                       err = btNotFound;
-                       }
-               }
-
-               if (err == noErr) {
-                       // Copy the found key back for the caller
-                       if (foundKey)
-                               BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey));
-                       // Copy the found data back for the caller
-                       BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord));
-               }
-       }
+#endif
 
        if (foundHint)
-               *foundHint = btIterator.hint.nodeNum;
+               *foundHint = btIterator->hint.nodeNum;
+
+       FREE(btIterator, M_TEMP);
        return err;
 }
 
@@ -348,7 +351,7 @@ static OSErr CreateExtentRecord(
        HFSPlusExtentRecord     extents,
        u_int32_t                       *hint)
 {
-       BTreeIterator btIterator;
+       struct BTreeIterator *btIterator = NULL;
        FSBufferDescriptor      btRecord;
        u_int16_t  btRecordSize;
        int  lockflags;
@@ -357,7 +360,11 @@ static OSErr CreateExtentRecord(
        err = noErr;
        *hint = 0;
 
-       bzero(&btIterator, sizeof(btIterator));
+       MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
+       if (btIterator == NULL) {
+               return memFullErr;  // translates to ENOMEM
+       }
+       bzero(btIterator, sizeof(*btIterator));
 
        /*
         * The lock taken by callers of ExtendFileC is speculative and
@@ -368,7 +375,18 @@ static OSErr CreateExtentRecord(
         */
        lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK);
 
-       if (vcb->vcbSigWord == kHFSSigWord) {
+       /* HFS+/HFSX */
+       if (vcb->vcbSigWord != kHFSSigWord) {
+               btRecordSize = sizeof(HFSPlusExtentRecord);
+               btRecord.bufferAddress = extents;
+               btRecord.itemSize = btRecordSize;
+               btRecord.itemCount = 1;
+
+               BlockMoveData(key, &btIterator->key, sizeof(HFSPlusExtentKey));
+       }
+#if CONFIG_HFS_STD
+       else {
+               /* HFS Standard */
                HFSExtentKey *          keyPtr;
                HFSExtentRecord         data;
                
@@ -377,7 +395,7 @@ static OSErr CreateExtentRecord(
                btRecord.itemSize = btRecordSize;
                btRecord.itemCount = 1;
 
-               keyPtr = (HFSExtentKey*) &btIterator.key;
+               keyPtr = (HFSExtentKey*) &btIterator->key;
                keyPtr->keyLength       = kHFSExtentKeyMaximumLength;
                keyPtr->forkType        = key->forkType;
                keyPtr->fileID          = key->fileID;
@@ -385,25 +403,19 @@ static OSErr CreateExtentRecord(
                
                err = HFSPlusToHFSExtents(extents, data);
        }
-       else {          // HFS Plus volume
-               btRecordSize = sizeof(HFSPlusExtentRecord);
-               btRecord.bufferAddress = extents;
-               btRecord.itemSize = btRecordSize;
-               btRecord.itemCount = 1;
-
-               BlockMoveData(key, &btIterator.key, sizeof(HFSPlusExtentKey));
-       }
+#endif
 
        if (err == noErr)
-               err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator, &btRecord, btRecordSize);
+               err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator, &btRecord, btRecordSize);
 
        if (err == noErr)
-               *hint = btIterator.hint.nodeNum;
+               *hint = btIterator->hint.nodeNum;
 
        (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum));
        
        hfs_systemfile_unlock(vcb, lockflags);
-       
+
+       FREE (btIterator, M_TEMP);      
        return err;
 }
 
@@ -414,36 +426,46 @@ static OSErr DeleteExtentRecord(
        u_int32_t                       fileID,
        u_int32_t                       startBlock)
 {
-       BTreeIterator btIterator;
+       struct BTreeIterator *btIterator = NULL;
        OSErr                           err;
        
        err = noErr;
 
-       bzero(&btIterator, sizeof(btIterator));
+       MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
+       if (btIterator == NULL) {
+               return memFullErr;  // translates to ENOMEM
+       }
+       bzero(btIterator, sizeof(*btIterator));
        
-       if (vcb->vcbSigWord == kHFSSigWord) {
-               HFSExtentKey *  keyPtr;
+       /* HFS+ / HFSX */
+       if (vcb->vcbSigWord != kHFSSigWord) {           //      HFS Plus volume
+               HFSPlusExtentKey *      keyPtr;
 
-               keyPtr = (HFSExtentKey*) &btIterator.key;
-               keyPtr->keyLength       = kHFSExtentKeyMaximumLength;
+               keyPtr = (HFSPlusExtentKey*) &btIterator->key;
+               keyPtr->keyLength       = kHFSPlusExtentKeyMaximumLength;
                keyPtr->forkType        = forkType;
+               keyPtr->pad                     = 0;
                keyPtr->fileID          = fileID;
                keyPtr->startBlock      = startBlock;
        }
-       else {          //      HFS Plus volume
-               HFSPlusExtentKey *      keyPtr;
+#if CONFIG_HFS_STD
+       else {
+               /* HFS standard */
+               HFSExtentKey *  keyPtr;
 
-               keyPtr = (HFSPlusExtentKey*) &btIterator.key;
-               keyPtr->keyLength       = kHFSPlusExtentKeyMaximumLength;
+               keyPtr = (HFSExtentKey*) &btIterator->key;
+               keyPtr->keyLength       = kHFSExtentKeyMaximumLength;
                keyPtr->forkType        = forkType;
-               keyPtr->pad                     = 0;
                keyPtr->fileID          = fileID;
                keyPtr->startBlock      = startBlock;
        }
+#endif
 
-       err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator);
+       err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator);
        (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum));
        
+
+       FREE(btIterator, M_TEMP);
        return err;
 }
 
@@ -497,7 +519,6 @@ OSErr MapFileBlockC (
        //
        //      Determine the end of the available space.  It will either be the end of the extent,
        //      or the file's PEOF, whichever is smaller.
-       
        //
        dataEnd = (off_t)((off_t)(nextFABN) * (off_t)(allocBlockSize));   // Assume valid data through end of this extent
        if (((off_t)fcb->ff_blocks * (off_t)allocBlockSize) < dataEnd)    // Is PEOF shorter?
@@ -536,10 +557,13 @@ OSErr MapFileBlockC (
                if (tmpOff <= 0) {
                        return EINVAL;
                }
-               if (tmpOff > (off_t)(numberOfBytes))
+
+               if (tmpOff > (off_t)(numberOfBytes)) {
                        *availableBytes = numberOfBytes;  // more there than they asked for, so pin the output
-               else
+               }
+               else {
                        *availableBytes = tmpOff;
+               }
        }
 
        return noErr;
@@ -716,6 +740,7 @@ OSErr FlushExtentFile( ExtendedVCB *vcb )
 }
 
 
+#if CONFIG_HFS_STD
 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
 //     Routine:        CompareExtentKeys
 //
@@ -777,7 +802,7 @@ int32_t CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *tr
        
        return( result );
 }
-
+#endif
 
 
 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
@@ -842,6 +867,69 @@ int32_t CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusE
        return( result );
 }
 
+static int
+should_pin_blocks(hfsmount_t *hfsmp, FCB *fcb)
+{
+       if (!ISSET(hfsmp->hfs_flags, HFS_CS_HOTFILE_PIN)
+               || fcb->ff_cp == NULL || fcb->ff_cp->c_vp == NULL) {
+               return 0;
+       }
+
+       int pin_blocks;
+
+       //
+       // File system metadata should get pinned
+       //
+       if (vnode_issystem(fcb->ff_cp->c_vp)) {
+               return 1;
+       }
+
+       //
+       // If a file is AutoCandidate, we should not pin its blocks because
+       // it was an automatically added file and this function is intended
+       // to pin new blocks being added to user-generated content.
+       //
+       if (fcb->ff_cp->c_attr.ca_recflags & kHFSAutoCandidateMask) {
+               return 0;
+       }
+
+       //
+       // If a file is marked FastDevPinned it is an existing pinned file 
+       // or a new file that should be pinned.
+       //
+       // If a file is marked FastDevCandidate it is a new file that is
+       // being written to for the first time so we don't want to pin it
+       // just yet as it may not meet the criteria (i.e. too large).
+       //
+       if ((fcb->ff_cp->c_attr.ca_recflags & (kHFSFastDevPinnedMask)) != 0) {
+               pin_blocks = 1;
+       } else {
+               pin_blocks = 0;
+       }
+
+       return pin_blocks;
+}
+       
+
+
+static void
+pin_blocks_if_needed(ExtendedVCB *vcb, FCB *fcb, u_int32_t startBlock, u_int32_t blockCount)   
+{
+       if (!should_pin_blocks(vcb, fcb)) {
+               return;
+       }
+       
+       // ask CoreStorage to pin the new blocks being added to this file
+       if (hfs_pin_block_range((struct hfsmount *)vcb, HFS_PIN_IT, startBlock, blockCount, vfs_context_kernel()) == 0) {
+               struct vnode *vp = fcb->ff_cp->c_vp;
+               
+               // and make sure to keep our accounting in order
+               hfs_hotfile_adjust_blocks(vp, -blockCount);
+       }
+}
+
+
+
 /*
  * Add a file extent to a file.
  *
@@ -893,8 +981,12 @@ AddFileExtent(ExtendedVCB *vcb, FCB *fcb, u_int32_t startBlock, u_int32_t blockC
                foundIndex = 0;
 
                error = CreateExtentRecord(vcb, &foundKey, foundData, &hint);
-               if (error == fxOvFlErr)
+               if (error == fxOvFlErr) {
                        error = dskFulErr;
+               } else if (error == 0) {
+                       pin_blocks_if_needed(vcb, fcb, startBlock, blockCount);
+               }
+               
        } else {
                /* 
                 * Add a new extent into existing record.
@@ -902,6 +994,9 @@ AddFileExtent(ExtendedVCB *vcb, FCB *fcb, u_int32_t startBlock, u_int32_t blockC
                foundData[foundIndex].startBlock = startBlock;
                foundData[foundIndex].blockCount = blockCount;
                error = UpdateExtentRecord(vcb, fcb, 0, &foundKey, foundData, hint);
+               if (error == 0) {
+                       pin_blocks_if_needed(vcb, fcb, startBlock, blockCount);
+               }
        }
        (void) FlushExtentFile(vcb);
 
@@ -940,6 +1035,7 @@ OSErr ExtendFileC (
        Boolean                         wantContig;
        Boolean                         useMetaZone;
        Boolean                         needsFlush;
+       int                                     allowFlushTxns;
        u_int32_t                       actualStartBlock;
        u_int32_t                       actualNumBlocks;
        u_int32_t                       numExtentsPerRecord;
@@ -947,8 +1043,10 @@ OSErr ExtendFileC (
        int64_t                         availbytes;
        int64_t                         peof;
        u_int32_t                       prevblocks;
-       
+       uint32_t                        fastdev = 0;
 
+       struct hfsmount *hfsmp = (struct hfsmount*)vcb; 
+       allowFlushTxns = 0;
        needsFlush = false;
        *actualBytesAdded = 0;
        volumeBlockSize = vcb->blockSize;
@@ -956,20 +1054,22 @@ OSErr ExtendFileC (
        forceContig = ((flags & kEFContigMask) != 0);
        prevblocks = fcb->ff_blocks;
 
-       if (vcb->vcbSigWord == kHFSPlusSigWord)
+       if (vcb->vcbSigWord != kHFSSigWord) {
                numExtentsPerRecord = kHFSPlusExtentDensity;
-       else
+       }
+#if CONFIG_HFS_STD
+       else {
+               /* HFS Standard */
                numExtentsPerRecord = kHFSExtentDensity;
 
-       //
-       //      Make sure the request and new PEOF are less than 2GB if HFS.
-       //
-       if (vcb->vcbSigWord == kHFSSigWord) {
+               /* Make sure the request and new PEOF are less than 2GB if HFS std*/
                if (bytesToAdd >=  kTwoGigabytes)
-                       goto Overflow;
+                       goto HFS_Std_Overflow;
                if ((((int64_t)fcb->ff_blocks * (int64_t)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes)
-                       goto Overflow;
+                       goto HFS_Std_Overflow;
        }
+#endif
+
        //
        //      Determine how many blocks need to be allocated.
        //      Round up the number of desired bytes to add.
@@ -984,15 +1084,20 @@ OSErr ExtendFileC (
        &&  (vcb->vcbSigWord == kHFSPlusSigWord)
        &&  (bytesToAdd < (int64_t)HFS_MAX_DEFERED_ALLOC)
        &&  (blocksToAdd < hfs_freeblks(VCBTOHFS(vcb), 1))) {
-               HFS_MOUNT_LOCK(vcb, TRUE);
+               hfs_lock_mount (hfsmp);
                vcb->loanedBlocks += blocksToAdd;
-               HFS_MOUNT_UNLOCK(vcb, TRUE);
+               hfs_unlock_mount(hfsmp);
 
                fcb->ff_unallocblocks += blocksToAdd;
                FTOC(fcb)->c_blocks   += blocksToAdd;
                fcb->ff_blocks        += blocksToAdd;
 
-               FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE;
+               /*
+                * We haven't touched the disk here; no blocks have been
+                * allocated and the volume will not be inconsistent if we
+                * don't update the catalog record immediately.
+                */
+               FTOC(fcb)->c_flag |= C_MINOR_MOD;
                *actualBytesAdded = bytesToAdd;
                return (0);
        }
@@ -1009,9 +1114,9 @@ OSErr ExtendFileC (
                fcb->ff_blocks -= loanedBlocks;
                fcb->ff_unallocblocks  = 0;
 
-               HFS_MOUNT_LOCK(vcb, TRUE);
+               hfs_lock_mount(hfsmp);
                vcb->loanedBlocks -= loanedBlocks;
-               HFS_MOUNT_UNLOCK(vcb, TRUE);
+               hfs_unlock_mount(hfsmp);
        }
 
        //
@@ -1028,18 +1133,20 @@ OSErr ExtendFileC (
                maximumBytes = bytesToAdd;
        }
        
+#if CONFIG_HFS_STD
        //
        //      Compute new physical EOF, rounded up to a multiple of a block.
        //
        if ( (vcb->vcbSigWord == kHFSSigWord) &&                //      Too big?
                 ((((int64_t)fcb->ff_blocks * (int64_t)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes) ) {
                if (allOrNothing)                                       // Yes, must they have it all?
-                       goto Overflow;                                          // Yes, can't have it
+                       goto HFS_Std_Overflow;                                          // Yes, can't have it
                else {
                        --blocksToAdd;                                          // No, give give 'em one block less
                        bytesToAdd -= volumeBlockSize;
                }
        }
+#endif
 
        //
        //      If allocation is all-or-nothing, make sure there are
@@ -1060,7 +1167,7 @@ OSErr ExtendFileC (
                //      Enough blocks are already allocated.  Just update the FCB to reflect the new length.
                fcb->ff_blocks = peof / volumeBlockSize;
                FTOC(fcb)->c_blocks += (bytesToAdd / volumeBlockSize);
-               FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE;
+               FTOC(fcb)->c_flag |= C_MODIFIED;
                goto Exit;
        }
        if (err != fxRangeErr)          // Any real error?
@@ -1131,6 +1238,10 @@ OSErr ExtendFileC (
        else {
                wantContig = true;
        }
+
+       if (should_pin_blocks(hfsmp, fcb))
+               fastdev = HFS_ALLOC_FAST_DEV;
+
        useMetaZone = flags & kEFMetadataMask;
        do {
                if (blockHint != 0)
@@ -1147,23 +1258,45 @@ OSErr ExtendFileC (
                if (availbytes <= 0) {
                        err = dskFulErr;
                } else {
-                       if (wantContig && (availbytes < bytesToAdd))
+                       if (wantContig && (availbytes < bytesToAdd)) {
                                err = dskFulErr;
+                       }
                        else {
+                               uint32_t ba_flags = fastdev;
+
+                               if (wantContig) {
+                                       ba_flags |= HFS_ALLOC_FORCECONTIG;      
+                               }
+                               if (useMetaZone) {
+                                       ba_flags |= HFS_ALLOC_METAZONE;
+                               }
+                               if (allowFlushTxns) {
+                                       ba_flags |= HFS_ALLOC_FLUSHTXN;
+                               }
+
                                err = BlockAllocate(
                                                  vcb,
                                                  startBlock,
                                                  howmany(MIN(bytesToAdd, availbytes), volumeBlockSize),
                                                  howmany(MIN(maximumBytes, availbytes), volumeBlockSize),
-                                                 (wantContig ? HFS_ALLOC_FORCECONTIG : 0) | 
-                                                 (useMetaZone ? HFS_ALLOC_METAZONE : 0),
+                                                 ba_flags,
                                                  &actualStartBlock,
                                                  &actualNumBlocks);
                        }
                }
                if (err == dskFulErr) {
-                       if (forceContig)
-                               break;                  // AllocContig failed because not enough contiguous space
+                       if (forceContig) {
+                               if (allowFlushTxns == 0) {
+                                       /* If we're forcing contiguity, re-try but allow plucking from recently freed regions */
+                                       allowFlushTxns = 1;
+                                       wantContig = 1;
+                                       err = noErr;
+                                       continue;
+                               }
+                               else {
+                                       break;                  // AllocContig failed because not enough contiguous space
+                               }
+                       }
                        if (wantContig) {
                                //      Couldn't get one big chunk, so get whatever we can.
                                err = noErr;
@@ -1172,20 +1305,23 @@ OSErr ExtendFileC (
                        }
                        if (actualNumBlocks != 0)
                                err = noErr;
+
                        if (useMetaZone == 0) {
                                /* Couldn't get anything so dip into metadat zone */
                                err = noErr;
                                useMetaZone = 1;
                                continue;
                        }
-               }
-               if (err == noErr) {
-                   if (actualNumBlocks != 0) {
-                               // this catalog entry *must* get forced to disk when
-                               // hfs_update() is called
-                               FTOC(fcb)->c_flag |= C_FORCEUPDATE;
+
+                       /* If we couldn't find what we needed without flushing the journal, then go ahead and do it now */
+                       if (allowFlushTxns == 0) {
+                               allowFlushTxns = 1;
+                               err = noErr;
+                               continue;
                        }
 
+               }
+               if (err == noErr) {
                        //      Add the new extent to the existing extent record, or create a new one.
                        if ((actualStartBlock == startBlock) && (blockHint == 0)) {
                                //      We grew the file's last extent, so just adjust the number of blocks.
@@ -1248,7 +1384,7 @@ OSErr ExtendFileC (
                                        if (err != noErr) break;
                                }
                        }
-                       
+
                        // Figure out how many bytes were actually allocated.
                        // NOTE: BlockAllocate could have allocated more than we asked for.
                        // Don't set the PEOF beyond what our client asked for.
@@ -1263,7 +1399,7 @@ OSErr ExtendFileC (
                        }
                        fcb->ff_blocks += (bytesThisExtent / volumeBlockSize);
                        FTOC(fcb)->c_blocks += (bytesThisExtent / volumeBlockSize);
-                       FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE;
+                       FTOC(fcb)->c_flag |= C_MODIFIED;
 
                        //      If contiguous allocation was requested, then we've already got one contiguous
                        //      chunk.  If we didn't get all we wanted, then adjust the error to disk full.
@@ -1281,10 +1417,10 @@ Exit:
                /* Keep the roving allocator out of the metadata zone. */
                if (vcb->nextAllocation >= VCBTOHFS(vcb)->hfs_metazone_start &&
                    vcb->nextAllocation <= VCBTOHFS(vcb)->hfs_metazone_end) {
-                       HFS_MOUNT_LOCK(vcb, TRUE);
+                       hfs_lock_mount (hfsmp);
                        HFS_UPDATE_NEXT_ALLOCATION(vcb, VCBTOHFS(vcb)->hfs_metazone_end + 1);   
                        MarkVCBDirty(vcb);
-                       HFS_MOUNT_UNLOCK(vcb, TRUE);
+                       hfs_unlock_mount(hfsmp);
                }
        }
        if (prevblocks < fcb->ff_blocks) {
@@ -1293,14 +1429,21 @@ Exit:
                *actualBytesAdded = 0;
        }
 
+       if (fastdev) {
+               hfs_hotfile_adjust_blocks(fcb->ff_cp->c_vp, 
+                                         (int64_t)prevblocks - fcb->ff_blocks);
+       }
+
        if (needsFlush)
                (void) FlushExtentFile(vcb);
 
        return err;
 
-Overflow:
+#if CONFIG_HFS_STD
+HFS_Std_Overflow:
        err = fileBoundsErr;
        goto ErrorExit;
+#endif
 }
 
 
@@ -1368,6 +1511,8 @@ OSErr TruncateFileC (
        //
        nextBlock = howmany(peof, vcb->blockSize);      // number of allocation blocks to remain in file
        peof = (int64_t)((int64_t)nextBlock * (int64_t)vcb->blockSize);                                 // number of bytes in those blocks
+
+#if CONFIG_HFS_STD
        if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= kTwoGigabytes)) {
                #if DEBUG_BUILD
                        DebugStr("HFS: Trying to truncate a file to 2GB or more");
@@ -1375,6 +1520,7 @@ OSErr TruncateFileC (
                err = fileBoundsErr;
                goto ErrorExit;
        }
+#endif
 
        //
        //      Update FCB's length
@@ -1396,7 +1542,7 @@ OSErr TruncateFileC (
                 * has been removed from disk already.  We wouldn't need to force 
                 * another update
                 */
-               FTOC(fcb)->c_flag |= (C_MODIFIED | C_FORCEUPDATE);
+               FTOC(fcb)->c_flag |= C_MODIFIED;
        }
        //
        //      If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate
@@ -1637,7 +1783,7 @@ CopyExtents:
                FTOC(fcb)->c_blocks -= headblks;
                fcb->ff_blocks = blkcnt;
 
-               FTOC(fcb)->c_flag |= C_FORCEUPDATE;
+               FTOC(fcb)->c_flag |= C_MODIFIED;
                FTOC(fcb)->c_touch_chgtime = TRUE;
 
                (void) FlushExtentFile(vcb);
@@ -1682,7 +1828,8 @@ static OSErr SearchExtentRecord(
 {
        OSErr   err = noErr;
        u_int32_t       extentIndex;
-       u_int32_t       numberOfExtents;
+       /* Set it to the HFS std value */
+       u_int32_t       numberOfExtents = kHFSExtentDensity;
        u_int32_t       numAllocationBlocks;
        Boolean foundExtent;
        
@@ -1690,10 +1837,10 @@ static OSErr SearchExtentRecord(
        *noMoreExtents          = false;
        foundExtent                     = false;
 
-       if (vcb->vcbSigWord == kHFSPlusSigWord)
+       /* Override numberOfExtents for HFS+/HFSX */
+       if (vcb->vcbSigWord != kHFSSigWord) {
                numberOfExtents = kHFSPlusExtentDensity;
-       else
-               numberOfExtents = kHFSExtentDensity;
+       }
        
        for( extentIndex = 0; extentIndex < numberOfExtents; ++extentIndex )
        {
@@ -1772,7 +1919,7 @@ static OSErr SearchExtentRecord(
 //             (other)                 (some other internal I/O error)
 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
 
-static OSErr SearchExtentFile(
+OSErr SearchExtentFile(
        ExtendedVCB     *vcb,
        const FCB                       *fcb,
        int64_t                         filePosition,
@@ -1890,7 +2037,7 @@ static OSErr UpdateExtentRecord (ExtendedVCB *vcb, FCB  *fcb, int deleted,
                }
        }
        else {
-               BTreeIterator btIterator;
+               struct BTreeIterator *btIterator = NULL;
                FSBufferDescriptor btRecord;
                u_int16_t btRecordSize;
                FCB * btFCB;
@@ -1900,8 +2047,12 @@ static OSErr UpdateExtentRecord (ExtendedVCB *vcb, FCB  *fcb, int deleted,
                //      Need to find and change a record in Extents BTree
                //
                btFCB = GetFileControlBlock(vcb->extentsRefNum);
-
-               bzero(&btIterator, sizeof(btIterator));
+               
+               MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
+               if (btIterator == NULL) {
+                       return memFullErr;  // translates to ENOMEM
+               }
+               bzero(btIterator, sizeof(*btIterator));
 
                /*
                 * The lock taken by callers of ExtendFileC/TruncateFileC is
@@ -1912,53 +2063,61 @@ static OSErr UpdateExtentRecord (ExtendedVCB *vcb, FCB  *fcb, int deleted,
                 */
                lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK);
 
-               if (vcb->vcbSigWord == kHFSSigWord) {
+               /* HFS+/HFSX */
+               if (vcb->vcbSigWord != kHFSSigWord) {           //      HFS Plus volume
+                       HFSPlusExtentRecord     foundData;              // The extent data actually found
+
+                       BlockMoveData(extentFileKey, &btIterator->key, sizeof(HFSPlusExtentKey));
+
+                       btIterator->hint.index = 0;
+                       btIterator->hint.nodeNum = extentBTreeHint;
+
+                       btRecord.bufferAddress = &foundData;
+                       btRecord.itemSize = sizeof(HFSPlusExtentRecord);
+                       btRecord.itemCount = 1;
+
+                       err = BTSearchRecord(btFCB, btIterator, &btRecord, &btRecordSize, btIterator);
+       
+                       if (err == noErr) {
+                               BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord));
+                               err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize);
+                       }
+                       (void) BTFlushPath(btFCB);
+               }
+#if CONFIG_HFS_STD
+               else {
+                       /* HFS Standard */
                        HFSExtentKey *  key;                            // Actual extent key used on disk in HFS
                        HFSExtentRecord foundData;                      // The extent data actually found
 
-                       key = (HFSExtentKey*) &btIterator.key;
+                       key = (HFSExtentKey*) &btIterator->key;
                        key->keyLength  = kHFSExtentKeyMaximumLength;
                        key->forkType   = extentFileKey->forkType;
                        key->fileID             = extentFileKey->fileID;
                        key->startBlock = extentFileKey->startBlock;
 
-                       btIterator.hint.index = 0;
-                       btIterator.hint.nodeNum = extentBTreeHint;
+                       btIterator->hint.index = 0;
+                       btIterator->hint.nodeNum = extentBTreeHint;
 
                        btRecord.bufferAddress = &foundData;
                        btRecord.itemSize = sizeof(HFSExtentRecord);
                        btRecord.itemCount = 1;
 
-                       err = BTSearchRecord(btFCB, &btIterator, &btRecord, &btRecordSize, &btIterator);
-                       
+                       err = BTSearchRecord(btFCB, btIterator, &btRecord, &btRecordSize, btIterator);
+
                        if (err == noErr)
                                err = HFSPlusToHFSExtents(extentData, (HFSExtentDescriptor *)&foundData);
 
                        if (err == noErr)
-                               err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize);
+                               err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize);
                        (void) BTFlushPath(btFCB);
-               }
-               else {          //      HFS Plus volume
-                       HFSPlusExtentRecord     foundData;              // The extent data actually found
-
-                       BlockMoveData(extentFileKey, &btIterator.key, sizeof(HFSPlusExtentKey));
 
-                       btIterator.hint.index = 0;
-                       btIterator.hint.nodeNum = extentBTreeHint;
-
-                       btRecord.bufferAddress = &foundData;
-                       btRecord.itemSize = sizeof(HFSPlusExtentRecord);
-                       btRecord.itemCount = 1;
-
-                       err = BTSearchRecord(btFCB, &btIterator, &btRecord, &btRecordSize, &btIterator);
-       
-                       if (err == noErr) {
-                               BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord));
-                               err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize);
-                       }
-                       (void) BTFlushPath(btFCB);
                }
+#endif
+
                hfs_systemfile_unlock(vcb, lockflags);
+
+               FREE(btIterator, M_TEMP);
        }
        
        return err;
@@ -1966,7 +2125,7 @@ static OSErr UpdateExtentRecord (ExtendedVCB *vcb, FCB  *fcb, int deleted,
 
 
 
-
+#if CONFIG_HFS_STD
 static OSErr HFSPlusToHFSExtents(
        const HFSPlusExtentRecord       oldExtents,
        HFSExtentRecord         newExtents)
@@ -1992,7 +2151,7 @@ static OSErr HFSPlusToHFSExtents(
        
        return err;
 }
-
+#endif