freezer: Have {,un}lock_system_sleep() save/restore flags

Rafael explained that the reason for having both PF_NOFREEZE and
PF_FREEZER_SKIP is that {,un}lock_system_sleep() is callable from
kthread context that has previously called set_freezable().

In preparation of merging the flags, have {,un}lock_system_slee() save
and restore current->flags.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://lore.kernel.org/r/20220822114648.725003428@infradead.org
This commit is contained in:
Peter Zijlstra 2022-08-22 13:18:17 +02:00
parent 0b9d46fc5e
commit 5950e5d574
7 changed files with 72 additions and 46 deletions

View File

@ -541,12 +541,14 @@ void acpi_s2idle_setup(void)
int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg) int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg)
{ {
unsigned int sleep_flags;
if (!lps0_device_handle || sleep_no_lps0) if (!lps0_device_handle || sleep_no_lps0)
return -ENODEV; return -ENODEV;
lock_system_sleep(); sleep_flags = lock_system_sleep();
list_add(&arg->list_node, &lps0_s2idle_devops_head); list_add(&arg->list_node, &lps0_s2idle_devops_head);
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
return 0; return 0;
} }
@ -554,12 +556,14 @@ EXPORT_SYMBOL_GPL(acpi_register_lps0_dev);
void acpi_unregister_lps0_dev(struct acpi_s2idle_dev_ops *arg) void acpi_unregister_lps0_dev(struct acpi_s2idle_dev_ops *arg)
{ {
unsigned int sleep_flags;
if (!lps0_device_handle || sleep_no_lps0) if (!lps0_device_handle || sleep_no_lps0)
return; return;
lock_system_sleep(); sleep_flags = lock_system_sleep();
list_del(&arg->list_node); list_del(&arg->list_node);
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
} }
EXPORT_SYMBOL_GPL(acpi_unregister_lps0_dev); EXPORT_SYMBOL_GPL(acpi_unregister_lps0_dev);

View File

@ -998,8 +998,9 @@ void
spi_dv_device(struct scsi_device *sdev) spi_dv_device(struct scsi_device *sdev)
{ {
struct scsi_target *starget = sdev->sdev_target; struct scsi_target *starget = sdev->sdev_target;
u8 *buffer;
const int len = SPI_MAX_ECHO_BUFFER_SIZE*2; const int len = SPI_MAX_ECHO_BUFFER_SIZE*2;
unsigned int sleep_flags;
u8 *buffer;
/* /*
* Because this function and the power management code both call * Because this function and the power management code both call
@ -1007,7 +1008,7 @@ spi_dv_device(struct scsi_device *sdev)
* while suspend or resume is in progress. Hence the * while suspend or resume is in progress. Hence the
* lock/unlock_system_sleep() calls. * lock/unlock_system_sleep() calls.
*/ */
lock_system_sleep(); sleep_flags = lock_system_sleep();
if (scsi_autopm_get_device(sdev)) if (scsi_autopm_get_device(sdev))
goto unlock_system_sleep; goto unlock_system_sleep;
@ -1058,7 +1059,7 @@ put_autopm:
scsi_autopm_put_device(sdev); scsi_autopm_put_device(sdev);
unlock_system_sleep: unlock_system_sleep:
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
} }
EXPORT_SYMBOL(spi_dv_device); EXPORT_SYMBOL(spi_dv_device);

View File

@ -510,8 +510,8 @@ extern bool pm_save_wakeup_count(unsigned int count);
extern void pm_wakep_autosleep_enabled(bool set); extern void pm_wakep_autosleep_enabled(bool set);
extern void pm_print_active_wakeup_sources(void); extern void pm_print_active_wakeup_sources(void);
extern void lock_system_sleep(void); extern unsigned int lock_system_sleep(void);
extern void unlock_system_sleep(void); extern void unlock_system_sleep(unsigned int);
#else /* !CONFIG_PM_SLEEP */ #else /* !CONFIG_PM_SLEEP */
@ -534,8 +534,8 @@ static inline void pm_system_wakeup(void) {}
static inline void pm_wakeup_clear(bool reset) {} static inline void pm_wakeup_clear(bool reset) {}
static inline void pm_system_irq_wakeup(unsigned int irq_number) {} static inline void pm_system_irq_wakeup(unsigned int irq_number) {}
static inline void lock_system_sleep(void) {} static inline unsigned int lock_system_sleep(void) { return 0; }
static inline void unlock_system_sleep(void) {} static inline void unlock_system_sleep(unsigned int flags) {}
#endif /* !CONFIG_PM_SLEEP */ #endif /* !CONFIG_PM_SLEEP */

