diff options
Diffstat (limited to 'drivers/s390/char/vmcp.c')
| -rw-r--r-- | drivers/s390/char/vmcp.c | 146 |
1 files changed, 69 insertions, 77 deletions
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 19762f3476a..0fdedadff7b 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -1,30 +1,29 @@ /* - * Copyright (C) 2004,2005 IBM Corporation - * Interface implementation for communication with the v/VM control program - * Author(s): Christian Borntraeger <cborntra@de.ibm.com> + * Copyright IBM Corp. 2004, 2010 + * Interface implementation for communication with the z/VM control program * + * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> * * z/VMs CP offers the possibility to issue commands via the diagnose code 8 * this driver implements a character device that issues these commands and * returns the answer of CP. - + * * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS */ #include <linux/fs.h> #include <linux/init.h> +#include <linux/compat.h> #include <linux/kernel.h> #include <linux/miscdevice.h> -#include <linux/module.h> +#include <linux/slab.h> +#include <linux/export.h> +#include <asm/compat.h> #include <asm/cpcmd.h> #include <asm/debug.h> #include <asm/uaccess.h> #include "vmcp.h" -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Christian Borntraeger <cborntra@de.ibm.com>"); -MODULE_DESCRIPTION("z/VM CP interface"); - static debug_info_t *vmcp_debug; static int vmcp_open(struct inode *inode, struct file *file) @@ -37,10 +36,11 @@ static int vmcp_open(struct inode *inode, struct file *file) session = kmalloc(sizeof(*session), GFP_KERNEL); if (!session) return -ENOMEM; + session->bufsize = PAGE_SIZE; session->response = NULL; session->resp_size = 0; - init_MUTEX(&session->mutex); + mutex_init(&session->mutex); file->private_data = session; return nonseekable_open(inode, file); } @@ -49,7 +49,7 @@ static int vmcp_release(struct inode *inode, struct file *file) { struct vmcp_session *session; - session = (struct vmcp_session *)file->private_data; + session = file->private_data; file->private_data = NULL; free_pages((unsigned long)session->response, get_order(session->bufsize)); kfree(session); @@ -57,37 +57,31 @@ static int vmcp_release(struct inode *inode, struct file *file) } static ssize_t -vmcp_read(struct file *file, char __user * buff, size_t count, loff_t * ppos) +vmcp_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) { - size_t tocopy; + ssize_t ret; + size_t size; struct vmcp_session *session; - session = (struct vmcp_session *)file->private_data; - if (down_interruptible(&session->mutex)) + session = file->private_data; + if (mutex_lock_interruptible(&session->mutex)) return -ERESTARTSYS; if (!session->response) { - up(&session->mutex); - return 0; - } - if (*ppos > session->resp_size) { - up(&session->mutex); + mutex_unlock(&session->mutex); return 0; } - tocopy = min(session->resp_size - (size_t) (*ppos), count); - tocopy = min(tocopy,session->bufsize - (size_t) (*ppos)); + size = min_t(size_t, session->resp_size, session->bufsize); + ret = simple_read_from_buffer(buff, count, ppos, + session->response, size); - if (copy_to_user(buff, session->response + (*ppos), tocopy)) { - up(&session->mutex); - return -EFAULT; - } - up(&session->mutex); - *ppos += tocopy; - return tocopy; + mutex_unlock(&session->mutex); + + return ret; } static ssize_t -vmcp_write(struct file *file, const char __user * buff, size_t count, - loff_t * ppos) +vmcp_write(struct file *file, const char __user *buff, size_t count, + loff_t *ppos) { char *cmd; struct vmcp_session *session; @@ -102,25 +96,24 @@ vmcp_write(struct file *file, const char __user * buff, size_t count, return -EFAULT; } cmd[count] = '\0'; - session = (struct vmcp_session *)file->private_data; - if (down_interruptible(&session->mutex)) { + session = file->private_data; + if (mutex_lock_interruptible(&session->mutex)) { kfree(cmd); return -ERESTARTSYS; } if (!session->response) session->response = (char *)__get_free_pages(GFP_KERNEL - | __GFP_REPEAT | GFP_DMA, + | __GFP_REPEAT | GFP_DMA, get_order(session->bufsize)); if (!session->response) { - up(&session->mutex); + mutex_unlock(&session->mutex); kfree(cmd); return -ENOMEM; } debug_text_event(vmcp_debug, 1, cmd); - session->resp_size = __cpcmd(cmd, session->response, - session->bufsize, - &session->resp_code); - up(&session->mutex); + session->resp_size = cpcmd(cmd, session->response, session->bufsize, + &session->resp_code); + mutex_unlock(&session->mutex); kfree(cmd); *ppos = 0; /* reset the file pointer after a command */ return count; @@ -142,46 +135,51 @@ vmcp_write(struct file *file, const char __user * buff, size_t count, static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct vmcp_session *session; + int __user *argp; int temp; - session = (struct vmcp_session *)file->private_data; - if (down_interruptible(&session->mutex)) + session = file->private_data; + if (is_compat_task()) + argp = compat_ptr(arg); + else + argp = (int __user *)arg; + if (mutex_lock_interruptible(&session->mutex)) return -ERESTARTSYS; switch (cmd) { case VMCP_GETCODE: temp = session->resp_code; - up(&session->mutex); - return put_user(temp, (int __user *)arg); + mutex_unlock(&session->mutex); + return put_user(temp, argp); case VMCP_SETBUF: free_pages((unsigned long)session->response, get_order(session->bufsize)); session->response=NULL; - temp = get_user(session->bufsize, (int __user *)arg); + temp = get_user(session->bufsize, argp); if (get_order(session->bufsize) > 8) { session->bufsize = PAGE_SIZE; temp = -EINVAL; } - up(&session->mutex); + mutex_unlock(&session->mutex); return temp; case VMCP_GETSIZE: temp = session->resp_size; - up(&session->mutex); - return put_user(temp, (int __user *)arg); + mutex_unlock(&session->mutex); + return put_user(temp, argp); default: - up(&session->mutex); + mutex_unlock(&session->mutex); return -ENOIOCTLCMD; } } -static struct file_operations vmcp_fops = { +static const struct file_operations vmcp_fops = { .owner = THIS_MODULE, - .open = &vmcp_open, - .release = &vmcp_release, - .read = &vmcp_read, - .llseek = &no_llseek, - .write = &vmcp_write, - .unlocked_ioctl = &vmcp_ioctl, - .compat_ioctl = &vmcp_ioctl + .open = vmcp_open, + .release = vmcp_release, + .read = vmcp_read, + .write = vmcp_write, + .unlocked_ioctl = vmcp_ioctl, + .compat_ioctl = vmcp_ioctl, + .llseek = no_llseek, }; static struct miscdevice vmcp_dev = { @@ -194,28 +192,22 @@ static int __init vmcp_init(void) { int ret; - if (!MACHINE_IS_VM) { - printk(KERN_WARNING - "z/VM CP interface is only available under z/VM\n"); - return -ENODEV; + if (!MACHINE_IS_VM) + return 0; + + vmcp_debug = debug_register("vmcp", 1, 1, 240); + if (!vmcp_debug) + return -ENOMEM; + + ret = debug_register_view(vmcp_debug, &debug_hex_ascii_view); + if (ret) { + debug_unregister(vmcp_debug); + return ret; } + ret = misc_register(&vmcp_dev); - if (!ret) - printk(KERN_INFO "z/VM CP interface loaded\n"); - else - printk(KERN_WARNING - "z/VM CP interface not loaded. Could not register misc device.\n"); - vmcp_debug = debug_register("vmcp", 1, 1, 240); - debug_register_view(vmcp_debug, &debug_hex_ascii_view); + if (ret) + debug_unregister(vmcp_debug); return ret; } - -static void __exit vmcp_exit(void) -{ - WARN_ON(misc_deregister(&vmcp_dev) != 0); - debug_unregister(vmcp_debug); - printk(KERN_INFO "z/VM CP interface unloaded.\n"); -} - -module_init(vmcp_init); -module_exit(vmcp_exit); +device_initcall(vmcp_init); |
