From 3999cdd966d5b37e00b85b58c0baf01688c18890 Mon Sep 17 00:00:00 2001
From: Joseph Qi <joseph.qi@linux.alibaba.com>
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 <joseph.qi@linux.alibaba.com>
Reviewed-by: Jiufei Xue <jiufei.xue@linux.alibaba.com>
Signed-off-by: zhangliguang <zhangliguang@linux.alibaba.com>
Reviewed by: Baoyou Xie <baoyou.xie@linux.alibaba.com>
Reviewed-by: Liu Bo <bo.liu@linux.alibaba.com>
Acked-by: Caspar Zhang <caspar@linux.alibaba.com>
---
 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

