added 8 changesets to branch 'refs/remotes/ahenriksson-github/production' old head: 8b54ad6ef747ef971a51e95c855fb6ec6e89e061 new head: 0e8f38ab332a8d0d43e9c03a07c076b9a8c3f759 ---------------------------------------------------------------------------- a8f4a6b: Fix locking in resize code be09956: Rework resize code to fit better with resizing infrastructure 34e2a64: Fix logic in disk_device regarding original and shadow values OriginalSize() etc. functions are added to access the BPartition's original values. I add Original* functions as needed by DiskDeviceJobGenerator, and the functions of the corresponding block in the header, since I don't really know if all of them make sense. 1e59a21: Fill in Resize() call in KFileSystem b70891c: Resize support in the BFS disk system add-on 81840c6: Resize support in the intel partitioning disk system add-on 21578de: Add resizefs utility 0e8f38a: Add a resizing back door for use with bfs_shell The resizefs command in bfs_shell is changed to use this interface. [ ahenriksson <sausageboy@xxxxxxxxx> ] ---------------------------------------------------------------------------- 21 files changed, 617 insertions(+), 480 deletions(-) build/jam/HaikuImage | 4 +- headers/private/storage/Partition.h | 17 ++ src/add-ons/disk_systems/bfs/BFSAddOn.cpp | 47 ++- src/add-ons/disk_systems/bfs/BFSAddOn.h | 9 + .../disk_systems/intel/PartitionMapAddOn.cpp | 60 ++++ src/add-ons/disk_systems/intel/PartitionMapAddOn.h | 10 + .../kernel/file_systems/bfs/BlockAllocator.cpp | 18 +- .../kernel/file_systems/bfs/BlockAllocator.h | 3 +- src/add-ons/kernel/file_systems/bfs/Index.cpp | 2 + .../kernel/file_systems/bfs/ResizeVisitor.cpp | 253 ++++++++-------- .../kernel/file_systems/bfs/ResizeVisitor.h | 23 +- src/add-ons/kernel/file_systems/bfs/Volume.cpp | 25 +- src/add-ons/kernel/file_systems/bfs/Volume.h | 7 - src/add-ons/kernel/file_systems/bfs/bfs_control.h | 49 +-- .../kernel/file_systems/bfs/kernel_interface.cpp | 92 +++--- src/bin/Jamfile | 1 + src/bin/resizefs.cpp | 132 ++++++++ .../storage/disk_device/DiskDeviceJobGenerator.cpp | 31 +- src/kits/storage/disk_device/Partition.cpp | 102 +++++++ .../kernel/disk_device_manager/KFileSystem.cpp | 16 +- src/tools/bfs_shell/command_resizefs.cpp | 196 +----------- ############################################################################ Commit: a8f4a6bb2af66dd1284dbb53e452acb6f74aa195 Author: ahenriksson <sausageboy@xxxxxxxxx> Date: Tue Jul 31 13:03:13 2012 UTC Fix locking in resize code ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp index 8e220f7..cf935d1 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp @@ -519,7 +519,7 @@ BlockAllocator::~BlockAllocator() status_t -BlockAllocator::Initialize(bool full) +BlockAllocator::Initialize(bool full, bool alreadyLocked) { fNumGroups = fVolume->AllocationGroups(); fBlocksPerGroup = fVolume->SuperBlock().BlocksPerAllocationGroup(); @@ -532,8 +532,10 @@ BlockAllocator::Initialize(bool full) if (!full) return B_OK; - recursive_lock_lock(&fLock); - // the lock will be released by the _Initialize() method + if (!alreadyLocked) { + recursive_lock_lock(&fLock); + // the lock will be released by the _Initialize() method + } thread_id id = spawn_kernel_thread((thread_func)BlockAllocator::_Initialize, "bfs block allocator", B_LOW_PRIORITY, this); @@ -609,16 +611,19 @@ BlockAllocator::InitializeAndClearBitmap(Transaction& transaction) status_t BlockAllocator::Reinitialize() { - RecursiveLocker locker(fLock); + recursive_lock_lock(&fLock); + // the lock will be unlocked in the call to Initialize() // need to write back any pending changes to the block bitmap // TODO: shall we read through the cache in _Initialize instead? status_t status = fVolume->GetJournal(0)->FlushLogAndBlocks(); - if (status != B_OK) + if (status != B_OK) { + recursive_lock_unlock(&fLock); return status; + } delete[] fGroups; - return Initialize(); + return Initialize(true, true); } @@ -1244,6 +1249,7 @@ BlockAllocator::CheckBlocks(off_t start, off_t length, bool allocated, uint32 blockOffset = start % fVolume->BlockSize(); AllocationBlock cached(fVolume); + RecursiveLocker locker(fLock); while (groupBlock < fGroups[group].NumBlocks() && length > 0) { if (cached.SetTo(fGroups[group], groupBlock) != B_OK) diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h index c22707f..cd494d2 100644 --- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h +++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h @@ -26,7 +26,8 @@ public: BlockAllocator(Volume* volume); ~BlockAllocator(); - status_t Initialize(bool full = true); + status_t Initialize(bool full = true, + bool alreadyLocked = false); status_t InitializeAndClearBitmap(Transaction& transaction); status_t Reinitialize(); diff --git a/src/add-ons/kernel/file_systems/bfs/Index.cpp b/src/add-ons/kernel/file_systems/bfs/Index.cpp index c66a879..8da3996 100644 --- a/src/add-ons/kernel/file_systems/bfs/Index.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Index.cpp @@ -389,6 +389,8 @@ status_t Index::UpdateInode(Transaction& transaction, const uint8* key, uint16 length, off_t oldInodeID, off_t newInodeID) { + Node()->WriteLockInTransaction(transaction); + // remove node and insert it with the new id (we can't use // BPlusTree::Replace, as it doesn't handle trees where duplicates // are allowed) diff --git a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp index 4156dfc..7c368bc 100644 --- a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp +++ b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp @@ -333,6 +333,8 @@ ResizeVisitor::_UpdateParent(Transaction& transaction, Inode* inode, if (status != B_OK) return status; + parent->WriteLockInTransaction(transaction); + // update inode id in parent if (inode->IsAttributeDirectory()) { parent->Attributes() = GetVolume()->ToBlockRun(newInodeID); @@ -511,6 +513,8 @@ ResizeVisitor::_UpdateChildren(Transaction& transaction, Inode* inode, if (status != B_OK) return status; + childInode->WriteLockInTransaction(transaction); + childInode->Node().parent = GetVolume()->ToBlockRun(newInodeID); childInode->WriteBack(transaction); ############################################################################ Commit: be09956f5ad17413e935f0a60798d46d88a5fd36 Author: ahenriksson <sausageboy@xxxxxxxxx> Date: Mon Jul 23 17:49:29 2012 UTC Rework resize code to fit better with resizing infrastructure ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp index 7c368bc..481615ed 100644 --- a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp +++ b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp @@ -22,148 +22,94 @@ ResizeVisitor::ResizeVisitor(Volume* volume) } -void -ResizeVisitor::StartResize() +status_t +ResizeVisitor::Resize(off_t size, disk_job_id job) { - _SetError(B_OK); - - uint32 blockSize = GetVolume()->BlockSize(); - uint32 blockShift = GetVolume()->BlockShift(); - - // fill in old values in the control - Control().stats.bitmap_blocks_old = GetVolume()->NumBitmapBlocks(); - Control().stats.log_start_old = GetVolume()->Log().Start(); - Control().stats.log_length_old = GetVolume()->Log().Length(); - - Control().stats.block_size = GetVolume()->BlockSize(); - - // calculate new values for the log and number of bitmap blocks - fNumBlocks = (Control().new_size + blockSize - 1) >> blockShift; - // round up to a whole block - - uint16 logLength = 2048; - if (fNumBlocks <= 20480) - logLength = 512; - if (Control().new_size > 1LL * 1024 * 1024 * 1024) - logLength = 4096; - - fBitmapBlocks = (fNumBlocks + blockSize * 8 - 1) / (blockSize * 8); - fNewLog.SetTo(0, 1 + fBitmapBlocks, logLength); - - off_t reservedLength = 1 + fBitmapBlocks + logLength; - - // fill in new values - Control().stats.bitmap_blocks_new = fBitmapBlocks; - Control().stats.log_start_new = 1 + fBitmapBlocks; - Control().stats.log_length_new = logLength; - + _CalculateNewSizes(size); - // See if the resize is actually possible - - // the new size is limited by what we can fit into the first allocation - // group - if (reservedLength > (1UL << GetVolume()->AllocationGroupShift())) { - _SetError(B_BAD_VALUE, BFS_SIZE_TOO_LARGE); - return; - } - - status_t status = GetVolume()->UpdateDeviceSize(); - if (status != B_OK) { - _SetError(status); - return; - } + status_t status = _IsResizePossible(size); + if (status != B_OK) + return status; - if (GetVolume()->DeviceSize() < (fNumBlocks << blockShift)) { - _SetError(B_BAD_VALUE, BFS_DISK_TOO_SMALL); - return; + if (fNumBlocks == GetVolume()->NumBlocks()) { + INFORM(("Resize: New size was equal to old.\n")); + return B_OK; } - if (GetVolume()->UsedBlocks() > fNumBlocks) { - _SetError(B_BAD_VALUE, BFS_NO_SPACE); - return; - } - - // stop now if we're only checking out the effects of a resize - if (Control().flags & BFS_CHECK_RESIZE) - return; - // make sure no unsynced transaction causes invalidated blocks to linger // in the block cache when we write data with write_pos + // TODO: how does this work when the file system is mounted? status = GetVolume()->GetJournal(0)->FlushLogAndBlocks(); if (status != B_OK) { - _SetError(status); - return; + FATAL(("Resize: Failed to flush log!\n")); + return status; } - fBeginBlock = reservedLength; - - if (fNumBlocks < GetVolume()->NumBlocks()) { - fShrinking = true; - fEndBlock = fNumBlocks; - } else { - fShrinking = false; - fEndBlock = GetVolume()->NumBlocks(); - } + update_disk_device_job_progress(job, 0.0); Start(VISIT_REGULAR | VISIT_INDICES | VISIT_REMOVED | VISIT_ATTRIBUTE_DIRECTORIES); -} + // move file system data out of the way + while (true) { + fError = false; -void -ResizeVisitor::FinishResize() -{ - if (Control().status != B_OK) { - _SetError(B_OK); - return; - } + status = Next(); + if (fError) + return status; - _SetError(B_OK); - status_t status; + if (status == B_ENTRY_NOT_FOUND) + break; + } + // move log and change file system size in the superblock if (fShrinking) { status = _ResizeVolume(); if (status != B_OK) { - _SetError(status, BFS_CHANGE_SIZE_FAILED); - return; + FATAL(("Resize: Failed to update file system size!\n")); + return status; } status = GetVolume()->GetJournal(0)->MoveLog(fNewLog); if (status != B_OK) { - _SetError(status, BFS_MOVE_LOG_FAILED); - return; + FATAL(("Resize: Failed to move the log area!\n")); + return status; } } else { status = GetVolume()->GetJournal(0)->MoveLog(fNewLog); if (status != B_OK) { - _SetError(status, BFS_MOVE_LOG_FAILED); - return; + FATAL(("Resize: Failed to move the log area!\n")); + return status; } status = _ResizeVolume(); if (status != B_OK) { - _SetError(status, BFS_CHANGE_SIZE_FAILED); - return; + FATAL(("Resize: Failed to update file system size!\n")); + return status; } } + + update_disk_device_job_progress(job, 1.0); + return B_OK; } status_t ResizeVisitor::VisitInode(Inode* inode, const char* treeName) { - Control().inode = inode->ID(); + // get the name so we can show it to the user if something goes wrong + // TODO: we don't really have to do this for every inode we visit + char name[B_FILE_NAME_LENGTH]; - // set name if (treeName == NULL) { - if (inode->GetName(Control().name) < B_OK) { + if (inode->GetName(name) < B_OK) { if (inode->IsContainer()) - strcpy(Control().name, "(dir has no name)"); + strcpy(name, "(dir has no name)"); else - strcpy(Control().name, "(node has no name)"); + strcpy(name, "(node has no name)"); } } else - strcpy(Control().name, treeName); + strcpy(name, treeName); WriteLocker writeLocker(inode->Lock()); @@ -181,7 +127,9 @@ ResizeVisitor::VisitInode(Inode* inode, const char* treeName) status = _MoveInode(inode, newInodeID, treeName); if (status != B_OK) { mark_vnode_busy(GetVolume()->FSVolume(), inode->ID(), false); - _SetError(status, BFS_MOVE_INODE_FAILED); + FATAL(("Resize: Failed to move inode %" B_PRIdINO + ", \"%s\"!\n", inode->ID(), name)); + fError = true; return status; } @@ -189,7 +137,9 @@ ResizeVisitor::VisitInode(Inode* inode, const char* treeName) newInodeID); if (status != B_OK) { mark_vnode_busy(GetVolume()->FSVolume(), inode->ID(), false); - _SetError(status, BFS_MOVE_INODE_FAILED); + FATAL(("Resize: Failed to change ID in vnode, inode %" B_PRIdINO + ", \"%s\"!\n", inode->ID(), name)); + fError = true; return status; } @@ -197,25 +147,26 @@ ResizeVisitor::VisitInode(Inode* inode, const char* treeName) // accessing the inode with the new ID mark_vnode_busy(GetVolume()->FSVolume(), inode->ID(), false); - - Control().stats.inodes_moved++; } // move the stream if necessary bool inRange; status = inode->StreamInRange(fBeginBlock, fEndBlock, inRange); if (status != B_OK) { - _SetError(status, BFS_MOVE_STREAM_FAILED); + FATAL(("Resize: Failed to check file stream, inode %" B_PRIdINO + ", \"%s\"!\n", inode->ID(), name)); + fError = true; return status; } if (!inRange) { status = inode->MoveStream(fBeginBlock, fEndBlock); if (status != B_OK) { - _SetError(status, BFS_MOVE_STREAM_FAILED); + FATAL(("Resize: Failed to move file stream, inode %" B_PRIdINO + ", \"%s\"!\n", inode->ID(), name)); + fError = true; return status; } - Control().stats.streams_moved++; } return B_OK; @@ -228,7 +179,7 @@ ResizeVisitor::OpenInodeFailed(status_t reason, ino_t id, Inode* parent, { FATAL(("Could not open inode at %" B_PRIdOFF "\n", id)); - _SetError(reason); + fError = true; return reason; } @@ -239,7 +190,7 @@ ResizeVisitor::OpenBPlusTreeFailed(Inode* inode) FATAL(("Could not open b+tree from inode at %" B_PRIdOFF "\n", inode->ID())); - _SetError(B_ERROR); + fError = true; return B_ERROR; } @@ -250,11 +201,73 @@ ResizeVisitor::TreeIterationFailed(status_t reason, Inode* parent) FATAL(("Tree iteration failed in parent at %" B_PRIdOFF "\n", parent->ID())); - _SetError(reason); + fError = true; return reason; } +void +ResizeVisitor::_CalculateNewSizes(off_t size) +{ + uint32 blockSize = GetVolume()->BlockSize(); + uint32 blockShift = GetVolume()->BlockShift(); + + fNumBlocks = size >> blockShift; + + fBitmapBlocks = (fNumBlocks + blockSize * 8 - 1) / (blockSize * 8); + // divide total number of blocks by the number of bits in a bitmap + // block, rounding up + + off_t logLength = Volume::CalculateLogSize(fNumBlocks, size); + + fNewLog.SetTo(0, 1 + fBitmapBlocks, logLength); + fReservedLength = 1 + fBitmapBlocks + logLength; + + fBeginBlock = fReservedLength; + + if (fNumBlocks < GetVolume()->NumBlocks()) { + fShrinking = true; + fEndBlock = fNumBlocks; + } else { + fShrinking = false; + fEndBlock = GetVolume()->NumBlocks(); + } +} + + +status_t +ResizeVisitor::_IsResizePossible(off_t size) +{ + if ((size % GetVolume()->BlockSize()) != 0) { + FATAL(("Resize: New size not multiple of block size!\n")); + return B_BAD_VALUE; + } + + // the new size is limited by what we can fit into the first allocation + // group + if (fReservedLength > (1UL << GetVolume()->AllocationGroupShift())) { + FATAL(("Resize: Reserved area is too large for allocation group!\n")); + return B_BAD_VALUE; + } + + status_t status = GetVolume()->UpdateDeviceSize(); + if (status != B_OK) + return status; + + if (GetVolume()->DeviceSize() < size) { + FATAL(("Resize: Device too small for new size\n")); + return B_BAD_VALUE; + } + + if (GetVolume()->UsedBlocks() > fNumBlocks) { + FATAL(("Resize: Not enough free space for resize!\n")); + return B_BAD_VALUE; + } + + return B_OK; +} + + status_t ResizeVisitor::_ResizeVolume() { @@ -268,11 +281,11 @@ ResizeVisitor::_ResizeVolume() if (status != B_OK) return status; } - + // make sure we have space to resize the bitmap if (1 + fBitmapBlocks > GetVolume()->Log().Start()) return B_ERROR; - + // clear bitmap blocks - aTODO maybe not use a transaction? Transaction transaction(GetVolume(), 0); @@ -290,7 +303,7 @@ ResizeVisitor::_ResizeVolume() status = transaction.Done(); if (status != B_OK) return status; - + // update superblock and volume information disk_super_block& superBlock = GetVolume()->SuperBlock(); @@ -629,23 +642,3 @@ ResizeVisitor::_MoveInode(Inode* inode, off_t& newInodeID, const char* treeName) return B_OK; } - - -bool -ResizeVisitor::_ControlValid() -{ - if (Control().magic != BFS_IOCTL_RESIZE_MAGIC) { - FATAL(("invalid resize_control!\n")); - return false; - } - - return true; -} - - -void -ResizeVisitor::_SetError(status_t status, uint32 failurePoint) -{ - Control().status = status; - Control().failure_point = failurePoint; -} diff --git a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.h b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.h index 246205f..41f5535 100644 --- a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.h +++ b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.h @@ -20,10 +20,7 @@ class ResizeVisitor : public FileSystemVisitor { public: ResizeVisitor(Volume* volume); - void StartResize(); - void FinishResize(); - - resize_control& Control() { return fControl; } + status_t Resize(off_t size, disk_job_id job); virtual status_t VisitInode(Inode* inode, const char* treeName); @@ -35,6 +32,8 @@ public: Inode* parent); private: + void _CalculateNewSizes(off_t size); + status_t _IsResizePossible(off_t size); status_t _ResizeVolume(); // moving the inode @@ -56,23 +55,19 @@ private: status_t _MoveInode(Inode* inode, off_t& newInodeID, const char* treeName); - bool _ControlValid(); - - void _SetError(status_t status, - uint32 failurePoint = BFS_OTHER_ERROR); - private: - resize_control fControl; - bool fShrinking; + bool fError; off_t fNumBlocks; + off_t fBitmapBlocks; + off_t fReservedLength; + + block_run fNewLog; off_t fBeginBlock; off_t fEndBlock; - off_t fBitmapBlocks; - - block_run fNewLog; + bool fShrinking; }; diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.cpp b/src/add-ons/kernel/file_systems/bfs/Volume.cpp index a212e8b..a04eaab 100644 --- a/src/add-ons/kernel/file_systems/bfs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Volume.cpp @@ -251,8 +251,7 @@ Volume::Volume(fs_volume* volume) fDirtyCachedBlocks(0), fFlags(0), fCheckingThread(-1), - fCheckVisitor(NULL), - fResizeVisitor(NULL) + fCheckVisitor(NULL) { mutex_init(&fLock, "bfs volume"); mutex_init(&fQueryLock, "bfs queries"); @@ -640,28 +639,6 @@ Volume::DeleteCheckVisitor() } -status_t -Volume::CreateResizeVisitor() -{ - if (fResizeVisitor != NULL) - return B_BUSY; - - fResizeVisitor = new(std::nothrow) ::ResizeVisitor(this); - if (fResizeVisitor == NULL) - return B_NO_MEMORY; - - return B_OK; -} - - -void -Volume::DeleteResizeVisitor() -{ - delete fResizeVisitor; - fResizeVisitor = NULL; -} - - // #pragma mark - Disk scanning and initialization diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.h b/src/add-ons/kernel/file_systems/bfs/Volume.h index 94972f6..6e877b7 100644 --- a/src/add-ons/kernel/file_systems/bfs/Volume.h +++ b/src/add-ons/kernel/file_systems/bfs/Volume.h @@ -127,11 +127,6 @@ public: void DeleteCheckVisitor(); ::CheckVisitor* CheckVisitor() { return fCheckVisitor; } - // resizing - status_t CreateResizeVisitor(); - void DeleteResizeVisitor(); - ::ResizeVisitor* ResizeVisitor() { return fResizeVisitor; } - // cache access status_t WriteSuperBlock(); status_t FlushDevice(); @@ -190,8 +185,6 @@ protected: thread_id fCheckingThread; ::CheckVisitor* fCheckVisitor; - ::ResizeVisitor* fResizeVisitor; - InodeList fRemovedInodes; }; 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 186002a..d5b859e 100644 --- a/src/add-ons/kernel/file_systems/bfs/bfs_control.h +++ b/src/add-ons/kernel/file_systems/bfs/bfs_control.h @@ -1,6 +1,5 @@ /* * Copyright 2001-2012, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx - * Copyright 2012, Andreas Henriksson, sausageboy@xxxxxxxxx * This file may be used under the terms of the MIT License. */ #ifndef BFS_CONTROL_H @@ -100,52 +99,4 @@ struct check_control { #define BFS_IOCTL_CHECK_MAGIC 'BChk' -/* ioctls to resize the file system - * usage is analogous to that of "chkbfs" above - */ -#define BFS_IOCTL_START_RESIZE 14205 -#define BFS_IOCTL_FINISH_RESIZE 14206 -#define BFS_IOCTL_MOVE_NEXT_NODE 14207 - -struct resize_control { - uint32 magic; - uint32 flags; - uint64 new_size; - char name[B_FILE_NAME_LENGTH]; - ino_t inode; - uint32 failure_point; - struct { - uint64 inodes_moved; - uint64 streams_moved; - - uint16 bitmap_blocks_new; - uint16 log_start_new; - uint16 log_length_new; - - uint16 bitmap_blocks_old; - uint16 log_start_old; - uint16 log_length_old; - - uint32 block_size; - } stats; - status_t status; -}; - -/* resize flags */ -#define BFS_CHECK_RESIZE 1 - -/* resize points of failure */ -#define BFS_OTHER_ERROR 1 -#define BFS_SIZE_TOO_LARGE 2 -#define BFS_DISK_TOO_SMALL 3 -#define BFS_NO_SPACE 4 -#define BFS_MOVE_LOG_FAILED 5 -#define BFS_MOVE_INODE_FAILED 6 -#define BFS_MOVE_STREAM_FAILED 7 -#define BFS_CHANGE_SIZE_FAILED 8 - -/* magic resize constant */ -#define BFS_IOCTL_RESIZE_MAGIC 'BRsz' - - #endif /* BFS_CONTROL_H */ diff --git a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp index e6aab3c..24f43c9 100644 --- a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp @@ -720,60 +720,6 @@ bfs_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd, return volume->WriteSuperBlock(); } - case BFS_IOCTL_START_RESIZE: - { - status_t status = volume->CreateResizeVisitor(); - if (status != B_OK) - return status; - - ResizeVisitor* resizer = volume->ResizeVisitor(); - - if (user_memcpy(&resizer->Control(), buffer, - sizeof(resize_control)) != B_OK) { - return B_BAD_ADDRESS; - } - - resizer->StartResize(); - - status = user_memcpy(buffer, &resizer->Control(), - sizeof(resize_control)); - - if (resizer->Control().status != B_OK - || (resizer->Control().flags & BFS_CHECK_RESIZE)) { - volume->DeleteResizeVisitor(); - } - - return status; - } - case BFS_IOCTL_FINISH_RESIZE: - { - ResizeVisitor* resizer = volume->ResizeVisitor(); - if (resizer == NULL) - return B_NO_INIT; - - resizer->FinishResize(); - - status_t status = user_memcpy(buffer, &resizer->Control(), - sizeof(resize_control)); - - volume->DeleteResizeVisitor(); - return status; - } - case BFS_IOCTL_MOVE_NEXT_NODE: - { - ResizeVisitor* resizer = volume->ResizeVisitor(); - if (resizer == NULL) - return B_NO_INIT; - - if (resizer->Next() == B_ENTRY_NOT_FOUND) { - // are we really done, or is this an error? - if (resizer->Control().status == B_OK) - return B_ENTRY_NOT_FOUND; - } - - return user_memcpy(buffer, &resizer->Control(), - sizeof(resize_control)); - } #ifdef DEBUG_FRAGMENTER case 56741: @@ -2318,13 +2264,43 @@ static uint32 bfs_get_supported_operations(partition_data* partition, uint32 mask) { // TODO: We should at least check the partition size. - return B_DISK_SYSTEM_SUPPORTS_INITIALIZING + return B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED + | B_DISK_SYSTEM_SUPPORTS_INITIALIZING | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME | B_DISK_SYSTEM_SUPPORTS_WRITING; } static status_t +bfs_resize(int fd, partition_id partitionID, off_t size, disk_job_id job) +{ +#ifndef BFS_SHELL + // get Volume pointer from partitionID + if (read_lock_disk_device(partitionID) == NULL) + return B_ERROR; + + partition_data* partition = get_partition(partitionID); + read_unlock_disk_device(partitionID); + + if (partition == NULL) + return B_ERROR; + + Volume* volume = (Volume*)partition->mount_cookie; + if (volume == NULL) + return B_ERROR; + + // do the resize + ResizeVisitor resizer(volume); + return resizer.Resize(size, job); +#else + // fs_shell can't use this interface as it doesn't have the + // partion_data concept + return B_ERROR; +#endif +} + + +static status_t bfs_initialize(int fd, partition_id partitionID, const char* name, const char* parameterString, off_t /*partitionSize*/, disk_job_id job) { @@ -2548,7 +2524,7 @@ static file_system_module_info sBeFileSystem = { // | B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING_WHILE_MOUNTED // | B_DISK_SYSTEM_SUPPORTS_CHECKING_WHILE_MOUNTED // | B_DISK_SYSTEM_SUPPORTS_REPAIRING_WHILE_MOUNTED -// | B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED + | B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED // | B_DISK_SYSTEM_SUPPORTS_MOVING_WHILE_MOUNTED // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME_WHILE_MOUNTED // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS_WHILE_MOUNTED @@ -2578,7 +2554,7 @@ static file_system_module_info sBeFileSystem = { /* writing */ NULL, // defragment NULL, // repair - NULL, // resize + bfs_resize, NULL, // move NULL, // set_content_name NULL, // set_content_parameters ############################################################################ Commit: 34e2a649b5c64cf263b5bc620407c17b59d76a23 Author: ahenriksson <sausageboy@xxxxxxxxx> Date: Tue Jul 31 15:35:26 2012 UTC Fix logic in disk_device regarding original and shadow values OriginalSize() etc. functions are added to access the BPartition's original values. I add Original* functions as needed by DiskDeviceJobGenerator, and the functions of the corresponding block in the header, since I don't really know if all of them make sense. ---------------------------------------------------------------------------- diff --git a/headers/private/storage/Partition.h b/headers/private/storage/Partition.h index 2f897c6..5a22de6 100644 --- a/headers/private/storage/Partition.h +++ b/headers/private/storage/Partition.h @@ -73,6 +73,23 @@ public: const char* parameters = NULL); status_t Unmount(uint32 unmountFlags = 0); + // Information about the unmodified partition + + off_t OriginalOffset() const; + off_t OriginalSize() const; + off_t OriginalContentSize() const; + uint32 OriginalBlockSize() const; + int32 OriginalIndex() const; + uint32 OriginalStatus() const; + + const char* OriginalName() const; + const char* OriginalContentName() const; + const char* OriginalType() const; + const char* OriginalContentType() const; + partition_id OriginalID() const; + const char* OriginalParameters() const; + const char* OriginalContentParameters() const; + // Hierarchy Info BDiskDevice* Device() const; diff --git a/src/kits/storage/disk_device/DiskDeviceJobGenerator.cpp b/src/kits/storage/disk_device/DiskDeviceJobGenerator.cpp index 3b46f88..9c26163 100644 --- a/src/kits/storage/disk_device/DiskDeviceJobGenerator.cpp +++ b/src/kits/storage/disk_device/DiskDeviceJobGenerator.cpp @@ -193,7 +193,7 @@ DiskDeviceJobGenerator::_GenerateCleanupJobs(BPartition* partition) // all descendants of a partition to be uninitialized or removed. if (BMutablePartition* shadow = _GetMutablePartition(partition)) { if ((shadow->ChangeFlags() & B_PARTITION_CHANGED_INITIALIZATION) - && partition->fPartitionData->content_type) { + && partition->OriginalContentType()) { // partition changes initialization status_t error = _GenerateUninitializeJob(partition); if (error != B_OK) @@ -224,12 +224,12 @@ DiskDeviceJobGenerator::_GeneratePlacementJobs(BPartition* partition) // Don't resize/move partitions that have an unrecognized contents. // They must have been uninitialized before. if (shadow->Status() == B_PARTITION_UNRECOGNIZED - && (shadow->Size() != partition->Size() - || shadow->Offset() != partition->Offset())) { + && (shadow->Size() != partition->OriginalSize() + || shadow->Offset() != partition->OriginalOffset())) { return B_ERROR; } - if (shadow->Size() > partition->Size()) { + if (shadow->Size() > partition->OriginalSize()) { // size grows: resize first status_t error = _GenerateResizeJob(partition); if (error != B_OK) @@ -241,7 +241,7 @@ DiskDeviceJobGenerator::_GeneratePlacementJobs(BPartition* partition) if (error != B_OK) return error; - if (shadow->Size() < partition->Size()) { + if (shadow->Size() < partition->OriginalSize()) { // size shrinks: resize now status_t error = _GenerateResizeJob(partition); if (error != B_OK) @@ -287,7 +287,7 @@ DiskDeviceJobGenerator::_GenerateChildPlacementJobs(BPartition* partition) moveBack++; // resize the child, if it shall shrink - if (childShadow->Size() < child->Size()) { + if (childShadow->Size() < child->OriginalSize()) { status_t error = _GeneratePlacementJobs(child); if (error != B_OK) return error; @@ -354,7 +354,7 @@ DiskDeviceJobGenerator::_GenerateChildPlacementJobs(BPartition* partition) // their descendants for (int32 i = 0; BPartition* child = partition->_ChildAt(i); i++) { if (BMutablePartition* childShadow = _GetMutablePartition(child)) { - if (childShadow->Size() >= child->Size()) { + if (childShadow->Size() >= child->OriginalSize()) { status_t error = _GeneratePlacementJobs(child); if (error != B_OK) return error; @@ -371,13 +371,11 @@ status_t DiskDeviceJobGenerator::_GenerateRemainingJobs(BPartition* parent, BPartition* partition) { - user_partition_data* partitionData = partition->fPartitionData; - uint32 changeFlags = partition->fDelegate->MutablePartition()->ChangeFlags(); // create the partition, if not existing yet - if (!partitionData) { + if (!partition->fPartitionData) { if (!parent) return B_BAD_VALUE; @@ -389,7 +387,7 @@ DiskDeviceJobGenerator::_GenerateRemainingJobs(BPartition* parent, // name if ((changeFlags & B_PARTITION_CHANGED_NAME) - || compare_string(partition->Name(), partitionData->name)) { + || compare_string(partition->Name(), partition->OriginalName())) { if (!parent) return B_BAD_VALUE; @@ -400,7 +398,7 @@ DiskDeviceJobGenerator::_GenerateRemainingJobs(BPartition* parent, // type if ((changeFlags & B_PARTITION_CHANGED_TYPE) - || compare_string(partition->Type(), partitionData->type)) { + || compare_string(partition->Type(), partition->OriginalType())) { if (!parent) return B_BAD_VALUE; @@ -412,7 +410,7 @@ DiskDeviceJobGenerator::_GenerateRemainingJobs(BPartition* parent, // parameters if ((changeFlags & B_PARTITION_CHANGED_PARAMETERS) || compare_string(partition->Parameters(), - partitionData->parameters)) { + partition->OriginalParameters())) { if (!parent) return B_BAD_VALUE; @@ -434,7 +432,7 @@ DiskDeviceJobGenerator::_GenerateRemainingJobs(BPartition* parent, // content name if ((changeFlags & B_PARTITION_CHANGED_NAME) || compare_string(partition->ContentName(), - partitionData->content_name)) { + partition->OriginalContentName())) { status_t error = _GenerateSetContentNameJob(partition); if (error != B_OK) return error; @@ -443,7 +441,7 @@ DiskDeviceJobGenerator::_GenerateRemainingJobs(BPartition* parent, // content parameters if ((changeFlags & B_PARTITION_CHANGED_PARAMETERS) || compare_string(partition->ContentParameters(), - partitionData->content_parameters)) { + partition->OriginalContentParameters())) { status_t error = _GenerateSetContentParametersJob(partition); if (error != B_OK) return error; @@ -669,6 +667,9 @@ DiskDeviceJobGenerator::_GenerateResizeJob(BPartition* partition) if (error != B_OK) return error; + TRACE("DiskDeviceJobGenerator::GenerateResizeJob() - 4\n"); + TRACE("DiskDeviceJobGenerator::GenerateResizeJob() - 5\n"); + return _AddJob(new(nothrow) ResizeJob(parentReference, reference, partition->Size(), partition->ContentSize())); } diff --git a/src/kits/storage/disk_device/Partition.cpp b/src/kits/storage/disk_device/Partition.cpp index 8bd5fea..518956f 100644 --- a/src/kits/storage/disk_device/Partition.cpp +++ b/src/kits/storage/disk_device/Partition.cpp @@ -642,6 +642,108 @@ BPartition::Unmount(uint32 unmountFlags) } +// OriginalOffset +off_t +BPartition::OriginalOffset() const +{ + return fPartitionData->offset; +} + + +// OriginalSize +off_t +BPartition::OriginalSize() const +{ + return fPartitionData->size; +} + + +// OriginalContentSize +off_t +BPartition::OriginalContentSize() const +{ + return fPartitionData->content_size; +} + +// OriginalBlockSize +uint32 +BPartition::OriginalBlockSize() const +{ + return fPartitionData->block_size; +} + + +// OriginalIndex +int32 +BPartition::OriginalIndex() const +{ + return fPartitionData->index; +} + + +// OriginalStatus +uint32 +BPartition::OriginalStatus() const +{ + return fPartitionData->status; +} + +// OriginalName +const char* +BPartition::OriginalName() const +{ + return fPartitionData->name; +} + + +// OriginalContentName +const char* +BPartition::OriginalContentName() const +{ + return fPartitionData->content_name; +} + + +// OriginalType +const char* +BPartition::OriginalType() const +{ + return fPartitionData->type; +} + + +// OriginalContentType +const char* +BPartition::OriginalContentType() const +{ + return fPartitionData->content_type; +} + + +// OriginalID +int32 +BPartition::OriginalID() const +{ + return fPartitionData->id; +} + + +// OriginalParameters +const char* +BPartition::OriginalParameters() const +{ + return fPartitionData->parameters; +} + + +// OriginalContentParameters +const char* +BPartition::OriginalContentParameters() const +{ + return fPartitionData->content_parameters; +} + + // Device /*! \brief Returns the device this partition resides on. \return The device this partition resides on. ############################################################################ Commit: 1e59a21a0171b41def0da092596856fd3a5242a7 Author: ahenriksson <sausageboy@xxxxxxxxx> Date: Tue Jul 31 10:42:58 2012 UTC Fill in Resize() call in KFileSystem ---------------------------------------------------------------------------- diff --git a/src/system/kernel/disk_device_manager/KFileSystem.cpp b/src/system/kernel/disk_device_manager/KFileSystem.cpp index 90f0018..cba020c 100644 --- a/src/system/kernel/disk_device_manager/KFileSystem.cpp +++ b/src/system/kernel/disk_device_manager/KFileSystem.cpp @@ -127,8 +127,20 @@ KFileSystem::Repair(KPartition* partition, bool checkOnly, disk_job_id job) status_t KFileSystem::Resize(KPartition* partition, off_t size, disk_job_id job) { - // to be implemented - return B_ERROR; + if (!partition || !fModule) + return B_ERROR; + if (!fModule->resize) + return B_NOT_SUPPORTED; + + int fd = -1; + status_t result = partition->Open(O_RDWR, &fd); + if (result != B_OK) + return result; + + result = fModule->resize(fd, partition->ID(), size, job); + + close(fd); + return result; } ############################################################################ Commit: b70891c7bcb223c06ab8e11ae59778de341f155c Author: ahenriksson <sausageboy@xxxxxxxxx> Date: Tue Jul 31 10:46:39 2012 UTC Resize support in the BFS disk system add-on ---------------------------------------------------------------------------- diff --git a/src/add-ons/disk_systems/bfs/BFSAddOn.cpp b/src/add-ons/disk_systems/bfs/BFSAddOn.cpp index b33c828..5f57689 100644 --- a/src/add-ons/disk_systems/bfs/BFSAddOn.cpp +++ b/src/add-ons/disk_systems/bfs/BFSAddOn.cpp @@ -48,7 +48,7 @@ static const uint32 kDiskSystemFlags = // | B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING_WHILE_MOUNTED | B_DISK_SYSTEM_SUPPORTS_CHECKING_WHILE_MOUNTED | B_DISK_SYSTEM_SUPPORTS_REPAIRING_WHILE_MOUNTED -// | B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED + | B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED // | B_DISK_SYSTEM_SUPPORTS_MOVING_WHILE_MOUNTED // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME_WHILE_MOUNTED // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS_WHILE_MOUNTED @@ -334,6 +334,51 @@ BFSPartitionHandle::Repair(bool checkOnly) } +status_t +BFSPartitionHandle::ValidateResize(off_t* size) +{ + return _FitSize(size); +} + + +status_t +BFSPartitionHandle::Resize(off_t size) +{ + off_t fittedSize = size; + status_t status = _FitSize(&fittedSize); + if (status != B_OK) + return status; + + if (fittedSize != size) + return B_BAD_VALUE; + + Partition()->SetContentSize(size); + + return B_OK; +} + + +status_t +BFSPartitionHandle::_FitSize(off_t* size) +{ + BVolume volume(Partition()->VolumeID()); + status_t status = volume.InitCheck(); + if (status != B_OK) + return status; + + if (*size < volume.Capacity() - volume.FreeBytes()) + return B_DEVICE_FULL; + + // TODO: we should check that the allocation groups are large enough to + // do the resize, but we'd need to ask the file system in some fashion. + + // round down to BFS block size + *size -= *size % volume.BlockSize(); + + return B_OK; +} + + // #pragma mark - diff --git a/src/add-ons/disk_systems/bfs/BFSAddOn.h b/src/add-ons/disk_systems/bfs/BFSAddOn.h index 252c0da..d24b9ec 100644 --- a/src/add-ons/disk_systems/bfs/BFSAddOn.h +++ b/src/add-ons/disk_systems/bfs/BFSAddOn.h @@ -8,6 +8,9 @@ #include <DiskSystemAddOn.h> +struct fs_info; + + class BFSAddOn : public BDiskSystemAddOn { public: BFSAddOn(); @@ -42,6 +45,12 @@ public: virtual uint32 SupportedOperations(uint32 mask); virtual status_t Repair(bool checkOnly); + + virtual status_t ValidateResize(off_t* size); + virtual status_t Resize(off_t size); + +private: + status_t _FitSize(off_t* size); }; ############################################################################ Commit: 81840c641c25b3a4404000d7256692795b897c7f Author: ahenriksson <sausageboy@xxxxxxxxx> Date: Wed Jul 25 12:46:42 2012 UTC Resize support in the intel partitioning disk system add-on ---------------------------------------------------------------------------- diff --git a/src/add-ons/disk_systems/intel/PartitionMapAddOn.cpp b/src/add-ons/disk_systems/intel/PartitionMapAddOn.cpp index 4dc6b2a..c4c27e5 100644 --- a/src/add-ons/disk_systems/intel/PartitionMapAddOn.cpp +++ b/src/add-ons/disk_systems/intel/PartitionMapAddOn.cpp @@ -531,3 +531,63 @@ PartitionMapHandle::DeleteChild(BMutablePartition* child) return error; } + + +status_t +PartitionMapHandle::ValidateResizeChild(const BMutablePartition* child, + off_t* size) +{ + _FitSizeToSpace(child, size); + return B_OK; +} + + +status_t +PartitionMapHandle::ResizeChild(BMutablePartition* child, off_t size) +{ + // is the new size valid? + off_t fittedSize = size; + _FitSizeToSpace(child, &fittedSize); + + if (fittedSize != size) + return B_BAD_VALUE; + + if (child->ContentSize() > size) + return B_BAD_VALUE; + + // update data structures + ::Partition* resizingPartition = fPartitionMap.PartitionAt(child->Index()); + + resizingPartition->SetSize(size); + child->SetSize(size); + + return B_OK; +} + + +void +PartitionMapHandle::_FitSizeToSpace(const BMutablePartition* child, off_t* size) +{ + int32 index = child->Index(); + const ::Partition* resizingPartition = fPartitionMap.PartitionAt(index); + + off_t newEndOffset = resizingPartition->Offset() + *size; + + // check if any other partition overlaps the resized partition + int32 partitionCount = fPartitionMap.CountPartitions(); + + for (int32 i = 0; i < partitionCount; i++) { + if (i == index) + continue; + + const ::Partition* otherPartition = fPartitionMap.PartitionAt(i); + + if (resizingPartition->Offset() <= otherPartition->Offset() + && otherPartition->Offset() < newEndOffset) { + // update size so the resizing partition fills the + // availible space + *size = otherPartition->Offset() - resizingPartition->Offset(); + newEndOffset = resizingPartition->Offset() + *size; + } + } +} diff --git a/src/add-ons/disk_systems/intel/PartitionMapAddOn.h b/src/add-ons/disk_systems/intel/PartitionMapAddOn.h index ecd3ea2..78ae21c 100644 --- a/src/add-ons/disk_systems/intel/PartitionMapAddOn.h +++ b/src/add-ons/disk_systems/intel/PartitionMapAddOn.h @@ -64,6 +64,16 @@ public: BMutablePartition** child); virtual status_t DeleteChild(BMutablePartition* child); + virtual status_t ValidateResizeChild( + const BMutablePartition* child, + off_t* size); + virtual status_t ResizeChild(BMutablePartition* child, + off_t size); + +private: + void _FitSizeToSpace(const BMutablePartition* child, + off_t* size); + private: PartitionMap fPartitionMap; }; ############################################################################ Commit: 21578deb73c80c8f08f9c97a142aa4116a8408e3 Author: ahenriksson <sausageboy@xxxxxxxxx> Date: Tue Jul 31 10:24:42 2012 UTC Add resizefs utility ---------------------------------------------------------------------------- diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index ffc8d7e..a9f244b 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -52,8 +52,8 @@ SYSTEM_BIN = "[" addattr alert arp base64 basename bash bc beep bfsinfo passwd paste patch pathchk pc ping ping6 play playfile playsound playwav pr prio printenv printf profile ps ptx pwd query quit - rc readlink ReadOnlyBootPrompt reindex release renice rlog rm rmattr - rmindex rmdir roster route + rc readlink ReadOnlyBootPrompt reindex release renice resizefs rlog rm + rmattr rmindex rmdir roster route safemode screen_blanker screenmode screenshot sdiff setdecor setmime settype setversion setvolume seq sha1sum shar shred shuf shutdown sleep sort spamdbm diff --git a/src/bin/Jamfile b/src/bin/Jamfile index 2a59586..1c30369 100644 --- a/src/bin/Jamfile +++ b/src/bin/Jamfile @@ -100,6 +100,7 @@ StdBinCommands play.cpp query.cpp quit.cpp + resizefs.cpp roster.cpp setversion.cpp trash.cpp diff --git a/src/bin/resizefs.cpp b/src/bin/resizefs.cpp new file mode 100644 index 0000000..b66a3c9 --- /dev/null +++ b/src/bin/resizefs.cpp @@ -0,0 +1,132 @@ +/* + * Copyright 2012, Andreas Henriksson, sausageboy@xxxxxxxxxx + * Copyright 2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx + * Distributed under the terms of the MIT License. + */ + + +#include <stdio.h> + +#include <DiskDevice.h> +#include <DiskDeviceRoster.h> +#include <DiskSystem.h> + + +extern "C" const char* __progname; +static const char* kProgramName = __progname; + + +int +main(int argc, char** argv) +{ + if (argc != 3) { + fprintf(stderr, "Usage: %s <device> <size>\n", kProgramName); + return 1; + } + + int64 size; + if (sscanf(argv[2], "%" B_SCNd64, &size) < 1) { + fprintf(stderr, "%s: The new size \"%s\" is not a number\n", + kProgramName, argv[2]); + return 1; + } + + BDiskDeviceRoster roster; + BPartition* partition; + BDiskDevice device; + + status_t status = roster.GetPartitionForPath(argv[1], &device, + &partition); + if (status != B_OK) { + if (strncmp(argv[1], "/dev", 4)) { + // try mounted volume + status = roster.FindPartitionByMountPoint(argv[1], &device, + &partition) ? B_OK : B_BAD_VALUE; + } + + // TODO: try to register file device + + if (status != B_OK) { + fprintf(stderr, "%s: Failed to get disk device for path \"%s\": " + "%s\n", kProgramName, argv[1], strerror(status)); + return 1; + } + } + + // Prepare the device for modifications + + status = device.PrepareModifications(); + if (status != B_OK) { + fprintf(stderr, "%s: Could not prepare the device for modifications: " + "%s\n", kProgramName, strerror(status)); + return false; + } + + // Check if the partition supports resizing + + bool canResizeWhileMounted; + bool canResize = partition->CanResize(NULL, &canResizeWhileMounted); + + if (!canResize && !canResizeWhileMounted) { + fprintf(stderr, "%s: The disk system does not support resizing.\n", + kProgramName); + return 1; + } + + if (partition->IsMounted() && !canResizeWhileMounted) { + fprintf(stderr, "%s: The disk system does not support resizing a " + "mounted volume.\n", kProgramName); + return 1; + } + if (!partition->IsMounted() && !canResize) { + fprintf(stderr, "%s: The disk system does not support resizing a " + "volume that is not mounted.\n", kProgramName); + return 1; + } + + BDiskSystem diskSystem; + status = partition->GetDiskSystem(&diskSystem); + if (status != B_OK) { + fprintf(stderr, "%s: Failed to get disk system for partition: %s\n", + kProgramName, strerror(status)); + return 1; + } + + // Validate the requested size + + off_t validatedSize = size; + status = partition->ValidateResize(&validatedSize); + if (status != B_OK) { + fprintf(stderr, "%s: Failed to validate the size: %s\n", kProgramName, + strerror(status)); + return 1; + } + + if (validatedSize != size) { + printf("The requested size (%" B_PRId64 " bytes) was not accepted.\n" + "Resize to %" B_PRId64 " bytes instead? (y/N): ", size, + (int64)validatedSize); + + int c = getchar(); + if (c != 'y') + return 0; + } + + // Resize the volume + + status = partition->Resize(validatedSize); + if (status != B_OK) { + fprintf(stderr, "%s: Resizing failed: %s\n", kProgramName, + strerror(status)); + return 1; + } + + status = device.CommitModifications(); + if (status != B_OK) { + fprintf(stderr, "%s: Failed to commit modifications: %s\n", + kProgramName, strerror(status)); + return 1; + } + + return 0; +} ############################################################################ Commit: 0e8f38ab332a8d0d43e9c03a07c076b9a8c3f759 Author: ahenriksson <sausageboy@xxxxxxxxx> Date: Mon Jul 23 17:51:26 2012 UTC Add a resizing back door for use with bfs_shell The resizefs command in bfs_shell is changed to use this interface. ---------------------------------------------------------------------------- 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 d5b859e..95c5fe2 100644 --- a/src/add-ons/kernel/file_systems/bfs/bfs_control.h +++ b/src/add-ons/kernel/file_systems/bfs/bfs_control.h @@ -99,4 +99,10 @@ struct check_control { #define BFS_IOCTL_CHECK_MAGIC 'BChk' +/* A "back door" to side-step the regular resize interface, primarily for + * testing with bfs_shell. The parameter is a uint64 with the desired size. + */ +#define BFS_IOCTL_RESIZE 14205 + + #endif /* BFS_CONTROL_H */ diff --git a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp index 24f43c9..a191757 100644 --- a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp @@ -720,6 +720,18 @@ bfs_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd, return volume->WriteSuperBlock(); } + case BFS_IOCTL_RESIZE: + { + if (bufferLength != sizeof(uint64)) + return B_BAD_VALUE; + + uint64 size; + if (user_memcpy((uint8*)&size, buffer, sizeof(uint64)) != B_OK) + return B_BAD_ADDRESS; + + ResizeVisitor resizer(volume); + return resizer.Resize(size, -1); + } #ifdef DEBUG_FRAGMENTER case 56741: diff --git a/src/tools/bfs_shell/command_resizefs.cpp b/src/tools/bfs_shell/command_resizefs.cpp index 22e7906..e2cfe28 100644 --- a/src/tools/bfs_shell/command_resizefs.cpp +++ b/src/tools/bfs_shell/command_resizefs.cpp @@ -14,42 +14,17 @@ namespace FSShell { -void Usage(const char* name); - -void PrintInformation(const resize_control& result); -void PrintError(const resize_control& result); -void PrintStats(const resize_control& result); -const char* FailureToString(uint32 failurePoint); - - fssh_status_t command_resizefs(int argc, const char* const* argv) { - // get command line options - bool hasNewSize = false; - uint64 newSize = 0; - - bool check = false; - - for (int i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--check")) - check = true; - else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { - Usage(argv[0]); - return B_OK; - } else { - if (fssh_sscanf(argv[i], "%" B_SCNu64, &newSize) < 1) { - fssh_dprintf("Unknown argument or invalid size\n\n"); - Usage(argv[0]); - return B_ERROR; - } - hasNewSize = true; - } + if (argc != 2) { + fssh_dprintf("Usage: %s <new size>\n", argv[0]); + return B_ERROR; } - - if (!hasNewSize) { - fssh_dprintf("No size specified\n\n"); - Usage(argv[0]); + + uint64 newSize; + if (fssh_sscanf(argv[1], "%" B_SCNu64, &newSize) < 1) { + fssh_dprintf("Unknown argument or invalid size\n"); return B_ERROR; } @@ -59,161 +34,18 @@ command_resizefs(int argc, const char* const* argv) return rootDir; } - struct resize_control result; - memset(&result, 0, sizeof(result)); - result.magic = BFS_IOCTL_RESIZE_MAGIC; - - if (check) - result.flags |= BFS_CHECK_RESIZE; - - result.new_size = newSize; - - // start resizing - fssh_status_t status = _kern_ioctl(rootDir, BFS_IOCTL_START_RESIZE, - &result, sizeof(result)); - - if (status != B_OK) { - fssh_dprintf("Error: Couldn't perform 'start' ioctl\n"); - return status; - } - - PrintInformation(result); - if (result.status != B_OK) { - PrintError(result); - _kern_close(rootDir); - return result.status; - } - - if (check) { - _kern_close(rootDir); - fssh_dprintf("Resizing appears to be possible.\n"); - return B_OK; - } - - bool resizeFailed = false; - uint64 counter = 0; - - // move all files out of the way - while (true) { - status = _kern_ioctl(rootDir, BFS_IOCTL_MOVE_NEXT_NODE, &result, - sizeof(result)); - if (status == B_ENTRY_NOT_FOUND) - break; - - if (++counter % 50 == 0) - fssh_dprintf("%9Ld nodes processed\x1b[1A\n", counter); - - // we couldn't return the resizefs_control struct - if (status != B_OK) { - fssh_dprintf("Error: Couldn't perform 'next' ioctl\n"); - break; - } - - if (result.status != B_OK) { - PrintError(result); - resizeFailed = true; - break; - } - } - - // finish the resize - if (_kern_ioctl(rootDir, BFS_IOCTL_FINISH_RESIZE, &result, sizeof(result)) - != B_OK) { - _kern_close(rootDir); - fssh_dprintf("Error: Couldn't perform 'finish' ioctl\n"); - return errno; - } + status_t status = _kern_ioctl(rootDir, BFS_IOCTL_RESIZE, + &newSize, sizeof(newSize)); _kern_close(rootDir); - if (result.status != B_OK) { - PrintError(result); - resizeFailed = true; - } - - PrintStats(result); - - if (resizeFailed) - fssh_dprintf("Failed to resize file system.\n"); - else - fssh_dprintf("File system successfully resized!\n"); - - return result.status; -} - - -void -Usage(const char* name) -{ - fssh_dprintf("Usage: %s <new size> [options]\n" - "\t-c, --check Don't resize, just check if it would be possible\n" - "\t-h, --help Print this message\n", name); -} - - -void -PrintInformation(const resize_control& result) -{ - fssh_dprintf("New file system information:\n"); - fssh_dprintf("\tBitmap: %" B_PRIu16 " blocks (was %" B_PRIu16 ")\n", - result.stats.bitmap_blocks_new, result.stats.bitmap_blocks_old); - fssh_dprintf("\tLog start: block %" B_PRIu16 " (was %" B_PRIu16 ")\n", - result.stats.log_start_new, result.stats.log_start_old); - fssh_dprintf("\tLog length: %" B_PRIu16 " blocks (was %" B_PRIu16 ")\n", - result.stats.log_length_new, result.stats.log_length_old); - fssh_dprintf("\tBlock size: %" B_PRIu16 " bytes\n\n", - result.stats.block_size); -} - - -void -PrintError(const resize_control& result) -{ - fssh_dprintf("Error: %s.\n", FailureToString(result.failure_point)); - fssh_dprintf("Status: %s\n", fssh_strerror(result.status)); - - if ((result.failure_point == BFS_MOVE_INODE_FAILED) - || (result.failure_point == BFS_MOVE_STREAM_FAILED)) { - fssh_dprintf("\tIn inode %" B_PRIdINO ", \"%s\"\n", result.inode, - result.name); + if (status != B_OK) { + fssh_dprintf("Resizing failed, status: %s\n", fssh_strerror(status)); + return status; } - fssh_dprintf("\n"); -} - - -void -PrintStats(const resize_control& result) -{ - fssh_dprintf(" Inodes moved: %" B_PRIu64 "\n", - result.stats.inodes_moved); - fssh_dprintf("\tData streams moved: %" B_PRIu64 "\n\n", - result.stats.streams_moved); -} - - -const char* -FailureToString(uint32 failurePoint) -{ - switch (failurePoint) { - case BFS_OTHER_ERROR: - return "Other error"; - case BFS_SIZE_TOO_LARGE: - return "Can't grow disk this much"; - case BFS_DISK_TOO_SMALL: - return "Not enough room on device to grow file system"; - case BFS_NO_SPACE: - return "Not enough space left"; - case BFS_MOVE_LOG_FAILED: - return "Failed to move the file system log"; - case BFS_MOVE_INODE_FAILED: - return "Failed to move inode"; - case BFS_MOVE_STREAM_FAILED: - return "Failed to move file data"; - case BFS_CHANGE_SIZE_FAILED: - return "Failed to update file system size"; - } - return "(Can't get type of failure)"; + fssh_dprintf("File system successfully resized!\n"); + return B_OK; }