跳至內容
出自 Arch Linux 中文维基

多種方法可用於掛起,特別是:

Suspend to idle(掛起到空閒狀態)
英特爾稱之為 S0ix,微軟稱之為現代待機(以前是「保持網絡連接的待機」),內核稱之為 S2Idle。設計用於替代 S3 睡眠狀態的支持系統,提供相同的節能,但大大減少了喚醒時間。
提示:雖然這種狀態會導致 WindowsmacOS 上的電池消耗問題,因為它們支持在這種狀態下喚醒設備進行網絡活動,但 Linux 軟體生態系統目前沒有使用這種特性,應該不會受到影響。
Suspend to RAM(掛起到內存,通稱掛起)
ACPI 定義的 S3 睡眠狀態。通過將機器中大多數和 RAM 不相關的部件斷電來工作,RAM 是恢復機器狀態所必需的。由於可以節省大量電力,建議筆記本電腦在使用電池運行且蓋子關閉時(或用戶在一段時間內處於非活動狀態)自動進入此模式。
Suspend to disk(掛起到硬碟,通稱休眠)
ACPI 定義的 S4 睡眠狀態。將機器狀態保存到交換空間並關閉機器。再次開機後,恢復狀態。直到開機前,機器都不會有任何待機功耗
Hybrid suspend(混合掛起)
掛起和休眠的混合,有時稱為掛起到兩者。將機器狀態保存到交換空間,但並不關閉電腦,而是調用默認的掛起機制,從而使未掉電的電腦能立刻恢復。如果電腦掉電(斷電且電池耗盡),系統也可以從硬碟的交換空間中恢復,儘管比從內存中恢復慢一些。

以上三者均由內核提供基礎功能,再由高級接口進行了一定調整,以適配一些較為複雜的硬體與內核模塊(如顯卡喚醒後的重新初始化)


內核接口 (swsusp)

注意:儘管可以直接使用內核接口,這更快,因為不需要額外的用戶空間處理,但建議使用高級接口。它通過執行額外的安全檢查以及提供預掛起和後掛起鉤子機制來更好地設置硬體時鐘、恢復無線等,從而做得更好。

可以通過直接告知內核中的軟體掛起代碼(swsusp)進入掛起狀態,具體的方法和狀態取決於硬體支持的程度。在現代內核中,向 /sys/power/state 寫入特定字符串是觸發此掛起的主要機制。

更多信息詳見內核文檔

高級接口 (systemd)

注意:高級接口旨在提供可執行的二進制文件/腳本,用於執行掛起/休眠操作,並提供將額外的準備/清理工作掛鉤到所述進程的方法。有關電源按鈕、菜單點擊或筆記本蓋事件自動進入睡眠狀態,請參閱 Power management#ACPI events

systemd 提供了用於掛起、休眠和混合掛起的原生命令。這是 Arch Linux 中使用的默認接口。

systemctl suspend 開箱即用。要使 systemctl hibernate 在你的系統上運行,你可能需要遵循 #休眠中的說明。

還有兩種結合掛起和休眠的模式:

  • systemctl hybrid-sleep 將系統同時掛起到 RAM 和磁碟,因此完全斷電不會導致數據丟失。 此模式也稱為「同時掛起」。
  • systemctl suspend-then-hibernate 最初會儘可能將系統掛起到 RAM 中,然後使用 RTC 警報將其喚醒並休眠。RTC 警報由 systemd-sleep.conf(5) 中的 HibernateDelaySec 設置。默認值通過估計電池放電率來設置,以使系統保持 5% 的電池電量,或者在沒有電池的情況下保持兩小時。 估計值是根據 systemd-sleep.conf(5)SuspendEstimationSec 指定的時間後電池電量變化獲得的,該系統將短暫喚醒進行測量(如果系統從掛起中手動喚醒,也會進行測量)。
提示:systemd v256 支持使用新的 systemctl sleep 命令自動選擇最合適的睡眠操作。默認情況下,使用 suspend-then-hibernate,如果不支持則回退到 suspendhibernate。更多信息請參見 systemctl(1)

關於配置睡眠或休眠鉤子,詳見電源管理#睡眠鉤子。又見 systemctl(1)systemd-sleep(8)systemd.special(7)

更改掛起方法

