交换挂起

首先,一些警告。

警告

重大警告

如果在挂起和恢复之间,你修改了磁盘上的任何内容...

...那么就和你的数据说再见吧。

如果在文件系统挂载后,你从 initrd 恢复...

...再见了,根分区。

[这实际上与上面的情况相同]

如果你有不支持( )DMA的设备,你可能会遇到一些问题。如果你的磁盘驱动程序不支持挂起...(IDE支持),它也可能导致一些问题。如果在挂起和恢复之间更改内核命令行,可能会发生错误。如果在系统挂起时更改硬件...嗯,这不是一个好主意;但可能只会崩溃。

需要( )挂起/恢复支持才能使其安全。

如果在软件挂起之前,你有任何文件系统挂载在 USB 设备上,那么恢复后它们将无法访问,你可能会丢失数据,就像你拔掉了挂载文件系统的 USB 设备一样;有关详细信息,请参见下面的常见问题解答。(对于更传统的电源状态(如“待机”)来说,情况并非如此,因为它们通常不会关闭 USB。)

交换分区

你需要将 resume=/dev/your_swap_partition 追加到内核命令行,或者使用 /sys/power/resume 指定它。

交换文件

如果使用交换文件,你还可以在内核命令行上使用 resume_offset=<数字> 指定恢复偏移量,或者在 /sys/power/resume_offset 中指定它。

准备好之后,你可以通过以下方式挂起:

echo shutdown > /sys/power/disk; echo disk > /sys/power/state
  • 如果你觉得 ACPI 在你的系统上运行良好,你可以尝试:

    echo platform > /sys/power/disk; echo disk > /sys/power/state
    
  • 如果你想将休眠映像写入交换空间,然后挂起至 RAM(如果你的平台支持),你可以尝试:

    echo suspend > /sys/power/disk; echo disk > /sys/power/state
    
  • 如果你有 SATA 磁盘,则需要具有 SATA 挂起支持的最新内核。为了使挂起和恢复工作正常,请确保你的磁盘驱动程序已构建到内核中——而不是模块。[有一种方法可以通过模块化磁盘驱动程序进行挂起/恢复,请参阅 FAQ,但你可能不应该这样做。]

如果你想将挂起镜像大小限制为 N 字节,请执行:

echo N > /sys/power/image_size

在挂起之前(默认情况下,它被限制为可用 RAM 的 2/5 左右)。

  • 恢复过程会检查恢复设备是否存在,如果找到,它会检查内容中是否存在休眠映像签名。如果两者都找到,则恢复休眠映像。

  • 可以通过两种方式触发恢复过程:

    1. 在 lateinit 期间:如果在内核命令行上指定了 resume=/dev/your_swap_partition,lateinit 将运行恢复过程。如果尚未探测到恢复设备,则恢复过程将失败,并且启动将继续。

    2. 手动从 initrd 或 initramfs:可以使用 /sys/power/resume 文件从 init 脚本运行。至关重要的是,必须在重新挂载任何文件系统(即使是只读)之前完成此操作,否则数据可能会损坏。

关于 Linux 软件挂起的 goals 和 implementation 的文章

作者:Gábor Kuti 最后修改:2003-10-20,作者:Pavel Machek

要实现的想法和目标

如今,在某些笔记本电脑中,它们都有一个挂起按钮是很常见的。它将机器的状态保存到文件系统或分区,并切换到待机模式。稍后恢复机器时,保存的状态将加载回 ram,并且机器可以继续其工作。它有两个真正的好处。首先,我们节省了机器关闭和稍后启动的时间,从电池运行时能源成本非常高。另一个好处是,我们不必中断我们的程序,因此长时间计算某些内容的进程不需要编写成可中断的。

swsusp 将机器的状态保存到活动的交换分区,然后重新启动或关闭电源。你必须使用 resume= 内核选项显式指定要从中恢复的交换分区。如果找到签名,它将加载并恢复保存的状态。如果选项 noresume 被指定为启动参数,它将跳过恢复。如果选项 hibernate=nocompress 被指定为启动参数,它将保存未压缩的休眠映像。

在系统挂起的这段时间里,你不应该添加/删除任何硬件,写入文件系统等等。

睡眠状态摘要

你可以使用三种不同的接口,/proc/acpi 应该像这样工作:

在一个真正完美的世界里:

