linux/kernel/power/user.c
<<
>>
Prefs
   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_WRONLY ?
 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
 155        mutex_lock(&pm_mutex);
 156
 157        data = filp->private_data;
 158        if (!data->ready) {
 159                res = -ENODATA;
 160                goto Unlock;
 161        }
 162        res = snapshot_read_next(&data->handle, count);
 163        if (res > 0) {
 164                if (copy_to_user(buf, data_of(data->handle), res))
 165                        res = -EFAULT;
 166                else
 167                        *offp = data->handle.offset;
 168        }
 169
 170 Unlock:
 171        mutex_unlock(&pm_mutex);
 172
 173        return res;
 174}
 175
 176static ssize_t snapshot_write(struct file *filp, const char __user *buf,
 177                              size_t count, loff_t *offp)
 178{
 179        struct snapshot_data *data;
 180        ssize_t res;
 181
 182        mutex_lock(&pm_mutex);
 183
 184        data = filp->private_data;
 185        res = snapshot_write_next(&data->handle, count);
 186        if (res > 0) {
 187                if (copy_from_user(data_of(data->handle), buf, res))
 188                        res = -EFAULT;
 189                else
 190                        *offp = data->handle.offset;
 191        }
 192
 193        mutex_unlock(&pm_mutex);
 194
 195        return res;
 196}
 197
 198static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 199                                                        unsigned long arg)
 200{
 201        int error = 0;
 202        struct snapshot_data *data;
 203        loff_t size;
 204        sector_t offset;
 205
 206        if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
 207                return -ENOTTY;
 208        if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
 209                return -ENOTTY;
 210        if (!capable(CAP_SYS_ADMIN))
 211                return -EPERM;
 212
 213        if (!mutex_trylock(&pm_mutex))
 214                return -EBUSY;
 215
 216        data = filp->private_data;
 217
 218        switch (cmd) {
 219
 220        case SNAPSHOT_FREEZE:
 221                if (data->frozen)
 222                        break;
 223
 224                printk("Syncing filesystems ... ");
 225                sys_sync();
 226                printk("done.\n");
 227
 228                error = usermodehelper_disable();
 229                if (error)
 230                        break;
 231
 232                error = freeze_processes();
 233                if (error) {
 234                        thaw_processes();
 235                        usermodehelper_enable();
 236                }
 237                if (!error)
 238                        data->frozen = 1;
 239                break;
 240
 241        case SNAPSHOT_UNFREEZE:
 242                if (!data->frozen || data->ready)
 243                        break;
 244                thaw_processes();
 245                usermodehelper_enable();
 246                data->frozen = 0;
 247                break;
 248
 249        case SNAPSHOT_CREATE_IMAGE:
 250        case SNAPSHOT_ATOMIC_SNAPSHOT:
 251                if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
 252                        error = -EPERM;
 253                        break;
 254                }
 255                error = hibernation_snapshot(data->platform_support);
 256                if (!error)
 257                        error = put_user(in_suspend, (int __user *)arg);
 258                if (!error)
 259                        data->ready = 1;
 260                break;
 261
 262        case SNAPSHOT_ATOMIC_RESTORE:
 263                snapshot_write_finalize(&data->handle);
 264                if (data->mode != O_WRONLY || !data->frozen ||
 265                    !snapshot_image_loaded(&data->handle)) {
 266                        error = -EPERM;
 267                        break;
 268                }
 269                error = hibernation_restore(data->platform_support);
 270                break;
 271
 272        case SNAPSHOT_FREE:
 273                swsusp_free();
 274                memset(&data->handle, 0, sizeof(struct snapshot_handle));
 275                data->ready = 0;
 276                break;
 277
 278        case SNAPSHOT_PREF_IMAGE_SIZE:
 279        case SNAPSHOT_SET_IMAGE_SIZE:
 280                image_size = arg;
 281                break;
 282
 283        case SNAPSHOT_GET_IMAGE_SIZE:
 284                if (!data->ready) {
 285                        error = -ENODATA;
 286                        break;
 287                }
 288                size = snapshot_get_image_size();
 289                size <<= PAGE_SHIFT;
 290                error = put_user(size, (loff_t __user *)arg);
 291                break;
 292
 293        case SNAPSHOT_AVAIL_SWAP_SIZE:
 294        case SNAPSHOT_AVAIL_SWAP:
 295                size = count_swap_pages(data->swap, 1);
 296                size <<= PAGE_SHIFT;
 297                error = put_user(size, (loff_t __user *)arg);
 298                break;
 299
 300        case SNAPSHOT_ALLOC_SWAP_PAGE:
 301        case SNAPSHOT_GET_SWAP_PAGE:
 302                if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
 303                        error = -ENODEV;
 304                        break;
 305                }
 306                offset = alloc_swapdev_block(data->swap);
 307                if (offset) {
 308                        offset <<= PAGE_SHIFT;
 309                        error = put_user(offset, (loff_t __user *)arg);
 310                } else {
 311                        error = -ENOSPC;
 312                }
 313                break;
 314
 315        case SNAPSHOT_FREE_SWAP_PAGES:
 316                if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
 317                        error = -ENODEV;
 318                        break;
 319                }
 320                free_all_swap_pages(data->swap);
 321                break;
 322
 323        case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */
 324                if (!swsusp_swap_in_use()) {
 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 (!data->frozen) {
 345                        error = -EPERM;
 346                        break;
 347                }
 348                /*
 349                 * Tasks are frozen and the notifiers have been called with
 350                 * PM_HIBERNATION_PREPARE
 351                 */
 352                error = suspend_devices_and_enter(PM_SUSPEND_MEM);
 353                break;
 354
 355        case SNAPSHOT_PLATFORM_SUPPORT:
 356                data->platform_support = !!arg;
 357                break;
 358
 359        case SNAPSHOT_POWER_OFF:
 360                if (data->platform_support)
 361                        error = hibernation_platform_enter();
 362                break;
 363
 364        case SNAPSHOT_PMOPS: /* This ioctl is deprecated */
 365                error = -EINVAL;
 366
 367                switch (arg) {
 368
 369                case PMOPS_PREPARE:
 370                        data->platform_support = 1;
 371                        error = 0;
 372                        break;
 373
 374                case PMOPS_ENTER:
 375                        if (data->platform_support)
 376                                error = hibernation_platform_enter();
 377                        break;
 378
 379                case PMOPS_FINISH:
 380                        if (data->platform_support)
 381                                error = 0;
 382                        break;
 383
 384                default:
 385                        printk(KERN_ERR "SNAPSHOT_PMOPS: invalid argument %ld\n", arg);
 386
 387                }
 388                break;
 389
 390        case SNAPSHOT_SET_SWAP_AREA:
 391                if (swsusp_swap_in_use()) {
 392                        error = -EPERM;
 393                } else {
 394                        struct resume_swap_area swap_area;
 395                        dev_t swdev;
 396
 397                        error = copy_from_user(&swap_area, (void __user *)arg,
 398                                        sizeof(struct resume_swap_area));
 399                        if (error) {
 400                                error = -EFAULT;
 401                                break;
 402                        }
 403
 404                        /*
 405                         * User space encodes device types as two-byte values,
 406                         * so we need to recode them
 407                         */
 408                        swdev = old_decode_dev(swap_area.dev);
 409                        if (swdev) {
 410                                offset = swap_area.offset;
 411                                data->swap = swap_type_of(swdev, offset, NULL);
 412                                if (data->swap < 0)
 413                                        error = -ENODEV;
 414                        } else {
 415                                data->swap = -1;
 416                                error = -EINVAL;
 417                        }
 418                }
 419                break;
 420
 421        default:
 422                error = -ENOTTY;
 423
 424        }
 425
 426        mutex_unlock(&pm_mutex);
 427
 428        return error;
 429}
 430
 431static const struct file_operations snapshot_fops = {
 432        .open = snapshot_open,
 433        .release = snapshot_release,
 434        .read = snapshot_read,
 435        .write = snapshot_write,
 436        .llseek = no_llseek,
 437        .unlocked_ioctl = snapshot_ioctl,
 438};
 439
 440static struct miscdevice snapshot_device = {
 441        .minor = SNAPSHOT_MINOR,
 442        .name = "snapshot",
 443        .fops = &snapshot_fops,
 444};
 445
 446static int __init snapshot_device_init(void)
 447{
 448        return misc_register(&snapshot_device);
 449};
 450
 451device_initcall(snapshot_device_init);
 452