Author: axeld Date: 2010-03-06 14:47:50 +0100 (Sat, 06 Mar 2010) New Revision: 35770 Changeset: http://dev.haiku-os.org/changeset/35770/haiku Ticket: http://dev.haiku-os.org/ticket/5536 Modified: haiku/trunk/src/add-ons/disk_systems/bfs/BFSAddOn.cpp haiku/trunk/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp haiku/trunk/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h haiku/trunk/src/add-ons/kernel/file_systems/bfs/bfs_control.h Log: * checkfs is now working again; I couldn't test my earlier changes because I had no time left, but I didn't want to lose them either. * This fixes bug #5536, sorry for the inconvenience. Modified: haiku/trunk/src/add-ons/disk_systems/bfs/BFSAddOn.cpp =================================================================== --- haiku/trunk/src/add-ons/disk_systems/bfs/BFSAddOn.cpp 2010-03-06 04:45:43 UTC (rev 35769) +++ haiku/trunk/src/add-ons/disk_systems/bfs/BFSAddOn.cpp 2010-03-06 13:47:50 UTC (rev 35770) @@ -267,7 +267,10 @@ } // stop checking - ioctl(fd, BFS_IOCTL_STOP_CHECKING, &result, sizeof(result)); + if (ioctl(fd, BFS_IOCTL_STOP_CHECKING, &result, sizeof(result)) != 0) { + close(fd); + return errno; + } close(fd); Modified: haiku/trunk/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp 2010-03-06 04:45:43 UTC (rev 35769) +++ haiku/trunk/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp 2010-03-06 13:47:50 UTC (rev 35770) @@ -1,10 +1,10 @@ /* - * Copyright 2001-2009, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx + * Copyright 2001-2010, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx * This file may be used under the terms of the MIT License. */ -//! block bitmap handling and allocation policies +//! Block bitmap handling and allocation policies #include "BlockAllocator.h" @@ -174,6 +174,7 @@ mode_t parent_mode; Stack<block_run> stack; TreeIterator* iterator; + check_control control; }; @@ -1222,6 +1223,8 @@ return B_NO_MEMORY; } + memcpy(&fCheckCookie->control, control, sizeof(check_control)); + // initialize bitmap memset(fCheckBitmap, 0, size); for (int32 block = fVolume->Log().Start() + fVolume->Log().Length(); @@ -1250,7 +1253,7 @@ BlockAllocator::StopChecking(check_control* control) { if (fCheckCookie == NULL) - return B_ERROR; + return B_NO_INIT; if (fCheckCookie->iterator != NULL) { delete fCheckCookie->iterator; @@ -1262,12 +1265,12 @@ if (fVolume->IsReadOnly()) { // We can't fix errors on this volume - control->flags &= ~BFS_FIX_BITMAP_ERRORS; + fCheckCookie->control.flags &= ~BFS_FIX_BITMAP_ERRORS; } // if CheckNextNode() could completely work through, we can // fix any damages of the bitmap - if (control != NULL && control->status == B_ENTRY_NOT_FOUND) { + 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; @@ -1282,14 +1285,15 @@ } } - control->stats.freed = fVolume->UsedBlocks() - usedBlocks - + control->stats.missing; - if (control->stats.freed < 0) - control->stats.freed = 0; + 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 ((control->flags & BFS_FIX_BITMAP_ERRORS) != 0 - && (control->stats.freed != 0 || control->stats.missing != 0)) { + 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 @@ -1339,6 +1343,9 @@ fVolume->SetCheckingThread(-1); + if (control != NULL) + user_memcpy(control, &fCheckCookie->control, sizeof(check_control)); + free(fCheckBitmap); fCheckBitmap = NULL; delete fCheckCookie; @@ -1353,16 +1360,37 @@ status_t BlockAllocator::CheckNextNode(check_control* control) { - if (!_IsValidCheckControl(control)) - return B_BAD_VALUE; + if (fCheckCookie == NULL) + return B_NO_INIT; fVolume->SetCheckingThread(find_thread(NULL)); + // Make sure the user control is copied on exit + class CopyControlOnExit { + public: + CopyControlOnExit(check_control* source, check_control* userTarget) + : + fSource(source), + fTarget(userTarget) + { + } + + ~CopyControlOnExit() + { + if (fTarget != NULL) + user_memcpy(fTarget, fSource, sizeof(check_control)); + } + + private: + check_control* fSource; + check_control* fTarget; + } copyControl(&fCheckCookie->control, control); + while (true) { if (fCheckCookie->iterator == NULL) { if (!fCheckCookie->stack.Pop(&fCheckCookie->current)) { // no more runs on the stack, we are obviously finished! - control->status = B_ENTRY_NOT_FOUND; + fCheckCookie->control.status = B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND; } @@ -1374,16 +1402,16 @@ continue; } - control->inode = inode->ID(); - control->mode = inode->Mode(); + fCheckCookie->control.inode = inode->ID(); + fCheckCookie->control.mode = inode->Mode(); if (!inode->IsContainer()) { // Check file - control->errors = 0; - control->status = CheckInode(inode, control); + fCheckCookie->control.errors = 0; + fCheckCookie->control.status = CheckInode(inode); - if (inode->GetName(control->name) < B_OK) - strcpy(control->name, "(node has no name)"); + if (inode->GetName(fCheckCookie->control.name) < B_OK) + strcpy(fCheckCookie->control.name, "(node has no name)"); return B_OK; } @@ -1408,11 +1436,11 @@ vnode.Keep(); // check the inode of the directory - control->errors = 0; - control->status = CheckInode(inode, control); + fCheckCookie->control.errors = 0; + fCheckCookie->control.status = CheckInode(inode); - if (inode->GetName(control->name) < B_OK) - strcpy(control->name, "(dir has no name)"); + if (inode->GetName(fCheckCookie->control.name) < B_OK) + strcpy(fCheckCookie->control.name, "(dir has no name)"); return B_OK; } @@ -1439,23 +1467,23 @@ continue; // fill in the control data as soon as we have them - strlcpy(control->name, name, B_FILE_NAME_LENGTH); - control->inode = id; - control->errors = 0; + strlcpy(fCheckCookie->control.name, name, B_FILE_NAME_LENGTH); + fCheckCookie->control.inode = id; + fCheckCookie->control.errors = 0; Vnode vnode(fVolume, id); Inode* inode; if (vnode.Get(&inode) != B_OK) { FATAL(("Could not open inode ID %" B_PRIdINO "!\n", id)); - control->errors |= BFS_COULD_NOT_OPEN; + fCheckCookie->control.errors |= BFS_COULD_NOT_OPEN; - if ((control->flags & BFS_REMOVE_INVALID) != 0) { + if ((fCheckCookie->control.flags & BFS_REMOVE_INVALID) != 0) { status = _RemoveInvalidNode(fCheckCookie->parent, fCheckCookie->iterator->Tree(), NULL, name); } else status = B_ERROR; - control->status = status; + fCheckCookie->control.status = status; return B_OK; } @@ -1466,11 +1494,12 @@ const char* localName = inode->Name(node.Node()); if (localName == NULL || strcmp(localName, name)) { - control->errors |= BFS_NAMES_DONT_MATCH; + fCheckCookie->control.errors |= BFS_NAMES_DONT_MATCH; FATAL(("Names differ: tree \"%s\", inode \"%s\"\n", name, localName)); - if ((control->flags & BFS_FIX_NAME_MISMATCHES) != 0) { + if ((fCheckCookie->control.flags & BFS_FIX_NAME_MISMATCHES) + != 0) { // Rename the inode Transaction transaction(fVolume, inode->BlockNumber()); @@ -1480,14 +1509,14 @@ if (status == B_OK) status = transaction.Done(); if (status != B_OK) { - control->status = status; + fCheckCookie->control.status = status; return B_OK; } } } } - control->mode = inode->Mode(); + fCheckCookie->control.mode = inode->Mode(); // 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) @@ -1503,15 +1532,16 @@ fCheckCookie->parent->BlockNumber())); // if we are allowed to fix errors, we should remove the file - if ((control->flags & BFS_REMOVE_WRONG_TYPES) != 0 - && (control->flags & BFS_FIX_BITMAP_ERRORS) != 0) { + if ((fCheckCookie->control.flags & BFS_REMOVE_WRONG_TYPES) != 0 + && (fCheckCookie->control.flags & BFS_FIX_BITMAP_ERRORS) + != 0) { status = _RemoveInvalidNode(fCheckCookie->parent, NULL, inode, name); } else status = B_ERROR; - control->errors |= BFS_WRONG_TYPE; - control->status = status; + fCheckCookie->control.errors |= BFS_WRONG_TYPE; + fCheckCookie->control.status = status; return B_OK; } @@ -1520,8 +1550,7 @@ fCheckCookie->stack.Push(inode->BlockRun()); else { // check it now - control->status = CheckInode(inode, control); - + fCheckCookie->control.status = CheckInode(inode); return B_OK; } } @@ -1626,8 +1655,7 @@ status_t -BlockAllocator::CheckBlockRun(block_run run, const char* type, - check_control* control, bool allocated) +BlockAllocator::CheckBlockRun(block_run run, const char* type, bool allocated) { if (run.AllocationGroup() < 0 || run.AllocationGroup() >= fNumGroups || run.Start() > fGroups[run.AllocationGroup()].fNumBits @@ -1636,10 +1664,10 @@ || run.length == 0) { PRINT(("%s: block_run(%ld, %u, %u) is invalid!\n", type, run.AllocationGroup(), run.Start(), run.Length())); - if (control == NULL) + if (fCheckCookie == NULL) return B_BAD_DATA; - control->errors |= BFS_INVALID_BLOCK_RUN; + fCheckCookie->control.errors |= BFS_INVALID_BLOCK_RUN; return B_OK; } @@ -1664,7 +1692,7 @@ while (length < run.Length() && pos < cached.NumBlockBits()) { if (cached.IsUsed(pos) != allocated) { - if (control == NULL) { + if (fCheckCookie == NULL) { PRINT(("%s: block_run(%ld, %u, %u) is only partially " "allocated (pos = %ld, length = %ld)!\n", type, run.AllocationGroup(), run.Start(), run.Length(), @@ -1673,9 +1701,9 @@ } if (firstMissing == -1) { firstMissing = firstGroupBlock + pos + block * bitsPerBlock; - control->errors |= BFS_MISSING_BLOCKS; + fCheckCookie->control.errors |= BFS_MISSING_BLOCKS; } - control->stats.missing++; + fCheckCookie->control.stats.missing++; } else if (firstMissing != -1) { PRINT(("%s: block_run(%ld, %u, %u): blocks %Ld - %Ld are " "%sallocated!\n", type, run.AllocationGroup(), run.Start(), @@ -1692,11 +1720,11 @@ if (_CheckBitmapIsUsedAt(firstGroupBlock + offset)) { if (firstSet == -1) { firstSet = firstGroupBlock + offset; - control->errors |= BFS_BLOCKS_ALREADY_SET; + fCheckCookie->control.errors |= BFS_BLOCKS_ALREADY_SET; dprintf("block %" B_PRIdOFF " is already set!!!\n", firstGroupBlock + offset); } - control->stats.already_set++; + fCheckCookie->control.stats.already_set++; } else { if (firstSet != -1) { FATAL(("%s: block_run(%d, %u, %u): blocks %" B_PRIdOFF @@ -1735,14 +1763,14 @@ status_t -BlockAllocator::CheckInode(Inode* inode, check_control* control) +BlockAllocator::CheckInode(Inode* inode) { - if (control != NULL && fCheckBitmap == NULL) + if (fCheckCookie != NULL && fCheckBitmap == NULL) return B_NO_INIT; if (inode == NULL) return B_BAD_VALUE; - status_t status = CheckBlockRun(inode->BlockRun(), "inode", control); + status_t status = CheckBlockRun(inode->BlockRun(), "inode"); if (status != B_OK) return status; @@ -1767,7 +1795,7 @@ if (data->direct[i].IsZero()) break; - status = CheckBlockRun(data->direct[i], "direct", control); + status = CheckBlockRun(data->direct[i], "direct"); if (status < B_OK) return status; } @@ -1778,7 +1806,7 @@ // check the indirect range if (data->max_indirect_range) { - status = CheckBlockRun(data->indirect, "indirect", control); + status = CheckBlockRun(data->indirect, "indirect"); if (status < B_OK) return status; @@ -1795,7 +1823,7 @@ if (runs[index].IsZero()) break; - status = CheckBlockRun(runs[index], "indirect->run", control); + status = CheckBlockRun(runs[index], "indirect->run"); if (status < B_OK) return status; } @@ -1807,8 +1835,7 @@ // check the double indirect range if (data->max_double_indirect_range) { - status = CheckBlockRun(data->double_indirect, "double indirect", - control); + status = CheckBlockRun(data->double_indirect, "double indirect"); if (status != B_OK) return status; @@ -1831,7 +1858,7 @@ if (indirect.IsZero()) return B_OK; - status = CheckBlockRun(indirect, "double indirect->runs", control); + status = CheckBlockRun(indirect, "double indirect->runs"); if (status != B_OK) return status; @@ -1850,7 +1877,7 @@ return B_OK; status = CheckBlockRun(runs[index % runsPerBlock], - "double indirect->runs->run", control); + "double indirect->runs->run"); if (status != B_OK) return status; } while ((++index % runsPerArray) != 0); Modified: haiku/trunk/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h 2010-03-06 04:45:43 UTC (rev 35769) +++ haiku/trunk/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h 2010-03-06 13:47:50 UTC (rev 35770) @@ -1,5 +1,5 @@ /* - * Copyright 2001-2009, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx + * Copyright 2001-2010, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx * This file may be used under the terms of the MIT License. */ #ifndef BLOCK_ALLOCATOR_H @@ -54,10 +54,8 @@ bool allocated = true); status_t CheckBlockRun(block_run run, const char* type = NULL, - check_control* control = NULL, bool allocated = true); - status_t CheckInode(Inode* inode, - check_control* control = NULL); + status_t CheckInode(Inode* inode); size_t BitmapSize() const; Modified: haiku/trunk/src/add-ons/kernel/file_systems/bfs/bfs_control.h =================================================================== --- haiku/trunk/src/add-ons/kernel/file_systems/bfs/bfs_control.h 2010-03-06 04:45:43 UTC (rev 35769) +++ haiku/trunk/src/add-ons/kernel/file_systems/bfs/bfs_control.h 2010-03-06 13:47:50 UTC (rev 35770) @@ -1,10 +1,11 @@ /* - * Copyright 2001-2009, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx + * Copyright 2001-2010, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx * This file may be used under the terms of the MIT License. */ #ifndef BFS_CONTROL_H #define BFS_CONTROL_H + //! additional functionality exported via ioctl() @@ -35,8 +36,8 @@ #define BFS_IOCTL_STOP_CHECKING 14202 #define BFS_IOCTL_CHECK_NEXT_NODE 14203 -/* all fields except "flags", and "name" must be set to zero before - * BFS_IOCTL_START_CHECKING is called +/* 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; @@ -78,4 +79,5 @@ /* check control magic value */ #define BFS_IOCTL_CHECK_MAGIC 'BChk' + #endif /* BFS_CONTROL_H */