From: Mike Yuan Date: Mon, 16 Oct 2023 12:34:29 +0000 (+0800) Subject: sleep-config: introduce sleep_supported_full that returns a reason X-Git-Tag: v255-rc1~170^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a0f6d74ec89d6f41de2b896e1e39b4f3af901428;p=thirdparty%2Fsystemd.git sleep-config: introduce sleep_supported_full that returns a reason Preparation for later commits. Also some other cleanups: * Add assertions * Use FOREACH_ARRAY --- diff --git a/src/login/logind-action.c b/src/login/logind-action.c index a2b211933a2..d4d53bddd70 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -201,20 +201,20 @@ int manager_handle_action( } if (handle == HANDLE_SUSPEND) - supported = can_sleep(SLEEP_SUSPEND) > 0; + supported = sleep_supported(SLEEP_SUSPEND) > 0; else if (handle == HANDLE_HIBERNATE) - supported = can_sleep(SLEEP_HIBERNATE) > 0; + supported = sleep_supported(SLEEP_HIBERNATE) > 0; else if (handle == HANDLE_HYBRID_SLEEP) - supported = can_sleep(SLEEP_HYBRID_SLEEP) > 0; + supported = sleep_supported(SLEEP_HYBRID_SLEEP) > 0; else if (handle == HANDLE_SUSPEND_THEN_HIBERNATE) - supported = can_sleep(SLEEP_SUSPEND_THEN_HIBERNATE) > 0; + supported = sleep_supported(SLEEP_SUSPEND_THEN_HIBERNATE) > 0; else if (handle == HANDLE_KEXEC) supported = access(KEXEC, X_OK) >= 0; else supported = true; if (!supported && HANDLE_ACTION_IS_SLEEP(handle) && handle != HANDLE_SUSPEND) { - supported = can_sleep(SLEEP_SUSPEND) > 0; + supported = sleep_supported(SLEEP_SUSPEND) > 0; if (supported) { log_notice("Requested %s operation is not supported, using regular suspend instead.", handle_action_to_string(handle)); diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index d631a307166..e17d48bf262 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1924,16 +1924,34 @@ static int method_do_shutdown_or_sleep( "There's already a shutdown or sleep operation in progress"); if (a->sleep_operation >= 0) { - r = can_sleep(a->sleep_operation); - if (r == -ENOSPC) - 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"); - if (r == 0) - return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, - "Sleep verb \"%s\" not supported", - sleep_operation_to_string(a->sleep_operation)); + SleepSupport support; + + r = sleep_supported_full(a->sleep_operation, &support); if (r < 0) return r; + if (r == 0) + switch (support) { + + case SLEEP_DISABLED: + return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, + "Sleep verb '%s' is disabled by config", + sleep_operation_to_string(a->sleep_operation)); + + case SLEEP_NOT_CONFIGURED: + case SLEEP_STATE_OR_MODE_NOT_SUPPORTED: + case SLEEP_ALARM_NOT_SUPPORTED: + return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, + "Sleep verb '%s' is not configured or configuration is not supported by kernel", + sleep_operation_to_string(a->sleep_operation)); + + 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"); + + default: + assert_not_reached(); + + } } r = verify_shutdown_creds(m, message, a, flags, error); @@ -2395,11 +2413,11 @@ static int method_can_shutdown_or_sleep( assert(a); if (a->sleep_operation >= 0) { - r = can_sleep(a->sleep_operation); - if (IN_SET(r, 0, -ENOSPC)) - return sd_bus_reply_method_return(message, "s", "na"); + r = sleep_supported(a->sleep_operation); if (r < 0) return r; + if (r == 0) + return sd_bus_reply_method_return(message, "s", "na"); } r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index 736e38381fb..e5e96041ed0 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -191,71 +191,122 @@ int sleep_mode_supported(char **modes) { return false; } -static int can_sleep_internal(const SleepConfig *sleep_config, SleepOperation operation, bool check_allowed); +static int sleep_supported_internal( + const SleepConfig *sleep_config, + SleepOperation operation, + bool check_allowed, + SleepSupport *ret_support); -static bool can_s2h(const SleepConfig *sleep_config) { +static int s2h_supported(const SleepConfig *sleep_config, SleepSupport *ret_support) { static const SleepOperation operations[] = { SLEEP_SUSPEND, SLEEP_HIBERNATE, }; + SleepSupport support; int r; + assert(sleep_config); + assert(ret_support); + if (!clock_supported(CLOCK_BOOTTIME_ALARM)) { - log_debug("CLOCK_BOOTTIME_ALARM is not supported."); + log_debug("CLOCK_BOOTTIME_ALARM is not supported, can't perform %s.", sleep_operation_to_string(SLEEP_SUSPEND_THEN_HIBERNATE)); + *ret_support = SLEEP_ALARM_NOT_SUPPORTED; return false; } - for (size_t i = 0; i < ELEMENTSOF(operations); i++) { - r = can_sleep_internal(sleep_config, operations[i], false); - if (IN_SET(r, 0, -ENOSPC)) { - log_debug("Unable to %s system.", sleep_operation_to_string(operations[i])); + FOREACH_ARRAY(i, operations, ELEMENTSOF(operations)) { + r = sleep_supported_internal(sleep_config, *i, /* check_allowed = */ false, &support); + if (r < 0) + return r; + if (r == 0) { + log_debug("Sleep operation %s is not supported, can't perform %s.", + sleep_operation_to_string(*i), sleep_operation_to_string(SLEEP_SUSPEND_THEN_HIBERNATE)); + *ret_support = support; return false; } - if (r < 0) - return log_debug_errno(r, "Failed to check if %s is possible: %m", sleep_operation_to_string(operations[i])); } + assert(support == SLEEP_SUPPORTED); + *ret_support = support; + return true; } -static int can_sleep_internal( +static int sleep_supported_internal( const SleepConfig *sleep_config, SleepOperation operation, - bool check_allowed) { + bool check_allowed, + SleepSupport *ret_support) { + + int r; + assert(sleep_config); assert(operation >= 0); assert(operation < _SLEEP_OPERATION_MAX); + assert(ret_support); if (check_allowed && !sleep_config->allow[operation]) { - log_debug("Sleep mode \"%s\" is disabled by configuration.", sleep_operation_to_string(operation)); + log_debug("Sleep operation %s is disabled by configuration.", sleep_operation_to_string(operation)); + *ret_support = SLEEP_DISABLED; return false; } if (operation == SLEEP_SUSPEND_THEN_HIBERNATE) - return can_s2h(sleep_config); + return s2h_supported(sleep_config, ret_support); - if (sleep_state_supported(sleep_config->states[operation]) <= 0 || - sleep_mode_supported(sleep_config->modes[operation]) <= 0) + assert(operation < _SLEEP_OPERATION_CONFIG_MAX); + + r = sleep_state_supported(sleep_config->states[operation]); + if (r == -ENOMSG) { + *ret_support = SLEEP_NOT_CONFIGURED; return false; + } + if (r < 0) + return r; + if (r == 0) { + *ret_support = SLEEP_STATE_OR_MODE_NOT_SUPPORTED; + return false; + } - if (operation == SLEEP_SUSPEND) - return true; + r = sleep_mode_supported(sleep_config->modes[operation]); + if (r < 0) + return r; + if (r == 0) { + *ret_support = SLEEP_STATE_OR_MODE_NOT_SUPPORTED; + return false; + } - if (!enough_swap_for_hibernation()) - return -ENOSPC; + if (IN_SET(operation, SLEEP_HIBERNATE, SLEEP_HYBRID_SLEEP) && !enough_swap_for_hibernation()) { + *ret_support = SLEEP_NOT_ENOUGH_SWAP_SPACE; + return false; + } + *ret_support = SLEEP_SUPPORTED; return true; } -int can_sleep(SleepOperation operation) { +int sleep_supported_full(SleepOperation operation, SleepSupport *ret_support) { _cleanup_(sleep_config_freep) SleepConfig *sleep_config = NULL; + SleepSupport support; int r; + assert(operation >= 0); + assert(operation < _SLEEP_OPERATION_MAX); + r = parse_sleep_config(&sleep_config); if (r < 0) return r; - return can_sleep_internal(sleep_config, operation, true); + r = sleep_supported_internal(sleep_config, operation, /* check_allowed = */ true, &support); + if (r < 0) + return r; + + assert((r > 0) == (support == SLEEP_SUPPORTED)); + + if (ret_support) + *ret_support = support; + + return r; } diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h index fc737bf9410..756b0e13ae2 100644 --- a/src/shared/sleep-config.h +++ b/src/shared/sleep-config.h @@ -35,7 +35,19 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(SleepConfig*, sleep_config_free); int parse_sleep_config(SleepConfig **sleep_config); -int can_sleep(SleepOperation operation); +typedef enum SleepSupport { + SLEEP_SUPPORTED, + 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_NOT_ENOUGH_SWAP_SPACE, + SLEEP_ALARM_NOT_SUPPORTED, /* CLOCK_BOOTTIME_ALARM is unsupported by kernel (only used by s2h) */ +} SleepSupport; + +int sleep_supported_full(SleepOperation operation, SleepSupport *ret_support); +static inline int sleep_supported(SleepOperation operation) { + return sleep_supported_full(operation, NULL); +} /* Only for test-sleep-config */ int sleep_state_supported(char **states); diff --git a/src/test/test-sleep-config.c b/src/test/test-sleep-config.c index c7aa0619b42..112fec63461 100644 --- a/src/test/test-sleep-config.c +++ b/src/test/test-sleep-config.c @@ -59,13 +59,13 @@ TEST(sleep_supported) { log_info("Freeze configured: %s", yes_no(sleep_state_supported(freeze) > 0)); log_info("/= high-level sleep verbs =/"); - r = can_sleep(SLEEP_SUSPEND); + r = sleep_supported(SLEEP_SUSPEND); log_info("Suspend configured and possible: %s", r >= 0 ? yes_no(r) : STRERROR(r)); - r = can_sleep(SLEEP_HIBERNATE); + r = sleep_supported(SLEEP_HIBERNATE); log_info("Hibernation configured and possible: %s", r >= 0 ? yes_no(r) : STRERROR(r)); - r = can_sleep(SLEEP_HYBRID_SLEEP); + r = sleep_supported(SLEEP_HYBRID_SLEEP); log_info("Hybrid-sleep configured and possible: %s", r >= 0 ? yes_no(r) : STRERROR(r)); - r = can_sleep(SLEEP_SUSPEND_THEN_HIBERNATE); + r = sleep_supported(SLEEP_SUSPEND_THEN_HIBERNATE); log_info("Suspend-then-Hibernate configured and possible: %s", r >= 0 ? yes_no(r) : STRERROR(r)); }