调试休眠和挂起¶
2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL
1. 测试休眠(也称为挂起到硬盘或 STD)¶
要检查休眠是否工作,您可以尝试在“reboot”模式下休眠
# echo reboot > /sys/power/disk
# echo disk > /sys/power/state
系统应该创建一个休眠镜像,重新启动,恢复并返回到您开始转换的命令提示符处。如果发生这种情况,休眠很可能工作正常。尽管如此,您仍然需要连续重复测试几次以获得信心。[这是必要的,因为某些问题仅在第二次尝试挂起和恢复系统时才会出现。]此外,在“reboot”和“shutdown”模式下休眠会导致 PM 核心跳过某些与平台相关的回调,而在 ACPI 系统上,这些回调可能对于使休眠工作是必要的。因此,如果您的机器无法在“reboot”模式下休眠或恢复,您应该尝试“platform”模式
# echo platform > /sys/power/disk
# echo disk > /sys/power/state
这是默认和推荐的休眠模式。
不幸的是,在某些具有损坏 BIOS 的系统上,“platform”休眠模式不起作用。在这种情况下,“shutdown”休眠模式可能会起作用
# echo shutdown > /sys/power/disk
# echo disk > /sys/power/state
(它类似于“reboot”模式,但需要您按电源按钮才能使系统恢复)。
如果“platform”和“shutdown”休眠模式都不起作用,您将需要确定哪里出了问题。
a) 测试休眠模式¶
要找出为什么休眠在您的系统上失败,您可以使用一个特殊的测试工具,如果内核编译时设置了 CONFIG_PM_DEBUG。然后,可以使用文件 /sys/power/pm_test 使休眠核心在测试模式下运行。有 5 种测试模式可用
- freezer
测试进程的冻结
- devices
测试进程的冻结和设备的挂起
- platform
测试进程的冻结、设备的挂起和平台全局控制方法 [1]
- processors
测试进程的冻结、设备的挂起、平台全局控制方法 [1] 和非启动 CPU 的禁用
- core
测试进程的冻结、设备的挂起、平台全局控制方法[1]、非启动 CPU 的禁用和平台/系统设备的挂起
要使用其中一种方法,需要将相应的字符串写入 /sys/power/pm_test(例如,“devices”来测试进程的冻结和设备的挂起)并发出标准休眠命令。例如,要将“devices”测试模式与“platform”休眠模式一起使用,您应该执行以下操作
# echo devices > /sys/power/pm_test
# echo platform > /sys/power/disk
# echo disk > /sys/power/state
然后,内核将尝试冻结进程,挂起设备,等待几秒钟(默认为 5 秒,但可以通过 suspend.pm_test_delay 模块参数配置),恢复设备并解冻进程。如果将“platform”写入 /sys/power/pm_test,则在挂起设备后,内核还将调用用于准备平台固件以进行休眠的全局控制方法(例如,ACPI 全局控制方法)。接下来,它将等待可配置的秒数并调用用于取消休眠的平台(例如,ACPI)全局方法等。
将“none”写入 /sys/power/pm_test 会导致内核切换到正常的休眠/挂起操作。此外,当打开以进行读取时,/sys/power/pm_test 包含一个以空格分隔的所有可用测试列表(包括代表正常功能的“none”),其中当前测试级别由方括号指示。
一般来说,正如您所看到的,每个测试级别都比前一个级别更具“侵入性”,并且“core”级别在不创建休眠镜像的情况下尽可能深入地测试硬件和驱动程序。显然,如果“devices”测试失败,“platform”测试也会失败,依此类推。因此,作为经验法则,您应该从“freezer”开始尝试测试模式,依次通过“devices”、“platform”和“processors”直到“core”(在每个级别重复测试几次,以确保避免任何随机因素)。
如果“freezer”测试失败,则存在无法冻结的任务(在这种情况下,通常可以通过分析失败测试后获得的 dmesg 输出来识别有问题的任务)。在此级别上的失败通常意味着任务冻结子系统存在问题,应予以报告。
如果“devices”测试失败,则很可能有一个驱动程序无法挂起或恢复其设备(在后一种情况下,系统可能会在测试后挂起或变得不稳定,因此请考虑到这一点)。要找到此驱动程序,您可以根据以下规则进行二分查找
如果测试失败,卸载当前加载的驱动程序的一半并重复(这可能涉及重新启动系统,因此请始终注意在测试之前已加载哪些驱动程序),
如果测试成功,加载您最近卸载的驱动程序的一半并重复。
一旦您找到失败的驱动程序(可能不止一个),您必须在每次休眠之前卸载它。在这种情况下,请务必报告驱动程序的问题。
也可能在您卸载所有模块后,“devices”测试仍然失败。在这种情况下,您可能希望在内核配置中查找可以编译为模块的驱动程序(并使用编译为模块的这些驱动程序再次进行测试)。您也可以尝试使用一些特殊的内核命令行选项,例如“noapic”、“noacpi”甚至“acpi=off”。
如果“platform”测试失败,则说明您的系统上平台(例如,ACPI)固件的处理存在问题。在这种情况下,“platform”休眠模式不太可能工作。您可以尝试“shutdown”模式,但这只是一种权宜之计。
如果“processors”测试失败,则非启动 CPU 的禁用/启用不起作用(当然,这可能只是 SMP 系统上的问题),应报告该问题。在这种情况下,您也可以尝试使用 /sys/devices/system/cpu/cpu*/online sysfs 属性来关闭和打开非启动 CPU,看看是否有效。
如果“core”测试失败,这意味着系统/平台设备的挂起失败(这些设备在中断关闭的情况下在一个 CPU 上挂起),那么问题很可能与硬件相关且很严重,因此应报告该问题。
任何“platform”、“processors”或“core”测试的失败都可能导致您的系统挂起或变得不稳定,因此请注意。这种失败通常表明一个严重的问题,很可能与硬件有关,但请无论如何报告它。
b) 测试最小配置¶
如果所有休眠测试模式都有效,您可以使用“init=/bin/bash”命令行参数启动系统,并尝试在“reboot”、“shutdown”和“platform”模式下休眠。如果这不起作用,则可能存在一个静态编译到内核中的驱动程序存在问题,您可以尝试将更多驱动程序编译为模块,以便可以单独进行测试。否则,模块化驱动程序存在问题,您可以通过加载通常使用的一半模块并按照以下算法进行二分查找来找到它:- 如果加载了 n 个模块并且尝试挂起和恢复失败,则卸载 n/2 个模块并重试(这可能涉及重新启动系统),- 如果加载了 n 个模块并且尝试挂起和恢复成功,则加载 n/2 个模块并重试。
同样,如果您找到有问题的模块,则必须在每次休眠之前卸载它,并请报告它的问题。
c) 使用“test_resume”休眠选项¶
/sys/power/disk 通常告诉内核在创建休眠镜像后该怎么做。可用选项之一是“test_resume”,它会导致刚刚创建的镜像用于立即恢复。也就是说,在执行
# echo test_resume > /sys/power/disk
# echo disk > /sys/power/state
将创建一个休眠镜像,并且将立即触发从该镜像的恢复,而无需以任何方式涉及平台固件。
该测试可用于检查从休眠状态恢复的失败是否与与平台固件的错误交互有关。也就是说,如果上述方法每次都有效,但从实际休眠状态恢复不起作用或不可靠,则平台固件可能对失败负责。
在支持使用不同内核来恢复休眠镜像的架构和平台上(即,用于从存储读取镜像并将其加载到内存中的内核与镜像中包含的内核不同)或支持内核地址空间随机化,它也可用于检查恢复失败是否可能与恢复内核和镜像内核之间的差异有关。
d) 高级调试¶
如果即使在最小配置下休眠在您的系统上也不起作用,并且将更多驱动程序编译为模块不切实际或某些模块无法卸载,您可以使用更高级的调试技术之一来查找问题。首先,如果您的机器中有一个串口,您可以使用“no_console_suspend”参数启动内核,并尝试使用串行控制台记录内核消息。这可能会为您提供有关挂起(恢复)失败原因的一些信息。或者,可以使用 FireWire 端口通过 firescope 进行调试 (http://v3.sk/~lkundrak/firescope/)。在 x86 上,也可以使用 如何让 s2ram 工作 中记录的 PM_TRACE 机制。
2. 测试挂起到 RAM (STR)¶
要验证 STR 是否有效,通常更方便使用 http://suspend.sf.net 提供的 s2ram 工具,并在 http://en.opensuse.org/SDB:Suspend_to_RAM (S2RAM_LINK) 中记录。
也就是说,在将“freezer”、“devices”、“platform”、“processors”或“core”写入 /sys/power/pm_test(如果内核编译时设置了 CONFIG_PM_DEBUG,则可用)后,挂起代码将以与给定字符串对应的测试模式工作。STR 测试模式的定义方式与休眠相同,因此请参阅第 1 节以获取有关它们的更多信息。特别是,“core”测试允许您测试除实际调用平台固件以使系统进入睡眠状态之外的所有内容。
其中,借助 /sys/power/pm_test 进行测试可以让您识别出无法挂起或恢复其设备的驱动程序。每次 STR 转换之前都应卸载它们。
接下来,您可以按照 S2RAM_LINK 中的说明测试系统,但如果它不能“开箱即用”,您可能需要使用“init=/bin/bash”启动它,并在最小配置中测试 s2ram。在这种情况下,您可以通过遵循与第 1 节中描述的过程类似的过程来搜索失败的驱动程序。如果您找到一些失败的驱动程序,您将必须在每次 STR 转换之前(即,在您运行 s2ram 之前)卸载它们,并请报告它们的问题。
有一个 debugfs 条目显示挂起到 RAM 的统计信息。这是一个输出示例
# mount -t debugfs none /sys/kernel/debug
# cat /sys/kernel/debug/suspend_stats
success: 20
fail: 5
failed_freeze: 0
failed_prepare: 0
failed_suspend: 5
failed_suspend_noirq: 0
failed_resume: 0
failed_resume_noirq: 0
failures:
last_failed_dev: alarm
adc
last_failed_errno: -16
-16
last_failed_step: suspend
suspend
字段 success 表示挂起到 RAM 的成功次数,字段 fail 表示失败次数。其他的是挂起到 RAM 的不同步骤的失败次数。suspend_stats 仅列出最后 2 个失败的设备,错误号和挂起的失败步骤。