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:
@@ -14,6 +14,14 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct log_entry : public DoublyLinkedListLinkImpl<log_entry> {
|
||||||
|
uint16 start;
|
||||||
|
uint16 length;
|
||||||
|
uint32 cached_blocks;
|
||||||
|
Journal *journal;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Journal::Journal(Volume *volume)
|
Journal::Journal(Volume *volume)
|
||||||
:
|
:
|
||||||
fVolume(volume),
|
fVolume(volume),
|
||||||
@@ -189,19 +197,20 @@ Journal::blockNotify(int32 transactionID, void *arg)
|
|||||||
|
|
||||||
// Set log_start pointer if possible...
|
// Set log_start pointer if possible...
|
||||||
|
|
||||||
if (logEntry == journal->fEntries.head) {
|
if (logEntry == journal->fEntries.First()) {
|
||||||
if (logEntry->Next() != NULL) {
|
log_entry *next = journal->fEntries.GetNext(logEntry);
|
||||||
int32 length = logEntry->next->start - logEntry->start;
|
if (next != NULL) {
|
||||||
|
int32 length = next->start - logEntry->start;
|
||||||
superBlock.log_start = (superBlock.log_start + length) % journal->fLogSize;
|
superBlock.log_start = (superBlock.log_start + length) % journal->fLogSize;
|
||||||
} else
|
} else
|
||||||
superBlock.log_start = journal->fVolume->LogEnd();
|
superBlock.log_start = journal->fVolume->LogEnd();
|
||||||
|
|
||||||
update = true;
|
update = true;
|
||||||
}
|
}
|
||||||
journal->fUsed -= logEntry->length;
|
|
||||||
|
|
||||||
journal->fEntriesLock.Lock();
|
journal->fEntriesLock.Lock();
|
||||||
logEntry->Remove();
|
journal->fUsed -= logEntry->length;
|
||||||
|
journal->fEntries.Remove(logEntry);
|
||||||
journal->fEntriesLock.Unlock();
|
journal->fEntriesLock.Unlock();
|
||||||
|
|
||||||
free(logEntry);
|
free(logEntry);
|
||||||
@@ -214,7 +223,11 @@ Journal::blockNotify(int32 transactionID, void *arg)
|
|||||||
if (superBlock.log_start == superBlock.log_end)
|
if (superBlock.log_start == superBlock.log_end)
|
||||||
superBlock.flags = SUPER_BLOCK_DISK_CLEAN;
|
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;
|
logPosition = (logPosition + 1) % fLogSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create and add log entry
|
||||||
|
|
||||||
log_entry *logEntry = (log_entry *)malloc(sizeof(log_entry));
|
log_entry *logEntry = (log_entry *)malloc(sizeof(log_entry));
|
||||||
if (logEntry != NULL) {
|
if (logEntry == NULL) {
|
||||||
logEntry->start = logStart;
|
DIE(("Could not create next log entry (out of memory)\n"));
|
||||||
logEntry->length = TransactionSize();
|
return B_NO_MEMORY;
|
||||||
logEntry->journal = this;
|
|
||||||
|
|
||||||
fEntriesLock.Lock();
|
|
||||||
fEntries.Add(logEntry);
|
|
||||||
fEntriesLock.Unlock();
|
|
||||||
|
|
||||||
fCurrent = logEntry;
|
|
||||||
fUsed += logEntry->length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// If the log goes to the next round (the log is written as a
|
||||||
// circular buffer), all blocks will be flushed out which is
|
// circular buffer), all blocks will be flushed out which is
|
||||||
@@ -313,19 +345,7 @@ Journal::WriteLogEntry()
|
|||||||
if (logPosition < logStart)
|
if (logPosition < logStart)
|
||||||
fVolume->FlushDevice();
|
fVolume->FlushDevice();
|
||||||
|
|
||||||
// We need to flush the drives own cache here to ensure
|
return status;
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
|
||||||
#ifdef USER
|
#ifdef USER
|
||||||
# include "myfs.h"
|
# include "myfs.h"
|
||||||
@@ -23,12 +24,8 @@
|
|||||||
#include "Utility.h"
|
#include "Utility.h"
|
||||||
|
|
||||||
|
|
||||||
struct log_entry : node<log_entry> {
|
struct log_entry;
|
||||||
uint16 start;
|
typedef DoublyLinkedList<log_entry> LogEntryList;
|
||||||
uint16 length;
|
|
||||||
uint32 cached_blocks;
|
|
||||||
Journal *journal;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Locking policy in BFS: if you need both, the volume lock and the
|
// 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);
|
static void blockNotify(int32 transactionID, void *arg);
|
||||||
status_t TransactionDone(bool success);
|
status_t TransactionDone(bool success);
|
||||||
|
|
||||||
Volume *fVolume;
|
Volume *fVolume;
|
||||||
RecursiveLock fLock;
|
RecursiveLock fLock;
|
||||||
Transaction *fOwner;
|
Transaction *fOwner;
|
||||||
BlockArray fArray;
|
BlockArray fArray;
|
||||||
uint32 fLogSize, fMaxTransactionSize, fUsed;
|
uint32 fLogSize, fMaxTransactionSize, fUsed;
|
||||||
int32 fTransactionsInEntry;
|
int32 fTransactionsInEntry;
|
||||||
SimpleLock fEntriesLock;
|
SimpleLock fEntriesLock;
|
||||||
list<log_entry> fEntries;
|
LogEntryList fEntries;
|
||||||
log_entry *fCurrent;
|
bool fHasChangedBlocks;
|
||||||
bool fHasChangedBlocks;
|
bigtime_t fTimestamp;
|
||||||
bigtime_t fTimestamp;
|
int32 fTransactionID;
|
||||||
int32 fTransactionID;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Utility - some helper classes
|
/* Utility - some helper classes
|
||||||
*
|
*
|
||||||
* Copyright 2001-2004, Axel Dörfler, [email protected].
|
* Copyright 2001-2005, Axel Dörfler, [email protected].
|
||||||
* This file may be used under the terms of the MIT License.
|
* This file may be used under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef UTILITY_H
|
#ifndef UTILITY_H
|
||||||
@@ -63,47 +63,4 @@ class BlockArray {
|
|||||||
int32 fMaxBlocks;
|
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 */
|
#endif /* UTILITY_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user