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

[PATCH] JBD: implement journal->j_free locking

Implement the designed locking around journal->j_free.

Things get a lot better here, too.
parent 2e89f6eb
...@@ -70,25 +70,33 @@ static int __try_to_free_cp_buf(struct journal_head *jh) ...@@ -70,25 +70,33 @@ static int __try_to_free_cp_buf(struct journal_head *jh)
} }
/* /*
* log_wait_for_space: wait until there is space in the journal. * __log_wait_for_space: wait until there is space in the journal.
* *
* Called with the journal already locked, but it will be unlocked if we have * Called under j-state_lock *only*. It will be unlocked if we have to wait
* to wait for a checkpoint to free up some space in the log. * for a checkpoint to free up some space in the log.
*/ */
void log_wait_for_space(journal_t *journal, int nblocks) void __log_wait_for_space(journal_t *journal, int nblocks)
{ {
while (log_space_left(journal) < nblocks) { assert_spin_locked(&journal->j_state_lock);
while (__log_space_left(journal) < nblocks) {
if (journal->j_flags & JFS_ABORT) if (journal->j_flags & JFS_ABORT)
return; return;
unlock_journal(journal); unlock_journal(journal);
spin_unlock(&journal->j_state_lock);
down(&journal->j_checkpoint_sem); down(&journal->j_checkpoint_sem);
lock_journal(journal); lock_journal(journal);
/* Test again, another process may have checkpointed /*
* while we were waiting for the checkpoint lock */ * Test again, another process may have checkpointed while we
if (log_space_left(journal) < nblocks) { * were waiting for the checkpoint lock
*/
spin_lock(&journal->j_state_lock);
if (__log_space_left(journal) < nblocks) {
spin_unlock(&journal->j_state_lock);
log_do_checkpoint(journal, nblocks); log_do_checkpoint(journal, nblocks);
spin_lock(&journal->j_state_lock);
} }
up(&journal->j_checkpoint_sem); up(&journal->j_checkpoint_sem);
} }
...@@ -275,7 +283,7 @@ static int __flush_buffer(journal_t *journal, struct journal_head *jh, ...@@ -275,7 +283,7 @@ static int __flush_buffer(journal_t *journal, struct journal_head *jh,
* Perform an actual checkpoint. We don't write out only enough to * Perform an actual checkpoint. We don't write out only enough to
* satisfy the current blocked requests: rather we submit a reasonably * satisfy the current blocked requests: rather we submit a reasonably
* sized chunk of the outstanding data to disk at once for * sized chunk of the outstanding data to disk at once for
* efficiency. log_wait_for_space() will retry if we didn't free enough. * efficiency. __log_wait_for_space() will retry if we didn't free enough.
* *
* However, we _do_ take into account the amount requested so that once * However, we _do_ take into account the amount requested so that once
* the IO has been queued, we can return as soon as enough of it has * the IO has been queued, we can return as soon as enough of it has
......
...@@ -392,17 +392,23 @@ int journal_write_metadata_buffer(transaction_t *transaction, ...@@ -392,17 +392,23 @@ int journal_write_metadata_buffer(transaction_t *transaction,
*/ */
/* /*
* log_space_left: Return the number of free blocks left in the journal. * __log_space_left: Return the number of free blocks left in the journal.
* *
* Called with the journal already locked. * Called with the journal already locked.
*
* Called under j_state_lock
*/ */
int log_space_left (journal_t *journal) int __log_space_left(journal_t *journal)
{ {
int left = journal->j_free; int left = journal->j_free;
/* Be pessimistic here about the number of those free blocks assert_spin_locked(&journal->j_state_lock);
* which might be required for log descriptor control blocks. */
/*
* Be pessimistic here about the number of those free blocks which
* might be required for log descriptor control blocks.
*/
#define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */ #define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */
......
...@@ -219,12 +219,10 @@ static int start_this_handle(journal_t *journal, handle_t *handle) ...@@ -219,12 +219,10 @@ static int start_this_handle(journal_t *journal, handle_t *handle)
needed += journal->j_committing_transaction-> needed += journal->j_committing_transaction->
t_outstanding_credits; t_outstanding_credits;
if (log_space_left(journal) < needed) { if (__log_space_left(journal) < needed) {
jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle);
spin_unlock(&transaction->t_handle_lock); spin_unlock(&transaction->t_handle_lock);
spin_unlock(&journal->j_state_lock); __log_wait_for_space(journal, needed);
log_wait_for_space(journal, needed);
spin_lock(&journal->j_state_lock);
goto repeat_locked; goto repeat_locked;
} }
...@@ -237,7 +235,7 @@ static int start_this_handle(journal_t *journal, handle_t *handle) ...@@ -237,7 +235,7 @@ static int start_this_handle(journal_t *journal, handle_t *handle)
transaction->t_handle_count++; transaction->t_handle_count++;
jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n",
handle, nblocks, transaction->t_outstanding_credits, handle, nblocks, transaction->t_outstanding_credits,
log_space_left(journal)); __log_space_left(journal));
spin_unlock(&transaction->t_handle_lock); spin_unlock(&transaction->t_handle_lock);
spin_unlock(&journal->j_state_lock); spin_unlock(&journal->j_state_lock);
unlock_journal(journal); unlock_journal(journal);
...@@ -330,14 +328,16 @@ int journal_extend(handle_t *handle, int nblocks) ...@@ -330,14 +328,16 @@ int journal_extend(handle_t *handle, int nblocks)
int result; int result;
int wanted; int wanted;
lock_journal (journal); lock_journal(journal);
result = -EIO; result = -EIO;
if (is_handle_aborted(handle)) if (is_handle_aborted(handle))
goto error_out; goto error_out;
result = 1; result = 1;
spin_lock(&journal->j_state_lock);
/* Don't extend a locked-down transaction! */ /* Don't extend a locked-down transaction! */
if (handle->h_transaction->t_state != T_RUNNING) { if (handle->h_transaction->t_state != T_RUNNING) {
jbd_debug(3, "denied handle %p %d blocks: " jbd_debug(3, "denied handle %p %d blocks: "
...@@ -345,7 +345,6 @@ int journal_extend(handle_t *handle, int nblocks) ...@@ -345,7 +345,6 @@ int journal_extend(handle_t *handle, int nblocks)
goto error_out; goto error_out;
} }
lock_kernel();
spin_lock(&transaction->t_handle_lock); spin_lock(&transaction->t_handle_lock);
wanted = transaction->t_outstanding_credits + nblocks; wanted = transaction->t_outstanding_credits + nblocks;
...@@ -355,7 +354,7 @@ int journal_extend(handle_t *handle, int nblocks) ...@@ -355,7 +354,7 @@ int journal_extend(handle_t *handle, int nblocks)
goto unlock; goto unlock;
} }
if (wanted > log_space_left(journal)) { if (wanted > __log_space_left(journal)) {
jbd_debug(3, "denied handle %p %d blocks: " jbd_debug(3, "denied handle %p %d blocks: "
"insufficient log space\n", handle, nblocks); "insufficient log space\n", handle, nblocks);
goto unlock; goto unlock;
...@@ -368,9 +367,9 @@ int journal_extend(handle_t *handle, int nblocks) ...@@ -368,9 +367,9 @@ int journal_extend(handle_t *handle, int nblocks)
jbd_debug(3, "extended handle %p by %d\n", handle, nblocks); jbd_debug(3, "extended handle %p by %d\n", handle, nblocks);
unlock: unlock:
spin_unlock(&transaction->t_handle_lock); spin_unlock(&transaction->t_handle_lock);
unlock_kernel();
error_out: error_out:
unlock_journal (journal); spin_unlock(&journal->j_state_lock);
unlock_journal(journal);
return result; return result;
} }
......
...@@ -1000,18 +1000,19 @@ extern int journal_test_revoke(journal_t *, unsigned long, tid_t); ...@@ -1000,18 +1000,19 @@ extern int journal_test_revoke(journal_t *, unsigned long, tid_t);
extern void journal_clear_revoke(journal_t *); extern void journal_clear_revoke(journal_t *);
extern void journal_brelse_array(struct buffer_head *b[], int n); extern void journal_brelse_array(struct buffer_head *b[], int n);
/* The log thread user interface: /*
* The log thread user interface:
* *
* Request space in the current transaction, and force transaction commit * Request space in the current transaction, and force transaction commit
* transitions on demand. * transitions on demand.
*/ */
extern int log_space_left (journal_t *); /* Called with journal locked */ int __log_space_left(journal_t *); /* Called with journal locked */
extern tid_t log_start_commit (journal_t *, transaction_t *); extern tid_t log_start_commit (journal_t *, transaction_t *);
extern int log_wait_commit (journal_t *, tid_t); extern int log_wait_commit (journal_t *, tid_t);
extern int log_do_checkpoint (journal_t *, int); extern int log_do_checkpoint (journal_t *, int);
extern void log_wait_for_space(journal_t *, int nblocks); void __log_wait_for_space(journal_t *, int nblocks);
extern void __journal_drop_transaction(journal_t *, transaction_t *); extern void __journal_drop_transaction(journal_t *, transaction_t *);
extern int cleanup_journal_tail(journal_t *); extern int cleanup_journal_tail(journal_t *);
......
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