On Wed, 2005-09-14 at 10:21 +1000, Rusty Russell wrote:
> So when someone opens the xenbus dev, we introduce a new page to the
> domain and the xenstored uses that for comms. When closed, the page is
> released. This actually simplifies the xenbus_dev driver a lot: now
> it's just a dumb pass-through since we don't have to worry about the
> userspace program blowing chunks all over the kernel's comms mechanism.
>
> I'll hack something up and see what you think...
OK, realized there's a problem with suspend/resume. Within the kernel,
we prevent suspend/resume by simply holding the xenstore_lock, so it
can't happen during normal operations, or transactions.
So let's leave this for now. It is fairly similar to the problem of
xenstored restarts, which I'm trying to merge, so I suggest we revisit
after that...
Patch for reading only (I subbed in NULL for the default store page for
the moment, since I know there's another patch out there which touches
this).
diff -r 0d8c0db04258 linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c Tue Sep 13
21:52:24 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c Wed Sep 14
19:16:48 2005
@@ -46,14 +46,18 @@
DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
-static inline struct ringbuf_head *outbuf(void)
-{
- return mfn_to_virt(xen_start_info->store_mfn);
-}
-
-static inline struct ringbuf_head *inbuf(void)
-{
- return mfn_to_virt(xen_start_info->store_mfn) + PAGE_SIZE/2;
+static inline struct ringbuf_head *outbuf(void *page)
+{
+ if (!page)
+ return mfn_to_virt(xen_start_info->store_mfn);
+ return page;
+}
+
+static inline struct ringbuf_head *inbuf(void *page)
+{
+ if (!page)
+ return mfn_to_virt(xen_start_info->store_mfn) + PAGE_SIZE/2;
+ return page + PAGE_SIZE/2;
}
static irqreturn_t wake_waiting(int irq, void *unused, struct pt_regs *regs)
@@ -117,10 +121,10 @@
return avail != 0;
}
-int xb_write(const void *data, unsigned len)
+int xb_write(const void *data, unsigned len, void *page)
{
struct ringbuf_head h;
- struct ringbuf_head *out = outbuf();
+ struct ringbuf_head *out = outbuf(page);
do {
void *dst;
@@ -151,19 +155,19 @@
return 0;
}
-int xs_input_avail(void)
+int xs_input_avail(void *page)
{
unsigned int avail;
- struct ringbuf_head *in = inbuf();
+ struct ringbuf_head *in = inbuf(page);
get_input_chunk(in, in->buf, &avail);
return avail != 0;
}
-int xb_read(void *data, unsigned len)
+int xb_read(void *data, unsigned len, void *page)
{
struct ringbuf_head h;
- struct ringbuf_head *in = inbuf();
+ struct ringbuf_head *in = inbuf(page);
int was_full;
while (len != 0) {
@@ -200,34 +204,25 @@
return 0;
}
-/* Set up interrupt handler off store event channel. */
-int xb_init_comms(void)
+/* Set up interrupt handler off store event channel, and clear page. */
+int xb_init_comms(unsigned int evtchn, void *page)
{
int err;
- if (!xen_start_info->store_evtchn)
- return 0;
-
- err = bind_evtchn_to_irqhandler(
- xen_start_info->store_evtchn, wake_waiting,
- 0, "xenbus", &xb_waitq);
+ err = bind_evtchn_to_irqhandler(evtchn, wake_waiting,
+ 0, "xenbus", &xb_waitq);
if (err) {
printk(KERN_ERR "XENBUS request irq failed %i\n", err);
- unbind_evtchn_from_irq(xen_start_info->store_evtchn);
return err;
}
/* FIXME zero out page -- domain builder should probably do this*/
- memset(mfn_to_virt(xen_start_info->store_mfn), 0, PAGE_SIZE);
-
+ memset(inbuf(page), 0, PAGE_SIZE/2);
+ memset(outbuf(page), 0, PAGE_SIZE/2);
return 0;
}
-void xb_suspend_comms(void)
-{
-
- if (!xen_start_info->store_evtchn)
- return;
-
- unbind_evtchn_from_irqhandler(xen_start_info->store_evtchn, &xb_waitq);
-}
+void xb_stop_comms(unsigned int evtchn)
+{
+ unbind_evtchn_from_irqhandler(evtchn, &xb_waitq);
+}
diff -r 0d8c0db04258 linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.h
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.h Tue Sep 13
21:52:24 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.h Wed Sep 14
19:16:48 2005
@@ -29,13 +29,13 @@
#define _XENBUS_COMMS_H
int xs_init(void);
-int xb_init_comms(void);
-void xb_suspend_comms(void);
+int xb_init_comms(unsigned int evtchn, void *page);
+void xb_stop_comms(unsigned int evtchn);
-/* Low level routines. */
-int xb_write(const void *data, unsigned len);
-int xb_read(void *data, unsigned len);
-int xs_input_avail(void);
+/* Low level routines: page is NULL for default store page */
+int xb_write(const void *data, unsigned len, void *page);
+int xb_read(void *data, unsigned len, void *page);
+int xs_input_avail(void *page);
extern wait_queue_head_t xb_waitq;
#endif /* _XENBUS_COMMS_H */
diff -r 0d8c0db04258 linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c Tue Sep 13
21:52:24 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c Wed Sep 14
19:16:48 2005
@@ -36,6 +36,7 @@
#include <linux/notifier.h>
#include <linux/wait.h>
#include <linux/fs.h>
+#include <linux/spinlock.h>
#include "xenbus_comms.h"
@@ -45,90 +46,47 @@
#include <asm-xen/linux-public/xenstored.h>
struct xenbus_dev_data {
- /* Are there bytes left to be read in this message? */
- int bytes_left;
- /* Are we still waiting for the reply to a message we wrote? */
- int awaiting_reply;
- /* Buffer for outgoing messages. */
- unsigned int len;
- union {
- struct xsd_sockmsg msg;
- char buffer[PAGE_SIZE];
- } u;
+ unsigned int evtchn;
+ char *page;
+ char bouncebuf[PAGE_SIZE];
};
static struct proc_dir_entry *xenbus_dev_intf;
-/* Reply can be long (dir, getperm): don't buffer, just examine
- * headers so we can discard rest if they die. */
static ssize_t xenbus_dev_read(struct file *filp,
char __user *ubuf,
size_t len, loff_t *ppos)
{
struct xenbus_dev_data *data = filp->private_data;
- struct xsd_sockmsg msg;
- int err;
+ int ret;
- /* Refill empty buffer? */
- if (data->bytes_left == 0) {
- if (len < sizeof(msg))
- return -EINVAL;
-
- err = xb_read(&msg, sizeof(msg));
- if (err)
- return err;
- data->bytes_left = msg.len;
- if (ubuf && copy_to_user(ubuf, &msg, sizeof(msg)) != 0)
- return -EFAULT;
- /* We can receive spurious XS_WATCH_EVENT messages. */
- if (msg.type != XS_WATCH_EVENT)
- data->awaiting_reply = 0;
- return sizeof(msg);
- }
-
- /* Don't read over next header, or over temporary buffer. */
- if (len > sizeof(data->u.buffer))
- len = sizeof(data->u.buffer);
- if (len > data->bytes_left)
- len = data->bytes_left;
-
- err = xb_read(data->u.buffer, len);
- if (err)
- return err;
-
- data->bytes_left -= len;
- if (ubuf && copy_to_user(ubuf, data->u.buffer, len) != 0)
- return -EFAULT;
- return len;
+ if (len > sizeof(data->bouncebuf))
+ len = sizeof(data->bouncebuf);
+ ret = xb_read(data->bouncebuf, len, data->page);
+ if (ret && copy_to_user(ubuf, data->bouncebuf, len) != 0)
+ ret = -EFAULT;
+ return ret;
}
-/* We do v. basic sanity checking so they don't screw up kernel later. */
static ssize_t xenbus_dev_write(struct file *filp,
const char __user *ubuf,
size_t len, loff_t *ppos)
{
struct xenbus_dev_data *data = filp->private_data;
- int err;
+ int ret;
- /* We gather data in buffer until we're ready to send it. */
- if (len > data->len + sizeof(data->u))
- return -EINVAL;
- if (copy_from_user(data->u.buffer + data->len, ubuf, len) != 0)
+ if (len > sizeof(data->bouncebuf))
+ len = sizeof(data->bouncebuf);
+ if (copy_from_user(data->bouncebuf, ubuf, len) != 0)
return -EFAULT;
- data->len += len;
- if (data->len >= sizeof(data->u.msg) + data->u.msg.len) {
- err = xb_write(data->u.buffer, data->len);
- if (err)
- return err;
- data->len = 0;
- data->awaiting_reply = 1;
- }
- return len;
+ return xb_write(data->boundbuf, len);
}
static int xenbus_dev_open(struct inode *inode, struct file *filp)
{
- struct xenbus_dev_data *u;
+ struct xenbus_dev_data *data;
+ int err;
+ evtchn_op_t op = { .cmd = EVTCHNOP_alloc_unbound };
if (xen_start_info->store_evtchn == 0)
return -ENOENT;
@@ -136,34 +94,71 @@
/* Don't try seeking. */
nonseekable_open(inode, filp);
- u = kmalloc(sizeof(*u), GFP_KERNEL);
- if (u == NULL)
- return -ENOMEM;
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto out;
+ }
+ data->page = (void *)__get_free_page(GFP_KERNEL);
+ if (!data->page) {
+ err = -ENOMEM;
+ goto free_data;
+ }
+ op.u.alloc_unbound.dom = 0;
+ err = HYPERVISOR_event_channel_op(&op);
+ if (err)
+ goto free_page;
+ data->evtchn = op.u.alloc_unbound.port;
+ err = xb_init_comms(data->evtchn, data->page);
+ if (err)
+ goto release_evtchn;
- memset(u, 0, sizeof(*u));
+ down(&xenbus_lock);
+ err = xenbus_introduce(virt_to_mfn(data->page), data->evtchn);
+ up(&xenbus_lock);
+ if (err)
+ goto release_comms;
filp->private_data = u;
+ return 0;
- down(&xenbus_lock);
+release_comms:
+ xb_stop_comms(data->evtchn);
+release_evtchn:
+ op.cmd = EVTCHNOP_close;
+ op.u.close.dom = DOMID_SELF;
+ op.u.close.port = data->evtchn;
+ if (HYPERVISOR_event_channel_op(&op) != 0)
+ printk(KERN_WARNING "xenbus_dev: channel close failed\n");
+free_page:
+ free_page((unsigned long)data->page);
+free_data:
+ kfree(data);
+out:
+ return err;
+}
- return 0;
-}
+static void xenbus_dev_stop(struct xenbus_dev_data *data)
+{
+
static int xenbus_dev_release(struct inode *inode, struct file *filp)
{
struct xenbus_dev_data *data = filp->private_data;
+ evtchn_op_t op = { .cmd = EVTCHNOP_close };
- /* Discard any unread replies. */
- while (data->bytes_left || data->awaiting_reply)
- xenbus_dev_read(filp, NULL, sizeof(data->u.buffer), NULL);
-
- /* Harmless if no transaction in progress. */
- xenbus_transaction_end(1);
-
+ down(&xenbus_lock);
+ if (xenbus_release(virt_to_mfn(data->page)) != 0)
+ printk(KERN_WARNING "xenbus_dev: release failed\n");
up(&xenbus_lock);
+ xb_stop_comms(data->evtchn);
+ op.u.close.dom = DOMID_SELF;
+ op.u.close.port = data->evtchn;
+ if (HYPERVISOR_event_channel_op(&op) != 0)
+ printk(KERN_WARNING "xenbus_dev: channel close failed\n");
+ free_page((unsigned long)data->page);
kfree(data);
-
return 0;
}
diff -r 0d8c0db04258 linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Tue Sep 13
21:52:24 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Wed Sep 14
19:16:48 2005
@@ -607,12 +607,12 @@
down(&xenbus_lock);
bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev);
- xb_suspend_comms();
+ xb_stop_comms(xen_start_info->store_evtchn);
}
void xenbus_resume(void)
{
- xb_init_comms();
+ xb_init_comms(xen_start_info->store_evtchn, NULL);
reregister_xenbus_watches();
bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev);
diff -r 0d8c0db04258 linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c Tue Sep 13
21:52:24 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c Wed Sep 14
19:16:48 2005
@@ -426,6 +426,44 @@
}
EXPORT_SYMBOL(xenbus_gather);
+int xenbus_introduce(unsigned long mfn, unsigned int evtchn)
+{
+ char domid_str[21];
+ char mfn_str[21];
+ char eventchn_str[21];
+ struct kvec iov[4];
+
+ sprintf(domid_str, "%u", DOMID_SELF);
+ sprintf(mfn_str, "%lu", mfn);
+ sprintf(eventchn_str, "%u", eventchn);
+
+ iov[0].iov_base = domid_str;
+ iov[0].iov_len = strlen(domid_str) + 1;
+ iov[1].iov_base = mfn_str;
+ iov[1].iov_len = strlen(mfn_str) + 1;
+ iov[2].iov_base = eventchn_str;
+ iov[2].iov_len = strlen(eventchn_str) + 1;
+ iov[3].iov_base = "";
+ iov[3].iov_len = 1;
+
+ return xs_error(xs_talkv(h, XS_INTRODUCE, iov, ARRAY_SIZE(iov), NULL));
+}
+
+int xenbus_release(unsigned long mfn);
+{
+ struct iovec iov[2];
+ char domid_str[21], mfn_str[21];
+
+ sprintf(domid_str, "%u", DOMID_SELF);
+ sprintf(mfn_str, "%lu", mfn);
+ iov[0].iov_base = domid_str;
+ iov[0].iov_len = strlen(domid_str) + 1;
+ iov[1].iov_base = mfn_str;
+ iov[1].iov_len = strlen(mfn_str) + 1;
+
+ return xs_error(xs_talkv(h, XS_RELEASE, iov, ARRAY_SIZE(iov), NULL));
+}
+
static int xs_watch(const char *path, const char *token)
{
struct kvec iov[2];
@@ -569,7 +607,7 @@
int err;
struct task_struct *watcher;
- err = xb_init_comms();
+ err = xb_init_comms(xen_start_info->store_evtchn, NULL);
if (err)
return err;
diff -r 0d8c0db04258 linux-2.6-xen-sparse/include/asm-xen/xenbus.h
--- a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h Tue Sep 13 21:52:24 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h Wed Sep 14 19:16:48 2005
@@ -90,6 +90,8 @@
int xenbus_rm(const char *dir, const char *node);
int xenbus_transaction_start(const char *subtree);
int xenbus_transaction_end(int abort);
+int xenbus_introduce(unsigned long mfn, unsigned int evtchn);
+int xenbus_release(unsigned long mfn);
/* Single read and scanf: returns -errno or num scanned if > 0. */
int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...)
diff -r 0d8c0db04258 tools/python/xen/lowlevel/xs/xs.c
--- a/tools/python/xen/lowlevel/xs/xs.c Tue Sep 13 21:52:24 2005
+++ b/tools/python/xen/lowlevel/xs/xs.c Wed Sep 14 19:16:48 2005
@@ -708,7 +708,7 @@
}
#define xspy_release_domain_doc "\n" \
- "Tell xenstore to release its channel to a domain.\n" \
+ "Tell xenstore to release its channel(s) to a domain.\n" \
"Unless this is done the domain will not be released.\n" \
" dom [int]: domain id\n" \
"\n" \
@@ -733,7 +733,7 @@
&dom))
goto exit;
Py_BEGIN_ALLOW_THREADS
- xsval = xs_release_domain(xh, dom);
+ xsval = xs_release_domain(xh, dom, 0);
Py_END_ALLOW_THREADS
if (!xsval) {
PyErr_SetFromErrno(PyExc_RuntimeError);
diff -r 0d8c0db04258 tools/xenstore/testsuite/09domain.test
--- a/tools/xenstore/testsuite/09domain.test Tue Sep 13 21:52:24 2005
+++ b/tools/xenstore/testsuite/09domain.test Wed Sep 14 19:16:48 2005
@@ -10,10 +10,16 @@
close
# Release that domain.
-release 1
+release 1 100
close
# Introduce and release by same connection.
expect handle is 2
introduce 1 100 7 /my/home
-release 1
+release 1 100
+
+# Introduce another connection from a domain connection
+expect handle is 3
+# FIXME: We can't actually handle multiple domain connections in xs_test.
+introduce 1 101 7 /my/home
+release 1 0
diff -r 0d8c0db04258 tools/xenstore/testsuite/11domain-watch.test
--- a/tools/xenstore/testsuite/11domain-watch.test Tue Sep 13 21:52:24 2005
+++ b/tools/xenstore/testsuite/11domain-watch.test Wed Sep 14 19:16:48 2005
@@ -12,7 +12,7 @@
1 waitwatch
1 ackwatch token
1 unwatch /test token
-release 1
+release 1 0
1 close
# ignore watches while doing commands, should work.
@@ -26,7 +26,7 @@
expect 1:/dir/test:token
1 waitwatch
1 ackwatch token
-release 1
+release 1 0
1 close
# unwatch
@@ -39,7 +39,7 @@
expect 1:/dir/test2:token2
1 waitwatch
1 unwatch /dir token2
-release 1
+release 1 0
1 close
# unwatch while watch pending.
@@ -48,5 +48,5 @@
1 watch /dir token1
write /dir/test2 create contents
1 unwatch /dir token1
-release 1
+release 1 0
1 close
diff -r 0d8c0db04258 tools/xenstore/xenstored_core.c
--- a/tools/xenstore/xenstored_core.c Tue Sep 13 21:52:24 2005
+++ b/tools/xenstore/xenstored_core.c Wed Sep 14 19:16:48 2005
@@ -1285,7 +1285,7 @@
break;
case XS_RELEASE:
- do_release(conn, onearg(in));
+ do_release(conn, in);
break;
case XS_GET_DOMAIN_PATH:
diff -r 0d8c0db04258 tools/xenstore/xenstored_domain.c
--- a/tools/xenstore/xenstored_domain.c Tue Sep 13 21:52:24 2005
+++ b/tools/xenstore/xenstored_domain.c Wed Sep 14 19:16:48 2005
@@ -51,6 +51,9 @@
/* Event channel port */
u16 port;
+ /* Shared page frame */
+ unsigned long mfn;
+
/* Domain path in store. */
char *path;
@@ -273,6 +276,7 @@
domain = talloc(context, struct domain);
domain->port = 0;
domain->domid = domid;
+ domain->mfn = mfn;
domain->path = talloc_strdup(domain, path);
domain->page = xc_map_foreign_range(*xc_handle, domain->domid,
getpagesize(),
@@ -302,6 +306,10 @@
void do_introduce(struct connection *conn, struct buffered_data *in)
{
struct domain *domain;
+ domid_t domid;
+ unsigned long mfn;
+ unsigned int evtchn;
+ char *path;
char *vec[4];
if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
@@ -309,7 +317,20 @@
return;
}
- if (conn->id != 0) {
+ domid = atoi(vec[0]);
+ mfn = atol(vec[1]);
+ evtchn = atoi(vec[2]);
+ path = vec[3];
+
+ /* Domains can introduce more pages: share same path. */
+ if (conn->domain) {
+ if (domid != DOMID_SELF) {
+ send_error(conn, EACCES);
+ return;
+ }
+ domid = conn->domain->domid;
+ path = conn->domain->path;
+ } else if (conn->id != 0) {
send_error(conn, EACCES);
return;
}
@@ -320,13 +341,12 @@
}
/* Sanity check args. */
- if ((atoi(vec[2]) <= 0) || !is_valid_nodename(vec[3])) {
+ if (mfn == 0 || !is_valid_nodename(path)) {
send_error(conn, EINVAL);
return;
}
/* Hang domain off "in" until we're finished. */
- domain = new_domain(in, atoi(vec[0]), atol(vec[1]), atol(vec[2]),
- vec[3]);
+ domain = new_domain(in, domid, mfn, evtchn, path);
if (!domain) {
send_error(conn, errno);
return;
@@ -340,54 +360,69 @@
send_ack(conn, XS_INTRODUCE);
}
-static struct domain *find_domain_by_domid(domid_t domid)
+static struct domain *find_domain(domid_t domid, unsigned long mfn)
{
struct domain *i;
list_for_each_entry(i, &domains, list) {
- if (i->domid == domid)
- return i;
+ if (i->domid == domid) {
+ if (!mfn || i->mfn == mfn)
+ return i;
+ }
}
return NULL;
}
-/* domid */
-void do_release(struct connection *conn, const char *domid_str)
+/* domid, mfn */
+void do_release(struct connection *conn, struct buffered_data *in)
{
struct domain *domain;
domid_t domid;
-
- if (!domid_str) {
+ unsigned long mfn;
+ char *vec[2];
+
+ if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
send_error(conn, EINVAL);
return;
}
-
- domid = atoi(domid_str);
+ domid = atol(vec[0]);
+ mfn = atol(vec[1]);
+
if (!domid) {
send_error(conn, EINVAL);
return;
}
- if (conn->id != 0) {
+ if (!conn->can_write) {
+ send_error(conn, EROFS);
+ return;
+ }
+
+ /* Domains can release own pages, but not all of them. */
+ if (conn->domain) {
+ if (domid != DOMID_SELF || !mfn) {
+ send_error(conn, EACCES);
+ return;
+ }
+ domid = conn->domain->domid;
+ } else if (conn->id != 0) {
send_error(conn, EACCES);
return;
}
- domain = find_domain_by_domid(domid);
- if (!domain) {
- send_error(conn, ENOENT);
- return;
- }
-
- if (!domain->conn) {
- send_error(conn, EINVAL);
- return;
- }
-
- talloc_free(domain->conn);
-
- fire_watches(NULL, "@releaseDomain", false);
-
+ if (mfn) {
+ domain = find_domain(domid, mfn);
+ if (!domain) {
+ send_error(conn, ENOENT);
+ return;
+ }
+ talloc_free(domain->conn);
+ } else {
+ while ((domain = find_domain(domid, 0)) != NULL)
+ talloc_free(domain->conn);
+
+ fire_watches(NULL, "@releaseDomain", false);
+ }
send_ack(conn, XS_RELEASE);
}
@@ -405,7 +440,7 @@
if (domid == DOMID_SELF)
domain = conn->domain;
else
- domain = find_domain_by_domid(domid);
+ domain = find_domain(domid, 0);
if (!domain)
send_error(conn, ENOENT);
diff -r 0d8c0db04258 tools/xenstore/xenstored_domain.h
--- a/tools/xenstore/xenstored_domain.h Tue Sep 13 21:52:24 2005
+++ b/tools/xenstore/xenstored_domain.h Wed Sep 14 19:16:48 2005
@@ -26,7 +26,7 @@
void do_introduce(struct connection *conn, struct buffered_data *in);
/* domid */
-void do_release(struct connection *conn, const char *domid_str);
+void do_release(struct connection *conn, struct buffered_data *in);
/* domid */
void do_get_domain_path(struct connection *conn, const char *domid_str);
diff -r 0d8c0db04258 tools/xenstore/xs.c
--- a/tools/xenstore/xs.c Tue Sep 13 21:52:24 2005
+++ b/tools/xenstore/xs.c Wed Sep 14 19:16:48 2005
@@ -565,13 +565,19 @@
return xs_bool(xs_talkv(h, XS_INTRODUCE, iov, ARRAY_SIZE(iov), NULL));
}
-bool xs_release_domain(struct xs_handle *h, domid_t domid)
-{
- char domid_str[MAX_STRLEN(domid)];
+bool xs_release_domain(struct xs_handle *h, domid_t domid, unsigned long mfn)
+{
+ struct iovec iov[2];
+ char domid_str[MAX_STRLEN(domid)], mfn_str[MAX_STRLEN(mfn)];
sprintf(domid_str, "%u", domid);
-
- return xs_bool(xs_single(h, XS_RELEASE, domid_str, NULL));
+ sprintf(mfn_str, "%lu", mfn);
+ iov[0].iov_base = domid_str;
+ iov[0].iov_len = strlen(domid_str) + 1;
+ iov[1].iov_base = mfn_str;
+ iov[1].iov_len = strlen(mfn_str) + 1;
+
+ return xs_bool(xs_talkv(h, XS_RELEASE, iov, ARRAY_SIZE(iov), NULL));
}
char *xs_get_domain_path(struct xs_handle *h, domid_t domid)
diff -r 0d8c0db04258 tools/xenstore/xs.h
--- a/tools/xenstore/xs.h Tue Sep 13 21:52:24 2005
+++ b/tools/xenstore/xs.h Wed Sep 14 19:16:48 2005
@@ -125,14 +125,16 @@
/* Introduce a new domain.
* This tells the store daemon about a shared memory page, event channel
* and store path associated with a domain: the domain uses these to
communicate.
+ * The domain can use this to add its own extra pages.
*/
bool xs_introduce_domain(struct xs_handle *h, domid_t domid, unsigned long mfn,
unsigned int eventchn, const char *path);
/* Release a domain.
* Tells the store domain to release the memory page to the domain.
+ * mfn == 0 means to release all pages.
*/
-bool xs_release_domain(struct xs_handle *h, domid_t domid);
+bool xs_release_domain(struct xs_handle *h, domid_t domid, unsigned long mfn);
/* Query the home path of a domain.
*/
diff -r 0d8c0db04258 tools/xenstore/xs_test.c
--- a/tools/xenstore/xs_test.c Tue Sep 13 21:52:24 2005
+++ b/tools/xenstore/xs_test.c Wed Sep 14 19:16:48 2005
@@ -207,6 +207,7 @@
" start <node>\n"
" abort\n"
" introduce <domid> <mfn> <eventchn> <path>\n"
+ " release <domid> <mfn>\n"
" commit\n"
" sleep <milliseconds>\n"
" expect <pattern>\n"
@@ -630,9 +631,9 @@
daemon_pid = *(int *)((void *)out + 32);
}
-static void do_release(unsigned int handle, const char *domid)
-{
- if (!xs_release_domain(handles[handle], atoi(domid)))
+static void do_release(unsigned int handle, const char *domid, const char *mfn)
+{
+ if (!xs_release_domain(handles[handle], atoi(domid), atol(mfn)))
failed(handle);
}
@@ -809,7 +810,7 @@
do_introduce(handle, arg(line, 1), arg(line, 2),
arg(line, 3), arg(line, 4));
else if (streq(command, "release"))
- do_release(handle, arg(line, 1));
+ do_release(handle, arg(line, 1), arg(line, 2));
else if (streq(command, "dump"))
dump(handle);
else if (streq(command, "sleep")) {
--
A bad analogy is like a leaky screwdriver -- Richard Braakman
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|