X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=kernel%2Fpower%2Fuser.c;h=ed97375daae9326ecf2b4864ff9368f1491f642a;hb=9d2a3f31d6d7832cd441eeda08bc2266cdd5d972;hp=b70d83d6b16e89c9882f99938e6cb40e173fb2e5;hpb=d12c610e08022a1b84d6bd4412c189214d32e713;p=safe%2Fjmp%2Flinux-2.6 diff --git a/kernel/power/user.c b/kernel/power/user.c index b70d83d..ed97375 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -23,68 +23,127 @@ #include #include #include +#include +#include #include #include "power.h" +/* + * NOTE: The SNAPSHOT_SET_SWAP_FILE and SNAPSHOT_PMOPS ioctls are obsolete and + * will be removed in the future. They are only preserved here for + * compatibility with existing userland utilities. + */ +#define SNAPSHOT_SET_SWAP_FILE _IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int) +#define SNAPSHOT_PMOPS _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int) + +#define PMOPS_PREPARE 1 +#define PMOPS_ENTER 2 +#define PMOPS_FINISH 3 + +/* + * NOTE: The following ioctl definitions are wrong and have been replaced with + * correct ones. They are only preserved here for compatibility with existing + * userland utilities and will be removed in the future. + */ +#define SNAPSHOT_ATOMIC_SNAPSHOT _IOW(SNAPSHOT_IOC_MAGIC, 3, void *) +#define SNAPSHOT_SET_IMAGE_SIZE _IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long) +#define SNAPSHOT_AVAIL_SWAP _IOR(SNAPSHOT_IOC_MAGIC, 7, void *) +#define SNAPSHOT_GET_SWAP_PAGE _IOR(SNAPSHOT_IOC_MAGIC, 8, void *) + + #define SNAPSHOT_MINOR 231 static struct snapshot_data { struct snapshot_handle handle; int swap; - struct bitmap_page *bitmap; int mode; char frozen; char ready; + char platform_support; } snapshot_state; -static atomic_t device_available = ATOMIC_INIT(1); +atomic_t snapshot_device_available = ATOMIC_INIT(1); static int snapshot_open(struct inode *inode, struct file *filp) { struct snapshot_data *data; + int error; - if (!atomic_add_unless(&device_available, -1, 0)) - return -EBUSY; + mutex_lock(&pm_mutex); - if ((filp->f_flags & O_ACCMODE) == O_RDWR) - return -ENOSYS; + if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { + error = -EBUSY; + goto Unlock; + } + if ((filp->f_flags & O_ACCMODE) == O_RDWR) { + atomic_inc(&snapshot_device_available); + error = -ENOSYS; + goto Unlock; + } + if(create_basic_memory_bitmaps()) { + atomic_inc(&snapshot_device_available); + error = -ENOMEM; + goto Unlock; + } nonseekable_open(inode, filp); data = &snapshot_state; filp->private_data = data; memset(&data->handle, 0, sizeof(struct snapshot_handle)); if ((filp->f_flags & O_ACCMODE) == O_RDONLY) { + /* Hibernating. The image device should be accessible. */ data->swap = swsusp_resume_device ? swap_type_of(swsusp_resume_device, 0, NULL) : -1; data->mode = O_RDONLY; + error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE); + if (error) + pm_notifier_call_chain(PM_POST_HIBERNATION); } else { + /* + * Resuming. We may need to wait for the image device to + * appear. + */ + wait_for_device_probe(); + scsi_complete_async_scans(); + data->swap = -1; data->mode = O_WRONLY; + error = pm_notifier_call_chain(PM_RESTORE_PREPARE); + if (error) + pm_notifier_call_chain(PM_POST_RESTORE); } - data->bitmap = NULL; + if (error) + atomic_inc(&snapshot_device_available); data->frozen = 0; data->ready = 0; + data->platform_support = 0; - return 0; + Unlock: + mutex_unlock(&pm_mutex); + + return error; } static int snapshot_release(struct inode *inode, struct file *filp) { struct snapshot_data *data; + mutex_lock(&pm_mutex); + swsusp_free(); + free_basic_memory_bitmaps(); data = filp->private_data; - free_all_swap_pages(data->swap, data->bitmap); - free_bitmap(data->bitmap); - if (data->frozen) { - mutex_lock(&pm_mutex); + free_all_swap_pages(data->swap); + if (data->frozen) thaw_processes(); - enable_nonboot_cpus(); - mutex_unlock(&pm_mutex); - } - atomic_inc(&device_available); + pm_notifier_call_chain(data->mode == O_WRONLY ? + PM_POST_HIBERNATION : PM_POST_RESTORE); + atomic_inc(&snapshot_device_available); + + mutex_unlock(&pm_mutex); + return 0; } @@ -94,7 +153,13 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf, struct snapshot_data *data; ssize_t res; + mutex_lock(&pm_mutex); + data = filp->private_data; + if (!data->ready) { + res = -ENODATA; + goto Unlock; + } res = snapshot_read_next(&data->handle, count); if (res > 0) { if (copy_to_user(buf, data_of(data->handle), res)) @@ -102,6 +167,10 @@ static ssize_t snapshot_read(struct file *filp, char __user *buf, else *offp = data->handle.offset; } + + Unlock: + mutex_unlock(&pm_mutex); + return res; } @@ -111,6 +180,8 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf, struct snapshot_data *data; ssize_t res; + mutex_lock(&pm_mutex); + data = filp->private_data; res = snapshot_write_next(&data->handle, count); if (res > 0) { @@ -119,68 +190,18 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf, else *offp = data->handle.offset; } - return res; -} - -static int snapshot_suspend(void) -{ - int error; - - mutex_lock(&pm_mutex); - /* Free memory before shutting down devices. */ - error = swsusp_shrink_memory(); - if (error) - goto Finish; - - suspend_console(); - error = device_suspend(PMSG_FREEZE); - if (error) - goto Resume_devices; - error = disable_nonboot_cpus(); - if (!error) { - in_suspend = 1; - error = swsusp_suspend(); - } - enable_nonboot_cpus(); - Resume_devices: - device_resume(); - resume_console(); - Finish: mutex_unlock(&pm_mutex); - return error; -} - -static int snapshot_restore(void) -{ - int error; - mutex_lock(&pm_mutex); - pm_prepare_console(); - suspend_console(); - error = device_suspend(PMSG_PRETHAW); - if (error) - goto Resume_devices; - - error = disable_nonboot_cpus(); - if (!error) - error = swsusp_resume(); - - enable_nonboot_cpus(); - Resume_devices: - device_resume(); - resume_console(); - pm_restore_console(); - mutex_unlock(&pm_mutex); - return error; + return res; } -static int snapshot_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +static long snapshot_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) { int error = 0; struct snapshot_data *data; - loff_t avail; + loff_t size; sector_t offset; if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC) @@ -190,6 +211,9 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (!mutex_trylock(&pm_mutex)) + return -EBUSY; + data = filp->private_data; switch (cmd) { @@ -197,33 +221,41 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, case SNAPSHOT_FREEZE: if (data->frozen) break; - mutex_lock(&pm_mutex); - if (freeze_processes()) { + + printk("Syncing filesystems ... "); + sys_sync(); + printk("done.\n"); + + error = usermodehelper_disable(); + if (error) + break; + + error = freeze_processes(); + if (error) { thaw_processes(); - error = -EBUSY; + usermodehelper_enable(); } - mutex_unlock(&pm_mutex); if (!error) data->frozen = 1; break; case SNAPSHOT_UNFREEZE: - if (!data->frozen) + if (!data->frozen || data->ready) break; - mutex_lock(&pm_mutex); thaw_processes(); - mutex_unlock(&pm_mutex); + usermodehelper_enable(); data->frozen = 0; break; + case SNAPSHOT_CREATE_IMAGE: case SNAPSHOT_ATOMIC_SNAPSHOT: if (data->mode != O_RDONLY || !data->frozen || data->ready) { error = -EPERM; break; } - error = snapshot_suspend(); + error = hibernation_snapshot(data->platform_support); if (!error) - error = put_user(in_suspend, (unsigned int __user *)arg); + error = put_user(in_suspend, (int __user *)arg); if (!error) data->ready = 1; break; @@ -235,7 +267,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, error = -EPERM; break; } - error = snapshot_restore(); + error = hibernation_restore(data->platform_support); break; case SNAPSHOT_FREE: @@ -244,32 +276,38 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, data->ready = 0; break; + case SNAPSHOT_PREF_IMAGE_SIZE: case SNAPSHOT_SET_IMAGE_SIZE: image_size = arg; break; + case SNAPSHOT_GET_IMAGE_SIZE: + if (!data->ready) { + error = -ENODATA; + break; + } + size = snapshot_get_image_size(); + size <<= PAGE_SHIFT; + error = put_user(size, (loff_t __user *)arg); + break; + + case SNAPSHOT_AVAIL_SWAP_SIZE: case SNAPSHOT_AVAIL_SWAP: - avail = count_swap_pages(data->swap, 1); - avail <<= PAGE_SHIFT; - error = put_user(avail, (loff_t __user *)arg); + size = count_swap_pages(data->swap, 1); + size <<= PAGE_SHIFT; + error = put_user(size, (loff_t __user *)arg); break; + case SNAPSHOT_ALLOC_SWAP_PAGE: case SNAPSHOT_GET_SWAP_PAGE: if (data->swap < 0 || data->swap >= MAX_SWAPFILES) { error = -ENODEV; break; } - if (!data->bitmap) { - data->bitmap = alloc_bitmap(count_swap_pages(data->swap, 0)); - if (!data->bitmap) { - error = -ENOMEM; - break; - } - } - offset = alloc_swapdev_block(data->swap, data->bitmap); + offset = alloc_swapdev_block(data->swap); if (offset) { offset <<= PAGE_SHIFT; - error = put_user(offset, (sector_t __user *)arg); + error = put_user(offset, (loff_t __user *)arg); } else { error = -ENOSPC; } @@ -280,13 +318,11 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, error = -ENODEV; break; } - free_all_swap_pages(data->swap, data->bitmap); - free_bitmap(data->bitmap); - data->bitmap = NULL; + free_all_swap_pages(data->swap); break; - case SNAPSHOT_SET_SWAP_FILE: - if (!data->bitmap) { + case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */ + if (!swsusp_swap_in_use()) { /* * User space encodes device types as two-byte values, * so we need to recode them @@ -310,67 +346,50 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, error = -EPERM; break; } + /* + * Tasks are frozen and the notifiers have been called with + * PM_HIBERNATION_PREPARE + */ + error = suspend_devices_and_enter(PM_SUSPEND_MEM); + break; - if (!mutex_trylock(&pm_mutex)) { - error = -EBUSY; - break; - } - - if (pm_ops->prepare) { - error = pm_ops->prepare(PM_SUSPEND_MEM); - if (error) - goto OutS3; - } - - /* Put devices to sleep */ - suspend_console(); - error = device_suspend(PMSG_SUSPEND); - if (error) { - printk(KERN_ERR "Failed to suspend some devices.\n"); - } else { - /* Enter S3, system is already frozen */ - suspend_enter(PM_SUSPEND_MEM); - - /* Wake up devices */ - device_resume(); - } - resume_console(); - if (pm_ops->finish) - pm_ops->finish(PM_SUSPEND_MEM); + case SNAPSHOT_PLATFORM_SUPPORT: + data->platform_support = !!arg; + break; - OutS3: - mutex_unlock(&pm_mutex); + case SNAPSHOT_POWER_OFF: + if (data->platform_support) + error = hibernation_platform_enter(); break; - case SNAPSHOT_PMOPS: + case SNAPSHOT_PMOPS: /* This ioctl is deprecated */ + error = -EINVAL; + switch (arg) { case PMOPS_PREPARE: - if (pm_ops->prepare) { - error = pm_ops->prepare(PM_SUSPEND_DISK); - } + data->platform_support = 1; + error = 0; break; case PMOPS_ENTER: - kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); - error = pm_ops->enter(PM_SUSPEND_DISK); + if (data->platform_support) + error = hibernation_platform_enter(); break; case PMOPS_FINISH: - if (pm_ops && pm_ops->finish) { - pm_ops->finish(PM_SUSPEND_DISK); - } + if (data->platform_support) + error = 0; break; default: printk(KERN_ERR "SNAPSHOT_PMOPS: invalid argument %ld\n", arg); - error = -EINVAL; } break; case SNAPSHOT_SET_SWAP_AREA: - if (data->bitmap) { + if (swsusp_swap_in_use()) { error = -EPERM; } else { struct resume_swap_area swap_area; @@ -405,6 +424,8 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, } + mutex_unlock(&pm_mutex); + return error; } @@ -414,7 +435,7 @@ static const struct file_operations snapshot_fops = { .read = snapshot_read, .write = snapshot_write, .llseek = no_llseek, - .ioctl = snapshot_ioctl, + .unlocked_ioctl = snapshot_ioctl, }; static struct miscdevice snapshot_device = {