/*
- * Copyright (c) 2000-2013 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
{
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,
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);
int64_t availbytes;
int64_t peof;
u_int32_t prevblocks;
+ uint32_t fastdev = 0;
+
struct hfsmount *hfsmp = (struct hfsmount*)vcb;
allowFlushTxns = 0;
needsFlush = false;
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);
}
// 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 = 0;
+ uint32_t ba_flags = fastdev;
+
if (wantContig) {
ba_flags |= HFS_ALLOC_FORCECONTIG;
}
}
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;
- }
-
// 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.
*actualBytesAdded = 0;
}
+ if (fastdev) {
+ hfs_hotfile_adjust_blocks(fcb->ff_cp->c_vp,
+ (int64_t)prevblocks - fcb->ff_blocks);
+ }
+
if (needsFlush)
(void) FlushExtentFile(vcb);
#if CONFIG_HFS_STD
HFS_Std_Overflow:
-#endif
err = fileBoundsErr;
goto ErrorExit;
+#endif
}
* 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);
// (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,