Root/kernel/power/user.c

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

Archive Download this file



interactive