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