Suspensión con root en USB

Suspensión con root en USB

Tengo una computadora portátil que ejecuta Ubuntu 14.04 desde un sistema de archivos raíz en un almacenamiento USB. Esto no funciona bien, porque después de reactivarse de la suspensión, ext4 frecuentemente intentará escribir en el sistema de archivos raíz antes de que el USB esté listo.

Esto es lo que veo en el registro del kernel cuando esto sucede, observe cómo recibo un montón de errores de E/S sda1y luego, un segundo después, el kernel finalmente detecta la unidad de almacenamiento USB.

[ 2826.517419] wlan0: associated
[ 2826.517452] IPv6: ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready
[ 2827.575371] EXT4-fs warning (device sda1): ext4_end_bio:317: I/O error -5 writing to inode 1733735 (offset 0 size 0 starting block 12629950)
[ 2827.575380] Buffer I/O error on device sda1, logical block 12629694
[ 2827.575400] EXT4-fs warning (device sda1): ext4_end_bio:317: I/O error -5 writing to inode 3148603 (offset 0 size 8192 starting block 12844470)
[ 2827.575404] Buffer I/O error on device sda1, logical block 12844212
[ 2827.575411] Buffer I/O error on device sda1, logical block 12844213
[ 2827.575448] EXT4-fs warning (device sda1): ext4_end_bio:317: I/O error -5 writing to inode 3015015 (offset 0 size 90112 starting block 6588832)
[ 2827.575453] Buffer I/O error on device sda1, logical block 6588576
[ 2827.575461] Buffer I/O error on device sda1, logical block 6588577
[ 2827.575465] Buffer I/O error on device sda1, logical block 6588578
[ 2827.575469] Buffer I/O error on device sda1, logical block 6588579
[ 2827.575473] Buffer I/O error on device sda1, logical block 6588580
[ 2827.575477] Buffer I/O error on device sda1, logical block 6588581
[ 2827.575481] Buffer I/O error on device sda1, logical block 6588582
[ 2828.857284] sd 0:0:0:0: [sda] No Caching mode page found
[ 2828.857293] sd 0:0:0:0: [sda] Assuming drive cache: write through

Al principio, no hay ninguna indicación visible fuera del registro del kernel de que el problema se haya desencadenado, pero si dejo que Ubuntu siga ejecutándose más allá de este punto, el sistema de archivos obtendrá errores y eventualmente cambiará al modo de solo lectura. En ese momento tengo que reiniciar en modo de recuperación y ejecutar fsck.ext4manualmente desde un shell raíz para reparar el sistema de archivos.

¿Hay alguna configuración que pueda cambiar de modo que el acceso al dispositivo raíz después de despertar de la suspensión pueda retrasarse hasta que la unidad USB esté lista?

Respuesta1

La razón por la que este problema sólo se ve con dispositivos USB y no con otros dispositivos es una combinación de dos factores:

  • El almacenamiento USB, a diferencia de otros medios de almacenamiento, depende de subprocesos del kernel para su funcionamiento.
  • Al salir de la suspensión, el kernel activa todos los subprocesos simultáneamente.

El resultado es que durante la reanudación habrá una carrera entre el sistema USB, por un lado, que intenta detectar medios y el syslog, por otro lado, que intenta escribir mensajes de registro desde la suspensión y la reanudación en el disco.

Si syslog intenta escribir antes de que se haya detectado el dispositivo USB, ext4 recibe un error, que por alguna razón no se maneja limpiamente y eventualmente el sistema de archivos necesitará que fsck se ejecute manualmente.

La solución que encontré fue darle a los subprocesos del kernel una ventaja de 12 segundos antes de que se activen otros subprocesos. Estos son los cambios que tuve que hacer en el kernel para que funcione:

--- 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),

información relacionada