ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c @ 8515:e93340cf4d02

test return value of kmalloc to prevent crash is the allocation fail.

Signed-off-by: Vincent Hanquez <vincent@xensource.com>
author vhanquez@kneesa.uk.xensource.com
date Fri Jan 06 22:07:04 2006 +0000 (2006-01-06)
parents a933d82321b3
children 96c7303b03ab
line source
1 /*
2 * xenbus_dev.c
3 *
4 * Driver giving user-space access to the kernel's xenbus connection
5 * to xenstore.
6 *
7 * Copyright (c) 2005, Christian Limpach
8 * Copyright (c) 2005, Rusty Russell, IBM Corporation
9 *
10 * This file may be distributed separately from the Linux kernel, or
11 * incorporated into other software packages, subject to the following license:
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a copy
14 * of this source file (the "Software"), to deal in the Software without
15 * restriction, including without limitation the rights to use, copy, modify,
16 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
17 * and to permit persons to whom the Software is furnished to do so, subject to
18 * the following conditions:
19 *
20 * The above copyright notice and this permission notice shall be included in
21 * all copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
29 * IN THE SOFTWARE.
30 */
32 #include <linux/config.h>
33 #include <linux/kernel.h>
34 #include <linux/errno.h>
35 #include <linux/uio.h>
36 #include <linux/notifier.h>
37 #include <linux/wait.h>
38 #include <linux/fs.h>
40 #include "xenbus_comms.h"
42 #include <asm/uaccess.h>
43 #include <asm/hypervisor.h>
44 #include <asm-xen/xenbus.h>
45 #include <asm-xen/xen_proc.h>
46 #include <asm/hypervisor.h>
48 struct xenbus_dev_transaction {
49 struct list_head list;
50 struct xenbus_transaction *handle;
51 };
53 struct xenbus_dev_data {
54 /* In-progress transaction. */
55 struct list_head transactions;
57 /* Partial request. */
58 unsigned int len;
59 union {
60 struct xsd_sockmsg msg;
61 char buffer[PAGE_SIZE];
62 } u;
64 /* Response queue. */
65 #define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1))
66 char read_buffer[PAGE_SIZE];
67 unsigned int read_cons, read_prod;
68 wait_queue_head_t read_waitq;
69 };
71 static struct proc_dir_entry *xenbus_dev_intf;
73 static ssize_t xenbus_dev_read(struct file *filp,
74 char __user *ubuf,
75 size_t len, loff_t *ppos)
76 {
77 struct xenbus_dev_data *u = filp->private_data;
78 int i;
80 if (wait_event_interruptible(u->read_waitq,
81 u->read_prod != u->read_cons))
82 return -EINTR;
84 for (i = 0; i < len; i++) {
85 if (u->read_cons == u->read_prod)
86 break;
87 put_user(u->read_buffer[MASK_READ_IDX(u->read_cons)], ubuf+i);
88 u->read_cons++;
89 }
91 return i;
92 }
94 static void queue_reply(struct xenbus_dev_data *u,
95 char *data, unsigned int len)
96 {
97 int i;
99 for (i = 0; i < len; i++, u->read_prod++)
100 u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
102 BUG_ON((u->read_prod - u->read_cons) > sizeof(u->read_buffer));
104 wake_up(&u->read_waitq);
105 }
107 static ssize_t xenbus_dev_write(struct file *filp,
108 const char __user *ubuf,
109 size_t len, loff_t *ppos)
110 {
111 struct xenbus_dev_data *u = filp->private_data;
112 struct xenbus_dev_transaction *trans;
113 void *reply;
115 if ((len + u->len) > sizeof(u->u.buffer))
116 return -EINVAL;
118 if (copy_from_user(u->u.buffer + u->len, ubuf, len) != 0)
119 return -EFAULT;
121 u->len += len;
122 if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
123 return len;
125 switch (u->u.msg.type) {
126 case XS_TRANSACTION_START:
127 case XS_TRANSACTION_END:
128 case XS_DIRECTORY:
129 case XS_READ:
130 case XS_GET_PERMS:
131 case XS_RELEASE:
132 case XS_GET_DOMAIN_PATH:
133 case XS_WRITE:
134 case XS_MKDIR:
135 case XS_RM:
136 case XS_SET_PERMS:
137 reply = xenbus_dev_request_and_reply(&u->u.msg);
138 if (IS_ERR(reply))
139 return PTR_ERR(reply);
141 if (u->u.msg.type == XS_TRANSACTION_START) {
142 trans = kmalloc(sizeof(*trans), GFP_KERNEL);
143 if (!trans)
144 return -ENOMEM;
145 trans->handle = (struct xenbus_transaction *)
146 simple_strtoul(reply, NULL, 0);
147 list_add(&trans->list, &u->transactions);
148 } else if (u->u.msg.type == XS_TRANSACTION_END) {
149 list_for_each_entry(trans, &u->transactions, list)
150 if ((unsigned long)trans->handle ==
151 (unsigned long)u->u.msg.tx_id)
152 break;
153 BUG_ON(&trans->list == &u->transactions);
154 list_del(&trans->list);
155 kfree(trans);
156 }
157 queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
158 queue_reply(u, (char *)reply, u->u.msg.len);
159 kfree(reply);
160 break;
162 default:
163 return -EINVAL;
164 }
166 u->len = 0;
167 return len;
168 }
170 static int xenbus_dev_open(struct inode *inode, struct file *filp)
171 {
172 struct xenbus_dev_data *u;
174 if (xen_start_info->store_evtchn == 0)
175 return -ENOENT;
177 nonseekable_open(inode, filp);
179 u = kmalloc(sizeof(*u), GFP_KERNEL);
180 if (u == NULL)
181 return -ENOMEM;
183 memset(u, 0, sizeof(*u));
184 INIT_LIST_HEAD(&u->transactions);
185 init_waitqueue_head(&u->read_waitq);
187 filp->private_data = u;
189 return 0;
190 }
192 static int xenbus_dev_release(struct inode *inode, struct file *filp)
193 {
194 struct xenbus_dev_data *u = filp->private_data;
195 struct xenbus_dev_transaction *trans, *tmp;
197 list_for_each_entry_safe(trans, tmp, &u->transactions, list) {
198 xenbus_transaction_end(trans->handle, 1);
199 list_del(&trans->list);
200 kfree(trans);
201 }
203 kfree(u);
205 return 0;
206 }
208 static struct file_operations xenbus_dev_file_ops = {
209 .read = xenbus_dev_read,
210 .write = xenbus_dev_write,
211 .open = xenbus_dev_open,
212 .release = xenbus_dev_release,
213 };
215 static int __init
216 xenbus_dev_init(void)
217 {
218 xenbus_dev_intf = create_xen_proc_entry("xenbus", 0400);
219 if (xenbus_dev_intf)
220 xenbus_dev_intf->proc_fops = &xenbus_dev_file_ops;
222 return 0;
223 }
225 __initcall(xenbus_dev_init);
227 /*
228 * Local variables:
229 * c-file-style: "linux"
230 * indent-tabs-mode: t
231 * c-indent-level: 8
232 * c-basic-offset: 8
233 * tab-width: 8
234 * End:
235 */