]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
hibernate-util: introduce hibernation_is_safe 29382/head
authorMike Yuan <me@yhndnzj.com>
Mon, 16 Oct 2023 05:10:01 +0000 (13:10 +0800)
committerMike Yuan <me@yhndnzj.com>
Fri, 20 Oct 2023 15:22:54 +0000 (23:22 +0800)
After 7470b80763ac0f598ca1ef73d44763967119c18d, we refuse
to hibernate if we fail to write HibernateLocation EFI
variable and resume= is not set. Let's teach sleep_supported
to follow the practice too.

src/login/logind-dbus.c
src/shared/hibernate-util.c
src/shared/hibernate-util.h
src/shared/sleep-config.c
src/shared/sleep-config.h

index e17d48bf262529d944fccf42a38300417786a9e2..f45a944f17ef88f643599d52841aec7c1bfa6a49 100644 (file)
@@ -1944,6 +1944,10 @@ static int method_do_shutdown_or_sleep(
                                                          "Sleep verb '%s' is not configured or configuration is not supported by kernel",
                                                          sleep_operation_to_string(a->sleep_operation));
 
+                        case SLEEP_RESUME_NOT_SUPPORTED:
+                                return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
+                                                        "Not running on EFI and resume= is not set. No available method to resume from hibernation");
+
                         case SLEEP_NOT_ENOUGH_SWAP_SPACE:
                                 return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
                                                         "Not enough suitable swap space for hibernation available on compatible block devices and file systems");
index ba5e5fe857acce4f6f42ce19d26cb57fd8e58f78..4a05320a40e6cd6491319dfff91ac77c072cc54e 100644 (file)
@@ -14,6 +14,7 @@
 #include "btrfs-util.h"
 #include "device-util.h"
 #include "devnum-util.h"
+#include "efivars.h"
 #include "env-util.h"
 #include "errno-util.h"
 #include "fd-util.h"
@@ -402,36 +403,52 @@ int find_suitable_hibernation_device_full(HibernationDevice *ret_device, uint64_
         return resume_config_devno > 0;
 }
 
-bool enough_swap_for_hibernation(void) {
+static int get_proc_meminfo_active(unsigned long long *ret) {
         _cleanup_free_ char *active_str = NULL;
         unsigned long long active;
-        uint64_t size, used;
         int r;
 
-        if (getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0)
-                return true;
+        r = get_proc_field("/proc/meminfo", "Active(anon)", WHITESPACE, &active_str);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to retrieve Active(anon) from /proc/meminfo: %m");
+
+        r = safe_atollu(active_str, &active);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to parse Active(anon) '%s' from /proc/meminfo: %m", active_str);
+
+        *ret = active;
+        return 0;
+}
+
+int hibernation_is_safe(void) {
+        unsigned long long active;
+        uint64_t size, used;
+        bool resume_set;
+        int r;
 
         r = find_suitable_hibernation_device_full(NULL, &size, &used);
         if (r < 0)
-                return false;
+                return r;
+        resume_set = r > 0;
 
-        r = get_proc_field("/proc/meminfo", "Active(anon)", WHITESPACE, &active_str);
-        if (r < 0) {
-                log_debug_errno(r, "Failed to retrieve Active(anon) from /proc/meminfo: %m");
-                return false;
-        }
+        if (!resume_set && !is_efi_boot())
+                return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+                                       "Not running on EFI and resume= is not set. Hibernation is not safe.");
 
-        r = safe_atollu(active_str, &active);
-        if (r < 0) {
-                log_debug_errno(r, "Failed to parse Active(anon) '%s' from /proc/meminfo: %m", active_str);
-                return false;
-        }
+        if (getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0)
+                return true;
+
+        r = get_proc_meminfo_active(&active);
+        if (r < 0)
+                return r;
 
         r = active <= (size - used) * HIBERNATION_SWAP_THRESHOLD;
         log_debug("Detected %s swap for hibernation: Active(anon)=%llu kB, size=%" PRIu64 " kB, used=%" PRIu64 " kB, threshold=%.2g%%",
                   r ? "enough" : "not enough", active, size, used, 100 * HIBERNATION_SWAP_THRESHOLD);
+        if (!r)
+                return -ENOSPC;
 
-        return r;
+        return resume_set;
 }
 
 int write_resume_config(dev_t devno, uint64_t offset, const char *device) {
index 8480026ce1801d068095146aee7603cfbc98967c..2ae10fb10013223ad2d503813427e3a0a665a63f 100644 (file)
@@ -18,7 +18,7 @@ static inline int find_suitable_hibernation_device(HibernationDevice *ret) {
         return find_suitable_hibernation_device_full(ASSERT_PTR(ret), NULL, NULL);
 }
 
-bool enough_swap_for_hibernation(void);
+int hibernation_is_safe(void);
 
 int write_resume_config(dev_t devno, uint64_t offset, const char *device);
 
index e5e96041ed05dd90549ed4284c3256402afccc70..deba2b1c588a2e86c86be5bca8ed4e2000b5b142 100644 (file)
@@ -278,9 +278,18 @@ static int sleep_supported_internal(
                 return false;
         }
 
-        if (IN_SET(operation, SLEEP_HIBERNATE, SLEEP_HYBRID_SLEEP) && !enough_swap_for_hibernation()) {
-                *ret_support = SLEEP_NOT_ENOUGH_SWAP_SPACE;
-                return false;
+        if (IN_SET(operation, SLEEP_HIBERNATE, SLEEP_HYBRID_SLEEP)) {
+                r = hibernation_is_safe();
+                if (r == -ENOTRECOVERABLE) {
+                        *ret_support = SLEEP_RESUME_NOT_SUPPORTED;
+                        return false;
+                }
+                if (r == -ENOSPC) {
+                        *ret_support = SLEEP_NOT_ENOUGH_SWAP_SPACE;
+                        return false;
+                }
+                if (r < 0)
+                        return r;
         }
 
         *ret_support = SLEEP_SUPPORTED;
index 756b0e13ae2b89332ea9d40c1f5f612531257b8f..bc10a5b39bbf6a629a6598f2f77f7e172e913631 100644 (file)
@@ -40,6 +40,7 @@ typedef enum SleepSupport {
         SLEEP_DISABLED,                    /* Disabled in SleepConfig.allow */
         SLEEP_NOT_CONFIGURED,              /* SleepConfig.states is not configured */
         SLEEP_STATE_OR_MODE_NOT_SUPPORTED, /* SleepConfig.states/modes are not supported by kernel */
+        SLEEP_RESUME_NOT_SUPPORTED,
         SLEEP_NOT_ENOUGH_SWAP_SPACE,
         SLEEP_ALARM_NOT_SUPPORTED,         /* CLOCK_BOOTTIME_ALARM is unsupported by kernel (only used by s2h) */
 } SleepSupport;