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