BTRFS: Implement a simple journaling approach, this is not finished and mostly satisfy the need for passing Transaction object for many functions.
Some details about the current Journal: * Journal can only end transaction. * It holds a transaction id of fs (fCurrentGeneration) that increments each time a transaction starts. * _TransactionWritten now just printing message. Signed-off-by: Augustin Cavalier <waddlesplash@gmail.com>
This commit is contained in:
parent
1750cd1e92
commit
c1320b3a33
|
@ -18,6 +18,7 @@ KernelAddon btrfs :
|
|||
DirectoryIterator.cpp
|
||||
ExtentAllocator.cpp
|
||||
Inode.cpp
|
||||
Journal.cpp
|
||||
Volume.cpp
|
||||
: kernel_libz.a
|
||||
;
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
#include "Journal.h"
|
||||
|
||||
|
||||
//#define TRACE_BTRFS
|
||||
#ifdef TRACE_BTRFS
|
||||
# define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
# define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)
|
||||
|
||||
|
||||
Journal::Journal(Volume* volume)
|
||||
:
|
||||
fVolume(volume),
|
||||
fOwner(NULL),
|
||||
fTransactionID(0),
|
||||
fCurrentGeneration(volume->SuperBlock().Generation())
|
||||
{
|
||||
recursive_lock_init(&fLock, "btrfs journal");
|
||||
}
|
||||
|
||||
|
||||
Journal::~Journal()
|
||||
{
|
||||
recursive_lock_destroy(&fLock);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ void
|
||||
Journal::_TransactionWritten(int32 transactionID, int32 event, void* _journal)
|
||||
{
|
||||
TRACE("TRANSACTION WRITTEN id %i\n", transactionID);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Journal::_TransactionDone(bool success)
|
||||
{
|
||||
if (!success) {
|
||||
cache_abort_transaction(fVolume->BlockCache(), fTransactionID);
|
||||
return B_OK;
|
||||
}
|
||||
cache_end_transaction(fVolume->BlockCache(), fTransactionID,
|
||||
&_TransactionWritten, this);
|
||||
//cache_sync_transaction(fVolume->BlockCache(), fTransactionID);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Journal::Lock(Transaction* owner)
|
||||
{
|
||||
status_t status = recursive_lock_lock(&fLock);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
if (recursive_lock_get_recursion(&fLock) > 1) {
|
||||
// we'll just use the current transaction again
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
if (owner != NULL)
|
||||
owner->SetParent(fOwner);
|
||||
|
||||
fOwner = owner;
|
||||
|
||||
if (fOwner != NULL) {
|
||||
fTransactionID = cache_start_transaction(fVolume->BlockCache());
|
||||
|
||||
if (fTransactionID < B_OK) {
|
||||
recursive_lock_unlock(&fLock);
|
||||
return fTransactionID;
|
||||
}
|
||||
fCurrentGeneration++;
|
||||
TRACE("Journal::Lock() start transaction id: %i\n", fTransactionID);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Journal::UnLock(Transaction* owner, bool success)
|
||||
{
|
||||
if (recursive_lock_get_recursion(&fLock) == 1) {
|
||||
if (owner != NULL) {
|
||||
status_t status = _TransactionDone(success);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
fOwner = owner->Parent();
|
||||
} else {
|
||||
fOwner = NULL;
|
||||
}
|
||||
}
|
||||
recursive_lock_unlock(&fLock);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// Transaction
|
||||
|
||||
|
||||
Transaction::Transaction(Volume* volume)
|
||||
:
|
||||
fJournal(NULL),
|
||||
fParent(NULL)
|
||||
{
|
||||
Start(volume);
|
||||
}
|
||||
|
||||
|
||||
Transaction::Transaction()
|
||||
:
|
||||
fJournal(NULL),
|
||||
fParent(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Transaction::~Transaction()
|
||||
{
|
||||
if (fJournal != NULL) {
|
||||
fJournal->UnLock(this, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Transaction::HasBlock(fsblock_t blockNumber) const
|
||||
{
|
||||
return cache_has_block_in_transaction(fJournal->GetVolume()->BlockCache(),
|
||||
ID(), blockNumber);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Transaction::Start(Volume* volume)
|
||||
{
|
||||
if (fJournal != NULL)
|
||||
return B_OK;
|
||||
|
||||
fJournal = volume->GetJournal();
|
||||
if (fJournal != NULL && fJournal->Lock(this) == B_OK) {
|
||||
return B_OK;
|
||||
}
|
||||
fJournal = NULL;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Transaction::Done()
|
||||
{
|
||||
status_t status = B_OK;
|
||||
if (fJournal != NULL) {
|
||||
status = fJournal->UnLock(this, true);
|
||||
if (status == B_OK)
|
||||
fJournal = NULL;
|
||||
}
|
||||
return status;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef JOURNAL_H
|
||||
#define JOURNAL_H
|
||||
|
||||
|
||||
#include "Volume.h"
|
||||
|
||||
class Transaction;
|
||||
|
||||
|
||||
class Journal {
|
||||
public:
|
||||
Journal(Volume* volume);
|
||||
~Journal();
|
||||
|
||||
Volume* GetVolume() const { return fVolume; }
|
||||
Transaction* CurrentTransaction() const { return fOwner; }
|
||||
uint64 SystemTransactionID() const
|
||||
{ return fCurrentGeneration; }
|
||||
int32 TransactionID() const { return fTransactionID; }
|
||||
status_t Lock(Transaction* owner);
|
||||
status_t UnLock(Transaction* owner, bool success);
|
||||
|
||||
private:
|
||||
static void _TransactionWritten(int32 transactionID, int32 event,
|
||||
void* _journal);
|
||||
status_t _TransactionDone(bool success);
|
||||
|
||||
private:
|
||||
Volume* fVolume;
|
||||
recursive_lock fLock;
|
||||
Transaction* fOwner;
|
||||
int32 fTransactionID;
|
||||
uint64 fCurrentGeneration;
|
||||
};
|
||||
|
||||
|
||||
class Transaction {
|
||||
public:
|
||||
Transaction(Volume* volume);
|
||||
Transaction();
|
||||
~Transaction();
|
||||
|
||||
int32 ID() const { return fJournal->TransactionID(); }
|
||||
uint64 SystemID() const
|
||||
{ return fJournal->SystemTransactionID(); }
|
||||
bool HasBlock(fsblock_t blockNumber) const;
|
||||
Transaction* Parent() const { return fParent; }
|
||||
void SetParent(Transaction* parent) { fParent = parent; }
|
||||
status_t Start(Volume* volume);
|
||||
status_t Done();
|
||||
private:
|
||||
Journal* fJournal;
|
||||
Transaction* fParent;
|
||||
};
|
||||
|
||||
|
||||
#endif // JOURNAL_H
|
|
@ -13,6 +13,7 @@
|
|||
#include "CachedBlock.h"
|
||||
#include "Chunk.h"
|
||||
#include "Inode.h"
|
||||
#include "Journal.h"
|
||||
#include "ExtentAllocator.h"
|
||||
|
||||
|
||||
|
@ -387,6 +388,11 @@ Volume::Mount(const char* deviceName, uint32 flags)
|
|||
fChecksumTree->SetRoot(root->LogicalAddress(), NULL);
|
||||
free(root);
|
||||
|
||||
// Initialize Journal
|
||||
fJournal = new(std::nothrow) Journal(this);
|
||||
if (fJournal == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// Initialize ExtentAllocator;
|
||||
fExtentAllocator = new(std::nothrow) ExtentAllocator(this);
|
||||
if (fExtentAllocator == NULL)
|
||||
|
@ -445,6 +451,7 @@ Volume::Unmount()
|
|||
delete fChecksumTree;
|
||||
delete fFSTree;
|
||||
delete fDevTree;
|
||||
delete fJournal;
|
||||
delete fExtentAllocator;
|
||||
fRootTree = NULL;
|
||||
fExtentTree = NULL;
|
||||
|
@ -452,6 +459,7 @@ Volume::Unmount()
|
|||
fChecksumTree = NULL;
|
||||
fFSTree = NULL;
|
||||
fDevTree = NULL;
|
||||
fJournal = NULL;
|
||||
fExtentAllocator = NULL;
|
||||
|
||||
TRACE("Volume::Unmount(): Putting root node\n");
|
||||
|
|
|
@ -17,6 +17,8 @@ enum volume_flags {
|
|||
class BTree;
|
||||
class Chunk;
|
||||
class Inode;
|
||||
class Journal;
|
||||
class Transaction;
|
||||
class ExtentAllocator;
|
||||
|
||||
|
||||
|
@ -46,6 +48,7 @@ public:
|
|||
uint32 SectorSize() const { return fSectorSize; }
|
||||
uint32 BlockSize() const { return fBlockSize; }
|
||||
Chunk* SystemChunk() const { return fChunk; }
|
||||
Journal* GetJournal() const { return fJournal; }
|
||||
ExtentAllocator* GetAllocator() const { return fExtentAllocator; }
|
||||
|
||||
btrfs_super_block& SuperBlock() { return fSuperBlock; }
|
||||
|
@ -76,6 +79,7 @@ private:
|
|||
|
||||
ExtentAllocator* fExtentAllocator;
|
||||
Chunk* fChunk;
|
||||
Journal* fJournal;
|
||||
BTree* fChunkTree;
|
||||
BTree* fRootTree;
|
||||
BTree* fDevTree;
|
||||
|
|
|
@ -44,6 +44,7 @@ local btrfsSources =
|
|||
DirectoryIterator.cpp
|
||||
ExtentAllocator.cpp
|
||||
Inode.cpp
|
||||
Journal.cpp
|
||||
Volume.cpp
|
||||
kernel_interface.cpp
|
||||
;
|
||||
|
|
Loading…
Reference in New Issue