[haiku-commits] BRANCH ahenriksson-github.production - src/add-ons/kernel/file_systems/bfs

  • From: ahenriksson-github.production <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 6 Aug 2012 22:49:28 +0200 (CEST)

added 11 changesets to branch 'refs/remotes/ahenriksson-github/production'
old head: 0e8f38ab332a8d0d43e9c03a07c076b9a8c3f759
new head: 5cbffd392ebc19ddcecc1ccc64fe20a1c36e370f

----------------------------------------------------------------------------

e125c56: Write the finished transaction to disk before writing super block

7348e62: Lock attribute directory when we move an attribute

e0121e2: Change vnode ID in associated VMVnodeCache

ee4521c: No need to get the DiskSystem in resizefs

9322b1e: Add a function for allocating a specific block run
  
  Intended for use by Journal::MoveLog().

95b0703: Use AllocateBlockRun in MoveLog

8ac30e3: Allowed allocation range is part of the block allocator's state
  
  This is necessary to successfully resize file systems while data is
  copied to them.

a938a37: Add mapping from vnode ID to block number for moved inodes

45fefb3: Don't check device size when resizing
  
  It's not our responsibility. This reverts "Calculate device size in
  Volume for use by resize code", and removes the check in ResizeVisitor.

e8d0bc3: Added code to update the block cache size

5cbffd3: Fix deadlock when reinitializing block allocator

                                      [ ahenriksson <sausageboy@xxxxxxxxx> ]

----------------------------------------------------------------------------

15 files changed, 416 insertions(+), 180 deletions(-)
.../kernel/file_systems/bfs/BlockAllocator.cpp     |  168 +++++++++++++---
.../kernel/file_systems/bfs/BlockAllocator.h       |   15 +-
src/add-ons/kernel/file_systems/bfs/Inode.cpp      |   81 +++-----
src/add-ons/kernel/file_systems/bfs/Inode.h        |   18 +-
src/add-ons/kernel/file_systems/bfs/Journal.cpp    |   50 +++--
src/add-ons/kernel/file_systems/bfs/Journal.h      |    4 +-
.../kernel/file_systems/bfs/ResizeVisitor.cpp      |   49 +++--
.../kernel/file_systems/bfs/ResizeVisitor.h        |    1 +
src/add-ons/kernel/file_systems/bfs/Volume.cpp     |  159 ++++++++++++---
src/add-ons/kernel/file_systems/bfs/Volume.h       |   26 ++-
.../kernel/file_systems/bfs/kernel_interface.cpp   |   10 +-
.../kernel/file_systems/bfs/system_dependencies.h  |    1 +
src/bin/resizefs.cpp                               |    8 -
src/system/kernel/cache/vnode_store.h              |    3 +
src/system/kernel/fs/vfs.cpp                       |    3 +

############################################################################

Commit:      e125c56e31ac5c5168178777970a84a0faa56e8d

Author:      ahenriksson <sausageboy@xxxxxxxxx>
Date:        Wed Aug  1 13:31:00 2012 UTC

