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("FindBlock(offset %" B_PRIdOFF "): %" B_PRIu64" %" B_PRIu32 "\n", offset, 174 block, _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: %" B_PRIdOFF ", target size: %" 183 B_PRIdOFF "\n", 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: %" B_PRIdOFF 200 ", target size: %" B_PRIdOFF "\n", fNumBlocks, targetBlocks); 201 202 if (fNumBlocks == targetBlocks) 203 return B_OK; 204 } 205 206 TRACE("DataStream::Enlarge(): indirect current size: %" B_PRIdOFF 207 ", target size: %" B_PRIdOFF "\n", 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: %" B_PRIdOFF 218 ", target size: %" B_PRIdOFF "\n", fNumBlocks, targetBlocks); 219 220 if (fNumBlocks == targetBlocks) 221 return B_OK; 222 } 223 224 TRACE("DataStream::Enlarge(): indirect2 current size: %" B_PRIdOFF 225 ", target size: %" B_PRIdOFF "\n", 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: %" B_PRIdOFF 236 ", target size: %" B_PRIdOFF "\n", fNumBlocks, targetBlocks); 237 238 if (fNumBlocks == targetBlocks) 239 return B_OK; 240 } 241 242 TRACE("DataStream::Enlarge(): indirect3 current size: %" B_PRIdOFF 243 ", target size: %" B_PRIdOFF "\n", fNumBlocks, targetBlocks); 244 245 TRACE("DataStream::Enlarge(): allocated: %" B_PRIu32 ", waiting: %" 246 B_PRIu32 "\n", fAllocated, 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: %" B_PRIdOFF ", target size: %" 256 B_PRIdOFF "\n", 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 %" B_PRIdOFF "\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(): %" B_PRIdOFF "\n", blocksNeeded); 367 return blocksNeeded; 368 } 369 370 371 status_t 372 DataStream::_GetBlock(Transaction& transaction, uint32& blockNum) 373 { 374 TRACE("DataStream::_GetBlock(): allocated: %" B_PRIu32 ", pos: %" B_PRIu64 375 ", waiting: %" B_PRIu32 "\n", 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: %" B_PRIu32 ", newpos: %" 391 B_PRIu64 ", newwaiting: %" B_PRIu32 "\n", fAllocated, 392 fAllocatedPos, fWaiting); 393 } 394 395 fAllocated--; 396 blockNum = (uint32)fAllocatedPos++; 397 398 return B_OK; 399 } 400 401 402 status_t 403 DataStream::_PrepareBlock(Transaction& transaction, uint32* pos, 404 uint32& blockNum, bool& clear) 405 { 406 blockNum = B_LENDIAN_TO_HOST_INT32(*pos); 407 clear = false; 408 409 if (blockNum == 0) { 410 status_t status = _GetBlock(transaction, blockNum); 411 if (status != B_OK) { 412 ERROR("DataStream::_PrepareBlock() _GetBlock() failed blockNum %" 413 B_PRIu32 "\n", blockNum); 414 return status; 415 } 416 417 *pos = B_HOST_TO_LENDIAN_INT32(blockNum); 418 clear = true; 419 } 420 421 return B_OK; 422 } 423 424 425 status_t 426 DataStream::_AddBlocks(Transaction& transaction, uint32* block, off_t _count) 427 { 428 off_t count = _count; 429 TRACE("DataStream::_AddBlocks(): count: %" B_PRIdOFF "\n", count); 430 431 while (count > 0) { 432 uint32 blockNum; 433 status_t status = _GetBlock(transaction, blockNum); 434 if (status != B_OK) 435 return status; 436 437 *(block++) = B_HOST_TO_LENDIAN_INT32(blockNum); 438 --count; 439 } 440 441 fNumBlocks += _count; 442 443 return B_OK; 444 } 445 446 447 status_t 448 DataStream::_AddBlocks(Transaction& transaction, uint32* block, off_t start, 449 off_t end, int recursion) 450 { 451 TRACE("DataStream::_AddBlocks(): start: %" B_PRIdOFF ", end %" B_PRIdOFF 452 ", recursion: %d\n", start, end, recursion); 453 454 bool clear; 455 uint32 blockNum; 456 status_t status = _PrepareBlock(transaction, block, blockNum, clear); 457 if (status != B_OK) 458 return status; 459 460 CachedBlock cached(fVolume); 461 uint32* childBlock = (uint32*)cached.SetToWritable(transaction, blockNum, 462 clear); 463 if (childBlock == NULL) 464 return B_IO_ERROR; 465 466 if (recursion == 0) 467 return _AddBlocks(transaction, &childBlock[start], end - start); 468 469 uint32 elementWidth; 470 if (recursion == 1) 471 elementWidth = kIndirectsPerBlock; 472 else if (recursion == 2) 473 elementWidth = kIndirectsPerBlock2; 474 else { 475 panic("Undefined recursion level\n"); 476 elementWidth = 0; 477 } 478 479 uint32 elementPos = start / elementWidth; 480 uint32 endPos = end / elementWidth; 481 482 TRACE("DataStream::_AddBlocks(): element pos: %" B_PRIu32 ", end pos: %" 483 B_PRIu32 "\n", elementPos, endPos); 484 485 recursion--; 486 487 if (elementPos == endPos) { 488 return _AddBlocks(transaction, &childBlock[elementPos], 489 start % elementWidth, end % elementWidth, recursion); 490 } 491 492 if (start % elementWidth != 0) { 493 status = _AddBlocks(transaction, &childBlock[elementPos], 494 start % elementWidth, elementWidth, recursion); 495 if (status != B_OK) { 496 ERROR("DataStream::_AddBlocks() _AddBlocks() start failed\n"); 497 return status; 498 } 499 500 elementPos++; 501 } 502 503 while (elementPos < endPos) { 504 status = _AddBlocks(transaction, &childBlock[elementPos], 0, 505 elementWidth, recursion); 506 if (status != B_OK) { 507 ERROR("DataStream::_AddBlocks() _AddBlocks() mid failed\n"); 508 return status; 509 } 510 511 elementPos++; 512 } 513 514 if (end % elementWidth != 0) { 515 status = _AddBlocks(transaction, &childBlock[elementPos], 0, 516 end % elementWidth, recursion); 517 if (status != B_OK) { 518 ERROR("DataStream::_AddBlocks() _AddBlocks() end failed\n"); 519 return status; 520 } 521 } 522 523 return B_OK; 524 } 525 526 527 status_t 528 DataStream::_AddForDirectBlocks(Transaction& transaction, uint32 numBlocks) 529 { 530 TRACE("DataStream::_AddForDirectBlocks(): current size: %" B_PRIdOFF 531 ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks); 532 uint32* direct = &fStream->direct[fNumBlocks]; 533 uint32 end = numBlocks > kMaxDirect ? kMaxDirect : numBlocks; 534 535 return _AddBlocks(transaction, direct, end - fNumBlocks); 536 } 537 538 539 status_t 540 DataStream::_AddForIndirectBlock(Transaction& transaction, uint32 numBlocks) 541 { 542 TRACE("DataStream::_AddForIndirectBlocks(): current size: %" B_PRIdOFF 543 ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks); 544 uint32 *indirect = &fStream->indirect; 545 uint32 start = fNumBlocks - kMaxDirect; 546 uint32 end = numBlocks - kMaxDirect; 547 548 if (end > kIndirectsPerBlock) 549 end = kIndirectsPerBlock; 550 551 return _AddBlocks(transaction, indirect, start, end, 0); 552 } 553 554 555 status_t 556 DataStream::_AddForDoubleIndirectBlock(Transaction& transaction, 557 uint32 numBlocks) 558 { 559 TRACE("DataStream::_AddForDoubleIndirectBlock(): current size: %" B_PRIdOFF 560 ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks); 561 uint32 *doubleIndirect = &fStream->double_indirect; 562 uint32 start = fNumBlocks - kMaxIndirect; 563 uint32 end = numBlocks - kMaxIndirect; 564 565 if (end > kIndirectsPerBlock2) 566 end = kIndirectsPerBlock2; 567 568 return _AddBlocks(transaction, doubleIndirect, start, end, 1); 569 } 570 571 572 status_t 573 DataStream::_AddForTripleIndirectBlock(Transaction& transaction, 574 uint32 numBlocks) 575 { 576 TRACE("DataStream::_AddForTripleIndirectBlock(): current size: %" B_PRIdOFF 577 ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks); 578 uint32 *tripleIndirect = &fStream->triple_indirect; 579 uint32 start = fNumBlocks - kMaxDoubleIndirect; 580 uint32 end = numBlocks - kMaxDoubleIndirect; 581 582 return _AddBlocks(transaction, tripleIndirect, start, end, 2); 583 } 584 585 586 status_t 587 DataStream::_PerformFree(Transaction& transaction) 588 { 589 TRACE("DataStream::_PerformFree(): start: %" B_PRIu32 ", count: %" B_PRIu32 590 "\n", fFreeStart, fFreeCount); 591 status_t status; 592 593 if (fFreeCount == 0) 594 status = B_OK; 595 else 596 status = fVolume->FreeBlocks(transaction, fFreeStart, fFreeCount); 597 598 fFreeStart = 0; 599 fFreeCount = 0; 600 601 return status; 602 } 603 604 605 status_t 606 DataStream::_MarkBlockForRemoval(Transaction& transaction, uint32* block) 607 { 608 609 TRACE("DataStream::_MarkBlockForRemoval(*(%p) = %" B_PRIu32 610 "): free start: %" B_PRIu32 ", free count: %" B_PRIu32 "\n", block, 611 B_LENDIAN_TO_HOST_INT32(*block), fFreeStart, fFreeCount); 612 uint32 blockNum = B_LENDIAN_TO_HOST_INT32(*block); 613 *block = 0; 614 615 if (blockNum != fFreeStart + fFreeCount) { 616 if (fFreeCount != 0) { 617 status_t status = fVolume->FreeBlocks(transaction, fFreeStart, 618 fFreeCount); 619 if (status != B_OK) 620 return status; 621 } 622 623 fFreeStart = blockNum; 624 fFreeCount = 0; 625 } 626 627 fFreeCount++; 628 629 return B_OK; 630 } 631 632 633 status_t 634 DataStream::_FreeBlocks(Transaction& transaction, uint32* block, uint32 _count) 635 { 636 uint32 count = _count; 637 TRACE("DataStream::_FreeBlocks(%p, %" B_PRIu32 ")\n", block, count); 638 639 while (count > 0) { 640 status_t status = _MarkBlockForRemoval(transaction, block); 641 if (status != B_OK) 642 return status; 643 644 block++; 645 count--; 646 } 647 648 fRemovedBlocks += _count; 649 650 return B_OK; 651 } 652 653 654 status_t 655 DataStream::_FreeBlocks(Transaction& transaction, uint32* block, off_t start, 656 off_t end, bool freeParent, int recursion) 657 { 658 // TODO: Designed specifically for shrinking. Perhaps make it more general? 659 TRACE("DataStream::_FreeBlocks(%p, %" B_PRIdOFF ", %" B_PRIdOFF 660 ", %c, %d)\n", block, start, end, freeParent ? 't' : 'f', recursion); 661 662 uint32 blockNum = B_LENDIAN_TO_HOST_INT32(*block); 663 664 if (freeParent) { 665 status_t status = _MarkBlockForRemoval(transaction, block); 666 if (status != B_OK) 667 return status; 668 } 669 670 CachedBlock cached(fVolume); 671 uint32* childBlock = (uint32*)cached.SetToWritable(transaction, blockNum); 672 if (childBlock == NULL) 673 return B_IO_ERROR; 674 675 if (recursion == 0) 676 return _FreeBlocks(transaction, &childBlock[start], end - start); 677 678 uint32 elementWidth; 679 if (recursion == 1) 680 elementWidth = kIndirectsPerBlock; 681 else if (recursion == 2) 682 elementWidth = kIndirectsPerBlock2; 683 else { 684 panic("Undefinied recursion level\n"); 685 elementWidth = 0; 686 } 687 688 uint32 elementPos = start / elementWidth; 689 uint32 endPos = end / elementWidth; 690 691 recursion--; 692 693 if (elementPos == endPos) { 694 bool free = freeParent || start % elementWidth == 0; 695 return _FreeBlocks(transaction, &childBlock[elementPos], 696 start % elementWidth, end % elementWidth, free, recursion); 697 } 698 699 status_t status = B_OK; 700 701 if (start % elementWidth != 0) { 702 status = _FreeBlocks(transaction, &childBlock[elementPos], 703 start % elementWidth, elementWidth, false, recursion); 704 if (status != B_OK) 705 return status; 706 707 elementPos++; 708 } 709 710 while (elementPos < endPos) { 711 status = _FreeBlocks(transaction, &childBlock[elementPos], 0, 712 elementWidth, true, recursion); 713 if (status != B_OK) 714 return status; 715 716 elementPos++; 717 } 718 719 if (end % elementWidth != 0) { 720 status = _FreeBlocks(transaction, &childBlock[elementPos], 0, 721 end % elementWidth, true, recursion); 722 } 723 724 return status; 725 } 726 727 728 status_t 729 DataStream::_RemoveFromDirectBlocks(Transaction& transaction, uint32 numBlocks) 730 { 731 TRACE("DataStream::_RemoveFromDirectBlocks(): current size: %" B_PRIdOFF 732 ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks); 733 uint32* direct = &fStream->direct[numBlocks]; 734 off_t end = fNumBlocks > kMaxDirect ? kMaxDirect : fNumBlocks; 735 736 return _FreeBlocks(transaction, direct, end - numBlocks); 737 } 738 739 740 status_t 741 DataStream::_RemoveFromIndirectBlock(Transaction& transaction, uint32 numBlocks) 742 { 743 TRACE("DataStream::_RemoveFromIndirectBlock(): current size: %" B_PRIdOFF 744 ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks); 745 uint32* indirect = &fStream->indirect; 746 off_t start = numBlocks <= kMaxDirect ? 0 : numBlocks - kMaxDirect; 747 off_t end = fNumBlocks - kMaxDirect; 748 749 if (end > kIndirectsPerBlock) 750 end = kIndirectsPerBlock; 751 752 bool freeAll = start == 0; 753 754 return _FreeBlocks(transaction, indirect, start, end, freeAll, 0); 755 } 756 757 758 status_t 759 DataStream::_RemoveFromDoubleIndirectBlock(Transaction& transaction, 760 uint32 numBlocks) 761 { 762 TRACE("DataStream::_RemoveFromDoubleIndirectBlock(): current size: %" B_PRIdOFF 763 ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks); 764 uint32* doubleIndirect = &fStream->double_indirect; 765 off_t start = numBlocks <= kMaxIndirect ? 0 : numBlocks - kMaxIndirect; 766 off_t end = fNumBlocks - kMaxIndirect; 767 768 if (end > kIndirectsPerBlock2) 769 end = kIndirectsPerBlock2; 770 771 bool freeAll = start == 0; 772 773 return _FreeBlocks(transaction, doubleIndirect, start, end, freeAll, 1); 774 } 775 776 777 status_t 778 DataStream::_RemoveFromTripleIndirectBlock(Transaction& transaction, 779 uint32 numBlocks) 780 { 781 TRACE("DataStream::_RemoveFromTripleIndirectBlock(): current size: %" B_PRIdOFF 782 ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks); 783 uint32* tripleIndirect = &fStream->triple_indirect; 784 off_t start = numBlocks <= kMaxDoubleIndirect ? 0 785 : numBlocks - kMaxDoubleIndirect; 786 off_t end = fNumBlocks - kMaxDoubleIndirect; 787 788 bool freeAll = start == 0; 789 790 return _FreeBlocks(transaction, tripleIndirect, start, end, freeAll, 2); 791 } 792