echo 1 > /proc/acpi/sleep       # for standby
echo 2 > /proc/acpi/sleep       # for suspend to ram
echo 3 > /proc/acpi/sleep       # for suspend to ram, but with more power
                                # conservative
echo 4 > /proc/acpi/sleep       # for suspend to disk
echo 5 > /proc/acpi/sleep       # for shutdown unfriendly the system

或许:

echo 4b > /proc/acpi/sleep      # for suspend to disk via s4bios

常见问题解答

问:

嗯,在我看来,挂起服务器真是一个愚蠢的事情,但是... (Diego Zuccato)

答:

你为你的服务器购买了新的 UPS。你如何在不关闭机器的情况下安装它?挂起至磁盘,重新布置电源线,恢复。

你的服务器在 UPS 上。电源已断开,UPS 指示还有 30 秒将要失效。你该怎么办?挂起至磁盘。

问:

也许我遗漏了一些东西,但是为什么常规的 I/O 路径不起作用呢?

答:

我们确实使用了常规的 I/O 路径。但是,我们在加载数据时无法将其恢复到原始位置。这将创建一个不一致的内核状态,这肯定会导致 oops。相反,我们将映像加载到未使用的内存中,然后以原子方式将其复制回原始位置。当然,这意味着最大映像大小为内存总量的一半。

对此有两种解决方案:

  • 要求在挂起期间释放一半的内存。这样你就可以将“新”数据读取到空闲位置,然后 cli 并复制。

  • 假设我们有一个特殊的“轮询” ide 驱动程序,它只使用 0-640KB 之间的内存。这样,我必须确保在挂起期间 0-640KB 是空闲的,否则它可以正常工作...

suspend2 共享这个基本限制,但通过预先保存用户数据和磁盘缓存,不会将它们包含到“已用内存”中。这意味着在实践中,这个限制就消失了。

问:

Linux 是否支持 ACPI S4?

答:

是的。这就是 echo platform > /sys/power/disk 的作用。

问:

什么是“suspend2”?

答:

suspend2 是“Software Suspend 2”,它是挂起至磁盘的派生实现,可以从 swsusp.sourceforge.net 获得用于 2.4 和 2.6 内核的单独补丁。它包括对 SMP、4GB highmem 和抢占的支持。它还具有可扩展的架构,允许对映像进行任意转换(压缩、加密)以及用于写入映像的任意后端(例如,交换空间或 NFS 共享[正在进行中])。有关 suspend2 的问题应发送到通过 suspend2 网站提供的邮件列表,而不是发送到 Linux 内核邮件列表。我们正在努力将 suspend2 合并到主线内核中。

问:

什么是任务冻结,我们为什么要使用它?

答:

任务冻结是一种机制,通过该机制,在休眠或系统范围的挂起期间(在某些架构上)控制用户空间进程和一些内核线程。有关详细信息,请参见 任务冻结

问:

“platform”和“shutdown”之间有什么区别?

答:
shutdown

在 Linux 中保存状态,然后告诉 bios 关闭电源

platform

在 Linux 中保存状态,然后告诉 bios 关闭电源并闪烁“挂起 LED”

“platform”实际上是在支持的情况下应该做的事情,但“shutdown”是最可靠的(在 ACPI 系统上除外)。

问:

我不明白为什么你对选择性挂起的想法有如此强烈的反对意见。

答:

在运行时电源管理期间进行选择性挂起是可以的。但对于挂起至磁盘来说,它是无用的。(我不知道你怎么能用它来进行挂起至 RAM,我希望你不想那样做)。

让我们看看,所以你建议:

  • 挂起除了交换设备及其父设备以外的所有设备

  • 快照

  • 将映像写入磁盘

  • 挂起交换设备及其父设备

  • 关闭电源

哦,不,这行不通,如果交换设备或其父设备使用 DMA,你已经损坏了数据。你必须这样做:

  • 挂起除了交换设备及其父设备以外的所有设备

  • 冻结交换设备及其父设备

  • 快照

  • 解冻交换设备及其父设备

  • 写入

  • 挂起交换设备及其父设备

这意味着你仍然需要 FREEZE 状态,并且你会得到更复杂的代码。(我还没有介绍像系统设备这样的细节)。

问:

在 SUSPEND 和 FREEZE 之间似乎没有任何通常有用的行为区别。

答:

当你被要求执行 FREEZE 时,执行 SUSPEND 始终是正确的,但它可能会不必要地慢。如果你想让你的驱动程序保持简单,那么缓慢可能对你来说并不重要。它可以稍后修复。

