/*
- * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2014 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include "../headers/BTreesInternal.h"
#include <sys/malloc.h>
+#include <sys/vnode_internal.h>
/*
============================================================
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).
============================================================
============================================================
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.
and was in the extents file, then delete the record instead.
*/
+#if CONFIG_HFS_STD
static const int64_t kTwoGigabytes = 0x80000000LL;
+#endif
enum
{
};
+#if CONFIG_HFS_STD
static OSErr HFSPlusToHFSExtents(
const HFSPlusExtentRecord oldExtents,
HFSExtentRecord newExtents);
+#endif
static OSErr FindExtentRecord(
const ExtendedVCB *vcb,
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,
u_int32_t *foundHint)
{
FCB * fcb;
- BTreeIterator btIterator;
+ struct BTreeIterator *btIterator = NULL;
FSBufferDescriptor btRecord;
OSErr err;
u_int16_t btRecordSize;
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;
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).
}
}
}
- 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;
}
HFSPlusExtentRecord extents,
u_int32_t *hint)
{
- BTreeIterator btIterator;
+ struct BTreeIterator *btIterator = NULL;
FSBufferDescriptor btRecord;
u_int16_t btRecordSize;
int lockflags;
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
*/
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;
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;
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;
}
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;
}
//
// 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?
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;
}
+#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
//
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
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.
*
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.
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);
Boolean wantContig;
Boolean useMetaZone;
Boolean needsFlush;
+ int allowFlushTxns;
u_int32_t actualStartBlock;
u_int32_t actualNumBlocks;
u_int32_t numExtentsPerRecord;
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;
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.
&& (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);
}
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);
}
//
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
// 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?
else {
wantContig = true;
}
+
+ if (should_pin_blocks(hfsmp, fcb))
+ fastdev = HFS_ALLOC_FAST_DEV;
+
useMetaZone = flags & kEFMetadataMask;
do {
if (blockHint != 0)
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;
}
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.
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.
}
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.
/* 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) {
*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
}
//
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");
err = fileBoundsErr;
goto ErrorExit;
}
+#endif
//
// Update FCB's length
* 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
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);
{
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;
*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 )
{
// (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,
}
}
else {
- BTreeIterator btIterator;
+ struct BTreeIterator *btIterator = NULL;
FSBufferDescriptor btRecord;
u_int16_t btRecordSize;
FCB * btFCB;
// 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
*/
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;
-
+#if CONFIG_HFS_STD
static OSErr HFSPlusToHFSExtents(
const HFSPlusExtentRecord oldExtents,
HFSExtentRecord newExtents)
return err;
}
-
+#endif