aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/xen')
-rw-r--r--drivers/xen/Kconfig24
-rw-r--r--drivers/xen/Makefile2
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c28
-rw-r--r--drivers/xen/xenbus/xenbus_xs.c1
-rw-r--r--drivers/xen/xenfs/Makefile3
-rw-r--r--drivers/xen/xenfs/super.c64
-rw-r--r--drivers/xen/xenfs/xenbus.c593
-rw-r--r--drivers/xen/xenfs/xenfs.h6
8 files changed, 715 insertions, 6 deletions
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 4b75a16de009..526187c8a12d 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -17,3 +17,27 @@ config XEN_SCRUB_PAGES
17 is not accidentally visible to other domains. Is it more 17 is not accidentally visible to other domains. Is it more
18 secure, but slightly less efficient. 18 secure, but slightly less efficient.
19 If in doubt, say yes. 19 If in doubt, say yes.
20
21config XENFS
22 tristate "Xen filesystem"
23 depends on XEN
24 default y
25 help
26 The xen filesystem provides a way for domains to share
27 information with each other and with the hypervisor.
28 For example, by reading and writing the "xenbus" file, guests
29 may pass arbitrary information to the initial domain.
30 If in doubt, say yes.
31
32config XEN_COMPAT_XENFS
33 bool "Create compatibility mount point /proc/xen"
34 depends on XENFS
35 default y
36 help
37 The old xenstore userspace tools expect to find "xenbus"
38 under /proc/xen, but "xenbus" is now found at the root of the
39 xenfs filesystem. Selecting this causes the kernel to create
40 the compatibilty mount point /proc/xen if it is running on
41 a xen platform.
42 If in doubt, say yes.
43
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index d2a8fdf0e191..ff8accc9e103 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -1,5 +1,7 @@
1obj-y += grant-table.o features.o events.o manage.o 1obj-y += grant-table.o features.o events.o manage.o
2obj-y += xenbus/ 2obj-y += xenbus/
3
3obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o 4obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
4obj-$(CONFIG_XEN_XENCOMM) += xencomm.o 5obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
5obj-$(CONFIG_XEN_BALLOON) += balloon.o 6obj-$(CONFIG_XEN_BALLOON) += balloon.o
7obj-$(CONFIG_XENFS) += xenfs/ \ No newline at end of file
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index b2a03184a246..773d1cf23283 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -40,6 +40,7 @@
40#include <linux/ctype.h> 40#include <linux/ctype.h>
41#include <linux/fcntl.h> 41#include <linux/fcntl.h>
42#include <linux/mm.h> 42#include <linux/mm.h>
43#include <linux/proc_fs.h>
43#include <linux/notifier.h> 44#include <linux/notifier.h>
44#include <linux/kthread.h> 45#include <linux/kthread.h>
45#include <linux/mutex.h> 46#include <linux/mutex.h>
@@ -55,7 +56,10 @@
55#include "xenbus_comms.h" 56#include "xenbus_comms.h"
56#include "xenbus_probe.h" 57#include "xenbus_probe.h"
57 58
59
58int xen_store_evtchn; 60int xen_store_evtchn;
61EXPORT_SYMBOL(xen_store_evtchn);
62
59struct xenstore_domain_interface *xen_store_interface; 63struct xenstore_domain_interface *xen_store_interface;
60static unsigned long xen_store_mfn; 64static unsigned long xen_store_mfn;
61 65
@@ -166,6 +170,9 @@ static int read_backend_details(struct xenbus_device *xendev)
166 return read_otherend_details(xendev, "backend-id", "backend"); 170 return read_otherend_details(xendev, "backend-id", "backend");
167} 171}
168 172
173static struct device_attribute xenbus_dev_attrs[] = {
174 __ATTR_NULL
175};
169 176
170/* Bus type for frontend drivers. */ 177/* Bus type for frontend drivers. */
171static struct xen_bus_type xenbus_frontend = { 178static struct xen_bus_type xenbus_frontend = {
@@ -174,12 +181,13 @@ static struct xen_bus_type xenbus_frontend = {
174 .get_bus_id = frontend_bus_id, 181 .get_bus_id = frontend_bus_id,
175 .probe = xenbus_probe_frontend, 182 .probe = xenbus_probe_frontend,
176 .bus = { 183 .bus = {
177 .name = "xen", 184 .name = "xen",
178 .match = xenbus_match, 185 .match = xenbus_match,
179 .uevent = xenbus_uevent, 186 .uevent = xenbus_uevent,
180 .probe = xenbus_dev_probe, 187 .probe = xenbus_dev_probe,
181 .remove = xenbus_dev_remove, 188 .remove = xenbus_dev_remove,
182 .shutdown = xenbus_dev_shutdown, 189 .shutdown = xenbus_dev_shutdown,
190 .dev_attrs = xenbus_dev_attrs,
183 }, 191 },
184}; 192};
185 193
@@ -852,6 +860,14 @@ static int __init xenbus_probe_init(void)
852 if (!xen_initial_domain()) 860 if (!xen_initial_domain())
853 xenbus_probe(NULL); 861 xenbus_probe(NULL);
854 862
863#ifdef CONFIG_XEN_COMPAT_XENFS
864 /*
865 * Create xenfs mountpoint in /proc for compatibility with
866 * utilities that expect to find "xenbus" under "/proc/xen".
867 */
868 proc_mkdir("xen", NULL);
869#endif
870
855 return 0; 871 return 0;
856 872
857 out_unreg_back: 873 out_unreg_back:
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
index 7f2f91c0e11d..e325eab4724d 100644
--- a/drivers/xen/xenbus/xenbus_xs.c
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -184,6 +184,7 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
184 184
185 return ret; 185 return ret;
186} 186}
187EXPORT_SYMBOL(xenbus_dev_request_and_reply);
187 188
188/* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ 189/* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */
189static void *xs_talkv(struct xenbus_transaction t, 190static void *xs_talkv(struct xenbus_transaction t,
diff --git a/drivers/xen/xenfs/Makefile b/drivers/xen/xenfs/Makefile
new file mode 100644
index 000000000000..25275c3bbdff
--- /dev/null
+++ b/drivers/xen/xenfs/Makefile
@@ -0,0 +1,3 @@
1obj-$(CONFIG_XENFS) += xenfs.o
2
3xenfs-objs = super.o xenbus.o \ No newline at end of file
diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c
new file mode 100644
index 000000000000..515741a8e6b8
--- /dev/null
+++ b/drivers/xen/xenfs/super.c
@@ -0,0 +1,64 @@
1/*
2 * xenfs.c - a filesystem for passing info between the a domain and
3 * the hypervisor.
4 *
5 * 2008-10-07 Alex Zeffertt Replaced /proc/xen/xenbus with xenfs filesystem
6 * and /proc/xen compatibility mount point.
7 * Turned xenfs into a loadable module.
8 */
9
10#include <linux/kernel.h>
11#include <linux/errno.h>
12#include <linux/module.h>
13#include <linux/fs.h>
14#include <linux/magic.h>
15
16#include "xenfs.h"
17
18#include <asm/xen/hypervisor.h>
19
20MODULE_DESCRIPTION("Xen filesystem");
21MODULE_LICENSE("GPL");
22
23static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
24{
25 static struct tree_descr xenfs_files[] = {
26 [2] = {"xenbus", &xenbus_file_ops, S_IRUSR|S_IWUSR},
27 {""},
28 };
29
30 return simple_fill_super(sb, XENFS_SUPER_MAGIC, xenfs_files);
31}
32
33static int xenfs_get_sb(struct file_system_type *fs_type,
34 int flags, const char *dev_name,
35 void *data, struct vfsmount *mnt)
36{
37 return get_sb_single(fs_type, flags, data, xenfs_fill_super, mnt);
38}
39
40static struct file_system_type xenfs_type = {
41 .owner = THIS_MODULE,
42 .name = "xenfs",
43 .get_sb = xenfs_get_sb,
44 .kill_sb = kill_litter_super,
45};
46
47static int __init xenfs_init(void)
48{
49 if (xen_pv_domain())
50 return register_filesystem(&xenfs_type);
51
52 printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n");
53 return 0;
54}
55
56static void __exit xenfs_exit(void)
57{
58 if (xen_pv_domain())
59 unregister_filesystem(&xenfs_type);
60}
61
62module_init(xenfs_init);
63module_exit(xenfs_exit);
64
diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c
new file mode 100644
index 000000000000..875a4c59c594
--- /dev/null
+++ b/drivers/xen/xenfs/xenbus.c
@@ -0,0 +1,593 @@
1/*
2 * Driver giving user-space access to the kernel's xenbus connection
3 * to xenstore.
4 *
5 * Copyright (c) 2005, Christian Limpach
6 * Copyright (c) 2005, Rusty Russell, IBM Corporation
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation; or, when distributed
11 * separately from the Linux kernel or incorporated into other
12 * software packages, subject to the following license:
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this source file (the "Software"), to deal in the Software without
16 * restriction, including without limitation the rights to use, copy, modify,
17 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18 * and to permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30 * IN THE SOFTWARE.
31 *
32 * Changes:
33 * 2008-10-07 Alex Zeffertt Replaced /proc/xen/xenbus with xenfs filesystem
34 * and /proc/xen compatibility mount point.
35 * Turned xenfs into a loadable module.
36 */
37
38#include <linux/kernel.h>
39#include <linux/errno.h>
40#include <linux/uio.h>
41#include <linux/notifier.h>
42#include <linux/wait.h>
43#include <linux/fs.h>
44#include <linux/poll.h>
45#include <linux/mutex.h>
46#include <linux/spinlock.h>
47#include <linux/mount.h>
48#include <linux/pagemap.h>
49#include <linux/uaccess.h>
50#include <linux/init.h>
51#include <linux/namei.h>
52#include <linux/string.h>
53
54#include "xenfs.h"
55#include "../xenbus/xenbus_comms.h"
56
57#include <xen/xenbus.h>
58#include <asm/xen/hypervisor.h>
59
60/*
61 * An element of a list of outstanding transactions, for which we're
62 * still waiting a reply.
63 */
64struct xenbus_transaction_holder {
65 struct list_head list;
66 struct xenbus_transaction handle;
67};
68
69/*
70 * A buffer of data on the queue.
71 */
72struct read_buffer {
73 struct list_head list;
74 unsigned int cons;
75 unsigned int len;
76 char msg[];
77};
78
79struct xenbus_file_priv {
80 /*
81 * msgbuffer_mutex is held while partial requests are built up
82 * and complete requests are acted on. It therefore protects
83 * the "transactions" and "watches" lists, and the partial
84 * request length and buffer.
85 *
86 * reply_mutex protects the reply being built up to return to
87 * usermode. It nests inside msgbuffer_mutex but may be held
88 * alone during a watch callback.
89 */
90 struct mutex msgbuffer_mutex;
91
92 /* In-progress transactions */
93 struct list_head transactions;
94
95 /* Active watches. */
96 struct list_head watches;
97
98 /* Partial request. */
99 unsigned int len;
100 union {
101 struct xsd_sockmsg msg;
102 char buffer[PAGE_SIZE];
103 } u;
104
105 /* Response queue. */
106 struct mutex reply_mutex;
107 struct list_head read_buffers;
108 wait_queue_head_t read_waitq;
109
110};
111
112/* Read out any raw xenbus messages queued up. */
113static ssize_t xenbus_file_read(struct file *filp,
114 char __user *ubuf,
115 size_t len, loff_t *ppos)
116{
117 struct xenbus_file_priv *u = filp->private_data;
118 struct read_buffer *rb;
119 unsigned i;
120 int ret;
121
122 mutex_lock(&u->reply_mutex);
123 while (list_empty(&u->read_buffers)) {
124 mutex_unlock(&u->reply_mutex);
125 ret = wait_event_interruptible(u->read_waitq,
126 !list_empty(&u->read_buffers));
127 if (ret)
128 return ret;
129 mutex_lock(&u->reply_mutex);
130 }
131
132 rb = list_entry(u->read_buffers.next, struct read_buffer, list);
133 i = 0;
134 while (i < len) {
135 unsigned sz = min((unsigned)len - i, rb->len - rb->cons);
136
137 ret = copy_to_user(ubuf + i, &rb->msg[rb->cons], sz);
138
139 i += sz - ret;
140 rb->cons += sz - ret;
141
142 if (ret != sz) {
143 if (i == 0)
144 i = -EFAULT;
145 goto out;
146 }
147
148 /* Clear out buffer if it has been consumed */
149 if (rb->cons == rb->len) {
150 list_del(&rb->list);
151 kfree(rb);
152 if (list_empty(&u->read_buffers))
153 break;
154 rb = list_entry(u->read_buffers.next,
155 struct read_buffer, list);
156 }
157 }
158
159out:
160 mutex_unlock(&u->reply_mutex);
161 return i;
162}
163
164/*
165 * Add a buffer to the queue. Caller must hold the appropriate lock
166 * if the queue is not local. (Commonly the caller will build up
167 * multiple queued buffers on a temporary local list, and then add it
168 * to the appropriate list under lock once all the buffers have een
169 * successfully allocated.)
170 */
171static int queue_reply(struct list_head *queue, const void *data, size_t len)
172{
173 struct read_buffer *rb;
174
175 if (len == 0)
176 return 0;
177
178 rb = kmalloc(sizeof(*rb) + len, GFP_KERNEL);
179 if (rb == NULL)
180 return -ENOMEM;
181
182 rb->cons = 0;
183 rb->len = len;
184
185 memcpy(rb->msg, data, len);
186
187 list_add_tail(&rb->list, queue);
188 return 0;
189}
190
191/*
192 * Free all the read_buffer s on a list.
193 * Caller must have sole reference to list.
194 */
195static void queue_cleanup(struct list_head *list)
196{
197 struct read_buffer *rb;
198
199 while (!list_empty(list)) {
200 rb = list_entry(list->next, struct read_buffer, list);
201 list_del(list->next);
202 kfree(rb);
203 }
204}
205
206struct watch_adapter {
207 struct list_head list;
208 struct xenbus_watch watch;
209 struct xenbus_file_priv *dev_data;
210 char *token;
211};
212
213static void free_watch_adapter(struct watch_adapter *watch)
214{
215 kfree(watch->watch.node);
216 kfree(watch->token);
217 kfree(watch);
218}
219
220static struct watch_adapter *alloc_watch_adapter(const char *path,
221 const char *token)
222{
223 struct watch_adapter *watch;
224
225 watch = kzalloc(sizeof(*watch), GFP_KERNEL);
226 if (watch == NULL)
227 goto out_fail;
228
229 watch->watch.node = kstrdup(path, GFP_KERNEL);
230 if (watch->watch.node == NULL)
231 goto out_free;
232
233 watch->token = kstrdup(token, GFP_KERNEL);
234 if (watch->token == NULL)
235 goto out_free;
236
237 return watch;
238
239out_free:
240 free_watch_adapter(watch);
241
242out_fail:
243 return NULL;
244}
245
246static void watch_fired(struct xenbus_watch *watch,
247 const char **vec,
248 unsigned int len)
249{
250 struct watch_adapter *adap;
251 struct xsd_sockmsg hdr;
252 const char *path, *token;
253 int path_len, tok_len, body_len, data_len = 0;
254 int ret;
255 LIST_HEAD(staging_q);
256
257 adap = container_of(watch, struct watch_adapter, watch);
258
259 path = vec[XS_WATCH_PATH];
260 token = adap->token;
261
262 path_len = strlen(path) + 1;
263 tok_len = strlen(token) + 1;
264 if (len > 2)
265 data_len = vec[len] - vec[2] + 1;
266 body_len = path_len + tok_len + data_len;
267
268 hdr.type = XS_WATCH_EVENT;
269 hdr.len = body_len;
270
271 mutex_lock(&adap->dev_data->reply_mutex);
272
273 ret = queue_reply(&staging_q, &hdr, sizeof(hdr));
274 if (!ret)
275 ret = queue_reply(&staging_q, path, path_len);
276 if (!ret)
277 ret = queue_reply(&staging_q, token, tok_len);
278 if (!ret && len > 2)
279 ret = queue_reply(&staging_q, vec[2], data_len);
280
281 if (!ret) {
282 /* success: pass reply list onto watcher */
283 list_splice_tail(&staging_q, &adap->dev_data->read_buffers);
284 wake_up(&adap->dev_data->read_waitq);
285 } else
286 queue_cleanup(&staging_q);
287
288 mutex_unlock(&adap->dev_data->reply_mutex);
289}
290
291static int xenbus_write_transaction(unsigned msg_type,
292 struct xenbus_file_priv *u)
293{
294 int rc, ret;
295 void *reply;
296 struct xenbus_transaction_holder *trans = NULL;
297 LIST_HEAD(staging_q);
298
299 if (msg_type == XS_TRANSACTION_START) {
300 trans = kmalloc(sizeof(*trans), GFP_KERNEL);
301 if (!trans) {
302 rc = -ENOMEM;
303 goto out;
304 }
305 }
306
307 reply = xenbus_dev_request_and_reply(&u->u.msg);
308 if (IS_ERR(reply)) {
309 kfree(trans);
310 rc = PTR_ERR(reply);
311 goto out;
312 }
313
314 if (msg_type == XS_TRANSACTION_START) {
315 trans->handle.id = simple_strtoul(reply, NULL, 0);
316
317 list_add(&trans->list, &u->transactions);
318 } else if (msg_type == XS_TRANSACTION_END) {
319 list_for_each_entry(trans, &u->transactions, list)
320 if (trans->handle.id == u->u.msg.tx_id)
321 break;
322 BUG_ON(&trans->list == &u->transactions);
323 list_del(&trans->list);
324
325 kfree(trans);
326 }
327
328 mutex_lock(&u->reply_mutex);
329 ret = queue_reply(&staging_q, &u->u.msg, sizeof(u->u.msg));
330 if (!ret)
331 ret = queue_reply(&staging_q, reply, u->u.msg.len);
332 if (!ret) {
333 list_splice_tail(&staging_q, &u->read_buffers);
334 wake_up(&u->read_waitq);
335 } else {
336 queue_cleanup(&staging_q);
337 rc = ret;
338 }
339 mutex_unlock(&u->reply_mutex);
340
341 kfree(reply);
342
343out:
344 return rc;
345}
346
347static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u)
348{
349 struct watch_adapter *watch, *tmp_watch;
350 char *path, *token;
351 int err, rc;
352 LIST_HEAD(staging_q);
353
354 path = u->u.buffer + sizeof(u->u.msg);
355 token = memchr(path, 0, u->u.msg.len);
356 if (token == NULL) {
357 rc = -EILSEQ;
358 goto out;
359 }
360 token++;
361
362 if (msg_type == XS_WATCH) {
363 watch = alloc_watch_adapter(path, token);
364 if (watch == NULL) {
365 rc = -ENOMEM;
366 goto out;
367 }
368
369 watch->watch.callback = watch_fired;
370 watch->dev_data = u;
371
372 err = register_xenbus_watch(&watch->watch);
373 if (err) {
374 free_watch_adapter(watch);
375 rc = err;
376 goto out;
377 }
378 list_add(&watch->list, &u->watches);
379 } else {
380 list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
381 if (!strcmp(watch->token, token) &&
382 !strcmp(watch->watch.node, path)) {
383 unregister_xenbus_watch(&watch->watch);
384 list_del(&watch->list);
385 free_watch_adapter(watch);
386 break;
387 }
388 }
389 }
390
391 /* Success. Synthesize a reply to say all is OK. */
392 {
393 struct {
394 struct xsd_sockmsg hdr;
395 char body[3];
396 } __packed reply = {
397 {
398 .type = msg_type,
399 .len = sizeof(reply.body)
400 },
401 "OK"
402 };
403
404 mutex_lock(&u->reply_mutex);
405 rc = queue_reply(&u->read_buffers, &reply, sizeof(reply));
406 mutex_unlock(&u->reply_mutex);
407 }
408
409out:
410 return rc;
411}
412
413static ssize_t xenbus_file_write(struct file *filp,
414 const char __user *ubuf,
415 size_t len, loff_t *ppos)
416{
417 struct xenbus_file_priv *u = filp->private_data;
418 uint32_t msg_type;
419 int rc = len;
420 int ret;
421 LIST_HEAD(staging_q);
422
423 /*
424 * We're expecting usermode to be writing properly formed
425 * xenbus messages. If they write an incomplete message we
426 * buffer it up. Once it is complete, we act on it.
427 */
428
429 /*
430 * Make sure concurrent writers can't stomp all over each
431 * other's messages and make a mess of our partial message
432 * buffer. We don't make any attemppt to stop multiple
433 * writers from making a mess of each other's incomplete
434 * messages; we're just trying to guarantee our own internal
435 * consistency and make sure that single writes are handled
436 * atomically.
437 */
438 mutex_lock(&u->msgbuffer_mutex);
439
440 /* Get this out of the way early to avoid confusion */
441 if (len == 0)
442 goto out;
443
444 /* Can't write a xenbus message larger we can buffer */
445 if ((len + u->len) > sizeof(u->u.buffer)) {
446 /* On error, dump existing buffer */
447 u->len = 0;
448 rc = -EINVAL;
449 goto out;
450 }
451
452 ret = copy_from_user(u->u.buffer + u->len, ubuf, len);
453
454 if (ret == len) {
455 rc = -EFAULT;
456 goto out;
457 }
458
459 /* Deal with a partial copy. */
460 len -= ret;
461 rc = len;
462
463 u->len += len;
464
465 /* Return if we haven't got a full message yet */
466 if (u->len < sizeof(u->u.msg))
467 goto out; /* not even the header yet */
468
469 /* If we're expecting a message that's larger than we can
470 possibly send, dump what we have and return an error. */
471 if ((sizeof(u->u.msg) + u->u.msg.len) > sizeof(u->u.buffer)) {
472 rc = -E2BIG;
473 u->len = 0;
474 goto out;
475 }
476
477 if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
478 goto out; /* incomplete data portion */
479
480 /*
481 * OK, now we have a complete message. Do something with it.
482 */
483
484 msg_type = u->u.msg.type;
485
486 switch (msg_type) {
487 case XS_TRANSACTION_START:
488 case XS_TRANSACTION_END:
489 case XS_DIRECTORY:
490 case XS_READ:
491 case XS_GET_PERMS:
492 case XS_RELEASE:
493 case XS_GET_DOMAIN_PATH:
494 case XS_WRITE:
495 case XS_MKDIR:
496 case XS_RM:
497 case XS_SET_PERMS:
498 /* Send out a transaction */
499 ret = xenbus_write_transaction(msg_type, u);
500 break;
501
502 case XS_WATCH:
503 case XS_UNWATCH:
504 /* (Un)Ask for some path to be watched for changes */
505 ret = xenbus_write_watch(msg_type, u);
506 break;
507
508 default:
509 ret = -EINVAL;
510 break;
511 }
512 if (ret != 0)
513 rc = ret;
514
515 /* Buffered message consumed */
516 u->len = 0;
517
518 out:
519 mutex_unlock(&u->msgbuffer_mutex);
520 return rc;
521}
522
523static int xenbus_file_open(struct inode *inode, struct file *filp)
524{
525 struct xenbus_file_priv *u;
526
527 if (xen_store_evtchn == 0)
528 return -ENOENT;
529
530 nonseekable_open(inode, filp);
531
532 u = kzalloc(sizeof(*u), GFP_KERNEL);
533 if (u == NULL)
534 return -ENOMEM;
535
536 INIT_LIST_HEAD(&u->transactions);
537 INIT_LIST_HEAD(&u->watches);
538 INIT_LIST_HEAD(&u->read_buffers);
539 init_waitqueue_head(&u->read_waitq);
540
541 mutex_init(&u->reply_mutex);
542 mutex_init(&u->msgbuffer_mutex);
543
544 filp->private_data = u;
545
546 return 0;
547}
548
549static int xenbus_file_release(struct inode *inode, struct file *filp)
550{
551 struct xenbus_file_priv *u = filp->private_data;
552 struct xenbus_transaction_holder *trans, *tmp;
553 struct watch_adapter *watch, *tmp_watch;
554
555 /*
556 * No need for locking here because there are no other users,
557 * by definition.
558 */
559
560 list_for_each_entry_safe(trans, tmp, &u->transactions, list) {
561 xenbus_transaction_end(trans->handle, 1);
562 list_del(&trans->list);
563 kfree(trans);
564 }
565
566 list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
567 unregister_xenbus_watch(&watch->watch);
568 list_del(&watch->list);
569 free_watch_adapter(watch);
570 }
571
572 kfree(u);
573
574 return 0;
575}
576
577static unsigned int xenbus_file_poll(struct file *file, poll_table *wait)
578{
579 struct xenbus_file_priv *u = file->private_data;
580
581 poll_wait(file, &u->read_waitq, wait);
582 if (!list_empty(&u->read_buffers))
583 return POLLIN | POLLRDNORM;
584 return 0;
585}
586
587const struct file_operations xenbus_file_ops = {
588 .read = xenbus_file_read,
589 .write = xenbus_file_write,
590 .open = xenbus_file_open,
591 .release = xenbus_file_release,
592 .poll = xenbus_file_poll,
593};
diff --git a/drivers/xen/xenfs/xenfs.h b/drivers/xen/xenfs/xenfs.h
new file mode 100644
index 000000000000..51f08b2d0bf1
--- /dev/null
+++ b/drivers/xen/xenfs/xenfs.h
@@ -0,0 +1,6 @@
1#ifndef _XENFS_XENBUS_H
2#define _XENFS_XENBUS_H
3
4extern const struct file_operations xenbus_file_ops;
5
6#endif /* _XENFS_XENBUS_H */