• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/kernel/power/
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 <scsi/scsi_scan.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
57static 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
66atomic_t snapshot_device_available = ATOMIC_INIT(1);
67
68static 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		/* Hibernating.  The image device should be accessible. */
96		data->swap = swsusp_resume_device ?
97			swap_type_of(swsusp_resume_device, 0, NULL) : -1;
98		data->mode = O_RDONLY;
99		error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
100		if (error)
101			pm_notifier_call_chain(PM_POST_HIBERNATION);
102	} else {
103		/*
104		 * Resuming.  We may need to wait for the image device to
105		 * appear.
106		 */
107		wait_for_device_probe();
108		scsi_complete_async_scans();
109
110		data->swap = -1;
111		data->mode = O_WRONLY;
112		error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
113		if (error)
114			pm_notifier_call_chain(PM_POST_RESTORE);
115	}
116	if (error)
117		atomic_inc(&snapshot_device_available);
118	data->frozen = 0;
119	data->ready = 0;
120	data->platform_support = 0;
121
122 Unlock:
123	mutex_unlock(&pm_mutex);
124
125	return error;
126}
127
128static int snapshot_release(struct inode *inode, struct file *filp)
129{
130	struct snapshot_data *data;
131
132	mutex_lock(&pm_mutex);
133
134	swsusp_free();
135	free_basic_memory_bitmaps();
136	data = filp->private_data;
137	free_all_swap_pages(data->swap);
138	if (data->frozen)
139		thaw_processes();
140	pm_notifier_call_chain(data->mode == O_RDONLY ?
141			PM_POST_HIBERNATION : PM_POST_RESTORE);
142	atomic_inc(&snapshot_device_available);
143
144	mutex_unlock(&pm_mutex);
145
146	return 0;
147}
148
149static ssize_t snapshot_read(struct file *filp, char __user *buf,
150                             size_t count, loff_t *offp)
151{
152	struct snapshot_data *data;
153	ssize_t res;
154	loff_t pg_offp = *offp & ~PAGE_MASK;
155
156	mutex_lock(&pm_mutex);
157
158	data = filp->private_data;
159	if (!data->ready) {
160		res = -ENODATA;
161		goto Unlock;
162	}
163	if (!pg_offp) { /* on page boundary? */
164		res = snapshot_read_next(&data->handle);
165		if (res <= 0)
166			goto Unlock;
167	} else {
168		res = PAGE_SIZE - pg_offp;
169	}
170
171	res = simple_read_from_buffer(buf, count, &pg_offp,
172			data_of(data->handle), res);
173	if (res > 0)
174		*offp += res;
175
176 Unlock:
177	mutex_unlock(&pm_mutex);
178
179	return res;
180}
181
182static ssize_t snapshot_write(struct file *filp, const char __user *buf,
183                              size_t count, loff_t *offp)
184{
185	struct snapshot_data *data;
186	ssize_t res;
187	loff_t pg_offp = *offp & ~PAGE_MASK;
188
189	mutex_lock(&pm_mutex);
190
191	data = filp->private_data;
192
193	if (!pg_offp) {
194		res = snapshot_write_next(&data->handle);
195		if (res <= 0)
196			goto unlock;
197	} else {
198		res = PAGE_SIZE - pg_offp;
199	}
200
201	res = simple_write_to_buffer(data_of(data->handle), res, &pg_offp,
202			buf, count);
203	if (res > 0)
204		*offp += res;
205unlock:
206	mutex_unlock(&pm_mutex);
207
208	return res;
209}
210
211static void snapshot_deprecated_ioctl(unsigned int cmd)
212{
213	if (printk_ratelimit())
214		printk(KERN_NOTICE "%pf: ioctl '%.8x' is deprecated and will "
215				"be removed soon, update your suspend-to-disk "
216				"utilities\n",
217				__builtin_return_address(0), cmd);
218}
219
220static long snapshot_ioctl(struct file *filp, unsigned int cmd,
221							unsigned long arg)
222{
223	int error = 0;
224	struct snapshot_data *data;
225	loff_t size;
226	sector_t offset;
227
228	if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
229		return -ENOTTY;
230	if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
231		return -ENOTTY;
232	if (!capable(CAP_SYS_ADMIN))
233		return -EPERM;
234
235	if (!mutex_trylock(&pm_mutex))
236		return -EBUSY;
237
238	data = filp->private_data;
239
240	switch (cmd) {
241
242	case SNAPSHOT_FREEZE:
243		if (data->frozen)
244			break;
245
246		printk("Syncing filesystems ... ");
247		sys_sync();
248		printk("done.\n");
249
250		error = usermodehelper_disable();
251		if (error)
252			break;
253
254		error = freeze_processes();
255		if (error) {
256			thaw_processes();
257			usermodehelper_enable();
258		}
259		if (!error)
260			data->frozen = 1;
261		break;
262
263	case SNAPSHOT_UNFREEZE:
264		if (!data->frozen || data->ready)
265			break;
266		pm_restore_gfp_mask();
267		thaw_processes();
268		usermodehelper_enable();
269		data->frozen = 0;
270		break;
271
272	case SNAPSHOT_ATOMIC_SNAPSHOT:
273		snapshot_deprecated_ioctl(cmd);
274	case SNAPSHOT_CREATE_IMAGE:
275		if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
276			error = -EPERM;
277			break;
278		}
279		pm_restore_gfp_mask();
280		error = hibernation_snapshot(data->platform_support);
281		if (!error)
282			error = put_user(in_suspend, (int __user *)arg);
283		if (!error)
284			data->ready = 1;
285		break;
286
287	case SNAPSHOT_ATOMIC_RESTORE:
288		snapshot_write_finalize(&data->handle);
289		if (data->mode != O_WRONLY || !data->frozen ||
290		    !snapshot_image_loaded(&data->handle)) {
291			error = -EPERM;
292			break;
293		}
294		error = hibernation_restore(data->platform_support);
295		break;
296
297	case SNAPSHOT_FREE:
298		swsusp_free();
299		memset(&data->handle, 0, sizeof(struct snapshot_handle));
300		data->ready = 0;
301		break;
302
303	case SNAPSHOT_SET_IMAGE_SIZE:
304		snapshot_deprecated_ioctl(cmd);
305	case SNAPSHOT_PREF_IMAGE_SIZE:
306		image_size = arg;
307		break;
308
309	case SNAPSHOT_GET_IMAGE_SIZE:
310		if (!data->ready) {
311			error = -ENODATA;
312			break;
313		}
314		size = snapshot_get_image_size();
315		size <<= PAGE_SHIFT;
316		error = put_user(size, (loff_t __user *)arg);
317		break;
318
319	case SNAPSHOT_AVAIL_SWAP:
320		snapshot_deprecated_ioctl(cmd);
321	case SNAPSHOT_AVAIL_SWAP_SIZE:
322		size = count_swap_pages(data->swap, 1);
323		size <<= PAGE_SHIFT;
324		error = put_user(size, (loff_t __user *)arg);
325		break;
326
327	case SNAPSHOT_GET_SWAP_PAGE:
328		snapshot_deprecated_ioctl(cmd);
329	case SNAPSHOT_ALLOC_SWAP_PAGE:
330		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
331			error = -ENODEV;
332			break;
333		}
334		offset = alloc_swapdev_block(data->swap);
335		if (offset) {
336			offset <<= PAGE_SHIFT;
337			error = put_user(offset, (loff_t __user *)arg);
338		} else {
339			error = -ENOSPC;
340		}
341		break;
342
343	case SNAPSHOT_FREE_SWAP_PAGES:
344		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
345			error = -ENODEV;
346			break;
347		}
348		free_all_swap_pages(data->swap);
349		break;
350
351	case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */
352		snapshot_deprecated_ioctl(cmd);
353		if (!swsusp_swap_in_use()) {
354			/*
355			 * User space encodes device types as two-byte values,
356			 * so we need to recode them
357			 */
358			if (old_decode_dev(arg)) {
359				data->swap = swap_type_of(old_decode_dev(arg),
360							0, NULL);
361				if (data->swap < 0)
362					error = -ENODEV;
363			} else {
364				data->swap = -1;
365				error = -EINVAL;
366			}
367		} else {
368			error = -EPERM;
369		}
370		break;
371
372	case SNAPSHOT_S2RAM:
373		if (!data->frozen) {
374			error = -EPERM;
375			break;
376		}
377		/*
378		 * Tasks are frozen and the notifiers have been called with
379		 * PM_HIBERNATION_PREPARE
380		 */
381		error = suspend_devices_and_enter(PM_SUSPEND_MEM);
382		break;
383
384	case SNAPSHOT_PLATFORM_SUPPORT:
385		data->platform_support = !!arg;
386		break;
387
388	case SNAPSHOT_POWER_OFF:
389		if (data->platform_support)
390			error = hibernation_platform_enter();
391		break;
392
393	case SNAPSHOT_PMOPS: /* This ioctl is deprecated */
394		snapshot_deprecated_ioctl(cmd);
395		error = -EINVAL;
396
397		switch (arg) {
398
399		case PMOPS_PREPARE:
400			data->platform_support = 1;
401			error = 0;
402			break;
403
404		case PMOPS_ENTER:
405			if (data->platform_support)
406				error = hibernation_platform_enter();
407			break;
408
409		case PMOPS_FINISH:
410			if (data->platform_support)
411				error = 0;
412			break;
413
414		default:
415			printk(KERN_ERR "SNAPSHOT_PMOPS: invalid argument %ld\n", arg);
416
417		}
418		break;
419
420	case SNAPSHOT_SET_SWAP_AREA:
421		if (swsusp_swap_in_use()) {
422			error = -EPERM;
423		} else {
424			struct resume_swap_area swap_area;
425			dev_t swdev;
426
427			error = copy_from_user(&swap_area, (void __user *)arg,
428					sizeof(struct resume_swap_area));
429			if (error) {
430				error = -EFAULT;
431				break;
432			}
433
434			/*
435			 * User space encodes device types as two-byte values,
436			 * so we need to recode them
437			 */
438			swdev = new_decode_dev(swap_area.dev);
439			if (swdev) {
440				offset = swap_area.offset;
441				data->swap = swap_type_of(swdev, offset, NULL);
442				if (data->swap < 0)
443					error = -ENODEV;
444			} else {
445				data->swap = -1;
446				error = -EINVAL;
447			}
448		}
449		break;
450
451	default:
452		error = -ENOTTY;
453
454	}
455
456	mutex_unlock(&pm_mutex);
457
458	return error;
459}
460
461static const struct file_operations snapshot_fops = {
462	.open = snapshot_open,
463	.release = snapshot_release,
464	.read = snapshot_read,
465	.write = snapshot_write,
466	.llseek = no_llseek,
467	.unlocked_ioctl = snapshot_ioctl,
468};
469
470static struct miscdevice snapshot_device = {
471	.minor = SNAPSHOT_MINOR,
472	.name = "snapshot",
473	.fops = &snapshot_fops,
474};
475
476static int __init snapshot_device_init(void)
477{
478	return misc_register(&snapshot_device);
479};
480
481device_initcall(snapshot_device_init);
482