Arch Linux Hibernates

MacBook Pro上运行Arch Linux 采用的是双操作系统,由于工作原因,需要经常在macOS和Linux之间切换,如果每次重新登陆到Linux操作系统,都要重头开始准备工作环境会非常繁琐(例如打开同样的编辑器和编辑文件,浏览器以及终端)。采用 Hibernages 可以将运行状态存储到磁盘中,这样下次切换到Linux就可以立即恢复到离开时的状态,提高了工作效率。

注解

我在 Ubuntu Hibernate休眠 实践中也有一些经验可以参考。

电源管理

Linux支持3中不同的挂起系统模式:

  • suspend to RAM(也称为suspend): 切断主机大多数部件的电源,但保持RAM电力,这样RAM可以存储主机的状态。由于维持内存的电力消耗很小,所以suspend可以让笔记本电池较长时间供电,并且恢复运行非常迅速。
  • suspend to disk(也称为hibernate): 通过swap磁盘来保存主机状态,这样就可以不需要电源,完全不消耗电池的电能。缺点是恢复速度比suspend慢,但是可以切换到其他操作系统(例如双启动的macOS)而不会丢失原先的运行状态。
  • suspend to both(也称为hybrid suspend): 同时将主机状态保存在内存和磁盘swap上,但不断开电能供应。如果电池够用,则直接从RAM恢复系统(速度最快),如果电池电能耗尽,则从磁盘恢复主机状态(速度较慢)。虽然后者比从内存恢复要慢很多,但是在电池电能耗尽情况下依然能够保证主机状态不丢失。

底层接口

注解

虽然可以直接使用底层接口实现suspend/hibernate,并且速度较快,但是高层接口可以实现pre-和post-suspend hooks,例如设置硬件时钟,恢复无线网络等。

内核级接口(swsusp)

在内核的 /sys/power/state 接口写入相应字符串可以触发suspend。在内核文档中 states.txt 有详细说明。

用户级软件设置(uswsusp)

uswsusp(“Userspace Software Suspend”)是包装了内核suspend-to-RAM机制,提供在suspsend和resume时候执行一些图形卡配置。

高层接口

systemd

systemd原生提供了suspend, hibernate 和 hybrid 支持,这也是Arch Linux使用的默认接口。

hibernation

要使用hibernate,需要创建swap磁盘,并且在内核启动参数 resume= 中指定内核使用swap,也就是需要配置 initramfs 来告诉内核从用户空间指定的swap恢复。

对于swap分区小于RAM,依然能够实现hibernate:

/sys/power/image_size 控制了 suspend-to-disk 机制创建的镜像大小,这个值是一个非负的整数,默认设置为内存的 2/5 。

可以调整 /sys/power/image_size 大小,可以尽可能缩小这个swap大小,也可以增加这个swap大小来加速hibernate处理速度。注意,suspend镜像不能跨多个swap分区或者多个swap文件,必须完全存储在一个swap分区或者一个swap文件。

需要的内核参数

需要使用内核参数 resume=swap_device ,这里的 swap_device 是持久化块设备命名,例如:

resume=UUID=4209c845-f495-4c43-8a03-5363dd433153
resume="PARTLABEL=Swap partition"
resume=/dev/archVolumeGroup/archLogicalVolume  (如果是LVM逻辑卷)

Hibernation到swap文件

注解

内核5.0之前不支持Btrfs文件系统的swap文件,如果在Btrfs文件系统中使用swap文件存储hibernetes会导致文件系统损坏。虽然能够在Btrfs中将swap文件挂载成一个loop设备,但是这样会显著降低swap性能。

使用swap文件爱你需要传递给内核参数 resume_offset=swap_file_offset

注解

resume 参数必须指向 swap文件所在的卷。对于堆叠类型的块设备,例如加密容器,或者RAID,或者LVM,这意味着 resume 必须指向包含swap文件的文件系统的 unlocked 或者 mapped 设备。