View File

@ -92,20 +92,24 @@ bool hibernation_available(void)
*/ */
void hibernation_set_ops(const struct platform_hibernation_ops *ops) void hibernation_set_ops(const struct platform_hibernation_ops *ops)
{ {
unsigned int sleep_flags;
if (ops && !(ops->begin && ops->end && ops->pre_snapshot if (ops && !(ops->begin && ops->end && ops->pre_snapshot
&& ops->prepare && ops->finish && ops->enter && ops->pre_restore && ops->prepare && ops->finish && ops->enter && ops->pre_restore
&& ops->restore_cleanup && ops->leave)) { && ops->restore_cleanup && ops->leave)) {
WARN_ON(1); WARN_ON(1);
return; return;
} }
lock_system_sleep();
sleep_flags = lock_system_sleep();
hibernation_ops = ops; hibernation_ops = ops;
if (ops) if (ops)
hibernation_mode = HIBERNATION_PLATFORM; hibernation_mode = HIBERNATION_PLATFORM;
else if (hibernation_mode == HIBERNATION_PLATFORM) else if (hibernation_mode == HIBERNATION_PLATFORM)
hibernation_mode = HIBERNATION_SHUTDOWN; hibernation_mode = HIBERNATION_SHUTDOWN;
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
} }
EXPORT_SYMBOL_GPL(hibernation_set_ops); EXPORT_SYMBOL_GPL(hibernation_set_ops);
@ -713,6 +717,7 @@ static int load_image_and_restore(void)
int hibernate(void) int hibernate(void)
{ {
bool snapshot_test = false; bool snapshot_test = false;
unsigned int sleep_flags;
int error; int error;
if (!hibernation_available()) { if (!hibernation_available()) {
@ -720,7 +725,7 @@ int hibernate(void)
return -EPERM; return -EPERM;
} }
lock_system_sleep(); sleep_flags = lock_system_sleep();
/* The snapshot device should not be opened while we're running */ /* The snapshot device should not be opened while we're running */
if (!hibernate_acquire()) { if (!hibernate_acquire()) {
error = -EBUSY; error = -EBUSY;
@ -794,7 +799,7 @@ int hibernate(void)
pm_restore_console(); pm_restore_console();
hibernate_release(); hibernate_release();
Unlock: Unlock:
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
pr_info("hibernation exit\n"); pr_info("hibernation exit\n");
return error; return error;
@ -809,9 +814,10 @@ int hibernate(void)
*/ */
int hibernate_quiet_exec(int (*func)(void *data), void *data) int hibernate_quiet_exec(int (*func)(void *data), void *data)
{ {
unsigned int sleep_flags;
int error; int error;
lock_system_sleep(); sleep_flags = lock_system_sleep();
if (!hibernate_acquire()) { if (!hibernate_acquire()) {
error = -EBUSY; error = -EBUSY;
@ -891,7 +897,7 @@ restore:
hibernate_release(); hibernate_release();
unlock: unlock:
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
return error; return error;
} }
@ -1100,11 +1106,12 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n) const char *buf, size_t n)
{ {
int mode = HIBERNATION_INVALID;
unsigned int sleep_flags;
int error = 0; int error = 0;
int i;
int len; int len;
char *p; char *p;
int mode = HIBERNATION_INVALID; int i;
if (!hibernation_available()) if (!hibernation_available())
return -EPERM; return -EPERM;
@ -1112,7 +1119,7 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
p = memchr(buf, '\n', n); p = memchr(buf, '\n', n);
len = p ? p - buf : n; len = p ? p - buf : n;
lock_system_sleep(); sleep_flags = lock_system_sleep();
for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
if (len == strlen(hibernation_modes[i]) if (len == strlen(hibernation_modes[i])
&& !strncmp(buf, hibernation_modes[i], len)) { && !strncmp(buf, hibernation_modes[i], len)) {
@ -1142,7 +1149,7 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
if (!error) if (!error)
pm_pr_dbg("Hibernation mode set to '%s'\n", pm_pr_dbg("Hibernation mode set to '%s'\n",
hibernation_modes[mode]); hibernation_modes[mode]);
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
return error ? error : n; return error ? error : n;
} }
@ -1158,9 +1165,10 @@ static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n) const char *buf, size_t n)
{ {
dev_t res; unsigned int sleep_flags;
int len = n; int len = n;
char *name; char *name;
dev_t res;
if (len && buf[len-1] == '\n') if (len && buf[len-1] == '\n')
len--; len--;
@ -1173,9 +1181,10 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
if (!res) if (!res)
return -EINVAL; return -EINVAL;
lock_system_sleep(); sleep_flags = lock_system_sleep();
swsusp_resume_device = res; swsusp_resume_device = res;
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
pm_pr_dbg("Configured hibernation resume from disk to %u\n", pm_pr_dbg("Configured hibernation resume from disk to %u\n",
swsusp_resume_device); swsusp_resume_device);
noresume = 0; noresume = 0;

View File

@ -21,14 +21,16 @@
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
void lock_system_sleep(void) unsigned int lock_system_sleep(void)
{ {
unsigned int flags = current->flags;
current->flags |= PF_FREEZER_SKIP; current->flags |= PF_FREEZER_SKIP;
mutex_lock(&system_transition_mutex); mutex_lock(&system_transition_mutex);
return flags;
} }
EXPORT_SYMBOL_GPL(lock_system_sleep); EXPORT_SYMBOL_GPL(lock_system_sleep);
void unlock_system_sleep(void) void unlock_system_sleep(unsigned int flags)
{ {
/* /*
* Don't use freezer_count() because we don't want the call to * Don't use freezer_count() because we don't want the call to
@ -46,7 +48,8 @@ void unlock_system_sleep(void)
* Which means, if we use try_to_freeze() here, it would make them * Which means, if we use try_to_freeze() here, it would make them
* enter the refrigerator, thus causing hibernation to lockup. * enter the refrigerator, thus causing hibernation to lockup.
*/ */
current->flags &= ~PF_FREEZER_SKIP; if (!(flags & PF_FREEZER_SKIP))
current->flags &= ~PF_FREEZER_SKIP;
mutex_unlock(&system_transition_mutex); mutex_unlock(&system_transition_mutex);
} }
EXPORT_SYMBOL_GPL(unlock_system_sleep); EXPORT_SYMBOL_GPL(unlock_system_sleep);
@ -263,16 +266,17 @@ static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr, static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n) const char *buf, size_t n)
{ {
unsigned int sleep_flags;
const char * const *s; const char * const *s;
int error = -EINVAL;
int level; int level;
char *p; char *p;
int len; int len;
int error = -EINVAL;
p = memchr(buf, '\n', n); p = memchr(buf, '\n', n);
len = p ? p - buf : n; len = p ? p - buf : n;
lock_system_sleep(); sleep_flags = lock_system_sleep();
level = TEST_FIRST; level = TEST_FIRST;
for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++) for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)
@ -282,7 +286,7 @@ static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
break; break;
} }
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
return error ? error : n; return error ? error : n;
} }

