Skip to content

Commit

Permalink
jbd2: avoid pointless scanning of checkpoint lists
Browse files Browse the repository at this point in the history
Yuanhan has reported that when he is running fsync(2) heavy workload
creating new files over ramdisk, significant amount of time is spent in
__jbd2_journal_clean_checkpoint_list() trying to clean old transactions
(but they cannot be cleaned up because flusher hasn't yet checkpointed
those buffers). The workload can be generated by:
  fs_mark -d /fs/ram0/1 -D 2 -N 2560 -n 1000000 -L 1 -S 1 -s 4096

Reduce the amount of scanning by stopping to scan the transaction list
once we find a transaction that cannot be checkpointed. Note that this
way of cleaning is still enough to keep freeing space in the journal
after fully checkpointed transactions.

Reported-and-tested-by: Yuanhan Liu <[email protected]>
Signed-off-by: Jan Kara <[email protected]>
Signed-off-by: Theodore Ts'o <[email protected]>
  • Loading branch information
jankara authored and tytso committed Sep 18, 2014
1 parent 8447497 commit cc97f1a
Showing 1 changed file with 18 additions and 14 deletions.
32 changes: 18 additions & 14 deletions fs/jbd2/checkpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,6 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
* Find all the written-back checkpoint buffers in the given list and
* release them.
*
* Called with the journal locked.
* Called with j_list_lock held.
* Returns number of buffers reaped (for debug)
*/
Expand All @@ -440,12 +439,12 @@ static int journal_clean_one_cp_list(struct journal_head *jh, int *released)
jh = next_jh;
next_jh = jh->b_cpnext;
ret = __try_to_free_cp_buf(jh);
if (ret) {
freed++;
if (ret == 2) {
*released = 1;
return freed;
}
if (!ret)
return freed;
freed++;
if (ret == 2) {
*released = 1;
return freed;
}
/*
* This function only frees up some memory
Expand All @@ -465,15 +464,15 @@ static int journal_clean_one_cp_list(struct journal_head *jh, int *released)
*
* Find all the written-back checkpoint buffers in the journal and release them.
*
* Called with the journal locked.
* Called with j_list_lock held.
* Returns number of buffers reaped (for debug)
*/

int __jbd2_journal_clean_checkpoint_list(journal_t *journal)
{
transaction_t *transaction, *last_transaction, *next_transaction;
int ret = 0;
int ret;
int freed = 0;
int released;

transaction = journal->j_checkpoint_transactions;
Expand All @@ -485,29 +484,34 @@ int __jbd2_journal_clean_checkpoint_list(journal_t *journal)
do {
transaction = next_transaction;
next_transaction = transaction->t_cpnext;
ret += journal_clean_one_cp_list(transaction->
ret = journal_clean_one_cp_list(transaction->
t_checkpoint_list, &released);
/*
* This function only frees up some memory if possible so we
* dont have an obligation to finish processing. Bail out if
* preemption requested:
*/
if (need_resched())
if (need_resched()) {
freed += ret;
goto out;
if (released)
}
if (released) {
freed += ret;
continue;
}
/*
* It is essential that we are as careful as in the case of
* t_checkpoint_list with removing the buffer from the list as
* we can possibly see not yet submitted buffers on io_list
*/
ret += journal_clean_one_cp_list(transaction->
t_checkpoint_io_list, &released);
if (need_resched())
freed += ret;
if (need_resched() || !ret)
goto out;
} while (transaction != last_transaction);
out:
return ret;
return freed;
}

/*
Expand Down

0 comments on commit cc97f1a

Please sign in to comment.