冬眠 Fedora 工作站

本文将引导您完成休眠的手动设置 Fedora Linux 36 工作站使用 BTRFS 并且基于 github 上 eloylp 的要点.

目标和理由

休眠将您机器的当前运行时状态——有效地存储在您的 RAM 中的内容到磁盘上并执行干净的关机。 下次启动时,此状态会从磁盘恢复到内存,因此包括打开的程序在内的所有内容都是您离开它的方式。

Fedora 工作站使用 ZRAM。 这是一种在 RAM 的一部分内使用压缩进行交换的复杂方法,以避免较慢的磁盘交换文件。 不幸的是,这意味着在关闭机器电源时,您没有永久空间来在休眠时移动 RAM。

这个怎么运作

该技术将 systemd 和 dracut 配置为在磁盘上的临时交换文件中存储和恢复 RAM 的内容。 交换文件在休眠之前创建并在休眠后立即删除,以避免 ZRAM 出现问题。 不建议将持久交换文件与 ZRAM 结合使用,因为它会产生一些影响系统稳定性的令人困惑的问题。

关于兼容性和期望的一句话

遵循本指南的休眠可能无法在您的特定机器上完美运行。 由于某些驱动程序可能存在的缺点,您可能会在从休眠状态恢复后遇到故障,例如无法工作的 wifi 或显示。 在这种情况下,请随时联系 github上的要点,或尝试本文底部故障排除部分的提示。

本文中介绍的更改与 systemd hibernation.service 和 hibernation.target 单元相关联,因此如果您不启动休眠,它们不会自行执行,也不会干扰您的系统。 话虽如此,如果它不起作用,它仍然会增加一些您可能想要删除的小膨胀。

冬眠 Fedora 工作站

第一步是创建一个 btrfs 子卷来包含交换文件。

$ btrfs subvolume create /swap

为了计算交换文件的大小,请使用 swapon 来获取 zram 设备的大小。

$ swapon
NAME       TYPE      SIZE USED PRIO
/dev/zram0 partition   8G   0B  100

在这 example 该机器有 16G 的 RAM 和一个 8G 的 zram 设备。 ZRAM 存储的系统 RAM 量大约是您的一部分 RAM 中压缩的系统 RAM 量的两倍。 让它沉入一会儿。 这意味着这台机器的内存总共可以容纳 8G * 2 + 8G 的 RAM,这等于 24G 的未压缩数据。 使用以下命令创建和配置交换文件。

$ touch /swap/swapfile
# Disable Copy On Write on the file
$ chattr +C /swap/swapfile
$ fallocate --length 24G /swap/swapfile
$ chmod 600 /swap/swapfile 
$ mkswap /swap/swapfile

修改 dracut 配置并重建您的 initramfs 以包含

resume 模块,因此它可以稍后在启动时恢复状态。

$ cat <<-EOF | sudo tee /etc/dracut.conf.d/resume.conf
add_dracutmodules+=" resume "
EOF
$ dracut -f

为了配置 grub 以告诉内核使用交换文件从休眠中恢复,您需要 UUID 和物理偏移量。

使用以下命令确定交换文件的 UUID 并记下它。

$ findmnt -no UUID -T /swap/swapfile
dbb0f71f-8fe9-491e-bce7-4e0e3125ecb8

计算正确的偏移量。 为了做到这一点,不幸的是,您需要 gcc 和 btrfs_map_physical 工具的来源,它计算磁盘上交换文件的物理偏移量。 在您放置源代码的目录中调用 gcc 并运行该工具。

$ gcc -O2 -o btrfs_map_physical btrfs_map_physical.c
$ ./btrfs_map_physical /path/to/swapfile

FILE OFFSET  EXTENT TYPE  LOGICAL SIZE  LOGICAL OFFSET  PHYSICAL SIZE  DEVID  PHYSICAL OFFSET
0            regular      4096          2927632384      268435456      1      <4009762816>
4096         prealloc     268431360     2927636480      268431360      1      4009766912
268435456    prealloc     268435456     3251634176      268435456      1      4333764608
536870912    prealloc     268435456     3520069632      268435456      1      4602200064
805306368    prealloc     268435456     3788505088      268435456      1      4870635520
1073741824   prealloc     268435456     4056940544      268435456      1      5139070976
1342177280   prealloc     268435456     4325376000      268435456      1      5407506432
1610612736   prealloc     268435456     4593811456      268435456      1      5675941888

PHYSICAL OFFSET 列中的第一个值是相关值。 在上述 example 这是 4009762816.

记下您从 getconf PAGESIZE 获得的页面大小。

通过物理偏移除以页面大小来计算内核 resume_offset。 在这 example 即 4009762816 / 4096 = 978946。

