[PATCH RFC] PM: sleep: Return -ECANCELED if aborting due to pm_wakeup_pending()
From: Nícolas F. R. A. Prado
Date: Tue Jun 09 2026 - 09:00:14 EST
If system sleep (suspend or hibernate) has been aborted due to
pm_wakeup_pending() returning true, return -ECANCELED so userspace can
tell it apart from actual failures.
ECANCELED is chosen both because it is a less common error code, so
it is less likely to be used for purposes other than the sleep abort due
to pending wakeups in this code path, and also because it more clearly
represents that the sleep was intentionally canceled.
Signed-off-by: Nícolas F. R. A. Prado <nfraprado@xxxxxxxxxxxxx>
---
To give more context on my specific use case:
I want to address the situation where the system is running systemd's
suspend-then-hibernate and while going into hibernation, the user
triggers a wakeup (by pressing the power button). The expectation is
that the system would abort suspend-then-hibernate and wakeup, but
instead it considers that as a hibernation failure and falls back to
suspend instead. The key thing here is that systemd isn't able to tell
that this hibernation failure is not really a failure but an intentional
abort, which is where the consistent error code for pm_wakeup_pending()
can solve the problem.
Sending as an RFC as this is changing an ABI and although I'm not aware
of userspace that relies on the current error codes, it would be good to
get more input on this.
---
drivers/base/power/main.c | 4 ++--
drivers/base/syscore.c | 2 +-
kernel/cpu.c | 2 +-
kernel/power/hibernate.c | 9 +++++++--
kernel/power/process.c | 2 +-
kernel/power/suspend.c | 2 +-
6 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index ed48c292f575..8585fb94811c 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1646,7 +1646,7 @@ static void device_suspend_late(struct device *dev, pm_message_t state, bool asy
goto Complete;
if (pm_wakeup_pending()) {
- WRITE_ONCE(async_error, -EBUSY);
+ WRITE_ONCE(async_error, -ECANCELED);
goto Complete;
}
@@ -1902,7 +1902,7 @@ static void device_suspend(struct device *dev, pm_message_t state, bool async)
if (pm_wakeup_pending()) {
dev->power.direct_complete = false;
- WRITE_ONCE(async_error, -EBUSY);
+ WRITE_ONCE(async_error, -ECANCELED);
goto Complete;
}
diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c
index 483adb796654..37877b0cabd4 100644
--- a/drivers/base/syscore.c
+++ b/drivers/base/syscore.c
@@ -54,7 +54,7 @@ int syscore_suspend(void)
/* Return error code if there are any wakeup interrupts pending. */
if (pm_wakeup_pending())
- return -EBUSY;
+ return -ECANCELED;
WARN_ONCE(!irqs_disabled(),
"Interrupts enabled before system core suspend.\n");
diff --git a/kernel/cpu.c b/kernel/cpu.c
index f975bb34915b..7e46d51d2431 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -1910,7 +1910,7 @@ int freeze_secondary_cpus(int primary)
if (pm_wakeup_pending()) {
pr_info("Wakeup pending. Abort CPU freeze\n");
- error = -EBUSY;
+ error = -ECANCELED;
break;
}
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index d2479c69d71a..56b431bf9b1d 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -349,9 +349,14 @@ static int create_image(int platform_mode)
goto Enable_irqs;
}
- if (hibernation_test(TEST_CORE) || pm_wakeup_pending())
+ if (hibernation_test(TEST_CORE))
goto Power_up;
+ if (pm_wakeup_pending()) {
+ error = -ECANCELED;
+ goto Power_up;
+ }
+
in_suspend = 1;
save_processor_state();
trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, true);
@@ -632,7 +637,7 @@ int hibernation_platform_enter(void)
goto Enable_irqs;
if (pm_wakeup_pending()) {
- error = -EAGAIN;
+ error = -ECANCELED;
goto Power_up;
}
diff --git a/kernel/power/process.c b/kernel/power/process.c
index dc0dfc349f22..bd164ccdcc2a 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -108,7 +108,7 @@ static int try_to_freeze_tasks(bool user_only)
what, elapsed_msecs / 1000, elapsed_msecs % 1000);
}
- return todo ? -EBUSY : 0;
+ return wakeup ? -ECANCELED : todo ? -EBUSY : 0;
}
/**
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 57c44268698f..8e1b43deb9e6 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -469,7 +469,7 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
trace_suspend_resume(TPS("machine_suspend"),
state, false);
} else if (*wakeup) {
- error = -EBUSY;
+ error = -ECANCELED;
}
syscore_resume();
}
---
base-commit: a87737435cfa134f9cdcc696ba3080759d04cf72
change-id: 20260609-wakeup-pending-ecanceled-e19bc14e6041
Best regards,
--
Nícolas F. R. A. Prado <nfraprado@xxxxxxxxxxxxx>