/* _______________________________________________________________________ Routine: BlockAllocateContig Function: Allocate a contiguous group of allocation blocks. The allocation is all-or-nothing. The caller guarantees that there are enough free blocks (though they may not be contiguous, in which case this call will fail). Inputs: vcb Pointer to volume where space is to be allocated startingBlock Preferred first block for allocation minBlocks Minimum number of contiguous blocks to allocate maxBlocks Maximum number of contiguous blocks to allocate useMetaZone Outputs: actualStartBlock First block of range allocated, or 0 if error actualNumBlocks Number of blocks allocated, or 0 if error _______________________________________________________________________ */ static OSErr BlockAllocateContig( ExtendedVCB *vcb, u_int32_t startingBlock, u_int32_t minBlocks, u_int32_t maxBlocks, Boolean useMetaZone, u_int32_t *actualStartBlock, u_int32_t *actualNumBlocks) { OSErr err; // // Find a contiguous group of blocks at least minBlocks long. // Determine the number of contiguous blocks available (up // to maxBlocks). // /* * NOTE: If the only contiguous free extent of at least minBlocks * crosses startingBlock (i.e. starts before, ends after), then we * won't find it. Earlier versions *did* find this case by letting * the second search look past startingBlock by minBlocks. But * with the free extent cache, this can lead to duplicate entries * in the cache, causing the same blocks to be allocated twice. */ err = BlockFindContiguous(vcb, startingBlock, vcb->allocLimit, minBlocks, maxBlocks, useMetaZone, actualStartBlock, actualNumBlocks); if (err == dskFulErr && startingBlock != 0) { /* * Constrain the endingBlock so we don't bother looking for ranges * that would overlap those found in the previous call. */ err = BlockFindContiguous(vcb, 1, startingBlock, minBlocks, maxBlocks, useMetaZone, actualStartBlock, actualNumBlocks); } // // Now mark those blocks allocated. // if (err == noErr) err = BlockMarkAllocated(vcb, *actualStartBlock, *actualNumBlocks); return err; }
/* _______________________________________________________________________ Routine: BlockAllocateContig Function: Allocate a contiguous group of allocation blocks. The allocation is all-or-nothing. The caller guarantees that there are enough free blocks (though they may not be contiguous, in which case this call will fail). The function uses on-disk volume bitmap for allocation and updates it with newly allocated blocks. It also updates the in-memory volume bitmap. Inputs: vcb Pointer to volume where space is to be allocated startingBlock Preferred first block for allocation minBlocks Minimum number of contiguous blocks to allocate maxBlocks Maximum number of contiguous blocks to allocate Outputs: actualStartBlock First block of range allocated, or 0 if error actualNumBlocks Number of blocks allocated, or 0 if error _______________________________________________________________________ */ static OSErr BlockAllocateContig( SVCB *vcb, UInt32 startingBlock, UInt32 minBlocks, UInt32 maxBlocks, UInt32 *actualStartBlock, UInt32 *actualNumBlocks) { OSErr err; // // Find a contiguous group of blocks at least minBlocks long. // Determine the number of contiguous blocks available (up // to maxBlocks). // err = BlockFindContiguous(vcb, startingBlock, vcb->vcbTotalBlocks, minBlocks, maxBlocks, actualStartBlock, actualNumBlocks); if (err == dskFulErr) { //ее Should constrain the endingBlock here, so we don't bother looking for ranges //ее that start after startingBlock, since we already checked those. err = BlockFindContiguous(vcb, 0, vcb->vcbTotalBlocks, minBlocks, maxBlocks, actualStartBlock, actualNumBlocks); } if (err != noErr) goto Exit; // // Now mark those blocks allocated. // err = BlockMarkAllocated(vcb, *actualStartBlock, *actualNumBlocks); Exit: if (err != noErr) { *actualStartBlock = 0; *actualNumBlocks = 0; } return err; }
/* _______________________________________________________________________ Routine: BlockAllocateKnown Function: Try to allocate space from known free space in the free extent cache. Inputs: vcb Pointer to volume where space is to be allocated maxBlocks Maximum number of contiguous blocks to allocate Outputs: actualStartBlock First block of range allocated, or 0 if error actualNumBlocks Number of blocks allocated, or 0 if error Returns: dskFulErr Free extent cache is empty _______________________________________________________________________ */ static OSErr BlockAllocateKnown( ExtendedVCB *vcb, u_int32_t maxBlocks, u_int32_t *actualStartBlock, u_int32_t *actualNumBlocks) { OSErr err; u_int32_t i; u_int32_t foundBlocks; u_int32_t newStartBlock, newBlockCount; if (vcb->vcbFreeExtCnt == 0) return dskFulErr; // Just grab up to maxBlocks of the first (largest) free exent. *actualStartBlock = vcb->vcbFreeExt[0].startBlock; foundBlocks = vcb->vcbFreeExt[0].blockCount; if (foundBlocks > maxBlocks) foundBlocks = maxBlocks; *actualNumBlocks = foundBlocks; // Adjust the start and length of that extent. newStartBlock = vcb->vcbFreeExt[0].startBlock + foundBlocks; newBlockCount = vcb->vcbFreeExt[0].blockCount - foundBlocks; // The first extent might not be the largest anymore. Bubble up any // (now larger) extents to the top of the list. for (i=1; i<vcb->vcbFreeExtCnt; ++i) { if (vcb->vcbFreeExt[i].blockCount > newBlockCount) { vcb->vcbFreeExt[i-1].startBlock = vcb->vcbFreeExt[i].startBlock; vcb->vcbFreeExt[i-1].blockCount = vcb->vcbFreeExt[i].blockCount; } else { break; } } // If this is now the smallest known free extent, then it might be smaller than // other extents we didn't keep track of. So, just forget about this extent. // After the previous loop, (i-1) is the index of the extent we just allocated from. if (i == vcb->vcbFreeExtCnt) { // It's now the smallest extent, so forget about it --vcb->vcbFreeExtCnt; } else { // It's not the smallest, so store it in its proper place vcb->vcbFreeExt[i-1].startBlock = newStartBlock; vcb->vcbFreeExt[i-1].blockCount = newBlockCount; } // sanity check if ((*actualStartBlock + *actualNumBlocks) > vcb->allocLimit) { printf ("hfs: BlockAllocateKnown() found allocation overflow on \"%s\"", vcb->vcbVN); hfs_mark_volume_inconsistent(vcb); *actualStartBlock = 0; *actualNumBlocks = 0; err = EIO; } else { // // Now mark the found extent in the bitmap // err = BlockMarkAllocated(vcb, *actualStartBlock, *actualNumBlocks); } return err; }