Write the finished transaction to disk before writing super block

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp 
b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
index 481615ed..35255d7 100644
--- a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
@@ -551,6 +551,15 @@ ResizeVisitor::_UpdateChildren(Transaction& transaction, 
Inode* inode,
 status_t
 ResizeVisitor::_UpdateSuperBlock(Inode* inode, off_t newInodeID)
 {
+       // we need to have our transaction written to disk before we can write
+       // the updated super block, otherwise we might end up with a dangling
+       // reference if something fails later on.
+       status_t status = GetVolume()->GetJournal(0)->FlushLogAndBlocks();
+       if (status != B_OK) {
+               FATAL(("Resize: Failed to flush log before updating super 
block!\n"));
+               return status;
+       }
+
        MutexLocker locker(GetVolume()->Lock());
        disk_super_block& superBlock = GetVolume()->SuperBlock();
        

############################################################################

Commit:      7348e621a1ae5b14f775d223e14dc517757d07c3

Author:      ahenriksson <sausageboy@xxxxxxxxx>
Date:        Wed Aug  1 13:33:26 2012 UTC

Lock attribute directory when we move an attribute

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp 
b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
index 35255d7..b7fa110 100644
--- a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
@@ -385,6 +385,8 @@ ResizeVisitor::_UpdateAttributeDirectory(Transaction& 
transaction, Inode* inode,
        if (status != B_OK)
                return status;
 
+       attributeDirectory->WriteLockInTransaction(transaction);
+
        attributeDirectory->Parent() = newInodeRun;
        return attributeDirectory->WriteBack(transaction);
 }

############################################################################

Commit:      e0121e2886391528a2363a2d2d18d492fe815926

Author:      ahenriksson <sausageboy@xxxxxxxxx>
Date:        Thu Aug  2 17:02:22 2012 UTC

Change vnode ID in associated VMVnodeCache

----------------------------------------------------------------------------

diff --git a/src/system/kernel/cache/vnode_store.h 
b/src/system/kernel/cache/vnode_store.h
index 3479976..b50417c 100644
--- a/src/system/kernel/cache/vnode_store.h
+++ b/src/system/kernel/cache/vnode_store.h
@@ -48,6 +48,9 @@ public:
 
                        void                            VnodeDeleted()  { 
fVnodeDeleted = true; }
 
+                       void                            SetVnodeID(ino_t id)
+                                                                       { 
fInode = id; }
+
 protected:
        virtual void                            DeleteObject();
 
diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp
index 5b2772c..3a6295c 100644
--- a/src/system/kernel/fs/vfs.cpp
+++ b/src/system/kernel/fs/vfs.cpp
@@ -3902,6 +3902,9 @@ change_vnode_id(fs_volume* volume, ino_t vnodeID, ino_t 
newID)
        vnode->id = newID;
        hash_insert(sVnodeTable, vnode);
 
+       if (vnode->cache)
+               ((VMVnodeCache*)vnode->cache)->SetVnodeID(newID);
+
        return B_OK;
 }
 

############################################################################

Commit:      ee4521c5b4b4a2040e06675ce599605711daf2e4

Author:      ahenriksson <sausageboy@xxxxxxxxx>
Date:        Thu Aug  2 17:04:51 2012 UTC

No need to get the DiskSystem in resizefs

----------------------------------------------------------------------------

diff --git a/src/bin/resizefs.cpp b/src/bin/resizefs.cpp
index b66a3c9..32f3bc6 100644
--- a/src/bin/resizefs.cpp
+++ b/src/bin/resizefs.cpp
@@ -84,14 +84,6 @@ main(int argc, char** argv)
                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;

############################################################################

Commit:      9322b1ea3095a7fa42321de9fed2a0d9e51463ac

Author:      ahenriksson <sausageboy@xxxxxxxxx>
Date:        Mon Aug  6 20:20:22 2012 UTC

Add a function for allocating a specific block run

Intended for use by Journal::MoveLog().

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp 
b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
index cf935d1..30f52d6 100644
--- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
@@ -1066,6 +1066,46 @@ BlockAllocator::Allocate(Transaction& transaction, 
Inode* inode,
 }
 
 
+/*!    Attempts to allocate a specific block run. 
+*/
+status_t
+BlockAllocator::AllocateBlockRun(Transaction& transaction, block_run run)
+{
+       RecursiveLocker lock(fLock);
+
+       if (run.AllocationGroup() >= fNumGroups)
+               return B_BAD_VALUE;
+
+       if (!IsBlockRunInRange(run))
+               return B_DEVICE_FULL;
+
+       uint32 bitsPerBlock = fVolume->BlockSize() << 3;
+
+       AllocationGroup& group = fGroups[run.AllocationGroup()];
+       AllocationBlock cached(fVolume);
+
+       int32 end = run.Start() + run.Length();
+
+       // check that the requested blocks are free
+       for (int32 block = run.Start(); block < end; block++) {
+               if (cached.SetTo(group, block / bitsPerBlock) < B_OK)
+                       RETURN_ERROR(B_ERROR);
+
+               if (cached.IsUsed(block % bitsPerBlock))
+                       return B_DEVICE_FULL;
+       }
+
+       status_t status = group.Allocate(transaction, run.Start(), 
run.Length());
+       if (status != B_OK)
+               return status;
+
+       fVolume->SuperBlock().used_blocks
+               = HOST_ENDIAN_TO_BFS_INT64(fVolume->UsedBlocks() + 
run.Length());
+
+       return B_OK;
+}
+
+
 status_t
 BlockAllocator::Free(Transaction& transaction, block_run run)
 {
diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h 
b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h
index cd494d2..4be864c 100644
--- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h
+++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h
@@ -47,6 +47,9 @@ public:
                                                                uint16 minimum, 
block_run& run,
                                                                off_t 
beginBlock = 0, off_t endBlock = 0);
 
+                       status_t                AllocateBlockRun(Transaction& 
transaction,
+                                                               block_run run);
+
                        status_t                CheckBlocks(off_t start, off_t 
length,
                                                                bool allocated 
= true,
                                                                off_t* 
firstError = NULL);

############################################################################

Commit:      95b070339397f1c6090d28b24a4fb2cefc227d6e

Author:      ahenriksson <sausageboy@xxxxxxxxx>
Date:        Mon Aug  6 20:26:30 2012 UTC

Use AllocateBlockRun in MoveLog

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/bfs/Journal.cpp 
b/src/add-ons/kernel/file_systems/bfs/Journal.cpp
index 00ec40a..b89f45a 100644
--- a/src/add-ons/kernel/file_systems/bfs/Journal.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/Journal.cpp
@@ -1110,17 +1110,11 @@ Journal::MoveLog(block_run newLog)
 
                Transaction transaction(fVolume, 0);
 
-               status = allocator.AllocateBlocks(transaction, 0, oldEnd,
-                       allocationSize, 1, allocatedRun, oldEnd, newEnd);
-               if (status != B_OK)
+               status = allocator.AllocateBlockRun(transaction,
+                               block_run::Run(0, oldEnd, allocationSize));
+               if (status != B_OK) {
+                       FATAL(("MoveLog: Could not allocate space to move log 
area!\n"));
                        return status;
-
-               if (allocatedRun.AllocationGroup() != 0
-                       || allocatedRun.Start() != oldEnd
-                       || allocatedRun.Length() != allocationSize) {
-                       // we couldn't allocate what we wanted, this means that 
we
-                       // failed to move all data from this area
-                       return B_ERROR;
                }
 
                status = transaction.Done();

############################################################################

Commit:      8ac30e396c70e4b316f36111c3da10fcd579af0e

Author:      ahenriksson <sausageboy@xxxxxxxxx>
Date:        Mon Aug  6 20:26:52 2012 UTC

Allowed allocation range is part of the block allocator's state

This is necessary to successfully resize file systems while data is
copied to them.

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp 
b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
index 30f52d6..2c93c2d 100644
--- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
@@ -505,7 +505,9 @@ AllocationGroup::Free(Transaction& transaction, uint16 
start, int32 length)
 BlockAllocator::BlockAllocator(Volume* volume)
        :
        fVolume(volume),
-       fGroups(NULL)
+       fGroups(NULL),
+       fBeginBlock(0),
+       fEndBlock(0)
 {
        recursive_lock_init(&fLock, "bfs allocator");
 }
@@ -734,26 +736,61 @@ BlockAllocator::Uninitialize()
 }
 
 
-/*!    Tries to allocate between \a minimum, and \a maximum blocks in the range
-       from \a beginBlock up to but not including \a endBlock, starting at 
group
-       \a groupIndex with offset \a start. The resulting allocation is put into
-       \a run.
+/*! Specifies the range in which blocks will be allocated, starting from
+       \a beginBlock, up to but not including \a endBlock.
 
-       An \a endBlock value of 0 means no upper limit on the allowed allocation
-       range.
+       \a beginBlock and \a endBlock values of 0 means that no limits on the
+       allowed allocation range are imposed.
+*/
+void
+BlockAllocator::SetRange(off_t beginBlock, off_t endBlock)
+{
+       RecursiveLocker lock(fLock);
+
+       fBeginBlock = beginBlock;
+       fEndBlock = endBlock;
+}
+
+
+bool
+BlockAllocator::IsBlockRunInRange(block_run run) const
+{
+       if (fBeginBlock == 0 && fEndBlock == 0)
+               return true;
+
+       off_t runStart = fVolume->ToBlock(run);
+       return runStart >= fBeginBlock && runStart + run.Length() <= fEndBlock;
+}
+
+
+bool
+BlockAllocator::IsBlockRunOutsideRange(block_run run) const
+{
+       if (fBeginBlock == 0 && fEndBlock == 0)
+               return false;
+
+       // note that this is not the opposite of _IsBlockRunInRange, as we only
+       // return true if the block run is completely outside the range.
+       off_t runStart = fVolume->ToBlock(run);
+       return runStart + run.Length() <= fBeginBlock || runStart >= fEndBlock;
+}
+
+
+/*!    Tries to allocate between \a minimum, and \a maximum blocks, starting at
+       group \a groupIndex with offset \a start. The resulting allocation is 
put
+       into \a run.
 
        The number of allocated blocks is always a multiple of \a minimum which
        has to be a power of two value.
 */
 status_t
 BlockAllocator::AllocateBlocks(Transaction& transaction, int32 groupIndex,
-       uint16 start, uint16 maximum, uint16 minimum, block_run& run,
-       off_t beginBlock, off_t endBlock)
+       uint16 start, uint16 maximum, uint16 minimum, block_run& run)
 {
        if (maximum == 0)
                return B_BAD_VALUE;
 
-       if (endBlock > fVolume->NumBlocks())
+       if (fEndBlock > fVolume->NumBlocks())
                return B_BAD_VALUE;
 
        FUNCTION_START(("group = %ld, start = %u, maximum = %u, minimum = %u\n",
@@ -766,21 +803,21 @@ BlockAllocator::AllocateBlocks(Transaction& transaction, 
int32 groupIndex,
 
        // Express the allowed allocation range in terms of allocation groups 
and
        // offsets.
-       int32 firstAllowedGroup = beginBlock / bitsPerFullBlock;
-       uint16 firstGroupBegin = beginBlock % bitsPerFullBlock;
+       int32 firstAllowedGroup = fBeginBlock / bitsPerFullBlock;
+       uint16 firstGroupBegin = fBeginBlock % bitsPerFullBlock;
 
        int32 lastAllowedGroup;
        int32 lastGroupEnd;
 
-       if (endBlock == 0) {
+       if (fEndBlock == 0) {
                lastAllowedGroup = fNumGroups - 1;
                lastGroupEnd = fGroups[lastAllowedGroup].NumBits();
        } else {
-               // If endBlock is the first block of an allocation group, the 
last
+               // If fEndBlock is the first block of an allocation group, the 
last
                // allowed group is the previous, and the end block offset is
                // bitsPerFullBlock.
-               lastAllowedGroup = (endBlock - 1) / bitsPerFullBlock;
-               lastGroupEnd = endBlock % bitsPerFullBlock;
+               lastAllowedGroup = (fEndBlock - 1) / bitsPerFullBlock;
+               lastGroupEnd = fEndBlock % bitsPerFullBlock;
                if (lastGroupEnd == 0)
                        lastGroupEnd = bitsPerFullBlock;
        }
@@ -965,8 +1002,8 @@ BlockAllocator::AllocateBlocks(Transaction& transaction, 
int32 groupIndex,
        run.start = HOST_ENDIAN_TO_BFS_INT16(bestStart);
        run.length = HOST_ENDIAN_TO_BFS_INT16(bestLength);
 
-       ASSERT(fVolume->ToBlock(run) >= beginBlock);
-       ASSERT(endBlock == 0 || fVolume->ToBlock(run) + run.Length() <= 
endBlock);
+       ASSERT(fVolume->ToBlock(run) >= fBeginBlock);
+       ASSERT(fEndBlock == 0 || fVolume->ToBlock(run) + run.Length() <= 
fEndBlock);
 
        fVolume->SuperBlock().used_blocks
                = HOST_ENDIAN_TO_BFS_INT64(fVolume->UsedBlocks() + bestLength);
@@ -1007,8 +1044,7 @@ BlockAllocator::AllocateForInode(Transaction& transaction,
 
 status_t
 BlockAllocator::Allocate(Transaction& transaction, Inode* inode,
-       off_t numBlocks, block_run& run, uint16 minimum, off_t beginBlock,
-       off_t endBlock)
+       off_t numBlocks, block_run& run, uint16 minimum)
 {
        if (numBlocks <= 0)
                return B_ERROR;
@@ -1061,12 +1097,12 @@ BlockAllocator::Allocate(Transaction& transaction, 
Inode* inode,
                group = inode->BlockRun().AllocationGroup() + 1;
        }
 
-       return AllocateBlocks(transaction, group, start, numBlocks, minimum, 
run,
-               beginBlock, endBlock);
+       return AllocateBlocks(transaction, group, start, numBlocks, minimum, 
run);
 }
 
 
-/*!    Attempts to allocate a specific block run. 
+/*!    Attempts to allocate a specific block run.
+       Does not check if the block run is within the current allocation range.
 */
 status_t
 BlockAllocator::AllocateBlockRun(Transaction& transaction, block_run run)
@@ -1076,9 +1112,6 @@ BlockAllocator::AllocateBlockRun(Transaction& 
transaction, block_run run)
        if (run.AllocationGroup() >= fNumGroups)
                return B_BAD_VALUE;
 
-       if (!IsBlockRunInRange(run))
-               return B_DEVICE_FULL;
-
        uint32 bitsPerBlock = fVolume->BlockSize() << 3;
 
        AllocationGroup& group = fGroups[run.AllocationGroup()];
diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h 
b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h
index 4be864c..3de7212 100644
--- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h
+++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h
@@ -33,19 +33,21 @@ public:
 
                        void                    Uninitialize();
 
+                       void                    SetRange(off_t beginBlock, 
off_t endBlock);
+                       bool                    IsBlockRunInRange(block_run 
run) const;
+                       bool                    
IsBlockRunOutsideRange(block_run run) const;
+
                        status_t                AllocateForInode(Transaction& 
transaction,
                                                                const 
block_run* parent, mode_t type,
                                                                block_run& run);
                        status_t                Allocate(Transaction& 
transaction, Inode* inode,
                                                                off_t 
numBlocks, block_run& run,
-                                                               uint16 minimum 
= 1, off_t beginBlock = 0,
-                                                               off_t endBlock 
= 0);
+                                                               uint16 minimum 
= 1);
                        status_t                Free(Transaction& transaction, 
block_run run);
 
                        status_t                AllocateBlocks(Transaction& 
transaction,
                                                                int32 group, 
uint16 start, uint16 numBlocks,
-                                                               uint16 minimum, 
block_run& run,
-                                                               off_t 
beginBlock = 0, off_t endBlock = 0);
+                                                               uint16 minimum, 
block_run& run);
 
                        status_t                AllocateBlockRun(Transaction& 
transaction,
                                                                block_run run);
@@ -80,6 +82,9 @@ private:
                        int32                   fNumGroups;
                        uint32                  fBlocksPerGroup;
                        uint32                  fNumBlocks;
+
+                       off_t                   fBeginBlock;
+                       off_t                   fEndBlock;
 };
 
 #ifdef BFS_DEBUGGER_COMMANDS
diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.cpp 
b/src/add-ons/kernel/file_systems/bfs/Inode.cpp
index 167821d..64b2a2a 100644
--- a/src/add-ons/kernel/file_systems/bfs/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/Inode.cpp
@@ -1833,13 +1833,13 @@ Inode::FillGapWithZeros(off_t pos, off_t newSize)
 */
 status_t
 Inode::_AllocateBlockArray(Transaction& transaction, block_run& run,
-       size_t length, bool variableSize, off_t beginBlock, off_t endBlock)
+       size_t length, bool variableSize)
 {
        if (!run.IsZero())
                return B_BAD_VALUE;
 
        status_t status = fVolume->Allocate(transaction, this, length, run,
-               variableSize ? 1 : length, beginBlock, endBlock);
+               variableSize ? 1 : length);
        if (status != B_OK)
                return status;
 
@@ -1867,8 +1867,7 @@ Inode::_AllocateBlockArray(Transaction& transaction, 
block_run& run,
 */
 status_t
 Inode::_AddBlockRun(Transaction& transaction, data_stream* dataStream,
-       block_run run, off_t targetSize, int32* rest, off_t beginBlock,
-       off_t endBlock)
+       block_run run, off_t targetSize, int32* rest)
 {
        status_t status;
 
@@ -1920,7 +1919,7 @@ Inode::_AddBlockRun(Transaction& transaction, 
data_stream* dataStream,
                // if there is no indirect block yet, create one
                if (dataStream->indirect.IsZero()) {
                        status = _AllocateBlockArray(transaction, 
dataStream->indirect,
-                               NUM_ARRAY_BLOCKS, true, beginBlock, endBlock);
+                               NUM_ARRAY_BLOCKS, true);
                        if (status != B_OK)
                                return status;
 
@@ -2001,7 +2000,7 @@ Inode::_AddBlockRun(Transaction& transaction, 
data_stream* dataStream,
                if (dataStream->double_indirect.IsZero()) {
                        status = _AllocateBlockArray(transaction,
                                dataStream->double_indirect, 
_DoubleIndirectBlockLength(),
-                               false, beginBlock, endBlock);
+                               false);
                        if (status != B_OK)
                                return status;
 
@@ -2051,8 +2050,7 @@ Inode::_AddBlockRun(Transaction& transaction, 
data_stream* dataStream,
 
                                        status = 
_AllocateBlockArray(transaction,
                                                array[indirectIndex % 
runsPerBlock],
-                                               
dataStream->double_indirect.Length(), false,
-                                               beginBlock, endBlock);
+                                               
dataStream->double_indirect.Length(), false);
                                        if (status != B_OK)
                                                return status;
                                }
@@ -2669,8 +2667,7 @@ Inode::Sync()
 */
 status_t
 Inode::_WriteBufferedRuns(Transaction& transaction, BlockRunBuffer& buffer,
-       data_stream* dataStream, off_t targetSize, bool flush, off_t beginBlock,
-       off_t endBlock)
+       data_stream* dataStream, off_t targetSize, bool flush)
 {
        status_t status;
        off_t doubleIndirectBlockLength = _DoubleIndirectBlockLength();
@@ -2696,8 +2693,7 @@ Inode::_WriteBufferedRuns(Transaction& transaction, 
BlockRunBuffer& buffer,
                        }
 
                        status = 
fVolume->Allocator().AllocateBlocks(transaction, 0, 0,
-                                       buffer.NumBlocks(), 
doubleIndirectBlockLength, run,
-                                       beginBlock, endBlock);
+                                       buffer.NumBlocks(), 
doubleIndirectBlockLength, run);
                        if (status != B_OK)
                                return status;
 
@@ -2710,7 +2706,7 @@ Inode::_WriteBufferedRuns(Transaction& transaction, 
BlockRunBuffer& buffer,
                                blocksToWrite = run.Length();
                } else {
                        status = 
fVolume->Allocator().AllocateBlocks(transaction, 0, 0,
-                               buffer.NumBlocks(), 1, run, beginBlock, 
endBlock);
+                               buffer.NumBlocks(), 1, run);
                        if (status != B_OK)
                                return status;
 
@@ -2719,8 +2715,7 @@ Inode::_WriteBufferedRuns(Transaction& transaction, 
BlockRunBuffer& buffer,
 
                // add the run to the data stream
                int32 rest;
-               status = _AddBlockRun(transaction, dataStream, run, targetSize,
-                       &rest, beginBlock, endBlock);
+               status = _AddBlockRun(transaction, dataStream, run, targetSize, 
&rest);
                if (status != B_OK)
                        return status;
 
@@ -2831,30 +2826,11 @@ Inode::_GetNextBlockRun(off_t& position, block_run& 
run) const
 }
 
 
-bool
-Inode::_IsBlockRunInRange(block_run run, off_t beginBlock, off_t endBlock) 
const
-{
-       off_t runStart = GetVolume()->ToBlock(run);
-       return runStart >= beginBlock && runStart + run.Length() <= endBlock;
-}
-
-
-bool
-Inode::_IsBlockRunOutsideRange(block_run run, off_t beginBlock, off_t endBlock)
-       const
-{
-       // note that this is not the opposite of _IsBlockRunInRange, as we only
-       // return true if the block run is completely outside the range.
-       off_t runStart = GetVolume()->ToBlock(run);
-       return runStart + run.Length() <= beginBlock || runStart >= endBlock;
-}
-
-
-/*! Move the file stream to lie completely in the range from \a beginBlock
-       up to but not including \a endBlock.
+/*! Move the file stream to lie completely in the allocation range specified
+       in the block allocator.
 */
 status_t
-Inode::MoveStream(off_t beginBlock, off_t endBlock)
+Inode::MoveStream()
 {
        // We move the stream by rebuilding it from scratch. block_runs which
        // can be reused are simply added to the result stream (newStream) as
@@ -2884,6 +2860,8 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock)
        if (status != B_OK)
                return status;
 
+       BlockAllocator& allocator = fVolume->Allocator();
+
        Stack<block_run> runsToFree;
                // no particular reason for using a stack, we just need 
something to
                // store block_run's in
@@ -2902,9 +2880,9 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock)
                if (status != B_OK)
                        return status;
 
-               if (_IsBlockRunInRange(run, beginBlock, endBlock)) {
+               if (allocator.IsBlockRunInRange(run)) {
                        status = _WriteBufferedRuns(transaction, buffer, 
&newStream,
-                               Size(), false, beginBlock, endBlock);
+                               Size(), false);
                        if (status != B_OK)
                                return status;
 
@@ -2914,7 +2892,7 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock)
                        if (buffer.IsEmpty()) {
                                int32 rest;
                                status = _AddBlockRun(transaction, &newStream, 
run, Size(),
-                                       &rest, beginBlock, endBlock);
+                                       &rest);
                                if (status != B_OK)
                                        return status;
 
@@ -2931,13 +2909,13 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock)
                // We can't reuse this block_run, add it to the block_run 
buffer.
                if (buffer.IsFull()) {
                        status = _WriteBufferedRuns(transaction, buffer, 
&newStream,
-                               Size(), false, beginBlock, endBlock);
+                               Size(), false);
                        if (status != B_OK)
                                return status;
                }
                buffer.PutRun(run);
 
-               if (_IsBlockRunOutsideRange(run, beginBlock, endBlock)) {
+               if (allocator.IsBlockRunOutsideRange(run)) {
                        // The block run was outside of the allowed range, 
which means
                        // that we can free it now without running the risk of
                        // reallocating it and overwriting its content.
@@ -2953,8 +2931,7 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock)
        }
 
        // write all blocks remaining in the buffer to disk
-       status = _WriteBufferedRuns(transaction, buffer, &newStream, Size(), 
true,
-               beginBlock, endBlock);
+       status = _WriteBufferedRuns(transaction, buffer, &newStream, Size(), 
true);
        if (status != B_OK)
                return status;
        
@@ -2979,25 +2956,27 @@ Inode::MoveStream(off_t beginBlock, off_t endBlock)
 }
 
 
-/*! Check if the file stream is in the range from \a beginBlock up to
-       but not including \endBlock.
+/*! Check if the file stream is in the allocation range specified in the
+       block allocator.
 */
 status_t
-Inode::StreamInRange(off_t beginBlock, off_t endBlock, bool& inRange) const
+Inode::StreamInRange(bool& inRange) const
 {
        inRange = false;
                // now we can simply return if we find a run which is not in 
the range
+
+       BlockAllocator& allocator = fVolume->Allocator();
        
        // check that the indirection blocks are in the allowed range
        const data_stream* data = &fNode.data;
 
        if (!data->indirect.IsZero()
-               && !_IsBlockRunInRange(data->indirect, beginBlock, endBlock)) {
+               && !allocator.IsBlockRunInRange(data->indirect)) {
                return B_OK;
        }
 
        if (!data->double_indirect.IsZero()) {
-               if (!_IsBlockRunInRange(data->double_indirect, beginBlock, 
endBlock))
+               if (!allocator.IsBlockRunInRange(data->double_indirect))
                        return B_OK;
 
                int32 runsPerBlock = fVolume->BlockSize() / sizeof(block_run);
@@ -3016,7 +2995,7 @@ Inode::StreamInRange(off_t beginBlock, off_t endBlock, 
bool& inRange) const
                                        break;
                                }
 
-                               if (!_IsBlockRunInRange(runArray[i], 
beginBlock, endBlock))
+                               if (!allocator.IsBlockRunInRange(runArray[i]))
                                        return B_OK;
                        }
 
@@ -3036,7 +3015,7 @@ Inode::StreamInRange(off_t beginBlock, off_t endBlock, 
bool& inRange) const
                if (status != B_OK)
                        return status;
 
-               if (!_IsBlockRunInRange(run, beginBlock, endBlock))
+               if (!allocator.IsBlockRunInRange(run))
                        return B_OK;
        }
 
diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.h 
b/src/add-ons/kernel/file_systems/bfs/Inode.h
index 15580f8..fa02dde 100644
--- a/src/add-ons/kernel/file_systems/bfs/Inode.h
+++ b/src/add-ons/kernel/file_systems/bfs/Inode.h
@@ -153,9 +153,8 @@ public:
                        status_t                        
TrimPreallocation(Transaction& transaction);
                        bool                            NeedsTrimming() const;
 
-                       status_t                        MoveStream(off_t 
beginBlock, off_t endBlock);
-                       status_t                        StreamInRange(off_t 
beginBlock, off_t endBlock,
-                                                                       bool& 
inRange) const;
+                       status_t                        MoveStream();
+                       status_t                        StreamInRange(bool& 
inRange) const;
 
                        status_t                        Free(Transaction& 
transaction);
                        status_t                        Sync();
@@ -251,32 +250,25 @@ private:
                                                                        off_t 
size, off_t& offset, off_t& max);
                        status_t                        
_AllocateBlockArray(Transaction& transaction,
                                                                        
block_run& run, size_t length,
-                                                                       bool 
variableSize = false,
-                                                                       off_t 
beginBlock = 0, off_t endBlock = 0);
+                                                                       bool 
variableSize = false);
                        status_t                        
