電源管理/サスペンドとハイバネート

提供: ArchWiki
2024年5月29日 (水) 17:30時点におけるAshMyzk (トーク | 投稿記録)による版 (同期)
ナビゲーションに移動 検索に移動

関連記事

サスペンドの複数の方法を利用できます。とりわけ:

Suspend to idle
Intel は S0ix と呼んでおり、Microsoft は Modern Standby (以前は "Connected Standby") と呼んでいます。Linux カーネルでは S2Idle と呼ばれています。サポートされているシステムにおいて S3 スリープ状態の代わりに使用されるように設計されており、同等の節電機能を提供しますが、復帰に掛かる時間が大幅に短縮されます。
ヒント: WindowsmacOS はネットワーク活動のためにこの状態のデバイスの復帰をサポートしているので、これらの OS においてこの状態はバッテリーの消耗問題の影響を受けます。一方、Linux のソフトウェアエコシステムは現在この機能を使用しないため、影響を受けないはずです。
Suspend to RAM (サスペンド、スリープとも呼ばれます)
ACPI で S3 スリープ状態として定義されています。RAM を除くマシンのほとんど全てのパーツの電源を切ります。RAM への電源はマシンの状態を保存するために必要です。電力を多く節約できるので、ラップトップでは、バッテリーでコンピュータが稼働していてフタが閉じられた時 (もしくはユーザーが長い間操作しなかった時) は自動的にこのモードに移行するのが得策でしょう。
Suspend to disk (ハイバネートとも呼ばれます)
ACPI で S4 スリープ状態として定義されています。マシンの状態をスワップ領域に保存してマシンの電源を完全にオフにします。マシンに電源を入れた時、状態が復元されます。それまでは、電力消費量はゼロです。
Hybrid suspend (ハイブリットスリープとも呼ばれます)
サスペンドとハイバネートのハイブリッドです。Suspend to both と呼ばれることもあります。マシンの状態をスワップ領域に保存しますが、マシンの電源を切りません。代わりに、デフォルトのサスペンドを呼び出します。これによって、バッテリーを使いきっても、システムは即座に復帰できます。バッテリーが枯渇した時は、システムはディスクから復帰し、RAM からの復帰に比べて時間がかかりますが、システムの状態が失われることはありません。

カーネルは、基本的な機能を提供しており、問題のあるハードウェアドライバ/カーネルモジュール (例: ビデオカードの再初期化) に対処する機能を提供する高レベルなインターフェイスもいくつかあります。

目次

カーネルのインターフェイス (swsusp)

ノート: カーネルのインターフェイスを直接使用することは可能です (ユーザー空間で追加の処理が無いので高速です) が、高レベルインターフェイスを使用することが推奨されます。このインターフェイスは、追加の安全性チェックを行い、さらに、ハードウェアクロックの修正や無線ネットワークの回復などをするためのサスペンド前後のフック機構を提供しているので、より優れています。

カーネル内のソフトウェアサスペンドコード (swsusp) にサスペンド状態に入るよう直接伝えることは可能です。実際の方法と状態はハードウェアサポートのレベルによります。最近のカーネルでは、サスペンドにするために /sys/power/state に適切な文字列を書くことが主な方法になっています。

詳しくは カーネルドキュメント を参照してください。

高レベルインターフェイス (systemd)

ノート: 高レベルなインターフェイスの目的は、サスペンド/ハイバネートを行う際に利用できるバイナリ/スクリプトと、追加の準備/クリーンアップの作業を行うためのフックを実行する手段を提供することです。電源ボタンの押下、メニューのクリック、ノート PC の蓋イベントのときにスリープ状態に自動的に移行する方法については、電源管理#ACPI イベント を見てください。

systemd は、サスペンド、ハイバネート、ハイブリッドサスペンドを行うためのネイティブなコマンドを提供しています。これは、Arch Linux で使用されるデフォルトのインターフェイスです。

systemctl suspend は、特に設定せずとも動くはずです。systemctl hibernate に関しては、#ハイバネーション の手順に従わないと動作しないかもしれません。

