From 98e10fd47f98c697df4c06f765a6df5f0420dcc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 25 Mar 2008 19:12:15 +0000 Subject: [PATCH] * _TransactionSize() did not take the block array into account. * Therefore, the log was not flushed often enough: _WriteTransactionToLog() did not check again, and would eventually overwrite incomplete transactions (leading to a corrupted log on reboot)! * _TransactionDone() now only flushes the log if the new transaction will be joined; _WriteTransactionToLog() now checks itself if there is enough space left to actually write the log entry. * Added a TODO about the logging code not being endian-aware. * Renamed _BlockNotify() to _TransactionNotify() as only complete transactions are notified, it's not working on block level anymore. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24577 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/file_systems/bfs/Journal.cpp | 52 +++++++++++-------- src/add-ons/kernel/file_systems/bfs/Journal.h | 13 ++--- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/add-ons/kernel/file_systems/bfs/Journal.cpp b/src/add-ons/kernel/file_systems/bfs/Journal.cpp index 74161527ea..306f6c4e64 100644 --- a/src/add-ons/kernel/file_systems/bfs/Journal.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Journal.cpp @@ -526,39 +526,38 @@ Journal::ReplayLog() /*! This is a callback function that is called by the cache, whenever - a block is flushed to disk that was updated as part of a transaction. - This is necessary to keep track of completed transactions, to be - able to update the log start pointer. + all blocks of a transaction have been flushed to disk. + This lets us keep track of completed transactions, and update + the log start pointer as needed. Note, the transactions may not be + completed in the order they were written. */ void -Journal::_BlockNotify(int32 transactionID, int32 event, void *arg) +Journal::_TransactionNotify(int32 transactionID, int32 event, void *_logEntry) { - LogEntry *logEntry = (LogEntry *)arg; + LogEntry *logEntry = (LogEntry *)_logEntry; if (event != TRANSACTION_WRITTEN) return; - PRINT(("Log entry %p has been finished, transaction ID = %ld\n", logEntry, transactionID)); + PRINT(("Log entry %p has been finished, transaction ID = %ld\n", logEntry, + transactionID)); Journal *journal = logEntry->GetJournal(); disk_super_block &superBlock = journal->fVolume->SuperBlock(); bool update = false; // Set log_start pointer if possible... + // TODO: this is not endian safe! journal->fEntriesLock.Lock(); if (logEntry == journal->fEntries.First()) { LogEntry *next = journal->fEntries.GetNext(logEntry); - if (next != NULL) { - int32 length = next->Start() - logEntry->Start(); - // log entries inbetween could have been already released, so - // we can't just use LogEntry::Length() here - superBlock.log_start = superBlock.log_start + length; - } else + if (next != NULL) + superBlock.log_start = next->Start() % journal->fLogSize; + else superBlock.log_start = journal->fVolume->LogEnd(); - superBlock.log_start %= journal->fLogSize; update = true; } @@ -654,6 +653,11 @@ Journal::_WriteTransactionToLog() return B_OK; } + // If necessary, flush the log, so that we have enough space for this + // transaction + if (runArrays.LogEntryLength() > FreeLogBlocks()) + cache_sync_transaction(fVolume->BlockCache(), fTransactionID); + // Write log entries to disk int32 maxVecs = runArrays.MaxArrayLength() + 1; @@ -759,11 +763,11 @@ Journal::_WriteTransactionToLog() if (detached) { fTransactionID = cache_detach_sub_transaction(fVolume->BlockCache(), - fTransactionID, _BlockNotify, logEntry); + fTransactionID, _TransactionNotify, logEntry); fUnwrittenTransactions = 1; } else { cache_end_transaction(fVolume->BlockCache(), fTransactionID, - _BlockNotify, logEntry); + _TransactionNotify, logEntry); fUnwrittenTransactions = 0; } @@ -866,7 +870,10 @@ Journal::_TransactionSize() const if (count < 0) return 0; - return count; + // take the number of array blocks in this transaction into account + uint32 maxRuns = run_array::MaxRuns(fVolume->BlockSize()); + uint32 arrayBlocks = (count + maxRuns - 1) / maxRuns; + return count + arrayBlocks; } @@ -882,14 +889,15 @@ Journal::_TransactionDone(bool success) return B_OK; } - // If necessary, flush the log, so that we have enough space for this - // transaction - if (_TransactionSize() > FreeLogBlocks()) - cache_sync_transaction(fVolume->BlockCache(), fTransactionID); - // Up to a maximum size, we will just batch several // transactions together to improve speed - if (_TransactionSize() < fMaxTransactionSize) { + uint32 size = _TransactionSize(); + if (size < fMaxTransactionSize) { + // Flush the log from time to time, so that we have enough space + // for this transaction + if (size > FreeLogBlocks()) + cache_sync_transaction(fVolume->BlockCache(), fTransactionID); + fUnwrittenTransactions++; return B_OK; } diff --git a/src/add-ons/kernel/file_systems/bfs/Journal.h b/src/add-ons/kernel/file_systems/bfs/Journal.h index 4f133745eb..827acd2b6e 100644 --- a/src/add-ons/kernel/file_systems/bfs/Journal.h +++ b/src/add-ons/kernel/file_systems/bfs/Journal.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2001-2008, Axel Dörfler, axeld@pinc-software.de. * This file may be used under the terms of the MIT License. */ #ifndef JOURNAL_H @@ -34,7 +34,7 @@ class Journal { public: Journal(Volume *); ~Journal(); - + status_t InitCheck(); status_t Lock(Transaction *owner); @@ -57,7 +57,8 @@ class Journal { status_t _CheckRunArray(const run_array *array); status_t _ReplayRunArray(int32 *start); status_t _TransactionDone(bool success); - static void _BlockNotify(int32 transactionID, int32 event, void *arg); + static void _TransactionNotify(int32 transactionID, int32 event, + void *_logEntry); Volume *fVolume; RecursiveLock fLock; @@ -72,11 +73,11 @@ class Journal { }; -inline uint32 +inline uint32 Journal::FreeLogBlocks() const { - return fVolume->LogStart() <= fVolume->LogEnd() ? - fLogSize - fVolume->LogEnd() + fVolume->LogStart() + return fVolume->LogStart() <= fVolume->LogEnd() + ? fLogSize - fVolume->LogEnd() + fVolume->LogStart() : fVolume->LogStart() - fVolume->LogEnd(); }