Suspendendo com root no USB

1

Eu tenho um laptop rodando o Ubuntu 14.04 a partir de um sistema de arquivos raiz no armazenamento USB. Isto não está funcionando bem, porque depois de acordar da suspensão, o ext4 freqüentemente tentará gravar no sistema de arquivos raiz antes que o USB esteja pronto.

Aqui está o que eu vejo no log do kernel quando isso acontece, observe como eu recebo um monte de erros de E / S em sda1 , e um segundo depois a unidade de armazenamento USB é finalmente detectada pelo kernel.

[ 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

A princípio não há nenhuma indicação visível fora do log do kernel, que o problema foi acionado, mas se eu deixar o Ubuntu ficar rodando além deste ponto, então o sistema de arquivos irá receber erros e eventualmente mudar para o modo somente leitura. Nesse ponto, tenho que reinicializar no modo de recuperação e executar fsck.ext4 manualmente a partir de um shell raiz para reparar o sistema de arquivos.

Existe alguma configuração que eu possa mudar de tal forma que o acesso ao dispositivo raiz depois de acordar da suspensão possa ser adiado até que a unidade USB esteja pronta?

    
por kasperd 02.08.2014 / 10:13

1 resposta

0

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),
    
por kasperd 04.08.2014 / 08:22