また、サスペンドとハイバネートを組み合わせたようなモードが2つあります:

  • systemctl hybrid-sleep は、システムを RAM とディスクの両方にサスペンドします。なので、電源が完全に失われても、データ損失が発生しません。このモードは suspend to both とも呼ばれています。
  • systemctl suspend-then-hibernate は、最初は可能な限り長くシステムを RAM にサスペンドし、RTC アラームで復帰し、そしてハイバネートします。RTC アラームは systemd-sleep.conf(5) 内の HibernateDelaySec で設定します。デフォルトの値は、システムのバッテリーレベルが 5% に下がるまでの推定された時間に設定されます。システムにバッテリーが存在しない場合は、デフォルトで2時間に設定されます。推定時間は、systemd-sleep.conf(5) 内の SuspendEstimationSec によって指定された時間後のバッテリーレベルの変化から計算されます。SuspendEstimationSec の時間後、システムは短い間サスペンドから復帰し、計測を行います (システムが手動でサスペンドから復帰された場合も、計測が行われます)。

サスペンド/ハイバネートのフックの設定に関するその他の情報は、#スリープフック を見てください。また、systemctl(1)systemd-sleep(8)systemd.special(7) も参照してください。

サスペンドの方法を変更する

S0ix サスペンドが通常の S3 スリープと同じ節電機能を提供しないシステム、あるいは、電力を節約することが復帰を高速化することよりも優先される場合においては、デフォルトのサスペンド方法を変更することが可能です。

ヒント: S0ix は S3 スリープと同等かより高い節電性能を提供するはずです。意図通りに S0ix を機能させることができるかどうかは、次の Intel のブログ投稿を参照してください: How to achieve S0ix states in LinuxLinux S0ix TroubleshootingIdling Efficiently on Linux: A Case Study。Intel システムでは S0ixSelftestTool を使うことができます。

以下のコマンドは、ハードウェアによってサポートされていると広告されている全てのサスペンド方法を出力します (現在のサスペンド方法は角括弧に囲まれます[1]):

$ cat /sys/power/mem_sleep
[s2idle] shallow deep

ハードウェアが deep スリープ状態を広告していない場合、UEFI にそのような設定がないか確認してください。通常、PowerSleep state などのような項目にあります。S0ix のオプションは Windows 10Windows and LinuxS3/Modern standby support という名前です。S3 スリープのオプションは LegacyLinuxLinux S3S3 enabled という名前です。設定できない場合、s2idle を使い続けることもできます、ハイバネート を使うことを検討するか、DSDT テーブルにパッチを当ててみてください (あるいは、パッチ適用済みのバージョンを見つけてください)。

ノート: 最後の解決策は将来的に問題が発生する可能性があります。Windows を同梱しているシステムではデフォルトで "Modern standby" を使うよう推奨されているため、メーカーは ACPI S3 状態のバグの修正を停止しています。メーカーが自発的にそれを広告していない場合、おそらく、S3 状態は何らかの形で壊れています。

スリープの方法を変更したあと、スリープサイクルを何回かテストして、ハードウェアが S3 スリープで問題を起こさないかテストしてください:

# echo "deep" > /sys/power/mem_sleep

問題が無ければ、mem_sleep_default=deep カーネルパラメータ を使って変更を永続化できます。

いくつかの逆の状況では、問題のあるファームウェアが s2idle しかサポートしていないにも関わらず、deep をサポートしていると広告することがあります。この場合、sleep.conf.d(5) 内で SuspendState を使うことにより、s2idle を使うことができます:

/etc/systemd/sleep.conf.d/freeze.conf
[Sleep]
SuspendState=freeze

ハイバネーション

ハイバネートを行うには、次のことを行う必要があります: スワップパーティションかスワップファイルの作成する。初期ユーザー空間で復帰プロセスを初期化できるようにするために initramfs を設定する。Initramfs から利用できる方法でスワップ領域の場所を指定する (例えば、HibernateLocation EFI 変数を systemd で定義したり、resume= カーネルパラメータを設定したり)。これらの3つの手順は以下で詳細に説明されています。

ノート:

スワップパーティション(ファイル)のサイズについて

スワップパーティションが RAM より小さかったとしても、ハイバネートが成功する可能性は高いと思われます。image_size sysfs(5) 疑似ファイルに関する情報は カーネルドキュメントの "image_size" を見てください。

