Contents of /trunk/kernel26-xen/patches-2.6.25-r1/1014-2.6.25-xen-Add-proc-xen-xenbus.patch
Parent Directory | Revision Log
Revision 606 -
(show annotations)
(download)
Thu May 22 23:13:13 2008 UTC (15 years, 11 months ago) by niro
File size: 14237 byte(s)
Thu May 22 23:13:13 2008 UTC (15 years, 11 months ago) by niro
File size: 14237 byte(s)
-ver bump to 2.6.25-magellan-r1: - linux-2.6.25.4 - fbcondecor-0.9.4 - squashfs-3.3 - unionfs-2.3.3 - tuxonice-3.0-rc7 - linux-phc-0.3.0 - acpi-dstd-0.9a - reiser4 - xen-3.2.0 . ipw3945-1.2.2
1 | From 8b4585c4677d8e9e58a1e156b113494abd74c541 Mon Sep 17 00:00:00 2001 |
2 | From: Mark McLoughlin <markmc@redhat.com> |
3 | Date: Mon, 4 Feb 2008 22:04:36 +0000 |
4 | Subject: [PATCH] xen: Add /proc/xen/xenbus |
5 | |
6 | This interface is used by userspace programs to talk to |
7 | xenstored. |
8 | |
9 | Since xenstored makes itself available to Dom0 userspace |
10 | via a socket this should only really be useful in Domu, |
11 | but it turns out that Dom0 apps historically default |
12 | to using /proc/xen/xenbus rather than the socket. |
13 | |
14 | Signed-off-by: Mark McLoughlin <markmc@redhat.com> |
15 | --- |
16 | drivers/xen/xenbus/xenbus_comms.h | 1 - |
17 | drivers/xen/xenbus/xenbus_probe.c | 2 + |
18 | drivers/xen/xenbus/xenbus_xs.c | 1 + |
19 | drivers/xen/xenctrl/Makefile | 1 + |
20 | drivers/xen/xenctrl/main.c | 6 + |
21 | drivers/xen/xenctrl/xenbus.c | 398 +++++++++++++++++++++++++++++++++++++ |
22 | drivers/xen/xenctrl/xenctrl.h | 6 + |
23 | include/xen/xenbus.h | 2 + |
24 | 8 files changed, 416 insertions(+), 1 deletions(-) |
25 | create mode 100644 drivers/xen/xenctrl/xenbus.c |
26 | |
27 | diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h |
28 | index c21db75..fcc9b29 100644 |
29 | --- a/drivers/xen/xenbus/xenbus_comms.h |
30 | +++ b/drivers/xen/xenbus/xenbus_comms.h |
31 | @@ -41,6 +41,5 @@ int xb_data_to_read(void); |
32 | int xb_wait_for_data_to_read(void); |
33 | int xs_input_avail(void); |
34 | extern struct xenstore_domain_interface *xen_store_interface; |
35 | -extern int xen_store_evtchn; |
36 | |
37 | #endif /* _XENBUS_COMMS_H */ |
38 | diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c |
39 | index 57ceb53..c811581 100644 |
40 | --- a/drivers/xen/xenbus/xenbus_probe.c |
41 | +++ b/drivers/xen/xenbus/xenbus_probe.c |
42 | @@ -56,6 +56,8 @@ |
43 | #include "xenbus_probe.h" |
44 | |
45 | int xen_store_evtchn; |
46 | +EXPORT_SYMBOL_GPL(xen_store_evtchn); |
47 | + |
48 | struct xenstore_domain_interface *xen_store_interface; |
49 | static unsigned long xen_store_mfn; |
50 | |
51 | diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c |
52 | index 227d53b..810e24a 100644 |
53 | --- a/drivers/xen/xenbus/xenbus_xs.c |
54 | +++ b/drivers/xen/xenbus/xenbus_xs.c |
55 | @@ -184,6 +184,7 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) |
56 | |
57 | return ret; |
58 | } |
59 | +EXPORT_SYMBOL(xenbus_dev_request_and_reply); |
60 | |
61 | /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ |
62 | static void *xs_talkv(struct xenbus_transaction t, |
63 | diff --git a/drivers/xen/xenctrl/Makefile b/drivers/xen/xenctrl/Makefile |
64 | index 8a706cb..23dafa3 100644 |
65 | --- a/drivers/xen/xenctrl/Makefile |
66 | +++ b/drivers/xen/xenctrl/Makefile |
67 | @@ -4,3 +4,4 @@ xenctrl-objs = |
68 | xenctrl-objs += main.o |
69 | xenctrl-objs += capabilities.o |
70 | xenctrl-objs += privcmd.o |
71 | +xenctrl-objs += xenbus.o |
72 | diff --git a/drivers/xen/xenctrl/main.c b/drivers/xen/xenctrl/main.c |
73 | index d1fe6ef..b0cf61b 100644 |
74 | --- a/drivers/xen/xenctrl/main.c |
75 | +++ b/drivers/xen/xenctrl/main.c |
76 | @@ -59,8 +59,13 @@ static int __init xenctrl_init(void) |
77 | if (ret) |
78 | goto fail2; |
79 | |
80 | + ret = xenbus_create_proc_entry(); |
81 | + if (ret) |
82 | + goto fail3; |
83 | + |
84 | return 0; |
85 | |
86 | + fail3: privcmd_remove_proc_entry(); |
87 | fail2: capabilities_remove_proc_entry(); |
88 | fail1: remove_proc_entry("xen", NULL); |
89 | return ret; |
90 | @@ -68,6 +73,7 @@ static int __init xenctrl_init(void) |
91 | |
92 | static void __exit xenctrl_exit(void) |
93 | { |
94 | + xenbus_remove_proc_entry(); |
95 | privcmd_remove_proc_entry(); |
96 | capabilities_remove_proc_entry(); |
97 | remove_proc_entry("xen", NULL); |
98 | diff --git a/drivers/xen/xenctrl/xenbus.c b/drivers/xen/xenctrl/xenbus.c |
99 | new file mode 100644 |
100 | index 0000000..57d5501 |
101 | --- /dev/null |
102 | +++ b/drivers/xen/xenctrl/xenbus.c |
103 | @@ -0,0 +1,398 @@ |
104 | +/* |
105 | + * xenbus.c |
106 | + * |
107 | + * /proc/xen/xenbus gives user-space access to the kernel's xenbus |
108 | + * connection to xenstore. |
109 | + * |
110 | + * Copyright (c) 2005, Christian Limpach |
111 | + * Copyright (c) 2005, Rusty Russell, IBM Corporation |
112 | + * |
113 | + * This program is free software; you can redistribute it and/or |
114 | + * modify it under the terms of the GNU General Public License version 2 |
115 | + * as published by the Free Software Foundation; or, when distributed |
116 | + * separately from the Linux kernel or incorporated into other |
117 | + * software packages, subject to the following license: |
118 | + * |
119 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
120 | + * of this source file (the "Software"), to deal in the Software without |
121 | + * restriction, including without limitation the rights to use, copy, modify, |
122 | + * merge, publish, distribute, sublicense, and/or sell copies of the Software, |
123 | + * and to permit persons to whom the Software is furnished to do so, subject to |
124 | + * the following conditions: |
125 | + * |
126 | + * The above copyright notice and this permission notice shall be included in |
127 | + * all copies or substantial portions of the Software. |
128 | + * |
129 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
130 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
131 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
132 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
133 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
134 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
135 | + * IN THE SOFTWARE. |
136 | + */ |
137 | + |
138 | +#include <linux/proc_fs.h> |
139 | +#include <linux/module.h> |
140 | +#include <linux/uaccess.h> |
141 | +#include <linux/poll.h> |
142 | + |
143 | +#include <xen/xenbus.h> |
144 | + |
145 | +struct xenbus_dev_transaction { |
146 | + struct list_head list; |
147 | + struct xenbus_transaction handle; |
148 | +}; |
149 | + |
150 | +struct read_buffer { |
151 | + struct list_head list; |
152 | + unsigned int cons; |
153 | + unsigned int len; |
154 | + char msg[]; |
155 | +}; |
156 | + |
157 | +struct xenbus_dev_data { |
158 | + /* In-progress transaction. */ |
159 | + struct list_head transactions; |
160 | + |
161 | + /* Active watches. */ |
162 | + struct list_head watches; |
163 | + |
164 | + /* Partial request. */ |
165 | + unsigned int len; |
166 | + union { |
167 | + struct xsd_sockmsg msg; |
168 | + char buffer[PAGE_SIZE]; |
169 | + } u; |
170 | + |
171 | + /* Response queue. */ |
172 | + struct list_head read_buffers; |
173 | + wait_queue_head_t read_waitq; |
174 | + |
175 | + struct mutex reply_mutex; |
176 | +}; |
177 | + |
178 | +static ssize_t xenbus_dev_read(struct file *filp, |
179 | + char __user *ubuf, |
180 | + size_t len, loff_t *ppos) |
181 | +{ |
182 | + struct xenbus_dev_data *u = filp->private_data; |
183 | + struct read_buffer *rb; |
184 | + int i, ret; |
185 | + |
186 | + mutex_lock(&u->reply_mutex); |
187 | + while (list_empty(&u->read_buffers)) { |
188 | + mutex_unlock(&u->reply_mutex); |
189 | + ret = wait_event_interruptible(u->read_waitq, |
190 | + !list_empty(&u->read_buffers)); |
191 | + if (ret) |
192 | + return ret; |
193 | + mutex_lock(&u->reply_mutex); |
194 | + } |
195 | + |
196 | + rb = list_entry(u->read_buffers.next, struct read_buffer, list); |
197 | + for (i = 0; i < len;) { |
198 | + put_user(rb->msg[rb->cons], ubuf + i); |
199 | + i++; |
200 | + rb->cons++; |
201 | + if (rb->cons == rb->len) { |
202 | + list_del(&rb->list); |
203 | + kfree(rb); |
204 | + if (list_empty(&u->read_buffers)) |
205 | + break; |
206 | + rb = list_entry(u->read_buffers.next, |
207 | + struct read_buffer, list); |
208 | + } |
209 | + } |
210 | + mutex_unlock(&u->reply_mutex); |
211 | + |
212 | + return i; |
213 | +} |
214 | + |
215 | +static void queue_reply(struct xenbus_dev_data *u, |
216 | + char *data, unsigned int len) |
217 | +{ |
218 | + struct read_buffer *rb; |
219 | + |
220 | + if (len == 0) |
221 | + return; |
222 | + |
223 | + rb = kmalloc(sizeof(*rb) + len, GFP_KERNEL); |
224 | + BUG_ON(rb == NULL); |
225 | + |
226 | + rb->cons = 0; |
227 | + rb->len = len; |
228 | + |
229 | + memcpy(rb->msg, data, len); |
230 | + |
231 | + list_add_tail(&rb->list, &u->read_buffers); |
232 | + |
233 | + wake_up(&u->read_waitq); |
234 | +} |
235 | + |
236 | +struct watch_adapter |
237 | +{ |
238 | + struct list_head list; |
239 | + struct xenbus_watch watch; |
240 | + struct xenbus_dev_data *dev_data; |
241 | + char *token; |
242 | +}; |
243 | + |
244 | +static void free_watch_adapter(struct watch_adapter *watch) |
245 | +{ |
246 | + kfree(watch->watch.node); |
247 | + kfree(watch->token); |
248 | + kfree(watch); |
249 | +} |
250 | + |
251 | +static void watch_fired(struct xenbus_watch *watch, |
252 | + const char **vec, |
253 | + unsigned int len) |
254 | +{ |
255 | + struct watch_adapter *adap = |
256 | + container_of(watch, struct watch_adapter, watch); |
257 | + struct xsd_sockmsg hdr; |
258 | + const char *path, *token; |
259 | + int path_len, tok_len, body_len; |
260 | + |
261 | + path = vec[XS_WATCH_PATH]; |
262 | + token = adap->token; |
263 | + |
264 | + path_len = strlen(path) + 1; |
265 | + tok_len = strlen(token) + 1; |
266 | + body_len = path_len + tok_len; |
267 | + |
268 | + hdr.type = XS_WATCH_EVENT; |
269 | + hdr.len = body_len; |
270 | + |
271 | + mutex_lock(&adap->dev_data->reply_mutex); |
272 | + queue_reply(adap->dev_data, (char *)&hdr, sizeof(hdr)); |
273 | + queue_reply(adap->dev_data, (char *)path, path_len); |
274 | + queue_reply(adap->dev_data, (char *)token, tok_len); |
275 | + mutex_unlock(&adap->dev_data->reply_mutex); |
276 | +} |
277 | + |
278 | +static LIST_HEAD(watch_list); |
279 | + |
280 | +static ssize_t xenbus_dev_write(struct file *filp, |
281 | + const char __user *ubuf, |
282 | + size_t len, loff_t *ppos) |
283 | +{ |
284 | + struct xenbus_dev_data *u = filp->private_data; |
285 | + struct xenbus_dev_transaction *trans = NULL; |
286 | + uint32_t msg_type; |
287 | + void *reply; |
288 | + char *path, *token; |
289 | + struct watch_adapter *watch, *tmp_watch; |
290 | + int err, rc = len; |
291 | + |
292 | + if ((len + u->len) > sizeof(u->u.buffer)) { |
293 | + rc = -EINVAL; |
294 | + goto out; |
295 | + } |
296 | + |
297 | + if (copy_from_user(u->u.buffer + u->len, ubuf, len) != 0) { |
298 | + rc = -EFAULT; |
299 | + goto out; |
300 | + } |
301 | + |
302 | + u->len += len; |
303 | + if ((u->len < sizeof(u->u.msg)) || |
304 | + (u->len < (sizeof(u->u.msg) + u->u.msg.len))) |
305 | + return rc; |
306 | + |
307 | + msg_type = u->u.msg.type; |
308 | + |
309 | + switch (msg_type) { |
310 | + case XS_TRANSACTION_START: |
311 | + case XS_TRANSACTION_END: |
312 | + case XS_DIRECTORY: |
313 | + case XS_READ: |
314 | + case XS_GET_PERMS: |
315 | + case XS_RELEASE: |
316 | + case XS_GET_DOMAIN_PATH: |
317 | + case XS_WRITE: |
318 | + case XS_MKDIR: |
319 | + case XS_RM: |
320 | + case XS_SET_PERMS: |
321 | + if (msg_type == XS_TRANSACTION_START) { |
322 | + trans = kmalloc(sizeof(*trans), GFP_KERNEL); |
323 | + if (!trans) { |
324 | + rc = -ENOMEM; |
325 | + goto out; |
326 | + } |
327 | + } |
328 | + |
329 | + reply = xenbus_dev_request_and_reply(&u->u.msg); |
330 | + if (IS_ERR(reply)) { |
331 | + kfree(trans); |
332 | + rc = PTR_ERR(reply); |
333 | + goto out; |
334 | + } |
335 | + |
336 | + if (msg_type == XS_TRANSACTION_START) { |
337 | + trans->handle.id = simple_strtoul(reply, NULL, 0); |
338 | + list_add(&trans->list, &u->transactions); |
339 | + } else if (msg_type == XS_TRANSACTION_END) { |
340 | + list_for_each_entry(trans, &u->transactions, list) |
341 | + if (trans->handle.id == u->u.msg.tx_id) |
342 | + break; |
343 | + BUG_ON(&trans->list == &u->transactions); |
344 | + list_del(&trans->list); |
345 | + kfree(trans); |
346 | + } |
347 | + mutex_lock(&u->reply_mutex); |
348 | + queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); |
349 | + queue_reply(u, (char *)reply, u->u.msg.len); |
350 | + mutex_unlock(&u->reply_mutex); |
351 | + kfree(reply); |
352 | + break; |
353 | + |
354 | + case XS_WATCH: |
355 | + case XS_UNWATCH: { |
356 | + static const char *XS_RESP = "OK"; |
357 | + struct xsd_sockmsg hdr; |
358 | + |
359 | + path = u->u.buffer + sizeof(u->u.msg); |
360 | + token = memchr(path, 0, u->u.msg.len); |
361 | + if (token == NULL) { |
362 | + rc = -EILSEQ; |
363 | + goto out; |
364 | + } |
365 | + token++; |
366 | + |
367 | + if (msg_type == XS_WATCH) { |
368 | + watch = kmalloc(sizeof(*watch), GFP_KERNEL); |
369 | + watch->watch.node = kmalloc(strlen(path)+1, |
370 | + GFP_KERNEL); |
371 | + strcpy((char *)watch->watch.node, path); |
372 | + watch->watch.callback = watch_fired; |
373 | + watch->token = kmalloc(strlen(token)+1, GFP_KERNEL); |
374 | + strcpy(watch->token, token); |
375 | + watch->dev_data = u; |
376 | + |
377 | + err = register_xenbus_watch(&watch->watch); |
378 | + if (err) { |
379 | + free_watch_adapter(watch); |
380 | + rc = err; |
381 | + goto out; |
382 | + } |
383 | + |
384 | + list_add(&watch->list, &u->watches); |
385 | + } else { |
386 | + list_for_each_entry_safe(watch, tmp_watch, |
387 | + &u->watches, list) { |
388 | + if (!strcmp(watch->token, token) && |
389 | + !strcmp(watch->watch.node, path)) |
390 | + { |
391 | + unregister_xenbus_watch(&watch->watch); |
392 | + list_del(&watch->list); |
393 | + free_watch_adapter(watch); |
394 | + break; |
395 | + } |
396 | + } |
397 | + } |
398 | + |
399 | + hdr.type = msg_type; |
400 | + hdr.len = strlen(XS_RESP) + 1; |
401 | + mutex_lock(&u->reply_mutex); |
402 | + queue_reply(u, (char *)&hdr, sizeof(hdr)); |
403 | + queue_reply(u, (char *)XS_RESP, hdr.len); |
404 | + mutex_unlock(&u->reply_mutex); |
405 | + break; |
406 | + } |
407 | + |
408 | + default: |
409 | + rc = -EINVAL; |
410 | + break; |
411 | + } |
412 | + |
413 | + out: |
414 | + u->len = 0; |
415 | + return rc; |
416 | +} |
417 | + |
418 | +static int xenbus_dev_open(struct inode *inode, struct file *filp) |
419 | +{ |
420 | + struct xenbus_dev_data *u; |
421 | + |
422 | + if (xen_store_evtchn == 0) |
423 | + return -ENOENT; |
424 | + |
425 | + nonseekable_open(inode, filp); |
426 | + |
427 | + u = kzalloc(sizeof(*u), GFP_KERNEL); |
428 | + if (u == NULL) |
429 | + return -ENOMEM; |
430 | + |
431 | + INIT_LIST_HEAD(&u->transactions); |
432 | + INIT_LIST_HEAD(&u->watches); |
433 | + INIT_LIST_HEAD(&u->read_buffers); |
434 | + init_waitqueue_head(&u->read_waitq); |
435 | + |
436 | + mutex_init(&u->reply_mutex); |
437 | + |
438 | + filp->private_data = u; |
439 | + |
440 | + return 0; |
441 | +} |
442 | + |
443 | +static int xenbus_dev_release(struct inode *inode, struct file *filp) |
444 | +{ |
445 | + struct xenbus_dev_data *u = filp->private_data; |
446 | + struct xenbus_dev_transaction *trans, *tmp; |
447 | + struct watch_adapter *watch, *tmp_watch; |
448 | + |
449 | + list_for_each_entry_safe(trans, tmp, &u->transactions, list) { |
450 | + xenbus_transaction_end(trans->handle, 1); |
451 | + list_del(&trans->list); |
452 | + kfree(trans); |
453 | + } |
454 | + |
455 | + list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) { |
456 | + unregister_xenbus_watch(&watch->watch); |
457 | + list_del(&watch->list); |
458 | + free_watch_adapter(watch); |
459 | + } |
460 | + |
461 | + kfree(u); |
462 | + |
463 | + return 0; |
464 | +} |
465 | + |
466 | +static unsigned int xenbus_dev_poll(struct file *file, poll_table *wait) |
467 | +{ |
468 | + struct xenbus_dev_data *u = file->private_data; |
469 | + |
470 | + poll_wait(file, &u->read_waitq, wait); |
471 | + if (!list_empty(&u->read_buffers)) |
472 | + return POLLIN | POLLRDNORM; |
473 | + return 0; |
474 | +} |
475 | + |
476 | +static const struct file_operations xenbus_dev_file_ops = { |
477 | + .read = xenbus_dev_read, |
478 | + .write = xenbus_dev_write, |
479 | + .open = xenbus_dev_open, |
480 | + .release = xenbus_dev_release, |
481 | + .poll = xenbus_dev_poll, |
482 | +}; |
483 | + |
484 | +int __init xenbus_create_proc_entry(void) |
485 | +{ |
486 | + struct proc_dir_entry *entry; |
487 | + |
488 | + entry = create_proc_entry("xen/xenbus", 0400, NULL); |
489 | + if (!entry) |
490 | + return -ENOMEM; |
491 | + |
492 | + entry->owner = THIS_MODULE; |
493 | + entry->proc_fops = &xenbus_dev_file_ops; |
494 | + |
495 | + return 0; |
496 | +} |
497 | + |
498 | +void __exit xenbus_remove_proc_entry(void) |
499 | +{ |
500 | + remove_proc_entry("xen/xenbus", NULL); |
501 | +} |
502 | diff --git a/drivers/xen/xenctrl/xenctrl.h b/drivers/xen/xenctrl/xenctrl.h |
503 | index a35209a..e585c4b 100644 |
504 | --- a/drivers/xen/xenctrl/xenctrl.h |
505 | +++ b/drivers/xen/xenctrl/xenctrl.h |
506 | @@ -43,3 +43,9 @@ void capabilities_remove_proc_entry(void) __exit; |
507 | */ |
508 | int privcmd_create_proc_entry(void) __init; |
509 | void privcmd_remove_proc_entry(void) __exit; |
510 | + |
511 | +/* |
512 | + * xenbus.c |
513 | + */ |
514 | +int xenbus_create_proc_entry(void) __init; |
515 | +void xenbus_remove_proc_entry(void) __exit; |
516 | diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h |
517 | index 6369d89..a3fef9d 100644 |
518 | --- a/include/xen/xenbus.h |
519 | +++ b/include/xen/xenbus.h |
520 | @@ -232,4 +232,6 @@ const char *xenbus_strstate(enum xenbus_state state); |
521 | int xenbus_dev_is_online(struct xenbus_device *dev); |
522 | int xenbus_frontend_closed(struct xenbus_device *dev); |
523 | |
524 | +extern int xen_store_evtchn; |
525 | + |
526 | #endif /* _XEN_XENBUS_H */ |
527 | -- |
528 | 1.5.4.1 |
529 |