在 S0ix 掛起不能提供與常規 S3 睡眠相同的節能的系統上,或者當節能優於快速的恢復時間時,可以更改默認掛起方法。

提示:S0ix 被認為可以提供與 S3 睡眠相同或更好的節能,請參閱以下英特爾博客文章 如何在 Linux 中實現 S0ix 狀態Linux S0ix 故障排除在 Linux 上高效空閒:一個案例研究,以檢查你是否可以使其按預期工作。英特爾用戶可以使用 S0ixSelftestTool。AMD 用戶可以使用 amd-debug-tools

運行以下命令以查看硬體公開支持的所有掛起方法(當前方法包裹在方括號中顯示[1]):

$ cat /sys/power/mem_sleep
[s2idle] shallow deep
mem_sleep 中支持的睡眠狀態
mem_sleep 字符串 睡眠狀態
s2idle suspend-to-idle
shallow standby
deep suspend-to-RAM

如果你的硬體沒有公布 deep 睡眠狀態,請首先檢查 UEFI 是否公布了它的某些設置,通常是在「電源(Power)」或「睡眠狀態(Sleep state)」或類似的用詞下,並使用名為 Windows 10, Windows and LinuxS3/Modern standby support 關於 S0ix 的選項,以及 Legacy, Linux, Linux S3S3 enabled 關於 S3 睡眠的選項。否則,你可以繼續使用 s2idle,考慮使用休眠或嘗試給 DSDT 表打補丁(或在線查找補丁版本)。

注意:最後一個解決方案很可能會引起問題。自從 Windows 系統默認使用 「現代待機 」後,製造商已經停止修復 ACPI S3 狀態的錯誤:如果它們主動地不公布它,它可能會在某種程度上出問題。

通過在更改睡眠方法後測試幾個睡眠周期,驗證你的硬體沒有 S3 睡眠問題:

# echo deep > /sys/power/mem_sleep

如果沒有發現任何問題,可以通過 systemd-sleep.conf(5) 中的 MemorySleepMode 選項使更改永久化。

/etc/systemd/sleep.conf.d/mem-deep.conf
[Sleep]
MemorySleepMode=deep

或者通過mem_sleep_default=deep 內核參數

在一些相反的情況下,有缺陷的固件公布支持 deep 睡眠,但只支持 s2idle。在這種情況下,通過選項中的 SuspendState 可以以另一種方法使用 s2idle

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

休眠

為了使用休眠功能,你必須創建一個 swap 分區或文件、#配置 initramfs 以便在早期用戶空間啟動恢復過程,並指定交換空間的位置以便 initramfs 可以訪問,例如:由 systemd 定義的 HibernateLocation EFI 變量或 resume= 內核參數。下面詳細描述了這三個步驟。

注意:

swap分區/文件的大小

即使交換分區比內存小,成功休眠的可能性仍然不小。參見內核文檔中的「image_size」部分以獲取關於 image_size sysfs(5) 偽文件的更多信息。

你可以減小 /sys/power/image_size 的設定值以使休眠鏡像儘可能小(對於小交換分區),或者增大它以加快休眠過程(也許)。對於 RAM 很大的系統,較小的值可能會顯著提高系統從休眠中恢復的速度。Systemd#systemd-tmpfiles_-_臨時文件可以用於固定你的修改。

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

休眠鏡像不能跨多個交換分區和/或交換文件。它必須完全適配一個交換分區或一個交換文件[2]

配置 initramfs

  • 當使用一個 busybox-based 的 initramfs 時(這是默認值),/etc/mkinitcpio.conf 中需要 resume 鉤子。無論是通過卷標還是通過 UUID,交換分區都是通過 udev 設備節點來引用的,因此 resume 鉤子必須在 udev 鉤子之後。這是一個使用默認鉤子配置的示例:
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block filesystems resume fsck)
編輯後記得重新生成 initramfs
注意:如果使用堆疊存儲作為交換空間,例如 dm-cryptRAIDLVM,則最終映射的設備必須在早期用戶空間中可用,並且在恢復過程啟動之前。也就是說,在這樣的設置中,resume 鉤子必須放在諸如 encryptlvm2 等鉤子之後。
  • 當使用帶有 systemd 鉤子的 initramfs 時,已經提供了恢復機制,不需要額外添加鉤子。

傳遞休眠位置到 initramfs

