diff --git a/src/add-ons/disk_systems/bfs/BFSAddOn.cpp b/src/add-ons/disk_systems/bfs/BFSAddOn.cpp index 6dab456c8c..32765fc82e 100644 --- a/src/add-ons/disk_systems/bfs/BFSAddOn.cpp +++ b/src/add-ons/disk_systems/bfs/BFSAddOn.cpp @@ -247,6 +247,7 @@ BFSPartitionHandle::Repair(bool checkOnly) uint64 attributeDirectories = 0, attributes = 0; uint64 files = 0, directories = 0, indices = 0; uint64 counter = 0; + uint32 previousPass = result.pass; // check all files and report errors while (ioctl(fd, BFS_IOCTL_CHECK_NEXT_NODE, &result, @@ -254,34 +255,42 @@ BFSPartitionHandle::Repair(bool checkOnly) if (++counter % 50 == 0) printf("%9Ld nodes processed\x1b[1A\n", counter); - if (result.errors) { - printf("%s (inode = %lld)", result.name, result.inode); - if ((result.errors & BFS_MISSING_BLOCKS) != 0) - printf(", some blocks weren't allocated"); - if ((result.errors & BFS_BLOCKS_ALREADY_SET) != 0) - printf(", has blocks already set"); - if ((result.errors & BFS_INVALID_BLOCK_RUN) != 0) - printf(", has invalid block run(s)"); - if ((result.errors & BFS_COULD_NOT_OPEN) != 0) - printf(", could not be opened"); - if ((result.errors & BFS_WRONG_TYPE) != 0) - printf(", has wrong type"); - if ((result.errors & BFS_NAMES_DONT_MATCH) != 0) - printf(", names don't match"); - if ((result.errors & BFS_INVALID_BPLUSTREE) != 0) - printf(", invalid b+tree"); - putchar('\n'); + if (result.pass == BFS_CHECK_PASS_BITMAP) { + if (result.errors) { + printf("%s (inode = %lld)", result.name, result.inode); + if ((result.errors & BFS_MISSING_BLOCKS) != 0) + printf(", some blocks weren't allocated"); + if ((result.errors & BFS_BLOCKS_ALREADY_SET) != 0) + printf(", has blocks already set"); + if ((result.errors & BFS_INVALID_BLOCK_RUN) != 0) + printf(", has invalid block run(s)"); + if ((result.errors & BFS_COULD_NOT_OPEN) != 0) + printf(", could not be opened"); + if ((result.errors & BFS_WRONG_TYPE) != 0) + printf(", has wrong type"); + if ((result.errors & BFS_NAMES_DONT_MATCH) != 0) + printf(", names don't match"); + if ((result.errors & BFS_INVALID_BPLUSTREE) != 0) + printf(", invalid b+tree"); + putchar('\n'); + } + + if ((result.mode & (S_INDEX_DIR | 0777)) == S_INDEX_DIR) + indices++; + else if (result.mode & S_ATTR_DIR) + attributeDirectories++; + else if (result.mode & S_ATTR) + attributes++; + else if (S_ISDIR(result.mode)) + directories++; + else + files++; + } else if (result.pass == BFS_CHECK_PASS_INDEX) { + if (previousPass != result.pass) { + printf("Recreating broken index b+trees...\n"); + previousPass = result.pass; + } } - if ((result.mode & (S_INDEX_DIR | 0777)) == S_INDEX_DIR) - indices++; - else if (result.mode & S_ATTR_DIR) - attributeDirectories++; - else if (result.mode & S_ATTR) - attributes++; - else if (S_ISDIR(result.mode)) - directories++; - else - files++; } // stop checking diff --git a/src/add-ons/kernel/file_systems/bfs/BPlusTree.cpp b/src/add-ons/kernel/file_systems/bfs/BPlusTree.cpp index 92dd8da3b5..ded3b14d47 100644 --- a/src/add-ons/kernel/file_systems/bfs/BPlusTree.cpp +++ b/src/add-ons/kernel/file_systems/bfs/BPlusTree.cpp @@ -752,6 +752,57 @@ BPlusTree::Validate(bool repair, bool& _errorsFound) } +status_t +BPlusTree::MakeEmpty() +{ + // Put all nodes into the free list in order + Transaction transaction(fStream->GetVolume(), fStream->BlockNumber()); + + // Reset the header, and root node + CachedNode cached(this); + bplustree_header* header = cached.SetToWritableHeader(transaction); + if (header == NULL) + return B_IO_ERROR; + + header->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1); + header->root_node_pointer = HOST_ENDIAN_TO_BFS_INT64(NodeSize()); + if (fStream->Size() > NodeSize() * 2) + header->free_node_pointer = HOST_ENDIAN_TO_BFS_INT64(2 * NodeSize()); + else { + header->free_node_pointer + = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL); + } + + bplustree_node* node = cached.SetToWritable(transaction, NodeSize()); + node->left_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL); + node->right_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL); + node->overflow_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL); + node->all_key_count = 0; + node->all_key_length = 0; + + for (off_t offset = 2 * NodeSize(); offset < fStream->Size(); + offset += NodeSize()) { + bplustree_node* node = cached.SetToWritable(transaction, offset, false); + if (node == NULL) { + dprintf("--> could not open %lld\n", offset); + return B_IO_ERROR; + } + if (offset < fStream->Size() - NodeSize()) + node->left_link = HOST_ENDIAN_TO_BFS_INT64(offset + NodeSize()); + else + node->left_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL); + + node->overflow_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_FREE); + + // It's not important to write it out in a single transaction + if (transaction.IsTooLarge()) + transaction.Split(); + } + + return transaction.Done(); +} + + int32 BPlusTree::TypeCodeToKeyType(type_code code) { diff --git a/src/add-ons/kernel/file_systems/bfs/BPlusTree.h b/src/add-ons/kernel/file_systems/bfs/BPlusTree.h index 1300558571..4150d684dd 100644 --- a/src/add-ons/kernel/file_systems/bfs/BPlusTree.h +++ b/src/add-ons/kernel/file_systems/bfs/BPlusTree.h @@ -217,6 +217,7 @@ public: Inode* Stream() const { return fStream; } status_t Validate(bool repair, bool& _errorsFound); + status_t MakeEmpty(); status_t Remove(Transaction& transaction, const uint8* key, uint16 keyLength, diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp index 2769f6f4e8..3b7184b413 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp @@ -166,15 +166,32 @@ private: #endif -struct check_cookie { - check_cookie() {} +struct check_index { + check_index() + : + inode(NULL) + { + } + char name[B_FILE_NAME_LENGTH]; + block_run run; + Inode* inode; +}; + + +struct check_cookie { + check_cookie() + { + } + + uint32 pass; block_run current; Inode* parent; mode_t parent_mode; Stack stack; TreeIterator* iterator; check_control control; + Stack indices; }; @@ -1230,6 +1247,7 @@ BlockAllocator::StartChecking(const check_control* control) _SetCheckBitmapAt(block); } + fCheckCookie->pass = BFS_CHECK_PASS_BITMAP; fCheckCookie->stack.Push(fVolume->Root()); fCheckCookie->stack.Push(fVolume->Indices()); fCheckCookie->iterator = NULL; @@ -1264,81 +1282,25 @@ BlockAllocator::StopChecking(check_control* control) if (fVolume->IsReadOnly()) { // We can't fix errors on this volume - fCheckCookie->control.flags &= ~BFS_FIX_BITMAP_ERRORS; + fCheckCookie->control.flags = 0; } - // if CheckNextNode() could completely work through, we can - // fix any damages of the bitmap - if (fCheckCookie->control.status == B_ENTRY_NOT_FOUND) { - // calculate the number of used blocks in the check bitmap - size_t size = BitmapSize(); - off_t usedBlocks = 0LL; - - // TODO: update the allocation groups used blocks info - for (uint32 i = size >> 2; i-- > 0;) { - uint32 compare = 1; - // Count the number of bits set - for (int16 j = 0; j < 32; j++, compare <<= 1) { - if ((compare & fCheckBitmap[i]) != 0) - usedBlocks++; - } - } - - fCheckCookie->control.stats.freed = fVolume->UsedBlocks() - usedBlocks - + fCheckCookie->control.stats.missing; - if (fCheckCookie->control.stats.freed < 0) - fCheckCookie->control.stats.freed = 0; - - // Should we fix errors? Were there any errors we can fix? - if ((fCheckCookie->control.flags & BFS_FIX_BITMAP_ERRORS) != 0 - && (fCheckCookie->control.stats.freed != 0 - || fCheckCookie->control.stats.missing != 0)) { - // If so, write the check bitmap back over the original one, - // and use transactions here to play safe - we even use several - // transactions, so that we don't blow the maximum log size - // on large disks, since we don't need to make this atomic. -#if 0 - // prints the blocks that differ - off_t block = 0; - for (int32 i = 0; i < fNumGroups; i++) { - AllocationBlock cached(fVolume); - for (uint32 j = 0; j < fGroups[i].NumBlocks(); j++) { - cached.SetTo(fGroups[i], j); - for (uint32 k = 0; k < cached.NumBlockBits(); k++) { - if (cached.IsUsed(k) != _CheckBitmapIsUsedAt(block)) { - dprintf("differ block %lld (should be %d)\n", block, - _CheckBitmapIsUsedAt(block)); - } - block++; - } - } - } -#endif - - fVolume->SuperBlock().used_blocks - = HOST_ENDIAN_TO_BFS_INT64(usedBlocks); - - size_t blockSize = fVolume->BlockSize(); - - for (uint32 i = 0; i < fNumBlocks; i += 512) { - Transaction transaction(fVolume, 1 + i); - - uint32 blocksToWrite = 512; - if (blocksToWrite + i > fNumBlocks) - blocksToWrite = fNumBlocks - i; - - status_t status = transaction.WriteBlocks(1 + i, - (uint8*)fCheckBitmap + i * blockSize, blocksToWrite); - if (status < B_OK) { - FATAL(("error writing bitmap: %s\n", strerror(status))); - break; - } - transaction.Done(); - } - } - } else + if (fCheckCookie->control.status != B_ENTRY_NOT_FOUND) FATAL(("BlockAllocator::CheckNextNode() didn't run through\n")); + switch (fCheckCookie->pass) { + case BFS_CHECK_PASS_BITMAP: + // if CheckNextNode() could completely work through, we can + // fix any damages of the bitmap + if (fCheckCookie->control.status == B_ENTRY_NOT_FOUND) + _WriteBackCheckBitmap(); + break; + + case BFS_CHECK_PASS_INDEX: + _FreeIndices(); + break; + } + fVolume->SetCheckingThread(-1); if (control != NULL) @@ -1387,7 +1349,19 @@ BlockAllocator::CheckNextNode(check_control* control) while (true) { if (fCheckCookie->iterator == NULL) { if (!fCheckCookie->stack.Pop(&fCheckCookie->current)) { - // no more runs on the stack, we are obviously finished! + // No more runs on the stack, we might be finished! + if (fCheckCookie->pass == BFS_CHECK_PASS_BITMAP + && !fCheckCookie->indices.IsEmpty()) { + // Start second pass to repair indices + _WriteBackCheckBitmap(); + + fCheckCookie->pass = BFS_CHECK_PASS_INDEX; + fCheckCookie->control.pass = BFS_CHECK_PASS_INDEX; + fCheckCookie->stack.Push(fVolume->Root()); + _PrepareIndices(); + continue; + } + fCheckCookie->control.status = B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND; } @@ -1406,7 +1380,7 @@ BlockAllocator::CheckNextNode(check_control* control) if (!inode->IsContainer()) { // Check file fCheckCookie->control.errors = 0; - fCheckCookie->control.status = CheckInode(inode); + fCheckCookie->control.status = CheckInode(inode, NULL); if (inode->GetName(fCheckCookie->control.name) < B_OK) strcpy(fCheckCookie->control.name, "(node has no name)"); @@ -1435,9 +1409,9 @@ BlockAllocator::CheckNextNode(check_control* control) // check the inode of the directory fCheckCookie->control.errors = 0; - fCheckCookie->control.status = CheckInode(inode); + fCheckCookie->control.status = CheckInode(inode, NULL); - if (inode->GetName(fCheckCookie->control.name) < B_OK) + if (inode->GetName(fCheckCookie->control.name) != B_OK) strcpy(fCheckCookie->control.name, "(dir has no name)"); return B_OK; @@ -1497,7 +1471,8 @@ BlockAllocator::CheckNextNode(check_control* control) } // check if the inode's name is the same as in the b+tree - if (inode->IsRegularNode()) { + if (fCheckCookie->pass == BFS_CHECK_PASS_BITMAP + && inode->IsRegularNode()) { RecursiveLocker locker(inode->SmallDataLock()); NodeGetter node(fVolume, inode); @@ -1531,12 +1506,13 @@ BlockAllocator::CheckNextNode(check_control* control) // Check for the correct mode of the node (if the mode of the // file don't fit to its parent, there is a serious problem) - if (((fCheckCookie->parent_mode & S_ATTR_DIR) != 0 - && !inode->IsAttribute()) - || ((fCheckCookie->parent_mode & S_INDEX_DIR) != 0 - && !inode->IsIndex()) - || (is_directory(fCheckCookie->parent_mode) - && !inode->IsRegularNode())) { + if (fCheckCookie->pass == BFS_CHECK_PASS_BITMAP + && (((fCheckCookie->parent_mode & S_ATTR_DIR) != 0 + && !inode->IsAttribute()) + || ((fCheckCookie->parent_mode & S_INDEX_DIR) != 0 + && !inode->IsIndex()) + || (is_directory(fCheckCookie->parent_mode) + && !inode->IsRegularNode()))) { FATAL(("inode at %" B_PRIdOFF " is of wrong type: %o (parent " "%o at %" B_PRIdOFF ")!\n", inode->BlockNumber(), inode->Mode(), fCheckCookie->parent_mode, @@ -1561,7 +1537,7 @@ BlockAllocator::CheckNextNode(check_control* control) fCheckCookie->stack.Push(inode->BlockRun()); else { // check it now - fCheckCookie->control.status = CheckInode(inode); + fCheckCookie->control.status = CheckInode(inode, name); return B_OK; } } @@ -1628,6 +1604,83 @@ BlockAllocator::_SetCheckBitmapAt(off_t block) } +status_t +BlockAllocator::_WriteBackCheckBitmap() +{ + if (fVolume->IsReadOnly()) + return B_OK; + + // calculate the number of used blocks in the check bitmap + size_t size = BitmapSize(); + off_t usedBlocks = 0LL; + + // TODO: update the allocation groups used blocks info + for (uint32 i = size >> 2; i-- > 0;) { + uint32 compare = 1; + // Count the number of bits set + for (int16 j = 0; j < 32; j++, compare <<= 1) { + if ((compare & fCheckBitmap[i]) != 0) + usedBlocks++; + } + } + + fCheckCookie->control.stats.freed = fVolume->UsedBlocks() - usedBlocks + + fCheckCookie->control.stats.missing; + if (fCheckCookie->control.stats.freed < 0) + fCheckCookie->control.stats.freed = 0; + + // Should we fix errors? Were there any errors we can fix? + if ((fCheckCookie->control.flags & BFS_FIX_BITMAP_ERRORS) != 0 + && (fCheckCookie->control.stats.freed != 0 + || fCheckCookie->control.stats.missing != 0)) { + // If so, write the check bitmap back over the original one, + // and use transactions here to play safe - we even use several + // transactions, so that we don't blow the maximum log size + // on large disks, since we don't need to make this atomic. +#if 0 + // prints the blocks that differ + off_t block = 0; + for (int32 i = 0; i < fNumGroups; i++) { + AllocationBlock cached(fVolume); + for (uint32 j = 0; j < fGroups[i].NumBlocks(); j++) { + cached.SetTo(fGroups[i], j); + for (uint32 k = 0; k < cached.NumBlockBits(); k++) { + if (cached.IsUsed(k) != _CheckBitmapIsUsedAt(block)) { + dprintf("differ block %lld (should be %d)\n", block, + _CheckBitmapIsUsedAt(block)); + } + block++; + } + } + } +#endif + + fVolume->SuperBlock().used_blocks + = HOST_ENDIAN_TO_BFS_INT64(usedBlocks); + + size_t blockSize = fVolume->BlockSize(); + + for (uint32 i = 0; i < fNumBlocks; i += 512) { + Transaction transaction(fVolume, 1 + i); + + uint32 blocksToWrite = 512; + if (blocksToWrite + i > fNumBlocks) + blocksToWrite = fNumBlocks - i; + + status_t status = transaction.WriteBlocks(1 + i, + (uint8*)fCheckBitmap + i * blockSize, blocksToWrite); + if (status < B_OK) { + FATAL(("error writing bitmap: %s\n", strerror(status))); + return status; + } + transaction.Done(); + } + } + + return B_OK; +} + + /*! Checks whether or not the specified block range is allocated or not, depending on the \a allocated argument. */ @@ -1775,13 +1828,55 @@ BlockAllocator::CheckBlockRun(block_run run, const char* type, bool allocated) status_t -BlockAllocator::CheckInode(Inode* inode) +BlockAllocator::CheckInode(Inode* inode, const char* name) { if (fCheckCookie != NULL && fCheckBitmap == NULL) return B_NO_INIT; if (inode == NULL) return B_BAD_VALUE; + switch (fCheckCookie->pass) { + case BFS_CHECK_PASS_BITMAP: + { + status_t status = _CheckInodeBlocks(inode, name); + if (status != B_OK) + return status; + + // Check the B+tree as well + if (inode->IsContainer()) { + bool repairErrors + = (fCheckCookie->control.flags & BFS_FIX_BPLUSTREES) != 0; + bool errorsFound = false; + status = inode->Tree()->Validate(repairErrors, errorsFound); + if (errorsFound) { + fCheckCookie->control.errors |= BFS_INVALID_BPLUSTREE; + if (inode->IsIndex() && name != NULL && repairErrors) { + // We completely rebuild corrupt indices + check_index* index = new(std::nothrow) check_index; + if (index == NULL) + return B_NO_MEMORY; + + strlcpy(index->name, name, sizeof(index->name)); + index->run = inode->BlockRun(); + fCheckCookie->indices.Push(index); + } + } + } + + return status; + } + + case BFS_CHECK_PASS_INDEX: + return _AddInodeToIndex(inode); + } + + return B_OK; +} + + +status_t +BlockAllocator::_CheckInodeBlocks(Inode* inode, const char* name) +{ status_t status = CheckBlockRun(inode->BlockRun(), "inode"); if (status != B_OK) return status; @@ -1913,19 +2008,100 @@ BlockAllocator::CheckInode(Inode* inode) } } - if (inode->IsContainer()) { - bool errorsFound = false; - status_t status = inode->Tree()->Validate( - (fCheckCookie->control.flags & BFS_FIX_BPLUSTREES) != 0, - errorsFound); - if (errorsFound) - fCheckCookie->control.errors |= BFS_INVALID_BPLUSTREE; + return B_OK; +} + + +status_t +BlockAllocator::_PrepareIndices() +{ + for (int32 i = 0; i < fCheckCookie->indices.CountItems(); i++) { + check_index* index = fCheckCookie->indices.Array()[i]; + Vnode vnode(fVolume, index->run); + Inode* inode; + status_t status = vnode.Get(&inode); + if (status != B_OK) { + FATAL(("check: Could not open index at %" B_PRIdOFF "\n", + fVolume->ToBlock(index->run))); + return status; + } + + BPlusTree* tree = inode->Tree(); + if (tree == NULL) { + // TODO: We can't yet repair those + continue; + } + + status = tree->MakeEmpty(); + if (status != B_OK) + return status; + + index->inode = inode; + vnode.Keep(); + } + + return B_OK; +} + + +void +BlockAllocator::_FreeIndices() +{ + for (int32 i = 0; i < fCheckCookie->indices.CountItems(); i++) { + check_index* index = fCheckCookie->indices.Array()[i]; + put_vnode(fVolume->FSVolume(), + fVolume->ToVnode(index->inode->BlockRun())); + } + fCheckCookie->indices.MakeEmpty(); +} + + +status_t +BlockAllocator::_AddInodeToIndex(Inode* inode) +{ + Transaction transaction(fVolume, inode->BlockNumber()); + + for (int32 i = 0; i < fCheckCookie->indices.CountItems(); i++) { + check_index* index = fCheckCookie->indices.Array()[i]; + if (index->inode == NULL) + continue; + + BPlusTree* tree = index->inode->Tree(); + if (tree == NULL) + return B_ERROR; + + status_t status = B_OK; + + if (!strcmp(index->name, "name")) { + if (inode->InNameIndex()) { + char name[B_FILE_NAME_LENGTH]; + if (inode->GetName(name, B_FILE_NAME_LENGTH) != B_OK) + return B_ERROR; + + status = tree->Insert(transaction, name, inode->ID()); + } + } else if (!strcmp(index->name, "last_modified")) { + if (inode->InLastModifiedIndex()) { + status = tree->Insert(transaction, inode->OldLastModified(), + inode->ID()); + } + } else if (!strcmp(index->name, "size")) { + if (inode->InSizeIndex()) + status = tree->Insert(transaction, inode->Size(), inode->ID()); + } else { + uint8 key[BPLUSTREE_MAX_KEY_LENGTH]; + size_t keyLength = BPLUSTREE_MAX_KEY_LENGTH; + if (inode->ReadAttribute(index->name, B_ANY_TYPE, 0, key, + &keyLength) == B_OK) { + status = tree->Insert(transaction, key, keyLength, inode->ID()); + } + } if (status != B_OK) return status; } - return B_OK; + return transaction.Done(); } diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h index 5e6bf2be50..ba490ba010 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h @@ -55,7 +55,7 @@ public: status_t CheckBlockRun(block_run run, const char* type = NULL, bool allocated = true); - status_t CheckInode(Inode* inode); + status_t CheckInode(Inode* inode, const char* name); size_t BitmapSize() const; @@ -75,6 +75,12 @@ private: bool _IsValidCheckControl(const check_control* control); bool _CheckBitmapIsUsedAt(off_t block) const; void _SetCheckBitmapAt(off_t block); + status_t _CheckInodeBlocks(Inode* inode, const char* name); + status_t _FinishBitmapPass(); + status_t _PrepareIndices(); + void _FreeIndices(); + status_t _AddInodeToIndex(Inode* inode); + status_t _WriteBackCheckBitmap(); static status_t _Initialize(BlockAllocator* self); diff --git a/src/add-ons/kernel/file_systems/bfs/bfs_control.h b/src/add-ons/kernel/file_systems/bfs/bfs_control.h index 2054456a01..aa3608a163 100644 --- a/src/add-ons/kernel/file_systems/bfs/bfs_control.h +++ b/src/add-ons/kernel/file_systems/bfs/bfs_control.h @@ -36,11 +36,16 @@ struct update_boot_block { #define BFS_IOCTL_STOP_CHECKING 14202 #define BFS_IOCTL_CHECK_NEXT_NODE 14203 +/* The "pass" field constants */ +#define BFS_CHECK_PASS_BITMAP 0 +#define BFS_CHECK_PASS_INDEX 1 + /* All fields except "flags", and "name" must be set to zero before * BFS_IOCTL_START_CHECKING is called, and magic must be set. */ struct check_control { uint32 magic; + uint32 pass; uint32 flags; char name[B_FILE_NAME_LENGTH]; ino_t inode; diff --git a/src/tools/bfs_shell/command_checkfs.cpp b/src/tools/bfs_shell/command_checkfs.cpp index a987f42c0e..3517e09462 100644 --- a/src/tools/bfs_shell/command_checkfs.cpp +++ b/src/tools/bfs_shell/command_checkfs.cpp @@ -49,6 +49,7 @@ command_checkfs(int argc, const char* const* argv) uint64 attributeDirectories = 0, attributes = 0; uint64 files = 0, directories = 0, indices = 0; uint64 counter = 0; + uint32 previousPass = result.pass; // check all files and report errors while (_kern_ioctl(rootDir, BFS_IOCTL_CHECK_NEXT_NODE, &result, @@ -56,34 +57,42 @@ command_checkfs(int argc, const char* const* argv) if (++counter % 50 == 0) fssh_dprintf("%9Ld nodes processed\x1b[1A\n", counter); - if (result.errors) { - fssh_dprintf("%s (inode = %lld)", result.name, result.inode); - if ((result.errors & BFS_MISSING_BLOCKS) != 0) - fssh_dprintf(", some blocks weren't allocated"); - if ((result.errors & BFS_BLOCKS_ALREADY_SET) != 0) - fssh_dprintf(", has blocks already set"); - if ((result.errors & BFS_INVALID_BLOCK_RUN) != 0) - fssh_dprintf(", has invalid block run(s)"); - if ((result.errors & BFS_COULD_NOT_OPEN) != 0) - fssh_dprintf(", could not be opened"); - if ((result.errors & BFS_WRONG_TYPE) != 0) - fssh_dprintf(", has wrong type"); - if ((result.errors & BFS_NAMES_DONT_MATCH) != 0) - fssh_dprintf(", names don't match"); - if ((result.errors & BFS_INVALID_BPLUSTREE) != 0) - fssh_dprintf(", invalid b+tree"); - fssh_dprintf("\n"); + if (result.pass == BFS_CHECK_PASS_BITMAP) { + if (result.errors) { + fssh_dprintf("%s (inode = %lld)", result.name, result.inode); + if ((result.errors & BFS_MISSING_BLOCKS) != 0) + fssh_dprintf(", some blocks weren't allocated"); + if ((result.errors & BFS_BLOCKS_ALREADY_SET) != 0) + fssh_dprintf(", has blocks already set"); + if ((result.errors & BFS_INVALID_BLOCK_RUN) != 0) + fssh_dprintf(", has invalid block run(s)"); + if ((result.errors & BFS_COULD_NOT_OPEN) != 0) + fssh_dprintf(", could not be opened"); + if ((result.errors & BFS_WRONG_TYPE) != 0) + fssh_dprintf(", has wrong type"); + if ((result.errors & BFS_NAMES_DONT_MATCH) != 0) + fssh_dprintf(", names don't match"); + if ((result.errors & BFS_INVALID_BPLUSTREE) != 0) + fssh_dprintf(", invalid b+tree"); + fssh_dprintf("\n"); + } + + if ((result.mode & (S_INDEX_DIR | 0777)) == S_INDEX_DIR) + indices++; + else if (result.mode & S_ATTR_DIR) + attributeDirectories++; + else if (result.mode & S_ATTR) + attributes++; + else if (S_ISDIR(result.mode)) + directories++; + else + files++; + } else if (result.pass == BFS_CHECK_PASS_INDEX) { + if (previousPass != result.pass) { + fssh_dprintf("Recreating broken index b+trees...\n"); + previousPass = result.pass; + } } - if ((result.mode & (S_INDEX_DIR | 0777)) == S_INDEX_DIR) - indices++; - else if (result.mode & S_ATTR_DIR) - attributeDirectories++; - else if (result.mode & S_ATTR) - attributes++; - else if (S_ISDIR(result.mode)) - directories++; - else - files++; } // stop checking