Fedora でハイバネーションを使う

Posted on 2024/04/16 in tech

tl;dr

ハイバネーションを使うなら素直に zswap を使えないか検討する。

ただスワップ領域は暗号化されないので注意。


Fedora でハイバネーションを使いたい

Linux のサスペンドには Arch wiki に詳しくまとまっている通りいくつかの種類がある。

その中でもハイバネーションはシステムの電源を完全に落とす。この電源を落とすという性質がある以上、不揮発なスワップ領域にマシンの状態を保存する必要がある。

zram はハイバネーションできない

Fedora Workstaion デフォルトのスワップには zram が使われる。1

zram は RAM 上にページデータを圧縮保存するブロックデバイスを作成する。

RAM 上にあるということは電源を落とせば揮発する。つまり zram のみだとハイバネーションは使えない。

zram を使いながらハイバネーションする

じゃぁ zram を使っているとハイバネーションできない、というわけではなく、ストレージデバイス上にもスワップ領域を作成すればいい。

ただ、ストレージに作成したスワップ(以下ストレージスワップと呼ぶ)は zram と一緒に使わない方がいいらしい(要出典)ので、ハイバネーション時にのみストレージスワップを有効化する。

このあたりは以下の記事を参考にした。本記事は systemd ユニットファイルや SELinux 周りの構成を筆者なりに最適化・整理したものである。

Hibernation in Fedora Workstation - Fedora Magazine

スワップ領域の作成

Fedora はデフォルトで btrfs を使用するので btrfs の手順。2

# 通常のファイルと扱い方が違うため subvolume にする
sudo btrfs subvolume create /var/swap
sudo touch /var/swap/swapfile
sudo chattr +C /var/swap/swapfile # Copy-on-Write 無効化

# スワップ領域を任意のサイズで
sudo dd if=/dev/zero of=/var/swap/swapfile bs=1G count=<任意のサイズ>
sudo chmod 600 /var/swap/swapfile

# SELinux コンテキストラベルを設定
sudo semanage fcontext -a -t swapfile_t -s system_u "/var/swap(/.*)?"
# セキュリティラベルを反映
sudo restorecon -FRv /var/swap

# スワップ領域準備
sudo mkswap /var/swap/swapfile

以前は mkswap で SELinux ラベルが付与されていた3 ようだが、今はオプション で指定なりしないと付与できない。上記では /var/swap サブボリューム配下にコンテキストラベル system_u:object_r:swapfile_t を付与している。

fstab 設定

作成したストレージスワップを swapon(マウント)できるように /etc/fstab に追記する。

ただこのスワップはハイバネーション時にしか使わないので自動マウントしないよう noauto を設定する

/var/swap/swapfile none swap noauto 0 0

追記したら systemd で読み込む。4

sudo systemctl daemon-reload

dracut 設定(initramfs の作成)

Fedora は initramfs の生成に dracut を利用する。

ハイバネーションから復帰したときにストレージスワップからシステムを復元する関係で、initramfs に resume モジュールを追加しする。

/etc/dracut.conf.d/ 配下に *.conf ファイルをし以下を記述。

add_dracutmodules+=" resume "

initramfs を生成。

sudo dracut --force

grub の設定(カーネルパラメータの設定)

マシン起動時のカーネルパラメータを追加する。5

ストレージスワップの UUID を取得。

findmnt -no UUID -T /var/swap/swapfile

オフセットを取得。

sudo btrfs inspect-internal map-swapfile -r /var/swap/swapfile

/etc/default/grubGRUB_CMDLINE_LINUX 変数に resumeresume_offset のパラメータを追加し、先程の UUID とオフセットを設定する

GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX resume=UUID=<スワップファイルのUUID> resume_offset=<swapfile のオフセット>"

追記したら grub ファイルを更新する。

sudo grub2-mkconfig -o /boot/grub2/grub.cfg

ここまでやったら 再起動 する。

systemd unit の設定

ハイバネーションは systemd を利用して行う。

systemctl edit systemd-hibernate.service して /etc/systemd/system/systemd-hibernate.service.d/override.conf を次のように作成する。

[Service]
# /var/swap/swapfile のマウント(swapon)
ExecStartPre=/usr/bin/systemctl start var-swap-swapfile.swap
# /dev/zram0 のアンマウント(swapoff)
ExecStartPre=/usr/bin/systemctl stop dev-zram0.swap

