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