(スワップパーティションを小さくして) /sys/power/image_size の値を減らしてサスペンドのイメージを出来る限り小さくすることも、値を増やしてハイバネーションを高速化することも可能です。大きな容量の RAM を搭載しているシステムでは、より小さい値にするとハイバネートからの復帰が劇的に速くなることがあります。image_size の値を再起動後も保持するために systemd#systemd-tmpfiles - 一時ファイル を使うことができます:

/etc/tmpfiles.d/hibernation_image_size.conf
#    Path                   Mode UID  GID  Age Argument
w    /sys/power/image_size  -    -    -    -   0

サスペンドイメージは複数のスワップパーティション/スワップファイルにまたがって保存することができません。イメージのすべての部分が1つのスワップパーティション/スワップファイルに収まらなければなりません。[2]

initramfs の設定

  • Busybox ベースの initramfs を使用している場合 (Arch ではデフォルトです)、/etc/mkinitcpio.confresume フックを追加する必要があります。ラベルあるいは UUID どちらを使用している場合でもスワップパーティションは udev デバイスノードによって参照されるので、resume フックは udev フックのに追加する必要があります。デフォルトのフック設定に resume フックを追加すると以下のようになります:
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block filesystems resume fsck)
変更を適用するために initramfs の再生成を忘れずに行ってください。
ノート: スワップ領域にスタックされたストレージ (例えば、dm-cryptRAIDLVM) を使用している場合は、最後のマッピングされるデバイスが、初期ユーザー空間内及び復帰プロセスの初期化前に利用できるようにする必要があります。つまり、どうすればよいかというと、resume フックを encryptlvm2 などのフックより後に置く必要があります (そのような環境である場合)。
  • initramfs で systemd フックを使っている場合は、復帰機構が既に提供されているので、フックを追加する必要はありません。

ハイバネート先指定を initramfs に渡す

システムがハイバネートする際、メモリイメージがスワップ領域に保存されます (メモリイメージには、マウント済みファイルシステムの状態も含まれます)。そのため、ハイバネートから復帰できるようにするには、ハイバネート先がどこであるかという情報が、initramfs で (つまり、ルートファイルシステムがマウントされる前の時点で) 利用できるようにする必要があります。

systemd v255 及び mkinitcpio v38 からは、システムが UEFI 上で実行されている場合、systemd-sleep(8) はハイバネート先として適切なスワップ領域を自動的に選択し、使用されたスワップ領域の情報は HibernateLocation EFI 変数に格納されます。次回のブート時には、systemd-hibernate-resume(8) がこの EFI 変数からスワップ領域の場所を読み込み、システムが復帰します。よって、システムがレガシー BIOS を使用している場合や、あなたが自動的に選択されるスワップ領域とは別のスワップ領域を使用したい場合を除いて、以下の手順は必須ではありません。

ハイバネート先を手動で指定する

カーネルパラメータ resume=swap_device を使用することで可能です。swap_device永続的なブロックデバイスの命名に従います。例えば:

  • resume=/dev/sda1
  • resume=UUID=4209c845-f495-4c43-8a03-5363dd433153
  • resume=/dev/mapper/archVolumeGroup-archLogicVolume – スワップが LVM 論理ボリューム上にある場合 (UUID や Label も使えるはずです)

カーネルパラメータは再起動後に有効となります。すぐにハイバネートできるようにするには、lsblk を使ってボリュームのメジャーデバイスナンバーとマイナーデバイスナンバーを手に入れて、/sys/power/resumemajor:minor という形式で書き込んでください。

例えば、スワップデバイスが 8:3 の場合:

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

スワップファイルを使用する場合、これに加えて #スワップファイルのオフセットを手に入れる の手順も行ってください。

スワップファイルのオフセットを手に入れる

スワップファイルをハイバネート用に使用する場合は、(スワップファイルが存在している) ファイルシステムを含んでいるブロックデバイスを resume= で指定する必要があり、さらに、スワップファイルの物理オフセットも resume_offset= カーネルパラメータで指定する必要があります。[3]

Btrfs 以外のファイルシステムでは、resume_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
...

