1 /* 2 * Copyright 2001-2010, Haiku Inc. All rights reserved. 3 * This file may be used under the terms of the MIT License. 4 * 5 * Authors: 6 * Janito V. Ferreira Filho 7 */ 8 9 10 #include "DataStream.h" 11 12 #include "CachedBlock.h" 13 #include "Volume.h" 14 15 16 //#define TRACE_EXT2 17 #ifdef TRACE_EXT2 18 # define TRACE(x...) dprintf("\33[34mext2:\33[0m " x) 19 #else 20 # define TRACE(x...) ; 21 #endif 22 #define ERROR(x...) dprintf("\33[34mext2:\33[0m " x) 23 24 25 DataStream::DataStream(Volume* volume, ext2_data_stream* stream, 26 off_t size) 27 : 28 kBlockSize(volume->BlockSize()), 29 kIndirectsPerBlock(kBlockSize / sizeof(uint32)), 30 kIndirectsPerBlock2(kIndirectsPerBlock * kIndirectsPerBlock), 31 kIndirectsPerBlock3(kIndirectsPerBlock2 * kIndirectsPerBlock), 32 kMaxDirect(EXT2_DIRECT_BLOCKS), 33 kMaxIndirect(kMaxDirect + kIndirectsPerBlock), 34 kMaxDoubleIndirect(kMaxIndirect + kIndirectsPerBlock2), 35 fVolume(volume), 36 fStream(stream), 37 fFirstBlock(volume->FirstDataBlock()), 38 fAllocated(0), 39 fAllocatedPos(fFirstBlock), 40 fWaiting(0), 41 fFreeStart(0), 42 fFreeCount(0), 43 fRemovedBlocks(0), 44 fSize(size) 45 { 46 fNumBlocks = size == 0 ? 0 : ((size - 1) >> fVolume->BlockShift()) + 1; 47 } 48 49 50 DataStream::~DataStream() 51 { 52 } 53 54 55 status_t 56 DataStream::FindBlock(off_t offset, fsblock_t& block, uint32 *_count) 57 { 58 uint32 index = offset >> fVolume->BlockShift(); 59 60 if (offset >= fSize) { 61 TRACE("FindBlock: offset larger than inode size\n"); 62 return B_ENTRY_NOT_FOUND; 63 } 64 65 // TODO: we could return the size of the sparse range, as this might be more 66 // than just a block 67 68 if (index < EXT2_DIRECT_BLOCKS) { 69 // direct blocks 70 block = B_LENDIAN_TO_HOST_INT32(fStream->direct[index]); 71 ASSERT(block != 0); 72 if (_count) { 73 *_count = 1; 74 uint32 nextBlock = block; 75 while (++index < EXT2_DIRECT_BLOCKS 76 && fStream->direct[index] == ++nextBlock) 77 (*_count)++; 78 } 79 } else if ((index -= EXT2_DIRECT_BLOCKS) < kIndirectsPerBlock) { 80 // indirect blocks 81 CachedBlock cached(fVolume); 82 uint32* indirectBlocks = (uint32*)cached.SetTo(B_LENDIAN_TO_HOST_INT32( 83 fStream->indirect)); 84 if (indirectBlocks == NULL) 85 return B_IO_ERROR; 86 87 block = B_LENDIAN_TO_HOST_INT32(indirectBlocks[index]); 88 ASSERT(block != 0); 89 if (_count) { 90 *_count = 1; 91 uint32 nextBlock = block; 92 while (++index < kIndirectsPerBlock 93 && indirectBlocks[index] == ++nextBlock) 94 (*_count)++; 95 } 96 } else if ((index -= kIndirectsPerBlock) < kIndirectsPerBlock2) { 97 // double indirect blocks 98 CachedBlock cached(fVolume); 99 uint32* indirectBlocks = (uint32*)cached.SetTo(B_LENDIAN_TO_HOST_INT32( 100 fStream->double_indirect)); 101 if (indirectBlocks == NULL) 102 return B_IO_ERROR; 103 104 uint32 indirectIndex = B_LENDIAN_TO_HOST_INT32(indirectBlocks[index 105 / kIndirectsPerBlock]); 106 if (indirectIndex == 0) { 107 // a sparse indirect block 108 block = 0; 109 } else { 110 indirectBlocks = (uint32*)cached.SetTo(indirectIndex); 111 if (indirectBlocks == NULL) 112 return B_IO_ERROR; 113 114 block = B_LENDIAN_TO_HOST_INT32( 115 indirectBlocks[index & (kIndirectsPerBlock - 1)]); 116 if (_count) { 117 *_count = 1; 118 uint32 nextBlock = block; 119 while (((++index & (kIndirectsPerBlock - 1)) != 0) 120 && indirectBlocks[index & (kIndirectsPerBlock - 1)] 121 == ++nextBlock) 122 (*_count)++; 123 } 124 } 125 ASSERT(block != 0); 126 } else if ((index -= kIndirectsPerBlock2) < kIndirectsPerBlock3) { 127 // triple indirect blocks 128 CachedBlock cached(fVolume); 129 uint32* indirectBlocks = (uint32*)cached.SetTo(B_LENDIAN_TO_HOST_INT32( 130 fStream->triple_indirect)); 131 if (indirectBlocks == NULL) 132 return B_IO_ERROR; 133 134 uint32 indirectIndex = B_LENDIAN_TO_HOST_INT32(indirectBlocks[index 135 / kIndirectsPerBlock2]); 136 if (indirectIndex == 0) { 137 // a sparse indirect block 138 block = 0; 139 } else { 140 indirectBlocks = (uint32*)cached.SetTo(indirectIndex); 141 if (indirectBlocks == NULL) 142 return B_IO_ERROR; 143 144 indirectIndex = B_LENDIAN_TO_HOST_INT32( 145 indirectBlocks[(index / kIndirectsPerBlock) & (kIndirectsPerBlock - 1)]); 146 if (indirectIndex == 0) { 147 // a sparse indirect block 148 block = 0; 149 } else { 150 indirectBlocks = (uint32*)cached.SetTo(indirectIndex); 151 if (indirectBlocks == NULL) 152 return B_IO_ERROR; 153 154 block = B_LENDIAN_TO_HOST_INT32( 155 indirectBlocks[index & (kIndirectsPerBlock - 1)]); 156 if (_count) { 157 *_count = 1; 158 uint32 nextBlock = block; 159 while (((++index & (kIndirectsPerBlock - 1)) != 0) 160 && indirectBlocks[index & (kIndirectsPerBlock - 1)] 161 == ++nextBlock) 162 (*_count)++; 163 } 164 } 165 } 166 ASSERT(block != 0); 167 } else { 168 // Outside of the possible data stream 169 dprintf("ext2: block outside datastream!\n"); 170 return B_ERROR; 171 } 172 173 TRACE("inode %Ld: FindBlock(offset %lld): %lld %ld\n", ID(), offset, block, 174 _count != NULL ? *_count : 1); 175 return B_OK; 176 } 177 178 179 status_t 180 DataStream::Enlarge(Transaction& transaction, off_t& numBlocks) 181 { 182 TRACE("DataStream::Enlarge(): current size: %llu, target size: %llu\n", 183 fNumBlocks, numBlocks); 184 185 off_t targetBlocks = numBlocks; 186 fWaiting = _BlocksNeeded(numBlocks); 187 numBlocks = fWaiting; 188 189 status_t status; 190 191 if (fNumBlocks <= kMaxDirect) { 192 status = _AddForDirectBlocks(transaction, targetBlocks); 193 194 if (status != B_OK) { 195 ERROR("DataStream::Enlarge(): _AddForDirectBlocks() failed\n"); 196 return status; 197 } 198 199 TRACE("DataStream::Enlarge(): current size: %llu, target size: %llu\n", 200 fNumBlocks, targetBlocks); 201 202 if (fNumBlocks == targetBlocks) 203 return B_OK; 204 } 205 206 TRACE("DataStream::Enlarge(): indirect current size: %llu, target size: %llu\n", 207 fNumBlocks, targetBlocks); 208 209 if (fNumBlocks <= kMaxIndirect) { 210 status = _AddForIndirectBlock(transaction, targetBlocks); 211 212 if (status != B_OK) { 213 ERROR("DataStream::Enlarge(): _AddForIndirectBlock() failed\n"); 214 return status; 215 } 216 217 TRACE("DataStream::Enlarge(): current size: %llu, target size: %llu\n", 218 fNumBlocks, targetBlocks); 219 220 if (fNumBlocks == targetBlocks) 221 return B_OK; 222 } 223 224 TRACE("DataStream::Enlarge(): indirect2 current size: %llu, target size: %llu\n", 225 fNumBlocks, targetBlocks); 226 227 if (fNumBlocks <= kMaxDoubleIndirect) { 228 status = _AddForDoubleIndirectBlock(transaction, targetBlocks); 229 230 if (status != B_OK) { 231 ERROR("DataStream::Enlarge(): _AddForDoubleIndirectBlock() failed\n"); 232 return status; 233 } 234 235 TRACE("DataStream::Enlarge(): current size: %llu, target size: %llu\n", 236 fNumBlocks, targetBlocks); 237 238 if (fNumBlocks == targetBlocks) 239 return B_OK; 240 } 241 242 TRACE("DataStream::Enlarge(): indirect3 current size: %llu, target size: %llu\n", 243 fNumBlocks, targetBlocks); 244 245 TRACE("DataStream::Enlarge(): allocated: %lu, waiting: %lu\n", fAllocated, 246 fWaiting); 247 248 return _AddForTripleIndirectBlock(transaction, targetBlocks); 249 } 250 251 252 status_t 253 DataStream::Shrink(Transaction& transaction, off_t& numBlocks) 254 { 255 TRACE("DataStream::Shrink(): current size: %llu, target size: %llu\n", 256 fNumBlocks, numBlocks); 257 258 fFreeStart = 0; 259 fFreeCount = 0; 260 fRemovedBlocks = 0; 261 262 off_t oldNumBlocks = fNumBlocks; 263 off_t blocksToRemove = fNumBlocks - numBlocks; 264 265 status_t status; 266 267 if (numBlocks < kMaxDirect) { 268 status = _RemoveFromDirectBlocks(transaction, numBlocks); 269 270 if (status != B_OK) { 271 ERROR("DataStream::Shrink(): _RemoveFromDirectBlocks() failed\n"); 272 return status; 273 } 274 275 if (fRemovedBlocks == blocksToRemove) { 276 fNumBlocks -= fRemovedBlocks; 277 numBlocks = _BlocksNeeded(oldNumBlocks); 278 279 return _PerformFree(transaction); 280 } 281 } 282 283 if (numBlocks < kMaxIndirect) { 284 status = _RemoveFromIndirectBlock(transaction, numBlocks); 285 286 if (status != B_OK) { 287 ERROR("DataStream::Shrink(): _RemoveFromIndirectBlock() failed\n"); 288 return status; 289 } 290 291 if (fRemovedBlocks == blocksToRemove) { 292 fNumBlocks -= fRemovedBlocks; 293 numBlocks = _BlocksNeeded(oldNumBlocks); 294 295 return _PerformFree(transaction); 296 } 297 } 298 299 if (numBlocks < kMaxDoubleIndirect) { 300 status = _RemoveFromDoubleIndirectBlock(transaction, numBlocks); 301 302 if (status != B_OK) { 303 ERROR("DataStream::Shrink(): _RemoveFromDoubleIndirectBlock() failed\n"); 304 return status; 305 } 306 307 if (fRemovedBlocks == blocksToRemove) { 308 fNumBlocks -= fRemovedBlocks; 309 numBlocks = _BlocksNeeded(oldNumBlocks); 310 311 return _PerformFree(transaction); 312 } 313 } 314 315 status = _RemoveFromTripleIndirectBlock(transaction, numBlocks); 316 317 if (status != B_OK) { 318 ERROR("DataStream::Shrink(): _RemoveFromTripleIndirectBlock() failed\n"); 319 return status; 320 } 321 322 fNumBlocks -= fRemovedBlocks; 323 numBlocks = _BlocksNeeded(oldNumBlocks); 324 325 return _PerformFree(transaction); 326 } 327 328 329 uint32 330 DataStream::_BlocksNeeded(off_t numBlocks) 331 { 332 TRACE("DataStream::BlocksNeeded(): num blocks %llu\n", numBlocks); 333 off_t blocksNeeded = 0; 334 335 if (numBlocks > fNumBlocks) { 336 blocksNeeded += numBlocks - fNumBlocks; 337 338 if (numBlocks > kMaxDirect) { 339 if (fNumBlocks <= kMaxDirect) 340 blocksNeeded += 1; 341 342 if (numBlocks > kMaxIndirect) { 343 if (fNumBlocks <= kMaxIndirect) { 344 blocksNeeded += 2 + (numBlocks - kMaxIndirect - 1) 345 / kIndirectsPerBlock; 346 } else { 347 blocksNeeded += (numBlocks - kMaxIndirect - 1) 348 / kIndirectsPerBlock - (fNumBlocks 349 - kMaxIndirect - 1) / kIndirectsPerBlock; 350 } 351 352 if (numBlocks > kMaxDoubleIndirect) { 353 if (fNumBlocks <= kMaxDoubleIndirect) { 354 blocksNeeded += 2 + (numBlocks - kMaxDoubleIndirect - 1) 355 / kIndirectsPerBlock2; 356 } else { 357 blocksNeeded += (numBlocks - kMaxDoubleIndirect - 1) 358 / kIndirectsPerBlock - (fNumBlocks 359 - kMaxDoubleIndirect - 1) / kIndirectsPerBlock; 360 } 361 } 362 } 363 } 364 } 365 366 TRACE("DataStream::BlocksNeeded(): %llu\n", blocksNeeded); 367 return blocksNeeded; 368 } 369 370 371 status_t 372 DataStream::_GetBlock(Transaction& transaction, uint32& blockNum) 373 { 374 TRACE("DataStream::_GetBlock(): allocated: %lu, pos: %llu, waiting: %lu\n", 375 fAllocated, fAllocatedPos, fWaiting); 376 377 if (fAllocated == 0) { 378 uint32 blockGroup = (fAllocatedPos - fFirstBlock) 379 / fVolume->BlocksPerGroup(); 380 381 status_t status = fVolume->AllocateBlocks(transaction, 1, fWaiting, 382 blockGroup, fAllocatedPos, fAllocated); 383 if (status != B_OK) { 384 ERROR("DataStream::_GetBlock(): AllocateBlocks() failed()\n"); 385 return status; 386 } 387 388 fWaiting -= fAllocated; 389 390 TRACE("DataStream::_GetBlock(): newAllocated: %lu, newpos: %llu," 391 "newwaiting: %lu\n", fAllocated, fAllocatedPos, fWaiting); 392 } 393 394 fAllocated--; 395 blockNum = (uint32)fAllocatedPos++; 396 397 return B_OK; 398 } 399 400 401 status_t 402 DataStream::_PrepareBlock(Transaction& transaction, uint32* pos, 403 uint32& blockNum, bool& clear) 404 { 405 blockNum = B_LENDIAN_TO_HOST_INT32(*pos); 406 clear = false; 407 408 if (blockNum == 0) { 409 status_t status = _GetBlock(transaction, blockNum); 410 if (status != B_OK) { 411 ERROR("DataStream::_PrepareBlock() _GetBlock() failed blockNum %ld\n", blockNum); 412 return status; 413 } 414 415 *pos = B_HOST_TO_LENDIAN_INT32(blockNum); 416 clear = true; 417 } 418 419 return B_OK; 420 } 421 422 423 status_t 424 DataStream::_AddBlocks(Transaction& transaction, uint32* block, off_t _count) 425 { 426 off_t count = _count; 427 TRACE("DataStream::_AddBlocks(): count: %llu\n", count); 428 429 while (count > 0) { 430 uint32 blockNum; 431 status_t status = _GetBlock(transaction, blockNum); 432 if (status != B_OK) 433 return status; 434 435 *(block++) = B_HOST_TO_LENDIAN_INT32(blockNum); 436 --count; 437 } 438 439 fNumBlocks += _count; 440 441 return B_OK; 442 } 443 444 445 status_t 446 DataStream::_AddBlocks(Transaction& transaction, uint32* block, off_t start, 447 off_t end, int recursion) 448 { 449 TRACE("DataStream::_AddBlocks(): start: %llu, end %llu, recursion: %d\n", 450 start, end, recursion); 451 452 bool clear; 453 uint32 blockNum; 454 status_t status = _PrepareBlock(transaction, block, blockNum, clear); 455 if (status != B_OK) 456 return status; 457 458 CachedBlock cached(fVolume); 459 uint32* childBlock = (uint32*)cached.SetToWritable(transaction, blockNum, 460 clear); 461 if (childBlock == NULL) 462 return B_IO_ERROR; 463 464 if (recursion == 0) 465 return _AddBlocks(transaction, &childBlock[start], end - start); 466 467 uint32 elementWidth; 468 if (recursion == 1) 469 elementWidth = kIndirectsPerBlock; 470 else if (recursion == 2) 471 elementWidth = kIndirectsPerBlock2; 472 else { 473 panic("Undefined recursion level\n"); 474 elementWidth = 0; 475 } 476 477 uint32 elementPos = start / elementWidth; 478 uint32 endPos = end / elementWidth; 479 480 TRACE("DataStream::_AddBlocks(): element pos: %lu, end pos: %lu\n", 481 elementPos, endPos); 482 483 recursion--; 484 485 if (elementPos == endPos) { 486 return _AddBlocks(transaction, &childBlock[elementPos], 487 start % elementWidth, end % elementWidth, recursion); 488 } 489 490 if (start % elementWidth != 0) { 491 status = _AddBlocks(transaction, &childBlock[elementPos], 492 start % elementWidth, elementWidth, recursion); 493 if (status != B_OK) { 494 ERROR("DataStream::_AddBlocks() _AddBlocks() start failed\n"); 495 return status; 496 } 497 498 elementPos++; 499 } 500 501 while (elementPos < endPos) { 502 status = _AddBlocks(transaction, &childBlock[elementPos], 0, 503 elementWidth, recursion); 504 if (status != B_OK) { 505 ERROR("DataStream::_AddBlocks() _AddBlocks() mid failed\n"); 506 return status; 507 } 508 509 elementPos++; 510 } 511 512 if (end % elementWidth != 0) { 513 status = _AddBlocks(transaction, &childBlock[elementPos], 0, 514 end % elementWidth, recursion); 515 if (status != B_OK) { 516 ERROR("DataStream::_AddBlocks() _AddBlocks() end failed\n"); 517 return status; 518 } 519 } 520 521 return B_OK; 522 } 523 524 525 status_t 526 DataStream::_AddForDirectBlocks(Transaction& transaction, uint32 numBlocks) 527 { 528 TRACE("DataStream::_AddForDirectBlocks(): current size: %llu, target size: " 529 "%lu\n", fNumBlocks, numBlocks); 530 uint32* direct = &fStream->direct[fNumBlocks]; 531 uint32 end = numBlocks > kMaxDirect ? kMaxDirect : numBlocks; 532 533 return _AddBlocks(transaction, direct, end - fNumBlocks); 534 } 535 536 537 status_t 538 DataStream::_AddForIndirectBlock(Transaction& transaction, uint32 numBlocks) 539 { 540 TRACE("DataStream::_AddForIndirectBlocks(): current size: %llu, target " 541 "size: %lu\n", fNumBlocks, numBlocks); 542 uint32 *indirect = &fStream->indirect; 543 uint32 start = fNumBlocks - kMaxDirect; 544 uint32 end = numBlocks - kMaxDirect; 545 546 if (end > kIndirectsPerBlock) 547 end = kIndirectsPerBlock; 548 549 return _AddBlocks(transaction, indirect, start, end, 0); 550 } 551 552 553 status_t 554 DataStream::_AddForDoubleIndirectBlock(Transaction& transaction, 555 uint32 numBlocks) 556 { 557 TRACE("DataStream::_AddForDoubleIndirectBlock(): current size: %llu, " 558 "target size: %lu\n", fNumBlocks, numBlocks); 559 uint32 *doubleIndirect = &fStream->double_indirect; 560 uint32 start = fNumBlocks - kMaxIndirect; 561 uint32 end = numBlocks - kMaxIndirect; 562 563 if (end > kIndirectsPerBlock2) 564 end = kIndirectsPerBlock2; 565 566 return _AddBlocks(transaction, doubleIndirect, start, end, 1); 567 } 568 569 570 status_t 571 DataStream::_AddForTripleIndirectBlock(Transaction& transaction, 572 uint32 numBlocks) 573 { 574 TRACE("DataStream::_AddForTripleIndirectBlock(): current size: %llu, " 575 "target size: %lu\n", fNumBlocks, numBlocks); 576 uint32 *tripleIndirect = &fStream->triple_indirect; 577 uint32 start = fNumBlocks - kMaxDoubleIndirect; 578 uint32 end = numBlocks - kMaxDoubleIndirect; 579 580 return _AddBlocks(transaction, tripleIndirect, start, end, 2); 581 } 582 583 584 status_t 585 DataStream::_PerformFree(Transaction& transaction) 586 { 587 TRACE("DataStream::_PerformFree(): start: %lu, count: %lu\n", fFreeStart, 588 fFreeCount); 589 status_t status; 590 591 if (fFreeCount == 0) 592 status = B_OK; 593 else 594 status = fVolume->FreeBlocks(transaction, fFreeStart, fFreeCount); 595 596 fFreeStart = 0; 597 fFreeCount = 0; 598 599 return status; 600 } 601 602 603 status_t 604 DataStream::_MarkBlockForRemoval(Transaction& transaction, uint32* block) 605 { 606 607 TRACE("DataStream::_MarkBlockForRemoval(*(%p) = %lu): free start: %lu, " 608 "free count: %lu\n", block, B_LENDIAN_TO_HOST_INT32(*block), 609 fFreeStart, fFreeCount); 610 uint32 blockNum = B_LENDIAN_TO_HOST_INT32(*block); 611 *block = 0; 612 613 if (blockNum != fFreeStart + fFreeCount) { 614 if (fFreeCount != 0) { 615 status_t status = fVolume->FreeBlocks(transaction, fFreeStart, 616 fFreeCount); 617 if (status != B_OK) 618 return status; 619 } 620 621 fFreeStart = blockNum; 622 fFreeCount = 0; 623 } 624 625 fFreeCount++; 626 627 return B_OK; 628 } 629 630 631 status_t 632 DataStream::_FreeBlocks(Transaction& transaction, uint32* block, uint32 _count) 633 { 634 uint32 count = _count; 635 TRACE("DataStream::_FreeBlocks(%p, %lu)\n", block, count); 636 637 while (count > 0) { 638 status_t status = _MarkBlockForRemoval(transaction, block); 639 if (status != B_OK) 640 return status; 641 642 block++; 643 count--; 644 } 645 646 fRemovedBlocks += _count; 647 648 return B_OK; 649 } 650 651 652 status_t 653 DataStream::_FreeBlocks(Transaction& transaction, uint32* block, off_t start, 654 off_t end, bool freeParent, int recursion) 655 { 656 // TODO: Designed specifically for shrinking. Perhaps make it more general? 657 TRACE("DataStream::_FreeBlocks(%p, %llu, %llu, %c, %d)\n", 658 block, start, end, freeParent ? 't' : 'f', recursion); 659 660 uint32 blockNum = B_LENDIAN_TO_HOST_INT32(*block); 661 662 if (freeParent) { 663 status_t status = _MarkBlockForRemoval(transaction, block); 664 if (status != B_OK) 665 return status; 666 } 667 668 CachedBlock cached(fVolume); 669 uint32* childBlock = (uint32*)cached.SetToWritable(transaction, blockNum); 670 if (childBlock == NULL) 671 return B_IO_ERROR; 672 673 if (recursion == 0) 674 return _FreeBlocks(transaction, &childBlock[start], end - start); 675 676 uint32 elementWidth; 677 if (recursion == 1) 678 elementWidth = kIndirectsPerBlock; 679 else if (recursion == 2) 680 elementWidth = kIndirectsPerBlock2; 681 else { 682 panic("Undefinied recursion level\n"); 683 elementWidth = 0; 684 } 685 686 uint32 elementPos = start / elementWidth; 687 uint32 endPos = end / elementWidth; 688 689 recursion--; 690 691 if (elementPos == endPos) { 692 bool free = freeParent || start % elementWidth == 0; 693 return _FreeBlocks(transaction, &childBlock[elementPos], 694 start % elementWidth, end % elementWidth, free, recursion); 695 } 696 697 status_t status = B_OK; 698 699 if (start % elementWidth != 0) { 700 status = _FreeBlocks(transaction, &childBlock[elementPos], 701 start % elementWidth, elementWidth, false, recursion); 702 if (status != B_OK) 703 return status; 704 705 elementPos++; 706 } 707 708 while (elementPos < endPos) { 709 status = _FreeBlocks(transaction, &childBlock[elementPos], 0, 710 elementWidth, true, recursion); 711 if (status != B_OK) 712 return status; 713 714 elementPos++; 715 } 716 717 if (end % elementWidth != 0) { 718 status = _FreeBlocks(transaction, &childBlock[elementPos], 0, 719 end % elementWidth, true, recursion); 720 } 721 722 return status; 723 } 724 725 726 status_t 727 DataStream::_RemoveFromDirectBlocks(Transaction& transaction, uint32 numBlocks) 728 { 729 TRACE("DataStream::_RemoveFromDirectBlocks(): current size: %llu, " 730 "target size: %lu\n", fNumBlocks, numBlocks); 731 uint32* direct = &fStream->direct[numBlocks]; 732 off_t end = fNumBlocks > kMaxDirect ? kMaxDirect : fNumBlocks; 733 734 return _FreeBlocks(transaction, direct, end - numBlocks); 735 } 736 737 738 status_t 739 DataStream::_RemoveFromIndirectBlock(Transaction& transaction, uint32 numBlocks) 740 { 741 TRACE("DataStream::_RemoveFromIndirectBlock(): current size: %llu, " 742 "target size: %lu\n", fNumBlocks, numBlocks); 743 uint32* indirect = &fStream->indirect; 744 off_t start = numBlocks <= kMaxDirect ? 0 : numBlocks - kMaxDirect; 745 off_t end = fNumBlocks - kMaxDirect; 746 747 if (end > kIndirectsPerBlock) 748 end = kIndirectsPerBlock; 749 750 bool freeAll = start == 0; 751 752 return _FreeBlocks(transaction, indirect, start, end, freeAll, 0); 753 } 754 755 756 status_t 757 DataStream::_RemoveFromDoubleIndirectBlock(Transaction& transaction, 758 uint32 numBlocks) 759 { 760 TRACE("DataStream::_RemoveFromDoubleIndirectBlock(): current size: %llu, " 761 "target size: %lu\n", fNumBlocks, numBlocks); 762 uint32* doubleIndirect = &fStream->double_indirect; 763 off_t start = numBlocks <= kMaxIndirect ? 0 : numBlocks - kMaxIndirect; 764 off_t end = fNumBlocks - kMaxIndirect; 765 766 if (end > kIndirectsPerBlock2) 767 end = kIndirectsPerBlock2; 768 769 bool freeAll = start == 0; 770 771 return _FreeBlocks(transaction, doubleIndirect, start, end, freeAll, 1); 772 } 773 774 775 status_t 776 DataStream::_RemoveFromTripleIndirectBlock(Transaction& transaction, 777 uint32 numBlocks) 778 { 779 TRACE("DataStream::_RemoveFromTripleIndirectBlock(): current size: %llu, " 780 "target size: %lu\n", fNumBlocks, numBlocks); 781 uint32* tripleIndirect = &fStream->triple_indirect; 782 off_t start = numBlocks <= kMaxDoubleIndirect ? 0 783 : numBlocks - kMaxDoubleIndirect; 784 off_t end = fNumBlocks - kMaxDoubleIndirect; 785 786 bool freeAll = start == 0; 787 788 return _FreeBlocks(transaction, tripleIndirect, start, end, freeAll, 2); 789 } 790