1a1b0ec30SJérôme Duval /* 2a1b0ec30SJérôme Duval * Copyright 2001-2010, Haiku Inc. All rights reserved. 3a1b0ec30SJérôme Duval * This file may be used under the terms of the MIT License. 4a1b0ec30SJérôme Duval * 5a1b0ec30SJérôme Duval * Authors: 6a1b0ec30SJérôme Duval * Janito V. Ferreira Filho 7a1b0ec30SJérôme Duval */ 8a1b0ec30SJérôme Duval 9a1b0ec30SJérôme Duval 10a1b0ec30SJérôme Duval #include "DataStream.h" 11a1b0ec30SJérôme Duval 12a1b0ec30SJérôme Duval #include "CachedBlock.h" 13a1b0ec30SJérôme Duval #include "Volume.h" 14a1b0ec30SJérôme Duval 15a1b0ec30SJérôme Duval 16a1b0ec30SJérôme Duval //#define TRACE_EXT2 17a1b0ec30SJérôme Duval #ifdef TRACE_EXT2 18a1b0ec30SJérôme Duval # define TRACE(x...) dprintf("\33[34mext2:\33[0m " x) 19a1b0ec30SJérôme Duval #else 20a1b0ec30SJérôme Duval # define TRACE(x...) ; 21a1b0ec30SJérôme Duval #endif 22d8772e0cSJérôme Duval #define ERROR(x...) dprintf("\33[34mext2:\33[0m " x) 23a1b0ec30SJérôme Duval 24a1b0ec30SJérôme Duval 25a1b0ec30SJérôme Duval DataStream::DataStream(Volume* volume, ext2_data_stream* stream, 26a1b0ec30SJérôme Duval off_t size) 27a1b0ec30SJérôme Duval : 28a1b0ec30SJérôme Duval kBlockSize(volume->BlockSize()), 29de66992bSJérôme Duval kIndirectsPerBlock(kBlockSize / sizeof(uint32)), 30a1b0ec30SJérôme Duval kIndirectsPerBlock2(kIndirectsPerBlock * kIndirectsPerBlock), 31a1b0ec30SJérôme Duval kIndirectsPerBlock3(kIndirectsPerBlock2 * kIndirectsPerBlock), 32a1b0ec30SJérôme Duval kMaxDirect(EXT2_DIRECT_BLOCKS), 33a1b0ec30SJérôme Duval kMaxIndirect(kMaxDirect + kIndirectsPerBlock), 34a1b0ec30SJérôme Duval kMaxDoubleIndirect(kMaxIndirect + kIndirectsPerBlock2), 35a1b0ec30SJérôme Duval fVolume(volume), 36a1b0ec30SJérôme Duval fStream(stream), 37a1b0ec30SJérôme Duval fFirstBlock(volume->FirstDataBlock()), 38a1b0ec30SJérôme Duval fAllocated(0), 39a1b0ec30SJérôme Duval fAllocatedPos(fFirstBlock), 40a1b0ec30SJérôme Duval fWaiting(0), 41a1b0ec30SJérôme Duval fFreeStart(0), 42a1b0ec30SJérôme Duval fFreeCount(0), 439637baaeSJérôme Duval fRemovedBlocks(0), 449637baaeSJérôme Duval fSize(size) 45a1b0ec30SJérôme Duval { 469637baaeSJérôme Duval fNumBlocks = size == 0 ? 0 : ((size - 1) >> fVolume->BlockShift()) + 1; 47a1b0ec30SJérôme Duval } 48a1b0ec30SJérôme Duval 49a1b0ec30SJérôme Duval 50a1b0ec30SJérôme Duval DataStream::~DataStream() 51a1b0ec30SJérôme Duval { 52a1b0ec30SJérôme Duval } 53a1b0ec30SJérôme Duval 54a1b0ec30SJérôme Duval 55a1b0ec30SJérôme Duval status_t 56*45af882dSJérôme Duval DataStream::FindBlock(off_t offset, fsblock_t& block, uint32 *_count) 579637baaeSJérôme Duval { 589637baaeSJérôme Duval uint32 index = offset >> fVolume->BlockShift(); 599637baaeSJérôme Duval 609637baaeSJérôme Duval if (offset >= fSize) { 619637baaeSJérôme Duval TRACE("FindBlock: offset larger than inode size\n"); 629637baaeSJérôme Duval return B_ENTRY_NOT_FOUND; 639637baaeSJérôme Duval } 649637baaeSJérôme Duval 659637baaeSJérôme Duval // TODO: we could return the size of the sparse range, as this might be more 669637baaeSJérôme Duval // than just a block 679637baaeSJérôme Duval 689637baaeSJérôme Duval if (index < EXT2_DIRECT_BLOCKS) { 699637baaeSJérôme Duval // direct blocks 709637baaeSJérôme Duval block = B_LENDIAN_TO_HOST_INT32(fStream->direct[index]); 719637baaeSJérôme Duval ASSERT(block != 0); 729637baaeSJérôme Duval if (_count) { 739637baaeSJérôme Duval *_count = 1; 749637baaeSJérôme Duval uint32 nextBlock = block; 759637baaeSJérôme Duval while (++index < EXT2_DIRECT_BLOCKS 769637baaeSJérôme Duval && fStream->direct[index] == ++nextBlock) 779637baaeSJérôme Duval (*_count)++; 789637baaeSJérôme Duval } 799637baaeSJérôme Duval } else if ((index -= EXT2_DIRECT_BLOCKS) < kIndirectsPerBlock) { 809637baaeSJérôme Duval // indirect blocks 819637baaeSJérôme Duval CachedBlock cached(fVolume); 829637baaeSJérôme Duval uint32* indirectBlocks = (uint32*)cached.SetTo(B_LENDIAN_TO_HOST_INT32( 839637baaeSJérôme Duval fStream->indirect)); 849637baaeSJérôme Duval if (indirectBlocks == NULL) 859637baaeSJérôme Duval return B_IO_ERROR; 869637baaeSJérôme Duval 879637baaeSJérôme Duval block = B_LENDIAN_TO_HOST_INT32(indirectBlocks[index]); 889637baaeSJérôme Duval ASSERT(block != 0); 899637baaeSJérôme Duval if (_count) { 909637baaeSJérôme Duval *_count = 1; 919637baaeSJérôme Duval uint32 nextBlock = block; 929637baaeSJérôme Duval while (++index < kIndirectsPerBlock 939637baaeSJérôme Duval && indirectBlocks[index] == ++nextBlock) 949637baaeSJérôme Duval (*_count)++; 959637baaeSJérôme Duval } 969637baaeSJérôme Duval } else if ((index -= kIndirectsPerBlock) < kIndirectsPerBlock2) { 979637baaeSJérôme Duval // double indirect blocks 989637baaeSJérôme Duval CachedBlock cached(fVolume); 999637baaeSJérôme Duval uint32* indirectBlocks = (uint32*)cached.SetTo(B_LENDIAN_TO_HOST_INT32( 1009637baaeSJérôme Duval fStream->double_indirect)); 1019637baaeSJérôme Duval if (indirectBlocks == NULL) 1029637baaeSJérôme Duval return B_IO_ERROR; 1039637baaeSJérôme Duval 1049637baaeSJérôme Duval uint32 indirectIndex = B_LENDIAN_TO_HOST_INT32(indirectBlocks[index 1059637baaeSJérôme Duval / kIndirectsPerBlock]); 1069637baaeSJérôme Duval if (indirectIndex == 0) { 1079637baaeSJérôme Duval // a sparse indirect block 1089637baaeSJérôme Duval block = 0; 1099637baaeSJérôme Duval } else { 1109637baaeSJérôme Duval indirectBlocks = (uint32*)cached.SetTo(indirectIndex); 1119637baaeSJérôme Duval if (indirectBlocks == NULL) 1129637baaeSJérôme Duval return B_IO_ERROR; 1139637baaeSJérôme Duval 1149637baaeSJérôme Duval block = B_LENDIAN_TO_HOST_INT32( 1159637baaeSJérôme Duval indirectBlocks[index & (kIndirectsPerBlock - 1)]); 1169637baaeSJérôme Duval if (_count) { 1179637baaeSJérôme Duval *_count = 1; 1189637baaeSJérôme Duval uint32 nextBlock = block; 1199637baaeSJérôme Duval while (((++index & (kIndirectsPerBlock - 1)) != 0) 1209637baaeSJérôme Duval && indirectBlocks[index & (kIndirectsPerBlock - 1)] 1219637baaeSJérôme Duval == ++nextBlock) 1229637baaeSJérôme Duval (*_count)++; 1239637baaeSJérôme Duval } 1249637baaeSJérôme Duval } 1259637baaeSJérôme Duval ASSERT(block != 0); 1269637baaeSJérôme Duval } else if ((index -= kIndirectsPerBlock2) < kIndirectsPerBlock3) { 1279637baaeSJérôme Duval // triple indirect blocks 1289637baaeSJérôme Duval CachedBlock cached(fVolume); 1299637baaeSJérôme Duval uint32* indirectBlocks = (uint32*)cached.SetTo(B_LENDIAN_TO_HOST_INT32( 1309637baaeSJérôme Duval fStream->triple_indirect)); 1319637baaeSJérôme Duval if (indirectBlocks == NULL) 1329637baaeSJérôme Duval return B_IO_ERROR; 1339637baaeSJérôme Duval 1349637baaeSJérôme Duval uint32 indirectIndex = B_LENDIAN_TO_HOST_INT32(indirectBlocks[index 1359637baaeSJérôme Duval / kIndirectsPerBlock2]); 1369637baaeSJérôme Duval if (indirectIndex == 0) { 1379637baaeSJérôme Duval // a sparse indirect block 1389637baaeSJérôme Duval block = 0; 1399637baaeSJérôme Duval } else { 1409637baaeSJérôme Duval indirectBlocks = (uint32*)cached.SetTo(indirectIndex); 1419637baaeSJérôme Duval if (indirectBlocks == NULL) 1429637baaeSJérôme Duval return B_IO_ERROR; 1439637baaeSJérôme Duval 1449637baaeSJérôme Duval indirectIndex = B_LENDIAN_TO_HOST_INT32( 1459637baaeSJérôme Duval indirectBlocks[(index / kIndirectsPerBlock) & (kIndirectsPerBlock - 1)]); 1469637baaeSJérôme Duval if (indirectIndex == 0) { 1479637baaeSJérôme Duval // a sparse indirect block 1489637baaeSJérôme Duval block = 0; 1499637baaeSJérôme Duval } else { 1509637baaeSJérôme Duval indirectBlocks = (uint32*)cached.SetTo(indirectIndex); 1519637baaeSJérôme Duval if (indirectBlocks == NULL) 1529637baaeSJérôme Duval return B_IO_ERROR; 1539637baaeSJérôme Duval 1549637baaeSJérôme Duval block = B_LENDIAN_TO_HOST_INT32( 1559637baaeSJérôme Duval indirectBlocks[index & (kIndirectsPerBlock - 1)]); 1569637baaeSJérôme Duval if (_count) { 1579637baaeSJérôme Duval *_count = 1; 1589637baaeSJérôme Duval uint32 nextBlock = block; 1599637baaeSJérôme Duval while (((++index & (kIndirectsPerBlock - 1)) != 0) 1609637baaeSJérôme Duval && indirectBlocks[index & (kIndirectsPerBlock - 1)] 1619637baaeSJérôme Duval == ++nextBlock) 1629637baaeSJérôme Duval (*_count)++; 1639637baaeSJérôme Duval } 1649637baaeSJérôme Duval } 1659637baaeSJérôme Duval } 1669637baaeSJérôme Duval ASSERT(block != 0); 1679637baaeSJérôme Duval } else { 1689637baaeSJérôme Duval // Outside of the possible data stream 1699637baaeSJérôme Duval dprintf("ext2: block outside datastream!\n"); 1709637baaeSJérôme Duval return B_ERROR; 1719637baaeSJérôme Duval } 1729637baaeSJérôme Duval 1739637baaeSJérôme Duval TRACE("inode %Ld: FindBlock(offset %lld): %lld %ld\n", ID(), offset, block, 1749637baaeSJérôme Duval _count != NULL ? *_count : 1); 1759637baaeSJérôme Duval return B_OK; 1769637baaeSJérôme Duval } 1779637baaeSJérôme Duval 1789637baaeSJérôme Duval 1799637baaeSJérôme Duval status_t 180d8772e0cSJérôme Duval DataStream::Enlarge(Transaction& transaction, off_t& numBlocks) 181a1b0ec30SJérôme Duval { 182d8772e0cSJérôme Duval TRACE("DataStream::Enlarge(): current size: %llu, target size: %llu\n", 183a1b0ec30SJérôme Duval fNumBlocks, numBlocks); 184a1b0ec30SJérôme Duval 185d8772e0cSJérôme Duval off_t targetBlocks = numBlocks; 186a1b0ec30SJérôme Duval fWaiting = _BlocksNeeded(numBlocks); 187a1b0ec30SJérôme Duval numBlocks = fWaiting; 188a1b0ec30SJérôme Duval 189a1b0ec30SJérôme Duval status_t status; 190a1b0ec30SJérôme Duval 191a1b0ec30SJérôme Duval if (fNumBlocks <= kMaxDirect) { 192a1b0ec30SJérôme Duval status = _AddForDirectBlocks(transaction, targetBlocks); 193a1b0ec30SJérôme Duval 194d8772e0cSJérôme Duval if (status != B_OK) { 195d8772e0cSJérôme Duval ERROR("DataStream::Enlarge(): _AddForDirectBlocks() failed\n"); 196a1b0ec30SJérôme Duval return status; 197d8772e0cSJérôme Duval } 198a1b0ec30SJérôme Duval 199d8772e0cSJérôme Duval TRACE("DataStream::Enlarge(): current size: %llu, target size: %llu\n", 200a1b0ec30SJérôme Duval fNumBlocks, targetBlocks); 201a1b0ec30SJérôme Duval 202a1b0ec30SJérôme Duval if (fNumBlocks == targetBlocks) 203a1b0ec30SJérôme Duval return B_OK; 204a1b0ec30SJérôme Duval } 205a1b0ec30SJérôme Duval 206d8772e0cSJérôme Duval TRACE("DataStream::Enlarge(): indirect current size: %llu, target size: %llu\n", 207d8772e0cSJérôme Duval fNumBlocks, targetBlocks); 208d8772e0cSJérôme Duval 209a1b0ec30SJérôme Duval if (fNumBlocks <= kMaxIndirect) { 210a1b0ec30SJérôme Duval status = _AddForIndirectBlock(transaction, targetBlocks); 211a1b0ec30SJérôme Duval 212d8772e0cSJérôme Duval if (status != B_OK) { 213d8772e0cSJérôme Duval ERROR("DataStream::Enlarge(): _AddForIndirectBlock() failed\n"); 214a1b0ec30SJérôme Duval return status; 215d8772e0cSJérôme Duval } 216a1b0ec30SJérôme Duval 217d8772e0cSJérôme Duval TRACE("DataStream::Enlarge(): current size: %llu, target size: %llu\n", 218a1b0ec30SJérôme Duval fNumBlocks, targetBlocks); 219a1b0ec30SJérôme Duval 220a1b0ec30SJérôme Duval if (fNumBlocks == targetBlocks) 221a1b0ec30SJérôme Duval return B_OK; 222a1b0ec30SJérôme Duval } 223a1b0ec30SJérôme Duval 224d8772e0cSJérôme Duval TRACE("DataStream::Enlarge(): indirect2 current size: %llu, target size: %llu\n", 225d8772e0cSJérôme Duval fNumBlocks, targetBlocks); 226d8772e0cSJérôme Duval 227a1b0ec30SJérôme Duval if (fNumBlocks <= kMaxDoubleIndirect) { 228a1b0ec30SJérôme Duval status = _AddForDoubleIndirectBlock(transaction, targetBlocks); 229a1b0ec30SJérôme Duval 230d8772e0cSJérôme Duval if (status != B_OK) { 231d8772e0cSJérôme Duval ERROR("DataStream::Enlarge(): _AddForDoubleIndirectBlock() failed\n"); 232a1b0ec30SJérôme Duval return status; 233d8772e0cSJérôme Duval } 234a1b0ec30SJérôme Duval 235d8772e0cSJérôme Duval TRACE("DataStream::Enlarge(): current size: %llu, target size: %llu\n", 236a1b0ec30SJérôme Duval fNumBlocks, targetBlocks); 237a1b0ec30SJérôme Duval 238a1b0ec30SJérôme Duval if (fNumBlocks == targetBlocks) 239a1b0ec30SJérôme Duval return B_OK; 240a1b0ec30SJérôme Duval } 241a1b0ec30SJérôme Duval 242d8772e0cSJérôme Duval TRACE("DataStream::Enlarge(): indirect3 current size: %llu, target size: %llu\n", 243d8772e0cSJérôme Duval fNumBlocks, targetBlocks); 244d8772e0cSJérôme Duval 245a1b0ec30SJérôme Duval TRACE("DataStream::Enlarge(): allocated: %lu, waiting: %lu\n", fAllocated, 246a1b0ec30SJérôme Duval fWaiting); 247a1b0ec30SJérôme Duval 248a1b0ec30SJérôme Duval return _AddForTripleIndirectBlock(transaction, targetBlocks); 249a1b0ec30SJérôme Duval } 250a1b0ec30SJérôme Duval 251a1b0ec30SJérôme Duval 252a1b0ec30SJérôme Duval status_t 253d8772e0cSJérôme Duval DataStream::Shrink(Transaction& transaction, off_t& numBlocks) 254a1b0ec30SJérôme Duval { 255d8772e0cSJérôme Duval TRACE("DataStream::Shrink(): current size: %llu, target size: %llu\n", 256a1b0ec30SJérôme Duval fNumBlocks, numBlocks); 257a1b0ec30SJérôme Duval 258a1b0ec30SJérôme Duval fFreeStart = 0; 259a1b0ec30SJérôme Duval fFreeCount = 0; 260a1b0ec30SJérôme Duval fRemovedBlocks = 0; 261a1b0ec30SJérôme Duval 262d8772e0cSJérôme Duval off_t oldNumBlocks = fNumBlocks; 263d8772e0cSJérôme Duval off_t blocksToRemove = fNumBlocks - numBlocks; 264a1b0ec30SJérôme Duval 265a1b0ec30SJérôme Duval status_t status; 266a1b0ec30SJérôme Duval 267a1b0ec30SJérôme Duval if (numBlocks < kMaxDirect) { 268a1b0ec30SJérôme Duval status = _RemoveFromDirectBlocks(transaction, numBlocks); 269a1b0ec30SJérôme Duval 270d8772e0cSJérôme Duval if (status != B_OK) { 271d8772e0cSJérôme Duval ERROR("DataStream::Shrink(): _RemoveFromDirectBlocks() failed\n"); 272a1b0ec30SJérôme Duval return status; 273d8772e0cSJérôme Duval } 274a1b0ec30SJérôme Duval 275a1b0ec30SJérôme Duval if (fRemovedBlocks == blocksToRemove) { 276a1b0ec30SJérôme Duval fNumBlocks -= fRemovedBlocks; 277a1b0ec30SJérôme Duval numBlocks = _BlocksNeeded(oldNumBlocks); 278a1b0ec30SJérôme Duval 279a1b0ec30SJérôme Duval return _PerformFree(transaction); 280a1b0ec30SJérôme Duval } 281a1b0ec30SJérôme Duval } 282a1b0ec30SJérôme Duval 283a1b0ec30SJérôme Duval if (numBlocks < kMaxIndirect) { 284a1b0ec30SJérôme Duval status = _RemoveFromIndirectBlock(transaction, numBlocks); 285a1b0ec30SJérôme Duval 286d8772e0cSJérôme Duval if (status != B_OK) { 287d8772e0cSJérôme Duval ERROR("DataStream::Shrink(): _RemoveFromIndirectBlock() failed\n"); 288a1b0ec30SJérôme Duval return status; 289d8772e0cSJérôme Duval } 290a1b0ec30SJérôme Duval 291a1b0ec30SJérôme Duval if (fRemovedBlocks == blocksToRemove) { 292a1b0ec30SJérôme Duval fNumBlocks -= fRemovedBlocks; 293a1b0ec30SJérôme Duval numBlocks = _BlocksNeeded(oldNumBlocks); 294a1b0ec30SJérôme Duval 295a1b0ec30SJérôme Duval return _PerformFree(transaction); 296a1b0ec30SJérôme Duval } 297a1b0ec30SJérôme Duval } 298a1b0ec30SJérôme Duval 299a1b0ec30SJérôme Duval if (numBlocks < kMaxDoubleIndirect) { 300a1b0ec30SJérôme Duval status = _RemoveFromDoubleIndirectBlock(transaction, numBlocks); 301a1b0ec30SJérôme Duval 302d8772e0cSJérôme Duval if (status != B_OK) { 303d8772e0cSJérôme Duval ERROR("DataStream::Shrink(): _RemoveFromDoubleIndirectBlock() failed\n"); 304a1b0ec30SJérôme Duval return status; 305d8772e0cSJérôme Duval } 306a1b0ec30SJérôme Duval 307a1b0ec30SJérôme Duval if (fRemovedBlocks == blocksToRemove) { 308a1b0ec30SJérôme Duval fNumBlocks -= fRemovedBlocks; 309a1b0ec30SJérôme Duval numBlocks = _BlocksNeeded(oldNumBlocks); 310a1b0ec30SJérôme Duval 311a1b0ec30SJérôme Duval return _PerformFree(transaction); 312a1b0ec30SJérôme Duval } 313a1b0ec30SJérôme Duval } 314a1b0ec30SJérôme Duval 315a1b0ec30SJérôme Duval status = _RemoveFromTripleIndirectBlock(transaction, numBlocks); 316a1b0ec30SJérôme Duval 317d8772e0cSJérôme Duval if (status != B_OK) { 318d8772e0cSJérôme Duval ERROR("DataStream::Shrink(): _RemoveFromTripleIndirectBlock() failed\n"); 319a1b0ec30SJérôme Duval return status; 320d8772e0cSJérôme Duval } 321a1b0ec30SJérôme Duval 322a1b0ec30SJérôme Duval fNumBlocks -= fRemovedBlocks; 323a1b0ec30SJérôme Duval numBlocks = _BlocksNeeded(oldNumBlocks); 324a1b0ec30SJérôme Duval 325a1b0ec30SJérôme Duval return _PerformFree(transaction); 326a1b0ec30SJérôme Duval } 327a1b0ec30SJérôme Duval 328a1b0ec30SJérôme Duval 329a1b0ec30SJérôme Duval uint32 330d8772e0cSJérôme Duval DataStream::_BlocksNeeded(off_t numBlocks) 331a1b0ec30SJérôme Duval { 332d8772e0cSJérôme Duval TRACE("DataStream::BlocksNeeded(): num blocks %llu\n", numBlocks); 333d8772e0cSJérôme Duval off_t blocksNeeded = 0; 334a1b0ec30SJérôme Duval 335a1b0ec30SJérôme Duval if (numBlocks > fNumBlocks) { 336a1b0ec30SJérôme Duval blocksNeeded += numBlocks - fNumBlocks; 337a1b0ec30SJérôme Duval 338a1b0ec30SJérôme Duval if (numBlocks > kMaxDirect) { 339a1b0ec30SJérôme Duval if (fNumBlocks <= kMaxDirect) 340a1b0ec30SJérôme Duval blocksNeeded += 1; 341a1b0ec30SJérôme Duval 342a1b0ec30SJérôme Duval if (numBlocks > kMaxIndirect) { 343a1b0ec30SJérôme Duval if (fNumBlocks <= kMaxIndirect) { 344a1b0ec30SJérôme Duval blocksNeeded += 2 + (numBlocks - kMaxIndirect - 1) 345a1b0ec30SJérôme Duval / kIndirectsPerBlock; 346a1b0ec30SJérôme Duval } else { 347de66992bSJérôme Duval blocksNeeded += (numBlocks - kMaxIndirect - 1) 348de66992bSJérôme Duval / kIndirectsPerBlock - (fNumBlocks 349de66992bSJérôme Duval - kMaxIndirect - 1) / kIndirectsPerBlock; 350a1b0ec30SJérôme Duval } 351a1b0ec30SJérôme Duval 352a1b0ec30SJérôme Duval if (numBlocks > kMaxDoubleIndirect) { 353a1b0ec30SJérôme Duval if (fNumBlocks <= kMaxDoubleIndirect) { 354a1b0ec30SJérôme Duval blocksNeeded += 2 + (numBlocks - kMaxDoubleIndirect - 1) 355a1b0ec30SJérôme Duval / kIndirectsPerBlock2; 356a1b0ec30SJérôme Duval } else { 357de66992bSJérôme Duval blocksNeeded += (numBlocks - kMaxDoubleIndirect - 1) 358de66992bSJérôme Duval / kIndirectsPerBlock - (fNumBlocks 359de66992bSJérôme Duval - kMaxDoubleIndirect - 1) / kIndirectsPerBlock; 360a1b0ec30SJérôme Duval } 361a1b0ec30SJérôme Duval } 362a1b0ec30SJérôme Duval } 363a1b0ec30SJérôme Duval } 364a1b0ec30SJérôme Duval } 365a1b0ec30SJérôme Duval 366d8772e0cSJérôme Duval TRACE("DataStream::BlocksNeeded(): %llu\n", blocksNeeded); 367a1b0ec30SJérôme Duval return blocksNeeded; 368a1b0ec30SJérôme Duval } 369a1b0ec30SJérôme Duval 370a1b0ec30SJérôme Duval 371a1b0ec30SJérôme Duval status_t 372d8772e0cSJérôme Duval DataStream::_GetBlock(Transaction& transaction, uint32& blockNum) 373a1b0ec30SJérôme Duval { 374d8772e0cSJérôme Duval TRACE("DataStream::_GetBlock(): allocated: %lu, pos: %llu, waiting: %lu\n", 375a1b0ec30SJérôme Duval fAllocated, fAllocatedPos, fWaiting); 376a1b0ec30SJérôme Duval 377a1b0ec30SJérôme Duval if (fAllocated == 0) { 378a1b0ec30SJérôme Duval uint32 blockGroup = (fAllocatedPos - fFirstBlock) 379a1b0ec30SJérôme Duval / fVolume->BlocksPerGroup(); 380a1b0ec30SJérôme Duval 381a1b0ec30SJérôme Duval status_t status = fVolume->AllocateBlocks(transaction, 1, fWaiting, 382a1b0ec30SJérôme Duval blockGroup, fAllocatedPos, fAllocated); 383d8772e0cSJérôme Duval if (status != B_OK) { 384d8772e0cSJérôme Duval ERROR("DataStream::_GetBlock(): AllocateBlocks() failed()\n"); 385a1b0ec30SJérôme Duval return status; 386d8772e0cSJérôme Duval } 387a1b0ec30SJérôme Duval 388a1b0ec30SJérôme Duval fWaiting -= fAllocated; 389de66992bSJérôme Duval 390d8772e0cSJérôme Duval TRACE("DataStream::_GetBlock(): newAllocated: %lu, newpos: %llu," 391de66992bSJérôme Duval "newwaiting: %lu\n", fAllocated, fAllocatedPos, fWaiting); 392a1b0ec30SJérôme Duval } 393a1b0ec30SJérôme Duval 394a1b0ec30SJérôme Duval fAllocated--; 395d8772e0cSJérôme Duval blockNum = (uint32)fAllocatedPos++; 396a1b0ec30SJérôme Duval 397a1b0ec30SJérôme Duval return B_OK; 398a1b0ec30SJérôme Duval } 399a1b0ec30SJérôme Duval 400a1b0ec30SJérôme Duval 401a1b0ec30SJérôme Duval status_t 402a1b0ec30SJérôme Duval DataStream::_PrepareBlock(Transaction& transaction, uint32* pos, 403a1b0ec30SJérôme Duval uint32& blockNum, bool& clear) 404a1b0ec30SJérôme Duval { 405a1b0ec30SJérôme Duval blockNum = B_LENDIAN_TO_HOST_INT32(*pos); 406a1b0ec30SJérôme Duval clear = false; 407a1b0ec30SJérôme Duval 408a1b0ec30SJérôme Duval if (blockNum == 0) { 409a1b0ec30SJérôme Duval status_t status = _GetBlock(transaction, blockNum); 410d8772e0cSJérôme Duval if (status != B_OK) { 411d8772e0cSJérôme Duval ERROR("DataStream::_PrepareBlock() _GetBlock() failed blockNum %ld\n", blockNum); 412a1b0ec30SJérôme Duval return status; 413d8772e0cSJérôme Duval } 414a1b0ec30SJérôme Duval 415a1b0ec30SJérôme Duval *pos = B_HOST_TO_LENDIAN_INT32(blockNum); 416a1b0ec30SJérôme Duval clear = true; 417a1b0ec30SJérôme Duval } 418a1b0ec30SJérôme Duval 419a1b0ec30SJérôme Duval return B_OK; 420a1b0ec30SJérôme Duval } 421a1b0ec30SJérôme Duval 422a1b0ec30SJérôme Duval 423a1b0ec30SJérôme Duval status_t 424d8772e0cSJérôme Duval DataStream::_AddBlocks(Transaction& transaction, uint32* block, off_t _count) 425a1b0ec30SJérôme Duval { 426d8772e0cSJérôme Duval off_t count = _count; 427d8772e0cSJérôme Duval TRACE("DataStream::_AddBlocks(): count: %llu\n", count); 428a1b0ec30SJérôme Duval 429a1b0ec30SJérôme Duval while (count > 0) { 430a1b0ec30SJérôme Duval uint32 blockNum; 431a1b0ec30SJérôme Duval status_t status = _GetBlock(transaction, blockNum); 432a1b0ec30SJérôme Duval if (status != B_OK) 433a1b0ec30SJérôme Duval return status; 434a1b0ec30SJérôme Duval 435a1b0ec30SJérôme Duval *(block++) = B_HOST_TO_LENDIAN_INT32(blockNum); 436a1b0ec30SJérôme Duval --count; 437a1b0ec30SJérôme Duval } 438a1b0ec30SJérôme Duval 439a1b0ec30SJérôme Duval fNumBlocks += _count; 440a1b0ec30SJérôme Duval 441a1b0ec30SJérôme Duval return B_OK; 442a1b0ec30SJérôme Duval } 443a1b0ec30SJérôme Duval 444a1b0ec30SJérôme Duval 445a1b0ec30SJérôme Duval status_t 446d8772e0cSJérôme Duval DataStream::_AddBlocks(Transaction& transaction, uint32* block, off_t start, 447d8772e0cSJérôme Duval off_t end, int recursion) 448a1b0ec30SJérôme Duval { 449d8772e0cSJérôme Duval TRACE("DataStream::_AddBlocks(): start: %llu, end %llu, recursion: %d\n", 450a1b0ec30SJérôme Duval start, end, recursion); 451a1b0ec30SJérôme Duval 452a1b0ec30SJérôme Duval bool clear; 453a1b0ec30SJérôme Duval uint32 blockNum; 454a1b0ec30SJérôme Duval status_t status = _PrepareBlock(transaction, block, blockNum, clear); 455a1b0ec30SJérôme Duval if (status != B_OK) 456a1b0ec30SJérôme Duval return status; 457a1b0ec30SJérôme Duval 458a1b0ec30SJérôme Duval CachedBlock cached(fVolume); 459a1b0ec30SJérôme Duval uint32* childBlock = (uint32*)cached.SetToWritable(transaction, blockNum, 460a1b0ec30SJérôme Duval clear); 461a1b0ec30SJérôme Duval if (childBlock == NULL) 462a1b0ec30SJérôme Duval return B_IO_ERROR; 463a1b0ec30SJérôme Duval 464a1b0ec30SJérôme Duval if (recursion == 0) 465a1b0ec30SJérôme Duval return _AddBlocks(transaction, &childBlock[start], end - start); 466a1b0ec30SJérôme Duval 467a1b0ec30SJérôme Duval uint32 elementWidth; 468a1b0ec30SJérôme Duval if (recursion == 1) 469a1b0ec30SJérôme Duval elementWidth = kIndirectsPerBlock; 470a1b0ec30SJérôme Duval else if (recursion == 2) 471a1b0ec30SJérôme Duval elementWidth = kIndirectsPerBlock2; 472a1b0ec30SJérôme Duval else { 473de66992bSJérôme Duval panic("Undefined recursion level\n"); 474a1b0ec30SJérôme Duval elementWidth = 0; 475a1b0ec30SJérôme Duval } 476a1b0ec30SJérôme Duval 477a1b0ec30SJérôme Duval uint32 elementPos = start / elementWidth; 478a1b0ec30SJérôme Duval uint32 endPos = end / elementWidth; 479a1b0ec30SJérôme Duval 480a1b0ec30SJérôme Duval TRACE("DataStream::_AddBlocks(): element pos: %lu, end pos: %lu\n", 481a1b0ec30SJérôme Duval elementPos, endPos); 482a1b0ec30SJérôme Duval 483a1b0ec30SJérôme Duval recursion--; 484a1b0ec30SJérôme Duval 485a1b0ec30SJérôme Duval if (elementPos == endPos) { 486a1b0ec30SJérôme Duval return _AddBlocks(transaction, &childBlock[elementPos], 487a1b0ec30SJérôme Duval start % elementWidth, end % elementWidth, recursion); 488a1b0ec30SJérôme Duval } 489a1b0ec30SJérôme Duval 490a1b0ec30SJérôme Duval if (start % elementWidth != 0) { 491a1b0ec30SJérôme Duval status = _AddBlocks(transaction, &childBlock[elementPos], 492a1b0ec30SJérôme Duval start % elementWidth, elementWidth, recursion); 493d8772e0cSJérôme Duval if (status != B_OK) { 494d8772e0cSJérôme Duval ERROR("DataStream::_AddBlocks() _AddBlocks() start failed\n"); 495a1b0ec30SJérôme Duval return status; 496d8772e0cSJérôme Duval } 497a1b0ec30SJérôme Duval 498a1b0ec30SJérôme Duval elementPos++; 499a1b0ec30SJérôme Duval } 500a1b0ec30SJérôme Duval 501a1b0ec30SJérôme Duval while (elementPos < endPos) { 502a1b0ec30SJérôme Duval status = _AddBlocks(transaction, &childBlock[elementPos], 0, 503a1b0ec30SJérôme Duval elementWidth, recursion); 504d8772e0cSJérôme Duval if (status != B_OK) { 505d8772e0cSJérôme Duval ERROR("DataStream::_AddBlocks() _AddBlocks() mid failed\n"); 506a1b0ec30SJérôme Duval return status; 507d8772e0cSJérôme Duval } 508a1b0ec30SJérôme Duval 509a1b0ec30SJérôme Duval elementPos++; 510a1b0ec30SJérôme Duval } 511a1b0ec30SJérôme Duval 512a1b0ec30SJérôme Duval if (end % elementWidth != 0) { 513a1b0ec30SJérôme Duval status = _AddBlocks(transaction, &childBlock[elementPos], 0, 514a1b0ec30SJérôme Duval end % elementWidth, recursion); 515d8772e0cSJérôme Duval if (status != B_OK) { 516d8772e0cSJérôme Duval ERROR("DataStream::_AddBlocks() _AddBlocks() end failed\n"); 517a1b0ec30SJérôme Duval return status; 518a1b0ec30SJérôme Duval } 519d8772e0cSJérôme Duval } 520a1b0ec30SJérôme Duval 521a1b0ec30SJérôme Duval return B_OK; 522a1b0ec30SJérôme Duval } 523a1b0ec30SJérôme Duval 524a1b0ec30SJérôme Duval 525a1b0ec30SJérôme Duval status_t 526a1b0ec30SJérôme Duval DataStream::_AddForDirectBlocks(Transaction& transaction, uint32 numBlocks) 527a1b0ec30SJérôme Duval { 528d8772e0cSJérôme Duval TRACE("DataStream::_AddForDirectBlocks(): current size: %llu, target size: " 529a1b0ec30SJérôme Duval "%lu\n", fNumBlocks, numBlocks); 530a1b0ec30SJérôme Duval uint32* direct = &fStream->direct[fNumBlocks]; 531a1b0ec30SJérôme Duval uint32 end = numBlocks > kMaxDirect ? kMaxDirect : numBlocks; 532a1b0ec30SJérôme Duval 533a1b0ec30SJérôme Duval return _AddBlocks(transaction, direct, end - fNumBlocks); 534a1b0ec30SJérôme Duval } 535a1b0ec30SJérôme Duval 536a1b0ec30SJérôme Duval 537a1b0ec30SJérôme Duval status_t 538a1b0ec30SJérôme Duval DataStream::_AddForIndirectBlock(Transaction& transaction, uint32 numBlocks) 539a1b0ec30SJérôme Duval { 540d8772e0cSJérôme Duval TRACE("DataStream::_AddForIndirectBlocks(): current size: %llu, target " 541a1b0ec30SJérôme Duval "size: %lu\n", fNumBlocks, numBlocks); 542a1b0ec30SJérôme Duval uint32 *indirect = &fStream->indirect; 543a1b0ec30SJérôme Duval uint32 start = fNumBlocks - kMaxDirect; 544a1b0ec30SJérôme Duval uint32 end = numBlocks - kMaxDirect; 545a1b0ec30SJérôme Duval 546a1b0ec30SJérôme Duval if (end > kIndirectsPerBlock) 547a1b0ec30SJérôme Duval end = kIndirectsPerBlock; 548a1b0ec30SJérôme Duval 549a1b0ec30SJérôme Duval return _AddBlocks(transaction, indirect, start, end, 0); 550a1b0ec30SJérôme Duval } 551a1b0ec30SJérôme Duval 552a1b0ec30SJérôme Duval 553a1b0ec30SJérôme Duval status_t 554a1b0ec30SJérôme Duval DataStream::_AddForDoubleIndirectBlock(Transaction& transaction, 555a1b0ec30SJérôme Duval uint32 numBlocks) 556a1b0ec30SJérôme Duval { 557d8772e0cSJérôme Duval TRACE("DataStream::_AddForDoubleIndirectBlock(): current size: %llu, " 558a1b0ec30SJérôme Duval "target size: %lu\n", fNumBlocks, numBlocks); 559a1b0ec30SJérôme Duval uint32 *doubleIndirect = &fStream->double_indirect; 560a1b0ec30SJérôme Duval uint32 start = fNumBlocks - kMaxIndirect; 561a1b0ec30SJérôme Duval uint32 end = numBlocks - kMaxIndirect; 562a1b0ec30SJérôme Duval 563a1b0ec30SJérôme Duval if (end > kIndirectsPerBlock2) 564a1b0ec30SJérôme Duval end = kIndirectsPerBlock2; 565a1b0ec30SJérôme Duval 566a1b0ec30SJérôme Duval return _AddBlocks(transaction, doubleIndirect, start, end, 1); 567a1b0ec30SJérôme Duval } 568a1b0ec30SJérôme Duval 569a1b0ec30SJérôme Duval 570a1b0ec30SJérôme Duval status_t 571a1b0ec30SJérôme Duval DataStream::_AddForTripleIndirectBlock(Transaction& transaction, 572a1b0ec30SJérôme Duval uint32 numBlocks) 573a1b0ec30SJérôme Duval { 574d8772e0cSJérôme Duval TRACE("DataStream::_AddForTripleIndirectBlock(): current size: %llu, " 575a1b0ec30SJérôme Duval "target size: %lu\n", fNumBlocks, numBlocks); 576a1b0ec30SJérôme Duval uint32 *tripleIndirect = &fStream->triple_indirect; 577a1b0ec30SJérôme Duval uint32 start = fNumBlocks - kMaxDoubleIndirect; 578a1b0ec30SJérôme Duval uint32 end = numBlocks - kMaxDoubleIndirect; 579a1b0ec30SJérôme Duval 580a1b0ec30SJérôme Duval return _AddBlocks(transaction, tripleIndirect, start, end, 2); 581a1b0ec30SJérôme Duval } 582a1b0ec30SJérôme Duval 583a1b0ec30SJérôme Duval 584a1b0ec30SJérôme Duval status_t 585a1b0ec30SJérôme Duval DataStream::_PerformFree(Transaction& transaction) 586a1b0ec30SJérôme Duval { 587a1b0ec30SJérôme Duval TRACE("DataStream::_PerformFree(): start: %lu, count: %lu\n", fFreeStart, 588a1b0ec30SJérôme Duval fFreeCount); 589a1b0ec30SJérôme Duval status_t status; 590a1b0ec30SJérôme Duval 591a1b0ec30SJérôme Duval if (fFreeCount == 0) 592a1b0ec30SJérôme Duval status = B_OK; 593a1b0ec30SJérôme Duval else 594a1b0ec30SJérôme Duval status = fVolume->FreeBlocks(transaction, fFreeStart, fFreeCount); 595a1b0ec30SJérôme Duval 596a1b0ec30SJérôme Duval fFreeStart = 0; 597a1b0ec30SJérôme Duval fFreeCount = 0; 598a1b0ec30SJérôme Duval 599a1b0ec30SJérôme Duval return status; 600a1b0ec30SJérôme Duval } 601a1b0ec30SJérôme Duval 602a1b0ec30SJérôme Duval 603a1b0ec30SJérôme Duval status_t 604a1b0ec30SJérôme Duval DataStream::_MarkBlockForRemoval(Transaction& transaction, uint32* block) 605a1b0ec30SJérôme Duval { 606d8772e0cSJérôme Duval 607a1b0ec30SJérôme Duval TRACE("DataStream::_MarkBlockForRemoval(*(%p) = %lu): free start: %lu, " 608d8772e0cSJérôme Duval "free count: %lu\n", block, B_LENDIAN_TO_HOST_INT32(*block), 609d8772e0cSJérôme Duval fFreeStart, fFreeCount); 610a1b0ec30SJérôme Duval uint32 blockNum = B_LENDIAN_TO_HOST_INT32(*block); 611a1b0ec30SJérôme Duval *block = 0; 612a1b0ec30SJérôme Duval 613a1b0ec30SJérôme Duval if (blockNum != fFreeStart + fFreeCount) { 614a1b0ec30SJérôme Duval if (fFreeCount != 0) { 615a1b0ec30SJérôme Duval status_t status = fVolume->FreeBlocks(transaction, fFreeStart, 616a1b0ec30SJérôme Duval fFreeCount); 617a1b0ec30SJérôme Duval if (status != B_OK) 618a1b0ec30SJérôme Duval return status; 619a1b0ec30SJérôme Duval } 620a1b0ec30SJérôme Duval 621a1b0ec30SJérôme Duval fFreeStart = blockNum; 622a1b0ec30SJérôme Duval fFreeCount = 0; 623a1b0ec30SJérôme Duval } 624a1b0ec30SJérôme Duval 625a1b0ec30SJérôme Duval fFreeCount++; 626a1b0ec30SJérôme Duval 627a1b0ec30SJérôme Duval return B_OK; 628a1b0ec30SJérôme Duval } 629a1b0ec30SJérôme Duval 630a1b0ec30SJérôme Duval 631a1b0ec30SJérôme Duval status_t 632a1b0ec30SJérôme Duval DataStream::_FreeBlocks(Transaction& transaction, uint32* block, uint32 _count) 633a1b0ec30SJérôme Duval { 634a1b0ec30SJérôme Duval uint32 count = _count; 635a1b0ec30SJérôme Duval TRACE("DataStream::_FreeBlocks(%p, %lu)\n", block, count); 636a1b0ec30SJérôme Duval 637a1b0ec30SJérôme Duval while (count > 0) { 638a1b0ec30SJérôme Duval status_t status = _MarkBlockForRemoval(transaction, block); 639a1b0ec30SJérôme Duval if (status != B_OK) 640a1b0ec30SJérôme Duval return status; 641a1b0ec30SJérôme Duval 642a1b0ec30SJérôme Duval block++; 643a1b0ec30SJérôme Duval count--; 644a1b0ec30SJérôme Duval } 645a1b0ec30SJérôme Duval 646a1b0ec30SJérôme Duval fRemovedBlocks += _count; 647a1b0ec30SJérôme Duval 648a1b0ec30SJérôme Duval return B_OK; 649a1b0ec30SJérôme Duval } 650a1b0ec30SJérôme Duval 651a1b0ec30SJérôme Duval 652a1b0ec30SJérôme Duval status_t 653d8772e0cSJérôme Duval DataStream::_FreeBlocks(Transaction& transaction, uint32* block, off_t start, 654d8772e0cSJérôme Duval off_t end, bool freeParent, int recursion) 655a1b0ec30SJérôme Duval { 656a1b0ec30SJérôme Duval // TODO: Designed specifically for shrinking. Perhaps make it more general? 657d8772e0cSJérôme Duval TRACE("DataStream::_FreeBlocks(%p, %llu, %llu, %c, %d)\n", 658a1b0ec30SJérôme Duval block, start, end, freeParent ? 't' : 'f', recursion); 659a1b0ec30SJérôme Duval 660a1b0ec30SJérôme Duval uint32 blockNum = B_LENDIAN_TO_HOST_INT32(*block); 661a1b0ec30SJérôme Duval 662a1b0ec30SJérôme Duval if (freeParent) { 663a1b0ec30SJérôme Duval status_t status = _MarkBlockForRemoval(transaction, block); 664a1b0ec30SJérôme Duval if (status != B_OK) 665a1b0ec30SJérôme Duval return status; 666a1b0ec30SJérôme Duval } 667a1b0ec30SJérôme Duval 668a1b0ec30SJérôme Duval CachedBlock cached(fVolume); 669a1b0ec30SJérôme Duval uint32* childBlock = (uint32*)cached.SetToWritable(transaction, blockNum); 670a1b0ec30SJérôme Duval if (childBlock == NULL) 671a1b0ec30SJérôme Duval return B_IO_ERROR; 672a1b0ec30SJérôme Duval 673a1b0ec30SJérôme Duval if (recursion == 0) 674a1b0ec30SJérôme Duval return _FreeBlocks(transaction, &childBlock[start], end - start); 675a1b0ec30SJérôme Duval 676a1b0ec30SJérôme Duval uint32 elementWidth; 677a1b0ec30SJérôme Duval if (recursion == 1) 678a1b0ec30SJérôme Duval elementWidth = kIndirectsPerBlock; 679a1b0ec30SJérôme Duval else if (recursion == 2) 680a1b0ec30SJérôme Duval elementWidth = kIndirectsPerBlock2; 681a1b0ec30SJérôme Duval else { 682a1b0ec30SJérôme Duval panic("Undefinied recursion level\n"); 683a1b0ec30SJérôme Duval elementWidth = 0; 684a1b0ec30SJérôme Duval } 685a1b0ec30SJérôme Duval 686a1b0ec30SJérôme Duval uint32 elementPos = start / elementWidth; 687a1b0ec30SJérôme Duval uint32 endPos = end / elementWidth; 688a1b0ec30SJérôme Duval 689a1b0ec30SJérôme Duval recursion--; 690a1b0ec30SJérôme Duval 691a1b0ec30SJérôme Duval if (elementPos == endPos) { 692a1b0ec30SJérôme Duval bool free = freeParent || start % elementWidth == 0; 693a1b0ec30SJérôme Duval return _FreeBlocks(transaction, &childBlock[elementPos], 694a1b0ec30SJérôme Duval start % elementWidth, end % elementWidth, free, recursion); 695a1b0ec30SJérôme Duval } 696a1b0ec30SJérôme Duval 697a1b0ec30SJérôme Duval status_t status = B_OK; 698a1b0ec30SJérôme Duval 699a1b0ec30SJérôme Duval if (start % elementWidth != 0) { 700a1b0ec30SJérôme Duval status = _FreeBlocks(transaction, &childBlock[elementPos], 701a1b0ec30SJérôme Duval start % elementWidth, elementWidth, false, recursion); 702a1b0ec30SJérôme Duval if (status != B_OK) 703a1b0ec30SJérôme Duval return status; 704a1b0ec30SJérôme Duval 705a1b0ec30SJérôme Duval elementPos++; 706a1b0ec30SJérôme Duval } 707a1b0ec30SJérôme Duval 708a1b0ec30SJérôme Duval while (elementPos < endPos) { 709a1b0ec30SJérôme Duval status = _FreeBlocks(transaction, &childBlock[elementPos], 0, 710a1b0ec30SJérôme Duval elementWidth, true, recursion); 711a1b0ec30SJérôme Duval if (status != B_OK) 712a1b0ec30SJérôme Duval return status; 713a1b0ec30SJérôme Duval 714a1b0ec30SJérôme Duval elementPos++; 715a1b0ec30SJérôme Duval } 716a1b0ec30SJérôme Duval 717a1b0ec30SJérôme Duval if (end % elementWidth != 0) { 718a1b0ec30SJérôme Duval status = _FreeBlocks(transaction, &childBlock[elementPos], 0, 719a1b0ec30SJérôme Duval end % elementWidth, true, recursion); 720a1b0ec30SJérôme Duval } 721a1b0ec30SJérôme Duval 722a1b0ec30SJérôme Duval return status; 723a1b0ec30SJérôme Duval } 724a1b0ec30SJérôme Duval 725a1b0ec30SJérôme Duval 726a1b0ec30SJérôme Duval status_t 727a1b0ec30SJérôme Duval DataStream::_RemoveFromDirectBlocks(Transaction& transaction, uint32 numBlocks) 728a1b0ec30SJérôme Duval { 729d8772e0cSJérôme Duval TRACE("DataStream::_RemoveFromDirectBlocks(): current size: %llu, " 730a1b0ec30SJérôme Duval "target size: %lu\n", fNumBlocks, numBlocks); 731a1b0ec30SJérôme Duval uint32* direct = &fStream->direct[numBlocks]; 732d8772e0cSJérôme Duval off_t end = fNumBlocks > kMaxDirect ? kMaxDirect : fNumBlocks; 733a1b0ec30SJérôme Duval 734a1b0ec30SJérôme Duval return _FreeBlocks(transaction, direct, end - numBlocks); 735a1b0ec30SJérôme Duval } 736a1b0ec30SJérôme Duval 737a1b0ec30SJérôme Duval 738a1b0ec30SJérôme Duval status_t 739a1b0ec30SJérôme Duval DataStream::_RemoveFromIndirectBlock(Transaction& transaction, uint32 numBlocks) 740a1b0ec30SJérôme Duval { 741d8772e0cSJérôme Duval TRACE("DataStream::_RemoveFromIndirectBlock(): current size: %llu, " 742a1b0ec30SJérôme Duval "target size: %lu\n", fNumBlocks, numBlocks); 743a1b0ec30SJérôme Duval uint32* indirect = &fStream->indirect; 744d8772e0cSJérôme Duval off_t start = numBlocks <= kMaxDirect ? 0 : numBlocks - kMaxDirect; 745d8772e0cSJérôme Duval off_t end = fNumBlocks - kMaxDirect; 746a1b0ec30SJérôme Duval 747a1b0ec30SJérôme Duval if (end > kIndirectsPerBlock) 748a1b0ec30SJérôme Duval end = kIndirectsPerBlock; 749a1b0ec30SJérôme Duval 750a1b0ec30SJérôme Duval bool freeAll = start == 0; 751a1b0ec30SJérôme Duval 752a1b0ec30SJérôme Duval return _FreeBlocks(transaction, indirect, start, end, freeAll, 0); 753a1b0ec30SJérôme Duval } 754a1b0ec30SJérôme Duval 755a1b0ec30SJérôme Duval 756a1b0ec30SJérôme Duval status_t 757a1b0ec30SJérôme Duval DataStream::_RemoveFromDoubleIndirectBlock(Transaction& transaction, 758a1b0ec30SJérôme Duval uint32 numBlocks) 759a1b0ec30SJérôme Duval { 760d8772e0cSJérôme Duval TRACE("DataStream::_RemoveFromDoubleIndirectBlock(): current size: %llu, " 761a1b0ec30SJérôme Duval "target size: %lu\n", fNumBlocks, numBlocks); 762a1b0ec30SJérôme Duval uint32* doubleIndirect = &fStream->double_indirect; 763d8772e0cSJérôme Duval off_t start = numBlocks <= kMaxIndirect ? 0 : numBlocks - kMaxIndirect; 764d8772e0cSJérôme Duval off_t end = fNumBlocks - kMaxIndirect; 765a1b0ec30SJérôme Duval 766a1b0ec30SJérôme Duval if (end > kIndirectsPerBlock2) 767a1b0ec30SJérôme Duval end = kIndirectsPerBlock2; 768a1b0ec30SJérôme Duval 769a1b0ec30SJérôme Duval bool freeAll = start == 0; 770a1b0ec30SJérôme Duval 771a1b0ec30SJérôme Duval return _FreeBlocks(transaction, doubleIndirect, start, end, freeAll, 1); 772a1b0ec30SJérôme Duval } 773a1b0ec30SJérôme Duval 774a1b0ec30SJérôme Duval 775a1b0ec30SJérôme Duval status_t 776a1b0ec30SJérôme Duval DataStream::_RemoveFromTripleIndirectBlock(Transaction& transaction, 777a1b0ec30SJérôme Duval uint32 numBlocks) 778a1b0ec30SJérôme Duval { 779d8772e0cSJérôme Duval TRACE("DataStream::_RemoveFromTripleIndirectBlock(): current size: %llu, " 780a1b0ec30SJérôme Duval "target size: %lu\n", fNumBlocks, numBlocks); 781a1b0ec30SJérôme Duval uint32* tripleIndirect = &fStream->triple_indirect; 782d8772e0cSJérôme Duval off_t start = numBlocks <= kMaxDoubleIndirect ? 0 783a1b0ec30SJérôme Duval : numBlocks - kMaxDoubleIndirect; 784d8772e0cSJérôme Duval off_t end = fNumBlocks - kMaxDoubleIndirect; 785a1b0ec30SJérôme Duval 786a1b0ec30SJérôme Duval bool freeAll = start == 0; 787a1b0ec30SJérôme Duval 788a1b0ec30SJérôme Duval return _FreeBlocks(transaction, tripleIndirect, start, end, freeAll, 2); 789a1b0ec30SJérôme Duval } 790