この例では、resume_offset= の値は最初の 38912 になります。

あるいは、オフセットの値を直接手に入れるには:

# filefrag -v swap_file | awk '$1=="0:" {print substr($4, 1, length($4)-2)}'

Btrfs の場合、filefrag ツールは使わないでください。filefrag から得られる "physical" オフセットの値は、ディスク上の実際の物理オフセットとは異なるからです。複数のデバイスをサポートするために、仮想的なディスクアドレス空間が存在するのです。[4] 代わりに、btrfs-inspect-internal(8) コマンドを使ってください。例えば:

# btrfs inspect-internal map-swapfile -r swap_file
198122980

この例では、カーネルパラメータは resume_offset=198122980 となります。

再起動せずにこの変更を即座に適用するには、resume offset を /sys/power/resume_offset に書き込んでください。例えば、オフセットが 38912 である場合は:

# echo 38912 > /sys/power/resume_offset
ヒント: 次のコマンドは、スワップファイルのバッキングデバイスを特定する際に使用できます: findmnt -no UUID -T swap_file
ノート: 暗号化コンテナ (LUKS)、 RAID、 LVM のようなスタックブロックデバイスでは、resume パラメータはスワップファイルのあるファイルシステムを含んでいる、アンロックまたはマップされたデバイスを指していなければなりません。

ハイバネート用のスワップファイルを zram で保持する

ヒント: 以下の方法は複数のスワップ領域を使用しますが、zswap を使えば似たようなことをすることができます。

RAM 圧縮 (zram) でのハイバーネートの問題は、複数のスワップ領域を同時に保持することで解決できます。Systemd は、ハイバネートをトリガーする前に zram ブロックデバイスを常に無視するので、特に設定せずに両方の領域 (スワップファイルと zram) を保持できるはずです。

スワップファイルの設定が済んだら、zram のページの手順に従ってください。このとき、zram に高いスワップ優先度 (例えば pri=100) を割り当ててください。

ノート:

thinly-provisioned LVM ボリュームへのハイバネーション

thinly-provisioned LVM されたボリュームへの休止状態は可能ですが、ボリュームが完全に割り当てられていることを確認する必要があります。そうしないと、再開に失敗します。FS#50703 を見てください。

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%のデータ使用量であると表示されます。

警告: 休止状態に使用される thinly-provisioned されたスワップボリュームで TRIM を使用しないでください。つまり、 /etc/fstabdiscard を使用しないでください。 swapon-d/--discard オプション。 そうしないと、使用済みスペースの割り当てが解除されます。

スリープフック

カスタムの systemd ユニット

systemd は、スリープ状態に応じて suspend.targethibernate.targethybrid-sleep.targetsuspend-then-hibernate.target のどれかを開始します。これらの target は全て、sleep.target も開始します。これらの target はどれも、サスペンド/ハイバネートの前や後にカスタムのユニットを実行するために使用することができます。ユーザーのアクション用と root ユーザー/システムのアクション用とで、別々のファイルを作成する必要があります。例えば:

/etc/systemd/system/user-suspend@.service
[Unit]
Description=User suspend actions
Before=sleep.target

[Service]
User=%I
Type=forking
Environment=DISPLAY=:0
ExecStartPre= -/usr/bin/pkill -u %u unison ; /usr/local/bin/music.sh stop
ExecStart=/usr/bin/sflock
ExecStartPost=/usr/bin/sleep 1

[Install]
WantedBy=sleep.target
/etc/systemd/system/user-resume@.service
[Unit]
Description=User resume actions
After=suspend.target

[Service]
User=%I
Type=simple
ExecStart=/usr/local/bin/ssh-connect.sh

[Install]
WantedBy=suspend.target

変更を適用するには、user-suspend@user.serviceuser-resume@user.service を有効化してください。

ノート: スクリーンが"ロックされる"前にスクリーンロックが返ってきてしまい、サスペンドから復帰するときに画面が点滅することがあります。ExecStartPost=/usr/bin/sleep 1 で小さな遅延を追加することでこれを防止できます。

root ユーザー/システムのアクション用:

/etc/systemd/system/root-suspend.service
[Unit]
Description=Local system suspend actions
Before=sleep.target

