diff options
Diffstat (limited to 'src/shared/sleep-config.c')
-rw-r--r-- | src/shared/sleep-config.c | 78 |
1 files changed, 55 insertions, 23 deletions
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index 7282111..3d4d331 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -54,6 +54,8 @@ SleepConfig* sleep_config_free(SleepConfig *sc) { strv_free(sc->modes[i]); } + strv_free(sc->mem_modes); + return mfree(sc); } @@ -69,8 +71,8 @@ static int config_parse_sleep_mode( void *data, void *userdata) { - _cleanup_strv_free_ char **modes = NULL; char ***sv = ASSERT_PTR(data); + _cleanup_strv_free_ char **modes = NULL; int r; assert(filename); @@ -87,7 +89,7 @@ static int config_parse_sleep_mode( return log_oom(); } - return free_and_replace(*sv, modes); + return strv_free_and_replace(*sv, modes); } static void sleep_config_validate_state_and_mode(SleepConfig *sc) { @@ -140,14 +142,19 @@ int parse_sleep_config(SleepConfig **ret) { { "Sleep", "HybridSleepState", config_parse_warn_compat, DISABLED_LEGACY, NULL }, { "Sleep", "HybridSleepMode", config_parse_warn_compat, DISABLED_LEGACY, NULL }, + { "Sleep", "MemorySleepMode", config_parse_sleep_mode, 0, &sc->mem_modes }, + { "Sleep", "HibernateDelaySec", config_parse_sec, 0, &sc->hibernate_delay_usec }, { "Sleep", "SuspendEstimationSec", config_parse_sec, 0, &sc->suspend_estimation_usec }, {} }; - (void) config_parse_config_file("sleep.conf", "Sleep\0", - config_item_table_lookup, items, - CONFIG_PARSE_WARN, NULL); + (void) config_parse_standard_file_with_dropins( + "systemd/sleep.conf", + "Sleep\0", + config_item_table_lookup, items, + CONFIG_PARSE_WARN, + /* userdata= */ NULL); /* use default values unless set */ sc->allow[SLEEP_SUSPEND] = allow_suspend != 0; @@ -180,7 +187,7 @@ int parse_sleep_config(SleepConfig **ret) { return 0; } -int sleep_state_supported(char **states) { +int sleep_state_supported(char * const *states) { _cleanup_free_ char *supported_sysfs = NULL; const char *found; int r; @@ -210,22 +217,24 @@ int sleep_state_supported(char **states) { return false; } -int sleep_mode_supported(char **modes) { +int sleep_mode_supported(const char *path, char * const *modes) { _cleanup_free_ char *supported_sysfs = NULL; int r; + assert(path); + /* Unlike state, kernel has its own default choice if not configured */ if (strv_isempty(modes)) { - log_debug("No sleep mode configured, using kernel default."); + log_debug("No sleep mode configured, using kernel default for %s.", path); return true; } - if (access("/sys/power/disk", W_OK) < 0) - return log_debug_errno(errno, "/sys/power/disk is not writable: %m"); + if (access(path, W_OK) < 0) + return log_debug_errno(errno, "%s is not writable: %m", path); - r = read_one_line_file("/sys/power/disk", &supported_sysfs); + r = read_one_line_file(path, &supported_sysfs); if (r < 0) - return log_debug_errno(r, "Failed to read /sys/power/disk: %m"); + return log_debug_errno(r, "Failed to read %s: %m", path); for (const char *p = supported_sysfs;;) { _cleanup_free_ char *word = NULL; @@ -234,7 +243,7 @@ int sleep_mode_supported(char **modes) { r = extract_first_word(&p, &word, NULL, 0); if (r < 0) - return log_debug_errno(r, "Failed to parse /sys/power/disk: %m"); + return log_debug_errno(r, "Failed to parse %s: %m", path); if (r == 0) break; @@ -247,14 +256,15 @@ int sleep_mode_supported(char **modes) { } if (strv_contains(modes, mode)) { - log_debug("Disk sleep mode '%s' is supported by kernel.", mode); + log_debug("Sleep mode '%s' is supported by kernel (%s).", mode, path); return true; } } if (DEBUG_LOGGING) { _cleanup_free_ char *joined = strv_join(modes, " "); - log_debug("None of the configured hibernation power modes are supported by kernel: %s", strnull(joined)); + log_debug("None of the configured modes are supported by kernel (%s): %s", + path, strnull(joined)); } return false; } @@ -284,7 +294,7 @@ static int s2h_supported(const SleepConfig *sleep_config, SleepSupport *ret_supp return false; } - FOREACH_ARRAY(i, operations, ELEMENTSOF(operations)) { + FOREACH_ELEMENT(i, operations) { r = sleep_supported_internal(sleep_config, *i, /* check_allowed = */ false, &support); if (r < 0) return r; @@ -338,8 +348,18 @@ static int sleep_supported_internal( return false; } - if (sleep_operation_is_hibernation(operation)) { - r = sleep_mode_supported(sleep_config->modes[operation]); + if (SLEEP_NEEDS_MEM_SLEEP(sleep_config, operation)) { + r = sleep_mode_supported("/sys/power/mem_sleep", sleep_config->mem_modes); + if (r < 0) + return r; + if (r == 0) { + *ret_support = SLEEP_STATE_OR_MODE_NOT_SUPPORTED; + return false; + } + } + + if (SLEEP_OPERATION_IS_HIBERNATION(operation)) { + r = sleep_mode_supported("/sys/power/disk", sleep_config->modes[operation]); if (r < 0) return r; if (r == 0) { @@ -348,16 +368,28 @@ static int sleep_supported_internal( } r = hibernation_is_safe(); - if (r == -ENOTRECOVERABLE) { + switch (r) { + + case -ENOTRECOVERABLE: *ret_support = SLEEP_RESUME_NOT_SUPPORTED; return false; - } - if (r == -ENOSPC) { + + case -ESTALE: + *ret_support = SLEEP_RESUME_DEVICE_MISSING; + return false; + + case -ENOMEDIUM: + *ret_support = SLEEP_RESUME_MISCONFIGURED; + return false; + + case -ENOSPC: *ret_support = SLEEP_NOT_ENOUGH_SWAP_SPACE; return false; + + default: + if (r < 0) + return r; } - if (r < 0) - return r; } else assert(!sleep_config->modes[operation]); |