當系統休眠時,內存映像被轉儲到交換空間,其中也包括掛載文件系統的狀態。因此,休眠位置必須提供給 initramfs,即在掛載根文件系統之前,以便從休眠狀態恢復。

systemd v255 和 mkinitcpio v38 開始,當系統運行在 UEFI 上時,systemd-sleep(8) 將自動選擇合適的交換空間進行休眠,並且所用交換空間的信息存儲在 HibernateLocation EFI 變量中。在下次啟動時,systemd-hibernate-resume(8) 從 EFI 變量讀取位置,系統恢復。這意味著除非系統使用遺留 BIOS 或你想選擇與自動選擇的不同的交換空間,否則以下步驟不是必需的。

手動指定休眠位置

可以傳遞內核參數 resume=swap_device。其中 swap_device 遵循 persistent block device naming。例如:

  • resume=UUID=4209c845-f495-4c43-8a03-5363dd433153
  • resume="PARTLABEL=swap分區卷標"
  • resume=/dev/archVolumeGroup/archLogicalVolume——如果swap在LVM邏輯卷上(UUID 和 標籤應該同樣可以工作)

內核參數只有在重新啟動後才會生效。要想不重啟而馬上休眠,請從lsblk獲取卷的主要和次要設備號,並 echo major:minor/sys/power/resume

例如,如果交換設備是8:3

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

如果使用交換文件,請繼續查看#獲取交換文件偏移量

獲取交換文件偏移量

使用交換文件進行休眠時,文件系統所在的塊設備應該在 resume= 中指定,並且還需要通過 resume_offset= 內核參數指定交換文件的物理偏移量。 [3]

在除 Btrfs 之外的文件系統上,可以通過運行 filefrag -v 交換文件 來獲取 resume_offset= 的值。輸出為表格格式,所需的值位於第一行 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 獲取到的「物理」偏移量並不是真正在硬碟上的偏移量;這是一個虛擬的硬碟地址空間,用於支持多設備[4]。請使用 btrfs-inspect-internal(8) 命令作為代替,例如:

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

在本例中,設置偏移量的內核參數是 resume_offset=198122980

為使該更改立刻生效(無需重啟),使用 echo 將偏移量改動至 /sys/power/resume_offset。例如,如果偏移量是38912

# echo 38912 > /sys/power/resume_offset
提示:這個命令也許可以用於查找交換文件所在設備:findmnt -no UUID -T swap_file
注意:對於一個堆疊塊設備,比如一個加密容器(LUKS),RAID 或者 LVM,resume 參數必須指向交換文件所在的已解鎖或映射的設備。

更改休眠鏡像的壓縮算法

從 Linux 6.9 開始[5],可以更改休眠鏡像的壓縮算法。默認的壓縮算法基於編譯時選項 CONFIG_HIBERNATION_DEF_COMP 選擇,但可以在啟動時和運行時覆蓋。

不同的壓縮算法具有不同的特性,休眠可能會受益於使用其中任何一種算法,尤其是當次要算法(LZ4)在默認算法(LZO)上提供更好的解壓縮速度時,這反過來會減少休眠鏡像的恢復時間。

你可以通過兩種方式覆蓋默認算法:

1) 傳遞 hibernate.compressor 作為 內核參數

hibernate.compressor=lzo
hibernate.compressor=lz4

2) 在運行時指定算法:

# echo lzo > /sys/module/hibernate/parameters/compressor
# echo lz4 > /sys/module/hibernate/parameters/compressor

目前 lzolz4 是支持的算法,LZO 是默認算法。

使用 zram 維護休眠的交換文件

提示:與以下涉及多個交換空間的設置不同,可以使用 zswap 來建立類似的行為。

通過同時維護兩個或更多的交換空間,可以解決使用 zram 僅內存交換時的休眠問題。systemd 在觸發休眠前會始終忽略 zram 塊設備 [6],因此保持兩個交換空間啟用應該可以在無需進一步干預的情況下正常工作。

配置交換文件後,請按照 zram 頁面的說明進行操作。確保 zram 具有更高的交換優先級(例如 pri=100)。

注意:

休眠到精簡配置的LVM卷中

在精簡配置的LVM卷中休眠是可能的,但必須確保該卷已完全分配。否則系統將無法從中恢復,參見 FS#50703

可以通過簡單地用零填充來完全分配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%的Data%

