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 | |
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')
-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 | /* |