[Service]
Type=simple
ExecStart=-/usr/bin/pkill sshfs

[Install]
WantedBy=sleep.target
/etc/systemd/system/root-resume.service
[Unit]
Description=Local system resume actions
After=suspend.target

[Service]
Type=simple
ExecStart=/usr/bin/systemctl restart mnt-media.automount

[Install]
WantedBy=suspend.target

スリープ/復帰のユニットの統合

サスペンド/レジュームのサービスファイルを統合すれば、様々なフェイズ (スリープ/レジューム) やターゲット (サスペンド/ハイバネート/ハイブリッドスリープ) でやることをひとつのフックで行うことができます。

例と説明:

/etc/systemd/system/wicd-sleep.service
[Unit]
Description=Wicd sleep hook
Before=sleep.target
StopWhenUnneeded=yes

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=-/usr/share/wicd/daemon/suspend.py
ExecStop=-/usr/share/wicd/daemon/autoconnect.py

[Install]
WantedBy=sleep.target
  • RemainAfterExit=yes: 起動後、明示的に止められるまでサービスは常時 active とみなされます。
  • StopWhenUnneeded=yes: active 時、他のサービスから必要とされなくなった場合、サービスは停止されます。この例では、sleep.target が停止されるとこのサービスは停止されます。
  • sleep.target では StopWhenUnneeded=yes が設定されているため、このフックは別のタスクにおいても適切に開始/停止することが保証されます。

/usr/lib/systemd/system-sleep のフック

ノート: systemd-sleep(8) によれば、この方法は systemd ではハックなやり方だとされています。systemd-sleep は、これらのフックを1つずつではなく並列に実行します。順序実行がサポートされている、より明確に定義されたインターフェイスについては、#カスタムの systemd ユニット をみてください。

systemd-sleep は、/usr/lib/systemd/system-sleep/ 内の全ての実行可能ファイルを実行します。このとき、2つの引数が渡されます:

  1. pre または post: マシンがスリープしようとしているのか、復帰しようとしているのか。
  2. suspendhibernatehybrid-sleep のどれか: どのスリープ状態が実行される/されたのか。

カスタムスクリプトの出力は、systemd-suspend.servicesystemd-hibernate.servicesystemd-hybrid-sleep.service によって記録されます。systemdjournalctl でこのログを見ることができます:

# journalctl -b -u systemd-suspend.service

カスタムのスリープスクリプト例:

