Commit e63ebf6b authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] JBD: implement j_running_transaction locking

Implement the designed locking around journal->j_running_transaction.

A lot more of the new locking scheme falls into place.
parent 152dede7
...@@ -399,7 +399,7 @@ int cleanup_journal_tail(journal_t *journal) ...@@ -399,7 +399,7 @@ int cleanup_journal_tail(journal_t *journal)
* next transaction ID we will write, and where it will * next transaction ID we will write, and where it will
* start. */ * start. */
/* j_checkpoint_transactions needs locking */ spin_lock(&journal->j_state_lock);
spin_lock(&journal->j_list_lock); spin_lock(&journal->j_list_lock);
transaction = journal->j_checkpoint_transactions; transaction = journal->j_checkpoint_transactions;
if (transaction) { if (transaction) {
...@@ -416,6 +416,7 @@ int cleanup_journal_tail(journal_t *journal) ...@@ -416,6 +416,7 @@ int cleanup_journal_tail(journal_t *journal)
blocknr = journal->j_head; blocknr = journal->j_head;
} }
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
spin_unlock(&journal->j_state_lock);
J_ASSERT (blocknr != 0); J_ASSERT (blocknr != 0);
/* If the oldest pinned transaction is at the tail of the log /* If the oldest pinned transaction is at the tail of the log
......
...@@ -62,7 +62,7 @@ void journal_commit_transaction(journal_t *journal) ...@@ -62,7 +62,7 @@ void journal_commit_transaction(journal_t *journal)
* all outstanding updates to complete. * all outstanding updates to complete.
*/ */
lock_journal(journal); /* Protect journal->j_running_transaction */ lock_journal(journal);
#ifdef COMMIT_STATS #ifdef COMMIT_STATS
spin_lock(&journal->j_list_lock); spin_lock(&journal->j_list_lock);
...@@ -72,14 +72,14 @@ void journal_commit_transaction(journal_t *journal) ...@@ -72,14 +72,14 @@ void journal_commit_transaction(journal_t *journal)
lock_kernel(); lock_kernel();
J_ASSERT (journal->j_running_transaction != NULL); J_ASSERT(journal->j_running_transaction != NULL);
J_ASSERT (journal->j_committing_transaction == NULL); J_ASSERT(journal->j_committing_transaction == NULL);
commit_transaction = journal->j_running_transaction; commit_transaction = journal->j_running_transaction;
J_ASSERT (commit_transaction->t_state == T_RUNNING); J_ASSERT(commit_transaction->t_state == T_RUNNING);
jbd_debug (1, "JBD: starting commit of transaction %d\n", jbd_debug(1, "JBD: starting commit of transaction %d\n",
commit_transaction->t_tid); commit_transaction->t_tid);
commit_transaction->t_state = T_LOCKED; commit_transaction->t_state = T_LOCKED;
...@@ -158,14 +158,13 @@ void journal_commit_transaction(journal_t *journal) ...@@ -158,14 +158,13 @@ void journal_commit_transaction(journal_t *journal)
* get a new running transaction for incoming filesystem updates * get a new running transaction for incoming filesystem updates
*/ */
spin_lock(&journal->j_state_lock);
commit_transaction->t_state = T_FLUSH; commit_transaction->t_state = T_FLUSH;
wake_up(&journal->j_wait_transaction_locked);
journal->j_committing_transaction = commit_transaction; journal->j_committing_transaction = commit_transaction;
journal->j_running_transaction = NULL; journal->j_running_transaction = NULL;
commit_transaction->t_log_start = journal->j_head; commit_transaction->t_log_start = journal->j_head;
wake_up(&journal->j_wait_transaction_locked);
spin_unlock(&journal->j_state_lock);
unlock_kernel(); unlock_kernel();
......
...@@ -417,14 +417,10 @@ int log_space_left (journal_t *journal) ...@@ -417,14 +417,10 @@ int log_space_left (journal_t *journal)
/* /*
* This function must be non-allocating for PF_MEMALLOC tasks * This function must be non-allocating for PF_MEMALLOC tasks
*/ */
tid_t log_start_commit (journal_t *journal, transaction_t *transaction) static tid_t __log_start_commit(journal_t *journal, transaction_t *transaction)
{ {
tid_t target; tid_t target = journal->j_commit_request;
lock_kernel(); /* Protect journal->j_running_transaction */
target = journal->j_commit_request;
/* /*
* A NULL transaction asks us to commit the currently running * A NULL transaction asks us to commit the currently running
* transaction, if there is one. * transaction, if there is one.
...@@ -456,10 +452,19 @@ tid_t log_start_commit (journal_t *journal, transaction_t *transaction) ...@@ -456,10 +452,19 @@ tid_t log_start_commit (journal_t *journal, transaction_t *transaction)
wake_up(&journal->j_wait_commit); wake_up(&journal->j_wait_commit);
out: out:
unlock_kernel();
return target; return target;
} }
tid_t log_start_commit(journal_t *journal, transaction_t *transaction)
{
tid_t ret;
spin_lock(&journal->j_state_lock);
ret = __log_start_commit(journal, transaction);
spin_unlock(&journal->j_state_lock);
return ret;
}
/* /*
* Wait for a specified commit to complete. * Wait for a specified commit to complete.
* The caller may not hold the journal lock. * The caller may not hold the journal lock.
...@@ -1205,24 +1210,30 @@ static int journal_convert_superblock_v1(journal_t *journal, ...@@ -1205,24 +1210,30 @@ static int journal_convert_superblock_v1(journal_t *journal,
* recovery does not need to happen on remount. * recovery does not need to happen on remount.
*/ */
int journal_flush (journal_t *journal) int journal_flush(journal_t *journal)
{ {
int err = 0; int err = 0;
transaction_t *transaction = NULL; transaction_t *transaction = NULL;
unsigned long old_tail; unsigned long old_tail;
lock_kernel(); spin_lock(&journal->j_state_lock);
/* Force everything buffered to the log... */ /* Force everything buffered to the log... */
if (journal->j_running_transaction) { if (journal->j_running_transaction) {
transaction = journal->j_running_transaction; transaction = journal->j_running_transaction;
log_start_commit(journal, transaction); __log_start_commit(journal, transaction);
} else if (journal->j_committing_transaction) } else if (journal->j_committing_transaction)
transaction = journal->j_committing_transaction; transaction = journal->j_committing_transaction;
/* Wait for the log commit to complete... */ /* Wait for the log commit to complete... */
if (transaction) if (transaction) {
log_wait_commit(journal, transaction->t_tid); tid_t tid = transaction->t_tid;
spin_unlock(&journal->j_state_lock);
log_wait_commit(journal, tid);
} else {
spin_unlock(&journal->j_state_lock);
}
/* ...and flush everything in the log out to disk. */ /* ...and flush everything in the log out to disk. */
lock_journal(journal); lock_journal(journal);
...@@ -1247,8 +1258,6 @@ int journal_flush (journal_t *journal) ...@@ -1247,8 +1258,6 @@ int journal_flush (journal_t *journal)
J_ASSERT(!journal->j_checkpoint_transactions); J_ASSERT(!journal->j_checkpoint_transactions);
J_ASSERT(journal->j_head == journal->j_tail); J_ASSERT(journal->j_head == journal->j_tail);
J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence); J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence);
unlock_kernel();
return err; return err;
} }
...@@ -1318,10 +1327,12 @@ const char *journal_dev_name(journal_t *journal, char *buffer) ...@@ -1318,10 +1327,12 @@ const char *journal_dev_name(journal_t *journal, char *buffer)
* itself are here. * itself are here.
*/ */
/* Quick version for internal journal use (doesn't lock the journal). /*
* Quick version for internal journal use (doesn't lock the journal).
* Aborts hard --- we mark the abort as occurred, but do _nothing_ else, * Aborts hard --- we mark the abort as occurred, but do _nothing_ else,
* and don't attempt to make any other journal updates. */ * and don't attempt to make any other journal updates.
void __journal_abort_hard (journal_t *journal) */
void __journal_abort_hard(journal_t *journal)
{ {
transaction_t *transaction; transaction_t *transaction;
char b[BDEVNAME_SIZE]; char b[BDEVNAME_SIZE];
...@@ -1329,15 +1340,15 @@ void __journal_abort_hard (journal_t *journal) ...@@ -1329,15 +1340,15 @@ void __journal_abort_hard (journal_t *journal)
if (journal->j_flags & JFS_ABORT) if (journal->j_flags & JFS_ABORT)
return; return;
printk (KERN_ERR "Aborting journal on device %s.\n", printk(KERN_ERR "Aborting journal on device %s.\n",
journal_dev_name(journal, b)); journal_dev_name(journal, b));
lock_kernel(); spin_lock(&journal->j_state_lock);
journal->j_flags |= JFS_ABORT; journal->j_flags |= JFS_ABORT;
transaction = journal->j_running_transaction; transaction = journal->j_running_transaction;
if (transaction) if (transaction)
log_start_commit(journal, transaction); __log_start_commit(journal, transaction);
unlock_kernel(); spin_unlock(&journal->j_state_lock);
} }
/* Soft abort: record the abort error status in the journal superblock, /* Soft abort: record the abort error status in the journal superblock,
......
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
* The journal MUST be locked. We don't perform atomic mallocs on the * The journal MUST be locked. We don't perform atomic mallocs on the
* new transaction and we can't block without protecting against other * new transaction and we can't block without protecting against other
* processes trying to touch the journal while it is in transition. * processes trying to touch the journal while it is in transition.
*
* Called under j_state_lock
*/ */
static transaction_t * static transaction_t *
...@@ -443,13 +445,14 @@ void journal_lock_updates(journal_t *journal) ...@@ -443,13 +445,14 @@ void journal_lock_updates(journal_t *journal)
spin_lock(&journal->j_state_lock); spin_lock(&journal->j_state_lock);
++journal->j_barrier_count; ++journal->j_barrier_count;
spin_unlock(&journal->j_state_lock);
/* Wait until there are no running updates */ /* Wait until there are no running updates */
while (1) { while (1) {
transaction_t *transaction = journal->j_running_transaction; transaction_t *transaction = journal->j_running_transaction;
if (!transaction) if (!transaction)
break; break;
spin_lock(&transaction->t_handle_lock); spin_lock(&transaction->t_handle_lock);
if (!transaction->t_updates) { if (!transaction->t_updates) {
spin_unlock(&transaction->t_handle_lock); spin_unlock(&transaction->t_handle_lock);
...@@ -458,12 +461,14 @@ void journal_lock_updates(journal_t *journal) ...@@ -458,12 +461,14 @@ void journal_lock_updates(journal_t *journal)
prepare_to_wait(&journal->j_wait_updates, &wait, prepare_to_wait(&journal->j_wait_updates, &wait,
TASK_UNINTERRUPTIBLE); TASK_UNINTERRUPTIBLE);
spin_unlock(&transaction->t_handle_lock); spin_unlock(&transaction->t_handle_lock);
spin_unlock(&journal->j_state_lock);
unlock_journal(journal); unlock_journal(journal);
schedule(); schedule();
finish_wait(&journal->j_wait_updates, &wait); finish_wait(&journal->j_wait_updates, &wait);
lock_journal(journal); lock_journal(journal);
spin_lock(&journal->j_state_lock);
} }
spin_unlock(&journal->j_state_lock);
unlock_journal(journal); unlock_journal(journal);
/* /*
...@@ -1781,6 +1786,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) ...@@ -1781,6 +1786,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
if (!buffer_jbd(bh)) if (!buffer_jbd(bh))
goto zap_buffer_unlocked; goto zap_buffer_unlocked;
spin_lock(&journal->j_state_lock);
jbd_lock_bh_state(bh); jbd_lock_bh_state(bh);
spin_lock(&journal->j_list_lock); spin_lock(&journal->j_list_lock);
jh = bh2jh(bh); jh = bh2jh(bh);
...@@ -1813,6 +1819,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) ...@@ -1813,6 +1819,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
journal->j_running_transaction); journal->j_running_transaction);
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
spin_unlock(&journal->j_state_lock);
return ret; return ret;
} else { } else {
/* There is no currently-running transaction. So the /* There is no currently-running transaction. So the
...@@ -1825,6 +1832,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) ...@@ -1825,6 +1832,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
journal->j_committing_transaction); journal->j_committing_transaction);
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
spin_unlock(&journal->j_state_lock);
return ret; return ret;
} else { } else {
/* The orphan record's transaction has /* The orphan record's transaction has
...@@ -1847,6 +1855,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) ...@@ -1847,6 +1855,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
} }
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
spin_unlock(&journal->j_state_lock);
return 0; return 0;
} else { } else {
/* Good, the buffer belongs to the running transaction. /* Good, the buffer belongs to the running transaction.
...@@ -1862,6 +1871,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh) ...@@ -1862,6 +1871,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
zap_buffer: zap_buffer:
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
spin_unlock(&journal->j_state_lock);
zap_buffer_unlocked: zap_buffer_unlocked:
clear_buffer_dirty(bh); clear_buffer_dirty(bh);
J_ASSERT_BH(bh, !buffer_jbddirty(bh)); J_ASSERT_BH(bh, !buffer_jbddirty(bh));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment