- patches.apparmor/remove_suid_new_case_in_2.6.22.diff: Merge fix.
[linux-flexiantxendom0-3.2.10.git] / kernel / power / user.c
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 #define SNAPSHOT_MINOR  231
32
33 static struct snapshot_data {
34         struct snapshot_handle handle;
35         int swap;
36         int mode;
37         char frozen;
38         char ready;
39         char platform_suspend;
40 } snapshot_state;
41
42 atomic_t snapshot_device_available = ATOMIC_INIT(1);
43
44 static int snapshot_open(struct inode *inode, struct file *filp)
45 {
46         struct snapshot_data *data;
47
48         if (!atomic_add_unless(&snapshot_device_available, -1, 0))
49                 return -EBUSY;
50
51         if ((filp->f_flags & O_ACCMODE) == O_RDWR) {
52                 atomic_inc(&snapshot_device_available);
53                 return -ENOSYS;
54         }
55         if(create_basic_memory_bitmaps()) {
56                 atomic_inc(&snapshot_device_available);
57                 return -ENOMEM;
58         }
59         nonseekable_open(inode, filp);
60         data = &snapshot_state;
61         filp->private_data = data;
62         memset(&data->handle, 0, sizeof(struct snapshot_handle));
63         if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
64                 data->swap = swsusp_resume_device ?
65                         swap_type_of(swsusp_resume_device, 0, NULL) : -1;
66                 data->mode = O_RDONLY;
67         } else {
68                 data->swap = -1;
69                 data->mode = O_WRONLY;
70         }
71         data->frozen = 0;
72         data->ready = 0;
73         data->platform_suspend = 0;
74
75         return 0;
76 }
77
78 static int snapshot_release(struct inode *inode, struct file *filp)
79 {
80         struct snapshot_data *data;
81
82         swsusp_free();
83         free_basic_memory_bitmaps();
84         data = filp->private_data;
85         free_all_swap_pages(data->swap);
86         if (data->frozen) {
87                 mutex_lock(&pm_mutex);
88                 thaw_processes();
89                 mutex_unlock(&pm_mutex);
90         }
91         atomic_inc(&snapshot_device_available);
92         return 0;
93 }
94
95 static ssize_t snapshot_read(struct file *filp, char __user *buf,
96                              size_t count, loff_t *offp)
97 {
98         struct snapshot_data *data;
99         ssize_t res;
100
101         data = filp->private_data;
102         res = snapshot_read_next(&data->handle, count);
103         if (res > 0) {
104                 if (copy_to_user(buf, data_of(data->handle), res))
105                         res = -EFAULT;
106                 else
107                         *offp = data->handle.offset;
108         }
109         return res;
110 }
111
112 static ssize_t snapshot_write(struct file *filp, const char __user *buf,
113                               size_t count, loff_t *offp)
114 {
115         struct snapshot_data *data;
116         ssize_t res;
117
118         data = filp->private_data;
119         res = snapshot_write_next(&data->handle, count);
120         if (res > 0) {
121                 if (copy_from_user(data_of(data->handle), buf, res))
122                         res = -EFAULT;
123                 else
124                         *offp = data->handle.offset;
125         }
126         return res;
127 }
128
129 static inline int platform_prepare(void)
130 {
131         int error = 0;
132
133         if (hibernation_ops)
134                 error = hibernation_ops->prepare();
135
136         return error;
137 }
138
139 static inline void platform_finish(void)
140 {
141         if (hibernation_ops)
142                 hibernation_ops->finish();
143 }
144
145 static inline int snapshot_suspend(int platform_suspend)
146 {
147         int error;
148
149         mutex_lock(&pm_mutex);
150         /* Free memory before shutting down devices. */
151         error = swsusp_shrink_memory();
152         if (error)
153                 goto Finish;
154
155         if (platform_suspend) {
156                 error = platform_prepare();
157                 if (error)
158                         goto Finish;
159         }
160         suspend_console();
161         error = device_suspend(PMSG_FREEZE);
162         if (error)
163                 goto Resume_devices;
164
165         error = disable_nonboot_cpus();
166         if (!error) {
167                 in_suspend = 1;
168                 error = swsusp_suspend();
169         }
170         enable_nonboot_cpus();
171  Resume_devices:
172         if (platform_suspend)
173                 platform_finish();
174
175         device_resume();
176         resume_console();
177  Finish:
178         mutex_unlock(&pm_mutex);
179         return error;
180 }
181
182 static inline int snapshot_restore(int platform_suspend)
183 {
184         int error;
185
186         mutex_lock(&pm_mutex);
187         pm_prepare_console();
188         if (platform_suspend) {
189                 error = platform_prepare();
190                 if (error)
191                         goto Finish;
192         }
193         suspend_console();
194         error = device_suspend(PMSG_PRETHAW);
195         if (error)
196                 goto Resume_devices;
197
198         error = disable_nonboot_cpus();
199         if (!error)
200                 error = swsusp_resume();
201
202         enable_nonboot_cpus();
203  Resume_devices:
204         if (platform_suspend)
205                 platform_finish();
206
207         device_resume();
208         resume_console();
209  Finish:
210         pm_restore_console();
211         mutex_unlock(&pm_mutex);
212         return error;
213 }
214
215 static int snapshot_ioctl(struct inode *inode, struct file *filp,
216                           unsigned int cmd, unsigned long arg)
217 {
218         int error = 0;
219         struct snapshot_data *data;
220         loff_t avail;
221         sector_t offset;
222
223         if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
224                 return -ENOTTY;
225         if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
226                 return -ENOTTY;
227         if (!capable(CAP_SYS_ADMIN))
228                 return -EPERM;
229
230         data = filp->private_data;
231
232         switch (cmd) {
233
234         case SNAPSHOT_FREEZE:
235                 if (data->frozen)
236                         break;
237                 mutex_lock(&pm_mutex);
238                 if (freeze_processes()) {
239                         thaw_processes();
240                         error = -EBUSY;
241                 }
242                 mutex_unlock(&pm_mutex);
243                 if (!error)
244                         data->frozen = 1;
245                 break;
246
247         case SNAPSHOT_UNFREEZE:
248                 if (!data->frozen)
249                         break;
250                 mutex_lock(&pm_mutex);
251                 thaw_processes();
252                 mutex_unlock(&pm_mutex);
253                 data->frozen = 0;
254                 break;
255
256         case SNAPSHOT_ATOMIC_SNAPSHOT:
257                 if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
258                         error = -EPERM;
259                         break;
260                 }
261                 error = snapshot_suspend(data->platform_suspend);
262                 if (!error)
263                         error = put_user(in_suspend, (unsigned int __user *)arg);
264                 if (!error)
265                         data->ready = 1;
266                 break;
267
268         case SNAPSHOT_ATOMIC_RESTORE:
269                 snapshot_write_finalize(&data->handle);
270                 if (data->mode != O_WRONLY || !data->frozen ||
271                     !snapshot_image_loaded(&data->handle)) {
272                         error = -EPERM;
273                         break;
274                 }
275                 error = snapshot_restore(data->platform_suspend);
276                 break;
277
278         case SNAPSHOT_FREE:
279                 swsusp_free();
280                 memset(&data->handle, 0, sizeof(struct snapshot_handle));
281                 data->ready = 0;
282                 break;
283
284         case SNAPSHOT_SET_IMAGE_SIZE:
285                 image_size = arg;
286                 break;
287
288         case SNAPSHOT_AVAIL_SWAP:
289                 avail = count_swap_pages(data->swap, 1);
290                 avail <<= PAGE_SHIFT;
291                 error = put_user(avail, (loff_t __user *)arg);
292                 break;
293
294         case SNAPSHOT_GET_SWAP_PAGE:
295                 if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
296                         error = -ENODEV;
297                         break;
298                 }
299                 offset = alloc_swapdev_block(data->swap);
300                 if (offset) {
301                         offset <<= PAGE_SHIFT;
302                         error = put_user(offset, (sector_t __user *)arg);
303                 } else {
304                         error = -ENOSPC;
305                 }
306                 break;
307
308         case SNAPSHOT_FREE_SWAP_PAGES:
309                 if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
310                         error = -ENODEV;
311                         break;
312                 }
313                 free_all_swap_pages(data->swap);
314                 break;
315
316         case SNAPSHOT_SET_SWAP_FILE:
317                 if (!swsusp_swap_in_use()) {
318                         /*
319                          * User space encodes device types as two-byte values,
320                          * so we need to recode them
321                          */
322                         if (old_decode_dev(arg)) {
323                                 data->swap = swap_type_of(old_decode_dev(arg),
324                                                         0, NULL);
325                                 if (data->swap < 0)
326                                         error = -ENODEV;
327                         } else {
328                                 data->swap = -1;
329                                 error = -EINVAL;
330                         }
331                 } else {
332                         error = -EPERM;
333                 }
334                 break;
335
336         case SNAPSHOT_S2RAM:
337                 if (!pm_ops) {
338                         error = -ENOSYS;
339                         break;
340                 }
341
342                 if (!data->frozen) {
343                         error = -EPERM;
344                         break;
345                 }
346
347                 if (!mutex_trylock(&pm_mutex)) {
348                         error = -EBUSY;
349                         break;
350                 }
351
352                 if (pm_ops->prepare) {
353                         error = pm_ops->prepare(PM_SUSPEND_MEM);
354                         if (error)
355                                 goto OutS3;
356                 }
357
358                 /* Put devices to sleep */
359                 suspend_console();
360                 error = device_suspend(PMSG_SUSPEND);
361                 if (error) {
362                         printk(KERN_ERR "Failed to suspend some devices.\n");
363                 } else {
364                         error = disable_nonboot_cpus();
365                         if (!error) {
366                                 /* Enter S3, system is already frozen */
367                                 suspend_enter(PM_SUSPEND_MEM);
368                                 enable_nonboot_cpus();
369                         }
370                         /* Wake up devices */
371                         device_resume();
372                 }
373                 resume_console();
374                 if (pm_ops->finish)
375                         pm_ops->finish(PM_SUSPEND_MEM);
376
377  OutS3:
378                 mutex_unlock(&pm_mutex);
379                 break;
380
381         case SNAPSHOT_PMOPS:
382                 error = -EINVAL;
383
384                 switch (arg) {
385
386                 case PMOPS_PREPARE:
387                         if (hibernation_ops) {
388                                 data->platform_suspend = 1;
389                                 error = 0;
390                         } else {
391                                 error = -ENOSYS;
392                         }
393                         break;
394
395                 case PMOPS_ENTER:
396                         if (data->platform_suspend) {
397                                 kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
398                                 error = hibernation_ops->enter();
399                         }
400                         break;
401
402                 case PMOPS_FINISH:
403                         if (data->platform_suspend)
404                                 error = 0;
405
406                         break;
407
408                 default:
409                         printk(KERN_ERR "SNAPSHOT_PMOPS: invalid argument %ld\n", arg);
410
411                 }
412                 break;
413
414         case SNAPSHOT_SET_SWAP_AREA:
415                 if (swsusp_swap_in_use()) {
416                         error = -EPERM;
417                 } else {
418                         struct resume_swap_area swap_area;
419                         dev_t swdev;
420
421                         error = copy_from_user(&swap_area, (void __user *)arg,
422                                         sizeof(struct resume_swap_area));
423                         if (error) {
424                                 error = -EFAULT;
425                                 break;
426                         }
427
428                         /*
429                          * User space encodes device types as two-byte values,
430                          * so we need to recode them
431                          */
432                         swdev = old_decode_dev(swap_area.dev);
433                         if (swdev) {
434                                 offset = swap_area.offset;
435                                 data->swap = swap_type_of(swdev, offset, NULL);
436                                 if (data->swap < 0)
437                                         error = -ENODEV;
438                         } else {
439                                 data->swap = -1;
440                                 error = -EINVAL;
441                         }
442                 }
443                 break;
444
445         default:
446                 error = -ENOTTY;
447
448         }
449
450         return error;
451 }
452
453 static const struct file_operations snapshot_fops = {
454         .open = snapshot_open,
455         .release = snapshot_release,
456         .read = snapshot_read,
457         .write = snapshot_write,
458         .llseek = no_llseek,
459         .ioctl = snapshot_ioctl,
460 };
461
462 static struct miscdevice snapshot_device = {
463         .minor = SNAPSHOT_MINOR,
464         .name = "snapshot",
465         .fops = &snapshot_fops,
466 };
467
468 static int __init snapshot_device_init(void)
469 {
470         return misc_register(&snapshot_device);
471 };
472
473 device_initcall(snapshot_device_init);