/usr/lib/systemd/system-sleep/example.sh
#!/bin/sh
case $1/$2 in
  pre/*)
    echo "Going to $2..."
    ;;
  post/*)
    echo "Waking up from $2..."
    ;;
esac

スクリプトを実行可能にするのを忘れないで下さい。

ヒントとテクニック

スリープを完全に無効化する

デバイスをサーバなどとして使用している場合、サスペンド/ハイバネートは必要ないかもしれませんし、かえって望ましくない可能性もあります。systemd-sleep.conf(5) を使えば任意のスリープ状態を無効化することができます:

/etc/systemd/sleep.conf.d/disable-sleep.conf
[Sleep]
AllowSuspend=no
AllowHibernation=no
AllowHybridSleep=no
AllowSuspendThenHibernate=no

Intel Rapid Start Technology (IRST)

Intel Rapid Start Technology とは、ハイバネートするためのハードウェア上の方法で、あらかじめ設定された時間の後やバッテリー状態に基づいてスリープからハイバネートに移行できるようにします。IRSTは、オペレーティングシステムのレベルではなくファームウェアによって行われるので、通常のハイバネートよりも速く信頼性が高いはずです。一般的に、IRST はファームウェアで有効化する必要があり、またファームウェアで、サスペンド/バッテリイベント後にハイバネートをトリガーするまでの時間を設定できます。しかし、一部のデバイスは IRST をファームウェアでサポートしていますが、Intel の Windows ドライバからでしか設定できません。そのような場合には、以下で説明している intel-rst カーネルモジュールで Linux でもイベントを設定できるはずです。

Intel Rapid Start Technology (IRST) が有効の場合、deep sleep からの再開には "S3から再開するよりも数秒長くなりますが、ハイバネートから再開するよりもはるかに高速です"。

Intel ベースのシステムの多くは、 IRST のファームウェアをサポートしていますが、(HDD ではなく) SSD 上に特別なパーティションを必要とします。 Windows の OEM 展開では、Arch Linux インストールプロセス中に (SSD 全体を消去して再パーティションするのではなく) 保持できる IRST パーティションがすでに存在している場合があります。システムの RAM と同じサイズの未フォーマットパーティションとして表示されます。

警告: Intel Rapid Start パーティションは暗号化されていません。「Intel は、あなたがソフトウェアベースのディスク暗号化を使用している場合、Intel Rapid Start Technology を無効化することを推奨します。」[5]

ドライブ全体を消去してパーティションを切り直すつもりなら (あるいはすでにそうしてしまっているなら) IRST パーティションも再作成しなければなりません。これを行うには、システムの RAM と同じサイズの空のパーティションを作成し、そのパーティションの種類が GPT パーティションの場合は GUID D3BFE2DE-3DAF-11DF-BA40-E3A556D89593 に、 MBR パーティションの場合は ID 0x84 に設定します。また、システムのファームウェア設定で IRST のサポートを有効にする必要がある場合もあります。

ヒント: (サスペンド後に)IRST が開始されるまでの時間は、システムのファームウェア設定で調整できます。

IRST ハイバネートにかかる時間 (つまり、"RAMの内容全体を特殊なパーティションに" コピーする時間) は、システムの RAM サイズと SSD 速度によって異なり、20~60秒かかります。システムによっては、プロセスの完了を(点滅を止めるなどして) LED インジケータで示す場合があります。

Linux カーネルで IRST ハイバネートイベントを設定するには、CONFIG_INTEL_RST オプションでカーネルに組み込むか、カーネルモジュールとして利用可能である必要があります。modprobe intel_rst を実行してモジュールをロードすれば、/sys/bus/acpi/drivers/intel_rapid_start/*/ にファイル wakeup_eventswakeup_time が生成されるはずです。これらを用いて、さらなる設定を行うことができます。このモジュールは簡潔にドキュメント化されています。詳細は drivers/platform/x86/intel/rst.c を見てください。

Intel Rapid Start Technology に関する情報は、general Q&Auser guides も見てください。

トラブルシューティング

ACPI_OS_NAME

DSDT table を動作するように設定することができます。DSDT の記事を参照してください。

サスペンド/ハイバネートが動作しない、あるいはたまに動作しなくなる

ハイバネートやサスペンドから復帰した時に画面が真っ暗になって、明確なエラーは表示されず、何もできなくなるという報告が多数存在します。これらの問題は、ノートパソコンとデスクトップの両方で確認されています。公式の解決方法ではありませんが、古いカーネル、特に LTS カーネルに切り替えることで問題が解決することがあります。

ハードウェアの watchdog タイマーを使用している場合に問題が起こることもあります (デフォルトで無効化されています、systemd-system.conf(5) § OPTIONSRuntimeWatchdogSec= を見てください)。バグのある watchdog タイマーにより、システムがハイバネートイメージの作成を終える前に、コンピュータがリセットされることがあります。

時々、initramfs 内からのデバイスの初期化によって黒画面が発生することがあります。Mkinitcpio#MODULES 内にあるモジュールを削除し、kms フックを削除し、initramfs を再ビルドすると、この問題を解決できる可能性があります (特に、KMS の早期開始が設定されたグラフィックスドライバの場合)。復帰前にそのようなデバイスを初期化すると、整合性がなくなり、システムのハイバネートからの復帰を妨げてしまう可能性があります。これは RAM からの復帰には影響しません。また、ブログ記事 best practices to debug suspend issues も確認してください。

ATI ビデオドライバから新しい AMDGPU ドライバに移行すると、ハイバネートと復帰のプロセスを成功させることができる可能性があります。

NVIDIA ユーザは、nvidiafb モジュールをブラックリスト化すると、問題が解決するかもしれません。[6]

Intel CPU を搭載していて、タッチパッドのために intel_lpss_pci をロードするノート PC では、復帰時にカーネルパニックを引き起こすことがあります(この時、caps lock が点滅する) [7]。このモジュールは、以下のように initramfs に追加する必要があります:

