lkml.org 
[lkml]   [2010]   [Apr]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 2/9] PM: suspend_block: Add driver to access suspend blockers from user-space
    Date
    Add a misc device, "suspend_blocker", that allows user-space processes
    to block auto suspend. The device has ioctls to create a suspend_blocker,
    and to block and unblock suspend. To delete the suspend_blocker, close
    the device.

    Signed-off-by: Arve Hjønnevåg <arve@android.com>
    ---
    Documentation/power/suspend-blockers.txt | 17 ++++
    include/linux/suspend_block_dev.h | 25 ++++++
    kernel/power/Kconfig | 9 ++
    kernel/power/Makefile | 1 +
    kernel/power/user_suspend_blocker.c | 128 ++++++++++++++++++++++++++++++
    5 files changed, 180 insertions(+), 0 deletions(-)
    create mode 100644 include/linux/suspend_block_dev.h
    create mode 100644 kernel/power/user_suspend_blocker.c

    diff --git a/Documentation/power/suspend-blockers.txt b/Documentation/power/suspend-blockers.txt
    index 1c48514..877bd8c 100644
    --- a/Documentation/power/suspend-blockers.txt
    +++ b/Documentation/power/suspend-blockers.txt
    @@ -95,3 +95,20 @@ if (list_empty(&state->pending_work))
    else
    suspend_block(&state->suspend_blocker);

    +User-space API
    +==============
    +
    +To create a suspend_blocker from user-space, open the suspend_blocker device:
    + fd = open("/dev/suspend_blocker", O_RDWR | O_CLOEXEC);
    +then call:
    + ioctl(fd, SUSPEND_BLOCKER_IOCTL_INIT(strlen(name)), name);
    +
    +To activate a suspend_blocker call:
    + ioctl(fd, SUSPEND_BLOCKER_IOCTL_BLOCK);
    +
    +To unblock call:
    + ioctl(fd, SUSPEND_BLOCKER_IOCTL_UNBLOCK);
    +
    +To destroy the suspend_blocker, close the device:
    + close(fd);
    +
    diff --git a/include/linux/suspend_block_dev.h b/include/linux/suspend_block_dev.h
    new file mode 100644
    index 0000000..24bc5c7
    --- /dev/null
    +++ b/include/linux/suspend_block_dev.h
    @@ -0,0 +1,25 @@
    +/* include/linux/suspend_block_dev.h
    + *
    + * Copyright (C) 2009 Google, Inc.
    + *
    + * This software is licensed under the terms of the GNU General Public
    + * License version 2, as published by the Free Software Foundation, and
    + * may be copied, distributed, and modified under those terms.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + */
    +
    +#ifndef _LINUX_SUSPEND_BLOCK_DEV_H
    +#define _LINUX_SUSPEND_BLOCK_DEV_H
    +
    +#include <linux/ioctl.h>
    +
    +#define SUSPEND_BLOCKER_IOCTL_INIT(len) _IOC(_IOC_WRITE, 's', 0, len)
    +#define SUSPEND_BLOCKER_IOCTL_BLOCK _IO('s', 1)
    +#define SUSPEND_BLOCKER_IOCTL_UNBLOCK _IO('s', 2)
    +
    +#endif
    diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
    index f8fa246..1ac50ee 100644
    --- a/kernel/power/Kconfig
    +++ b/kernel/power/Kconfig
    @@ -141,6 +141,15 @@ config SUSPEND_BLOCKERS
    state through /sys/power/state, the requested sleep state will be
    entered when no suspend blockers are active.

    +config USER_SUSPEND_BLOCKERS
    + bool "Userspace suspend blockers"
    + depends on SUSPEND_BLOCKERS
    + default y
    + ---help---
    + User-space suspend block api. Creates a misc device with ioctls
    + to create, block and unblock a suspend_blocker. The suspend_blocker
    + will be deleted when the device is closed.
    +
    config HIBERNATION_NVS
    bool

    diff --git a/kernel/power/Makefile b/kernel/power/Makefile
    index f570801..80086c6 100644
    --- a/kernel/power/Makefile
    +++ b/kernel/power/Makefile
    @@ -8,6 +8,7 @@ obj-$(CONFIG_PM_SLEEP) += console.o
    obj-$(CONFIG_FREEZER) += process.o
    obj-$(CONFIG_SUSPEND) += suspend.o
    obj-$(CONFIG_SUSPEND_BLOCKERS) += suspend_blocker.o
    +obj-$(CONFIG_USER_SUSPEND_BLOCKERS) += user_suspend_blocker.o
    obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
    obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o
    obj-$(CONFIG_HIBERNATION_NVS) += hibernate_nvs.o
    diff --git a/kernel/power/user_suspend_blocker.c b/kernel/power/user_suspend_blocker.c
    new file mode 100644
    index 0000000..a9be6f4
    --- /dev/null
    +++ b/kernel/power/user_suspend_blocker.c
    @@ -0,0 +1,128 @@
    +/* kernel/power/user_suspend_block.c
    + *
    + * Copyright (C) 2009-2010 Google, Inc.
    + *
    + * This software is licensed under the terms of the GNU General Public
    + * License version 2, as published by the Free Software Foundation, and
    + * may be copied, distributed, and modified under those terms.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + *
    + */
    +
    +#include <linux/fs.h>
    +#include <linux/miscdevice.h>
    +#include <linux/module.h>
    +#include <linux/uaccess.h>
    +#include <linux/slab.h>
    +#include <linux/suspend_blocker.h>
    +#include <linux/suspend_block_dev.h>
    +
    +enum {
    + DEBUG_FAILURE = BIT(0),
    +};
    +static int debug_mask = DEBUG_FAILURE;
    +module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
    +
    +static DEFINE_MUTEX(ioctl_lock);
    +
    +struct user_suspend_blocker {
    + struct suspend_blocker blocker;
    + char name[0];
    +};
    +
    +static int create_user_suspend_blocker(struct file *file, void __user *name,
    + size_t name_len)
    +{
    + struct user_suspend_blocker *bl;
    + if (file->private_data)
    + return -EBUSY;
    + if (name_len > NAME_MAX)
    + return -ENAMETOOLONG;
    + bl = kzalloc(sizeof(*bl) + name_len + 1, GFP_KERNEL);
    + if (!bl)
    + return -ENOMEM;
    + if (copy_from_user(bl->name, name, name_len))
    + goto err_fault;
    + suspend_blocker_init(&bl->blocker, bl->name);
    + file->private_data = bl;
    + return 0;
    +
    +err_fault:
    + kfree(bl);
    + return -EFAULT;
    +}
    +
    +static long user_suspend_blocker_ioctl(struct file *file, unsigned int cmd,
    + unsigned long _arg)
    +{
    + void __user *arg = (void __user *)_arg;
    + struct user_suspend_blocker *bl;
    + long ret;
    +
    + mutex_lock(&ioctl_lock);
    + if ((cmd & ~IOCSIZE_MASK) == SUSPEND_BLOCKER_IOCTL_INIT(0)) {
    + ret = create_user_suspend_blocker(file, arg, _IOC_SIZE(cmd));
    + goto done;
    + }
    + bl = file->private_data;
    + if (!bl) {
    + ret = -ENOENT;
    + goto done;
    + }
    + switch (cmd) {
    + case SUSPEND_BLOCKER_IOCTL_BLOCK:
    + suspend_block(&bl->blocker);
    + ret = 0;
    + break;
    + case SUSPEND_BLOCKER_IOCTL_UNBLOCK:
    + suspend_unblock(&bl->blocker);
    + ret = 0;
    + break;
    + default:
    + ret = -ENOTSUPP;
    + }
    +done:
    + if (ret && debug_mask & DEBUG_FAILURE)
    + pr_err("user_suspend_blocker_ioctl: cmd %x failed, %ld\n",
    + cmd, ret);
    + mutex_unlock(&ioctl_lock);
    + return ret;
    +}
    +
    +static int user_suspend_blocker_release(struct inode *inode, struct file *file)
    +{
    + struct user_suspend_blocker *bl = file->private_data;
    + if (!bl)
    + return 0;
    + suspend_blocker_destroy(&bl->blocker);
    + kfree(bl);
    + return 0;
    +}
    +
    +const struct file_operations user_suspend_blocker_fops = {
    + .release = user_suspend_blocker_release,
    + .unlocked_ioctl = user_suspend_blocker_ioctl,
    +};
    +
    +struct miscdevice user_suspend_blocker_device = {
    + .minor = MISC_DYNAMIC_MINOR,
    + .name = "suspend_blocker",
    + .fops = &user_suspend_blocker_fops,
    +};
    +
    +static int __init user_suspend_blocker_init(void)
    +{
    + return misc_register(&user_suspend_blocker_device);
    +}
    +
    +static void __exit user_suspend_blocker_exit(void)
    +{
    + misc_deregister(&user_suspend_blocker_device);
    +}
    +
    +module_init(user_suspend_blocker_init);
    +module_exit(user_suspend_blocker_exit);
    --
    1.6.5.1
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2010-04-23 03:15    [W:0.035 / U:212.748 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site