[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.