hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/kernel/power/user.c
....@@ -1,16 +1,13 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * linux/kernel/power/user.c
34 *
45 * This file provides the user space interface for software suspend/resume.
56 *
67 * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
7
- *
8
- * This file is released under the GPLv2.
9
- *
108 */
119
1210 #include <linux/suspend.h>
13
-#include <linux/syscalls.h>
1411 #include <linux/reboot.h>
1512 #include <linux/string.h>
1613 #include <linux/device.h>
....@@ -29,8 +26,7 @@
2926
3027 #include "power.h"
3128
32
-
33
-#define SNAPSHOT_MINOR 231
29
+static bool need_wait;
3430
3531 static struct snapshot_data {
3632 struct snapshot_handle handle;
....@@ -40,27 +36,31 @@
4036 bool ready;
4137 bool platform_support;
4238 bool free_bitmaps;
39
+ dev_t dev;
4340 } snapshot_state;
4441
45
-atomic_t snapshot_device_available = ATOMIC_INIT(1);
42
+int is_hibernate_resume_dev(dev_t dev)
43
+{
44
+ return hibernation_available() && snapshot_state.dev == dev;
45
+}
4646
4747 static int snapshot_open(struct inode *inode, struct file *filp)
4848 {
4949 struct snapshot_data *data;
50
- int error, nr_calls = 0;
50
+ int error;
5151
5252 if (!hibernation_available())
5353 return -EPERM;
5454
5555 lock_system_sleep();
5656
57
- if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
57
+ if (!hibernate_acquire()) {
5858 error = -EBUSY;
5959 goto Unlock;
6060 }
6161
6262 if ((filp->f_flags & O_ACCMODE) == O_RDWR) {
63
- atomic_inc(&snapshot_device_available);
63
+ hibernate_release();
6464 error = -ENOSYS;
6565 goto Unlock;
6666 }
....@@ -70,38 +70,32 @@
7070 memset(&data->handle, 0, sizeof(struct snapshot_handle));
7171 if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
7272 /* Hibernating. The image device should be accessible. */
73
- data->swap = swsusp_resume_device ?
74
- swap_type_of(swsusp_resume_device, 0, NULL) : -1;
73
+ data->swap = swap_type_of(swsusp_resume_device, 0);
7574 data->mode = O_RDONLY;
7675 data->free_bitmaps = false;
77
- error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls);
78
- if (error)
79
- __pm_notifier_call_chain(PM_POST_HIBERNATION, --nr_calls, NULL);
76
+ error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION);
8077 } else {
8178 /*
8279 * Resuming. We may need to wait for the image device to
8380 * appear.
8481 */
85
- wait_for_device_probe();
82
+ need_wait = true;
8683
8784 data->swap = -1;
8885 data->mode = O_WRONLY;
89
- error = __pm_notifier_call_chain(PM_RESTORE_PREPARE, -1, &nr_calls);
86
+ error = pm_notifier_call_chain_robust(PM_RESTORE_PREPARE, PM_POST_RESTORE);
9087 if (!error) {
9188 error = create_basic_memory_bitmaps();
9289 data->free_bitmaps = !error;
93
- } else
94
- nr_calls--;
95
-
96
- if (error)
97
- __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
90
+ }
9891 }
9992 if (error)
100
- atomic_inc(&snapshot_device_available);
93
+ hibernate_release();
10194
10295 data->frozen = false;
10396 data->ready = false;
10497 data->platform_support = false;
98
+ data->dev = 0;
10599
106100 Unlock:
107101 unlock_system_sleep();
....@@ -117,6 +111,7 @@
117111
118112 swsusp_free();
119113 data = filp->private_data;
114
+ data->dev = 0;
120115 free_all_swap_pages(data->swap);
121116 if (data->frozen) {
122117 pm_restore_gfp_mask();
....@@ -127,7 +122,7 @@
127122 }
128123 pm_notifier_call_chain(data->mode == O_RDONLY ?
129124 PM_POST_HIBERNATION : PM_POST_RESTORE);
130
- atomic_inc(&snapshot_device_available);
125
+ hibernate_release();
131126
132127 unlock_system_sleep();
133128
....@@ -174,6 +169,11 @@
174169 ssize_t res;
175170 loff_t pg_offp = *offp & ~PAGE_MASK;
176171
172
+ if (need_wait) {
173
+ wait_for_device_probe();
174
+ need_wait = false;
175
+ }
176
+
177177 lock_system_sleep();
178178
179179 data = filp->private_data;
....@@ -201,6 +201,47 @@
201201 return res;
202202 }
203203
204
+struct compat_resume_swap_area {
205
+ compat_loff_t offset;
206
+ u32 dev;
207
+} __packed;
208
+
209
+static int snapshot_set_swap_area(struct snapshot_data *data,
210
+ void __user *argp)
211
+{
212
+ sector_t offset;
213
+ dev_t swdev;
214
+
215
+ if (swsusp_swap_in_use())
216
+ return -EPERM;
217
+
218
+ if (in_compat_syscall()) {
219
+ struct compat_resume_swap_area swap_area;
220
+
221
+ if (copy_from_user(&swap_area, argp, sizeof(swap_area)))
222
+ return -EFAULT;
223
+ swdev = new_decode_dev(swap_area.dev);
224
+ offset = swap_area.offset;
225
+ } else {
226
+ struct resume_swap_area swap_area;
227
+
228
+ if (copy_from_user(&swap_area, argp, sizeof(swap_area)))
229
+ return -EFAULT;
230
+ swdev = new_decode_dev(swap_area.dev);
231
+ offset = swap_area.offset;
232
+ }
233
+
234
+ /*
235
+ * User space encodes device types as two-byte values,
236
+ * so we need to recode them
237
+ */
238
+ data->swap = swap_type_of(swdev, offset);
239
+ if (data->swap < 0)
240
+ return swdev ? -ENODEV : -EINVAL;
241
+ data->dev = swdev;
242
+ return 0;
243
+}
244
+
204245 static long snapshot_ioctl(struct file *filp, unsigned int cmd,
205246 unsigned long arg)
206247 {
....@@ -208,6 +249,11 @@
208249 struct snapshot_data *data;
209250 loff_t size;
210251 sector_t offset;
252
+
253
+ if (need_wait) {
254
+ wait_for_device_probe();
255
+ need_wait = false;
256
+ }
211257
212258 if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
213259 return -ENOTTY;
....@@ -228,9 +274,7 @@
228274 if (data->frozen)
229275 break;
230276
231
- printk("Syncing filesystems ... ");
232
- ksys_sync();
233
- printk("done.\n");
277
+ ksys_sync_helper();
234278
235279 error = freeze_processes();
236280 if (error)
....@@ -358,34 +402,7 @@
358402 break;
359403
360404 case SNAPSHOT_SET_SWAP_AREA:
361
- if (swsusp_swap_in_use()) {
362
- error = -EPERM;
363
- } else {
364
- struct resume_swap_area swap_area;
365
- dev_t swdev;
366
-
367
- error = copy_from_user(&swap_area, (void __user *)arg,
368
- sizeof(struct resume_swap_area));
369
- if (error) {
370
- error = -EFAULT;
371
- break;
372
- }
373
-
374
- /*
375
- * User space encodes device types as two-byte values,
376
- * so we need to recode them
377
- */
378
- swdev = new_decode_dev(swap_area.dev);
379
- if (swdev) {
380
- offset = swap_area.offset;
381
- data->swap = swap_type_of(swdev, offset, NULL);
382
- if (data->swap < 0)
383
- error = -ENODEV;
384
- } else {
385
- data->swap = -1;
386
- error = -EINVAL;
387
- }
388
- }
405
+ error = snapshot_set_swap_area(data, (void __user *)arg);
389406 break;
390407
391408 default:
....@@ -400,12 +417,6 @@
400417 }
401418
402419 #ifdef CONFIG_COMPAT
403
-
404
-struct compat_resume_swap_area {
405
- compat_loff_t offset;
406
- u32 dev;
407
-} __packed;
408
-
409420 static long
410421 snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
411422 {
....@@ -414,49 +425,15 @@
414425 switch (cmd) {
415426 case SNAPSHOT_GET_IMAGE_SIZE:
416427 case SNAPSHOT_AVAIL_SWAP_SIZE:
417
- case SNAPSHOT_ALLOC_SWAP_PAGE: {
418
- compat_loff_t __user *uoffset = compat_ptr(arg);
419
- loff_t offset;
420
- mm_segment_t old_fs;
421
- int err;
422
-
423
- old_fs = get_fs();
424
- set_fs(KERNEL_DS);
425
- err = snapshot_ioctl(file, cmd, (unsigned long) &offset);
426
- set_fs(old_fs);
427
- if (!err && put_user(offset, uoffset))
428
- err = -EFAULT;
429
- return err;
430
- }
431
-
428
+ case SNAPSHOT_ALLOC_SWAP_PAGE:
432429 case SNAPSHOT_CREATE_IMAGE:
430
+ case SNAPSHOT_SET_SWAP_AREA:
433431 return snapshot_ioctl(file, cmd,
434432 (unsigned long) compat_ptr(arg));
435
-
436
- case SNAPSHOT_SET_SWAP_AREA: {
437
- struct compat_resume_swap_area __user *u_swap_area =
438
- compat_ptr(arg);
439
- struct resume_swap_area swap_area;
440
- mm_segment_t old_fs;
441
- int err;
442
-
443
- err = get_user(swap_area.offset, &u_swap_area->offset);
444
- err |= get_user(swap_area.dev, &u_swap_area->dev);
445
- if (err)
446
- return -EFAULT;
447
- old_fs = get_fs();
448
- set_fs(KERNEL_DS);
449
- err = snapshot_ioctl(file, SNAPSHOT_SET_SWAP_AREA,
450
- (unsigned long) &swap_area);
451
- set_fs(old_fs);
452
- return err;
453
- }
454
-
455433 default:
456434 return snapshot_ioctl(file, cmd, arg);
457435 }
458436 }
459
-
460437 #endif /* CONFIG_COMPAT */
461438
462439 static const struct file_operations snapshot_fops = {