O motivo pelo qual esse problema é visto apenas em dispositivos USB e não em outros dispositivos é uma combinação de dois fatores:
- O armazenamento USB, ao contrário de outras mídias de armazenamento, depende de threads do kernel para operação.
- Ao retomar da suspensão, o kernel ativa todos os threads simultaneamente.
O resultado é que, durante o currículo, haverá uma corrida entre o sistema USB, por um lado, tentando detectar a mídia e o syslog, por outro, tentando gravar as mensagens de log da suspensão e continuar no disco.
Se o syslog tentar escrever antes do dispositivo USB ser detectado, o ext4 receberá um erro, que por algum motivo não é tratado corretamente e, eventualmente, o sistema de arquivos precisará que o fsck seja executado manualmente.
A solução que encontrei foi dar aos encadeamentos do kernel um início de 12 segundos antes que outros encadeamentos fossem ativados. Estas são as mudanças que eu tive que fazer no kernel para que isso funcionasse:
--- linux-3.13.0/kernel/power/suspend.c.orig 2014-01-20 03:40:07.000000000 +0100
+++ linux-3.13.0/kernel/power/suspend.c 2014-08-04 00:57:43.847038640 +0200
@@ -299,6 +299,8 @@
goto Resume_devices;
}
+unsigned int resume_delay = 0;
+
/**
* suspend_finish - Clean up before finishing the suspend sequence.
*
@@ -307,6 +309,15 @@
*/
static void suspend_finish(void)
{
+ if (resume_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_debug("PM: Sleeping for %d milliseconds.\n", resume_delay);
+ msleep(resume_delay);
+ }
suspend_thaw_processes();
pm_notifier_call_chain(PM_POST_SUSPEND);
pm_restore_console();
--- linux-3.13.0/kernel/sysctl.c.orig 2014-08-04 08:11:26.000000000 +0200
+++ linux-3.13.0/kernel/sysctl.c 2014-08-03 23:27:23.796278219 +0200
@@ -277,8 +277,17 @@
static int max_extfrag_threshold = 1000;
#endif
+extern unsigned int resume_delay;
+
static struct ctl_table kern_table[] = {
{
+ .procname = "resume_delay",
+ .data = &resume_delay,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
.procname = "sched_child_runs_first",
.data = &sysctl_sched_child_runs_first,
.maxlen = sizeof(unsigned int),