//---------------------------------------------------------------------- // This software is part of the OpenBeOS distribution and is covered // by the OpenBeOS license. // // Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net //---------------------------------------------------------------------- /*! \file Allocator.cpp Physical block allocator class implementation. */ #include "Allocator.h" #include #include "Utils.h" /*! \brief Creates a new Allocator object. */ Allocator::Allocator(uint32 blockSize) : fLength(0) , fBlockSize(blockSize) , fBlockShift(0) , fInitStatus(B_NO_INIT) { status_t error = Udf::get_block_shift(BlockSize(), fBlockShift); if (!error) fInitStatus = B_OK; } status_t Allocator::InitCheck() const { return fInitStatus; } /*! \brief Allocates the given block, if available. \return - B_OK: Success. - error code: Failure, the block has already been allocated. */ status_t Allocator::GetBlock(uint32 block) { Udf::extent_address extent(block, BlockSize()); return GetExtent(extent); } /*! \brief Allocates the given extent, if available. \return - B_OK: Success. - error code: Failure, the extent (or some portion of it) has already been allocated. */ status_t Allocator::GetExtent(Udf::extent_address extent) { status_t error = InitCheck(); if (!error) { uint32 offset = extent.location(); uint32 length = BlocksFor(extent.length()); // First see if the extent is past the allocation tail, // since we then don't have to do any chunklist traversal if (offset >= Length()) { // Add a new chunk to the end of the chunk list if // necessary if (offset > Length()) { Udf::extent_address chunk(Length(), (offset-Length())<::iterator i = fChunkList.begin(); i != fChunkList.end(); i++) { uint32 chunkOffset = i->location(); uint32 chunkLength = BlocksFor(i->length()); if (chunkOffset <= offset && (offset+length) <= (chunkOffset+chunkLength)) { // Found it. Split the chunk. First look for an orphan // before the block, then after. if (chunkOffset < offset) { // Orhpan before; add a new chunk in front // of the current one Udf::extent_address chunk(chunkOffset, (offset-chunkOffset)<set_location(offset+length); i->set_length(((chunkOffset+chunkLength)-(offset+length))<::iterator i = fChunkList.begin(); i != fChunkList.end(); i++) { uint32 chunkOffset = i->location(); uint32 chunkLength = BlocksFor(i->length()); if (chunkOffset < minimumStartingBlock) { if (minimumStartingBlock < chunkOffset+chunkLength) { // Start of chunk is below min starting block. See if // any part of the chunk would make for an acceptable // allocation uint32 difference = minimumStartingBlock - chunkOffset; uint32 newOffset = minimumStartingBlock; uint32 newLength = chunkLength-difference; if (length <= newLength) { // new chunk is still long enough Udf::extent_address newExtent(newOffset, _length); if (GetExtent(newExtent) == B_OK) { extent = newExtent; return B_OK; } } else if (!contiguous) { // new chunk is too short, but we're allowed to // allocate a shorter extent, so we'll do it. Udf::extent_address newExtent(newOffset, newLength<set_location(chunkOffset+length); i->set_length((chunkLength-length)< 0 ? B_OK : B_DEVICE_FULL; if (!error) { if (minimumStartingBlock > Tail()) maxLength -= minimumStartingBlock - Tail(); uint32 tail = minimumStartingBlock > Tail() ? minimumStartingBlock : Tail(); if (length > maxLength) { if (contiguous) error = B_DEVICE_FULL; else { isPartial = true; length = maxLength; } } if (!error) { Udf::extent_address newExtent(tail, isPartial ? length<> BlockShift(); if (bytes % BlockSize() != 0) blocks++; uint64 mask = 0xffffffff; mask <<= 32; if (blocks & mask) { // ToDo: Convert this to actually signal an error DEBUG_INIT_ETC("Allocator", ("bytes: %ld\n", bytes)); PRINT(("WARNING: bytes argument too large for corresponding number " "of blocks to be specified with a uint32! (bytes: %Ld, blocks: %Ld, " "maxblocks: %ld).\n", bytes, blocks, ULONG_MAX)); blocks = 0; } return blocks; } }