# HG changeset patch
# User Christian Limpach <Christian.Limpach@xxxxxxxxxxxxx>
# Date 1175076118 -3600
# Node ID f9d23364567aef2430c47ac6e451c6b7ed0bf959
# Parent 4c5ea17290fe4157d657d46d220f47a1a9ed8256
[linux] Fix xenbus device to allow replies larger than 4096 bytes.
Also fix reply_queue mutex across fragmented replies and for concurrent
readers.
Signed-off-by: Christian Limpach <Christian.Limpach@xxxxxxxxxxxxx>
---
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c | 86 +++++++++++++------
1 files changed, 59 insertions(+), 27 deletions(-)
diff -r 4c5ea17290fe -r f9d23364567a
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c Wed Mar 28
10:41:53 2007 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c Wed Mar 28
11:01:58 2007 +0100
@@ -58,6 +58,13 @@ struct xenbus_dev_transaction {
struct xenbus_transaction handle;
};
+struct read_buffer {
+ struct list_head list;
+ unsigned int cons;
+ unsigned int len;
+ char msg[];
+};
+
struct xenbus_dev_data {
/* In-progress transaction. */
struct list_head transactions;
@@ -73,9 +80,7 @@ struct xenbus_dev_data {
} u;
/* Response queue. */
-#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1))
- char read_buffer[PAGE_SIZE];
- unsigned int read_cons, read_prod;
+ struct list_head read_buffers;
wait_queue_head_t read_waitq;
struct mutex reply_mutex;
@@ -88,18 +93,34 @@ static ssize_t xenbus_dev_read(struct fi
size_t len, loff_t *ppos)
{
struct xenbus_dev_data *u = filp->private_data;
- int i;
-
- if (wait_event_interruptible(u->read_waitq,
- u->read_prod != u->read_cons))
- return -EINTR;
-
- for (i = 0; i < len; i++) {
- if (u->read_cons == u->read_prod)
- break;
- put_user(u->read_buffer[MASK_READ_IDX(u->read_cons)], ubuf+i);
- u->read_cons++;
- }
+ struct read_buffer *rb;
+ int i, ret;
+
+ mutex_lock(&u->reply_mutex);
+ while (list_empty(&u->read_buffers)) {
+ mutex_unlock(&u->reply_mutex);
+ ret = wait_event_interruptible(u->read_waitq,
+ !list_empty(&u->read_buffers));
+ if (ret)
+ return ret;
+ mutex_lock(&u->reply_mutex);
+ }
+
+ rb = list_entry(u->read_buffers.next, struct read_buffer, list);
+ for (i = 0; i < len;) {
+ put_user(rb->msg[rb->cons], ubuf + i);
+ i++;
+ rb->cons++;
+ if (rb->cons == rb->len) {
+ list_del(&rb->list);
+ kfree(rb);
+ if (list_empty(&u->read_buffers))
+ break;
+ rb = list_entry(u->read_buffers.next,
+ struct read_buffer, list);
+ }
+ }
+ mutex_unlock(&u->reply_mutex);
return i;
}
@@ -107,16 +128,20 @@ static void queue_reply(struct xenbus_de
static void queue_reply(struct xenbus_dev_data *u,
char *data, unsigned int len)
{
- 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);
+ struct read_buffer *rb;
+
+ if (len == 0)
+ return;
+
+ rb = kmalloc(sizeof(*rb) + len, GFP_KERNEL);
+ BUG_ON(rb == NULL);
+
+ rb->cons = 0;
+ rb->len = len;
+
+ memcpy(rb->msg, data, len);
+
+ list_add_tail(&rb->list, &u->read_buffers);
wake_up(&u->read_waitq);
}
@@ -155,10 +180,12 @@ static void watch_fired(struct xenbus_wa
hdr.type = XS_WATCH_EVENT;
hdr.len = body_len;
-
+
+ mutex_lock(&adap->dev_data->reply_mutex);
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);
+ mutex_unlock(&adap->dev_data->reply_mutex);
}
static LIST_HEAD(watch_list);
@@ -230,8 +257,10 @@ static ssize_t xenbus_dev_write(struct f
list_del(&trans->list);
kfree(trans);
}
+ mutex_lock(&u->reply_mutex);
queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
queue_reply(u, (char *)reply, u->u.msg.len);
+ mutex_unlock(&u->reply_mutex);
kfree(reply);
break;
@@ -282,8 +311,10 @@ static ssize_t xenbus_dev_write(struct f
hdr.type = msg_type;
hdr.len = strlen(XS_RESP) + 1;
+ mutex_lock(&u->reply_mutex);
queue_reply(u, (char *)&hdr, sizeof(hdr));
queue_reply(u, (char *)XS_RESP, hdr.len);
+ mutex_unlock(&u->reply_mutex);
break;
}
@@ -312,6 +343,7 @@ static int xenbus_dev_open(struct inode
INIT_LIST_HEAD(&u->transactions);
INIT_LIST_HEAD(&u->watches);
+ INIT_LIST_HEAD(&u->read_buffers);
init_waitqueue_head(&u->read_waitq);
mutex_init(&u->reply_mutex);
@@ -349,7 +381,7 @@ static unsigned int xenbus_dev_poll(stru
struct xenbus_dev_data *u = file->private_data;
poll_wait(file, &u->read_waitq, wait);
- if (u->read_cons != u->read_prod)
+ if (!list_empty(&u->read_buffers))
return POLLIN | POLLRDNORM;
return 0;
}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|