Commit 67e59f8d authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'pm-sysoff'

Merge fixes for regressions introduced by the recent rework of the
system reboot/poweroff code.

* pm-sysoff:
  kernel/reboot: Fix powering off using a non-syscall code paths
  kernel/reboot: Use static handler for register_platform_power_off()
parents 32d4fd57 2b8c612c
...@@ -315,6 +315,43 @@ static int sys_off_notify(struct notifier_block *nb, ...@@ -315,6 +315,43 @@ static int sys_off_notify(struct notifier_block *nb,
return handler->sys_off_cb(&data); return handler->sys_off_cb(&data);
} }
static struct sys_off_handler platform_sys_off_handler;
static struct sys_off_handler *alloc_sys_off_handler(int priority)
{
struct sys_off_handler *handler;
gfp_t flags;
/*
* Platforms like m68k can't allocate sys_off handler dynamically
* at the early boot time because memory allocator isn't available yet.
*/
if (priority == SYS_OFF_PRIO_PLATFORM) {
handler = &platform_sys_off_handler;
if (handler->cb_data)
return ERR_PTR(-EBUSY);
} else {
if (system_state > SYSTEM_RUNNING)
flags = GFP_ATOMIC;
else
flags = GFP_KERNEL;
handler = kzalloc(sizeof(*handler), flags);
if (!handler)
return ERR_PTR(-ENOMEM);
}
return handler;
}
static void free_sys_off_handler(struct sys_off_handler *handler)
{
if (handler == &platform_sys_off_handler)
memset(handler, 0, sizeof(*handler));
else
kfree(handler);
}
/** /**
* register_sys_off_handler - Register sys-off handler * register_sys_off_handler - Register sys-off handler
* @mode: Sys-off mode * @mode: Sys-off mode
...@@ -345,9 +382,9 @@ register_sys_off_handler(enum sys_off_mode mode, ...@@ -345,9 +382,9 @@ register_sys_off_handler(enum sys_off_mode mode,
struct sys_off_handler *handler; struct sys_off_handler *handler;
int err; int err;
handler = kzalloc(sizeof(*handler), GFP_KERNEL); handler = alloc_sys_off_handler(priority);
if (!handler) if (IS_ERR(handler))
return ERR_PTR(-ENOMEM); return handler;
switch (mode) { switch (mode) {
case SYS_OFF_MODE_POWER_OFF_PREPARE: case SYS_OFF_MODE_POWER_OFF_PREPARE:
...@@ -364,7 +401,7 @@ register_sys_off_handler(enum sys_off_mode mode, ...@@ -364,7 +401,7 @@ register_sys_off_handler(enum sys_off_mode mode,
break; break;
default: default:
kfree(handler); free_sys_off_handler(handler);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
...@@ -391,7 +428,7 @@ register_sys_off_handler(enum sys_off_mode mode, ...@@ -391,7 +428,7 @@ register_sys_off_handler(enum sys_off_mode mode,
} }
if (err) { if (err) {
kfree(handler); free_sys_off_handler(handler);
return ERR_PTR(err); return ERR_PTR(err);
} }
...@@ -409,7 +446,7 @@ void unregister_sys_off_handler(struct sys_off_handler *handler) ...@@ -409,7 +446,7 @@ void unregister_sys_off_handler(struct sys_off_handler *handler)
{ {
int err; int err;
if (!handler) if (IS_ERR_OR_NULL(handler))
return; return;
if (handler->blocking) if (handler->blocking)
...@@ -422,7 +459,7 @@ void unregister_sys_off_handler(struct sys_off_handler *handler) ...@@ -422,7 +459,7 @@ void unregister_sys_off_handler(struct sys_off_handler *handler)
/* sanity check, shall never happen */ /* sanity check, shall never happen */
WARN_ON(err); WARN_ON(err);
kfree(handler); free_sys_off_handler(handler);
} }
EXPORT_SYMBOL_GPL(unregister_sys_off_handler); EXPORT_SYMBOL_GPL(unregister_sys_off_handler);
...@@ -584,7 +621,23 @@ static void do_kernel_power_off_prepare(void) ...@@ -584,7 +621,23 @@ static void do_kernel_power_off_prepare(void)
*/ */
void do_kernel_power_off(void) void do_kernel_power_off(void)
{ {
struct sys_off_handler *sys_off = NULL;
/*
* Register sys-off handlers for legacy PM callback. This allows
* legacy PM callbacks temporary co-exist with the new sys-off API.
*
* TODO: Remove legacy handlers once all legacy PM users will be
* switched to the sys-off based APIs.
*/
if (pm_power_off)
sys_off = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
SYS_OFF_PRIO_DEFAULT,
legacy_pm_power_off, NULL);
atomic_notifier_call_chain(&power_off_handler_list, 0, NULL); atomic_notifier_call_chain(&power_off_handler_list, 0, NULL);
unregister_sys_off_handler(sys_off);
} }
/** /**
...@@ -595,7 +648,8 @@ void do_kernel_power_off(void) ...@@ -595,7 +648,8 @@ void do_kernel_power_off(void)
*/ */
bool kernel_can_power_off(void) bool kernel_can_power_off(void)
{ {
return !atomic_notifier_call_chain_is_empty(&power_off_handler_list); return !atomic_notifier_call_chain_is_empty(&power_off_handler_list) ||
pm_power_off;
} }
EXPORT_SYMBOL_GPL(kernel_can_power_off); EXPORT_SYMBOL_GPL(kernel_can_power_off);
...@@ -630,7 +684,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, ...@@ -630,7 +684,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg) void __user *, arg)
{ {
struct pid_namespace *pid_ns = task_active_pid_ns(current); struct pid_namespace *pid_ns = task_active_pid_ns(current);
struct sys_off_handler *sys_off = NULL;
char buffer[256]; char buffer[256];
int ret = 0; int ret = 0;
...@@ -655,21 +708,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, ...@@ -655,21 +708,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
if (ret) if (ret)
return ret; return ret;
/*
* Register sys-off handlers for legacy PM callback. This allows
* legacy PM callbacks temporary co-exist with the new sys-off API.
*
* TODO: Remove legacy handlers once all legacy PM users will be
* switched to the sys-off based APIs.
*/
if (pm_power_off) {
sys_off = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
SYS_OFF_PRIO_DEFAULT,
legacy_pm_power_off, NULL);
if (IS_ERR(sys_off))
return PTR_ERR(sys_off);
}
/* Instead of trying to make the power_off code look like /* Instead of trying to make the power_off code look like
* halt when pm_power_off is not set do it the easy way. * halt when pm_power_off is not set do it the easy way.
*/ */
...@@ -727,7 +765,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, ...@@ -727,7 +765,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
break; break;
} }
mutex_unlock(&system_transition_mutex); mutex_unlock(&system_transition_mutex);
unregister_sys_off_handler(sys_off);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment