From 3999cdd966d5b37e00b85b58c0baf01688c18890 Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Wed, 7 Mar 2018 17:12:11 +0800 Subject: [PATCH 0301/2944] alinux: jbd2: create jbd2-ckpt thread for journal checkpoint This is trying to do jbd2 checkpoint in a specific kernel thread, then checkpoint won't be under io throttle control. Signed-off-by: Joseph Qi Reviewed-by: Jiufei Xue Signed-off-by: zhangliguang Reviewed by: Baoyou Xie Reviewed-by: Liu Bo Acked-by: Caspar Zhang --- fs/ext4/super.c | 3 +++ fs/jbd2/checkpoint.c | 10 +++++++++- fs/jbd2/journal.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++- include/linux/jbd2.h | 13 ++++++++++++ 4 files changed, 80 insertions(+), 2 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index fd3dbff..890c0f3 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4332,6 +4332,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) } set_task_ioprio(sbi->s_journal->j_task, journal_ioprio); + set_task_ioprio(sbi->s_journal->j_checkpoint_task, journal_ioprio); sbi->s_journal->j_commit_callback = ext4_journal_commit_callback; @@ -5268,6 +5269,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) if (sbi->s_journal) { ext4_init_journal_params(sb, sbi->s_journal); set_task_ioprio(sbi->s_journal->j_task, journal_ioprio); + set_task_ioprio(sbi->s_journal->j_checkpoint_task, + journal_ioprio); } if (*flags & SB_LAZYTIME) diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 02e0b79..1f45de0 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c @@ -143,7 +143,15 @@ void __jbd2_log_wait_for_space(journal_t *journal) spin_unlock(&journal->j_list_lock); write_unlock(&journal->j_state_lock); if (chkpt) { - jbd2_log_do_checkpoint(journal); + DEFINE_WAIT(wait); + prepare_to_wait(&journal->j_wait_done_checkpoint, &wait, + TASK_UNINTERRUPTIBLE); + mutex_unlock(&journal->j_checkpoint_mutex); + wake_up(&journal->j_wait_checkpoint); + schedule(); + mutex_lock(&journal->j_checkpoint_mutex); + finish_wait(&journal->j_wait_done_checkpoint, &wait); + jbd_debug(1, "wake up checkpoint thread.\n"); } else if (jbd2_cleanup_journal_tail(journal) == 0) { /* We were able to recover space; yay! */ ; diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index cb4d251..b780e9e 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -221,6 +221,9 @@ static int kjournald2(void *arg) if (journal->j_flags & JBD2_UNMOUNT) goto end_loop; + if (kthread_should_stop()) + goto end_loop; + jbd_debug(1, "commit_sequence=%d, commit_request=%d\n", journal->j_commit_sequence, journal->j_commit_request); @@ -291,9 +294,39 @@ static int kjournald2(void *arg) return 0; } +static int jbd2_checkpoint_thread(void *arg) +{ + journal_t *journal = arg; + DEFINE_WAIT(wait); + jbd_debug(1, "jbd2_checkpoint_thread\n"); + journal->j_checkpoint_task = current; + +loop: + prepare_to_wait(&journal->j_wait_checkpoint, &wait, + TASK_INTERRUPTIBLE); + wake_up_all(&journal->j_wait_done_checkpoint); + schedule(); + finish_wait(&journal->j_wait_checkpoint, &wait); + + if (journal->j_flags & JBD2_UNMOUNT) + goto end_loop; + + mutex_lock(&journal->j_checkpoint_mutex); + jbd2_log_do_checkpoint(journal); + mutex_unlock(&journal->j_checkpoint_mutex); + + goto loop; + +end_loop: + journal->j_checkpoint_task = NULL; + wake_up_all(&journal->j_wait_done_checkpoint); + jbd_debug(1, "jbd2_checkpoint_thread exiting.\n"); + return 0; +} + static int jbd2_journal_start_thread(journal_t *journal) { - struct task_struct *t; + struct task_struct *t, *t_ckpt; t = kthread_run(kjournald2, journal, "jbd2/%s", journal->j_devname); @@ -301,6 +334,17 @@ static int jbd2_journal_start_thread(journal_t *journal) return PTR_ERR(t); wait_event(journal->j_wait_done_commit, journal->j_task != NULL); + + t_ckpt = kthread_run(jbd2_checkpoint_thread, journal, "jbd2-ckpt/%s", + journal->j_devname); + if (IS_ERR(t_ckpt)) { + kthread_stop(t); + return PTR_ERR(t_ckpt); + } + + wait_event(journal->j_wait_done_checkpoint, + journal->j_checkpoint_task != NULL); + return 0; } @@ -316,6 +360,14 @@ static void journal_kill_thread(journal_t *journal) write_lock(&journal->j_state_lock); } write_unlock(&journal->j_state_lock); + + while (journal->j_checkpoint_task) { + mutex_lock(&journal->j_checkpoint_mutex); + wake_up(&journal->j_wait_checkpoint); + wait_event(journal->j_wait_done_checkpoint, + journal->j_checkpoint_task == NULL); + mutex_unlock(&journal->j_checkpoint_mutex); + } } /* @@ -1144,6 +1196,8 @@ static journal_t *journal_init_common(struct block_device *bdev, init_waitqueue_head(&journal->j_wait_transaction_locked); init_waitqueue_head(&journal->j_wait_done_commit); + init_waitqueue_head(&journal->j_wait_checkpoint); + init_waitqueue_head(&journal->j_wait_done_checkpoint); init_waitqueue_head(&journal->j_wait_commit); init_waitqueue_head(&journal->j_wait_updates); init_waitqueue_head(&journal->j_wait_reserved); diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 268f300..8064de4 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -850,6 +850,16 @@ struct journal_s wait_queue_head_t j_wait_commit; /** + * @j_wait_done_checkpoint: Wait queue for waiting for checkpoint to complete. + */ + wait_queue_head_t j_wait_done_checkpoint; + + /** + * @j_wait_checkpoint: Wait queue to trigger checkpointing. + */ + wait_queue_head_t j_wait_checkpoint; + + /** * @j_wait_updates: Wait queue to wait for updates to complete. */ wait_queue_head_t j_wait_updates; @@ -1108,6 +1118,9 @@ struct journal_s void (*j_commit_callback)(journal_t *, transaction_t *); + /* Pointer to the current checkpoint thread for this journal */ + struct task_struct *j_checkpoint_task; + /* * Journal statistics */ -- 1.8.3.1