ia64/xen-unstable
changeset 10914:9a4a560d0a23
[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@epoch.ncsc.mil>
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@epoch.ncsc.mil>
author | kfraser@localhost.localdomain |
---|---|
date | Wed Aug 02 15:01:59 2006 +0100 (2006-08-02) |
parents | 153e69eae665 |
children | 08415dfc5918 |
files | linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c |
line diff
1.1 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c Wed Aug 02 15:00:39 2006 +0100 1.2 +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c Wed Aug 02 15:01:59 2006 +0100 1.3 @@ -58,6 +58,9 @@ struct xenbus_dev_data { 1.4 /* In-progress transaction. */ 1.5 struct list_head transactions; 1.6 1.7 + /* Active watches. */ 1.8 + struct list_head watches; 1.9 + 1.10 /* Partial request. */ 1.11 unsigned int len; 1.12 union { 1.13 @@ -70,6 +73,8 @@ struct xenbus_dev_data { 1.14 char read_buffer[PAGE_SIZE]; 1.15 unsigned int read_cons, read_prod; 1.16 wait_queue_head_t read_waitq; 1.17 + 1.18 + struct mutex reply_mutex; 1.19 }; 1.20 1.21 static struct proc_dir_entry *xenbus_dev_intf; 1.22 @@ -100,14 +105,60 @@ static void queue_reply(struct xenbus_de 1.23 { 1.24 int i; 1.25 1.26 + mutex_lock(&u->reply_mutex); 1.27 + 1.28 for (i = 0; i < len; i++, u->read_prod++) 1.29 u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i]; 1.30 1.31 BUG_ON((u->read_prod - u->read_cons) > sizeof(u->read_buffer)); 1.32 1.33 + mutex_unlock(&u->reply_mutex); 1.34 + 1.35 wake_up(&u->read_waitq); 1.36 } 1.37 1.38 +struct watch_adapter 1.39 +{ 1.40 + struct list_head list; 1.41 + struct xenbus_watch watch; 1.42 + struct xenbus_dev_data *dev_data; 1.43 + char *token; 1.44 +}; 1.45 + 1.46 +static void free_watch_adapter (struct watch_adapter *watch) 1.47 +{ 1.48 + kfree(watch->watch.node); 1.49 + kfree(watch->token); 1.50 + kfree(watch); 1.51 +} 1.52 + 1.53 +static void watch_fired(struct xenbus_watch *watch, 1.54 + const char **vec, 1.55 + unsigned int len) 1.56 +{ 1.57 + struct watch_adapter *adap = 1.58 + container_of(watch, struct watch_adapter, watch); 1.59 + struct xsd_sockmsg hdr; 1.60 + const char *path, *token; 1.61 + int path_len, tok_len, body_len; 1.62 + 1.63 + path = vec[XS_WATCH_PATH]; 1.64 + token = adap->token; 1.65 + 1.66 + path_len = strlen(path) + 1; 1.67 + tok_len = strlen(token) + 1; 1.68 + body_len = path_len + tok_len; 1.69 + 1.70 + hdr.type = XS_WATCH_EVENT; 1.71 + hdr.len = body_len; 1.72 + 1.73 + queue_reply(adap->dev_data, (char *)&hdr, sizeof(hdr)); 1.74 + queue_reply(adap->dev_data, (char *)path, path_len); 1.75 + queue_reply(adap->dev_data, (char *)token, tok_len); 1.76 +} 1.77 + 1.78 +static LIST_HEAD(watch_list); 1.79 + 1.80 static ssize_t xenbus_dev_write(struct file *filp, 1.81 const char __user *ubuf, 1.82 size_t len, loff_t *ppos) 1.83 @@ -116,6 +167,9 @@ static ssize_t xenbus_dev_write(struct f 1.84 struct xenbus_dev_transaction *trans = NULL; 1.85 uint32_t msg_type; 1.86 void *reply; 1.87 + char *path, *token; 1.88 + struct watch_adapter *watch, *tmp_watch; 1.89 + int err; 1.90 1.91 if ((len + u->len) > sizeof(u->u.buffer)) 1.92 return -EINVAL; 1.93 @@ -169,6 +223,56 @@ static ssize_t xenbus_dev_write(struct f 1.94 kfree(reply); 1.95 break; 1.96 1.97 + case XS_WATCH: 1.98 + case XS_UNWATCH: 1.99 + path = u->u.buffer + sizeof(u->u.msg); 1.100 + token = memchr(path, 0, u->u.msg.len); 1.101 + if (token == NULL) 1.102 + return -EILSEQ; 1.103 + token++; 1.104 + 1.105 + if (msg_type == XS_WATCH) { 1.106 + static const char * XS_WATCH_RESP = "OK"; 1.107 + struct xsd_sockmsg hdr; 1.108 + 1.109 + watch = kmalloc(sizeof(*watch), GFP_KERNEL); 1.110 + watch->watch.node = kmalloc(strlen(path)+1, 1.111 + GFP_KERNEL); 1.112 + strcpy((char *)watch->watch.node, path); 1.113 + watch->watch.callback = watch_fired; 1.114 + watch->token = kmalloc(strlen(token)+1, GFP_KERNEL); 1.115 + strcpy(watch->token, token); 1.116 + watch->dev_data = u; 1.117 + 1.118 + err = register_xenbus_watch(&watch->watch); 1.119 + if (err) { 1.120 + free_watch_adapter(watch); 1.121 + return err; 1.122 + } 1.123 + 1.124 + list_add(&watch->list, &u->watches); 1.125 + 1.126 + hdr.type = XS_WATCH; 1.127 + hdr.len = strlen(XS_WATCH_RESP) + 1; 1.128 + queue_reply(u, (char *)&hdr, sizeof(hdr)); 1.129 + queue_reply(u, (char *)XS_WATCH_RESP, hdr.len); 1.130 + } else { 1.131 + list_for_each_entry_safe(watch, tmp_watch, 1.132 + &u->watches, list) { 1.133 + if (!strcmp(watch->token, token) && 1.134 + !strcmp(watch->watch.node, path)) 1.135 + break; 1.136 + { 1.137 + unregister_xenbus_watch(&watch->watch); 1.138 + list_del(&watch->list); 1.139 + free_watch_adapter(watch); 1.140 + break; 1.141 + } 1.142 + } 1.143 + } 1.144 + 1.145 + break; 1.146 + 1.147 default: 1.148 return -EINVAL; 1.149 } 1.150 @@ -191,8 +295,11 @@ static int xenbus_dev_open(struct inode 1.151 return -ENOMEM; 1.152 1.153 INIT_LIST_HEAD(&u->transactions); 1.154 + INIT_LIST_HEAD(&u->watches); 1.155 init_waitqueue_head(&u->read_waitq); 1.156 1.157 + mutex_init(&u->reply_mutex); 1.158 + 1.159 filp->private_data = u; 1.160 1.161 return 0; 1.162 @@ -202,6 +309,7 @@ static int xenbus_dev_release(struct ino 1.163 { 1.164 struct xenbus_dev_data *u = filp->private_data; 1.165 struct xenbus_dev_transaction *trans, *tmp; 1.166 + struct watch_adapter *watch, *tmp_watch; 1.167 1.168 list_for_each_entry_safe(trans, tmp, &u->transactions, list) { 1.169 xenbus_transaction_end(trans->handle, 1); 1.170 @@ -209,6 +317,12 @@ static int xenbus_dev_release(struct ino 1.171 kfree(trans); 1.172 } 1.173 1.174 + list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) { 1.175 + unregister_xenbus_watch(&watch->watch); 1.176 + list_del(&watch->list); 1.177 + free_watch_adapter(watch); 1.178 + } 1.179 + 1.180 kfree(u); 1.181 1.182 return 0;