diff options
Diffstat (limited to 'drivers/s390/char/vmcp.c')
-rw-r--r-- | drivers/s390/char/vmcp.c | 41 |
1 files changed, 17 insertions, 24 deletions
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 2f419b0ea628..09e7d9bf438b 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/miscdevice.h> | 17 | #include <linux/miscdevice.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/smp_lock.h> | ||
19 | #include <asm/cpcmd.h> | 20 | #include <asm/cpcmd.h> |
20 | #include <asm/debug.h> | 21 | #include <asm/debug.h> |
21 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
@@ -39,11 +40,14 @@ static int vmcp_open(struct inode *inode, struct file *file) | |||
39 | session = kmalloc(sizeof(*session), GFP_KERNEL); | 40 | session = kmalloc(sizeof(*session), GFP_KERNEL); |
40 | if (!session) | 41 | if (!session) |
41 | return -ENOMEM; | 42 | return -ENOMEM; |
43 | |||
44 | lock_kernel(); | ||
42 | session->bufsize = PAGE_SIZE; | 45 | session->bufsize = PAGE_SIZE; |
43 | session->response = NULL; | 46 | session->response = NULL; |
44 | session->resp_size = 0; | 47 | session->resp_size = 0; |
45 | mutex_init(&session->mutex); | 48 | mutex_init(&session->mutex); |
46 | file->private_data = session; | 49 | file->private_data = session; |
50 | unlock_kernel(); | ||
47 | return nonseekable_open(inode, file); | 51 | return nonseekable_open(inode, file); |
48 | } | 52 | } |
49 | 53 | ||
@@ -61,30 +65,24 @@ static int vmcp_release(struct inode *inode, struct file *file) | |||
61 | static ssize_t | 65 | static ssize_t |
62 | vmcp_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) | 66 | vmcp_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) |
63 | { | 67 | { |
64 | size_t tocopy; | 68 | ssize_t ret; |
69 | size_t size; | ||
65 | struct vmcp_session *session; | 70 | struct vmcp_session *session; |
66 | 71 | ||
67 | session = (struct vmcp_session *)file->private_data; | 72 | session = file->private_data; |
68 | if (mutex_lock_interruptible(&session->mutex)) | 73 | if (mutex_lock_interruptible(&session->mutex)) |
69 | return -ERESTARTSYS; | 74 | return -ERESTARTSYS; |
70 | if (!session->response) { | 75 | if (!session->response) { |
71 | mutex_unlock(&session->mutex); | 76 | mutex_unlock(&session->mutex); |
72 | return 0; | 77 | return 0; |
73 | } | 78 | } |
74 | if (*ppos > session->resp_size) { | 79 | size = min_t(size_t, session->resp_size, session->bufsize); |
75 | mutex_unlock(&session->mutex); | 80 | ret = simple_read_from_buffer(buff, count, ppos, |
76 | return 0; | 81 | session->response, size); |
77 | } | ||
78 | tocopy = min(session->resp_size - (size_t) (*ppos), count); | ||
79 | tocopy = min(tocopy, session->bufsize - (size_t) (*ppos)); | ||
80 | 82 | ||
81 | if (copy_to_user(buff, session->response + (*ppos), tocopy)) { | ||
82 | mutex_unlock(&session->mutex); | ||
83 | return -EFAULT; | ||
84 | } | ||
85 | mutex_unlock(&session->mutex); | 83 | mutex_unlock(&session->mutex); |
86 | *ppos += tocopy; | 84 | |
87 | return tocopy; | 85 | return ret; |
88 | } | 86 | } |
89 | 87 | ||
90 | static ssize_t | 88 | static ssize_t |
@@ -198,27 +196,23 @@ static int __init vmcp_init(void) | |||
198 | PRINT_WARN("z/VM CP interface is only available under z/VM\n"); | 196 | PRINT_WARN("z/VM CP interface is only available under z/VM\n"); |
199 | return -ENODEV; | 197 | return -ENODEV; |
200 | } | 198 | } |
199 | |||
201 | vmcp_debug = debug_register("vmcp", 1, 1, 240); | 200 | vmcp_debug = debug_register("vmcp", 1, 1, 240); |
202 | if (!vmcp_debug) { | 201 | if (!vmcp_debug) |
203 | PRINT_ERR("z/VM CP interface not loaded. Could not register " | ||
204 | "debug feature\n"); | ||
205 | return -ENOMEM; | 202 | return -ENOMEM; |
206 | } | 203 | |
207 | ret = debug_register_view(vmcp_debug, &debug_hex_ascii_view); | 204 | ret = debug_register_view(vmcp_debug, &debug_hex_ascii_view); |
208 | if (ret) { | 205 | if (ret) { |
209 | PRINT_ERR("z/VM CP interface not loaded. Could not register " | ||
210 | "debug feature view. Error code: %d\n", ret); | ||
211 | debug_unregister(vmcp_debug); | 206 | debug_unregister(vmcp_debug); |
212 | return ret; | 207 | return ret; |
213 | } | 208 | } |
209 | |||
214 | ret = misc_register(&vmcp_dev); | 210 | ret = misc_register(&vmcp_dev); |
215 | if (ret) { | 211 | if (ret) { |
216 | PRINT_ERR("z/VM CP interface not loaded. Could not register " | ||
217 | "misc device. Error code: %d\n", ret); | ||
218 | debug_unregister(vmcp_debug); | 212 | debug_unregister(vmcp_debug); |
219 | return ret; | 213 | return ret; |
220 | } | 214 | } |
221 | PRINT_INFO("z/VM CP interface loaded\n"); | 215 | |
222 | return 0; | 216 | return 0; |
223 | } | 217 | } |
224 | 218 | ||
@@ -226,7 +220,6 @@ static void __exit vmcp_exit(void) | |||
226 | { | 220 | { |
227 | misc_deregister(&vmcp_dev); | 221 | misc_deregister(&vmcp_dev); |
228 | debug_unregister(vmcp_debug); | 222 | debug_unregister(vmcp_debug); |
229 | PRINT_INFO("z/VM CP interface unloaded.\n"); | ||
230 | } | 223 | } |
231 | 224 | ||
232 | module_init(vmcp_init); | 225 | module_init(vmcp_init); |