电源管理/挂起和休眠
有多种方法的挂起可用,主要有
- 挂起到空闲
- Intel 称之为 S0ix,微软称之为 现代待机(之前称为“连接待机”),内核称之为 S2Idle。旨在替代支持系统中的 S3 睡眠状态,提供相同的节能效果,但大幅缩短唤醒时间。
- 挂起到 RAM(又称挂起)
- ACPI 定义的 S3 睡眠状态。其工作原理是切断机器大部分部件的电源,只保留 RAM 的电源,RAM 是恢复机器状态所必需的。由于具有很大的节能效果,建议笔记本电脑在电池供电且盖上盖子(或用户一段时间不活动)时自动进入此模式。
- 挂起到磁盘(又称休眠)
- ACPI 定义的 S4 睡眠状态。将机器状态保存到 交换空间 并完全关闭机器电源。当机器开机时,状态将被恢复。在此之前,功耗为 零。
- 混合挂起(又称混合睡眠)
- 挂起和休眠的混合,有时称为 挂起到两者。将机器状态保存到交换空间,但不关闭机器电源。相反,它调用默认的挂起。因此,如果电池未耗尽,系统可以立即恢复。如果电池耗尽,系统可以从磁盘恢复,这比从 RAM 恢复慢得多,但机器状态没有丢失。
内核提供基本功能,一些高级接口提供调整以处理有问题的硬件驱动程序/内核模块(例如,显卡重新初始化)。
内核接口 (swsusp)
可以直接通知内核软件挂起代码 (swsusp) 进入挂起状态;具体方法和状态取决于硬件支持的级别。在现代内核上,将适当的字符串写入 /sys/power/state
是触发此挂起的主要机制。
有关详细信息,请参阅 内核文档。
高级接口 (systemd)
systemd 提供了用于挂起、休眠和混合挂起的本地命令。这是 Arch Linux 中使用的默认接口。
systemctl suspend
应该可以直接使用。要使 systemctl hibernate
在您的系统上工作,您可能需要按照 #休眠 中的说明进行操作。
还有两种结合了挂起和休眠的模式
systemctl hybrid-sleep
将系统挂起到 RAM 和磁盘,因此完全断电不会导致数据丢失。此模式也称为“挂起到两者”。systemctl suspend-then-hibernate
最初尽可能长时间地将系统挂起到 RAM,然后使用 RTC 闹钟唤醒并休眠。RTC 闹钟通过 systemd-sleep.conf(5) 中的HibernateDelaySec
设置。默认值是通过估计电池放电率来设置的,以使系统保持 5% 的电量,或者在没有电池的情况下保持两个小时。所述估计值是从 systemd-sleep.conf(5) 中的SuspendEstimationSec
指定的时间后电池电量的变化获得的,系统将在该时间短暂唤醒以进行测量(如果系统从挂起状态手动唤醒,也会进行测量)。
systemctl sleep
命令自动选择最合适的睡眠操作。默认情况下,使用 suspend-then-hibernate
,如果不支持,则回退到 suspend
,然后再回退到 hibernate
。有关更多信息,请参阅 systemctl(1)。有关配置挂起/休眠挂钩的更多信息,请参阅 #睡眠挂钩。另请参阅 systemctl(1)、 systemd-sleep(8) 和 systemd.special(7)。
更改挂起方法
在 S0ix 挂起无法提供与常规 S3 睡眠相同的节能效果的系统上,或者当节能优先于快速恢复时间时,可以更改默认的挂起方法。
运行以下命令以查看硬件广告支持的所有挂起方法(当前方法显示在方括号中[1])
$ cat /sys/power/mem_sleep
[s2idle] shallow deep
mem_sleep 字符串 | 睡眠状态 |
---|---|
s2idle | 挂起到空闲 |
浅层 | 待机 |
深层 | 挂起到 RAM |
如果您的硬件未通告“深层”睡眠状态,请首先检查您的 UEFI 是否通告了相关设置,通常在“电源”或“睡眠状态”或类似措辞下,选项名称为“Windows 10”、“Windows 和 Linux”或 S0ix 的“S3/现代待机支持”,以及 S3 睡眠的“Legacy”、“Linux”、“Linux S3”或“S3 已启用”。如果失败,您可以继续使用 s2idle
,考虑使用休眠或尝试修补 DSDT 表(或在线查找修补版本)。
通过在更改睡眠方法后测试几个睡眠周期来确认您的硬件在 S3 睡眠中没有问题
# echo deep > /sys/power/mem_sleep
如果未发现问题,您可以通过 systemd-sleep.conf(5) 中的 MemorySleepMode
指令使更改永久生效
/etc/systemd/sleep.conf.d/mem-deep.conf
[Sleep] MemorySleepMode=deep
或者通过 mem_sleep_default=deep
内核参数。
在某些相反的情况下,有故障的固件通告支持“深层”睡眠,而仅支持 s2idle
。在这种情况下,可以通过 SuspendState
设置获得使用 s2idle
的替代方法
/etc/systemd/sleep.conf.d/freeze.conf
[Sleep] SuspendState=freeze
休眠
为了使用休眠,您必须创建一个交换分区或文件,配置 initramfs,以便在早期用户空间中启动恢复进程,并以 initramfs 可用的方式指定交换空间的位置,例如 systemd 定义的 HibernateLocation
EFI 变量,或者 resume=
内核参数。以下详细描述了这三个步骤。
- 当使用加密时,请参阅 dm-crypt/Swap encryption#With suspend-to-disk support。
- linux-hardened 不支持休眠,请参阅 FS#63648。
- 不支持休眠到 zram 上的交换空间,即使 zram 配置了永久存储上的后备设备。虽然 logind 将防止尝试休眠到 zram 上的交换空间,但作为替代方案,您可以创建多个交换空间。内存将被存储到一个交换文件中,而另一个可用的交换空间将为 zram 保留。有关详细信息,请参阅 #使用 zram 维护休眠交换文件。
关于交换分区/文件大小
即使您的交换分区小于 RAM,您仍然很有可能成功休眠。有关 image_size
sysfs(5) 伪文件的信息,请参阅 内核文档中的 "image_size"。
您可以减小 /sys/power/image_size
的值,以使挂起镜像尽可能小(对于小的交换分区),或者增加它以可能加快休眠过程。对于具有大量 RAM 的系统,较小的值可能会大大提高恢复休眠系统的速度。systemd#systemd-tmpfiles - temporary files 可以用于使此更改持久化
/etc/tmpfiles.d/hibernation_image_size.conf
# Path Mode UID GID Age Argument w /sys/power/image_size - - - - 0
挂起镜像不能跨越多个交换分区和/或交换文件。它必须完全容纳在一个交换分区或一个交换文件中。[2]
配置 initramfs
- 当使用基于 busybox 的 initramfs(默认情况)时,
/etc/mkinitcpio.conf
中需要resume
hook。无论通过标签还是 UUID,交换分区都使用 udev 设备节点引用,因此resume
hook 必须位于udev
hook 之后。此示例是从默认 hook 配置开始制作的
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block filesystems resume fsck)
- 记住要重新生成 initramfs 以使这些更改生效。
- 当使用带有
systemd
hook 的 initramfs 时,已经提供了恢复机制,无需添加其他 hook。
将休眠位置传递给 initramfs
当系统休眠时,内存镜像会被转储到交换空间,其中还包括已挂载文件系统的状态。因此,休眠位置必须对 initramfs 可用,即在挂载根文件系统以从休眠状态恢复之前。
自从 systemd v255 和 mkinitcpio v38 以来,当系统在 UEFI 上运行时,systemd-sleep(8) 将自动选择合适的交换空间进行休眠,并且所用交换空间的信息存储在 HibernateLocation
EFI 变量中。下次启动时,systemd-hibernate-resume(8) 从 EFI 变量中读取位置,系统恢复。这意味着以下步骤不是必需的,除非系统使用传统的 BIOS,或者您想选择与自动选择的交换空间不同的交换空间。
手动指定休眠位置
可以使用 内核参数 resume=swap_device
,其中 swap_device 遵循 持久块设备命名。例如
resume=UUID=4209c845-f495-4c43-8a03-5363dd433153
resume="PARTLABEL=Swap partition"
resume=/dev/archVolumeGroup/archLogicalVolume
– 如果交换空间位于 LVM 逻辑卷上(UUID 和 Label 也应该有效)
内核参数仅在重启后生效。要立即休眠,请从 lsblk 获取卷的主设备号和次设备号,并以 major:minor
格式回显到 /sys/power/resume
。
例如,如果交换设备是 8:3
# echo 8:3 > /sys/power/resume
如果使用交换文件,请另外按照 #获取交换文件偏移量 中的步骤操作。
获取交换文件偏移量
当使用交换文件进行休眠时,应在 resume=
中指定文件系统所在的块设备,并且必须通过 resume_offset=
内核参数 另外指定交换文件的物理偏移量。[3]
在 Btrfs 以外的文件系统上,可以通过运行 filefrag -v swap_file
获取 resume_offset=
的值。输出是表格格式,所需的值位于 physical_offset
列的第一行。
例如
# filefrag -v /swapfile
Filesystem type is: ef53 File size of /swapfile is 4294967296 (1048576 blocks of 4096 bytes) ext: logical_offset: physical_offset: length: expected: flags: 0: 0.. 0: 38912.. 38912: 1: 1: 1.. 22527: 38913.. 61439: 22527: unwritten 2: 22528.. 53247: 899072.. 929791: 30720: 61440: unwritten ...
在示例中,resume_offset=
的值是第一个 38912
。
或者,要直接获取偏移值
# filefrag -v swap_file | awk '$1=="0:" {print substr($4, 1, length($4)-2)}'
对于 Btrfs,不要尝试使用 filefrag 工具,因为从 filefrag 获取的“物理”偏移量不是磁盘上的真实物理偏移量;为了支持多个设备,存在一个虚拟磁盘地址空间。[4] 而是使用 btrfs-inspect-internal(8) 命令。例如
# btrfs inspect-internal map-swapfile -r swap_file
198122980
在此示例中,内核参数将是 resume_offset=198122980
。
要立即应用更改(无需重启),请将 resume 偏移量回显到 /sys/power/resume_offset
。例如,如果偏移量为 38912
# echo 38912 > /sys/power/resume_offset
findmnt -no UUID -T swap_file
resume
参数必须指向包含带有交换文件的文件系统的已解锁/映射设备。更改休眠的镜像压缩算法
从 Linux 6.9[5] 开始,可以更改休眠的镜像压缩算法。默认压缩算法是基于编译时选项 CONFIG_HIBERNATION_DEF_COMP
选择的,但可以在启动时和运行时覆盖。
不同的压缩算法具有不同的特性,当休眠使用这些算法中的任何一种时,可能会受益,特别是当辅助算法 (LZ4) 提供比默认算法 (LZO) 更好的解压缩速度时,这反过来会减少休眠镜像恢复时间。
您可以通过两种方式覆盖默认算法
1) 将 hibernate.compressor
作为 内核参数 传递
hibernate.compressor=lzo hibernate.compressor=lz4
2) 在运行时指定算法
# echo lzo > /sys/module/hibernate/parameters/compressor # echo lz4 > /sys/module/hibernate/parameters/compressor
目前 lzo
和 lz4
是支持的算法,其中 LZO 是默认算法。
使用 zram 维护休眠交换文件
通过同时维护两个或多个交换空间,可以解决 zram 仅 RAM 交换的休眠问题。systemd 在触发休眠之前总是会忽略 zram 块设备 [6],因此保持两个空间都启用应该可以工作,无需进一步干预。
在 配置交换文件 后,按照 zram 页面操作。确保 zram 具有更高的交换优先级(例如 pri=100
)。
- 不要为休眠创建按需交换单元,因为它没有官方支持。请参阅 systemd 问题 #16708 和 #30083。
- 内核单独负责回收页面的匿名内存并交换它们;不使用交换空间实际上可能导致不良的内存使用。用户可以以 控制组 的形式管理某些应用程序回收内存的优先级,该优先级可以通过
memory.low
进行调整。总的来说,这比设置 swappiness 参数更有效。 - 阅读 内核文档中的交换管理 和 Chris Down 的文章 - In defence of swap: common misconceptions 以了解更多详细信息。
休眠到精简配置的 LVM 卷
休眠到精简配置的 LVM 卷是可能的,但您必须确保该卷已完全分配。否则,从中恢复将失败,请参阅 FS#50703。
您可以通过简单地用零填充 LVM 卷来完全分配它。例如
# dd if=/dev/zero of=/dev/vg0/swap bs=1M status=progress
要验证卷是否已完全分配,您可以使用
# lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert swap vg0 Vwi-aot--- 10.00g pool 100
完全分配的卷将显示为具有 100% 的数据使用率。
禁用 zswap 回写以仅将交换空间用于休眠
在 Linux 6.8 中,zswap 获得了 每个 cgroup 禁用回写的选项。通过在所有可能的单元类型中使用 systemd 单元设置 MemoryZSwapWriteback
(参见 systemd.resource-control(5) § Memory Accounting and Control),可以有效地完全禁用 zswap 回写。这允许像使用 zram 一样使用 zswap,并增加了支持休眠的优势。
为了避免必须手动创建十二个顶级每类型 drop-in 文件(用于系统和用户 scope
、service
、slice
、socket
、mount
、swap
单元类型),安装 zswap-disable-writebackAUR。启用 zswap 并重启以使设置生效。
尝试执行内存密集型任务,并确认 zswap 没有写入任何内容到磁盘
# cat /sys/kernel/debug/zswap/written_back_pages
0
睡眠 hook
自定义 systemd 单元
systemd 分别为每个睡眠状态启动 suspend.target
、hibernate.target
、hybrid-sleep.target
或 suspend-then-hibernate.target
。所有上述目标都拉入 sleep.target
。任何目标都可用于在挂起/休眠之前或之后调用自定义单元。应为用户操作和 root/系统操作创建单独的文件。示例
/etc/systemd/system/user-suspend@.service
[Unit] Description=User suspend actions Before=sleep.target [Service] User=%I Type=forking Environment=DISPLAY=:0 ExecStartPre= -/usr/bin/pkill -u %u unison ; /usr/local/bin/music.sh stop ExecStart=/usr/bin/sflock ExecStartPost=/usr/bin/sleep 1 [Install] WantedBy=sleep.target
/etc/systemd/system/user-resume@.service
[Unit] Description=User resume actions After=suspend.target [Service] User=%I Type=simple ExecStart=/usr/local/bin/ssh-connect.sh [Install] WantedBy=suspend.target
启用 user-suspend@user.service
和/或 user-resume@user.service
以使更改生效。
ExecStartPost=/usr/bin/sleep 1
添加少量延迟有助于防止这种情况。对于 root/系统操作
/etc/systemd/system/root-suspend.service
[Unit] Description=Local system suspend actions Before=sleep.target [Service] Type=simple ExecStart=-/usr/bin/pkill sshfs [Install] WantedBy=sleep.target
/etc/systemd/system/root-resume.service
[Unit] Description=Local system resume actions After=suspend.target [Service] Type=simple ExecStart=/usr/bin/systemctl restart mnt-media.automount [Install] WantedBy=suspend.target
组合的睡眠/恢复单元
使用组合的单元文件,单个 hook 完成不同阶段(睡眠/恢复)和不同目标的所有工作。
示例和说明
/etc/systemd/system/wicd-sleep.service
[Unit] Description=Wicd sleep hook Before=sleep.target StopWhenUnneeded=yes [Service] Type=oneshot RemainAfterExit=yes ExecStart=-/usr/share/wicd/daemon/suspend.py ExecStop=-/usr/share/wicd/daemon/autoconnect.py [Install] WantedBy=sleep.target
RemainAfterExit=yes
:启动后,服务被认为是活动的,直到显式停止。StopWhenUnneeded=yes
:活动时,如果没有其他活动服务需要该服务,该服务将被停止。在此特定示例中,它将在sleep.target
停止后停止。- 由于
sleep.target
具有StopWhenUnneeded=yes
,因此保证 hook 可以针对不同任务正确启动/停止。
/usr/lib/systemd/system-sleep 中的 Hooks
systemd-sleep 运行 /usr/lib/systemd/system-sleep/
中的所有可执行文件,并向每个文件传递两个参数
pre
或post
,取决于机器是要进入睡眠还是正在唤醒。suspend
、hibernate
、hybrid-sleep
或suspend-then-hibernate
,取决于正在调用哪一个。
将设置一个名为 SYSTEMD_SLEEP_ACTION
的环境变量,其中包含正在处理的睡眠操作。这对于 suspend-then-hibernate 尤其有用,在该模式下,变量的值将是 suspend
、hibernate
或 suspend-after-failed-hibernate
,以处理休眠失败的情况。
任何自定义脚本的输出都将由 systemd-suspend.service、systemd-hibernate.service 或 systemd-hybrid-sleep.service 记录。您可以在 systemd 的 journalctl 中查看其输出
# journalctl -b -u systemd-suspend.service
自定义睡眠脚本的示例
/usr/lib/systemd/system-sleep/example.sh
#!/bin/sh case $1/$2 in pre/*) echo "Going to $2..." ;; post/*) echo "Waking up from $2..." ;; esac
不要忘记使您的脚本可执行。
技巧和窍门
在受信任的位置恢复时自动解锁
恢复时,如果系统连接到某些设备或受信任的 Wi-Fi 网络,您可以自动解锁系统。
/etc/local-scripts/resume-unlock.sh
#!/usr/bin/bash # Unlock session if at a trusted location function trusted() { # Check if connected to a trusted Wi-Fi network [[ $(iwgetid -r) == your_home_ssid ]] \ && return 0 # Check if trusted USB device is connected. #lsusb -d xxxx:xxxx && return 0 return 1 # Not trusted } for (( i=0; i < 10; i++ )); do if trusted; then loginctl unlock-sessions exit fi sleep 0.5 done
配置您的桌面环境,使其在恢复时锁定,然后创建一个睡眠 hook,在恢复后运行上述脚本。您还需要安装 wireless_tools 以读取连接的 Wi-Fi SSID。如果您还想测试连接的 USB 设备,请取消注释脚本中的 lsusb -d ...
行,并填写您信任的设备的 ID。您可以通过运行 lsusb
获取设备的 ID。
完全禁用睡眠
当将设备用作服务器等时,可能不需要挂起/休眠,甚至可能是不希望的。可以通过 systemd-sleep.conf(5) 禁用每种睡眠状态
/etc/systemd/sleep.conf.d/disable-sleep.conf
[Sleep] AllowSuspend=no AllowHibernation=no AllowHybridSleep=no AllowSuspendThenHibernate=no
英特尔快速启动技术 (IRST)
英特尔快速启动技术是一种固件休眠方法,允许在预定义的时间间隔后或根据电池状态从睡眠状态休眠。这应该比常规休眠更快、更可靠,因为它是由固件而不是在操作系统级别完成的。通常,必须在固件中启用它,并且固件还提供对设置挂起/电池事件触发休眠后持续时间的支持。但是,某些设备——尽管在固件中支持 IRST——只允许通过英特尔的 Windows 驱动程序进行配置。在这种情况下,下面描述的 intel-rst 内核模块应该能够在 Linux 下配置事件。
启用英特尔快速启动技术 (IRST) 后,从深度睡眠状态恢复“比从 S3 状态恢复稍慢几秒,但比从休眠状态恢复快得多”。
许多基于英特尔的系统在其固件中支持 IRST,但需要在 SSD(而不是 HDD)上有一个特殊分区。Windows 的 OEM 部署可能有一个预先存在的 IRST 分区,可以在 Arch Linux 安装过程中保留该分区(而不是擦除和重新分区整个 SSD)。它应该显示为一个未格式化的分区,大小与系统的 RAM 相等。
如果您打算擦除并重新分区整个驱动器(或已经这样做),那么如果您还计划使用该技术,则必须重新创建 IRST 分区。这可以通过创建一个大小与系统 RAM 相等的空分区,并将其分区类型设置为 GPT 分区的 GUID D3BFE2DE-3DAF-11DF-BA40-E3A556D89593
或 MBR 分区的 ID 0x84
来完成。您可能还需要在系统的固件设置中启用对 IRST 的支持。
IRST 休眠过程的持续时间(即,将“RAM 的全部内容复制到特殊分区”)取决于系统的 RAM 大小和 SSD 速度,因此可能需要 20-60 秒。某些系统可能会通过 LED 指示灯指示该过程的完成,例如,当它停止闪烁时。
在 Linux 内核中配置 IRST 休眠事件需要内置或作为模块的 CONFIG_INTEL_RST
。一旦通过 modprobe intel_rst
加载,它应该在 /sys/bus/acpi/drivers/intel_rapid_start/*/
下创建文件 wakeup_events
和 wakeup_time
,这些文件可用于进一步配置。此模块的文档很少,有关更多详细信息,请参见源代码 drivers/platform/x86/intel/rst.c。
跟踪笔记本电脑在睡眠状态下的电池能量变化
要测量挂起状态下的功耗,请使用 Batenergy 脚本将电池变化记录到系统日志中。这允许比较 S3/S0x 状态下的功耗,或在 BIOS 和内核更新后检查回归和修复。该脚本需要安装 bc 才能进行计算。
故障排除
ACPI_OS_NAME
您可能需要调整您的 DSDT 表以使其工作。请参阅 DSDT。
挂起/休眠不起作用,或无法持续工作
有许多报告指出,在进入和退出挂起和/或休眠状态时,屏幕会变黑,没有容易查看的错误,也无法执行任何操作。这些问题在笔记本电脑和台式机上都已出现。这不是官方解决方案,但切换到较旧的内核,尤其是 LTS 内核,可能会解决此问题。
当使用硬件看门狗定时器(默认禁用,请参阅 systemd-system.conf(5) § OPTIONS 中的 RuntimeWatchdogSec=
)时,可能会出现问题。有缺陷的看门狗定时器可能会在系统完成创建休眠映像之前重置计算机。
有时,屏幕变黑是由于从 initramfs 中进行的设备初始化引起的。删除您在 Mkinitcpio#MODULES 中可能拥有的任何模块,删除 kms
hook 并重建 initramfs 可能会解决此问题,特别是对于 早期 KMS 的图形驱动程序。在恢复之前初始化此类设备可能会导致不一致,从而阻止系统从休眠状态恢复。这不会影响从 RAM 恢复。另外,请查看博客文章 best practices to debug suspend issues。
从 ATI 视频驱动程序迁移到较新的 AMDGPU 驱动程序也可能有助于使休眠和唤醒过程成功。
对于 NVIDIA 用户,黑名单模块 nvidiafb
可能会有所帮助。[8]
配备英特尔 CPU 的笔记本电脑,如果加载用于触摸板的 intel_lpss_pci
模块,可能会在恢复时遇到内核崩溃(caps lock 闪烁) [9]。该模块需要添加到 initramfs,如下所示
/etc/mkinitcpio.conf
MODULES=(... intel_lpss_pci ...)
USB 设备错误
系统可能因 USB 设备而无法挂起。您可能会看到以下错误
PM: Some devices failed to suspend, or early wake event detected ... xhci_hcd 0000:02:00.0: PM: failed to suspend async: error -16
lspci
可能会为您提供有关故障设备的更多信息
$ lspci -s 02:00.0
02:00.0 USB controller: Advanced Micro Devices, Inc. [AMD] 500 Series Chipset USB 3.1 XHCI Controller
尝试断开该端口上的设备。
网络唤醒 (Wake-on-LAN)
如果网络唤醒 (Wake-on-LAN) 处于活动状态,即使计算机处于休眠状态,网卡也会消耗电力。
挂起后瞬间唤醒
休眠时系统未关机
当您休眠系统时,系统应关机(在将状态保存到磁盘后)。在某些固件上,S4 睡眠状态无法可靠地工作。例如,系统可能不会关机,而是重新启动或保持开机状态但不响应。如果发生这种情况,在 sleep.conf.d(5) 中将 HibernateMode
设置为 shutdown
可能会有所帮助
/etc/systemd/sleep.conf.d/hibernatemode.conf
[Sleep] HibernateMode=shutdown
通过以上配置,如果其他一切都设置正确,则在调用 systemctl hibernate
时,机器将关机,同时将状态保存到磁盘。
休眠后启动时找不到操作系统(或启动错误的操作系统)
当启动磁盘是外部磁盘时,可能会发生这种情况,这似乎是由 BIOS/固件限制引起的。BIOS/固件尝试从内部磁盘启动,而休眠是从外部(或其他)磁盘上的操作系统完成的。
按照 #休眠时系统未关机 中所示,设置 HibernateMode=shutdown
以永久解决问题。如果您已经被锁定,您可以尝试重新启动系统 4 次(每次都等待错误出现),这在某些 BIOS 上会强制执行正常的启动过程。
/home 中的交换文件
如果交换文件在 /home/
中,systemd-logind 将无法访问它,并给出 Call to Hibernate failed: No such file or directory
警告消息,并导致在 systemctl hibernate
上需要身份验证。应避免此设置,因为它被认为是上游不支持的。有关两种解决方法,请参阅 systemd issue 15354。
PC 在 A520I 和 B550I 主板上无法从睡眠状态唤醒
在某些配备 A520i 和 B550i 芯片组的主板上,系统将无法完全进入睡眠状态或从中唤醒。症状包括系统进入睡眠状态,显示器关闭,而主板上的内部 LED 或电源 LED 保持亮起。随后,系统将无法从该状态恢复,并且需要硬关机。如果您在使用 AMD 时遇到类似问题,请首先确保您的系统已完全更新,并检查是否已安装 AMD microcode 软件包。
验证以 GPP0
开头的行是否具有启用状态
$ cat /proc/acpi/wakeup
Device S-state Status Sysfs node GP12 S4 *enabled pci:0000:00:07.1 GP13 S4 *enabled pci:0000:00:08.1 XHC0 S4 *enabled pci:0000:0b:00.3 GP30 S4 *disabled GP31 S4 *disabled PS2K S3 *disabled GPP0 S4 *enabled pci:0000:00:01.1 GPP8 S4 *enabled pci:0000:00:03.1 PTXH S4 *enabled pci:0000:05:00.0 PT20 S4 *disabled PT24 S4 *disabled PT26 S4 *disabled PT27 S4 *disabled PT28 S4 *enabled pci:0000:06:08.0 PT29 S4 *enabled pci:0000:06:09.0
如果已启用,您可以运行以下命令禁用它
# echo GPP0 > /proc/acpi/wakeup
现在通过运行 systemctl suspend
进行测试,并让系统进入睡眠状态。然后尝试在几秒钟后唤醒系统。如果它有效,您可以使此解决方法永久生效。创建一个 systemd 单元文件
/etc/systemd/system/toggle-gpp0-to-fix-wakeup.service
[Unit] Description="Disable GPP0 to fix suspend issue" [Service] ExecStart=/bin/sh -c "/bin/echo GPP0 > /proc/acpi/wakeup" [Install] WantedBy=multi-user.target
执行 daemon-reload 并 启动/启用 新创建的单元。
或者,您可以创建一个 udev 规则。假设 GPP0
的 sysfs 节点像示例中一样是 pci:0000:00:01.1
,运行 udevadm info -a -p /sys/bus/pci/devices/0000\:00\:01.1
以获取相关信息,并创建一个像这样的 udev 规则
/etc/udev/rules.d/10-gpp0-acpi-fix.rules
KERNEL=="0000:00:01.1", SUBSYSTEM=="pci", DRIVERS=="pcieport", ATTR{vendor}=="0x1022", ATTR{device}=="0x1483", ATTR{power/wakeup}="disabled"
udev 守护程序默认已在监视系统中的更改。如果需要,您可以手动重新加载规则。
笔记本电脑 Fn 键对应的挂起功能不起作用
如果,无论 logind.conf 中的设置如何,睡眠按钮都不起作用(按下它甚至不会在 syslog 中产生消息),则 logind 可能没有监视键盘设备。[10] 执行
# journalctl --grep="Watching system buttons"
您可能会看到类似这样的内容
May 25 21:28:19 vmarch.lan systemd-logind[210]: Watching system buttons on /dev/input/event2 (Power Button) May 25 21:28:19 vmarch.lan systemd-logind[210]: Watching system buttons on /dev/input/event3 (Sleep Button) May 25 21:28:19 vmarch.lan systemd-logind[210]: Watching system buttons on /dev/input/event4 (Video Bus)
请注意,没有键盘设备。按如下方式列出键盘设备
$ stat -c%N /dev/input/by-id/*-kbd
... /dev/input/by-id/usb-SIGMACHIP_USB_Keyboard-event-kbd -> ../event6 ...
现在获取父键盘设备的 ATTRS{name}
[11]。例如,在上面的列表中,此键盘设备具有 event6
作为设备输入事件,它可以用于搜索其各自的属性名称
# udevadm info -a /dev/input/event6
... KERNEL=="event6" ... ATTRS{name}=="SIGMACHIP USB Keyboard"
现在编写自定义 udev 规则以添加 “power-switch” 标签
/etc/udev/rules.d/70-power-switch-my.rules
ACTION=="remove", GOTO="power_switch_my_end" SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="SIGMACHIP USB Keyboard", TAG+="power-switch" LABEL="power_switch_my_end"
在 重新加载 udev 规则并 重新启动 systemd-logind.service
后,您应该在 logind 的日志中看到 Watching system buttons on /dev/input/event6
。
系统冻结 60 秒,然后唤醒或在唤醒后挂起
自 systemd v256 版本起,systemd 在休眠前会冻结 user.slice
。此过程可能因内核错误而失败,尤其是在使用 KVM 时。[12][13]
日志中的消息会包含 Failed to freeze unit 'user.slice'
在休眠前。当此类问题发生时,尝试登录(启动另一个会话)将会失败,并显示
pam_systemd(process:session): Failed to create session: Job 9876 for unit 'session-6.scope' failed with 'frozen'
要临时恢复到旧的行为,编辑 systemd-suspend.service
、systemd-hibernate.service
、systemd-hybrid-sleep.service
和 systemd-suspend-then-hibernate.service
,并使用以下 drop-in 配置
[Service] Environment=SYSTEMD_SLEEP_FREEZE_USER_SESSIONS=false