mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
hibernate-util: introduce hibernation_is_safe
After 7470b80763, 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.
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
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 r;
|
||||
resume_set = r > 0;
|
||||
|
||||
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.");
|
||||
|
||||
if (getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0)
|
||||
return true;
|
||||
|
||||
r = find_suitable_hibernation_device_full(NULL, &size, &used);
|
||||
r = get_proc_meminfo_active(&active);
|
||||
if (r < 0)
|
||||
return false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user