# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID 9a4a560d0a23eb8cc8474ff422b8e3a2735e993a
# Parent 153e69eae6655c648f4acee0b05ea4a8c0aeb808
[LINUX] Allows userspace tools on a domU to set up a watch on the xenstore.
It does this by intercepting XS_WATCH requests written
to /proc/xen/xenbus and then re-submitting the request to the
in-kernel xenstore interface, in
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c. When a callback
occurs, an in-kernel function is invoked, which then reconstructs a
response in the format expected by userspace, and sends this response
through /proc/xen/xenbus.
It was necessary to add some supporting infrastructure to
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c, such as an
additional mutex to protect the response queue and a list of active
watches associated with each connection.
Signed-off-by: Michael LeMay <mdlemay@xxxxxxxxxxxxxx>
---
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c | 114 +++++++++++++++++++
1 files changed, 114 insertions(+)
diff -r 153e69eae665 -r 9a4a560d0a23
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c Wed Aug 02
15:00:39 2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c Wed Aug 02
15:01:59 2006 +0100
@@ -58,6 +58,9 @@ struct xenbus_dev_data {
/* In-progress transaction. */
struct list_head transactions;
+ /* Active watches. */
+ struct list_head watches;
+
/* Partial request. */
unsigned int len;
union {
@@ -70,6 +73,8 @@ struct xenbus_dev_data {
char read_buffer[PAGE_SIZE];
unsigned int read_cons, read_prod;
wait_queue_head_t read_waitq;
+
+ struct mutex reply_mutex;
};
static struct proc_dir_entry *xenbus_dev_intf;
@@ -100,13 +105,59 @@ static void queue_reply(struct xenbus_de
{
int i;
+ mutex_lock(&u->reply_mutex);
+
for (i = 0; i < len; i++, u->read_prod++)
u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
BUG_ON((u->read_prod - u->read_cons) > sizeof(u->read_buffer));
+ mutex_unlock(&u->reply_mutex);
+
wake_up(&u->read_waitq);
}
+
+struct watch_adapter
+{
+ struct list_head list;
+ struct xenbus_watch watch;
+ struct xenbus_dev_data *dev_data;
+ char *token;
+};
+
+static void free_watch_adapter (struct watch_adapter *watch)
+{
+ kfree(watch->watch.node);
+ kfree(watch->token);
+ kfree(watch);
+}
+
+static void watch_fired(struct xenbus_watch *watch,
+ const char **vec,
+ unsigned int len)
+{
+ struct watch_adapter *adap =
+ container_of(watch, struct watch_adapter, watch);
+ struct xsd_sockmsg hdr;
+ const char *path, *token;
+ int path_len, tok_len, body_len;
+
+ path = vec[XS_WATCH_PATH];
+ token = adap->token;
+
+ path_len = strlen(path) + 1;
+ tok_len = strlen(token) + 1;
+ body_len = path_len + tok_len;
+
+ hdr.type = XS_WATCH_EVENT;
+ hdr.len = body_len;
+
+ queue_reply(adap->dev_data, (char *)&hdr, sizeof(hdr));
+ queue_reply(adap->dev_data, (char *)path, path_len);
+ queue_reply(adap->dev_data, (char *)token, tok_len);
+}
+
+static LIST_HEAD(watch_list);
static ssize_t xenbus_dev_write(struct file *filp,
const char __user *ubuf,
@@ -116,6 +167,9 @@ static ssize_t xenbus_dev_write(struct f
struct xenbus_dev_transaction *trans = NULL;
uint32_t msg_type;
void *reply;
+ char *path, *token;
+ struct watch_adapter *watch, *tmp_watch;
+ int err;
if ((len + u->len) > sizeof(u->u.buffer))
return -EINVAL;
@@ -169,6 +223,56 @@ static ssize_t xenbus_dev_write(struct f
kfree(reply);
break;
+ case XS_WATCH:
+ case XS_UNWATCH:
+ path = u->u.buffer + sizeof(u->u.msg);
+ token = memchr(path, 0, u->u.msg.len);
+ if (token == NULL)
+ return -EILSEQ;
+ token++;
+
+ if (msg_type == XS_WATCH) {
+ static const char * XS_WATCH_RESP = "OK";
+ struct xsd_sockmsg hdr;
+
+ watch = kmalloc(sizeof(*watch), GFP_KERNEL);
+ watch->watch.node = kmalloc(strlen(path)+1,
+ GFP_KERNEL);
+ strcpy((char *)watch->watch.node, path);
+ watch->watch.callback = watch_fired;
+ watch->token = kmalloc(strlen(token)+1, GFP_KERNEL);
+ strcpy(watch->token, token);
+ watch->dev_data = u;
+
+ err = register_xenbus_watch(&watch->watch);
+ if (err) {
+ free_watch_adapter(watch);
+ return err;
+ }
+
+ list_add(&watch->list, &u->watches);
+
+ hdr.type = XS_WATCH;
+ hdr.len = strlen(XS_WATCH_RESP) + 1;
+ queue_reply(u, (char *)&hdr, sizeof(hdr));
+ queue_reply(u, (char *)XS_WATCH_RESP, hdr.len);
+ } else {
+ list_for_each_entry_safe(watch, tmp_watch,
+ &u->watches, list) {
+ if (!strcmp(watch->token, token) &&
+ !strcmp(watch->watch.node, path))
+ break;
+ {
+ unregister_xenbus_watch(&watch->watch);
+ list_del(&watch->list);
+ free_watch_adapter(watch);
+ break;
+ }
+ }
+ }
+
+ break;
+
default:
return -EINVAL;
}
@@ -191,7 +295,10 @@ static int xenbus_dev_open(struct inode
return -ENOMEM;
INIT_LIST_HEAD(&u->transactions);
+ INIT_LIST_HEAD(&u->watches);
init_waitqueue_head(&u->read_waitq);
+
+ mutex_init(&u->reply_mutex);
filp->private_data = u;
@@ -202,11 +309,18 @@ static int xenbus_dev_release(struct ino
{
struct xenbus_dev_data *u = filp->private_data;
struct xenbus_dev_transaction *trans, *tmp;
+ struct watch_adapter *watch, *tmp_watch;
list_for_each_entry_safe(trans, tmp, &u->transactions, list) {
xenbus_transaction_end(trans->handle, 1);
list_del(&trans->list);
kfree(trans);
+ }
+
+ list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
+ unregister_xenbus_watch(&watch->watch);
+ list_del(&watch->list);
+ free_watch_adapter(watch);
}
kfree(u);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|