# /dev/zram0 のマウント
ExecStartPost=/usr/bin/systemctl start dev-zram0.swap
# /var/swap/swapfile のアンマウント
ExecStartPost=/usr/bin/systemctl stop var-swap-swapfile.swap

上記で何をしているかというと systemd を通して

  • ハイバネーション前:ストレージスワップを マウントしてから zram スワップをアンマウント
  • ハイバネーション後:zram スワップを マウントしてから ストレージスワップをアンマウント

している。

一度 zram とストレージスワップを共存させるのがポイント。

スワップをアンマウントするとき、当然ながらスワップが保持していたページデータをメモリに書き戻す必要がある。が、十分な領域がメモリになければ書き戻せない6。退避先を確保するため、一度 2 つのスワップを同時にマウントする。

なお systemd-hibernate.service(8) によると systemd-hibernate 以外の次のサービスもストレージスワップが必要になる。

  • systemd-suspend-then-hibernate.service (サスペンドしてからハイバネーションへ移行する)
  • systemd-hybrid-sleep.service (マシンの状態をスワップへ保存しサスペンドする)

この 2 つは RAM からの復帰もできるので、zram のアンマウントは不要でいいかもしれない。

[Service]
# ハイバネーション前に /var/swap/swapfile をマウント
ExecStartPre=/usr/bin/systemctl start var-swap-swapfile.swap

# ハイバネーション復帰時に /var/swap/swapfile をアンマウント
ExecStartPost=/usr/bin/systemctl stop var-swap-swapfile.swap

とそれらしいことを書いてきたが、メモリ負荷が高いときの挙動や単純なハイバネーション以外の挙動は未検証なので、誤りがあればツッコミをいただきたい…

ハイバネーションする

ここまでできれば systemctl hibernate でハイバネーションできるはず。(systemctl start … ではないので注意 )

同様に systemctl suspend-then-hibernatesystemctl hybrid-sleep も使えるはず。

zswap でいいんじゃないか

zram は RAM で完結するブロックデバイスなので、当然ストレージの IO が減らせるメリットがある。

しかしここまで書いておいてだが、 ハイバネーションのためにストレージスワップにページデータを書き出して、ハイバネーションから復帰したらまた RAM に書き戻す というのは、なんだかとても効率が悪い気がする。

zram とよくセットで語られる(筆者主観)zswap はストレージスワップを使いながらストレージの IO を減らせる。

結論、どうしてもハイバネーションを使いたいなら、zswap を使うのがスマートな気はする。

zswap

zswap はスワップアウトされたページを、まず RAM 上で圧縮キャッシュとしてプールする。ストレージスワップへの書き出しはこの圧縮キャッシュプールでも賄えなくなったときに限定される。ので、ストレージ IO も減らしつつストレージスワップの恩恵を得ることができる。

RAM 上にページングデータを圧縮してもつ のは zram に似ているが、zswap はストレージスワップへの書き出しも行う。

つまりストレージスワップの利用が前提になる。つまりハイバネーションも使える。

zram 無効化

zswap と zram とは併用しない方がいいらしい

zram を無効化するにはいくつか方法があるので、以下を参考にされたい。

How can it be disabled? -- Changes/SwapOnZRAM - Fedora Project Wiki

zswap 有効化

記事前半の手順でストレージスワップは作成済なので、カーネルパラメータを設定する。

/etc/default/grubGRUB_CMDLINE_LINUX 変数を次のように定義する。

GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX zswap.enabled=1 zswap.max_pool_percent=20 zswap.compressor=lz4 resume=UUID=<スワップファイルのUUID> resume_offset=<swapfile のオフセット>"

zswap.enabled=1 で zswap を有効化している。

zswap.max_pool_percentzswap.compressor といったパラメータ設定は zswap - ArchWiki などを参考とされたい。

grub.cfg を忘れずに更新すること。

sudo grub2-mkconfig -o /boot/grub2/grub.cfg

再起動すれば zswap が有効化できているはず。swapon コマンドで確認できる:

$ swapon
NAME               TYPE SIZE USED PRIO
/var/swap/swapfile file  24G 4.3M   -2

ストレージスワップを使う上での注意

留意すべき点として、ストレージスワップは暗号化なしのページングデータが保存される。そのためセキュアとは言えないらしい。7

確かに最近「サスペンド」は見ても「ハイバネーション」は見なくなった。そういった背景もあるのだろうか。