对于像磁盘这样的设备来说,这很重要,你不希望在 FREEZE 时停止旋转。

问:

恢复后,系统正在大量分页,导致非常糟糕的交互性。

答:

尝试运行:

cat /proc/[0-9]*/maps | grep / | sed 's:.* /:/:' | sort -u | while read file
do
  test -f "$file" && cat "$file" > /dev/null
done

恢复后。swapoff -a; swapon -a 也可能有用。

问:

在 swsusp 期间设备会发生什么?它们似乎在系统挂起期间恢复了?

答:

没错。如果我们想将映像写入磁盘,我们需要恢复它们。整个序列如下所示:

挂起部分

运行系统,用户请求挂起至磁盘

用户进程被停止

suspend(PMSG_FREEZE):设备被冻结,以便它们不干扰状态快照

状态快照:在禁用中断的情况下获取整个已用内存的副本

resume():设备被唤醒,以便我们可以将映像写入交换空间

将映像写入交换空间

suspend(PMSG_SUSPEND):挂起设备,以便我们可以关闭电源

关闭电源

恢复部分

(实际上非常相似)

运行系统,用户请求挂起至磁盘

用户进程被停止(在常见情况下没有,但是通过从 initrd 恢复,没有人知道)

从磁盘读取映像

suspend(PMSG_FREEZE):设备被冻结,以便它们不干扰映像恢复

映像恢复:使用映像重写内存

resume():设备被唤醒,以便系统可以继续

解冻所有用户进程

问:

“加密挂起映像”是做什么用的?

答:

首先:它不能替代 dm-crypt 加密的交换空间。它无法在你的计算机挂起时保护它。相反,它可以防止在从挂起恢复后泄露敏感数据。

考虑以下情况:你在一个应用程序运行时挂起,该应用程序将敏感数据保存在内存中。应用程序本身会阻止数据被交换出去。但是,挂起必须将这些数据写入交换空间才能稍后恢复。如果没有挂起加密,你的敏感数据将以纯文本形式存储在磁盘上。这意味着在恢复后,所有可以直接访问用于挂起的交换设备的应用程序都可以访问你的敏感数据。如果你在恢复后不需要交换空间,这些数据几乎可以永远保留在磁盘上。因此,可能会发生你的系统在几周后被入侵,并且你认为已加密和保护的敏感数据从交换设备中被检索和窃取。为了防止这种情况发生,你应该使用“加密挂起映像”。

在挂起期间,会创建一个临时密钥,并且该密钥用于加密写入磁盘的数据。当在恢复期间将数据读回内存时,临时密钥会被销毁,这仅仅意味着在挂起期间写入磁盘的所有数据都无法访问,因此无法被窃取。然后,你必须注意的唯一一件事是,在常规启动期间尽早为用于挂起的交换分区调用“mkswap”。这可以确保从 oops 挂起或从失败或中止的恢复中获得的任何临时密钥都将从交换设备中删除。

根据经验,使用加密的交换空间来保护你的数据,而你的系统处于关闭或挂起状态。此外,使用加密的挂起映像来防止在恢复后窃取敏感数据。

问:

我可以挂起至交换文件吗?

答:

通常,是的,你可以。但是,它要求你使用“resume=”和“resume_offset=”内核命令行参数,因此无法从 initrd 或 initramfs 映像启动从交换文件恢复。有关详细信息,请参见 将交换文件与软件挂起 (swsusp) 一起使用

问:

swsusp 支持的最大系统 RAM 大小是多少?

答:

它应该可以在 highmem 上正常工作。

问:

swsusp(挂起至磁盘)是否仅使用一个交换分区,还是可以使用多个交换分区(将它们聚合成一个逻辑空间)?

答:

仅一个交换分区,对不起。

问:

如果我的应用程序导致大量内存和交换空间被使用(超过系统总 RAM 的一半),那么在应用程序运行时尝试挂起至磁盘可能没用,这是正确的吗?

答:

不,它应该可以正常工作,只要你的应用程序不 mlock() 它。只需准备足够大的交换分区。

问:

哪些信息对于调试挂起至磁盘问题很有用?

答:

嗯,屏幕上的最后消息总是有用的。如果某些东西坏了,通常是某些内核驱动程序,因此尝试尽可能少地加载模块会有很大帮助。我也喜欢人们从控制台挂起,最好不要运行 X。使用 init=/bin/bash 启动,然后 swapon 并手动启动挂起序列通常可以解决问题。然后,尝试使用最新的 vanilla 内核是个好主意。

