在USB上挂起root用户

我有一台笔记本电脑从USB存储上的根文件系统运行Ubuntu 14.04。 这不能正常工作,因为从挂起唤醒后,ext4会在USB准备好之前经常尝试写入根文件系统。

这是我在内核日志中看到的,当发生这种情况时,请注意我如何在sda1上获得一堆I / O错误,然后一秒钟后内核最终检测到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 

最初在内核日志之外没有可见的指示,问题已经触发,但是如果我让Ubuntu继续运行超过这一点,那么文件系统将获得错误并最终切换到只读模式。 此时,我必须重新启动到恢复模式并从root shell手动运行fsck.ext4以修复文件系统。

是否有一些设置我可以更改,以便从挂起唤醒后访问根设备可能会延迟,直到USB驱动器准备好?

仅在USB设备而非其他设备上才会出现此问题的原因是两个因素的组合:

  • 与其他存储介质不同,USB存储依赖于内核线程进行操作。
  • 从suspend恢复时,内核会同时唤醒所有线程。

结果是,在恢复期间,USB系统之间将发生竞争,一方面试图检测媒体,另一方面试图从暂停和恢复到磁盘写入日志消息。

如果syslog在检测到USB设备之前碰巧尝试写入,则ext4会收到错误,由于某种原因,该错误无法正常处理,最终文件系统将需要手动运行fsck。

我发现的解决方案是在其他线程被唤醒之前给内核线程一个12秒的启动时间。 这些是我必须对内核进行的更改才能使其工作:

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