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>
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;