Merge pull request #32705 from YHNdnzj/hibernate-error
hibernate-util: differentiate some errors from the generic ENOSPC; systemctl: adjust the fallback behavior for sleep operations
This commit is contained in:
@@ -2156,6 +2156,14 @@ static int method_do_shutdown_or_sleep(
|
||||
return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
|
||||
"Not running on EFI and resume= is not set, or noresume is set. No available method to resume from hibernation");
|
||||
|
||||
case SLEEP_RESUME_DEVICE_MISSING:
|
||||
return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
|
||||
"Specified resume device is missing or is not an active swap device");
|
||||
|
||||
case SLEEP_RESUME_MISCONFIGURED:
|
||||
return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
|
||||
"Invalid resume config: resume= is not populated yet resume_offset= is");
|
||||
|
||||
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");
|
||||
|
||||
@@ -159,7 +159,7 @@ static int read_resume_config(dev_t *ret_devno, uint64_t *ret_offset) {
|
||||
}
|
||||
|
||||
if (devno == 0 && offset > 0 && offset != UINT64_MAX)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM),
|
||||
"Found populated /sys/power/resume_offset (%" PRIu64 ") but /sys/power/resume is not set, refusing.",
|
||||
offset);
|
||||
|
||||
@@ -394,7 +394,7 @@ int find_suitable_hibernation_device_full(HibernationDevice *ret_device, uint64_
|
||||
if (!entry) {
|
||||
/* No need to check n_swaps == 0, since it's rejected early */
|
||||
assert(resume_config_devno > 0);
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ENOSPC), "Cannot find swap entry corresponding to /sys/power/resume.");
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "Cannot find swap entry corresponding to /sys/power/resume.");
|
||||
}
|
||||
|
||||
if (ret_device) {
|
||||
@@ -452,11 +452,11 @@ int hibernation_is_safe(void) {
|
||||
bypass_space_check = getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0;
|
||||
|
||||
r = find_suitable_hibernation_device_full(NULL, &size, &used);
|
||||
if (r == -ENOSPC && bypass_space_check)
|
||||
/* If we don't have any available swap space at all, and SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK
|
||||
* is set, skip all remaining checks since we can't do that properly anyway. It is quite
|
||||
* possible that the user is using a setup similar to #30083. When we actually perform
|
||||
* hibernation in sleep.c we'll check everything again. */
|
||||
if (IN_SET(r, -ENOSPC, -ESTALE) && bypass_space_check)
|
||||
/* If we don't have any available swap space at all, or the specified resume device is missing,
|
||||
* and $SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK is set, skip all remaining checks since
|
||||
* we can't do that properly anyway. It is quite possible that the user is using a setup
|
||||
* similar to #30083. When we actually perform hibernation in sleep.c we'll check everything again. */
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -368,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]);
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ typedef enum SleepSupport {
|
||||
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_RESUME_DEVICE_MISSING, /* resume= is specified, but the device cannot be found in /proc/swaps */
|
||||
SLEEP_RESUME_MISCONFIGURED, /* resume= is not set yet resume_offset= is configured */
|
||||
SLEEP_NOT_ENOUGH_SWAP_SPACE,
|
||||
SLEEP_ALARM_NOT_SUPPORTED, /* CLOCK_BOOTTIME_ALARM is unsupported by kernel (only used by s2h) */
|
||||
} SleepSupport;
|
||||
|
||||
@@ -223,8 +223,11 @@ int verb_start_special(int argc, char *argv[], void *userdata) {
|
||||
case ACTION_HYBRID_SLEEP:
|
||||
case ACTION_SUSPEND_THEN_HIBERNATE:
|
||||
|
||||
/* For sleep operations, do not automatically fall back to low-level operation for
|
||||
* errors other than logind not available. There's a high chance that logind did
|
||||
* some extra sanity check and that didn't pass. */
|
||||
r = logind_reboot(a);
|
||||
if (r >= 0 || IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS))
|
||||
if (r >= 0 || (r != -ENOSYS && arg_force == 0))
|
||||
return r;
|
||||
|
||||
arg_no_block = true;
|
||||
|
||||
Reference in New Issue
Block a user