電源管理/サスペンドとハイバネート
現在サスペンドには3つの手法が存在します: suspend to RAM (通常はサスペンドとだけ呼ばれます)、suspend to disk (通常はハイバネートと呼ばれます)、そして hybrid suspend (suspend to both とも呼ばれます):
- Suspend to RAM は RAM を除くマシンのほとんど全てのパーツの電源を切ります。RAM への電源はマシンの状態を保存するために必要です。電力を多く節約できるので、ラップトップでは、バッテリーでコンピュータが稼働していてフタが閉じられた時 (もしくはユーザーが長い間操作しなかった時) は自動的にこのモードに移行するのが得策でしょう。
- Suspend to disk はマシンの状態をスワップ領域に保存してマシンの電源を完全にオフにします。マシンに電源を入れた時、状態が復元されます。それまでは、電力消費量はゼロです。
- Suspend to both はマシンの状態をスワップ領域に保存しますが、マシンの電源を切りません。代わりに、通常の suspend to RAM を呼び出します。これによって、バッテリーを使いきっても、システムを RAM から復帰することが可能です。バッテリーが枯渇した時は、システムはディスクから復帰し、RAM からの復帰に比べて時間がかかりますが、システムの状態が失われることはありません。
基本的な機能を提供する低レベルなインターフェイス (バックエンド) が複数存在し、問題のあるハードウェアドライバ・カーネルモジュール (例: ビデオカードの再初期化) を扱う機能を提供する高レベルなインターフェイスもいくつかあります。
低レベルインターフェイス
これらのインターフェイスは直接使うこともできますが、通常は高レベルインターフェイスを使ってサスペンド・ハイバネートを行うとよいでしょう。低レベルなインターフェイスを直接使うと、サスペンドの前や後に行うフック処理を全て実行する高レベルインターフェイスよりもかなり早くサスペンドが可能です。ただしフックはハードウェアクロックの設定や、ワイヤレスの復旧などを正しく処理することができます。
カーネル (swsusp)
直球の方法はカーネル内のソフトウェアサスペンドコード (swsusp) にサスペンド状態に入るよう直接伝えることです。実際の方法と状態はハードウェアサポートのレベルによります。最近のカーネルでは、サスペンドにするために /sys/power/state
に適切な文字列を書くことが主な方法になっています。
詳しくは カーネルドキュメント を参照してください。
uswsusp
uswsusp ('Userspace Software Suspend') はカーネルの suspend-to-RAM のラッパーで、サスペンドの前と復帰の後にユーザー空間からグラフィックアダプタの操作を行います。
Uswsusp の記事を参照してください。
高レベルインターフェイス
systemd
systemd はサスペンド・ハイバネート・ハイブリッドサスペンドを行うためのネイティブのコマンドを提供しています。詳しくは 電源管理#systemd による電源管理 を見て下さい。これは Arch Linux で使われているデフォルトのインターフェースです。
サスペンド・ハイバネートのフックの設定に関する情報は電源管理#スリープフックに載っています。man systemctl
, man systemd-sleep
, man systemd.special
もあわせて参照してください。
ハイバネーション
ハイバネーションを使うには、スワップパーティションかスワップファイルを作成する必要があります。そして resume=
カーネルパラメータを使ってスワップを指定してください。カーネルパラメータはブートローダで設定します。initramfs の設定も必要になります。設定によってカーネルは初期ユーザー空間で指定されたスワップからの復帰を試みます。以下ではスワップの作成・カーネルパラメータの設定・initramfs の設定について詳細に説明します。
About swap partition/file size
スワップパーティションが RAM より小さかったとしても、ハイバネートが成功する可能性は高いと思われます。image_size
sysfs(5) 疑似ファイルに関する情報は kernel documentation の "image_size" を見てください。
(スワップパーティションを小さくして) /sys/power/image_size
の値を減らしてサスペンドのイメージを出来る限り小さくすることも、値を増やしてハイバネーションを高速化することも可能です。大きな容量の RAM を搭載しているシステムでは、より小さい値にするとハイバネートからの復帰が劇的に速くなることがあります。image_size
の値を再起動後も保持するには systemd#systemd-tmpfiles - 一時ファイル を見てください。
サスペンドイメージは複数のスワップパーティション/スワップファイルにまたがって保存することができません。イメージのすべての部分が1つのスワップパーティション/スワップファイルに収まらなければなりません。[1]
必要なカーネルパラメータ
カーネルパラメータ resume=swap_device
を使う必要があります。永続的なブロックデバイスの命名を swap_device
に使用することができます。例:
resume=/dev/sda1
resume=UUID=4209c845-f495-4c43-8a03-5363dd433153
resume=/dev/mapper/archVolumeGroup-archLogicVolume
-- スワップが LVM 論理ボリュームにある場合
カーネルパラメータは再起動後に有効となります。すぐにハイバネートできるようにするには、lsblk を使ってボリュームのメジャーデバイスナンバーとマイナーデバイスナンバーを手に入れて、/sys/power/resume
に major:minor
という形式で書き込んでください。スワップファイルを使用している場合は、追加で /sys/power/resume_offset
に resume オフセットを書き込んでください。[2]
例えば、スワップデバイスが 8:3
の場合:
# echo 8:3 > /sys/power/resume
スワップファイルにハイバネートする場合で、スワップファイルがボリューム 8:2
にあり、オフセットが 38912
の場合:
# echo 8:2 > /sys/power/resume # echo 38912 > /sys/power/resume_offset
スワップファイル を使用するには resume=swap_device
だけでなく、resume_offset=swap_file_offset
カーネルパラメータも設定する必要があります。カーネルのドキュメントを見てください。
swap_device
はスワップファイルが存在するボリュームで、root パラメータと同じ形式に従います。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
の値は2つのピリオドが付いている最初の 38912
です。
Btrfs のスワップファイルへのハイバネーション
スワップファイルへの休止状態は、systemd の最近のバージョン [3] でサポートされています。
resume_offset 番号は、 tool btrfs_map_physical.c を使用して計算できます。 Btrfs では、 filefrag ツールを使用しないでください。 filefrag から取得する 物理的 オフセットは、ディスク上の実際の物理的オフセットではありません。 複数のデバイスをサポートするために、仮想ディスクのアドレス空間があります。 [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
このツールによって返される最初の物理オフセットに注意してください。 この例では、 4009762816
を使用します。 getconf PAGESIZE
で見つけることができるページサイズにも注意してください。
resume_offset
値を計算するには、物理オフセットをページサイズで割ります。 この例では、 4009762816 / 4096 = 978946
です。
thinly-provisioned LVM ボリュームへのハイバネーション
thinly-provisioned 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%のデータ使用量であると表示されます。
initramfs の設定
- initramfs で
base
フックを使っている場合 (Arch ではデフォルトで使っています)、/etc/mkinitcpio.conf
にresume
フックを追加する必要があります。ラベルあるいは UUID どちらを使用している場合でもスワップパーティションは udev デバイスノードによって参照されるので、resume
フックは必ずfilesystems
の前に追加してください。デフォルトのフック設定にresume
フックを追加すると以下のようになります:
HOOKS="base udev autodetect modconf block resume filesystems keyboard fsck"
- 変更を適用するために initramfs の再生成を忘れずに行ってください。
- initramfs で
systemd
フックを使っている場合は、復帰機構が既に提供されているので、フックを追加する必要はありません。
Intel Rapid Start Technology (IRST)
Intel Rapid Start Technology (IRST) が有効の場合、 deep sleep からの再開には "S3から再開するよりも数秒長くなりますが、休止状態から再開するよりもはるかに高速です"。
Intel ベースのシステムの多くは、 IRST のファームウェアをサポートしていますが、 (HDDではなく) SSD 上に特別なパーティションを必要とします。 Windows の OEM 展開では、Arch Linux インストールプロセス中に (SSD 全体を消去して再パーティションするのではなく) 保持できる IRST パーティションがすでに存在している場合があります。システムの RAM と同じサイズの未フォーマットパーティションとして表示されます。
しかし、ドライブ全体を消去してパーティションを切り直すつもりなら (あるいはすでにそうしてしまっているなら) IRST パーティションも再作成しなければなりません。これを行うには、システムの RAM と同じサイズの空のパーティションを作成し、そのパーティションの種類が GPT パーティションの場合は GUID D3BFE2DE-3DAF-11DF-BA40-E3A556D89593
に、 MBR パーティションの場合は ID 0 x 84
に設定します。また、システムのファームウェア設定で IRST のサポートを有効にする必要がある場合もあります。
IRST 休止状態プロセスの時間 ("RAMの内容全体を特殊なパーティションに" コピー) は、システムの RAM サイズと SSD 速度によって異なり、20~60秒かかります。システムによっては、プロセスの完了を LED インジケータで示す場合があります (点滅が停止した場合など)
トラブルシューティング
ACPI_OS_NAME
DSDT table を動作するように設定することができます。DSDT の記事を参照してください。
サスペンド/ハイバネートが動作しない、あるいはたまに動作しなくなる
サスペンドやハイバネートをした場合、あるいは復帰した場合に画面が表示されなくなるという報告が多数存在します。ノートパソコンとデスクトップの両方で問題は確認されています。正式な解決方法ではありませんが、古いカーネル、特に LTS カーネルに切り替えることで問題は解決することがあります。
initramfs からのデバイスの初期化によって画面が表示されなくなっていることもあります。Mkinitcpio#MODULES に追加したモジュールを削除して initramfs を再生成することで問題が解決するかもしれません。特にグラフィックドライバのモジュールは問題を起こしがちです。復帰するまえにデバイスが初期化されると矛盾状態になってシステムがハイバネートから復帰できなくなります。サスペンドからの復帰の場合は関係ありません。サスペンドやハイバネートの問題をデバッグする際のベストプラクティスが こちらの記事 に記載されています。
Wake-on-LAN
Wake-on-LAN が有効になっている場合、コンピュータがハイバネート状態になっていてもネットワークインターフェイスカードによって電力が消費されます。
サスペンドからすぐに復帰する
LynxPoint や LynxPoint-LP チップセットが搭載された Intel Haswell の場合、サスペンドからすぐに復帰してしまうと報告されています。BIOS の ACPI 実装に問題があり起動時に xhci_hcd
モジュールによって ACPI イベントが解釈されてしまうのが原因です。解決策としてカーネルによってケースバイケースで問題のあるシステムがブラックリスト (XHCI_SPURIOUS_WAKEUP
) に追加されています [5]。
サスペンド中に USB デバイスを接続したときなどに ACPI の復帰トリガーが有効になって復帰してしまいます。ブラックリストに追加されるまで一時的な応急処置としては復帰トリガーを無効化する方法があります。以下の設定で USB による復帰を無効化することができます [6]。
現在の設定を確認:
$ cat /proc/acpi/wakeup
Device S-state Status Sysfs node ... EHC1 S3 *enabled pci:0000:00:1d.0 EHC2 S3 *enabled pci:0000:00:1a.0 XHC S3 *enabled pci:0000:00:14.0 ...
問題のデバイスは EHC1
, EHC1
, XHC
(USB 3.0) です。状態を変更するには root でデバイス名をファイルに echo してください:
# echo EHC1 > /proc/acpi/wakeup # echo EHC2 > /proc/acpi/wakeup # echo XHC > /proc/acpi/wakeup
上記のコマンドでサスペンドが再度機能するようになります。ただし、設定は一時的なものなので再起動するたびに設定し直す必要があります。自動化したい場合は systemd#ユニットファイルを見てください。詳しくは BBS スレッド を参照。
System does not power off when hibernating
When you hibernate your system, the system should power off (after saving the state on the disk). Sometimes, you might see the power LED is still glowing. If that happens, it might be instructive to set the HibernateMode
to shutdown
in sleep.conf.d(5):
/etc/systemd/sleep.conf.d/hibernatemode.conf
[Sleep] HibernateMode=shutdown
With the above configuration, if everything else is set up correctly, on invocation of a systemctl hibernate
the machine will shutdown saving state to disk as it does so.