The commit sets the transaction to T_COMMITTED after the commit block
is on disk, with the journal lock dropped for the I/O.  The write-hazard
path reads the committing transaction's state under the lock to decide
whether a pager write may go home.  The unlocked store is a data race.
It is harmless in practice: a reader that still sees T_FLUSHING only
intercepts the write, and the store follows the device flush, so it
cannot be seen before the commit block is on disk.  Every other state
change is made under the lock so lets stay consistent and make this one
do the same as well.
---
 ext2fs/journal.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/ext2fs/journal.c b/ext2fs/journal.c
index 2ab8802ff..37139056e 100644
--- a/ext2fs/journal.c
+++ b/ext2fs/journal.c
@@ -2623,8 +2623,11 @@ journal_commit_running_transaction_locked (journal_t 
*journal)
   /* Ensure Commit is persistent */
   flush_to_disk ();
 
-  /* The WAL barrier is crossed! Tell the Pager it can write safely! */
+  /* The WAL barrier is crossed! Tell the Pager it can write safely!
+     The write-hazard path reads the state under the lock.  */
+  JOURNAL_LOCK (journal);
   txn->t_state = T_COMMITTED;
+  JOURNAL_UNLOCK (journal);
   /* Flush any intercepted VM pager blocks to the primary disk */
   journal_flush_intercepted_payloads (journal, txn);
 
-- 
2.56.0


Reply via email to