1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * linux/kernel/power/user.c |
4 | * |
5 | * This file provides the user space interface for software suspend/resume. |
6 | * |
7 | * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl> |
8 | */ |
9 | |
10 | #include <linux/suspend.h> |
11 | #include <linux/reboot.h> |
12 | #include <linux/string.h> |
13 | #include <linux/device.h> |
14 | #include <linux/miscdevice.h> |
15 | #include <linux/mm.h> |
16 | #include <linux/swap.h> |
17 | #include <linux/swapops.h> |
18 | #include <linux/pm.h> |
19 | #include <linux/fs.h> |
20 | #include <linux/compat.h> |
21 | #include <linux/console.h> |
22 | #include <linux/cpu.h> |
23 | #include <linux/freezer.h> |
24 | |
25 | #include <linux/uaccess.h> |
26 | |
27 | #include "power.h" |
28 | |
29 | static bool need_wait; |
30 | |
31 | static struct snapshot_data { |
32 | struct snapshot_handle handle; |
33 | int swap; |
34 | int mode; |
35 | bool frozen; |
36 | bool ready; |
37 | bool platform_support; |
38 | bool free_bitmaps; |
39 | dev_t dev; |
40 | } snapshot_state; |
41 | |
42 | int is_hibernate_resume_dev(dev_t dev) |
43 | { |
44 | return hibernation_available() && snapshot_state.dev == dev; |
45 | } |
46 | |
47 | static int snapshot_open(struct inode *inode, struct file *filp) |
48 | { |
49 | struct snapshot_data *data; |
50 | unsigned int sleep_flags; |
51 | int error; |
52 | |
53 | if (!hibernation_available()) |
54 | return -EPERM; |
55 | |
56 | sleep_flags = lock_system_sleep(); |
57 | |
58 | if (!hibernate_acquire()) { |
59 | error = -EBUSY; |
60 | goto Unlock; |
61 | } |
62 | |
63 | if ((filp->f_flags & O_ACCMODE) == O_RDWR) { |
64 | hibernate_release(); |
65 | error = -ENOSYS; |
66 | goto Unlock; |
67 | } |
68 | nonseekable_open(inode, filp); |
69 | data = &snapshot_state; |
70 | filp->private_data = data; |
71 | memset(&data->handle, 0, sizeof(struct snapshot_handle)); |
72 | if ((filp->f_flags & O_ACCMODE) == O_RDONLY) { |
73 | /* Hibernating. The image device should be accessible. */ |
74 | data->swap = swap_type_of(device: swsusp_resume_device, offset: 0); |
75 | data->mode = O_RDONLY; |
76 | data->free_bitmaps = false; |
77 | error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION); |
78 | } else { |
79 | /* |
80 | * Resuming. We may need to wait for the image device to |
81 | * appear. |
82 | */ |
83 | need_wait = true; |
84 | |
85 | data->swap = -1; |
86 | data->mode = O_WRONLY; |
87 | error = pm_notifier_call_chain_robust(PM_RESTORE_PREPARE, PM_POST_RESTORE); |
88 | if (!error) { |
89 | error = create_basic_memory_bitmaps(); |
90 | data->free_bitmaps = !error; |
91 | } |
92 | } |
93 | if (error) |
94 | hibernate_release(); |
95 | |
96 | data->frozen = false; |
97 | data->ready = false; |
98 | data->platform_support = false; |
99 | data->dev = 0; |
100 | |
101 | Unlock: |
102 | unlock_system_sleep(sleep_flags); |
103 | |
104 | return error; |
105 | } |
106 | |
107 | static int snapshot_release(struct inode *inode, struct file *filp) |
108 | { |
109 | struct snapshot_data *data; |
110 | unsigned int sleep_flags; |
111 | |
112 | sleep_flags = lock_system_sleep(); |
113 | |
114 | swsusp_free(); |
115 | data = filp->private_data; |
116 | data->dev = 0; |
117 | free_all_swap_pages(swap: data->swap); |
118 | if (data->frozen) { |
119 | pm_restore_gfp_mask(); |
120 | free_basic_memory_bitmaps(); |
121 | thaw_processes(); |
122 | } else if (data->free_bitmaps) { |
123 | free_basic_memory_bitmaps(); |
124 | } |
125 | pm_notifier_call_chain(val: data->mode == O_RDONLY ? |
126 | PM_POST_HIBERNATION : PM_POST_RESTORE); |
127 | hibernate_release(); |
128 | |
129 | unlock_system_sleep(sleep_flags); |
130 | |
131 | return 0; |
132 | } |
133 | |
134 | static ssize_t snapshot_read(struct file *filp, char __user *buf, |
135 | size_t count, loff_t *offp) |
136 | { |
137 | loff_t pg_offp = *offp & ~PAGE_MASK; |
138 | struct snapshot_data *data; |
139 | unsigned int sleep_flags; |
140 | ssize_t res; |
141 | |
142 | sleep_flags = lock_system_sleep(); |
143 | |
144 | data = filp->private_data; |
145 | if (!data->ready) { |
146 | res = -ENODATA; |
147 | goto Unlock; |
148 | } |
149 | if (!pg_offp) { /* on page boundary? */ |
150 | res = snapshot_read_next(handle: &data->handle); |
151 | if (res <= 0) |
152 | goto Unlock; |
153 | } else { |
154 | res = PAGE_SIZE - pg_offp; |
155 | } |
156 | |
157 | res = simple_read_from_buffer(to: buf, count, ppos: &pg_offp, |
158 | data_of(data->handle), available: res); |
159 | if (res > 0) |
160 | *offp += res; |
161 | |
162 | Unlock: |
163 | unlock_system_sleep(sleep_flags); |
164 | |
165 | return res; |
166 | } |
167 | |
168 | static ssize_t snapshot_write(struct file *filp, const char __user *buf, |
169 | size_t count, loff_t *offp) |
170 | { |
171 | loff_t pg_offp = *offp & ~PAGE_MASK; |
172 | struct snapshot_data *data; |
173 | unsigned long sleep_flags; |
174 | ssize_t res; |
175 | |
176 | if (need_wait) { |
177 | wait_for_device_probe(); |
178 | need_wait = false; |
179 | } |
180 | |
181 | sleep_flags = lock_system_sleep(); |
182 | |
183 | data = filp->private_data; |
184 | |
185 | if (!pg_offp) { |
186 | res = snapshot_write_next(handle: &data->handle); |
187 | if (res <= 0) |
188 | goto unlock; |
189 | } else { |
190 | res = PAGE_SIZE; |
191 | } |
192 | |
193 | if (!data_of(data->handle)) { |
194 | res = -EINVAL; |
195 | goto unlock; |
196 | } |
197 | |
198 | res = simple_write_to_buffer(data_of(data->handle), available: res, ppos: &pg_offp, |
199 | from: buf, count); |
200 | if (res > 0) |
201 | *offp += res; |
202 | unlock: |
203 | unlock_system_sleep(sleep_flags); |
204 | |
205 | return res; |
206 | } |
207 | |
208 | struct compat_resume_swap_area { |
209 | compat_loff_t offset; |
210 | u32 dev; |
211 | } __packed; |
212 | |
213 | static int snapshot_set_swap_area(struct snapshot_data *data, |
214 | void __user *argp) |
215 | { |
216 | sector_t offset; |
217 | dev_t swdev; |
218 | |
219 | if (swsusp_swap_in_use()) |
220 | return -EPERM; |
221 | |
222 | if (in_compat_syscall()) { |
223 | struct compat_resume_swap_area swap_area; |
224 | |
225 | if (copy_from_user(to: &swap_area, from: argp, n: sizeof(swap_area))) |
226 | return -EFAULT; |
227 | swdev = new_decode_dev(dev: swap_area.dev); |
228 | offset = swap_area.offset; |
229 | } else { |
230 | struct resume_swap_area swap_area; |
231 | |
232 | if (copy_from_user(to: &swap_area, from: argp, n: sizeof(swap_area))) |
233 | return -EFAULT; |
234 | swdev = new_decode_dev(dev: swap_area.dev); |
235 | offset = swap_area.offset; |
236 | } |
237 | |
238 | /* |
239 | * User space encodes device types as two-byte values, |
240 | * so we need to recode them |
241 | */ |
242 | data->swap = swap_type_of(device: swdev, offset); |
243 | if (data->swap < 0) |
244 | return swdev ? -ENODEV : -EINVAL; |
245 | data->dev = swdev; |
246 | return 0; |
247 | } |
248 | |
249 | static long snapshot_ioctl(struct file *filp, unsigned int cmd, |
250 | unsigned long arg) |
251 | { |
252 | int error = 0; |
253 | struct snapshot_data *data; |
254 | loff_t size; |
255 | sector_t offset; |
256 | |
257 | if (need_wait) { |
258 | wait_for_device_probe(); |
259 | need_wait = false; |
260 | } |
261 | |
262 | if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC) |
263 | return -ENOTTY; |
264 | if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR) |
265 | return -ENOTTY; |
266 | if (!capable(CAP_SYS_ADMIN)) |
267 | return -EPERM; |
268 | |
269 | if (!mutex_trylock(lock: &system_transition_mutex)) |
270 | return -EBUSY; |
271 | |
272 | lock_device_hotplug(); |
273 | data = filp->private_data; |
274 | |
275 | switch (cmd) { |
276 | |
277 | case SNAPSHOT_FREEZE: |
278 | if (data->frozen) |
279 | break; |
280 | |
281 | ksys_sync_helper(); |
282 | |
283 | error = freeze_processes(); |
284 | if (error) |
285 | break; |
286 | |
287 | error = create_basic_memory_bitmaps(); |
288 | if (error) |
289 | thaw_processes(); |
290 | else |
291 | data->frozen = true; |
292 | |
293 | break; |
294 | |
295 | case SNAPSHOT_UNFREEZE: |
296 | if (!data->frozen || data->ready) |
297 | break; |
298 | pm_restore_gfp_mask(); |
299 | free_basic_memory_bitmaps(); |
300 | data->free_bitmaps = false; |
301 | thaw_processes(); |
302 | data->frozen = false; |
303 | break; |
304 | |
305 | case SNAPSHOT_CREATE_IMAGE: |
306 | if (data->mode != O_RDONLY || !data->frozen || data->ready) { |
307 | error = -EPERM; |
308 | break; |
309 | } |
310 | pm_restore_gfp_mask(); |
311 | error = hibernation_snapshot(platform_mode: data->platform_support); |
312 | if (!error) { |
313 | error = put_user(in_suspend, (int __user *)arg); |
314 | data->ready = !freezer_test_done && !error; |
315 | freezer_test_done = false; |
316 | } |
317 | break; |
318 | |
319 | case SNAPSHOT_ATOMIC_RESTORE: |
320 | error = snapshot_write_finalize(handle: &data->handle); |
321 | if (error) |
322 | break; |
323 | if (data->mode != O_WRONLY || !data->frozen || |
324 | !snapshot_image_loaded(handle: &data->handle)) { |
325 | error = -EPERM; |
326 | break; |
327 | } |
328 | error = hibernation_restore(platform_mode: data->platform_support); |
329 | break; |
330 | |
331 | case SNAPSHOT_FREE: |
332 | swsusp_free(); |
333 | memset(&data->handle, 0, sizeof(struct snapshot_handle)); |
334 | data->ready = false; |
335 | /* |
336 | * It is necessary to thaw kernel threads here, because |
337 | * SNAPSHOT_CREATE_IMAGE may be invoked directly after |
338 | * SNAPSHOT_FREE. In that case, if kernel threads were not |
339 | * thawed, the preallocation of memory carried out by |
340 | * hibernation_snapshot() might run into problems (i.e. it |
341 | * might fail or even deadlock). |
342 | */ |
343 | thaw_kernel_threads(); |
344 | break; |
345 | |
346 | case SNAPSHOT_PREF_IMAGE_SIZE: |
347 | image_size = arg; |
348 | break; |
349 | |
350 | case SNAPSHOT_GET_IMAGE_SIZE: |
351 | if (!data->ready) { |
352 | error = -ENODATA; |
353 | break; |
354 | } |
355 | size = snapshot_get_image_size(); |
356 | size <<= PAGE_SHIFT; |
357 | error = put_user(size, (loff_t __user *)arg); |
358 | break; |
359 | |
360 | case SNAPSHOT_AVAIL_SWAP_SIZE: |
361 | size = count_swap_pages(data->swap, 1); |
362 | size <<= PAGE_SHIFT; |
363 | error = put_user(size, (loff_t __user *)arg); |
364 | break; |
365 | |
366 | case SNAPSHOT_ALLOC_SWAP_PAGE: |
367 | if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { |
368 | error = -ENODEV; |
369 | break; |
370 | } |
371 | offset = alloc_swapdev_block(swap: data->swap); |
372 | if (offset) { |
373 | offset <<= PAGE_SHIFT; |
374 | error = put_user(offset, (loff_t __user *)arg); |
375 | } else { |
376 | error = -ENOSPC; |
377 | } |
378 | break; |
379 | |
380 | case SNAPSHOT_FREE_SWAP_PAGES: |
381 | if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { |
382 | error = -ENODEV; |
383 | break; |
384 | } |
385 | free_all_swap_pages(swap: data->swap); |
386 | break; |
387 | |
388 | case SNAPSHOT_S2RAM: |
389 | if (!data->frozen) { |
390 | error = -EPERM; |
391 | break; |
392 | } |
393 | /* |
394 | * Tasks are frozen and the notifiers have been called with |
395 | * PM_HIBERNATION_PREPARE |
396 | */ |
397 | error = suspend_devices_and_enter(PM_SUSPEND_MEM); |
398 | data->ready = false; |
399 | break; |
400 | |
401 | case SNAPSHOT_PLATFORM_SUPPORT: |
402 | data->platform_support = !!arg; |
403 | break; |
404 | |
405 | case SNAPSHOT_POWER_OFF: |
406 | if (data->platform_support) |
407 | error = hibernation_platform_enter(); |
408 | break; |
409 | |
410 | case SNAPSHOT_SET_SWAP_AREA: |
411 | error = snapshot_set_swap_area(data, argp: (void __user *)arg); |
412 | break; |
413 | |
414 | default: |
415 | error = -ENOTTY; |
416 | |
417 | } |
418 | |
419 | unlock_device_hotplug(); |
420 | mutex_unlock(lock: &system_transition_mutex); |
421 | |
422 | return error; |
423 | } |
424 | |
425 | #ifdef CONFIG_COMPAT |
426 | static long |
427 | snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
428 | { |
429 | BUILD_BUG_ON(sizeof(loff_t) != sizeof(compat_loff_t)); |
430 | |
431 | switch (cmd) { |
432 | case SNAPSHOT_GET_IMAGE_SIZE: |
433 | case SNAPSHOT_AVAIL_SWAP_SIZE: |
434 | case SNAPSHOT_ALLOC_SWAP_PAGE: |
435 | case SNAPSHOT_CREATE_IMAGE: |
436 | case SNAPSHOT_SET_SWAP_AREA: |
437 | return snapshot_ioctl(filp: file, cmd, |
438 | arg: (unsigned long) compat_ptr(uptr: arg)); |
439 | default: |
440 | return snapshot_ioctl(filp: file, cmd, arg); |
441 | } |
442 | } |
443 | #endif /* CONFIG_COMPAT */ |
444 | |
445 | static const struct file_operations snapshot_fops = { |
446 | .open = snapshot_open, |
447 | .release = snapshot_release, |
448 | .read = snapshot_read, |
449 | .write = snapshot_write, |
450 | .llseek = no_llseek, |
451 | .unlocked_ioctl = snapshot_ioctl, |
452 | #ifdef CONFIG_COMPAT |
453 | .compat_ioctl = snapshot_compat_ioctl, |
454 | #endif |
455 | }; |
456 | |
457 | static struct miscdevice snapshot_device = { |
458 | .minor = SNAPSHOT_MINOR, |
459 | .name = "snapshot" , |
460 | .fops = &snapshot_fops, |
461 | }; |
462 | |
463 | static int __init snapshot_device_init(void) |
464 | { |
465 | return misc_register(misc: &snapshot_device); |
466 | }; |
467 | |
468 | device_initcall(snapshot_device_init); |
469 | |