forked from Minki/linux
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()
This commit is contained in:
commit
67e59f8d01
@ -315,6 +315,43 @@ static int sys_off_notify(struct notifier_block *nb,
|
||||
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
|
||||
* @mode: Sys-off mode
|
||||
@ -345,9 +382,9 @@ register_sys_off_handler(enum sys_off_mode mode,
|
||||
struct sys_off_handler *handler;
|
||||
int err;
|
||||
|
||||
handler = kzalloc(sizeof(*handler), GFP_KERNEL);
|
||||
if (!handler)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
handler = alloc_sys_off_handler(priority);
|
||||
if (IS_ERR(handler))
|
||||
return handler;
|
||||
|
||||
switch (mode) {
|
||||
case SYS_OFF_MODE_POWER_OFF_PREPARE:
|
||||
@ -364,7 +401,7 @@ register_sys_off_handler(enum sys_off_mode mode,
|
||||
break;
|
||||
|
||||
default:
|
||||
kfree(handler);
|
||||
free_sys_off_handler(handler);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
@ -391,7 +428,7 @@ register_sys_off_handler(enum sys_off_mode mode,
|
||||
}
|
||||
|
||||
if (err) {
|
||||
kfree(handler);
|
||||
free_sys_off_handler(handler);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
@ -409,7 +446,7 @@ void unregister_sys_off_handler(struct sys_off_handler *handler)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!handler)
|
||||
if (IS_ERR_OR_NULL(handler))
|
||||
return;
|
||||
|
||||
if (handler->blocking)
|
||||
@ -422,7 +459,7 @@ void unregister_sys_off_handler(struct sys_off_handler *handler)
|
||||
/* sanity check, shall never happen */
|
||||
WARN_ON(err);
|
||||
|
||||
kfree(handler);
|
||||
free_sys_off_handler(handler);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_sys_off_handler);
|
||||
|
||||
@ -584,7 +621,23 @@ static void do_kernel_power_off_prepare(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);
|
||||
|
||||
unregister_sys_off_handler(sys_off);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -595,7 +648,8 @@ void do_kernel_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);
|
||||
|
||||
@ -630,7 +684,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
|
||||
void __user *, arg)
|
||||
{
|
||||
struct pid_namespace *pid_ns = task_active_pid_ns(current);
|
||||
struct sys_off_handler *sys_off = NULL;
|
||||
char buffer[256];
|
||||
int ret = 0;
|
||||
|
||||
@ -655,21 +708,6 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
|
||||
if (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
|
||||
* 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,
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&system_transition_mutex);
|
||||
unregister_sys_off_handler(sys_off);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user