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/grub
の GRUB_CMDLINE_LINUX
変数に resume
と resume_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-hibernate
や systemctl 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/grub
の GRUB_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_percent
や zswap.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
確かに最近「サスペンド」は見ても「ハイバネーション」は見なくなった。そういった背景もあるのだろうか。