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/compat.h>
  24#include <linux/console.h>
  25#include <linux/cpu.h>
  26#include <linux/freezer.h>
  27#include <linux/security.h>
  28
  29#include <asm/uaccess.h>
  30
  31#include "power.h"
  32
  33
  34#define SNAPSHOT_MINOR  231
  35
  36static struct snapshot_data {
  37        struct snapshot_handle handle;
  38        int swap;
  39        int mode;
  40        char frozen;
  41        char ready;
  42        char platform_support;
  43} snapshot_state;
  44
  45atomic_t snapshot_device_available = ATOMIC_INIT(1);
  46
  47static int snapshot_open(struct inode *inode, struct file *filp)
  48{
  49        struct snapshot_data *data;
  50        int error;
  51
  52        if (get_securelevel() > 0)
  53                return -EPERM;
  54
  55        if (!hibernation_available())
  56                return -EPERM;
  57
  58        lock_system_sleep();
  59
  60        if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
  61                error = -EBUSY;
  62                goto Unlock;
  63        }
  64
  65        if ((filp->f_flags & O_ACCMODE) == O_RDWR) {
  66                atomic_inc(&snapshot_device_available);
  67                error = -ENOSYS;
  68                goto Unlock;
  69        }
  70        nonseekable_open(inode, filp);
  71        data = &snapshot_state;
  72        filp->private_data = data;
  73        memset(&data->handle, 0, sizeof(struct snapshot_handle));
  74        if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
  75                /* Hibernating.  The image device should be accessible. */
  76                data->swap = swsusp_resume_device ?
  77                        swap_type_of(swsusp_resume_device, 0, NULL) : -1;
  78                data->mode = O_RDONLY;
  79                error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
  80                if (error)
  81                        pm_notifier_call_chain(PM_POST_HIBERNATION);
  82        } else {
  83                /*
  84                 * Resuming.  We may need to wait for the image device to
  85                 * appear.
  86                 */
  87                wait_for_device_probe();
  88
  89                data->swap = -1;
  90                data->mode = O_WRONLY;
  91                error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
  92                if (error)
  93                        pm_notifier_call_chain(PM_POST_RESTORE);
  94        }
  95        if (error)
  96                atomic_inc(&snapshot_device_available);
  97
  98        data->frozen = 0;
  99        data->ready = 0;
 100        data->platform_support = 0;
 101
 102 Unlock:
 103        unlock_system_sleep();
 104
 105        return error;
 106}
 107
 108static int snapshot_release(struct inode *inode, struct file *filp)
 109{
 110        struct snapshot_data *data;
 111
 112        lock_system_sleep();
 113
 114        swsusp_free();
 115        data = filp->private_data;
 116        free_all_swap_pages(data->swap);
 117        if (data->frozen) {
 118                pm_restore_gfp_mask();
 119                free_basic_memory_bitmaps();
 120                thaw_processes();
 121        }
 122        pm_notifier_call_chain(data->mode == O_RDONLY ?
 123                        PM_POST_HIBERNATION : PM_POST_RESTORE);
 124        atomic_inc(&snapshot_device_available);
 125
 126        unlock_system_sleep();
 127
 128        return 0;
 129}
 130
 131static ssize_t snapshot_read(struct file *filp, char __user *buf,
 132                             size_t count, loff_t *offp)
 133{
 134        struct snapshot_data *data;
 135        ssize_t res;
 136        loff_t pg_offp = *offp & ~PAGE_MASK;
 137
 138        lock_system_sleep();
 139
 140        data = filp->private_data;
 141        if (!data->ready) {
 142                res = -ENODATA;
 143                goto Unlock;
 144        }
 145        if (!pg_offp) { /* on page boundary? */
 146                res = snapshot_read_next(&data->handle);
 147                if (res <= 0)
 148                        goto Unlock;
 149        } else {
 150                res = PAGE_SIZE - pg_offp;
 151        }
 152
 153        res = simple_read_from_buffer(buf, count, &pg_offp,
 154                        data_of(data->handle), res);
 155        if (res > 0)
 156                *offp += res;
 157
 158 Unlock:
 159        unlock_system_sleep();
 160
 161        return res;
 162}
 163
 164static ssize_t snapshot_write(struct file *filp, const char __user *buf,
 165                              size_t count, loff_t *offp)
 166{
 167        struct snapshot_data *data;
 168        ssize_t res;
 169        loff_t pg_offp = *offp & ~PAGE_MASK;
 170
 171        lock_system_sleep();
 172
 173        data = filp->private_data;
 174
 175        if (!pg_offp) {
 176                res = snapshot_write_next(&data->handle);
 177                if (res <= 0)
 178                        goto unlock;
 179        } else {
 180                res = PAGE_SIZE - pg_offp;
 181        }
 182
 183        res = simple_write_to_buffer(data_of(data->handle), res, &pg_offp,
 184                        buf, count);
 185        if (res > 0)
 186                *offp += res;
 187unlock:
 188        unlock_system_sleep();
 189
 190        return res;
 191}
 192
 193static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 194                                                        unsigned long arg)
 195{
 196        int error = 0;
 197        struct snapshot_data *data;
 198        loff_t size;
 199        sector_t offset;
 200
 201        if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
 202                return -ENOTTY;
 203        if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
 204                return -ENOTTY;
 205        if (!capable(CAP_SYS_ADMIN))
 206                return -EPERM;
 207
 208        if (!mutex_trylock(&pm_mutex))
 209                return -EBUSY;
 210
 211        lock_device_hotplug();
 212        data = filp->private_data;
 213
 214        switch (cmd) {
 215
 216        case SNAPSHOT_FREEZE:
 217                if (data->frozen)
 218                        break;
 219
 220                printk("Syncing filesystems ... ");
 221                sys_sync();
 222                printk("done.\n");
 223
 224                error = freeze_processes();
 225                if (error)
 226                        break;
 227
 228                error = create_basic_memory_bitmaps();
 229                if (error)
 230                        thaw_processes();
 231                else
 232                        data->frozen = 1;
 233
 234                break;
 235
 236        case SNAPSHOT_UNFREEZE:
 237                if (!data->frozen || data->ready)
 238                        break;
 239                pm_restore_gfp_mask();
 240                free_basic_memory_bitmaps();
 241                thaw_processes();
 242                data->frozen = 0;
 243                break;
 244
 245        case SNAPSHOT_CREATE_IMAGE:
 246                if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
 247                        error = -EPERM;
 248                        break;
 249                }
 250                pm_restore_gfp_mask();
 251                error = hibernation_snapshot(data->platform_support);
 252                if (!error) {
 253                        error = put_user(in_suspend, (int __user *)arg);
 254                        data->ready = !freezer_test_done && !error;
 255                        freezer_test_done = false;
 256                }
 257                break;
 258
 259        case SNAPSHOT_ATOMIC_RESTORE:
 260                snapshot_write_finalize(&data->handle);
 261                if (data->mode != O_WRONLY || !data->frozen ||
 262                    !snapshot_image_loaded(&data->handle)) {
 263                        error = -EPERM;
 264                        break;
 265                }
 266                error = hibernation_restore(data->platform_support);
 267                break;
 268
 269        case SNAPSHOT_FREE:
 270                swsusp_free();
 271                memset(&data->handle, 0, sizeof(struct snapshot_handle));
 272                data->ready = 0;
 273                /*
 274                 * It is necessary to thaw kernel threads here, because
 275                 * SNAPSHOT_CREATE_IMAGE may be invoked directly after
 276                 * SNAPSHOT_FREE.  In that case, if kernel threads were not
 277                 * thawed, the preallocation of memory carried out by
 278                 * hibernation_snapshot() might run into problems (i.e. it
 279                 * might fail or even deadlock).
 280                 */
 281                thaw_kernel_threads();
 282                break;
 283
 284        case SNAPSHOT_PREF_IMAGE_SIZE:
 285                image_size = arg;
 286                break;
 287
 288        case SNAPSHOT_GET_IMAGE_SIZE:
 289                if (!data->ready) {
 290                        error = -ENODATA;
 291                        break;
 292                }
 293                size = snapshot_get_image_size();
 294                size <<= PAGE_SHIFT;
 295                error = put_user(size, (loff_t __user *)arg);
 296                break;
 297
 298        case SNAPSHOT_AVAIL_SWAP_SIZE:
 299                size = count_swap_pages(data->swap, 1);
 300                size <<= PAGE_SHIFT;
 301                error = put_user(size, (loff_t __user *)arg);
 302                break;
 303
 304        case SNAPSHOT_ALLOC_SWAP_PAGE:
 305                if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
 306                        error = -ENODEV;
 307                        break;
 308                }
 309                offset = alloc_swapdev_block(data->swap);
 310                if (offset) {
 311                        offset <<= PAGE_SHIFT;
 312                        error = put_user(offset, (loff_t __user *)arg);
 313                } else {
 314                        error = -ENOSPC;
 315                }
 316                break;
 317
 318        case SNAPSHOT_FREE_SWAP_PAGES:
 319                if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
 320                        error = -ENODEV;
 321                        break;
 322                }
 323                free_all_swap_pages(data->swap);
 324                break;
 325
 326        case SNAPSHOT_S2RAM:
 327                if (!data->frozen) {
 328                        error = -EPERM;
 329                        break;
 330                }
 331                /*
 332                 * Tasks are frozen and the notifiers have been called with
 333                 * PM_HIBERNATION_PREPARE
 334                 */
 335                error = suspend_devices_and_enter(PM_SUSPEND_MEM);
 336                data->ready = 0;
 337                break;
 338
 339        case SNAPSHOT_PLATFORM_SUPPORT:
 340                data->platform_support = !!arg;
 341                break;
 342
 343        case SNAPSHOT_POWER_OFF:
 344                if (data->platform_support)
 345                        error = hibernation_platform_enter();
 346                break;
 347
 348        case SNAPSHOT_SET_SWAP_AREA:
 349                if (swsusp_swap_in_use()) {
 350                        error = -EPERM;
 351                } else {
 352                        struct resume_swap_area swap_area;
 353                        dev_t swdev;
 354
 355                        error = copy_from_user(&swap_area, (void __user *)arg,
 356                                        sizeof(struct resume_swap_area));
 357                        if (error) {
 358                                error = -EFAULT;
 359                                break;
 360                        }
 361
 362                        /*
 363                         * User space encodes device types as two-byte values,
 364                         * so we need to recode them
 365                         */
 366                        swdev = new_decode_dev(swap_area.dev);
 367                        if (swdev) {
 368                                offset = swap_area.offset;
 369                                data->swap = swap_type_of(swdev, offset, NULL);
 370                                if (data->swap < 0)
 371                                        error = -ENODEV;
 372                        } else {
 373                                data->swap = -1;
 374                                error = -EINVAL;
 375                        }
 376                }
 377                break;
 378
 379        default:
 380                error = -ENOTTY;
 381
 382        }
 383
 384        unlock_device_hotplug();
 385        mutex_unlock(&pm_mutex);
 386
 387        return error;
 388}
 389
 390#ifdef CONFIG_COMPAT
 391
 392struct compat_resume_swap_area {
 393        compat_loff_t offset;
 394        u32 dev;
 395} __packed;
 396
 397static long
 398snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 399{
 400        BUILD_BUG_ON(sizeof(loff_t) != sizeof(compat_loff_t));
 401
 402        switch (cmd) {
 403        case SNAPSHOT_GET_IMAGE_SIZE:
 404        case SNAPSHOT_AVAIL_SWAP_SIZE:
 405        case SNAPSHOT_ALLOC_SWAP_PAGE: {
 406                compat_loff_t __user *uoffset = compat_ptr(arg);
 407                loff_t offset;
 408                mm_segment_t old_fs;
 409                int err;
 410
 411                old_fs = get_fs();
 412                set_fs(KERNEL_DS);
 413                err = snapshot_ioctl(file, cmd, (unsigned long) &offset);
 414                set_fs(old_fs);
 415                if (!err && put_user(offset, uoffset))
 416                        err = -EFAULT;
 417                return err;
 418        }
 419
 420        case SNAPSHOT_CREATE_IMAGE:
 421                return snapshot_ioctl(file, cmd,
 422                                      (unsigned long) compat_ptr(arg));
 423
 424        case SNAPSHOT_SET_SWAP_AREA: {
 425                struct compat_resume_swap_area __user *u_swap_area =
 426                        compat_ptr(arg);
 427                struct resume_swap_area swap_area;
 428                mm_segment_t old_fs;
 429                int err;
 430
 431                err = get_user(swap_area.offset, &u_swap_area->offset);
 432                err |= get_user(swap_area.dev, &u_swap_area->dev);
 433                if (err)
 434                        return -EFAULT;
 435                old_fs = get_fs();
 436                set_fs(KERNEL_DS);
 437                err = snapshot_ioctl(file, SNAPSHOT_SET_SWAP_AREA,
 438                                     (unsigned long) &swap_area);
 439                set_fs(old_fs);
 440                return err;
 441        }
 442
 443        default:
 444                return snapshot_ioctl(file, cmd, arg);
 445        }
 446}
 447
 448#endif /* CONFIG_COMPAT */
 449
 450static const struct file_operations snapshot_fops = {
 451        .open = snapshot_open,
 452        .release = snapshot_release,
 453        .read = snapshot_read,
 454        .write = snapshot_write,
 455        .llseek = no_llseek,
 456        .unlocked_ioctl = snapshot_ioctl,
 457#ifdef CONFIG_COMPAT
 458        .compat_ioctl = snapshot_compat_ioctl,
 459#endif
 460};
 461
 462static struct miscdevice snapshot_device = {
 463        .minor = SNAPSHOT_MINOR,
 464        .name = "snapshot",
 465        .fops = &snapshot_fops,
 466};
 467
 468static int __init snapshot_device_init(void)
 469{
 470        return misc_register(&snapshot_device);
 471};
 472
 473device_initcall(snapshot_device_init);
 474