Power management (简体中文)/Suspend and hibernate (简体中文)

From ArchWiki
Jump to navigation Jump to search

Tango-preferences-desktop-locale.png本文或本节需要翻译。要贡献翻译,请访问简体中文翻译团队Tango-preferences-desktop-locale.png

翻译状态:本文是 Power_management/Suspend_and_hibernate翻译。上次翻译日期:2020-07-13。如果英文版本有所更改,则您可以帮助同步翻译。

现主要有三种挂起方式:suspend to RAM(挂起到内存,通称挂起/睡眠),suspend to disk(通称休眠),和hybrid suspend或者suspend to both(内存和硬盘都保存当前内存状态,通称混合休眠):

  • 睡眠(挂起)将机器中大多数和RAM不相关的部件断电,电脑状态仅仅保存在RAM中。关闭多数外围设备,保留鼠标键盘等少数外围设备,以对用户操作进行快速响应。建议用户将笔记本设置为合盖时进入此模式。同样建议将系统设置为使用电池而用户离开时自动进入此模式。
  • 休眠将机器内容保存至swap space并完全断电。再次开机时从硬盘读取swap进内存,恢复运行状态。和睡眠不同,休眠时不会耗电。
  • 混合休眠将电脑状态保存进swap,但并不对电脑断电,而是引用睡眠机制,从而使未掉电的电脑能从内存中恢复。如果电脑掉电(断电且电池耗尽),系统也可以从硬盘的swap中恢复,尽管比从内存中恢复慢一些。

以上三者均由许多底层接口提供基础功能,再由高级接口进行一定调整,以适配一些较为复杂的硬件与内核模块(如显卡唤醒后的重新初始化)

底层接口

直接使用低级接口显然会比任何高级接口都快很多,因为执行睡眠/休眠前后的钩子(hooks)需要时间。然而,钩子可以提供很多功能,如正确设置设备时钟、恢复无线网络状态等。因此,虽然这些接口可以被直接使用,我们仍然建议用户使用高级接口进行睡眠/休眠。

内核休眠(软件休眠,swsusp)

最直接的方法是直接告知内核中的软件挂起代码(swsusp)进入挂起状态,具体的方法和状态取决于硬件支持的程度。在现代内核中,向 /sys/power/state 写入特定字符串是触发此挂起的主要机制。

更多信息详见Linux内核文档

用户空间软件休眠(uswswsp)

uswsusp(“Userspace Software Suspend”)是内核Suspend to RAM机制的封装,该机制在挂起前和恢复后从用户空间执行一些有关图形适配器的操作。

详见 Uswsusp

高级接口

这些软件包的目标是提供二进制文件或脚本,使用户可以调它们来进行睡眠或休眠。在实际使用中,往往由其它软件(如桌面环境/DE)将它们与电源按钮、菜单点击或笔记本电脑盖事件联系起来。如果不想借助其他软件调用高级接口,又希望设备能在某些电源事件(如合上盖子或电池耗尽)时自动睡眠/休眠,你也许需要看看Acpid

systemd

systemd为睡眠、休眠和混合休眠提供原生支持。详见 Power management#Power management with systemd 。systemd是 Arch Linux 默认使用的接口。

关于配置睡眠或休眠钩子,详见 Power management#Sleep hooks。又见 systemctl(1)systemd-sleep(8)systemd.special(7)

休眠

为了使用休眠,用户需要创建一个交换分区或文件。使用resume= 内核参数向内核传递swap信息,该参数应通过引导程序配置。您还需要configure the initramfs[断开的链接:无效的部分]。这将让内核尝试从早期用户空间中的指定swap分区/文件恢复。下面将详细描述这三个步骤。

swap分区/文件的大小

即使swap比内存小,成功休眠的可能性仍然很大。内核文档如是说:

/sys/power/image_size控制由休眠机制创建的镜像的大小。它可以被写入一个字符串,表示将用作镜像大小上限的非负整数(以字节为单位)。休眠机制将尽力确保镜像大小不会超过这个数字。但是,如果这是不可能的,它将尝试使用尽可能小的镜像休眠。特别地,如果将“0”写入此文件,则休眠镜像将尽可能小。读取该文件将显示当前镜像大小限制,默认设置为可用RAM的2/5。

您可以减小/sys/power/image_size的设定值以使休眠镜像尽可能小(对于小swap),或者增大它以加快休眠过程(也许)。对于RAM很大大的系统,较小的值可能会显著提高系统从休眠中恢复的速度。这是一个临时文件,参阅Systemd#Temporary files[断开的链接:无效的部分]以固定你的修改。

休眠镜像不能跨多个交换分区和/或交换文件。它必须完全适配一个交换分区或一个交换文件[1]

必需的内核参数

想要休眠,必须传递kernel parameter resume=swap_device。(以 persistent block device naming 方法中的任何一个替换掉swap_device )如:

  • resume=UUID=4209c845-f495-4c43-8a03-5363dd433153
  • resume=“PARTLABEL=swap分区卷标”
  • resume=/dev/archVolumeGroup/archLogicalVolume——如果swap在LVM逻辑卷上