View File

@ -75,9 +75,11 @@ EXPORT_SYMBOL_GPL(pm_suspend_default_s2idle);
void s2idle_set_ops(const struct platform_s2idle_ops *ops) void s2idle_set_ops(const struct platform_s2idle_ops *ops)
{ {
lock_system_sleep(); unsigned int sleep_flags;
sleep_flags = lock_system_sleep();
s2idle_ops = ops; s2idle_ops = ops;
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
} }
static void s2idle_begin(void) static void s2idle_begin(void)
@ -200,7 +202,9 @@ __setup("mem_sleep_default=", mem_sleep_default_setup);
*/ */
void suspend_set_ops(const struct platform_suspend_ops *ops) void suspend_set_ops(const struct platform_suspend_ops *ops)
{ {
lock_system_sleep(); unsigned int sleep_flags;
sleep_flags = lock_system_sleep();
suspend_ops = ops; suspend_ops = ops;
@ -216,7 +220,7 @@ void suspend_set_ops(const struct platform_suspend_ops *ops)
mem_sleep_current = PM_SUSPEND_MEM; mem_sleep_current = PM_SUSPEND_MEM;
} }
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
} }
EXPORT_SYMBOL_GPL(suspend_set_ops); EXPORT_SYMBOL_GPL(suspend_set_ops);

