* The check mechanism in the block allocator now locks the journal as well to

fix a potential deadlock.
* Journal::Lock() now accepts another parameter that specified whether child
  transactions should be split - this is nothing you would want in normal
  operation unless the parent transaction is only there to prevent others from
  writing (such as with the block allocator check stuff).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28438 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-11-01 19:04:14 +00:00
parent d9810e04cf
commit 6c3348f1cd
3 changed files with 27 additions and 8 deletions

View File

@ -1116,14 +1116,20 @@ BlockAllocator::StartChecking(check_control* control)
if (!_IsValidCheckControl(control))
return B_BAD_VALUE;
fVolume->GetJournal(0)->Lock(NULL, true);
// Lock the volume's journal
status_t status = mutex_lock(&fLock);
if (status < B_OK)
if (status < B_OK) {
fVolume->GetJournal(0)->Unlock(NULL, true);
return status;
}
size_t size = BitmapSize();
fCheckBitmap = (uint32*)malloc(size);
if (fCheckBitmap == NULL) {
mutex_unlock(&fLock);
fVolume->GetJournal(0)->Unlock(NULL, true);
return B_NO_MEMORY;
}
@ -1132,6 +1138,7 @@ BlockAllocator::StartChecking(check_control* control)
free(fCheckBitmap);
fCheckBitmap = NULL;
mutex_unlock(&fLock);
fVolume->GetJournal(0)->Unlock(NULL, true);
return B_NO_MEMORY;
}
@ -1209,7 +1216,7 @@ BlockAllocator::StopChecking(check_control* control)
= HOST_ENDIAN_TO_BFS_INT64(usedBlocks);
int32 blocksInBitmap = fNumGroups * fBlocksPerGroup;
int32 blockSize = fVolume->BlockSize();
size_t blockSize = fVolume->BlockSize();
for (int32 i = 0; i < blocksInBitmap; i += 512) {
Transaction transaction(fVolume, 1 + i);
@ -1235,6 +1242,7 @@ BlockAllocator::StopChecking(check_control* control)
fCheckCookie = NULL;
delete cookie;
mutex_unlock(&fLock);
fVolume->GetJournal(0)->Unlock(NULL, true);
return B_OK;
}

View File

@ -403,7 +403,8 @@ Journal::Journal(Volume* volume)
fMaxTransactionSize(fLogSize / 2 - 5),
fUsed(0),
fUnwrittenTransactions(0),
fHasSubtransaction(false)
fHasSubtransaction(false),
fSeparateSubTransactions(false)
{
recursive_lock_init(&fLock, "bfs journal");
mutex_init(&fEntriesLock, "bfs journal entries");
@ -909,17 +910,20 @@ Journal::FlushLogAndBlocks()
status_t
Journal::Lock(Transaction* owner)
Journal::Lock(Transaction* owner, bool separateSubTransactions)
{
status_t status = recursive_lock_lock(&fLock);
if (status != B_OK)
return status;
if (recursive_lock_get_recursion(&fLock) > 1) {
if (!fSeparateSubTransactions && recursive_lock_get_recursion(&fLock) > 1) {
// we'll just use the current transaction again
return B_OK;
}
if (separateSubTransactions)
fSeparateSubTransactions = true;
fOwner = owner;
// TODO: we need a way to find out how big the current transaction is;
@ -951,13 +955,18 @@ Journal::Lock(Transaction* owner)
void
Journal::Unlock(Transaction* owner, bool success)
{
if (recursive_lock_get_recursion(&fLock) == 1) {
if (fSeparateSubTransactions || recursive_lock_get_recursion(&fLock) == 1) {
// we only end the transaction if we would really unlock it
// TODO: what about failing transactions that do not unlock?
// (they must make the parent fail, too)
_TransactionDone(success);
fTimestamp = system_time();
fOwner = NULL;
if (fSeparateSubTransactions
&& recursive_lock_get_recursion(&fLock) == 1)
fSeparateSubTransactions = false;
}
recursive_lock_unlock(&fLock);
@ -1061,7 +1070,7 @@ Transaction::Start(Volume* volume, off_t refBlock)
return B_OK;
fJournal = volume->GetJournal(refBlock);
if (fJournal != NULL && fJournal->Lock(this) == B_OK)
if (fJournal != NULL && fJournal->Lock(this, false) == B_OK)
return B_OK;
fJournal = NULL;

View File

@ -26,7 +26,8 @@ public:
status_t InitCheck();
status_t Lock(Transaction* owner);
status_t Lock(Transaction* owner,
bool separateSubTransactions);
void Unlock(Transaction* owner, bool success);
status_t ReplayLog();
@ -69,6 +70,7 @@ private:
bigtime_t fTimestamp;
int32 fTransactionID;
bool fHasSubtransaction;
bool fSeparateSubTransactions;
};