更新您的 grub 配置文件并添加 resume 和 resume_offset 内核命令行参数。

grubby --args="resume=UUID=dbb0f71f-8fe9-491e-bce7-4e0e3125ecb8 resume_offset=2459934" --update-kernel=ALL

创建的交换文件仅用于系统关闭和启动的休眠阶段,因此未在 fstab 中配置。 Systemd 单元控制此行为,因此创建两个单元 hibernate-preparation.service 和 hibernate-resume.service。

$ cat <<-EOF | sudo tee /etc/systemd/system/hibernate-preparation.service
[Unit]
Description=Enable swap file and disable zram before hibernate
Before=systemd-hibernate.service

[Service]
User=root
Type=oneshot
ExecStart=/bin/bash -c "/usr/sbin/swapon /swap/swapfile && /usr/sbin/swapoff /dev/zram0"

[Install]
WantedBy=systemd-hibernate.service
EOF
$ systemctl enable hibernate-preparation.service
$ cat <<-EOF | sudo tee /etc/systemd/system/hibernate-resume.service
[Unit]
Description=Disable swap after resuming from hibernation
After=hibernate.target

[Service]
User=root
Type=oneshot
ExecStart=/usr/sbin/swapoff /swap/swapfile

[Install]
WantedBy=hibernate.target
EOF
$ systemctl enable hibernate-resume.service

Systemd 对登录和休眠进行内存检查。 为了避免在交换文件和 zram 之间来回移动内存时出现问题,请禁用其中一些。

$ mkdir -p /etc/systemd/system/systemd-logind.service.d/
$ cat <<-EOF | sudo tee /etc/systemd/system/systemd-logind.service.d/override.conf
[Service]
Environment=SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1
EOF
$ mkdir -p /etc/systemd/system/systemd-hibernate.service.d/
$ cat <<-EOF | sudo tee /etc/systemd/system/systemd-hibernate.service.d/override.conf
[Service]
Environment=SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1
EOF

重新启动计算机以使更改生效. 如果您不先重新启动,则以下 SELinux 配置将不起作用。

SELinux 还不喜欢休眠尝试。 用新政策改变它。 一种简单但“粗暴”的方法是启动休眠并通过 audit2allow 使用此失败尝试的审核日志。 以下命令将失败,返回登录提示。

systemctl hibernate

再次登录后检查审核日志,编译策略并安装它。 -b 选项过滤来自上次引导的审计日志条目。 -M 选项将所有过滤规则编译成一个模块,然后使用 semodule -i 安装该模块。

$ audit2allow -b
#============= systemd_sleep_t ==============
allow systemd_sleep_t unlabeled_t:dir search;
$ cd /tmp
$ audit2allow -b -M systemd_sleep
$ semodule -i systemd_sleep.pp

再次通过 systemctl hibernate 检查休眠是否正常工作。 恢复后检查 ZRAM 确实是唯一的活动交换设备。

$ swapon
NAME       TYPE      SIZE USED PRIO
/dev/zram0 partition   8G   0B  100

您现在已配置休眠。

GNOME Shell 休眠集成

您可能希望在 GNOME Shell “关机/注销”部分添加一个休眠按钮。 查看扩展程序 休眠状态按钮 这样做。

故障排除

解决任何问题的第一个地方是通过 journalctl -b。 在尝试休眠后,查看日志的末尾,以查明告诉您可能出现什么问题的日志条目。

错误信息的另一个来源是问题报告工具。 尤其是不常见但更具体到您的硬件配置的问题。 在尝试休眠之前和之后查看它,看看是否出现了问题。 通过 BugZilla 跟进任何问题,看看其他人是否遇到类似问题。

还原更改

要撤消上述更改,请遵循以下清单:

  • 删除交换文件
  • 删除交换子卷
  • 删除 dracut 配置并重建 dracut
  • 通过 grubby –remove-args= 删除内核命令行参数
  • 禁用和删除休眠准备和恢复服务
  • 删除 systemd-logind.service 和 systemd-hibernation.service 的 systemd 覆盖
  • 通过 semodule -r systemd_sleep 删除 SELinux 模块

学分和其他资源

本文是主要基于 eloylp 工作的社区努力。 作为本文的作者,我想澄清一下,我参与了讨论以推进这背后的要点,但更多的人为这项工作做出了贡献。 确保检查 github上的讨论.

已经有一些 ansible 剧本和 shell 脚本来自动化本指南中描述的过程。 为了 example 通过以下方式查看 shell 脚本 克罗温皮特里扎克 或 ansible 剧本 约普

拱维基 有关怎样计算交换文件偏移量的完整指南。