WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

Re: [Xen-devel] /proc/xen/xenbus supports watch?

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