xref: /openbmc/linux/kernel/power/user.c (revision 643d1f7f)
1 /*
2  * linux/kernel/power/user.c
3  *
4  * This file provides the user space interface for software suspend/resume.
5  *
6  * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
7  *
8  * This file is released under the GPLv2.
9  *
10  */
11 
12 #include <linux/suspend.h>
13 #include <linux/syscalls.h>
14 #include <linux/reboot.h>
15 #include <linux/string.h>
16 #include <linux/device.h>
17 #include <linux/miscdevice.h>
18 #include <linux/mm.h>
19 #include <linux/swap.h>
20 #include <linux/swapops.h>
21 #include <linux/pm.h>
22 #include <linux/fs.h>
23 #include <linux/console.h>
24 #include <linux/cpu.h>
25 #include <linux/freezer.h>
26 
27 #include <asm/uaccess.h>
28 
29 #include "power.h"
30 
31 /*
32  * NOTE: The SNAPSHOT_SET_SWAP_FILE and SNAPSHOT_PMOPS ioctls are obsolete and
33  * will be removed in the future.  They are only preserved here for
34  * compatibility with existing userland utilities.
35  */
36 #define SNAPSHOT_SET_SWAP_FILE	_IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int)
37 #define SNAPSHOT_PMOPS		_IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int)
38 
39 #define PMOPS_PREPARE	1
40 #define PMOPS_ENTER	2
41 #define PMOPS_FINISH	3
42 
43 /*
44  * NOTE: The following ioctl definitions are wrong and have been replaced with
45  * correct ones.  They are only preserved here for compatibility with existing
46  * userland utilities and will be removed in the future.
47  */
48 #define SNAPSHOT_ATOMIC_SNAPSHOT	_IOW(SNAPSHOT_IOC_MAGIC, 3, void *)
49 #define SNAPSHOT_SET_IMAGE_SIZE		_IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long)
50 #define SNAPSHOT_AVAIL_SWAP		_IOR(SNAPSHOT_IOC_MAGIC, 7, void *)
51 #define SNAPSHOT_GET_SWAP_PAGE		_IOR(SNAPSHOT_IOC_MAGIC, 8, void *)
52 
53 
54 #define SNAPSHOT_MINOR	231
55 
56 static struct snapshot_data {
57 	struct snapshot_handle handle;
58 	int swap;
59 	int mode;
60 	char frozen;
61 	char ready;
62 	char platform_support;
63 } snapshot_state;
64 
65 atomic_t snapshot_device_available = ATOMIC_INIT(1);
66 
67 static int snapshot_open(struct inode *inode, struct file *filp)
68 {
69 	struct snapshot_data *data;
70 	int error;
71 
72 	if (!atomic_add_unless(&snapshot_device_available, -1, 0))
73 		return -EBUSY;
74 
75 	if ((filp->f_flags & O_ACCMODE) == O_RDWR) {
76 		atomic_inc(&snapshot_device_available);
77 		return -ENOSYS;
78 	}
79 	if(create_basic_memory_bitmaps()) {
80 		atomic_inc(&snapshot_device_available);
81 		return -ENOMEM;
82 	}
83 	nonseekable_open(inode, filp);
84 	data = &snapshot_state;
85 	filp->private_data = data;
86 	memset(&data->handle, 0, sizeof(struct snapshot_handle));
87 	if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
88 		data->swap = swsusp_resume_device ?
89 			swap_type_of(swsusp_resume_device, 0, NULL) : -1;
90 		data->mode = O_RDONLY;
91 		error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
92 		if (error)
93 			pm_notifier_call_chain(PM_POST_RESTORE);
94 	} else {
95 		data->swap = -1;
96 		data->mode = O_WRONLY;
97 		error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
98 		if (error)
99 			pm_notifier_call_chain(PM_POST_HIBERNATION);
100 	}
101 	if (error) {
102 		atomic_inc(&snapshot_device_available);
103 		return error;
104 	}
105 	data->frozen = 0;
106 	data->ready = 0;
107 	data->platform_support = 0;
108 
109 	return 0;
110 }
111 
112 static int snapshot_release(struct inode *inode, struct file *filp)
113 {
114 	struct snapshot_data *data;
115 
116 	swsusp_free();
117 	free_basic_memory_bitmaps();
118 	data = filp->private_data;
119 	free_all_swap_pages(data->swap);
120 	if (data->frozen) {
121 		mutex_lock(&pm_mutex);
122 		thaw_processes();
123 		mutex_unlock(&pm_mutex);
124 	}
125 	pm_notifier_call_chain(data->mode == O_WRONLY ?
126 			PM_POST_HIBERNATION : PM_POST_RESTORE);
127 	atomic_inc(&snapshot_device_available);
128 	return 0;
129 }
130 
131 static ssize_t snapshot_read(struct file *filp, char __user *buf,
132                              size_t count, loff_t *offp)
133 {
134 	struct snapshot_data *data;
135 	ssize_t res;
136 
137 	data = filp->private_data;
138 	if (!data->ready)
139 		return -ENODATA;
140 	res = snapshot_read_next(&data->handle, count);
141 	if (res > 0) {
142 		if (copy_to_user(buf, data_of(data->handle), res))
143 			res = -EFAULT;
144 		else
145 			*offp = data->handle.offset;
146 	}
147 	return res;
148 }
149 
150 static ssize_t snapshot_write(struct file *filp, const char __user *buf,
151                               size_t count, loff_t *offp)
152 {
153 	struct snapshot_data *data;
154 	ssize_t res;
155 
156 	data = filp->private_data;
157 	res = snapshot_write_next(&data->handle, count);
158 	if (res > 0) {
159 		if (copy_from_user(data_of(data->handle), buf, res))
160 			res = -EFAULT;
161 		else
162 			*offp = data->handle.offset;
163 	}
164 	return res;
165 }
166 
167 static int snapshot_ioctl(struct inode *inode, struct file *filp,
168                           unsigned int cmd, unsigned long arg)
169 {
170 	int error = 0;
171 	struct snapshot_data *data;
172 	loff_t size;
173 	sector_t offset;
174 
175 	if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
176 		return -ENOTTY;
177 	if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
178 		return -ENOTTY;
179 	if (!capable(CAP_SYS_ADMIN))
180 		return -EPERM;
181 
182 	data = filp->private_data;
183 
184 	switch (cmd) {
185 
186 	case SNAPSHOT_FREEZE:
187 		if (data->frozen)
188 			break;
189 		mutex_lock(&pm_mutex);
190 		printk("Syncing filesystems ... ");
191 		sys_sync();
192 		printk("done.\n");
193 
194 		error = freeze_processes();
195 		if (error)
196 			thaw_processes();
197 		mutex_unlock(&pm_mutex);
198 		if (!error)
199 			data->frozen = 1;
200 		break;
201 
202 	case SNAPSHOT_UNFREEZE:
203 		if (!data->frozen || data->ready)
204 			break;
205 		mutex_lock(&pm_mutex);
206 		thaw_processes();
207 		mutex_unlock(&pm_mutex);
208 		data->frozen = 0;
209 		break;
210 
211 	case SNAPSHOT_CREATE_IMAGE:
212 	case SNAPSHOT_ATOMIC_SNAPSHOT:
213 		if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
214 			error = -EPERM;
215 			break;
216 		}
217 		error = hibernation_snapshot(data->platform_support);
218 		if (!error)
219 			error = put_user(in_suspend, (int __user *)arg);
220 		if (!error)
221 			data->ready = 1;
222 		break;
223 
224 	case SNAPSHOT_ATOMIC_RESTORE:
225 		snapshot_write_finalize(&data->handle);
226 		if (data->mode != O_WRONLY || !data->frozen ||
227 		    !snapshot_image_loaded(&data->handle)) {
228 			error = -EPERM;
229 			break;
230 		}
231 		error = hibernation_restore(data->platform_support);
232 		break;
233 
234 	case SNAPSHOT_FREE:
235 		swsusp_free();
236 		memset(&data->handle, 0, sizeof(struct snapshot_handle));
237 		data->ready = 0;
238 		break;
239 
240 	case SNAPSHOT_PREF_IMAGE_SIZE:
241 	case SNAPSHOT_SET_IMAGE_SIZE:
242 		image_size = arg;
243 		break;
244 
245 	case SNAPSHOT_GET_IMAGE_SIZE:
246 		if (!data->ready) {
247 			error = -ENODATA;
248 			break;
249 		}
250 		size = snapshot_get_image_size();
251 		size <<= PAGE_SHIFT;
252 		error = put_user(size, (loff_t __user *)arg);
253 		break;
254 
255 	case SNAPSHOT_AVAIL_SWAP_SIZE:
256 	case SNAPSHOT_AVAIL_SWAP:
257 		size = count_swap_pages(data->swap, 1);
258 		size <<= PAGE_SHIFT;
259 		error = put_user(size, (loff_t __user *)arg);
260 		break;
261 
262 	case SNAPSHOT_ALLOC_SWAP_PAGE:
263 	case SNAPSHOT_GET_SWAP_PAGE:
264 		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
265 			error = -ENODEV;
266 			break;
267 		}
268 		offset = alloc_swapdev_block(data->swap);
269 		if (offset) {
270 			offset <<= PAGE_SHIFT;
271 			error = put_user(offset, (loff_t __user *)arg);
272 		} else {
273 			error = -ENOSPC;
274 		}
275 		break;
276 
277 	case SNAPSHOT_FREE_SWAP_PAGES:
278 		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
279 			error = -ENODEV;
280 			break;
281 		}
282 		free_all_swap_pages(data->swap);
283 		break;
284 
285 	case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */
286 		if (!swsusp_swap_in_use()) {
287 			/*
288 			 * User space encodes device types as two-byte values,
289 			 * so we need to recode them
290 			 */
291 			if (old_decode_dev(arg)) {
292 				data->swap = swap_type_of(old_decode_dev(arg),
293 							0, NULL);
294 				if (data->swap < 0)
295 					error = -ENODEV;
296 			} else {
297 				data->swap = -1;
298 				error = -EINVAL;
299 			}
300 		} else {
301 			error = -EPERM;
302 		}
303 		break;
304 
305 	case SNAPSHOT_S2RAM:
306 		if (!data->frozen) {
307 			error = -EPERM;
308 			break;
309 		}
310 		if (!mutex_trylock(&pm_mutex)) {
311 			error = -EBUSY;
312 			break;
313 		}
314 		/*
315 		 * Tasks are frozen and the notifiers have been called with
316 		 * PM_HIBERNATION_PREPARE
317 		 */
318 		error = suspend_devices_and_enter(PM_SUSPEND_MEM);
319 		mutex_unlock(&pm_mutex);
320 		break;
321 
322 	case SNAPSHOT_PLATFORM_SUPPORT:
323 		data->platform_support = !!arg;
324 		break;
325 
326 	case SNAPSHOT_POWER_OFF:
327 		if (data->platform_support)
328 			error = hibernation_platform_enter();
329 		break;
330 
331 	case SNAPSHOT_PMOPS: /* This ioctl is deprecated */
332 		error = -EINVAL;
333 
334 		switch (arg) {
335 
336 		case PMOPS_PREPARE:
337 			data->platform_support = 1;
338 			error = 0;
339 			break;
340 
341 		case PMOPS_ENTER:
342 			if (data->platform_support)
343 				error = hibernation_platform_enter();
344 			break;
345 
346 		case PMOPS_FINISH:
347 			if (data->platform_support)
348 				error = 0;
349 			break;
350 
351 		default:
352 			printk(KERN_ERR "SNAPSHOT_PMOPS: invalid argument %ld\n", arg);
353 
354 		}
355 		break;
356 
357 	case SNAPSHOT_SET_SWAP_AREA:
358 		if (swsusp_swap_in_use()) {
359 			error = -EPERM;
360 		} else {
361 			struct resume_swap_area swap_area;
362 			dev_t swdev;
363 
364 			error = copy_from_user(&swap_area, (void __user *)arg,
365 					sizeof(struct resume_swap_area));
366 			if (error) {
367 				error = -EFAULT;
368 				break;
369 			}
370 
371 			/*
372 			 * User space encodes device types as two-byte values,
373 			 * so we need to recode them
374 			 */
375 			swdev = old_decode_dev(swap_area.dev);
376 			if (swdev) {
377 				offset = swap_area.offset;
378 				data->swap = swap_type_of(swdev, offset, NULL);
379 				if (data->swap < 0)
380 					error = -ENODEV;
381 			} else {
382 				data->swap = -1;
383 				error = -EINVAL;
384 			}
385 		}
386 		break;
387 
388 	default:
389 		error = -ENOTTY;
390 
391 	}
392 
393 	return error;
394 }
395 
396 static const struct file_operations snapshot_fops = {
397 	.open = snapshot_open,
398 	.release = snapshot_release,
399 	.read = snapshot_read,
400 	.write = snapshot_write,
401 	.llseek = no_llseek,
402 	.ioctl = snapshot_ioctl,
403 };
404 
405 static struct miscdevice snapshot_device = {
406 	.minor = SNAPSHOT_MINOR,
407 	.name = "snapshot",
408 	.fops = &snapshot_fops,
409 };
410 
411 static int __init snapshot_device_init(void)
412 {
413 	return misc_register(&snapshot_device);
414 };
415 
416 device_initcall(snapshot_device_init);
417