/* _______________________________________________________________________ Routine: BlockMarkAllocated Function: Mark a contiguous group of blocks as allocated (set in the bitmap). It assumes those bits are currently marked deallocated (clear in the bitmap). Inputs: vcb Pointer to volume where space is to be allocated startingBlock First block number to mark as allocated numBlocks Number of blocks to mark as allocated _______________________________________________________________________ */ __private_extern__ OSErr BlockMarkAllocated( ExtendedVCB *vcb, u_int32_t startingBlock, register u_int32_t numBlocks) { OSErr err; register u_int32_t *currentWord; // Pointer to current word within bitmap block register u_int32_t wordsLeft; // Number of words left in this bitmap block register u_int32_t bitMask; // Word with given bits already set (ready to OR in) u_int32_t firstBit; // Bit index within word of first bit to allocate u_int32_t numBits; // Number of bits in word to allocate u_int32_t *buffer = NULL; u_int32_t blockRef; u_int32_t bitsPerBlock; u_int32_t wordsPerBlock; // XXXdbg struct hfsmount *hfsmp = VCBTOHFS(vcb); // // Pre-read the bitmap block containing the first word of allocation // err = ReadBitmapBlock(vcb, startingBlock, &buffer, &blockRef); if (err != noErr) goto Exit; // // Initialize currentWord, and wordsLeft. // { u_int32_t wordIndexInBlock; bitsPerBlock = vcb->vcbVBMIOSize * kBitsPerByte; wordsPerBlock = vcb->vcbVBMIOSize / kBytesPerWord; wordIndexInBlock = (startingBlock & (bitsPerBlock-1)) / kBitsPerWord; currentWord = buffer + wordIndexInBlock; wordsLeft = wordsPerBlock - wordIndexInBlock; } // XXXdbg if (hfsmp->jnl) { journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef); } // // If the first block to allocate doesn't start on a word // boundary in the bitmap, then treat that first word // specially. // firstBit = startingBlock % kBitsPerWord; if (firstBit != 0) { bitMask = kAllBitsSetInWord >> firstBit; // turn off all bits before firstBit numBits = kBitsPerWord - firstBit; // number of remaining bits in this word if (numBits > numBlocks) { numBits = numBlocks; // entire allocation is inside this one word bitMask &= ~(kAllBitsSetInWord >> (firstBit + numBits)); // turn off bits after last }
__private_extern__ u_int32_t MetaZoneFreeBlocks(ExtendedVCB *vcb) { u_int32_t freeblocks; u_int32_t *currCache; u_int32_t blockRef; u_int32_t bit; u_int32_t lastbit; int bytesleft; int bytesperblock; u_int8_t byte; u_int8_t *buffer; blockRef = 0; bytesleft = freeblocks = 0; buffer = NULL; bit = VCBTOHFS(vcb)->hfs_metazone_start; if (bit == 1) bit = 0; lastbit = VCBTOHFS(vcb)->hfs_metazone_end; bytesperblock = vcb->vcbVBMIOSize; /* * Count all the bits from bit to lastbit. */ while (bit < lastbit) { /* * Get next bitmap block. */ if (bytesleft == 0) { if (blockRef) { (void) ReleaseBitmapBlock(vcb, blockRef, false); blockRef = 0; } if (ReadBitmapBlock(vcb, bit, &currCache, &blockRef) != 0) { return (0); } buffer = (u_int8_t *)currCache; bytesleft = bytesperblock; } byte = *buffer++; freeblocks += freebitcount[byte & 0x0F]; freeblocks += freebitcount[(byte >> 4) & 0x0F]; bit += kBitsPerByte; --bytesleft; } if (blockRef) (void) ReleaseBitmapBlock(vcb, blockRef, false); return (freeblocks); }
/* _______________________________________________________________________ Routine: BlockMarkAllocated Function: Mark a contiguous group of blocks as allocated (set in the bitmap). The function sets the bit independent of the previous state (set/clear) of the bit. 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 First block number to mark as allocated numBlocks Number of blocks to mark as allocated _______________________________________________________________________ */ static OSErr BlockMarkAllocated( SVCB *vcb, UInt32 startingBlock, register UInt32 numBlocks) { OSErr err; register UInt32 *currentWord; // Pointer to current word within bitmap block register UInt32 wordsLeft; // Number of words left in this bitmap block register UInt32 bitMask; // Word with given bits already set (ready to OR in) UInt32 firstBit; // Bit index within word of first bit to allocate UInt32 numBits; // Number of bits in word to allocate UInt32 *buffer; BlockDescriptor bd = {0}; OptionBits relOpt = kReleaseBlock; UInt32 saveNumBlocks = numBlocks; UInt32 saveStartingBlock = startingBlock; // // Pre-read the bitmap block containing the first word of allocation // err = ReadBitmapBlock(vcb, startingBlock, &bd); if (err != noErr) goto Exit; buffer = (UInt32 *) bd.buffer; relOpt = kMarkBlockDirty; // // Initialize currentWord, and wordsLeft. // { UInt32 wordIndexInBlock; wordIndexInBlock = (startingBlock & kBitsWithinBlockMask) / kBitsPerWord; currentWord = buffer + wordIndexInBlock; wordsLeft = kWordsPerBlock - wordIndexInBlock; } // // If the first block to allocate doesn't start on a word // boundary in the bitmap, then treat that first word // specially. // firstBit = startingBlock % kBitsPerWord; if (firstBit != 0) { bitMask = kAllBitsSetInWord >> firstBit; // turn off all bits before firstBit numBits = kBitsPerWord - firstBit; // number of remaining bits in this word if (numBits > numBlocks) { numBits = numBlocks; // entire allocation is inside this one word bitMask &= ~(kAllBitsSetInWord >> (firstBit + numBits)); // turn off bits after last }
/* _______________________________________________________________________ Routine: BlockAllocateAny Function: Allocate one or more allocation blocks. If there are fewer free blocks than requested, all free blocks will be allocated. The caller guarantees that there is at least one free block. Inputs: vcb Pointer to volume where space is to be allocated startingBlock Preferred first block for allocation endingBlock Last block to check + 1 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 BlockAllocateAny( ExtendedVCB *vcb, u_int32_t startingBlock, register u_int32_t endingBlock, u_int32_t maxBlocks, Boolean useMetaZone, u_int32_t *actualStartBlock, u_int32_t *actualNumBlocks) { OSErr err; register u_int32_t block; // current block number register u_int32_t currentWord; // Pointer to current word within bitmap block register u_int32_t bitMask; // Word with given bits already set (ready to OR in) register u_int32_t wordsLeft; // Number of words left in this bitmap block u_int32_t *buffer = NULL; u_int32_t *currCache = NULL; u_int32_t blockRef; u_int32_t bitsPerBlock; u_int32_t wordsPerBlock; Boolean dirty = false; struct hfsmount *hfsmp = VCBTOHFS(vcb); /* * When we're skipping the metadata zone and the start/end * range overlaps with the metadata zone then adjust the * start to be outside of the metadata zone. If the range * is entirely inside the metadata zone then we can deny the * request (dskFulErr). */ if (!useMetaZone && (vcb->hfs_flags & HFS_METADATA_ZONE)) { if (startingBlock <= vcb->hfs_metazone_end) { if (endingBlock > (vcb->hfs_metazone_end + 2)) startingBlock = vcb->hfs_metazone_end + 1; else { err = dskFulErr; goto Exit; } } } // Since this routine doesn't wrap around if (maxBlocks > (endingBlock - startingBlock)) { maxBlocks = endingBlock - startingBlock; } // // Pre-read the first bitmap block // err = ReadBitmapBlock(vcb, startingBlock, &currCache, &blockRef); if (err != noErr) goto Exit; buffer = currCache; // // Set up the current position within the block // { u_int32_t wordIndexInBlock; bitsPerBlock = vcb->vcbVBMIOSize * kBitsPerByte; wordsPerBlock = vcb->vcbVBMIOSize / kBytesPerWord; wordIndexInBlock = (startingBlock & (bitsPerBlock-1)) / kBitsPerWord; buffer += wordIndexInBlock; wordsLeft = wordsPerBlock - wordIndexInBlock; currentWord = SWAP_BE32 (*buffer); bitMask = kHighBitInWordMask >> (startingBlock & kBitsWithinWordMask); } // // Find the first unallocated block // block=startingBlock; while (block < endingBlock) { if ((currentWord & bitMask) == 0) break; // Next bit ++block; bitMask >>= 1; if (bitMask == 0) { // Next word bitMask = kHighBitInWordMask; ++buffer; if (--wordsLeft == 0) { // Next block buffer = currCache = NULL; err = ReleaseBitmapBlock(vcb, blockRef, false); if (err != noErr) goto Exit; /* * Skip over metadata blocks. */ if (!useMetaZone) { block = NextBitmapBlock(vcb, block); } if (block >= endingBlock) { err = dskFulErr; goto Exit; } err = ReadBitmapBlock(vcb, block, &currCache, &blockRef); if (err != noErr) goto Exit; buffer = currCache; wordsLeft = wordsPerBlock; } currentWord = SWAP_BE32 (*buffer); } } // Did we get to the end of the bitmap before finding a free block? // If so, then couldn't allocate anything. if (block >= endingBlock) { err = dskFulErr; goto Exit; } // Return the first block in the allocated range *actualStartBlock = block; dirty = true; // If we could get the desired number of blocks before hitting endingBlock, // then adjust endingBlock so we won't keep looking. Ideally, the comparison // would be (block + maxBlocks) < endingBlock, but that could overflow. The // comparison below yields identical results, but without overflow. if (block < (endingBlock-maxBlocks)) { endingBlock = block + maxBlocks; // if we get this far, we've found enough } // XXXdbg if (hfsmp->jnl) { journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef); } // // Allocate all of the consecutive blocks // while ((currentWord & bitMask) == 0) { // Allocate this block currentWord |= bitMask; // Move to the next block. If no more, then exit. ++block; if (block == endingBlock) break; // Next bit bitMask >>= 1; if (bitMask == 0) { *buffer = SWAP_BE32 (currentWord); // update value in bitmap // Next word bitMask = kHighBitInWordMask; ++buffer; if (--wordsLeft == 0) { // Next block buffer = currCache = NULL; err = ReleaseBitmapBlock(vcb, blockRef, true); if (err != noErr) goto Exit; /* * Skip over metadata blocks. */ if (!useMetaZone) { u_int32_t nextBlock; nextBlock = NextBitmapBlock(vcb, block); if (nextBlock != block) { goto Exit; /* allocation gap, so stop */ } } err = ReadBitmapBlock(vcb, block, &currCache, &blockRef); if (err != noErr) goto Exit; buffer = currCache; // XXXdbg if (hfsmp->jnl) { journal_modify_block_start(hfsmp->jnl, (struct buf *)blockRef); } wordsLeft = wordsPerBlock; } currentWord = SWAP_BE32 (*buffer); } } *buffer = SWAP_BE32 (currentWord); // update the last change Exit: if (err == noErr) { *actualNumBlocks = block - *actualStartBlock; // sanity check if ((*actualStartBlock + *actualNumBlocks) > vcb->allocLimit) panic("BlockAllocateAny: allocation overflow on \"%s\"", vcb->vcbVN); } else { *actualStartBlock = 0; *actualNumBlocks = 0; } if (currCache) (void) ReleaseBitmapBlock(vcb, blockRef, dirty); return err; }
/* _______________________________________________________________________ Routine: BlockAllocateAny Function: Allocate one or more allocation blocks. If there are fewer free blocks than requested, all free blocks will be allocated. The caller guarantees that there is at least one free block. 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 endingBlock Last block to check + 1 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 BlockAllocateAny( SVCB *vcb, UInt32 startingBlock, register UInt32 endingBlock, UInt32 maxBlocks, UInt32 *actualStartBlock, UInt32 *actualNumBlocks) { OSErr err; register UInt32 block = 0; // current block number register UInt32 currentWord; // Pointer to current word within bitmap block register UInt32 bitMask; // Word with given bits already set (ready to OR in) register UInt32 wordsLeft; // Number of words left in this bitmap block UInt32 *buffer; BlockDescriptor bd = {0}; OptionBits relOpt = kReleaseBlock; // Since this routine doesn't wrap around if (maxBlocks > (endingBlock - startingBlock)) { maxBlocks = endingBlock - startingBlock; } // // Pre-read the first bitmap block // err = ReadBitmapBlock(vcb, startingBlock, &bd); if (err != noErr) goto Exit; relOpt = kMarkBlockDirty; buffer = (UInt32 *) bd.buffer; // // Set up the current position within the block // { UInt32 wordIndexInBlock; wordIndexInBlock = (startingBlock & kBitsWithinBlockMask) / kBitsPerWord; buffer += wordIndexInBlock; wordsLeft = kWordsPerBlock - wordIndexInBlock; currentWord = SWAP_BE32(*buffer); bitMask = kHighBitInWordMask >> (startingBlock & kBitsWithinWordMask); } // // Find the first unallocated block // block = startingBlock; while (block < endingBlock) { if ((currentWord & bitMask) == 0) break; // Next bit ++block; bitMask >>= 1; if (bitMask == 0) { // Next word bitMask = kHighBitInWordMask; ++buffer; if (--wordsLeft == 0) { // Next block err = ReleaseBitmapBlock(vcb, relOpt, &bd); bd.buffer = NULL; if (err != noErr) goto Exit; err = ReadBitmapBlock(vcb, block, &bd); if (err != noErr) goto Exit; buffer = (UInt32 *) bd.buffer; relOpt = kMarkBlockDirty; wordsLeft = kWordsPerBlock; } currentWord = SWAP_BE32(*buffer); } } // Did we get to the end of the bitmap before finding a free block? // If so, then couldn't allocate anything. if (block == endingBlock) { err = dskFulErr; goto Exit; } // Return the first block in the allocated range *actualStartBlock = block; // If we could get the desired number of blocks before hitting endingBlock, // then adjust endingBlock so we won't keep looking. Ideally, the comparison // would be (block + maxBlocks) < endingBlock, but that could overflow. The // comparison below yields identical results, but without overflow. if (block < (endingBlock-maxBlocks)) { endingBlock = block + maxBlocks; // if we get this far, we've found enough } // // Allocate all of the consecutive blocks // while ((currentWord & bitMask) == 0) { // Allocate this block currentWord |= bitMask; // Move to the next block. If no more, then exit. ++block; if (block == endingBlock) break; // Next bit bitMask >>= 1; if (bitMask == 0) { *buffer = SWAP_BE32(currentWord); // update value in bitmap // Next word bitMask = kHighBitInWordMask; ++buffer; if (--wordsLeft == 0) { // Next block err = ReleaseBitmapBlock(vcb, relOpt, &bd); if (err != noErr) goto Exit; bd.buffer = NULL; err = ReadBitmapBlock(vcb, block, &bd); if (err != noErr) goto Exit; buffer = (UInt32 *) bd.buffer; relOpt = kMarkBlockDirty; wordsLeft = kWordsPerBlock; } currentWord = SWAP_BE32(*buffer); } } *buffer = SWAP_BE32(currentWord); // update the last change Exit: if (err == noErr) { *actualNumBlocks = block - *actualStartBlock; /* Update the in-memory copy of bitmap */ (void) CaptureBitmapBits (*actualStartBlock, *actualNumBlocks); } else { *actualStartBlock = 0; *actualNumBlocks = 0; } if (bd.buffer != NULL) (void) ReleaseBitmapBlock(vcb, relOpt, &bd); return err; }