_GrowStream(Transaction& transaction,
                                                                        off_t 
size);
                        status_t                        
_ShrinkStream(Transaction& transaction,
                                                                        off_t 
size);
                        status_t                        
_AddBlockRun(Transaction& transaction,
                                                                        
data_stream* dataStream, block_run run,
-                                                                       off_t 
targetSize, int32* rest = NULL,
-                                                                       off_t 
beginBlock = 0, off_t endBlock = 0);
+                                                                       off_t 
targetSize, int32* rest = NULL);
 
                        // moving the data stream
                        status_t                        
_WriteBufferedRuns(Transaction& transaction,
                                                                        
BlockRunBuffer& buffer,
                                                                        
data_stream* dataStream, off_t targetSize,
-                                                                       bool 
flush = false, off_t beginBlock = 0,
-                                                                       off_t 
endBlock = 0);
+                                                                       bool 
flush = false);
                        status_t                        
_FreeIndirectBlocks(Transaction& transaction,
                                                                        
data_stream *dataStream);
 
                        status_t                        _GetNextBlockRun(off_t& 
position,
                                                                        
block_run& run) const;
-                       bool                            
_IsBlockRunInRange(block_run run,
-                                                                       off_t 
beginBlock, off_t endBlock) const;
-                       bool                            
_IsBlockRunOutsideRange(block_run run,
-                                                                       off_t 
beginBlock, off_t endBlock) const;
 
 private:
                        rw_lock                         fLock;
