From a46c524ce3b6e37161fc1956a3e7a8083f00770d Mon Sep 17 00:00:00 2001
From: Thomas Orgis <thomas@orgis.org>
Date: Mon, 9 Jul 2018 14:19:27 +0200
Subject: [PATCH] suspend: resume_usr_delay: headstart for kernel threads

This applies the idea of

	https://askubuntu.com/questions/505779/suspending-with-root-on-usb

in the hope that it may help with the random

[13807.451872] EXT4-fs warning (device dm-4): ext4_end_bio:323: I/O error 10 writing to inode 3409454 (offset 0 size 0 starting block 19793351)
[13807.451878] Buffer I/O error on device dm-4, logical block 19793351
[13807.451897] EXT4-fs warning (device dm-4): ext4_end_bio:323: I/O error 10 writing to inode 3409454 (offset 1867776 size 4096 starting block 19793352)
[13807.451900] Buffer I/O error on device dm-4, logical block 19793352

I get on a SD card connected via USB, used as /home storag via encrypted LVM.
My resume sequence does not really mirror what the OP had there, with the
device not vanishing and reappearing in the logs, but _something_ is not ready
yet, apparently. These I/O errors sometimes lead to read-only re-mounts, so
there is damage involved.

With the patch and a delay of 1000 ms, I did not observe the I/O again, so far.

This all is a hack that hopefully points to the relevant kernel code that causes
writes of the I/O layer before some driver is ready for it.
---
 kernel/power/hibernate.c | 11 ++++++++++-
 kernel/power/suspend.c   | 11 +++++++++++
 kernel/sysctl.c          |  9 +++++++++
 3 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 9c85c7822383..18b93af401fd 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -775,7 +775,7 @@ int hibernate(void)
 	return error;
 }
 
-
+extern unsigned int resume_usr_delay;
 /**
  * software_resume - Resume from a saved hibernation image.
  *
@@ -891,6 +891,15 @@ static int software_resume(void)
 	if (error)
 		goto Close_Finish;
 	error = load_image_and_restore();
+	if (resume_usr_delay) {
+		/* Give kernel threads a head start, such that usb-storage
+		 * can detect devices before syslog attempts to write log
+		 * messages from the suspend code.
+		 */
+		thaw_kernel_threads();
+		pr_info("PM: Sleeping for %d milliseconds.\n", resume_usr_delay);
+		msleep(resume_usr_delay);
+	}
 	thaw_processes();
  Finish:
 	__pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 87331565e505..d46b1cea2e70 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -520,6 +520,8 @@ int suspend_devices_and_enter(suspend_state_t state)
 	goto Resume_devices;
 }
 
+unsigned int resume_usr_delay = 0;
+
 /**
  * suspend_finish - Clean up before finishing the suspend sequence.
  *
@@ -528,6 +530,15 @@ int suspend_devices_and_enter(suspend_state_t state)
  */
 static void suspend_finish(void)
 {
+	if (resume_usr_delay) {
+		/* Give kernel threads a head start, such that usb-storage
+		 * can detect devices before syslog attempts to write log
+		 * messages from the suspend code.
+		 */
+		thaw_kernel_threads();
+		pr_info("PM: Sleeping for %d milliseconds.\n", resume_usr_delay);
+		msleep(resume_usr_delay);
+	}
 	suspend_thaw_processes();
 	pm_notifier_call_chain(PM_POST_SUSPEND);
 	pm_restore_console();
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 2d9837c0aff4..2911897a5cc6 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -308,6 +308,8 @@ static int min_extfrag_threshold;
 static int max_extfrag_threshold = 1000;
 #endif
 
+extern unsigned int resume_usr_delay;
+
 static struct ctl_table kern_table[] = {
 	{
 		.procname	= "sched_child_runs_first",
@@ -1873,6 +1875,13 @@ static struct ctl_table debug_table[] = {
 		.extra2		= &one,
 	},
 #endif
+	{
+		.procname       = "resume_usr_delay",
+		.data	   = &resume_usr_delay,
+		.maxlen	 = sizeof(unsigned int),
+		.mode	   = 0644,
+		.proc_handler   = proc_dointvec,
+	},
 	{ }
 };
 
-- 
2.17.1

