On 10.07.2012 20:49, ahenriksson-github.production wrote:
+ // these can't fail if AllocateBlocks works correctly, but perhaps + // they ought to be checked in the release build anyways rather than + // risking user data? (since we're not actually using the returned run) + ASSERT(allocatedRun.AllocationGroup() == 0); + ASSERT(allocatedRun.Start() == oldEnd); + ASSERT(allocatedRun.Length() == allocationSize);
If it doesn't work correctly, the data is likely to be toasted, anyway :-) IMO this is the perfect use for an ASSERT.
+ // lock journal here? + + status = FlushLogAndBlocks(); + if (status != B_OK) + return status; + + status = recursive_lock_lock(&fLock);
Yes, you should lock the journal first if your intention is to have a clean log at this point (as it should).
BTW instead of calling recursive_lock_lock() manually, you might want to use a RecursiveLocker instead -- less error prone, and nicer to read, too.
+ status = fVolume->WriteSuperBlock(); + if (status != B_OK) { + fVolume->SuperBlock().log_blocks = oldLog; + recursive_lock_unlock(&fLock); + + /* + // if we had to allocate some blocks, try to free them + // TODO: does it even make sense to try this after we couldn't write + // the superblock? + if (!allocatedRun.IsZero()) {
It's unlikely to succeed, but why not. Otherwise the next checkfs run would free the log as well.
status_t +BlockAllocator::Reinitialize() +{ + RecursiveLocker locker(fLock); + + // 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();
That would make _Initialize() a bit nicer, but also more complicated. Also, resizing the block bitmap probably cannot be done in a single transaction, as the log might be too small, or in a transaction at all, since the log area might interfere. When growing a disk, a solution might be to temporary move the log to a safe place (atomically) first, and the resize the disk.
BTW, how do you solve that the block bitmap is used, but must not overwrite existing data at the same time?
+ off_t newLogSize = 2048; + if (newNumBlocks <= 20480) + newLogSize = 512; + if (newSize > 1LL * 1024 * 1024 * 1024) + newLogSize = 4096;
Maybe add a static method containing this logic to be used by Initialize() as well.
+ if (newNumBlocks < GetVolume()->NumBlocks()) { + fShrinking = true; + } else { + fShrinking = false; + } // aTODO handle no resize needed / no data moving needed
If you could not fulfill the user's request, I would return a meaningful error code like B_NOT_SUPPORTED (if it's theoretically possible), or something like B_BAD_VALUE.
+ //if (newReservedLength + //> GetVolume()->Log().Start() + GetVolume()->Log().Length()) { + + Start(VISIT_REGULAR | VISIT_INDICES | VISIT_REMOVED + /*| VISIT_ATTRIBUTE_DIRECTORIES can't move these yet*/);
I guess that is just a matter of updating the parent?
+ + /* + if (newNumBlocks < GetVolume()->NumBlocks()) { + // shrinking + //move data to allowed + //do resize + //move journal(?)
Moving the journal is always problematic, as it's the only thing that cannot use the journal :-) However, it could be done in an atomic way, and that certainly should be done if possible.
+ } else if (newNumBlocks > GetVolume()->NumBlocks()) { + // growing + if (newReservedLength + > GetVolume()->Log().Start() + GetVolume()->Log().Length()) { + //move data out of the area we need as reserved + } + //move journal + //do resize
How would that work in this direction? How to move the journal before having made space for it by moving away inodes?
Or are these just leftovers? :-)
+ // if the inode is not outside the allowed area, we might be able to + // resize anyways + FATAL(("Could not open inode at %" B_PRIdOFF "\n", id)); + + if (fForce) + return B_OK;
While that is true in theory, it's probably not too much to ask for a clean disk before resizing (ie. letting the user call checkfs in case of errors).
+ // make sure we have space to resize the bitmap + if (1 + fBitmapBlocks > GetVolume()->Log().Start()) { + return B_ERROR; + }
Superfluous curly braces.
+status_t +ResizeVisitor::_MoveInode(Inode* inode) +{
[...]
+ status = _UpdateParent(transaction, inode, newInodeID); + if (status != B_OK) + return status; + + status = _UpdateParent(transaction, inode, newInodeID); + if (status != B_OK) + return status;
Doing it twice is twice as much fun?
+status_t +ResizeVisitor::_TemporaryGetDiskSize(off_t& size)
What does the temporary mean?
diff --git a/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.h b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.h new file mode 100644 index 0000000..a8a93ff --- /dev/null
+++ b/src/add-ons/kernel/file_systems/bfs/ResizeVisitor.h @@ -0,0 +1,58 @@ +#ifndef RESIZE_VISITOR_H +#define RESIZE_VISITOR_H
You should add a license header, too.
+ ResizeVisitor(Volume* volume) // aTODO tmp + : + FileSystemVisitor(volume), + fForce(false) {}
Unless it's performance critical, I would put that into the source file instead.
diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.h b/src/add-ons/kernel/file_systems/bfs/Volume.h index f7f3c35..729fe30 100644 @@ -121,6 +122,10 @@ public: { return find_thread(NULL) == fCheckingThread; } CheckVisitor*& GetCheckVisitor() { return fCheckVisitor; }
I would prefer a dedicated setter for this instead, or even a CreateCheckVisitor() method instead. Also, the above method should be called CheckVisitor() - it can be a bit annoying in this case, though, since the class has the same name, and you would need to add the scope to the class name, ie. use ::CheckVisitor.
+ // resizing + // TODO / aTODO: do we need SetResizingThread?
aTODO? :-) Bye, Axel.