diff --git a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp 
b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
index b7fa110..47c05b0 100644
--- a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
@@ -22,6 +22,13 @@ ResizeVisitor::ResizeVisitor(Volume* volume)
 }
 
 
+ResizeVisitor::~ResizeVisitor()
+{
+       // reset the allocation range
+       GetVolume()->Allocator().SetRange(0, 0);
+}
+
+
 status_t
 ResizeVisitor::Resize(off_t size, disk_job_id job)
 {
@@ -50,6 +57,9 @@ ResizeVisitor::Resize(off_t size, disk_job_id job)
        Start(VISIT_REGULAR | VISIT_INDICES | VISIT_REMOVED
                | VISIT_ATTRIBUTE_DIRECTORIES);
 
+       GetVolume()->Allocator().SetRange(fBeginBlock, fEndBlock);
+               // this is reset in our destructor
+
        // move file system data out of the way
        while (true) {
                fError = false;
@@ -151,7 +161,7 @@ ResizeVisitor::VisitInode(Inode* inode, const char* 
treeName)
 
        // move the stream if necessary
        bool inRange;
-       status = inode->StreamInRange(fBeginBlock, fEndBlock, inRange);
+       status = inode->StreamInRange(inRange);
        if (status != B_OK) {
                FATAL(("Resize: Failed to check file stream, inode %" B_PRIdINO
                        ", \"%s\"!\n", inode->ID(), name));
@@ -160,7 +170,7 @@ ResizeVisitor::VisitInode(Inode* inode, const char* 
treeName)
        }
 
        if (!inRange) {
-               status = inode->MoveStream(fBeginBlock, fEndBlock);
+               status = inode->MoveStream();
                if (status != B_OK) {
                        FATAL(("Resize: Failed to move file stream, inode %" 
B_PRIdINO
                                ", \"%s\"!\n", inode->ID(), name));
@@ -590,7 +600,7 @@ ResizeVisitor::_MoveInode(Inode* inode, off_t& newInodeID, 
const char* treeName)
 
        block_run run;
        status_t status = GetVolume()->Allocator().AllocateBlocks(transaction, 
0, 0,
-               1, 1, run, fBeginBlock, fEndBlock);
+               1, 1, run);
                // TODO: use a hint, maybe old position % new volume size?
                //       stuff that originally was in the beginning should 
probably
                //       stay close to it
diff --git a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.h 
b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.h
index 41f5535..69e8328 100644
--- a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.h
+++ b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.h
@@ -19,6 +19,7 @@ class Transaction;
 class ResizeVisitor : public FileSystemVisitor {
 public:
                                                                
ResizeVisitor(Volume* volume);
+       virtual                                         ~ResizeVisitor();
 
                        status_t                        Resize(off_t size, 
disk_job_id job);
 
diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.h 
b/src/add-ons/kernel/file_systems/bfs/Volume.h
index 6e877b7..d1c6a0d 100644
--- a/src/add-ons/kernel/file_systems/bfs/Volume.h
+++ b/src/add-ons/kernel/file_systems/bfs/Volume.h
@@ -116,8 +116,7 @@ public:
                                                                block_run& run);
                        status_t                Allocate(Transaction& 
transaction, Inode* inode,
                                                                off_t 
numBlocks, block_run& run,
-                                                               uint16 minimum 
= 1, off_t beginBlock = 0,
-                                                               off_t endBlock 
= 0);
+                                                               uint16 minimum 
= 1);
                        status_t                Free(Transaction& transaction, 
block_run run);
                        void                    SetCheckingThread(thread_id 
thread)
                                                                { 
fCheckingThread = thread; }
@@ -222,10 +221,10 @@ Volume::AllocateForInode(Transaction& transaction, const 
block_run* parent,
 
 inline status_t
 Volume::Allocate(Transaction& transaction, Inode* inode, off_t numBlocks,
-       block_run& run, uint16 minimum, off_t beginBlock, off_t endBlock)
+       block_run& run, uint16 minimum)
 {
        return fBlockAllocator.Allocate(transaction, inode, numBlocks, run,
-               minimum, beginBlock, endBlock);
+               minimum);
 }
 
 

############################################################################

Commit:      a938a37bddc195b3765e7f31dfac27b5375a69a7

Author:      ahenriksson <sausageboy@xxxxxxxxx>
Date:        Thu Aug  2 17:09:15 2012 UTC

Add mapping from vnode ID to block number for moved inodes

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp 
b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
index 2c93c2d..e310ddf 100644
--- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
@@ -785,7 +785,7 @@ BlockAllocator::IsBlockRunOutsideRange(block_run run) const
 */
 status_t
 BlockAllocator::AllocateBlocks(Transaction& transaction, int32 groupIndex,
-       uint16 start, uint16 maximum, uint16 minimum, block_run& run)
+       uint16 start, uint16 maximum, uint16 minimum, block_run& run, bool 
inode)
 {
        if (maximum == 0)
                return B_BAD_VALUE;
@@ -799,6 +799,16 @@ BlockAllocator::AllocateBlocks(Transaction& transaction, 
int32 groupIndex,
        AllocationBlock cached(fVolume);
        RecursiveLocker lock(fLock);
 
+       bool checkMovedInodes = false;
+       ReadLocker movedInodesLocker;
+       if (inode) {
+               movedInodesLocker.SetTo(fVolume->MovedInodesLock(), false);
+
+               // don't check for moved inodes unless the volume actually has 
them
+               if (fVolume->HasMovedInodes())
+                       checkMovedInodes = true;
+       }
+
        uint32 bitsPerFullBlock = fVolume->BlockSize() << 3;
 
        // Express the allowed allocation range in terms of allocation groups 
and
@@ -854,7 +864,7 @@ BlockAllocator::AllocateBlocks(Transaction& transaction, 
int32 groupIndex,
                if (start < group.fFirstFree)
                        start = group.fFirstFree;
 
-               if (group.fLargestValid) {
+               if (group.fLargestValid && !checkMovedInodes) {
                        if (group.fLargestLength < bestLength)
                                continue;
 
@@ -884,7 +894,8 @@ BlockAllocator::AllocateBlocks(Transaction& transaction, 
int32 groupIndex,
                int32 groupLargestStart = -1;
                int32 groupLargestLength = -1;
                int32 currentBit = start;
-               bool canFindGroupLargest = start == 0 && end == group.NumBits();
+               bool canFindGroupLargest = start == 0 && end == group.NumBits()
+                       && !checkMovedInodes;
 
                // If end is the first bit in a block, the last block 
considered is the
                // previous one, and the end bit is bitsPerFullBlock.
@@ -908,7 +919,22 @@ BlockAllocator::AllocateBlocks(Transaction& transaction, 
int32 groupIndex,
 
                        // find a block large enough to hold the allocation
                        for (uint32 bit = start % bitsPerFullBlock; bit < 
endBit; bit++) {
-                               if (!cached.IsUsed(bit)) {
+                               bool isUsed = cached.IsUsed(bit);
+
+                               // if we're allocating space for an inode, we 
treat blocks
+                               // which used to have moved inodes as used
+                               if (checkMovedInodes && !isUsed) {
+                                       ino_t currentBlock = fVolume->ToBlock(
+                                                       
block_run::Run(groupIndex, currentBit, 1));
+
+                                       // while it might seem excessive to do 
a hash lookup for
+                                       // every bit we check, an inode only 
requires a single
+                                       // block, so we're unlikely to do this 
more than once, or
+                                       // a couple of times at most
+                                       isUsed = 
fVolume->WasMovedInode(currentBlock);
+                               }
+
+                               if (!isUsed) {
                                        if (currentLength == 0) {
                                                // start new range
                                                currentStart = currentBit;
@@ -1038,7 +1064,7 @@ BlockAllocator::AllocateForInode(Transaction& transaction,
        if ((type & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR)) == S_DIRECTORY)
                group += 8;
 
-       return AllocateBlocks(transaction, group, 0, 1, 1, run);
+       return AllocateBlocks(transaction, group, 0, 1, 1, run, true);
 }
 
 
diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h 
b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h
index 3de7212..c8bf937 100644
--- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h
+++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.h
@@ -47,7 +47,8 @@ public:
 
                        status_t                AllocateBlocks(Transaction& 
transaction,
                                                                int32 group, 
uint16 start, uint16 numBlocks,
-                                                               uint16 minimum, 
block_run& run);
+                                                               uint16 minimum, 
block_run& run,
+                                                               bool inode = 
false);
 
                        status_t                AllocateBlockRun(Transaction& 
transaction,
                                                                block_run run);
diff --git a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp 
b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
index 47c05b0..fb1329e 100644
--- a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
@@ -129,6 +129,8 @@ ResizeVisitor::VisitInode(Inode* inode, const char* 
treeName)
        // start by moving the inode so we can place the stream close to it
        // if possible
        if (inodeBlock < fBeginBlock || inodeBlock >= fEndBlock) {
+               WriteLocker movedInodesLocker(GetVolume()->MovedInodesLock());
+
                status = mark_vnode_busy(GetVolume()->FSVolume(), inode->ID(), 
true);
 
                ino_t oldInodeID = inode->ID();
@@ -600,7 +602,7 @@ ResizeVisitor::_MoveInode(Inode* inode, off_t& newInodeID, 
const char* treeName)
 
        block_run run;
        status_t status = GetVolume()->Allocator().AllocateBlocks(transaction, 
0, 0,
-               1, 1, run);
+               1, 1, run, true);
                // TODO: use a hint, maybe old position % new volume size?
                //       stuff that originally was in the beginning should 
probably
                //       stay close to it
@@ -661,5 +663,11 @@ ResizeVisitor::_MoveInode(Inode* inode, off_t& newInodeID, 
const char* treeName)
                }
        }
 
+       status = GetVolume()->AddMovedInode(inode->ID(), newInodeID);
+       if (status != B_OK) {
+               FATAL(("_MoveInode: Could not add inode to vnodeID -> inodeID 
map!\n"));
+               return status;
+       }
+
        return B_OK;
 }
diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.cpp 
b/src/add-ons/kernel/file_systems/bfs/Volume.cpp
index a04eaab..5e33044 100644
--- a/src/add-ons/kernel/file_systems/bfs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/Volume.cpp
@@ -251,15 +251,20 @@ Volume::Volume(fs_volume* volume)
        fDirtyCachedBlocks(0),
        fFlags(0),
        fCheckingThread(-1),
-       fCheckVisitor(NULL)
+       fCheckVisitor(NULL),
+       fMovedInodes(NULL)
 {
        mutex_init(&fLock, "bfs volume");
        mutex_init(&fQueryLock, "bfs queries");
+       rw_lock_init(&fMovedInodesLock, "bfs moved inodes");
 }
 
 
 Volume::~Volume()
 {
+       delete fMovedInodes;
+
+       rw_lock_destroy(&fMovedInodesLock);
        mutex_destroy(&fQueryLock);
        mutex_destroy(&fLock);
 }
@@ -511,6 +516,65 @@ Volume::CreateIndicesRoot(Transaction& transaction)
 
 
 status_t
+Volume::AddMovedInode(ino_t oldID, ino_t newID)
+{
+       ASSERT_WRITE_LOCKED_RW_LOCK(&fMovedInodesLock);
+
+       if (fMovedInodes == NULL)
+               fMovedInodes = new(std::nothrow) InodeMap;
+
+       if (fMovedInodes == NULL)
+               return B_NO_MEMORY;
+
+       return fMovedInodes->Put(oldID, newID);
+}
+
+
+bool
+Volume::HasMovedInodes() const
+{
+       return fMovedInodes != NULL;
+}
+
+
+InodeMap::Iterator
+Volume::MovedInodesIterator() const
+{
+       ASSERT(fMovedInodes != NULL);
+       return fMovedInodes->GetIterator();
+}
+
+
+ino_t
+Volume::ResolveVnodeID(ino_t vnodeID)
+{
+       ReadLocker locker(fMovedInodesLock);
+
+       // no inodes have been moved
+       if (fMovedInodes == NULL)
+               return vnodeID;
+
+       ino_t* inodeID;
+
+       // has this inode been moved?
+       if (fMovedInodes->Get(vnodeID, inodeID))
+               return *inodeID;
+
+       return vnodeID;
+}
+
+
+bool
+Volume::WasMovedInode(ino_t blockNumber)
+{
+       ASSERT(fMovedInodes != NULL);
+       ReadLocker locker(fMovedInodesLock);
+
+       return fMovedInodes->ContainsKey(blockNumber);
+}
+
+
+status_t
 Volume::CreateVolumeID(Transaction& transaction)
 {
        Attribute attr(fRootNode);
diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.h 
b/src/add-ons/kernel/file_systems/bfs/Volume.h
index d1c6a0d..e22d4b7 100644
--- a/src/add-ons/kernel/file_systems/bfs/Volume.h
+++ b/src/add-ons/kernel/file_systems/bfs/Volume.h
@@ -29,6 +29,8 @@ enum volume_initialize_flags {
 
 typedef DoublyLinkedList<Inode> InodeList;
 
+typedef HashMap<HashKey64<ino_t>, ino_t> InodeMap;
+
 
 class Volume {
 public:
@@ -106,6 +108,15 @@ public:
                        InodeList&              RemovedInodes() { return 
fRemovedInodes; }
                                // This list is guarded by the transaction lock
 
+                       // moved inodes
+                       rw_lock&                MovedInodesLock() { return 
fMovedInodesLock; }
+                       status_t                AddMovedInode(ino_t oldID, 
ino_t newID);
+                       bool                    HasMovedInodes() const;
+                       InodeMap::Iterator MovedInodesIterator() const;
+
+                       ino_t                   ResolveVnodeID(ino_t vnodeID);
+                       bool                    WasMovedInode(ino_t 
blockNumber);
+
                        // block bitmap
                        BlockAllocator& Allocator();
                        status_t                AllocateForInode(Transaction& 
transaction,
@@ -185,6 +196,9 @@ protected:
                        ::CheckVisitor* fCheckVisitor;
 
                        InodeList               fRemovedInodes;
+
+                       rw_lock                 fMovedInodesLock;
+                       InodeMap*               fMovedInodes;
 };
 
 
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 a191757..8a45fc3 100644
--- a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp
@@ -269,12 +269,20 @@ bfs_sync(fs_volume* _volume)
 /*!    Reads in the node from disk and creates an inode object from it.
 */
 static status_t
-bfs_get_vnode(fs_volume* _volume, ino_t id, fs_vnode* _node, int* _type,
+bfs_get_vnode(fs_volume* _volume, ino_t _id, fs_vnode* _node, int* _type,
        uint32* _flags, bool reenter)
 {
        //FUNCTION_START(("ino_t = %Ld\n", id));
        Volume* volume = (Volume*)_volume->private_volume;
 
+       ino_t id = volume->ResolveVnodeID(_id);
+       if (id != _id) {
+               // TODO: we return an error here for now
+               INFORM(("Denying access to remapped inode, old ID=%" B_PRIdINO
+                       ", new ID=%" B_PRIdINO "\n", _id, id));
+               return B_ERROR;
+       }
+
        // first inode may be after the log area, we don't go through
        // the hassle and try to load an earlier block from disk
        if (id < volume->ToBlock(volume->Log()) + volume->Log().Length()
diff --git a/src/add-ons/kernel/file_systems/bfs/system_dependencies.h 
b/src/add-ons/kernel/file_systems/bfs/system_dependencies.h
index 6e89896..1b27fea 100644
--- a/src/add-ons/kernel/file_systems/bfs/system_dependencies.h
+++ b/src/add-ons/kernel/file_systems/bfs/system_dependencies.h
@@ -16,6 +16,7 @@
 #else  // !BFS_SHELL
 
 #include <AutoDeleter.h>
+#include <shared/HashMap.h>
 #include <util/AutoLock.h>
 #include <util/DoublyLinkedList.h>
 #include <util/kernel_cpp.h>

############################################################################

Commit:      45fefb34d31080190ba4107f7865236650bd24e8

Author:      ahenriksson <sausageboy@xxxxxxxxx>
Date:        Thu Aug  2 17:43:37 2012 UTC

Don't check device size when resizing

It's not our responsibility. This reverts "Calculate device size in
Volume for use by resize code", and removes the check in ResizeVisitor.

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp 
b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
index fb1329e..eef632e 100644
--- a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
@@ -262,15 +262,6 @@ ResizeVisitor::_IsResizePossible(off_t size)
                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;
diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.cpp 
b/src/add-ons/kernel/file_systems/bfs/Volume.cpp
index 5e33044..ae2fce5 100644
--- a/src/add-ons/kernel/file_systems/bfs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/Volume.cpp
@@ -46,6 +46,8 @@ public:
                        int                     Mode() const { return fMode; }
                        bool            IsReadOnly() const { return 
_IsReadOnly(fMode); }
 
+                       status_t        GetSize(off_t* _size, uint32* 
_blockSize = NULL);
+
 private:
        static  bool            _IsReadOnly(int mode)
                                                        { return (mode & 
O_RWMASK) == O_RDONLY;}
@@ -154,6 +156,38 @@ DeviceOpener::Keep()
 }
 
 
+/*!    Returns the size of the device in bytes. It uses B_GET_GEOMETRY
+       to compute the size, or fstat() if that failed.
+*/
+status_t
+DeviceOpener::GetSize(off_t* _size, uint32* _blockSize)
+{
+       device_geometry geometry;
+       if (ioctl(fDevice, B_GET_GEOMETRY, &geometry) < 0) {
+               // maybe it's just a file
+               struct stat stat;
+               if (fstat(fDevice, &stat) < 0)
+                       return B_ERROR;
+
+               if (_size)
+                       *_size = stat.st_size;
+               if (_blockSize) // that shouldn't cause us any problems
+                       *_blockSize = 512;
+
+               return B_OK;
+       }
+
+       if (_size) {
+               *_size = 1LL * geometry.head_count * geometry.cylinder_count
+                       * geometry.sectors_per_track * 
geometry.bytes_per_sector;
+       }
+       if (_blockSize)
+               *_blockSize = geometry.bytes_per_sector;
+
+       return B_OK;
+}
+
+
 //     #pragma mark -
 
 
@@ -328,11 +362,10 @@ Volume::Mount(const char* deviceName, uint32 flags)
        fAllocationGroupShift = fSuperBlock.AllocationGroupShift();
 
        // check if the device size is large enough to hold the file system
-       status_t status = UpdateDeviceSize();
-       if (status != B_OK)
-               RETURN_ERROR(status);
-       
-       if (fDeviceSize < (NumBlocks() << BlockShift()))
+       off_t diskSize;
+       if (opener.GetSize(&diskSize, &fDeviceBlockSize) != B_OK)
+               RETURN_ERROR(B_ERROR);
+       if (diskSize < (NumBlocks() << BlockShift()))
                RETURN_ERROR(B_BAD_VALUE);
 
        // set the current log pointers, so that journaling will work correctly
@@ -346,7 +379,7 @@ Volume::Mount(const char* deviceName, uint32 flags)
        if (fJournal == NULL)
                return B_NO_MEMORY;
 
-       status = fJournal->InitCheck();
+       status_t status = fJournal->InitCheck();
        if (status < B_OK) {
                FATAL(("could not initialize journal: %s!\n", 
strerror(status)));
                return status;
@@ -441,34 +474,6 @@ Volume::Sync()
 }
 
 
-/*!    Reads the size and block size of the device in bytes. It uses
-       B_GET_GEOMETRY to compute the size, or fstat() if that failed.
-*/
-status_t
-Volume::UpdateDeviceSize()
-{
-       device_geometry geometry;
-       if (ioctl(fDevice, B_GET_GEOMETRY, &geometry) < 0) {
-               // maybe it's just a file
-               struct stat stat;
-               if (fstat(fDevice, &stat) < 0)
-                       return B_ERROR;
-
-               fDeviceSize = stat.st_size;
-               fDeviceBlockSize = 512;
-                       // that shouldn't cause us any problems
-
-               return B_OK;
-       }
-
-       fDeviceSize = 1LL * geometry.head_count * geometry.cylinder_count
-               * geometry.sectors_per_track * geometry.bytes_per_sector;
-       fDeviceBlockSize = geometry.bytes_per_sector;
-
-       return B_OK;
-}
-
-
 status_t
 Volume::ValidateBlockRun(block_run run)
 {
@@ -783,11 +788,12 @@ Volume::Initialize(int fd, const char* name, uint32 
blockSize,
 
        fDevice = opener.Device();
 
-       status_t status = UpdateDeviceSize();
-       if (status != B_OK)
-               return status;
+       uint32 deviceBlockSize;
+       off_t deviceSize;
+       if (opener.GetSize(&deviceSize, &deviceBlockSize) < B_OK)
+               return B_ERROR;
 
-       off_t numBlocks = fDeviceSize / blockSize;
+       off_t numBlocks = deviceSize / blockSize;
 
        // create valid super block
 
@@ -798,7 +804,7 @@ Volume::Initialize(int fd, const char* name, uint32 
blockSize,
        fBlockShift = fSuperBlock.BlockShift();
        fAllocationGroupShift = fSuperBlock.AllocationGroupShift();
 
-       off_t logSize = CalculateLogSize(numBlocks, fDeviceSize);
+       off_t logSize = CalculateLogSize(numBlocks, deviceSize);
 
        // since the allocator has not been initialized yet, we
        // cannot use BlockAllocator::BitmapSize() here
@@ -831,7 +837,7 @@ Volume::Initialize(int fd, const char* name, uint32 
blockSize,
                RETURN_ERROR(B_ERROR);
 
        off_t id;
-       status = Inode::Create(transaction, NULL, NULL,
+       status_t status = Inode::Create(transaction, NULL, NULL,
                S_DIRECTORY | 0755, 0, 0, NULL, &id, &fRootNode);
        if (status < B_OK)
                RETURN_ERROR(status);
diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.h 
b/src/add-ons/kernel/file_systems/bfs/Volume.h
index e22d4b7..40ae6bf 100644
--- a/src/add-ons/kernel/file_systems/bfs/Volume.h
+++ b/src/add-ons/kernel/file_systems/bfs/Volume.h
@@ -73,10 +73,7 @@ public:
                                                                { return 
(NumBlocks() + fBlockSize * 8 - 1)
                                                                        / 
(fBlockSize * 8); }
 
-                       status_t                UpdateDeviceSize();
-                       off_t                   DeviceSize() const { return 
fDeviceSize; }
                        uint32                  DeviceBlockSize() const { 
return fDeviceBlockSize; }
-
                        uint32                  BlockSize() const { return 
fBlockSize; }
                        uint32                  BlockShift() const { return 
fBlockShift; }
                        uint32                  InodeSize() const
@@ -169,7 +166,6 @@ protected:
                        int                             fDevice;
                        disk_super_block fSuperBlock;
 
-                       off_t                   fDeviceSize;
                        uint32                  fDeviceBlockSize;
                        uint32                  fBlockSize;
                        uint32                  fBlockShift;

############################################################################

Commit:      e8d0bc3a5956076c0367eecc7b82ac084447d767

Author:      ahenriksson <sausageboy@xxxxxxxxx>
Date:        Fri Aug  3 09:04:34 2012 UTC

Added code to update the block cache size

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/bfs/Journal.cpp 
b/src/add-ons/kernel/file_systems/bfs/Journal.cpp
index b89f45a..bacfde1 100644
--- a/src/add-ons/kernel/file_systems/bfs/Journal.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/Journal.cpp
@@ -900,18 +900,18 @@ Journal::_WriteTransactionToLog()
 
 
 /*!    Flushes the current log entry to disk. If \a flushBlocks is \c true it 
will
-       also write back all dirty blocks for this volume. If \a movingLog is \c
+       also write back all dirty blocks for this volume. If \a alreadyLocked 
is \c
        true, we allow the lock to be held when the function is called.
 */
 status_t
-Journal::_FlushLog(bool canWait, bool flushBlocks, bool movingLog)
+Journal::_FlushLog(bool canWait, bool flushBlocks, bool alreadyLocked)
 {
        status_t status = canWait ? recursive_lock_lock(&fLock)
                : recursive_lock_trylock(&fLock);
        if (status != B_OK)
                return status;
 
-       int32 allowedLocks = movingLog ? 2 : 1;
+       int32 allowedLocks = alreadyLocked ? 2 : 1;
        if (recursive_lock_get_recursion(&fLock) > allowedLocks) {
                // whoa, FlushLogAndBlocks() was called from inside a 
transaction
                recursive_lock_unlock(&fLock);
@@ -944,6 +944,26 @@ Journal::FlushLogAndBlocks()
 }
 
 
+/*!    Locks the journal, in addition to flushing the log and blocks. A return
+       value of \c B_OK indicates that the operation was successful, and that
+       the journal is locked.
+*/
+status_t
+Journal::FlushLogAndLockJournal()
+{
+       status_t status = Lock(NULL, true);
+       if (status != B_OK)
+               return status;
+
+       status = _FlushLog(true, true, true);
+
+       if (status != B_OK)
+               recursive_lock_unlock(&fLock);
+
+       return status;
+}
+
+
 status_t
 Journal::Lock(Transaction* owner, bool separateSubTransactions)
 {
@@ -1122,19 +1142,19 @@ Journal::MoveLog(block_run newLog)
                        return status;
        }
 
-       RecursiveLocker locker(fLock);
+       MutexLocker volumeLock(fVolume->Lock());
 
-       status = _FlushLog(true, true, true);
+       status = FlushLogAndLockJournal();
        if (status != B_OK)
                return status;
 
-       MutexLocker volumeLock(fVolume->Lock());
-
        // update references to the log location and size
        fVolume->SuperBlock().log_blocks = newLog;
        status = fVolume->WriteSuperBlock();
        if (status != B_OK) {
                fVolume->SuperBlock().log_blocks = oldLog;
+
+               Unlock(NULL, true);
                
                // if we had to allocate some blocks, try to free them
                if (!allocatedRun.IsZero()) {
@@ -1154,8 +1174,8 @@ Journal::MoveLog(block_run newLog)
        fLogSize = newLog.Length();
        fMaxTransactionSize = fLogSize / 2 - 5;
 
+       Unlock(NULL, true);
        volumeLock.Unlock();
-       locker.Unlock();
 
        // at this point, the log is moved and functional in its new location
 
diff --git a/src/add-ons/kernel/file_systems/bfs/Journal.h 
b/src/add-ons/kernel/file_systems/bfs/Journal.h
index a168cd8..5a519a6 100644
--- a/src/add-ons/kernel/file_systems/bfs/Journal.h
+++ b/src/add-ons/kernel/file_systems/bfs/Journal.h
@@ -36,6 +36,8 @@ public:
                        bool                    CurrentTransactionTooLarge() 
const;
 
                        status_t                FlushLogAndBlocks();
+                       status_t                FlushLogAndLockJournal();
+
                        Volume*                 GetVolume() const { return 
fVolume; }
                        int32                   TransactionID() const { return 
fTransactionID; }
 
@@ -52,7 +54,7 @@ private:
                                                                { return 
fHasSubtransaction; }
 
                        status_t                _FlushLog(bool canWait, bool 
flushBlocks,
-                                                               bool movingLog 
= false);
+                                                               bool 
alreadyLocked = false);
                        uint32                  _TransactionSize() const;
                        status_t                _WriteTransactionToLog();
                        status_t                _CheckRunArray(const run_array* 
array);
diff --git a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp 
b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
index eef632e..b3ec05f 100644
--- a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.cpp
@@ -307,6 +307,11 @@ ResizeVisitor::_ResizeVolume()
        if (status != B_OK)
                return status;
 
+       // change size of block cache
+       status = GetVolume()->ResizeBlockCache(fNumBlocks);
+       if (status != B_OK)
+               return status;
+
        // update superblock and volume information
        disk_super_block& superBlock = GetVolume()->SuperBlock();
 
diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.cpp 
b/src/add-ons/kernel/file_systems/bfs/Volume.cpp
index ae2fce5..7021b27 100644
--- a/src/add-ons/kernel/file_systems/bfs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/Volume.cpp
@@ -475,6 +475,31 @@ Volume::Sync()
 
 
 status_t
+Volume::ResizeBlockCache(off_t numBlocks)
+{
+       status_t status = fJournal->FlushLogAndLockJournal();
+       if (status != B_OK)
+               return status;
+
+       void* newBlockCache = block_cache_create(fDevice, numBlocks, fBlockSize,
+               IsReadOnly());
+
+       if (newBlockCache != NULL) {
+               block_cache_delete(fBlockCache, false);
+                       // we have the journal flushed and locked, so there 
can't be
+                       // any unwritten blocks in this cache
+
+               fBlockCache = newBlockCache;
+               status = B_OK;
+       } else
+               status = B_ERROR;
+
+       fJournal->Unlock(NULL, true);
+       return status;
+}
+
+
+status_t
 Volume::ValidateBlockRun(block_run run)
 {
        if (run.AllocationGroup() < 0
diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.h 
b/src/add-ons/kernel/file_systems/bfs/Volume.h
index 40ae6bf..faec36a 100644
--- a/src/add-ons/kernel/file_systems/bfs/Volume.h
+++ b/src/add-ons/kernel/file_systems/bfs/Volume.h
@@ -155,6 +155,7 @@ public:
                        Journal*                GetJournal(off_t refBlock) 
const;
 
                        void*                   BlockCache() { return 
fBlockCache; }
+                       status_t                ResizeBlockCache(off_t 
numBlocks);
 
        static  status_t                CheckSuperBlock(const uint8* data,
                                                                uint32* _offset 
= NULL);

############################################################################

Commit:      5cbffd392ebc19ddcecc1ccc64fe20a1c36e370f

Author:      ahenriksson <sausageboy@xxxxxxxxx>
Date:        Mon Aug  6 18:51:15 2012 UTC

Fix deadlock when reinitializing block allocator

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp 
b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
index e310ddf..59274c2 100644
--- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
@@ -613,16 +613,19 @@ BlockAllocator::InitializeAndClearBitmap(Transaction& 
transaction)
 status_t
 BlockAllocator::Reinitialize()
 {
-       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) {
-               recursive_lock_unlock(&fLock);
+       status_t status = fVolume->GetJournal(0)->FlushLogAndLockJournal();
+       if (status != B_OK)
                return status;
-       }
+
+       recursive_lock_lock(&fLock);
+               // the lock will be unlocked in the call to Initialize()
+
+       fVolume->GetJournal(0)->Unlock(NULL, true);
+               // unlock the journal here: we only need to make sure that no 
one
+               // starts a transaction before we get the allocator lock, as 
that
+               // would cause a deadlock
 
        delete[] fGroups;
        return Initialize(true, true);


Other related posts: