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