aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/user.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/power/user.c')
-rw-r--r--kernel/power/user.c195
1 files changed, 93 insertions, 102 deletions
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 6d8f535c2b88..3e100075b13c 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -21,6 +21,7 @@
21#include <linux/swapops.h> 21#include <linux/swapops.h>
22#include <linux/pm.h> 22#include <linux/pm.h>
23#include <linux/fs.h> 23#include <linux/fs.h>
24#include <linux/compat.h>
24#include <linux/console.h> 25#include <linux/console.h>
25#include <linux/cpu.h> 26#include <linux/cpu.h>
26#include <linux/freezer.h> 27#include <linux/freezer.h>
@@ -30,28 +31,6 @@
30 31
31#include "power.h" 32#include "power.h"
32 33
33/*
34 * NOTE: The SNAPSHOT_SET_SWAP_FILE and SNAPSHOT_PMOPS ioctls are obsolete and
35 * will be removed in the future. They are only preserved here for
36 * compatibility with existing userland utilities.
37 */
38#define SNAPSHOT_SET_SWAP_FILE _IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int)
39#define SNAPSHOT_PMOPS _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int)
40
41#define PMOPS_PREPARE 1
42#define PMOPS_ENTER 2
43#define PMOPS_FINISH 3
44
45/*
46 * NOTE: The following ioctl definitions are wrong and have been replaced with
47 * correct ones. They are only preserved here for compatibility with existing
48 * userland utilities and will be removed in the future.
49 */
50#define SNAPSHOT_ATOMIC_SNAPSHOT _IOW(SNAPSHOT_IOC_MAGIC, 3, void *)
51#define SNAPSHOT_SET_IMAGE_SIZE _IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long)
52#define SNAPSHOT_AVAIL_SWAP _IOR(SNAPSHOT_IOC_MAGIC, 7, void *)
53#define SNAPSHOT_GET_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 8, void *)
54
55 34
56#define SNAPSHOT_MINOR 231 35#define SNAPSHOT_MINOR 231
57 36
@@ -71,7 +50,7 @@ static int snapshot_open(struct inode *inode, struct file *filp)
71 struct snapshot_data *data; 50 struct snapshot_data *data;
72 int error; 51 int error;
73 52
74 mutex_lock(&pm_mutex); 53 lock_system_sleep();
75 54
76 if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { 55 if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
77 error = -EBUSY; 56 error = -EBUSY;
@@ -123,7 +102,7 @@ static int snapshot_open(struct inode *inode, struct file *filp)
123 data->platform_support = 0; 102 data->platform_support = 0;
124 103
125 Unlock: 104 Unlock:
126 mutex_unlock(&pm_mutex); 105 unlock_system_sleep();
127 106
128 return error; 107 return error;
129} 108}
@@ -132,7 +111,7 @@ static int snapshot_release(struct inode *inode, struct file *filp)
132{ 111{
133 struct snapshot_data *data; 112 struct snapshot_data *data;
134 113
135 mutex_lock(&pm_mutex); 114 lock_system_sleep();
136 115
137 swsusp_free(); 116 swsusp_free();
138 free_basic_memory_bitmaps(); 117 free_basic_memory_bitmaps();
@@ -146,7 +125,7 @@ static int snapshot_release(struct inode *inode, struct file *filp)
146 PM_POST_HIBERNATION : PM_POST_RESTORE); 125 PM_POST_HIBERNATION : PM_POST_RESTORE);
147 atomic_inc(&snapshot_device_available); 126 atomic_inc(&snapshot_device_available);
148 127
149 mutex_unlock(&pm_mutex); 128 unlock_system_sleep();
150 129
151 return 0; 130 return 0;
152} 131}
@@ -158,7 +137,7 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf,
158 ssize_t res; 137 ssize_t res;
159 loff_t pg_offp = *offp & ~PAGE_MASK; 138 loff_t pg_offp = *offp & ~PAGE_MASK;
160 139
161 mutex_lock(&pm_mutex); 140 lock_system_sleep();
162 141
163 data = filp->private_data; 142 data = filp->private_data;
164 if (!data->ready) { 143 if (!data->ready) {
@@ -179,7 +158,7 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf,
179 *offp += res; 158 *offp += res;
180 159
181 Unlock: 160 Unlock:
182 mutex_unlock(&pm_mutex); 161 unlock_system_sleep();
183 162
184 return res; 163 return res;
185} 164}
@@ -191,7 +170,7 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
191 ssize_t res; 170 ssize_t res;
192 loff_t pg_offp = *offp & ~PAGE_MASK; 171 loff_t pg_offp = *offp & ~PAGE_MASK;
193 172
194 mutex_lock(&pm_mutex); 173 lock_system_sleep();
195 174
196 data = filp->private_data; 175 data = filp->private_data;
197 176
@@ -208,20 +187,11 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
208 if (res > 0) 187 if (res > 0)
209 *offp += res; 188 *offp += res;
210unlock: 189unlock:
211 mutex_unlock(&pm_mutex); 190 unlock_system_sleep();
212 191
213 return res; 192 return res;
214} 193}
215 194
216static void snapshot_deprecated_ioctl(unsigned int cmd)
217{
218 if (printk_ratelimit())
219 printk(KERN_NOTICE "%pf: ioctl '%.8x' is deprecated and will "
220 "be removed soon, update your suspend-to-disk "
221 "utilities\n",
222 __builtin_return_address(0), cmd);
223}
224
225static long snapshot_ioctl(struct file *filp, unsigned int cmd, 195static long snapshot_ioctl(struct file *filp, unsigned int cmd,
226 unsigned long arg) 196 unsigned long arg)
227{ 197{
@@ -257,11 +227,9 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
257 break; 227 break;
258 228
259 error = freeze_processes(); 229 error = freeze_processes();
260 if (error) { 230 if (error)
261 thaw_processes();
262 usermodehelper_enable(); 231 usermodehelper_enable();
263 } 232 else
264 if (!error)
265 data->frozen = 1; 233 data->frozen = 1;
266 break; 234 break;
267 235
@@ -274,8 +242,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
274 data->frozen = 0; 242 data->frozen = 0;
275 break; 243 break;
276 244
277 case SNAPSHOT_ATOMIC_SNAPSHOT:
278 snapshot_deprecated_ioctl(cmd);
279 case SNAPSHOT_CREATE_IMAGE: 245 case SNAPSHOT_CREATE_IMAGE:
280 if (data->mode != O_RDONLY || !data->frozen || data->ready) { 246 if (data->mode != O_RDONLY || !data->frozen || data->ready) {
281 error = -EPERM; 247 error = -EPERM;
@@ -283,10 +249,17 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
283 } 249 }
284 pm_restore_gfp_mask(); 250 pm_restore_gfp_mask();
285 error = hibernation_snapshot(data->platform_support); 251 error = hibernation_snapshot(data->platform_support);
286 if (!error) 252 if (error) {
253 thaw_kernel_threads();
254 } else {
287 error = put_user(in_suspend, (int __user *)arg); 255 error = put_user(in_suspend, (int __user *)arg);
288 if (!error) 256 if (!error && !freezer_test_done)
289 data->ready = 1; 257 data->ready = 1;
258 if (freezer_test_done) {
259 freezer_test_done = false;
260 thaw_kernel_threads();
261 }
262 }
290 break; 263 break;
291 264
292 case SNAPSHOT_ATOMIC_RESTORE: 265 case SNAPSHOT_ATOMIC_RESTORE:
@@ -303,10 +276,17 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
303 swsusp_free(); 276 swsusp_free();
304 memset(&data->handle, 0, sizeof(struct snapshot_handle)); 277 memset(&data->handle, 0, sizeof(struct snapshot_handle));
305 data->ready = 0; 278 data->ready = 0;
279 /*
280 * It is necessary to thaw kernel threads here, because
281 * SNAPSHOT_CREATE_IMAGE may be invoked directly after
282 * SNAPSHOT_FREE. In that case, if kernel threads were not
283 * thawed, the preallocation of memory carried out by
284 * hibernation_snapshot() might run into problems (i.e. it
285 * might fail or even deadlock).
286 */
287 thaw_kernel_threads();
306 break; 288 break;
307 289
308 case SNAPSHOT_SET_IMAGE_SIZE:
309 snapshot_deprecated_ioctl(cmd);
310 case SNAPSHOT_PREF_IMAGE_SIZE: 290 case SNAPSHOT_PREF_IMAGE_SIZE:
311 image_size = arg; 291 image_size = arg;
312 break; 292 break;
@@ -321,16 +301,12 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
321 error = put_user(size, (loff_t __user *)arg); 301 error = put_user(size, (loff_t __user *)arg);
322 break; 302 break;
323 303
324 case SNAPSHOT_AVAIL_SWAP:
325 snapshot_deprecated_ioctl(cmd);
326 case SNAPSHOT_AVAIL_SWAP_SIZE: 304 case SNAPSHOT_AVAIL_SWAP_SIZE:
327 size = count_swap_pages(data->swap, 1); 305 size = count_swap_pages(data->swap, 1);
328 size <<= PAGE_SHIFT; 306 size <<= PAGE_SHIFT;
329 error = put_user(size, (loff_t __user *)arg); 307 error = put_user(size, (loff_t __user *)arg);
330 break; 308 break;
331 309
332 case SNAPSHOT_GET_SWAP_PAGE:
333 snapshot_deprecated_ioctl(cmd);
334 case SNAPSHOT_ALLOC_SWAP_PAGE: 310 case SNAPSHOT_ALLOC_SWAP_PAGE:
335 if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { 311 if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
336 error = -ENODEV; 312 error = -ENODEV;
@@ -353,27 +329,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
353 free_all_swap_pages(data->swap); 329 free_all_swap_pages(data->swap);
354 break; 330 break;
355 331
356 case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */
357 snapshot_deprecated_ioctl(cmd);
358 if (!swsusp_swap_in_use()) {
359 /*
360 * User space encodes device types as two-byte values,
361 * so we need to recode them
362 */
363 if (old_decode_dev(arg)) {
364 data->swap = swap_type_of(old_decode_dev(arg),
365 0, NULL);
366 if (data->swap < 0)
367 error = -ENODEV;
368 } else {
369 data->swap = -1;
370 error = -EINVAL;
371 }
372 } else {
373 error = -EPERM;
374 }
375 break;
376
377 case SNAPSHOT_S2RAM: 332 case SNAPSHOT_S2RAM:
378 if (!data->frozen) { 333 if (!data->frozen) {
379 error = -EPERM; 334 error = -EPERM;
@@ -396,33 +351,6 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
396 error = hibernation_platform_enter(); 351 error = hibernation_platform_enter();
397 break; 352 break;
398 353
399 case SNAPSHOT_PMOPS: /* This ioctl is deprecated */
400 snapshot_deprecated_ioctl(cmd);
401 error = -EINVAL;
402
403 switch (arg) {
404
405 case PMOPS_PREPARE:
406 data->platform_support = 1;
407 error = 0;
408 break;
409
410 case PMOPS_ENTER:
411 if (data->platform_support)
412 error = hibernation_platform_enter();
413 break;
414
415 case PMOPS_FINISH:
416 if (data->platform_support)
417 error = 0;
418 break;
419
420 default:
421 printk(KERN_ERR "SNAPSHOT_PMOPS: invalid argument %ld\n", arg);
422
423 }
424 break;
425
426 case SNAPSHOT_SET_SWAP_AREA: 354 case SNAPSHOT_SET_SWAP_AREA:
427 if (swsusp_swap_in_use()) { 355 if (swsusp_swap_in_use()) {
428 error = -EPERM; 356 error = -EPERM;
@@ -464,6 +392,66 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
464 return error; 392 return error;
465} 393}
466 394
395#ifdef CONFIG_COMPAT
396
397struct compat_resume_swap_area {
398 compat_loff_t offset;
399 u32 dev;
400} __packed;
401
402static long
403snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
404{
405 BUILD_BUG_ON(sizeof(loff_t) != sizeof(compat_loff_t));
406
407 switch (cmd) {
408 case SNAPSHOT_GET_IMAGE_SIZE:
409 case SNAPSHOT_AVAIL_SWAP_SIZE:
410 case SNAPSHOT_ALLOC_SWAP_PAGE: {
411 compat_loff_t __user *uoffset = compat_ptr(arg);
412 loff_t offset;
413 mm_segment_t old_fs;
414 int err;
415
416 old_fs = get_fs();
417 set_fs(KERNEL_DS);
418 err = snapshot_ioctl(file, cmd, (unsigned long) &offset);
419 set_fs(old_fs);
420 if (!err && put_user(offset, uoffset))
421 err = -EFAULT;
422 return err;
423 }
424
425 case SNAPSHOT_CREATE_IMAGE:
426 return snapshot_ioctl(file, cmd,
427 (unsigned long) compat_ptr(arg));
428
429 case SNAPSHOT_SET_SWAP_AREA: {
430 struct compat_resume_swap_area __user *u_swap_area =
431 compat_ptr(arg);
432 struct resume_swap_area swap_area;
433 mm_segment_t old_fs;
434 int err;
435
436 err = get_user(swap_area.offset, &u_swap_area->offset);
437 err |= get_user(swap_area.dev, &u_swap_area->dev);
438 if (err)
439 return -EFAULT;
440 old_fs = get_fs();
441 set_fs(KERNEL_DS);
442 err = snapshot_ioctl(file, SNAPSHOT_SET_SWAP_AREA,
443 (unsigned long) &swap_area);
444 set_fs(old_fs);
445 return err;
446 }
447
448 default:
449 return snapshot_ioctl(file, cmd, arg);
450 }
451}
452
453#endif /* CONFIG_COMPAT */
454
467static const struct file_operations snapshot_fops = { 455static const struct file_operations snapshot_fops = {
468 .open = snapshot_open, 456 .open = snapshot_open,
469 .release = snapshot_release, 457 .release = snapshot_release,
@@ -471,6 +459,9 @@ static const struct file_operations snapshot_fops = {
471 .write = snapshot_write, 459 .write = snapshot_write,
472 .llseek = no_llseek, 460 .llseek = no_llseek,
473 .unlocked_ioctl = snapshot_ioctl, 461 .unlocked_ioctl = snapshot_ioctl,
462#ifdef CONFIG_COMPAT
463 .compat_ioctl = snapshot_compat_ioctl,
464#endif
474}; 465};
475 466
476static struct miscdevice snapshot_device = { 467static struct miscdevice snapshot_device = {