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