diff options
| author | Jan Kara <jack@suse.cz> | 2014-09-18 00:42:16 -0400 |
|---|---|---|
| committer | Theodore Ts'o <tytso@mit.edu> | 2014-09-18 00:42:16 -0400 |
| commit | cc97f1a7c7eed970e674b84be0e68f479c80228d (patch) | |
| tree | 43d4358c0792994358968b8d1dc2ebef654ba396 /fs/jbd2 | |
| parent | 844749764b416ee2c4ba2da328c04eaad7388242 (diff) | |
jbd2: avoid pointless scanning of checkpoint lists
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 <yuanhan.liu@linux.intel.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs/jbd2')
| -rw-r--r-- | fs/jbd2/checkpoint.c | 32 |
1 files changed, 18 insertions, 14 deletions
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 1fbf59938cc0..3ab4c5ee12ce 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c | |||
| @@ -420,7 +420,6 @@ int jbd2_cleanup_journal_tail(journal_t *journal) | |||
| 420 | * Find all the written-back checkpoint buffers in the given list and | 420 | * Find all the written-back checkpoint buffers in the given list and |
| 421 | * release them. | 421 | * release them. |
| 422 | * | 422 | * |
| 423 | * Called with the journal locked. | ||
| 424 | * Called with j_list_lock held. | 423 | * Called with j_list_lock held. |
| 425 | * Returns number of buffers reaped (for debug) | 424 | * Returns number of buffers reaped (for debug) |
| 426 | */ | 425 | */ |
| @@ -440,12 +439,12 @@ static int journal_clean_one_cp_list(struct journal_head *jh, int *released) | |||
| 440 | jh = next_jh; | 439 | jh = next_jh; |
| 441 | next_jh = jh->b_cpnext; | 440 | next_jh = jh->b_cpnext; |
| 442 | ret = __try_to_free_cp_buf(jh); | 441 | ret = __try_to_free_cp_buf(jh); |
| 443 | if (ret) { | 442 | if (!ret) |
| 444 | freed++; | 443 | return freed; |
| 445 | if (ret == 2) { | 444 | freed++; |
| 446 | *released = 1; | 445 | if (ret == 2) { |
| 447 | return freed; | 446 | *released = 1; |
| 448 | } | 447 | return freed; |
| 449 | } | 448 | } |
| 450 | /* | 449 | /* |
| 451 | * This function only frees up some memory | 450 | * This function only frees up some memory |
| @@ -465,7 +464,6 @@ static int journal_clean_one_cp_list(struct journal_head *jh, int *released) | |||
| 465 | * | 464 | * |
| 466 | * Find all the written-back checkpoint buffers in the journal and release them. | 465 | * Find all the written-back checkpoint buffers in the journal and release them. |
| 467 | * | 466 | * |
| 468 | * Called with the journal locked. | ||
| 469 | * Called with j_list_lock held. | 467 | * Called with j_list_lock held. |
| 470 | * Returns number of buffers reaped (for debug) | 468 | * Returns number of buffers reaped (for debug) |
| 471 | */ | 469 | */ |
| @@ -473,7 +471,8 @@ static int journal_clean_one_cp_list(struct journal_head *jh, int *released) | |||
| 473 | int __jbd2_journal_clean_checkpoint_list(journal_t *journal) | 471 | int __jbd2_journal_clean_checkpoint_list(journal_t *journal) |
| 474 | { | 472 | { |
| 475 | transaction_t *transaction, *last_transaction, *next_transaction; | 473 | transaction_t *transaction, *last_transaction, *next_transaction; |
| 476 | int ret = 0; | 474 | int ret; |
| 475 | int freed = 0; | ||
| 477 | int released; | 476 | int released; |
| 478 | 477 | ||
| 479 | transaction = journal->j_checkpoint_transactions; | 478 | transaction = journal->j_checkpoint_transactions; |
| @@ -485,17 +484,21 @@ int __jbd2_journal_clean_checkpoint_list(journal_t *journal) | |||
| 485 | do { | 484 | do { |
| 486 | transaction = next_transaction; | 485 | transaction = next_transaction; |
| 487 | next_transaction = transaction->t_cpnext; | 486 | next_transaction = transaction->t_cpnext; |
| 488 | ret += journal_clean_one_cp_list(transaction-> | 487 | ret = journal_clean_one_cp_list(transaction-> |
| 489 | t_checkpoint_list, &released); | 488 | t_checkpoint_list, &released); |
| 490 | /* | 489 | /* |
| 491 | * This function only frees up some memory if possible so we | 490 | * This function only frees up some memory if possible so we |
| 492 | * dont have an obligation to finish processing. Bail out if | 491 | * dont have an obligation to finish processing. Bail out if |
| 493 | * preemption requested: | 492 | * preemption requested: |
| 494 | */ | 493 | */ |
| 495 | if (need_resched()) | 494 | if (need_resched()) { |
| 495 | freed += ret; | ||
| 496 | goto out; | 496 | goto out; |
| 497 | if (released) | 497 | } |
| 498 | if (released) { | ||
| 499 | freed += ret; | ||
| 498 | continue; | 500 | continue; |
| 501 | } | ||
| 499 | /* | 502 | /* |
| 500 | * It is essential that we are as careful as in the case of | 503 | * It is essential that we are as careful as in the case of |
| 501 | * t_checkpoint_list with removing the buffer from the list as | 504 | * t_checkpoint_list with removing the buffer from the list as |
| @@ -503,11 +506,12 @@ int __jbd2_journal_clean_checkpoint_list(journal_t *journal) | |||
| 503 | */ | 506 | */ |
| 504 | ret += journal_clean_one_cp_list(transaction-> | 507 | ret += journal_clean_one_cp_list(transaction-> |
| 505 | t_checkpoint_io_list, &released); | 508 | t_checkpoint_io_list, &released); |
| 506 | if (need_resched()) | 509 | freed += ret; |
| 510 | if (need_resched() || !ret) | ||
| 507 | goto out; | 511 | goto out; |
| 508 | } while (transaction != last_transaction); | 512 | } while (transaction != last_transaction); |
| 509 | out: | 513 | out: |
| 510 | return ret; | 514 | return freed; |
| 511 | } | 515 | } |
| 512 | 516 | ||
| 513 | /* | 517 | /* |