问:

发行版如何使用模块化磁盘驱动程序(尤其是 SATA)发布支持 swsusp 的内核?

答:

嗯,可以做到,加载驱动程序,然后从 initrd 回显到 /sys/power/resume 文件。确保不要挂载任何东西,甚至不要进行只读挂载,否则你将丢失数据。

问:

如何使挂起更详细?

答:

如果想在内核在挂起期间切换到的虚拟终端上看到任何非错误的内核消息,则必须将内核控制台日志级别设置为至少 4 (KERN_WARNING),例如,通过执行:

# save the old loglevel
read LOGLEVEL DUMMY < /proc/sys/kernel/printk
# set the loglevel so we see the progress bar.
# if the level is higher than needed, we leave it alone.
if [ $LOGLEVEL -lt 5 ]; then
        echo 5 > /proc/sys/kernel/printk
        fi

IMG_SZ=0
read IMG_SZ < /sys/power/image_size
echo -n disk > /sys/power/state
RET=$?
#
# the logic here is:
# if image_size > 0 (without kernel support, IMG_SZ will be zero),
# then try again with image_size set to zero.
if [ $RET -ne 0 -a $IMG_SZ -ne 0 ]; then # try again with minimal image size
        echo 0 > /sys/power/image_size
        echo -n disk > /sys/power/state
        RET=$?
fi

# restore previous loglevel
echo $LOGLEVEL > /proc/sys/kernel/printk
exit $RET
问:

如果我在 USB 设备上挂载了文件系统并且我挂起至磁盘,除非文件系统已使用“sync”挂载,否则我可能会丢失数据,这是真的吗?

答:

这是正确的...如果你断开该设备的连接,你可能会丢失数据。事实上,即使使用“-o sync”,如果你的程序在它们尚未写入你断开连接的磁盘的缓冲区中有信息,或者如果你在设备完成保存你写入的数据之前断开连接,你也可能会丢失数据。

软件挂起通常会关闭 USB 控制器的电源,这相当于断开连接到你系统的所有 USB 设备。

你的系统很可能支持在系统处于睡眠状态时 USB 控制器的低功耗模式,从而使用真正的睡眠模式(如“挂起至 RAM”或“待机”)来维持连接。(不要将“disk”写入 /sys/power/state 文件;写入“standby”或“mem”。)我们还没有看到任何可以通过软件挂起使用这些模式的硬件,尽管理论上某些系统可能支持不会破坏 USB 连接的“平台”模式。

请记住,拔下包含已挂载文件系统的磁盘驱动器始终是一个坏主意。即使你的系统处于睡眠状态也是如此!最安全的方法是在挂起之前卸载可移动媒体上的所有文件系统(例如 USB、Firewire、CompactFlash、MMC、外部 SATA 甚至 IDE 热插拔托架);然后在恢复后重新挂载它们。

有一个解决此问题的方法。有关更多信息,请参见 系统挂起期间的 USB 设备持久性

问:

我可以使用 LVM 下的交换分区挂起至磁盘吗?

答:

是也不是。你可以成功挂起,但是内核将无法自行恢复。你需要一个可以识别恢复情况的 initramfs,激活包含交换卷的逻辑卷(但不接触任何文件系统!),并最终调用

echo -n "$major:$minor" > /sys/power/resume

其中 $major 和 $minor 分别是交换卷的主设备号和次设备号。

uswsusp 也可以与 LVM 一起使用。请参阅 http://suspend.sourceforge.net/

问:

我将内核从 2.6.15 升级到 2.6.16。两个内核都是使用类似的配置文件编译的。无论如何,我发现与 2.6.15 相比,在 2.6.16 上挂起至磁盘(和恢复)要慢得多。有什么原因或我如何加快它的速度吗?

答:

这是因为挂起映像的大小现在大于 2.6.15(通过保存更多数据,我们可以在恢复后获得更快的系统响应)。

有一个 /sys/power/image_size knob 控制映像的大小。如果将其设置为 0(例如,通过以 root 身份执行 echo 0 > /sys/power/image_size),则应恢复 2.6.15 的行为。如果仍然太慢,请查看 suspend.sf.net -- 用户空间挂起速度更快,并支持 LZF 压缩以进一步加快速度。