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 | snapshot_write_finalize(handle: &data->handle); |
321 | if (data->mode != O_WRONLY || !data->frozen || |
322 | !snapshot_image_loaded(handle: &data->handle)) { |
323 | error = -EPERM; |
324 | break; |
325 | } |
326 | error = hibernation_restore(platform_mode: data->platform_support); |
327 | break; |
328 | |
329 | case SNAPSHOT_FREE: |
330 | swsusp_free(); |
331 | memset(&data->handle, 0, sizeof(struct snapshot_handle)); |
332 | data->ready = false; |
333 | /* |
334 | * It is necessary to thaw kernel threads here, because |
335 | * SNAPSHOT_CREATE_IMAGE may be invoked directly after |
336 | * SNAPSHOT_FREE. In that case, if kernel threads were not |
337 | * thawed, the preallocation of memory carried out by |
338 | * hibernation_snapshot() might run into problems (i.e. it |
339 | * might fail or even deadlock). |
340 | */ |
341 | thaw_kernel_threads(); |
342 | break; |
343 | |
344 | case SNAPSHOT_PREF_IMAGE_SIZE: |
345 | image_size = arg; |
346 | break; |
347 | |
348 | case SNAPSHOT_GET_IMAGE_SIZE: |
349 | if (!data->ready) { |
350 | error = -ENODATA; |
351 | break; |
352 | } |
353 | size = snapshot_get_image_size(); |
354 | size <<= PAGE_SHIFT; |
355 | error = put_user(size, (loff_t __user *)arg); |
356 | break; |
357 | |
358 | case SNAPSHOT_AVAIL_SWAP_SIZE: |
359 | size = count_swap_pages(data->swap, 1); |
360 | size <<= PAGE_SHIFT; |
361 | error = put_user(size, (loff_t __user *)arg); |
362 | break; |
363 | |
364 | case SNAPSHOT_ALLOC_SWAP_PAGE: |
365 | if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { |
366 | error = -ENODEV; |
367 | break; |
368 | } |
369 | offset = alloc_swapdev_block(swap: data->swap); |
370 | if (offset) { |
371 | offset <<= PAGE_SHIFT; |
372 | error = put_user(offset, (loff_t __user *)arg); |
373 | } else { |
374 | error = -ENOSPC; |
375 | } |
376 | break; |
377 | |
378 | case SNAPSHOT_FREE_SWAP_PAGES: |
379 | if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { |
380 | error = -ENODEV; |
381 | break; |
382 | } |
383 | free_all_swap_pages(swap: data->swap); |
384 | break; |
385 | |
386 | case SNAPSHOT_S2RAM: |
387 | if (!data->frozen) { |
388 | error = -EPERM; |
389 | break; |
390 | } |
391 | /* |
392 | * Tasks are frozen and the notifiers have been called with |
393 | * PM_HIBERNATION_PREPARE |
394 | */ |
395 | error = suspend_devices_and_enter(PM_SUSPEND_MEM); |
396 | data->ready = false; |
397 | break; |
398 | |
399 | case SNAPSHOT_PLATFORM_SUPPORT: |
400 | data->platform_support = !!arg; |
401 | break; |
402 | |
403 | case SNAPSHOT_POWER_OFF: |
404 | if (data->platform_support) |
405 | error = hibernation_platform_enter(); |
406 | break; |
407 | |
408 | case SNAPSHOT_SET_SWAP_AREA: |
409 | error = snapshot_set_swap_area(data, argp: (void __user *)arg); |
410 | break; |
411 | |
412 | default: |
413 | error = -ENOTTY; |
414 | |
415 | } |
416 | |
417 | unlock_device_hotplug(); |
418 | mutex_unlock(lock: &system_transition_mutex); |
419 | |
420 | return error; |
421 | } |
422 | |
423 | #ifdef CONFIG_COMPAT |
424 | static long |
425 | snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
426 | { |
427 | BUILD_BUG_ON(sizeof(loff_t) != sizeof(compat_loff_t)); |
428 | |
429 | switch (cmd) { |
430 | case SNAPSHOT_GET_IMAGE_SIZE: |
431 | case SNAPSHOT_AVAIL_SWAP_SIZE: |
432 | case SNAPSHOT_ALLOC_SWAP_PAGE: |
433 | case SNAPSHOT_CREATE_IMAGE: |
434 | case SNAPSHOT_SET_SWAP_AREA: |
435 | return snapshot_ioctl(filp: file, cmd, |
436 | arg: (unsigned long) compat_ptr(uptr: arg)); |
437 | default: |
438 | return snapshot_ioctl(filp: file, cmd, arg); |
439 | } |
440 | } |
441 | #endif /* CONFIG_COMPAT */ |
442 | |
443 | static const struct file_operations snapshot_fops = { |
444 | .open = snapshot_open, |
445 | .release = snapshot_release, |
446 | .read = snapshot_read, |
447 | .write = snapshot_write, |
448 | .llseek = no_llseek, |
449 | .unlocked_ioctl = snapshot_ioctl, |
450 | #ifdef CONFIG_COMPAT |
451 | .compat_ioctl = snapshot_compat_ioctl, |
452 | #endif |
453 | }; |
454 | |
455 | static struct miscdevice snapshot_device = { |
456 | .minor = SNAPSHOT_MINOR, |
457 | .name = "snapshot" , |
458 | .fops = &snapshot_fops, |
459 | }; |
460 | |
461 | static int __init snapshot_device_init(void) |
462 | { |
463 | return misc_register(misc: &snapshot_device); |
464 | }; |
465 | |
466 | device_initcall(snapshot_device_init); |
467 | |