Ported r13366 back from the R5 BFS to the Haiku BFS: fixed bad bug in the journaling

code, the super block log data could have been wrong. Moved the doubly linked list
code to the kernel's util/DoublyLinkedList.h.
Also removed Journal::fCurrent, as it's not really used.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13367 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2005-06-30 16:38:37 +00:00
parent 2921880701
commit c0614f3291
3 changed files with 65 additions and 92 deletions

View File

@ -14,6 +14,14 @@
#include <errno.h>
struct log_entry : public DoublyLinkedListLinkImpl<log_entry> {
uint16 start;
uint16 length;
uint32 cached_blocks;
Journal *journal;
};
Journal::Journal(Volume *volume)
:
fVolume(volume),
@ -189,19 +197,20 @@ Journal::blockNotify(int32 transactionID, void *arg)
// Set log_start pointer if possible...
if (logEntry == journal->fEntries.head) {
if (logEntry->Next() != NULL) {
int32 length = logEntry->next->start - logEntry->start;
if (logEntry == journal->fEntries.First()) {
log_entry *next = journal->fEntries.GetNext(logEntry);
if (next != NULL) {
int32 length = next->start - logEntry->start;
superBlock.log_start = (superBlock.log_start + length) % journal->fLogSize;
} else
superBlock.log_start = journal->fVolume->LogEnd();
update = true;
}
journal->fUsed -= logEntry->length;
journal->fEntriesLock.Lock();
logEntry->Remove();
journal->fUsed -= logEntry->length;
journal->fEntries.Remove(logEntry);
journal->fEntriesLock.Unlock();
free(logEntry);
@ -214,7 +223,11 @@ Journal::blockNotify(int32 transactionID, void *arg)
if (superBlock.log_start == superBlock.log_end)
superBlock.flags = SUPER_BLOCK_DISK_CLEAN;
journal->fVolume->WriteSuperBlock();
status_t status = journal->fVolume->WriteSuperBlock();
if (status != B_OK) {
FATAL(("blockNotify: could not write back super block: %s\n",
strerror(status)));
}
}
}
@ -290,21 +303,40 @@ Journal::WriteLogEntry()
logPosition = (logPosition + 1) % fLogSize;
}
// create and add log entry
log_entry *logEntry = (log_entry *)malloc(sizeof(log_entry));
if (logEntry != NULL) {
logEntry->start = logStart;
logEntry->length = TransactionSize();
logEntry->journal = this;
fEntriesLock.Lock();
fEntries.Add(logEntry);
fEntriesLock.Unlock();
fCurrent = logEntry;
fUsed += logEntry->length;
if (logEntry == NULL) {
DIE(("Could not create next log entry (out of memory)\n"));
return B_NO_MEMORY;
}
cache_end_transaction(fVolume->BlockCache(), fTransactionID, blockNotify, fCurrent);
logEntry->start = logStart;
logEntry->length = TransactionSize();
logEntry->journal = this;
fEntriesLock.Lock();
fEntries.Add(logEntry);
fUsed += logEntry->length;
fEntriesLock.Unlock();
// Update the log end pointer in the super block
fVolume->SuperBlock().flags = SUPER_BLOCK_DISK_DIRTY;
fVolume->SuperBlock().log_end = logPosition;
fVolume->LogEnd() = logPosition;
status_t status = fVolume->WriteSuperBlock();
// We need to flush the drives own cache here to ensure
// disk consistency.
// If that call fails, we can't do anything about it anyway
ioctl(fVolume->Device(), B_FLUSH_DRIVE_CACHE);
// at this point, we can finally end the transaction - we're in
// a guaranteed valid state
cache_end_transaction(fVolume->BlockCache(), fTransactionID, blockNotify, logEntry);
fArray.MakeEmpty();
// If the log goes to the next round (the log is written as a
// circular buffer), all blocks will be flushed out which is
@ -313,19 +345,7 @@ Journal::WriteLogEntry()
if (logPosition < logStart)
fVolume->FlushDevice();
// We need to flush the drives own cache here to ensure
// disk consistency.
// If that call fails, we can't do anything about it anyway
ioctl(fVolume->Device(), B_FLUSH_DRIVE_CACHE);
fArray.MakeEmpty();
// Update the log end pointer in the super block
fVolume->SuperBlock().flags = SUPER_BLOCK_DISK_DIRTY;
fVolume->SuperBlock().log_end = logPosition;
fVolume->LogEnd() = logPosition;
return fVolume->WriteSuperBlock();
return status;
}

View File

@ -8,6 +8,7 @@
#include <KernelExport.h>
#include <util/DoublyLinkedList.h>
#ifdef USER
# include "myfs.h"
@ -23,12 +24,8 @@
#include "Utility.h"
struct log_entry : node<log_entry> {
uint16 start;
uint16 length;
uint32 cached_blocks;
Journal *journal;
};
struct log_entry;
typedef DoublyLinkedList<log_entry> LogEntryList;
// Locking policy in BFS: if you need both, the volume lock and the
@ -71,18 +68,17 @@ class Journal {
static void blockNotify(int32 transactionID, void *arg);
status_t TransactionDone(bool success);
Volume *fVolume;
Volume *fVolume;
RecursiveLock fLock;
Transaction *fOwner;
BlockArray fArray;
uint32 fLogSize, fMaxTransactionSize, fUsed;
int32 fTransactionsInEntry;
SimpleLock fEntriesLock;
list<log_entry> fEntries;
log_entry *fCurrent;
bool fHasChangedBlocks;
bigtime_t fTimestamp;
int32 fTransactionID;
Transaction *fOwner;
BlockArray fArray;
uint32 fLogSize, fMaxTransactionSize, fUsed;
int32 fTransactionsInEntry;
SimpleLock fEntriesLock;
LogEntryList fEntries;
bool fHasChangedBlocks;
bigtime_t fTimestamp;
int32 fTransactionID;
};

View File

@ -1,6 +1,6 @@
/* Utility - some helper classes
*
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2001-2005, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License.
*/
#ifndef UTILITY_H
@ -63,47 +63,4 @@ class BlockArray {
int32 fMaxBlocks;
};
// Doubly linked list
template<class Node> struct node {
Node *next, *prev;
void
Remove()
{
prev->next = next;
next->prev = prev;
}
Node *
Next()
{
if (next && next->next != NULL)
return next;
return NULL;
}
};
template<class Node> struct list {
Node *head, *tail, *last;
list()
{
head = (Node *)&tail;
tail = NULL;
last = (Node *)&head;
}
void
Add(Node *entry)
{
entry->next = (Node *)&tail;
entry->prev = last;
last->next = entry;
last = entry;
}
};
#endif /* UTILITY_H */