警告:不要在用於休眠的精簡配置的swap分區上使用TRIM,即:不要在/etc/fstab使用discard,也不要在swapon時加入-d--discard參數。否則已被使用的空間會被重新去分配

禁用 zswap 寫回以僅將交換空間用於休眠

在 Linux 6.8 中,zswap 增加了 一個按 cgroup 禁用寫回的選項。通過在所有可能的單元類型中使用 systemd 單元設置 MemoryZSwapWriteback(參見 systemd.resource-control(5) § Memory Accounting and Control),可以有效地完全禁用 zswap 寫回。這使得 zswap 可以像 zram 一樣使用,同時還支持休眠。

為了避免手動創建十二個頂級按類型的 drop-in 文件(用於系統和用戶的 scopeserviceslicesocketmountswap 單元類型),請 安裝 zswap-disable-writebackAUR啟用 zswap 並重新啟動以使設置生效。

嘗試執行內存密集型任務並確認 zswap 沒有將任何內容寫入磁碟:

# cat /sys/kernel/debug/zswap/written_back_pages
0

Sleep hooks

Custom systemd units

systemd 會分別為每個睡眠狀態啟動 suspend.targethibernate.targethybrid-sleep.targetsuspend-then-hibernate.target。所有上述目標都會拉取 sleep.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 hibernate.target

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

[Install]
WantedBy=suspend.target hibernate.target

啟用 user-suspend@user.service 和/或 user-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 hibernate.target

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

[Install]
WantedBy=suspend.target hibernate.target

Combined sleep/resume unit

使用組合單元文件,單個鉤子可以為不同的階段(睡眠/恢復)和不同的目標完成所有工作。

示例和解釋:

/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:啟動後,服務被視為活動狀態,直到顯式停止。
  • StopWhenUnneeded=yes:當活動時,如果沒有其他活動服務需要它,服務將被停止。在這個特定示例中,它將在 sleep.target 停止後被停止。
  • 因為 sleep.targetStopWhenUnneeded=yes,所以鉤子保證會為不同的任務正確啟動/停止。

Hooks in /usr/lib/systemd/system-sleep

注意:根據 systemd-sleep(8),此方法被視為一種 hack。systemd-sleep 會並行運行這些鉤子,而不是一個接一個地運行。有關支持排序的更明確接口,請參見#Custom systemd units

systemd-sleep 會運行 /usr/lib/systemd/system-sleep/ 中的所有可執行文件,並向每個文件傳遞兩個參數:

  1. 要麼是 pre,要麼是 post,取決於機器是進入睡眠還是喚醒。
  2. suspendhibernatehybrid-sleepsuspend-then-hibernate,取決於正在調用的是哪個。

任何自定義腳本的輸出都將由 systemd-suspend.servicesystemd-hibernate.servicesystemd-hybrid-sleep.service 記錄。你可以在 systemd's journalctl 中查看其輸出:

# 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_ACTION 的環境變量將被設置,並包含正在處理的睡眠操作。這對於 suspend-then-hibernate 特別有用,其中變量的值將是 suspendhibernatesuspend-after-failed-hibernate(在休眠失敗的情況下)。

提示與技巧

在受信任的位置自動解鎖

在恢復時,如果系統連接到某些設備或受信任的 Wi-Fi 網絡,你可以自動解鎖系統。

/etc/local-scripts/resume-unlock.sh
#!/usr/bin/bash
# 如果在受信任的位置,則解鎖會話

function trusted() {
    # 檢查是否連接到受信任的 Wi-Fi 網絡
    [[ $(iwgetid -r) == your_home_ssid ]] \
        && return 0

    # 檢查是否連接了受信任的 USB 設備。
    #lsusb -d xxxx:xxxx && return 0

    return 1 # 不受信任
}

for (( i=0; i < 10; i++ )); do
    if trusted; then
        loginctl unlock-sessions
        exit
    fi
    sleep 0.5
done

配置你的桌面環境,使其在恢復時鎖定,然後創建一個睡眠鉤子,在恢復後運行上述腳本。你還需要安裝 wireless_tools 以讀取連接的 Wi-Fi SSID。如果你還想測試連接的 USB 設備,請取消腳本中的 lsusb -d ... 行的注釋,並填寫你受信任設備的 ID。你可以通過運行 lsusb 獲取設備的 ID。