内核参数只有在重新启动后才会生效。要想不重启而立即休眠,请从lsblk获取卷的主要和次要设备号,并 echo major:minor/sys/power/resume。如果使用交换文件,则还应将 resume offset 添加到/sys/power/resume_offset[2]

例如,如果交换设备是8:3

# echo 8:3 > /sys/power/resume

或者在休眠到交换文件时,如果交换文件位于卷8:2上并且offset为38912

# echo 8:2 > /sys/power/resume
# echo 38912 > /sys/power/resume_offset

休眠到交换文件

警告: Btrfs版本5.0之前的Linux内核不支持交换文件。不注意此警告可能会导致文件系统损坏。当通过循环设备装入Btrfs时,交换文件可能会被使用,这将导致交换性能严重下降。

使用交换文件需要设置resume=swap_device,另外还需要设置resume_offset=swap_file_offset内核参数。见 内核文档


swap_device 是交换文件所在的卷,其格式与root parameter相同。swap_file_offset的值可以通过运行filefrag -v swap_file来获得,输出为表格形式,所需的值位于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
...

在本例中,swap_file_offset 的值是38912..(包括英文句点在内)。

提示:
  • 以下可用于替换swap_devicefindmnt -no UUID -T /swapfile
  • 以下可用于替换swap_file_offsetfilefrag -v /swapfile | awk '{ if($1=="0:"){print $4} }'
  • swap_file_offset的值也可以通过运行swap-offset swap_file来获得。工具集uswsusp中提供了swap-offset二进制文件。如果使用此方法,则必须在/etc/suspend.conf通过键resume deviceresume offset。在这种情况下,不需要重新启动。
注意:
  • 对于堆叠块设备,如加密容器(LUKS)、RAID或LVM,resume参数必须指向包含交换文件的文件系统的未锁定/映射设备。
  • 如果交换文件在/home/中,则systemd-logind将无法确定其大小,因此将阻止休眠。解决办法见systemd issue 15354
提示: 如果你只想休眠而不扩展RAM,则可能需要减少交换文件的swappiness

休眠到 Btrfs 上的交换文件中

最新版本的 systemd 支持在交换文件上休眠[3]

可以使用btrfs_map_physical.c计算resume_offset。 不要尝试使用filefrag工具,在Btrfs上,从filefrag获得的physical_offset不是实际offset。因为btefs有一个虚拟磁盘地址空间以支持多个设备。[4] 下载或复制tool btrfs_map_physical.c到名为btrfs_map_physical.c的文件中,然后编译它,

$ 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。在此案例中,我们使用4009762816。同样需要在getconf PAGESIZE中获得pagesize。

要计算resume_offset的值,请将物理偏移量除以页面大小。在这个例子中,它是4009762816 / 4096 = 978946

休眠到精简配置的LVM卷中

在精简配置的LVM卷中休眠是可能的,但必须确保该卷已完全分配。否则系统将无法从中恢复。

可以通过简单地用零填充来完全分配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%的Data%

警告: 不要在用于休眠的精简配置的swap分区上使用TRIM,即:不要在/etc/fstab使用discard,也不要在swapon时加入-d--discard参数。否则已被使用的空间会被重新去分配

需要添加resume=/dev/sdxY (sdxY 是swap分区的名字) ,让系统在启动时读取swap分区中的内容。

配置 initramfs

1. 添加resume钩子或systemd钩子 编辑/etc/mkinitcpio.conf,在HOOKS行中添加resume钩子或systemd钩子: 例如该行原有内容是:

HOOKS="base udev autodetect modconf block filesystems keyboard fsck"

添加resume后就是:

HOOKS="base udev resume autodetect modconf block filesystems keyboard fsck"

添加systemd后是:

HOOKS="base udev systemd autodetect modconf block filesystems keyboard fsck"

resume和systemd二选一加入即可。

注意: 如果使用lvm分区,需要将resume放在lvm后面

使用lvm的示例:

HOOKS="base udev autodetect modconf block lvm2 resume filesystems keyboard fsck"

2. 重新生成 initramfs 镜像:

mkinitcpio -P

设置低电量休眠

用于带有内置电池的设备。

当电池电量极低时,使其休眠,以免丢失数据。 修改/etc/UPower/UPower.conf相关配置.示例,在电量低至%5时自动休眠:

PercentageLow=15  #<=15%低电量
PercentageCritical=10  #<=10%警告电量
PercentageAction=5  #<=5%执行动作(即CriticalPowerAction)的电量
CriticalPowerAction=Hibernate #(在本示例中是电量<=5%)执行休眠

当电池低至5%,设备会自动休眠。

CriticalPowerAction的取值有Poweroff、Hibernate和Hybid-sleep。

更多配置项参考该文件中的说明。

设置盖上笔记本盖子或按下电源键休眠

1. 编辑/etc/systemd/logind.conf , 盖上盖子休眠,添加:

HandleLidSwitch=hibernate

按下电源键休眠,添加:

HandlePowerKey=hibernate

2. 执行以下命令使其立即生效:

systemctl restart systemd-logind

其他详细的设置请参考 电源管理页面

参看

linux-laptop笔记本相关 linux笔记本设置休眠