View File

@ -47,12 +47,13 @@ int is_hibernate_resume_dev(dev_t dev)
static int snapshot_open(struct inode *inode, struct file *filp) static int snapshot_open(struct inode *inode, struct file *filp)
{ {
struct snapshot_data *data; struct snapshot_data *data;
unsigned int sleep_flags;
int error; int error;
if (!hibernation_available()) if (!hibernation_available())
return -EPERM; return -EPERM;
lock_system_sleep(); sleep_flags = lock_system_sleep();
if (!hibernate_acquire()) { if (!hibernate_acquire()) {
error = -EBUSY; error = -EBUSY;
@ -98,7 +99,7 @@ static int snapshot_open(struct inode *inode, struct file *filp)
data->dev = 0; data->dev = 0;
Unlock: Unlock:
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
return error; return error;
} }
@ -106,8 +107,9 @@ static int snapshot_open(struct inode *inode, struct file *filp)
static int snapshot_release(struct inode *inode, struct file *filp) static int snapshot_release(struct inode *inode, struct file *filp)
{ {
struct snapshot_data *data; struct snapshot_data *data;
unsigned int sleep_flags;
lock_system_sleep(); sleep_flags = lock_system_sleep();
swsusp_free(); swsusp_free();
data = filp->private_data; data = filp->private_data;
@ -124,7 +126,7 @@ static int snapshot_release(struct inode *inode, struct file *filp)
PM_POST_HIBERNATION : PM_POST_RESTORE); PM_POST_HIBERNATION : PM_POST_RESTORE);
hibernate_release(); hibernate_release();
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
return 0; return 0;
} }
@ -132,11 +134,12 @@ static int snapshot_release(struct inode *inode, struct file *filp)
static ssize_t snapshot_read(struct file *filp, char __user *buf, static ssize_t snapshot_read(struct file *filp, char __user *buf,
size_t count, loff_t *offp) size_t count, loff_t *offp)
{ {
struct snapshot_data *data;
ssize_t res;
loff_t pg_offp = *offp & ~PAGE_MASK; loff_t pg_offp = *offp & ~PAGE_MASK;
struct snapshot_data *data;
unsigned int sleep_flags;
ssize_t res;
lock_system_sleep(); sleep_flags = lock_system_sleep();
data = filp->private_data; data = filp->private_data;
if (!data->ready) { if (!data->ready) {
@ -157,7 +160,7 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf,
*offp += res; *offp += res;
Unlock: Unlock:
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
return res; return res;
} }
@ -165,16 +168,17 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf,
static ssize_t snapshot_write(struct file *filp, const char __user *buf, static ssize_t snapshot_write(struct file *filp, const char __user *buf,
size_t count, loff_t *offp) size_t count, loff_t *offp)
{ {
struct snapshot_data *data;
ssize_t res;
loff_t pg_offp = *offp & ~PAGE_MASK; loff_t pg_offp = *offp & ~PAGE_MASK;
struct snapshot_data *data;
unsigned long sleep_flags;
ssize_t res;
if (need_wait) { if (need_wait) {
wait_for_device_probe(); wait_for_device_probe();
need_wait = false; need_wait = false;
} }
lock_system_sleep(); sleep_flags = lock_system_sleep();
data = filp->private_data; data = filp->private_data;
@ -196,7 +200,7 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
if (res > 0) if (res > 0)
*offp += res; *offp += res;
unlock: unlock:
unlock_system_sleep(); unlock_system_sleep(sleep_flags);
return res; return res;
} }