通过 filefreg -v swap_file 可以获得 swap_file_offset 值,输出内容的第一行中 phyiscal_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

上述输出中第一行的 physical_offset 列,即 38912 就是我们查询得到的偏移值。

注解

如果安装了 uswsusp 工具包,则提供了一个 swap-offset 命令可以直接输出swap问价的偏移值:

swap-offset swap_file

Hibernate设置实践

  • 获取swap文件应该设置的大小:

    /sys/power/image_size
    

例如,输出值是 6672080896 则对应大约 6.4GB

  • 创建swap文件:

    dd if=/dev/zero of=/swap bs=64MiB count=100
    
  • 创建swap:

    mkswap /swap
    swapon /swap
    
  • 配置 /etc/fstab 添加swap配置:

    /swap none swap defaults 0 0
    
  • 获取磁盘分区uuid:

    blkid /dev/sda3
    

输出显示:

/dev/sda3: UUID="e38d80cc-4044-4d34-b730-1f0c874ad765" TYPE="ext4" PARTLABEL="arch_linux" PARTUUID="c31f68cd-97f7-4471-93c7-adb62b22a17b"
  • 获取 /swap 文件偏移量:

    filefrag -v /swap
    

输出:

Filesystem type is: ef53
File size of /swap is 6710886400 (1638400 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..   32767:    7798784..   7831551:  32768:
...

则偏移量是: 7798784

  • 需要向内核传递参数:

    resume=UUID=e38d80cc-4044-4d34-b730-1f0c874ad765
    swap_file_offset=7798784
    

注解

我在MacBook Pro上使用的EFI设置启动是采用 efibootmgr ,请参考 MacBook Pro上运行Arch Linux ,所以,这里需要通过 efibootmgr 传递内核参数。

将原先设置efibootmgr命令:

efibootmgr --disk /dev/sda --part 1 --create --label "Arch Linux" --loader /vmlinuz-linux --unicode 'root=PARTUUID=c31f68cd-97f7-4471-93c7-adb62b22a17b rw initrd=\initramfs-linux.img' --verbose

添加上hibernate参数如下:

efibootmgr --disk /dev/sda --part 1 --create --label "Arch Linux" --loader /vmlinuz-linux --unicode 'root=PARTUUID=c31f68cd-97f7-4471-93c7-adb62b22a17b rw initrd=\initramfs-linux.img resume=UUID=e38d80cc-4044-4d34-b730-1f0c874ad765 swap_file_offset=7798784' --verbose
  • 重启操作系统

  • 重启操作系统后,再次登陆到 Xfce 图形界面,此时用户 Log Out 菜单选项中就会增加 HibernateHybrid Sleep 选项。并且 cat /proc/cmdline 可以看到内核参数:

    root=PARTUUID=c31f68cd-97f7-4471-93c7-adb62b22a17b rw initrd=\initramfs-linux.img resume=UUID=e38d80cc-4044-4d34-b730-1f0c874ad765 swap_file_offset=7798784
    

注解

不过,我此时使用 Hibernate 功能发现操作系统是直接关机了,并没有成功恢复到

参考 Arch Linux社区文档 - MacBookPro11,x#Kernel parameters 提示需要向内核传递参数 acpi_osi=Darwin 才能使 suspension/hibernation 工作正常。

所以MacBook Pro完整的内核启动配置,请参考 MacBook Pro上运行Arch Linux

但是,我发现并没有实现hibernate存储到磁盘的操作,每次执行 systemctl hibernate 实际是直接关机。

按照内核文档:

The states are represented by strings that can be read or written to the
/sys/power/state file.  Those strings may be "mem", "standby", "freeze" and
"disk", where the last three always represent Power-On Suspend (if supported),
Suspend-To-Idle and hibernation (Suspend-To-Disk), respectively.

通过直接 echo disk > /sys/power/state 应该能够直接 suspend to disk ,但是我发现在字符终端显示设备不能写入? why