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:
parent
2921880701
commit
c0614f3291
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user