/etc/mkinitcpio.conf
MODULES=(... intel_lpss_pci ...)

そして、initramfs を再生成してください。

Wake-on-LAN

Wake-on-LAN が有効になっている場合、コンピュータがハイバネート状態になっていてもネットワークインターフェイスカードによって電力が消費されます。

サスペンドからすぐに復帰する

電源管理/復帰トリガー#サスペンドからすぐに復帰する を見てください。

AMD CPU 上で Linux カーネル 6.1 以上を使用している場合、これはカーネル内の S3 関連の制御ポリシーの問題が原因である可能性もあります。一時的な解決策は、関連する i2c デバイスの復帰をオフにすることです。関連する i2c デバイスは以下のコマンドで見つけられます:

$ ls /sys/bus/i2c/devices/*/power/wakeup

デバイス名の形式は i2c-ELAN0679:00i2c-MSFT0001:00 であるはずです。次に、以下のコマンドでサスペンドに移行できるかテストします:

# echo disabled > /sys/bus/i2c/devices/device_name/power/wakeup
# systemctl suspend

これでうまく行くならば、udev ルールを追加することで、この設定を永続化できます:

/etc/udev/rules.d/99-avoid-i2c-wakeup.rules
KERNEL=="device_name", SUBSYSTEM=="i2c", ATTR{power/wakeup}="disabled"

ハイバネートした時にシステムの電源が落ちない

システムをハイバネートすると、(現在の状態がディスクに保存されたあとに) システムの電源が切られるはずです。一部のファームウェアでは、S4 スリープ状態が正しく機能しないことがあります。例えば、電源が切られず、システムが再起動してしまうことがあります。そのような場合、sleep.conf.d(5)HibernateMode の値を shutdown に設定すると良いかもしれません:

/etc/systemd/sleep.conf.d/hibernatemode.conf
[Sleep]
HibernateMode=shutdown

これにより、その他の設定が適切であれば、systemctl hibernate を実行すると現在の状態がディスクに保存され、マシンの電源が切られます。

ハイバネート後に起動するとオペレーティングシステムが見つからない (または、間違った OS が起動する)

これは、ブートディスクが外部ディスクである場合に起こる可能性があります。BIOS/ファームウェアの制限が原因であるようです。ハイバネーションは外部 (あるいは別の) ディスク上の OS から行われたが、BIOS/ファームウェアは内部ディスクから起動を試みてしまっているのです。

#ハイバネートした時にシステムの電源が落ちない で説明したように HibernateMode=shutdown を設定することで、この問題を永久に解決できます。すでにシステムから締め出されてしまっている場合、システムを4回再起動 (毎回、エラーが表示されるまで待ってください) してみることで、一部の BIOS 上では通常のブート手順を強制することができます。

/home にスワップファイルを置く

スワップファイルが /home/ にある場合、systemd-logind はスワップファイルにアクセスできず、Call to Hibernate failed: No such file or directory という警告メッセージを出力して、systemctl hibernate の実行時に認証を求められます。このようなセットアップは、上流でサポートされていないとされているので、避けるべきです。2つの回避策については systemd issue 15354 を参照してください。

A520I および B550I マザーボードで PC がスリープから復帰しない

A520i および B550i チップセットを搭載した一部のマザーボードでは、システムが完全にスリープ状態に入らない、またはスリープ状態から復帰しないことがあります。症状は、システムがスリープ状態に入り、マザーボード上の内部 LED または電源 LED が点灯したまま、モニターの電源が切れるというものです。その後、システムはこの状態から復帰することができず、ハードパワーオフが必要となります。AMD で同様の問題が発生した場合、まずシステムが完全にアップデートされていることを確認し、AMD マイクロコード パッケージがインストールされているかどうかをチェックしてください。

GPP0 で始まる行のステータスが有効になっていることを確認します:

$ cat /proc/acpi/wakeup
Device	S-state	  Status   Sysfs node
GP12	  S4	*enabled   pci:0000:00:07.1
GP13	  S4	*enabled   pci:0000:00:08.1
XHC0	  S4	*enabled   pci:0000:0b:00.3
GP30	  S4	*disabled
GP31	  S4	*disabled
PS2K	  S3	*disabled
GPP0	  S4	*enabled   pci:0000:00:01.1
GPP8	  S4	*enabled   pci:0000:00:03.1
PTXH	  S4	*enabled   pci:0000:05:00.0
PT20	  S4	*disabled
PT24	  S4	*disabled
PT26	  S4	*disabled
PT27	  S4	*disabled
PT28	  S4	*enabled   pci:0000:06:08.0
PT29	  S4	*enabled   pci:0000:06:09.0

これが有効になっている場合は、次のコマンドを実行して無効化できます:

# echo GPP0 > /proc/acpi/wakeup

systemctl suspend を実行してテストし、システムをスリープ状態にします。次に、数秒後にシステムを起動してみてください。うまくいく場合は、回避策を永続的にすることができます。systemd ユニットファイル作成します。:

/etc/systemd/system/toggle-gpp0-to-fix-wakeup.service
[Unit]
Description="Disable GPP0 to fix suspend issue"

[Service]
ExecStart=/bin/sh -c "/bin/echo GPP0 > /proc/acpi/wakeup"

[Install]
WantedBy=multi-user.target

daemon-reload するか、新しく作成したユニットを起動/有効化してください。

あるいは、udev ルールを作成することもできます。先の例のように GPP0 の sysfs ノードが pci:0000:00:01.1 である場合、関連する情報は udevadm info -a -p /sys/bus/pci/devices/0000\:00\:01.1 を実行することで得られ、以下のような udev ルールを作成すれば良いことになります:

/etc/udev/rules.d/10-gpp0-acpi-fix.rules
KERNEL=="0000:00:01.1", SUBSYSTEM=="pci", DRIVERS=="pcieport", ATTR{vendor}=="0x1022", ATTR{device}=="0x1483", ATTR{power/wakeup}="disabled"

デフォルトで、udev デーモンはシステム内の (ルールの) 変更を監視する用に設定されています。必要であれば、手動でルールを再読み込みすることもできます。

ノートパソコンをサスペンドする Fn キーが動作しない

logind.conf をどう設定してもスリープボタンが動作しない場合 (ボタンを押しても syslog にメッセージすら表示されない)、おそらく logind がキーボードデバイスを監視していません。[8] 次のコマンドを実行してください:

# journalctl --grep="Watching system buttons"

すると以下のような表示がされます:

May 25 21:28:19 vmarch.lan systemd-logind[210]: Watching system buttons on /dev/input/event2 (Power Button)
May 25 21:28:19 vmarch.lan systemd-logind[210]: Watching system buttons on /dev/input/event3 (Sleep Button)
May 25 21:28:19 vmarch.lan systemd-logind[210]: Watching system buttons on /dev/input/event4 (Video Bus)

キーボードデバイスが出力に無いことに注意してください。以下のようにして、キーボードデバイスを一覧表示してみてください:

$ stat -c%N /dev/input/by-id/*-kbd
...
/dev/input/by-id/usb-SIGMACHIP_USB_Keyboard-event-kbd -> ../event6
...

次に、親キーボードデバイスの ATTRS{name} の値を調べます [9]。例えば、上記のコマンドの出力から、このキーボードデバイスのデバイス入力イベントは event6 であることがわかるので、このイベント名を使って ATTRS{name} 属性の値を検索することができます:

# udevadm info -a /dev/input/event6
...
KERNEL=="event6"
...
ATTRS{name}=="SIGMACHIP USB Keyboard"

カスタムの udev ルールを作成して、"power-switch" タグを追加してください:

/etc/udev/rules.d/70-power-switch-my.rules
ACTION=="remove", GOTO="power_switch_my_end"
SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="SIGMACHIP USB Keyboard", TAG+="power-switch"
LABEL="power_switch_my_end"

上記の udev ルールを再読み込みして systemd-logind.service再起動したら、logind の journal に Watching system buttons on /dev/input/event6 という出力が現れるはずです。

翻訳ステータス: このページは en:Power management/Suspend and hibernate の翻訳バージョンです。最後の翻訳日は 2024-05-29 です。もし英語版に 変更 があれば、翻訳の同期を手伝うことができます。