完全禁用睡眠

當使用設備作為伺服器時,可能不需要或甚至不希望掛起/休眠。可以通過 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)

英特爾快速啟動技術是一種基於固件的休眠方法,允許在預定義的時間間隔或根據電池狀態從睡眠中休眠。這應該比常規休眠更快更可靠,因為它是由固件而不是在作業系統級別完成的。通常,它必須在固件中啟用,固件還支持設置暫停/電池事件觸發休眠後的持續時間。然而,儘管固件中支持 IRST,但某些設備僅允許通過英特爾的 Windows 驅動程序進行配置。在這種情況下,下面描述的 intel-rst 內核模塊應該能夠在 Linux 下配置事件。

啟用英特爾快速啟動技術(IRST)後,從深度睡眠中恢復需要「比從 S3 恢復長几秒,但比從休眠中恢復快得多」。

許多基於英特爾的系統都支持 IRST 固件,但需要在 SSD(而不是 HDD)上使用特殊分區。Windows 的 OEM 部署可能已經有一個預先存在的 IRST 分區,可以在 Arch Linux 安裝過程中保留(而不是擦除和重新分區整個 SSD)。它應該顯示為與系統 RAM 大小相等的未格式化分區。

警告:英特爾快速啟動分區未加密;「如果你使用基於軟體的磁碟加密,英特爾建議禁用英特爾快速啟動技術」。[7]

但是,如果你打算擦除並重新分區整個驅動器(或者已經這樣做了),那麼如果你也計劃使用該技術,則必須重新創建IRST分區。這可以通過創建一個與系統 RAM 大小相等的空分區,並將其分區類型設置為 GUID D3BFE2DE-3DAF-11DF-BA40-E3A556D89593(對於 GPT 分區)或 ID 0x84(對於 MBR 分區)來實現。你可能還需要在系統的固件設置中啟用對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 以獲取更多詳細信息。

另請參閱英特爾快速啟動技術的一般問答用戶手冊

跟蹤筆記本電腦電池在睡眠狀態下的能量變化

要測量掛起狀態下的功耗,請使用 Batenergy 腳本將電池變化記錄到系統日誌中。這允許比較 S3 / S0x 狀態下的功耗,或在 BIOS 和內核更新後檢查回歸和修復。該腳本需要安裝 bc 進行計算。

故障排除

ACPI_OS_NAME

你也許需要調整你的 DSDT table 來讓它工作。參閱 DSDT 詞條。

睡眠/休眠無法進行,或無法穩定進行

本文或本章節的事實準確性存在爭議。

原因: 本節混合了幾個無關的原因。(在 Talk:電源管理/掛起與休眠 中討論)


有相當多的錯誤報告指出,他們的屏幕在給出可讀的錯誤信息前就關閉了,有時屏幕關閉了,卻再也無法喚醒。這些故障在筆記本電腦和台式機上都曾發生。這不是個官方解決方案,但切換到舊的內核,尤其是LTS內核,或許可以修復這個問題。

使用硬體看門狗定時器(默認禁用,參見RuntimeWatchdogSec= in systemd-system.conf(5) § OPTIONS)時可能會出現一個問題。一個有問題的看門狗定時器可能會在系統完成創建休眠映像之前重置計算機。

有時屏幕會變黑,這是由於從initramfs內部初始化設備引起的。移除Mkinitcpio#MODULES中可能包含的任何模塊,移除kms鉤子並重新生成initramfs可能會解決這個問題,特別是對於早期KMS的圖形驅動程序。在恢復之前初始化這些設備可能會導致系統無法從休眠中恢復的不一致情況。這不影響從RAM中恢復。此外,請查看博客文章調試掛起問題的最佳實踐

ATI視頻驅動程序切換到較新的AMDGPU驅動程序也可能有助於使休眠和喚醒過程成功。

對於NVIDIA用戶,禁用模塊nvidiafb可能會有所幫助。[8]

帶有Intel CPU的筆記本電腦如果加載了intel_lpss_pci模塊用於觸摸板,可能會在恢復時遇到內核恐慌(大寫鎖定鍵閃爍)[9]。需要將該模塊添加到initramfs中:

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

然後重新生成initramfs


USB 設備錯誤

系統可能因為USB設備而無法掛起。你可能會看到以下錯誤:

PM: Some devices failed to suspend, or early wake event detected
...
xhci_hcd 0000:02:00.0: PM: failed to suspend async: error -16

lspci可能會給你更多關於故障設備的信息:

$ lspci -s 02:00.0
02:00.0 USB controller: Advanced Micro Devices, Inc. [AMD] 500 Series Chipset USB 3.1 XHCI Controller

嘗試斷開該埠上的設備。

網絡喚醒(WoL, Wake-on-LAN)

如果網絡喚醒被啟用,網卡可能會消耗電力,即使電腦處於休眠狀態。

掛起後被立即喚醒

參見電源管理/喚醒觸發器#掛起後被立即喚醒

系統在休眠後沒有斷電

當你休眠系統時,系統應該會斷電(在將狀態保存到磁碟後)。在某些固件上,S4 睡眠狀態可能無法可靠工作。例如,系統可能會重啟或保持開啟但無響應,而不是斷電。如果發生這種情況,可以在 sleep.conf.d(5) 中將 HibernateMode 設置為 shutdown

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

使用上述配置,如果其他設置都正確,在調用 systemctl hibernate 時,機器將會關閉,並在關閉過程中將狀態保存到磁碟。

休眠後啟動時未找到作業系統(或啟動錯誤的作業系統)

當引導磁碟是外部磁碟時,可能會發生這種情況,這似乎是由 BIOS/固件限制引起的。BIOS/固件嘗試從內部磁碟啟動,而休眠是從外部(或其他)磁碟上的作業系統完成的。

類似於#系統在休眠後沒有斷電,設置 HibernateMode=shutdown 以永久解決問題。如果你已經將自己鎖定在外,你可以嘗試重新啟動系統4次(每次等待錯誤出現),這在某些BIOS上強制執行正常的引導過程。

Swap file in /home

如果交換文件位於 /home/ 目錄下,systemd-logind 將無法訪問它,從而導致 Call to Hibernate failed: No such file or directory 警告信息,並且在執行 systemctl hibernate 時需要身份驗證。應避免這種設置,因為它被認為是 上游不支持的。有關兩種解決方法,請參閱 systemd issue 15354

PC 無法從 A520I 和 B550I 主板的睡眠中喚醒

在某些使用 A520i 和 B550i 晶片組的主板上,系統無法完全進入睡眠狀態或從睡眠狀態中恢復。症狀包括系統進入睡眠狀態,顯示器關閉,但主板上的內部 LED 或電源 LED 仍然亮著。隨後,系統無法從該狀態恢復,需要強制關機。如果你在使用 AMD 時遇到類似問題,請首先確保你的系統已完全更新,並檢查是否安裝了 AMD microcode 軟體包。

驗證以 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="禁用 GPP0 以修復睡眠問題"

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

[Install]
WantedBy=multi-user.target

執行 daemon-reloadstart/enable 新創建的單元。

或者,你可以創建一個 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 守護程序已經在監視系統中的更改。如果需要,你可以 手動重新加載規則

Suspend from corresponding laptop Fn key not working

如果無論 `logind.conf` 中的設置如何,睡眠按鈕都不起作用(按下它甚至不會在 `syslog` 中產生消息),那麼 `logind` 可能沒有監視鍵盤設備。[10] 請執行以下操作:

# 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} [11]。例如,在上面的列表中,此鍵盤設備的設備輸入事件為 event6,可以用於搜索其相應的屬性名稱:

# 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` 的日誌中看到 Watching system buttons on /dev/input/event6

System freezes for 60 seconds and then wakes back up or hangs after waking up

自 systemd v256 起,systemd 在休眠前會凍結 user.slice。由於內核錯誤,特別是當使用 KVM 時,此過程可能會失敗。[12][13]

日誌中的消息會在休眠前包含 Failed to freeze unit 'user.slice'。當發生此類問題時,嘗試登錄(啟動另一個會話)將失敗,並顯示:

pam_systemd(process:session): Failed to create session: Job 9876 for unit 'session-6.scope' failed with 'frozen'

要暫時恢復舊行為,請edit systemd-suspend.servicesystemd-hibernate.servicesystemd-hybrid-sleep.servicesystemd-suspend-then-hibernate.service,並添加以下 drop-in:

[Service]
Environment=SYSTEMD_SLEEP_FREEZE_USER_SESSIONS=false