# HG changeset patch
# User Rusty Russell <rusty@xxxxxxxxxxxxxxx>
# Node ID b0de1894df67ac7c7d905bf61cdf0210b42752cc
# Parent ba5d5bd28edf8bce89bdf9fc64047ee4f1dceded
Xenstore watch rework
Change watches to all fire simultaneously, removing priority argument.
Watches no longer fired back to connection/domain which caused event.
Fix up testsuite to match
Use state enum, rather than return value inside daemon to determine blockage
Signed-off-by: Rusty Russell <rusty@xxxxxxxxxxxxxxx>
diff -r ba5d5bd28edf -r b0de1894df67
linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_probe.c
--- a/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Thu Aug 4
10:43:03 2005
+++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Thu Aug 4
11:39:03 2005
@@ -800,7 +800,6 @@
{
static int init_done = 0;
static struct xenbus_watch watch = { .node = "/",
- .priority = 0,
.callback = test_callback };
if(init_done) return;
diff -r ba5d5bd28edf -r b0de1894df67
linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_xs.c
--- a/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_xs.c Thu Aug 4
10:43:03 2005
+++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_xs.c Thu Aug 4
11:39:03 2005
@@ -321,18 +321,14 @@
return xs_single(XS_GETDOMAINPATH, domid_str, NULL);
}
-static int xs_watch(const char *path, const char *token, unsigned int priority)
-{
- char prio[32];
- struct kvec iov[3];
-
- sprintf(prio, "%u", priority);
+static int xs_watch(const char *path, const char *token)
+{
+ struct kvec iov[2];
+
iov[0].iov_base = (void *)path;
iov[0].iov_len = strlen(path) + 1;
iov[1].iov_base = (void *)token;
iov[1].iov_len = strlen(token) + 1;
- iov[2].iov_base = prio;
- iov[2].iov_len = strlen(prio) + 1;
return xs_error(xs_talkv(XS_WATCH, iov, ARRAY_SIZE(iov), NULL));
}
@@ -393,7 +389,7 @@
BUG_ON(find_watch(token));
down(&xs_lock);
- err = xs_watch(watch->node, token, watch->priority);
+ err = xs_watch(watch->node, token);
up(&xs_lock);
if (!err)
list_add(&watch->list, &watches);
diff -r ba5d5bd28edf -r b0de1894df67
linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h
--- a/linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h Thu Aug 4 10:43:03 2005
+++ b/linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h Thu Aug 4 11:39:03 2005
@@ -117,7 +117,6 @@
{
struct list_head list;
char *node;
- unsigned int priority;
void (*callback)(struct xenbus_watch *, const char *node);
};
diff -r ba5d5bd28edf -r b0de1894df67 tools/python/xen/lowlevel/xs/xs.c
--- a/tools/python/xen/lowlevel/xs/xs.c Thu Aug 4 10:43:03 2005
+++ b/tools/python/xen/lowlevel/xs/xs.c Thu Aug 4 11:39:03 2005
@@ -343,7 +343,6 @@
#define xspy_watch_doc "\n" \
"Watch a path, get notifications when it changes.\n" \
" path [string] : xenstore path.\n" \
- " priority [int] : watch priority (default 0).\n" \
" token [string] : returned in watch notification.\n" \
"\n" \
"Returns: [int] 0 on success.\n" \
@@ -352,10 +351,9 @@
static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds)
{
- static char *kwd_spec[] = { "path", "priority", "token", NULL };
+ static char *kwd_spec[] = { "path", "token", NULL };
static char *arg_spec = "s|is";
char *path = NULL;
- int priority = 0;
char *token = "";
struct xs_handle *xh = xshandle(self);
@@ -365,9 +363,9 @@
if (!xh)
goto exit;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
- &path, &priority, &token))
- goto exit;
- xsval = xs_watch(xh, path, token, priority);
+ &path, &token))
+ goto exit;
+ xsval = xs_watch(xh, path, token);
val = pyvalue_int(xsval);
exit:
return val;
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/Makefile
--- a/tools/xenstore/Makefile Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/Makefile Thu Aug 4 11:39:03 2005
@@ -42,9 +42,8 @@
xs_test: xs_test.o xs_lib.o utils.o
xs_random: xs_random.o xs_test_lib.o xs_lib.o talloc.o utils.o
xs_stress: xs_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o
-xs_watch_stress: xs_watch_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o
-xs_test.o xs_stress.o xs_watch_stress.o xenstored_core_test.o
xenstored_watch_test.o xenstored_transaction_test.o xenstored_domain_test.o
xs_random.o xs_test_lib.o talloc_test.o fake_libxc.o: CFLAGS=$(BASECFLAGS)
$(TESTFLAGS)
+xs_test.o xs_stress.o xenstored_core_test.o xenstored_watch_test.o
xenstored_transaction_test.o xenstored_domain_test.o xs_random.o xs_test_lib.o
talloc_test.o fake_libxc.o: CFLAGS=$(BASECFLAGS) $(TESTFLAGS)
xenstored_%_test.o: xenstored_%.c
$(COMPILE.c) -o $@ $<
@@ -66,7 +65,7 @@
clean: testsuite-clean
rm -f *.o *.opic *.a
- rm -f xen xenstored xs_random xs_stress xs_watch_stress
+ rm -f xen xenstored xs_random xs_stress
rm -f xs_test xenstored_test xs_dom0_test
-$(RM) $(PROG_DEP)
@@ -86,11 +85,9 @@
$(TESTENV) ./xs_random --fast /tmp/xs_random 100000 $(RANDSEED)
$(TESTENV) ./xs_random --fail /tmp/xs_random 10000 $(RANDSEED)
-stresstest: xs_stress xs_watch_stress xenstored_test
+stresstest: xs_stress xenstored_test
rm -rf $(TESTDIR)/store $(TESTDIR)/transactions
export $(TESTENV); PID=`./xenstored_test --output-pid
--trace-file=/tmp/trace`; ./xs_stress 5000; ret=$$?; kill $$PID; exit $$ret
- rm -rf $(TESTDIR)/store $(TESTDIR)/transactions
- export $(TESTENV); PID=`./xenstored_test --output-pid`;
./xs_watch_stress; ret=$$?; kill $$PID; exit $$ret
xs_dom0_test: xs_dom0_test.o utils.o
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxc -o $@
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/testsuite/07watch.sh
--- a/tools/xenstore/testsuite/07watch.sh Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/testsuite/07watch.sh Thu Aug 4 11:39:03 2005
@@ -3,20 +3,20 @@
# Watch something, write to it, check watch has fired.
[ "`echo -e 'write /test create contents' | ./xs_test 2>&1`" = "" ]
-[ "`echo -e '1 watch /test token 100
+[ "`echo -e '1 watch /test token
2 write /test create contents2
1 waitwatch
1 ackwatch token' | ./xs_test 2>&1`" = "1:/test:token" ]
# Check that reads don't set it off.
-[ "`echo -e '1 watch /test token 100
+[ "`echo -e '1 watch /test token
2 read /test
1 waitwatch' | ./xs_test 2>&1`" = "2:contents2
1:waitwatch timeout" ]
# mkdir, setperm and rm should (also tests watching dirs)
[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ]
-[ "`echo -e '1 watch /dir token 100
+[ "`echo -e '1 watch /dir token
2 mkdir /dir/newdir
1 waitwatch
1 ackwatch token
@@ -29,18 +29,23 @@
1:/dir/newdir:token
1:/dir/newdir:token" ]
+# We don't get a watch from our own commands.
+[ "`echo -e 'watch /dir token
+mkdir /dir/newdir
+waitwatch' | ./xs_test 2>&1`" = "waitwatch timeout" ]
+
# ignore watches while doing commands, should work.
-[ "`echo -e 'watch /dir token 100
-write /dir/test create contents
+[ "`echo -e 'watch /dir token
+1 write /dir/test create contents
read /dir/test
waitwatch
ackwatch token' | ./xs_test 2>&1`" = "contents
/dir/test:token" ]
-# watch priority /test.
-[ "`echo -e '1 watch /dir token1 1
-3 watch /dir token3 3
-2 watch /dir token2 2
+# watch priority test: all simultaneous
+[ "`echo -e '1 watch /dir token1
+3 watch /dir token3
+2 watch /dir token2
write /dir/test create contents
3 waitwatch
3 ackwatch token3
@@ -52,8 +57,8 @@
1:/dir/test:token1" ]
# If one dies (without acking), the other should still get ack.
-[ "`echo -e '1 watch /dir token1 0
-2 watch /dir token2 1
+[ "`echo -e '1 watch /dir token1
+2 watch /dir token2
write /dir/test create contents
2 waitwatch
2 close
@@ -62,40 +67,40 @@
1:/dir/test:token1" ]
# If one dies (without reading at all), the other should still get ack.
-[ "`echo -e '1 watch /dir token1 0
-2 watch /dir token2 1
+[ "`echo -e '1 watch /dir token1
+2 watch /dir token2
write /dir/test create contents
2 close
1 waitwatch
1 ackwatch token1' | ./xs_test 2>&1`" = "1:/dir/test:token1" ]
# unwatch
-[ "`echo -e '1 watch /dir token1 0
+[ "`echo -e '1 watch /dir token1
1 unwatch /dir token1
-1 watch /dir token2 0
+1 watch /dir token2
2 write /dir/test2 create contents
1 waitwatch
1 unwatch /dir token2' | ./xs_test 2>&1`" = "1:/dir/test2:token2" ]
# unwatch while watch pending. Next watcher gets the event.
-[ "`echo -e '1 watch /dir token1 0
-2 watch /dir token2 1
+[ "`echo -e '1 watch /dir token1
+2 watch /dir token2
write /dir/test create contents
2 unwatch /dir token2
1 waitwatch
1 ackwatch token1' | ./xs_test 2>&1`" = "1:/dir/test:token1" ]
# unwatch while watch pending. Should clear this so we get next event.
-[ "`echo -e '1 watch /dir token1 0
+[ "`echo -e '1 watch /dir token1
write /dir/test create contents
1 unwatch /dir token1
-1 watch /dir/test token2 0
+1 watch /dir/test token2
write /dir/test none contents2
1 waitwatch
1 ackwatch token2' | ./xs_test 2>&1`" = "1:/dir/test:token2" ]
# check we only get notified once.
-[ "`echo -e '1 watch /test token 100
+[ "`echo -e '1 watch /test token
2 write /test create contents2
1 waitwatch
1 ackwatch token
@@ -103,7 +108,7 @@
1:waitwatch timeout" ]
# watches are queued in order.
-[ "`echo -e '1 watch / token 100
+[ "`echo -e '1 watch / token
2 write /test1 create contents
2 write /test2 create contents
2 write /test3 create contents
@@ -117,7 +122,7 @@
1:/test3:token" ]
# Creation of subpaths should be covered correctly.
-[ "`echo -e '1 watch / token 100
+[ "`echo -e '1 watch / token
2 write /test/subnode create contents2
2 write /test/subnode/subnode create contents2
1 waitwatch
@@ -129,22 +134,22 @@
1:waitwatch timeout" ]
# Watch event must have happened before we registered interest.
-[ "`echo -e '1 watch / token 100
+[ "`echo -e '1 watch / token
2 write /test/subnode create contents2
-2 watch / token2 0
+1 watch / token2 0
1 waitwatch
1 ackwatch token
-2 waitwatch' | ./xs_test 2>&1`" = "1:/test/subnode:token
-2:waitwatch timeout" ]
+1 waitwatch' | ./xs_test 2>&1`" = "1:/test/subnode:token
+1:waitwatch timeout" ]
# Rm fires notification on child.
-[ "`echo -e '1 watch /test/subnode token 100
+[ "`echo -e '1 watch /test/subnode token
2 rm /test
1 waitwatch
1 ackwatch token' | ./xs_test 2>&1`" = "1:/test/subnode:token" ]
# Watch should not double-send after we ack, even if we did something in
between.
-[ "`echo -e '1 watch /test2 token 100
+[ "`echo -e '1 watch /test2 token
2 write /test2/foo create contents2
1 waitwatch
1 read /test2/foo
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/testsuite/08transaction.sh
--- a/tools/xenstore/testsuite/08transaction.sh Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/testsuite/08transaction.sh Thu Aug 4 11:39:03 2005
@@ -45,27 +45,27 @@
sleep 1
rm /test/entry1
commit
-dir /test' | ./xs_test`" = "" ]
+dir /test' | ./xs_test --no-timeout`" = "" ]
# ... as long as noone is waiting.
[ "`echo -e '1 start /test
2 mkdir /test/dir
1 mkdir /test/dir
1 dir /test
-1 commit' | ./xs_test 2>&1`" = "1:dir
+1 commit' | ./xs_test --no-timeout 2>&1`" = "1:dir
FATAL: 1: commit: Connection timed out" ]
# Events inside transactions don't trigger watches until (successful) commit.
-[ "`echo -e '1 watch /test token 100
+[ "`echo -e '1 watch /test token
2 start /test
2 mkdir /test/dir/sub
1 waitwatch' | ./xs_test 2>&1`" = "1:waitwatch timeout" ]
-[ "`echo -e '1 watch /test token 100
+[ "`echo -e '1 watch /test token
2 start /test
2 mkdir /test/dir/sub
2 abort
1 waitwatch' | ./xs_test 2>&1`" = "1:waitwatch timeout" ]
-[ "`echo -e '1 watch /test token 100
+[ "`echo -e '1 watch /test token
2 start /test
2 mkdir /test/dir/sub
2 commit
@@ -73,7 +73,7 @@
1 ackwatch token' | ./xs_test 2>&1`" = "1:/test/dir/sub:token" ]
# Rm inside transaction works like rm outside: children get notified.
-[ "`echo -e '1 watch /test/dir/sub token 100
+[ "`echo -e '1 watch /test/dir/sub token
2 start /test
2 rm /test/dir
2 commit
diff -r ba5d5bd28edf -r b0de1894df67
tools/xenstore/testsuite/10domain-homedir.sh
--- a/tools/xenstore/testsuite/10domain-homedir.sh Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/testsuite/10domain-homedir.sh Thu Aug 4 11:39:03 2005
@@ -13,7 +13,7 @@
# Place a watch using a relative path: expect relative answer.
[ "`echo 'introduce 1 100 7 /home
1 mkdir foo
-1 watch foo token 0
+1 watch foo token
write /home/foo/bar create contents
1 waitwatch
1 ackwatch token' | ./xs_test 2>&1`" = "handle is 1
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/testsuite/11domain-watch.sh
--- a/tools/xenstore/testsuite/11domain-watch.sh Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/testsuite/11domain-watch.sh Thu Aug 4 11:39:03 2005
@@ -6,7 +6,7 @@
[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ]
[ "`echo -e 'introduce 1 100 7 /my/home
-1 watch /test token 100
+1 watch /test token
write /test create contents2
1 waitwatch
1 ackwatch token
@@ -16,8 +16,8 @@
# ignore watches while doing commands, should work.
[ "`echo -e 'introduce 1 100 7 /my/home
-1 watch /dir token 100
-1 write /dir/test create contents
+1 watch /dir token
+write /dir/test create contents
1 read /dir/test
1 waitwatch
1 ackwatch token
@@ -27,9 +27,9 @@
# unwatch
[ "`echo -e 'introduce 1 100 7 /my/home
-1 watch /dir token1 0
+1 watch /dir token1
1 unwatch /dir token1
-1 watch /dir token2 0
+1 watch /dir token2
2 write /dir/test2 create contents
1 waitwatch
1 unwatch /dir token2
@@ -39,8 +39,8 @@
# unwatch while watch pending.
[ "`echo -e 'introduce 1 100 7 /my/home
introduce 2 101 8 /my/secondhome
-1 watch /dir token1 0
-2 watch /dir token2 1
+1 watch /dir token1
+2 watch /dir token2
write /dir/test create contents
2 unwatch /dir token2
1 waitwatch
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/testsuite/12readonly.sh
--- a/tools/xenstore/testsuite/12readonly.sh Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/testsuite/12readonly.sh Thu Aug 4 11:39:03 2005
@@ -9,7 +9,7 @@
[ "`echo 'read /test
getperm /test
-watch /test token 0
+watch /test token
unwatch /test token
start /
commit
@@ -27,7 +27,7 @@
# Check that watches work like normal.
set -m
-[ "`echo 'watch / token 0
+[ "`echo 'watch / token
waitwatch
ackwatch token' | ./xs_test --readonly 2>&1`" = "/test:token" ] &
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_core.c
--- a/tools/xenstore/xenstored_core.c Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/xenstored_core.c Thu Aug 4 11:39:03 2005
@@ -51,7 +51,7 @@
#include "xenstored_domain.h"
static bool verbose;
-static LIST_HEAD(connections);
+LIST_HEAD(connections);
static int tracefd = -1;
#ifdef TESTING
@@ -335,7 +335,7 @@
list_for_each_entry(i, &connections, list) {
if (i->domain)
continue;
- if (!i->blocked)
+ if (i->state == OK)
FD_SET(i->fd, inset);
if (i->out)
FD_SET(i->fd, outset);
@@ -471,8 +471,7 @@
return i;
}
-/* Returns "false", meaning "connection is not blocked". */
-bool send_reply(struct connection *conn, enum xsd_sockmsg_type type,
+void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
const void *data, unsigned int len)
{
struct buffered_data *bdata;
@@ -493,16 +492,15 @@
conn->waiting_reply = bdata;
} else
conn->out = bdata;
- return false;
}
/* Some routines (write, mkdir, etc) just need a non-error return */
-bool send_ack(struct connection *conn, enum xsd_sockmsg_type type)
-{
- return send_reply(conn, type, "OK", sizeof("OK"));
-}
-
-bool send_error(struct connection *conn, int error)
+void send_ack(struct connection *conn, enum xsd_sockmsg_type type)
+{
+ send_reply(conn, type, "OK", sizeof("OK"));
+}
+
+void send_error(struct connection *conn, int error)
{
unsigned int i;
@@ -511,7 +509,7 @@
corrupt(conn, "Unknown error %i (%s)", error,
strerror(error));
- return send_reply(conn, XS_ERROR, xsd_errors[i].errstring,
+ send_reply(conn, XS_ERROR, xsd_errors[i].errstring,
strlen(xsd_errors[i].errstring) + 1);
}
@@ -797,7 +795,7 @@
return false;
}
-static bool send_directory(struct connection *conn, const char *node)
+static void send_directory(struct connection *conn, const char *node)
{
char *path, *reply = talloc_strdup(node, "");
unsigned int reply_len = 0;
@@ -805,13 +803,17 @@
struct dirent *dirent;
node = canonicalize(conn, node);
- if (!check_node_perms(conn, node, XS_PERM_READ))
- return send_error(conn, errno);
+ if (!check_node_perms(conn, node, XS_PERM_READ)) {
+ send_error(conn, errno);
+ return;
+ }
path = node_dir(conn->transaction, node);
dir = talloc_opendir(path);
- if (!dir)
- return send_error(conn, errno);
+ if (!dir) {
+ send_error(conn, errno);
+ return;
+ }
while ((dirent = readdir(*dir)) != NULL) {
int len = strlen(dirent->d_name) + 1;
@@ -824,32 +826,35 @@
reply_len += len;
}
- return send_reply(conn, XS_DIRECTORY, reply, reply_len);
-}
-
-static bool do_read(struct connection *conn, const char *node)
+ send_reply(conn, XS_DIRECTORY, reply, reply_len);
+}
+
+static void do_read(struct connection *conn, const char *node)
{
char *value;
unsigned int size;
int *fd;
node = canonicalize(conn, node);
- if (!check_node_perms(conn, node, XS_PERM_READ))
- return send_error(conn, errno);
+ if (!check_node_perms(conn, node, XS_PERM_READ)) {
+ send_error(conn, errno);
+ return;
+ }
fd = talloc_open(node_datafile(conn->transaction, node), O_RDONLY, 0);
if (!fd) {
/* Data file doesn't exist? We call that a directory */
if (errno == ENOENT)
errno = EISDIR;
- return send_error(conn, errno);
+ send_error(conn, errno);
+ return;
}
value = read_all(fd, &size);
if (!value)
- return send_error(conn, errno);
-
- return send_reply(conn, XS_READ, value, size);
+ send_error(conn, errno);
+ else
+ send_reply(conn, XS_READ, value, size);
}
/* Create a new directory. Optionally put data in it (if data != NULL) */
@@ -893,7 +898,7 @@
}
/* path, flags, data... */
-static bool do_write(struct connection *conn, struct buffered_data *in)
+static void do_write(struct connection *conn, struct buffered_data *in)
{
unsigned int offset, datalen;
char *vec[2];
@@ -902,15 +907,19 @@
struct stat st;
/* Extra "strings" can be created by binary data. */
- if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec))
- return send_error(conn, EINVAL);
+ if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
+ send_error(conn, EINVAL);
+ return;
+ }
node = canonicalize(conn, vec[0]);
- if (!within_transaction(conn->transaction, node))
- return send_error(conn, EROFS);
+ if (!within_transaction(conn->transaction, node)) {
+ send_error(conn, EROFS);
+ return;
+ }
if (transaction_block(conn, node))
- return true;
+ return;
offset = strlen(vec[0]) + strlen(vec[1]) + 2;
datalen = in->used - offset;
@@ -921,193 +930,244 @@
mode = XS_PERM_WRITE|XS_PERM_CREATE;
else if (streq(vec[1], XS_WRITE_CREATE_EXCL))
mode = XS_PERM_WRITE|XS_PERM_CREATE;
- else
- return send_error(conn, EINVAL);
-
- if (!check_node_perms(conn, node, mode))
- return send_error(conn, errno);
+ else {
+ send_error(conn, EINVAL);
+ return;
+ }
+
+ if (!check_node_perms(conn, node, mode)) {
+ send_error(conn, errno);
+ return;
+ }
if (lstat(node_dir(conn->transaction, node), &st) != 0) {
/* Does not exist... */
- if (errno != ENOENT)
- return send_error(conn, errno);
+ if (errno != ENOENT) {
+ send_error(conn, errno);
+ return;
+ }
/* Not going to create it? */
- if (!(mode & XS_PERM_CREATE))
- return send_error(conn, ENOENT);
-
- if (!new_directory(conn, node, in->buffer + offset, datalen))
- return send_error(conn, errno);
+ if (!(mode & XS_PERM_CREATE)) {
+ send_error(conn, ENOENT);
+ return;
+ }
+
+ if (!new_directory(conn, node, in->buffer + offset, datalen)) {
+ send_error(conn, errno);
+ return;
+ }
} else {
/* Exists... */
- if (streq(vec[1], XS_WRITE_CREATE_EXCL))
- return send_error(conn, EEXIST);
+ if (streq(vec[1], XS_WRITE_CREATE_EXCL)) {
+ send_error(conn, EEXIST);
+ return;
+ }
tmppath = tempfile(node_datafile(conn->transaction, node),
in->buffer + offset, datalen);
- if (!tmppath)
- return send_error(conn, errno);
+ if (!tmppath) {
+ send_error(conn, errno);
+ return;
+ }
commit_tempfile(tmppath);
}
add_change_node(conn->transaction, node, false);
+ fire_watches(conn, node, false);
send_ack(conn, XS_WRITE);
- fire_watches(conn->transaction, node, false);
- return false;
-}
-
-static bool do_mkdir(struct connection *conn, const char *node)
+}
+
+static void do_mkdir(struct connection *conn, const char *node)
{
node = canonicalize(conn, node);
- if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_CREATE))
- return send_error(conn, errno);
-
- if (!within_transaction(conn->transaction, node))
- return send_error(conn, EROFS);
+ if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_CREATE)) {
+ send_error(conn, errno);
+ return;
+ }
+
+ if (!within_transaction(conn->transaction, node)) {
+ send_error(conn, EROFS);
+ return;
+ }
if (transaction_block(conn, node))
- return true;
-
- if (!new_directory(conn, node, NULL, 0))
- return send_error(conn, errno);
+ return;
+
+ if (!new_directory(conn, node, NULL, 0)) {
+ send_error(conn, errno);
+ return;
+ }
add_change_node(conn->transaction, node, false);
+ fire_watches(conn, node, false);
send_ack(conn, XS_MKDIR);
- fire_watches(conn->transaction, node, false);
- return false;
-}
-
-static bool do_rm(struct connection *conn, const char *node)
+}
+
+static void do_rm(struct connection *conn, const char *node)
{
char *tmppath, *path;
node = canonicalize(conn, node);
- if (!check_node_perms(conn, node, XS_PERM_WRITE))
- return send_error(conn, errno);
-
- if (!within_transaction(conn->transaction, node))
- return send_error(conn, EROFS);
+ if (!check_node_perms(conn, node, XS_PERM_WRITE)) {
+ send_error(conn, errno);
+ return;
+ }
+
+ if (!within_transaction(conn->transaction, node)) {
+ send_error(conn, EROFS);
+ return;
+ }
if (transaction_block(conn, node))
- return true;
-
- if (streq(node, "/"))
- return send_error(conn, EINVAL);
+ return;
+
+ if (streq(node, "/")) {
+ send_error(conn, EINVAL);
+ return;
+ }
/* We move the directory to temporary name, destructor cleans up. */
path = node_dir(conn->transaction, node);
tmppath = talloc_asprintf(node, "%s.tmp", path);
talloc_set_destructor(tmppath, destroy_path);
- if (rename(path, tmppath) != 0)
- return send_error(conn, errno);
+ if (rename(path, tmppath) != 0) {
+ send_error(conn, errno);
+ return;
+ }
add_change_node(conn->transaction, node, true);
+ fire_watches(conn, node, true);
send_ack(conn, XS_RM);
- fire_watches(conn->transaction, node, true);
- return false;
-}
-
-static bool do_get_perms(struct connection *conn, const char *node)
+}
+
+static void do_get_perms(struct connection *conn, const char *node)
{
struct xs_permissions *perms;
char *strings;
unsigned int len, num;
node = canonicalize(conn, node);
- if (!check_node_perms(conn, node, XS_PERM_READ))
- return send_error(conn, errno);
+ if (!check_node_perms(conn, node, XS_PERM_READ)) {
+ send_error(conn, errno);
+ return;
+ }
perms = get_perms(conn->transaction, node, &num);
- if (!perms)
- return send_error(conn, errno);
+ if (!perms) {
+ send_error(conn, errno);
+ return;
+ }
strings = perms_to_strings(node, perms, num, &len);
if (!strings)
- return send_error(conn, errno);
-
- return send_reply(conn, XS_GET_PERMS, strings, len);
-}
-
-static bool do_set_perms(struct connection *conn, struct buffered_data *in)
+ send_error(conn, errno);
+ else
+ send_reply(conn, XS_GET_PERMS, strings, len);
+}
+
+static void do_set_perms(struct connection *conn, struct buffered_data *in)
{
unsigned int num;
char *node;
struct xs_permissions *perms;
num = xs_count_strings(in->buffer, in->used);
- if (num < 2)
- return send_error(conn, EINVAL);
+ if (num < 2) {
+ send_error(conn, EINVAL);
+ return;
+ }
/* First arg is node name. */
node = canonicalize(conn, in->buffer);
in->buffer += strlen(in->buffer) + 1;
num--;
- if (!within_transaction(conn->transaction, node))
- return send_error(conn, EROFS);
+ if (!within_transaction(conn->transaction, node)) {
+ send_error(conn, EROFS);
+ return;
+ }
if (transaction_block(conn, node))
- return true;
+ return;
/* We must own node to do this (tools can do this too). */
- if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_OWNER))
- return send_error(conn, errno);
+ if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_OWNER)) {
+ send_error(conn, errno);
+ return;
+ }
perms = talloc_array(node, struct xs_permissions, num);
- if (!xs_strings_to_perms(perms, num, in->buffer))
- return send_error(conn, errno);
-
- if (!set_perms(conn->transaction, node, perms, num))
- return send_error(conn, errno);
+ if (!xs_strings_to_perms(perms, num, in->buffer)) {
+ send_error(conn, errno);
+ return;
+ }
+
+ if (!set_perms(conn->transaction, node, perms, num)) {
+ send_error(conn, errno);
+ return;
+ }
+
add_change_node(conn->transaction, node, false);
+ fire_watches(conn, node, false);
send_ack(conn, XS_SET_PERMS);
- fire_watches(conn->transaction, node, false);
- return false;
}
/* Process "in" for conn: "in" will vanish after this conversation, so
* we can talloc off it for temporary variables. May free "conn".
- * Returns true if can't complete due to block.
*/
-static bool process_message(struct connection *conn, struct buffered_data *in)
+static void process_message(struct connection *conn, struct buffered_data *in)
{
switch (in->hdr.msg.type) {
case XS_DIRECTORY:
- return send_directory(conn, onearg(in));
+ send_directory(conn, onearg(in));
+ break;
case XS_READ:
- return do_read(conn, onearg(in));
+ do_read(conn, onearg(in));
+ break;
case XS_WRITE:
- return do_write(conn, in);
+ do_write(conn, in);
+ break;
case XS_MKDIR:
- return do_mkdir(conn, onearg(in));
+ do_mkdir(conn, onearg(in));
+ break;
case XS_RM:
- return do_rm(conn, onearg(in));
+ do_rm(conn, onearg(in));
+ break;
case XS_GET_PERMS:
- return do_get_perms(conn, onearg(in));
+ do_get_perms(conn, onearg(in));
+ break;
case XS_SET_PERMS:
- return do_set_perms(conn, in);
+ do_set_perms(conn, in);
+ break;
case XS_SHUTDOWN:
/* FIXME: Implement gentle shutdown too. */
/* Only tools can do this. */
- if (conn->id != 0)
- return send_error(conn, EACCES);
- if (!conn->can_write)
- return send_error(conn, EROFS);
+ if (conn->id != 0) {
+ send_error(conn, EACCES);
+ break;
+ }
+ if (!conn->can_write) {
+ send_error(conn, EROFS);
+ break;
+ }
send_ack(conn, XS_SHUTDOWN);
/* Everything hangs off auto-free context, freed at exit. */
exit(0);
+ case XS_DEBUG:
+ if (streq(in->buffer, "print"))
+ xprintf("debug: %s", in->buffer + get_string(in, 0));
#ifdef TESTING
- case XS_DEBUG: {
/* For testing, we allow them to set id. */
if (streq(in->buffer, "setid")) {
conn->id = atoi(in->buffer + get_string(in, 0));
@@ -1118,39 +1178,45 @@
send_ack(conn, XS_DEBUG);
failtest = true;
}
- return false;
- }
#endif /* TESTING */
+ break;
case XS_WATCH:
- return do_watch(conn, in);
+ do_watch(conn, in);
+ break;
case XS_WATCH_ACK:
- return do_watch_ack(conn, onearg(in));
+ do_watch_ack(conn, onearg(in));
+ break;
case XS_UNWATCH:
- return do_unwatch(conn, in);
+ do_unwatch(conn, in);
+ break;
case XS_TRANSACTION_START:
- return do_transaction_start(conn, onearg(in));
+ do_transaction_start(conn, onearg(in));
+ break;
case XS_TRANSACTION_END:
- return do_transaction_end(conn, onearg(in));
+ do_transaction_end(conn, onearg(in));
+ break;
case XS_INTRODUCE:
- return do_introduce(conn, in);
+ do_introduce(conn, in);
+ break;
case XS_RELEASE:
- return do_release(conn, onearg(in));
+ do_release(conn, onearg(in));
+ break;
case XS_GETDOMAINPATH:
- return do_get_domain_path(conn, onearg(in));
+ do_get_domain_path(conn, onearg(in));
+ break;
case XS_WATCH_EVENT:
default:
eprintf("Client unknown operation %i", in->hdr.msg.type);
send_error(conn, ENOSYS);
- return false;
}
}
@@ -1164,6 +1230,8 @@
struct buffered_data *in = NULL;
enum xsd_sockmsg_type type = conn->in->hdr.msg.type;
jmp_buf talloc_fail;
+
+ assert(conn->state == OK);
/* For simplicity, we kill the connection on OOM. */
talloc_set_fail_handler(out_of_mem, &talloc_fail);
@@ -1187,7 +1255,9 @@
*/
in = talloc_steal(talloc_autofree_context(), conn->in);
conn->in = new_buffer(conn);
- if (process_message(conn, in)) {
+ process_message(conn, in);
+
+ if (conn->state == BLOCKED) {
/* Blocked by transaction: queue for re-xmit. */
talloc_free(conn->in);
conn->in = in;
@@ -1210,7 +1280,7 @@
int bytes;
struct buffered_data *in;
- assert(!conn->blocked);
+ assert(conn->state == OK);
in = conn->in;
/* Not finished header yet? */
@@ -1267,13 +1337,17 @@
struct connection *i, *tmp;
list_for_each_entry_safe(i, tmp, &connections, list) {
- if (!i->blocked)
- continue;
-
- if (!transaction_covering_node(i->blocked)) {
- talloc_free(i->blocked);
- i->blocked = NULL;
- consider_message(i);
+ switch (i->state) {
+ case BLOCKED:
+ if (!transaction_covering_node(i->blocked_by)) {
+ talloc_free(i->blocked_by);
+ i->blocked_by = NULL;
+ i->state = OK;
+ consider_message(i);
+ }
+ break;
+ case OK:
+ break;
}
}
@@ -1294,7 +1368,8 @@
if (!new)
return NULL;
- new->blocked = false;
+ new->state = OK;
+ new->blocked_by = NULL;
new->out = new->waiting_reply = NULL;
new->fd = -1;
new->id = 0;
@@ -1303,6 +1378,7 @@
new->write = write;
new->read = read;
new->can_write = true;
+ INIT_LIST_HEAD(&new->watches);
talloc_set_fail_handler(out_of_mem, &talloc_fail);
if (setjmp(talloc_fail)) {
@@ -1371,12 +1447,14 @@
list_for_each_entry(i, &connections, list) {
printf("Connection %p:\n", i);
+ printf(" state = %s\n",
+ i->state == OK ? "OK"
+ : i->state == BLOCKED ? "BLOCKED"
+ : "INVALID");
if (i->id)
printf(" id = %i\n", i->id);
- if (i->blocked)
- printf(" blocked on = %s\n", i->blocked);
- if (i->waiting_for_ack)
- printf(" waiting_for_ack TRUE\n");
+ if (i->blocked_by)
+ printf(" blocked on = %s\n", i->blocked_by);
if (!i->in->inhdr || i->in->used)
printf(" got %i bytes of %s\n",
i->in->used, i->in->inhdr ? "header" : "data");
@@ -1431,7 +1509,6 @@
permfile = talloc_strdup(root, "/tool/xenstored");
if (!set_perms(NULL, permfile, &perms, 1))
barf_perror("Could not create permissions on %s", permfile);
-
talloc_free(root);
if (mkdir(xs_daemon_transactions(), 0750) != 0)
barf_perror("Could not create transaction dir %s",
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_core.h
--- a/tools/xenstore/xenstored_core.h Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/xenstored_core.h Thu Aug 4 11:39:03 2005
@@ -47,6 +47,14 @@
typedef int connwritefn_t(struct connection *, const void *, unsigned int);
typedef int connreadfn_t(struct connection *, void *, unsigned int);
+enum state
+{
+ /* Blocked by transaction. */
+ BLOCKED,
+ /* Completed */
+ OK,
+};
+
struct connection
{
struct list_head list;
@@ -57,8 +65,11 @@
/* Who am I? 0 for socket connections. */
domid_t id;
- /* Are we blocked waiting for a transaction to end? Contains node. */
- char *blocked;
+ /* Blocked on transaction? */
+ enum state state;
+
+ /* Node we are waiting for (if state == BLOCKED) */
+ char *blocked_by;
/* Is this a read-only connection? */
bool can_write;
@@ -81,10 +92,14 @@
/* The domain I'm associated with, if any. */
struct domain *domain;
+ /* My watches. */
+ struct list_head watches;
+
/* Methods for communicating over this connection: write can be NULL */
connwritefn_t *write;
connreadfn_t *read;
};
+extern struct list_head connections;
/* Return length of string (including nul) at this offset. */
unsigned int get_string(const struct buffered_data *data,
@@ -100,14 +115,14 @@
/* Create a new buffer with lifetime of context. */
struct buffered_data *new_buffer(void *ctx);
-bool send_reply(struct connection *conn, enum xsd_sockmsg_type type,
- const void *data, unsigned int len);
+void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
+ const void *data, unsigned int len);
/* Some routines (write, mkdir, etc) just need a non-error return */
-bool send_ack(struct connection *conn, enum xsd_sockmsg_type type);
+void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
/* Send an error: error is usually "errno". */
-bool send_error(struct connection *conn, int error);
+void send_error(struct connection *conn, int error);
/* Canonicalize this path if possible. */
char *canonicalize(struct connection *conn, const char *node);
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_domain.c
--- a/tools/xenstore/xenstored_domain.c Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/xenstored_domain.c Thu Aug 4 11:39:03 2005
@@ -239,7 +239,8 @@
* careful that handle_input/handle_output can destroy conn.
*/
while ((domain = find_domain(port)) != NULL) {
- if (!domain->conn->blocked && buffer_has_input(domain->input))
+ if (domain->conn->state == OK
+ && buffer_has_input(domain->input))
handle_input(domain->conn);
else if (domain->conn->out
&& buffer_has_output_room(domain->output))
@@ -287,33 +288,42 @@
}
/* domid, mfn, evtchn, path */
-bool do_introduce(struct connection *conn, struct buffered_data *in)
+void do_introduce(struct connection *conn, struct buffered_data *in)
{
struct domain *domain;
char *vec[4];
- if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec))
- return send_error(conn, EINVAL);
-
- if (conn->id != 0)
- return send_error(conn, EACCES);
-
- if (!conn->can_write)
- return send_error(conn, EROFS);
+ if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
+ send_error(conn, EINVAL);
+ return;
+ }
+
+ if (conn->id != 0) {
+ send_error(conn, EACCES);
+ return;
+ }
+
+ if (!conn->can_write) {
+ send_error(conn, EROFS);
+ return;
+ }
/* Sanity check args. */
- if ((atoi(vec[2]) <= 0) || !is_valid_nodename(vec[3]))
- return send_error(conn, EINVAL);
+ if ((atoi(vec[2]) <= 0) || !is_valid_nodename(vec[3])) {
+ 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]);
- if (!domain)
- return send_error(conn, errno);
+ if (!domain) {
+ send_error(conn, errno);
+ return;
+ }
/* Now domain belongs to its connection. */
talloc_steal(domain->conn, domain);
-
- return send_ack(conn, XS_INTRODUCE);
+ send_ack(conn, XS_INTRODUCE);
}
static struct domain *find_domain_by_domid(domid_t domid)
@@ -328,39 +338,51 @@
}
/* domid */
-bool do_release(struct connection *conn, const char *domid_str)
+void do_release(struct connection *conn, const char *domid_str)
{
struct domain *domain;
domid_t domid;
- if (!domid_str)
- return send_error(conn, EINVAL);
+ if (!domid_str) {
+ send_error(conn, EINVAL);
+ return;
+ }
domid = atoi(domid_str);
- if (!domid)
- return send_error(conn, EINVAL);
-
- if (conn->id != 0)
- return send_error(conn, EACCES);
+ if (!domid) {
+ send_error(conn, EINVAL);
+ return;
+ }
+
+ if (conn->id != 0) {
+ send_error(conn, EACCES);
+ return;
+ }
domain = find_domain_by_domid(domid);
- if (!domain)
- return send_error(conn, ENOENT);
-
- if (!domain->conn)
- return send_error(conn, EINVAL);
-
- talloc_free(domain->conn);
- return send_ack(conn, XS_RELEASE);
-}
-
-bool do_get_domain_path(struct connection *conn, const char *domid_str)
+ if (!domain) {
+ send_error(conn, ENOENT);
+ return;
+ }
+
+ if (!domain->conn) {
+ send_error(conn, EINVAL);
+ return;
+ }
+
+ talloc_free(domain->conn);
+ send_ack(conn, XS_RELEASE);
+}
+
+void do_get_domain_path(struct connection *conn, const char *domid_str)
{
struct domain *domain;
domid_t domid;
- if (!domid_str)
- return send_error(conn, EINVAL);
+ if (!domid_str) {
+ send_error(conn, EINVAL);
+ return;
+ }
domid = atoi(domid_str);
if (domid == DOMID_SELF)
@@ -368,11 +390,11 @@
else
domain = find_domain_by_domid(domid);
- if (!domain)
- return send_error(conn, ENOENT);
-
- return send_reply(conn, XS_GETDOMAINPATH, domain->path,
- strlen(domain->path) + 1);
+ if (!domain)
+ send_error(conn, ENOENT);
+ else
+ send_reply(conn, XS_GETDOMAINPATH, domain->path,
+ strlen(domain->path) + 1);
}
static int close_xc_handle(void *_handle)
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_domain.h
--- a/tools/xenstore/xenstored_domain.h Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/xenstored_domain.h Thu Aug 4 11:39:03 2005
@@ -22,13 +22,13 @@
void handle_event(int event_fd);
/* domid, mfn, eventchn, path */
-bool do_introduce(struct connection *conn, struct buffered_data *in);
+void do_introduce(struct connection *conn, struct buffered_data *in);
/* domid */
-bool do_release(struct connection *conn, const char *domid_str);
+void do_release(struct connection *conn, const char *domid_str);
/* domid */
-bool do_get_domain_path(struct connection *conn, const char *domid_str);
+void do_get_domain_path(struct connection *conn, const char *domid_str);
/* Returns the event channel handle */
int domain_init(void);
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_transaction.c
--- a/tools/xenstore/xenstored_transaction.c Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/xenstored_transaction.c Thu Aug 4 11:39:03 2005
@@ -114,7 +114,8 @@
trans = transaction_covering_node(node);
if (trans) {
start_transaction_timeout(trans);
- conn->blocked = talloc_strdup(conn, node);
+ conn->state = BLOCKED;
+ conn->blocked_by = talloc_strdup(conn, node);
return true;
}
return false;
@@ -239,20 +240,24 @@
return true;
}
-bool do_transaction_start(struct connection *conn, const char *node)
+void do_transaction_start(struct connection *conn, const char *node)
{
struct transaction *transaction;
char *dir;
- if (conn->transaction)
- return send_error(conn, EBUSY);
+ if (conn->transaction) {
+ send_error(conn, EBUSY);
+ return;
+ }
node = canonicalize(conn, node);
- if (!check_node_perms(conn, node, XS_PERM_READ))
- return send_error(conn, errno);
+ if (!check_node_perms(conn, node, XS_PERM_READ)) {
+ send_error(conn, errno);
+ return;
+ }
if (transaction_block(conn, node))
- return true;
+ return;
dir = node_dir_outside_transaction(node);
@@ -270,18 +275,19 @@
talloc_set_destructor(transaction, destroy_transaction);
trace_create(transaction, "transaction");
- if (!copy_dir(dir, transaction->divert))
- return send_error(conn, errno);
+ if (!copy_dir(dir, transaction->divert)) {
+ send_error(conn, errno);
+ return;
+ }
talloc_steal(conn, transaction);
conn->transaction = transaction;
- return send_ack(transaction->conn, XS_TRANSACTION_START);
+ send_ack(transaction->conn, XS_TRANSACTION_START);
}
static bool commit_transaction(struct transaction *trans)
{
char *tmp, *dir;
- struct changed_node *i;
/* Move: orig -> .old, repl -> orig. Cleanup deletes .old. */
dir = node_dir_outside_transaction(trans->node);
@@ -294,39 +300,44 @@
trans->divert, dir);
trans->divert = tmp;
-
- /* Fire off the watches for everything that changed. */
- list_for_each_entry(i, &trans->changes, list)
- fire_watches(NULL, i->node, i->recurse);
return true;
}
-bool do_transaction_end(struct connection *conn, const char *arg)
-{
- if (!arg || (!streq(arg, "T") && !streq(arg, "F")))
- return send_error(conn, EINVAL);
-
- if (!conn->transaction)
- return send_error(conn, ENOENT);
+void do_transaction_end(struct connection *conn, const char *arg)
+{
+ struct changed_node *i;
+ struct transaction *trans;
+
+ if (!arg || (!streq(arg, "T") && !streq(arg, "F"))) {
+ send_error(conn, EINVAL);
+ return;
+ }
+
+ if (!conn->transaction) {
+ send_error(conn, ENOENT);
+ return;
+ }
+
+ /* Set to NULL so fire_watches sends events. */
+ trans = conn->transaction;
+ conn->transaction = NULL;
+ /* Attach transaction to arg for auto-cleanup */
+ talloc_steal(arg, trans);
if (streq(arg, "T")) {
- if (conn->transaction->destined_to_fail) {
+ if (trans->destined_to_fail) {
send_error(conn, ETIMEDOUT);
- goto failed;
+ return;
}
- if (!commit_transaction(conn->transaction)) {
+ if (!commit_transaction(trans)) {
send_error(conn, errno);
- goto failed;
+ return;
}
- }
-
- talloc_free(conn->transaction);
- conn->transaction = NULL;
- return send_ack(conn, XS_TRANSACTION_END);
-
-failed:
- talloc_free(conn->transaction);
- conn->transaction = NULL;
- return false;
-}
-
+
+ /* Fire off the watches for everything that changed. */
+ list_for_each_entry(i, &trans->changes, list)
+ fire_watches(conn, i->node, i->recurse);
+ }
+ send_ack(conn, XS_TRANSACTION_END);
+}
+
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_transaction.h
--- a/tools/xenstore/xenstored_transaction.h Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/xenstored_transaction.h Thu Aug 4 11:39:03 2005
@@ -22,8 +22,8 @@
struct transaction;
-bool do_transaction_start(struct connection *conn, const char *node);
-bool do_transaction_end(struct connection *conn, const char *arg);
+void do_transaction_start(struct connection *conn, const char *node);
+void do_transaction_end(struct connection *conn, const char *arg);
/* Is node covered by this transaction? */
bool within_transaction(struct transaction *trans, const char *node);
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_watch.c
--- a/tools/xenstore/xenstored_watch.c Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/xenstored_watch.c Thu Aug 4 11:39:03 2005
@@ -33,69 +33,36 @@
#include "xenstored_domain.h"
/* FIXME: time out unacked watches. */
-
-/* We create this if anyone is interested "node", then we pass it from
- * watch to watch as each connection acks it.
- */
struct watch_event
{
- /* The watch we are firing for (watch->events) */
+ /* The events on this watch. */
struct list_head list;
- /* Watches we need to fire for (watches[0]->events == this). */
- struct watch **watches;
- unsigned int num_watches;
-
- struct timeval timeout;
-
- /* Name of node which changed. */
- char *node;
-
- /* For remove, we trigger on all the children of this node too. */
- bool recurse;
+ /* Data to send (node\0token\0). */
+ unsigned int len;
+ char *data;
};
struct watch
{
+ /* Watches on this connection */
struct list_head list;
- unsigned int priority;
/* Current outstanding events applying to this watch. */
struct list_head events;
/* Is this relative to connnection's implicit path? */
- bool relative;
+ const char *relative_path;
char *token;
char *node;
- struct connection *conn;
};
-static LIST_HEAD(watches);
-
-static struct watch_event *get_first_event(struct connection *conn)
-{
- struct watch *watch;
- struct watch_event *event;
-
- /* Find first watch with an event. */
- list_for_each_entry(watch, &watches, list) {
- if (watch->conn != conn)
- continue;
-
- event = list_top(&watch->events, struct watch_event, list);
- if (event)
- return event;
- }
- return NULL;
-}
/* Look through our watches: if any of them have an event, queue it. */
void queue_next_event(struct connection *conn)
{
struct watch_event *event;
- const char *node;
- char *buffer;
- unsigned int len;
+ struct watch *watch;
/* We had a reply queued already? Send it: other end will
* discard watch. */
@@ -110,170 +77,83 @@
if (conn->waiting_for_ack)
return;
- event = get_first_event(conn);
- if (!event)
- return;
-
- /* If we decide to cancel, we will reset this. */
- conn->waiting_for_ack = event->watches[0];
-
- /* If we deleted /foo and they're watching /foo/bar, that's what we
- * tell them has changed. */
- if (!is_child(event->node, event->watches[0]->node)) {
- assert(event->recurse);
- node = event->watches[0]->node;
- } else
- node = event->node;
-
- /* If watch placed using relative path, give them relative answer. */
- if (event->watches[0]->relative) {
- node += strlen(get_implicit_path(conn));
- if (node[0] == '/') /* Could be "". */
+ list_for_each_entry(watch, &conn->watches, list) {
+ event = list_top(&watch->events, struct watch_event, list);
+ if (event) {
+ conn->waiting_for_ack = watch;
+ send_reply(conn,XS_WATCH_EVENT,event->data,event->len);
+ break;
+ }
+ }
+}
+
+static int destroy_watch_event(void *_event)
+{
+ struct watch_event *event = _event;
+
+ trace_destroy(event, "watch_event");
+ return 0;
+}
+
+static void add_event(struct watch *watch, const char *node)
+{
+ struct watch_event *event;
+
+ if (watch->relative_path) {
+ node += strlen(watch->relative_path);
+ if (*node == '/') /* Could be "" */
node++;
}
- /* Create reply from path and token */
- len = strlen(node) + 1 + strlen(event->watches[0]->token) + 1;
- buffer = talloc_array(conn, char, len);
- strcpy(buffer, node);
- strcpy(buffer+strlen(node)+1, event->watches[0]->token);
- send_reply(conn, XS_WATCH_EVENT, buffer, len);
- talloc_free(buffer);
-}
-
-static struct watch **find_watches(const char *node, bool recurse,
- unsigned int *num)
-{
- struct watch *i;
- struct watch **ret = NULL;
-
- *num = 0;
-
- /* We include children too if this is an rm. */
- list_for_each_entry(i, &watches, list) {
- if (is_child(node, i->node) ||
- (recurse && is_child(i->node, node))) {
- (*num)++;
- ret = talloc_realloc(node, ret, struct watch *, *num);
- ret[*num - 1] = i;
- }
- }
- return ret;
+ event = talloc(watch, struct watch_event);
+ event->len = strlen(node) + 1 + strlen(watch->token) + 1;
+ event->data = talloc_array(event, char, event->len);
+ strcpy(event->data, node);
+ strcpy(event->data + strlen(node) + 1, watch->token);
+ talloc_set_destructor(event, destroy_watch_event);
+ list_add_tail(&event->list, &watch->events);
+ trace_create(event, "watch_event");
}
/* FIXME: we fail to fire on out of memory. Should drop connections. */
-void fire_watches(struct transaction *trans, const char *node, bool recurse)
-{
- struct watch **watches;
- struct watch_event *event;
- unsigned int num_watches;
+void fire_watches(struct connection *conn, const char *node, bool recurse)
+{
+ struct connection *i;
+ struct watch *watch;
/* During transactions, don't fire watches. */
- if (trans)
- return;
-
- watches = find_watches(node, recurse, &num_watches);
- if (!watches)
- return;
-
- /* Create and fill in info about event. */
- event = talloc(talloc_autofree_context(), struct watch_event);
- event->node = talloc_strdup(event, node);
-
- /* Tie event to this watch. */
- event->watches = watches;
- talloc_steal(event, watches);
- event->num_watches = num_watches;
- event->recurse = recurse;
- list_add_tail(&event->list, &watches[0]->events);
-
- /* Warn if not finished after thirty seconds. */
- gettimeofday(&event->timeout, NULL);
- event->timeout.tv_sec += 30;
-
- /* If connection not doing anything, queue this. */
- if (!watches[0]->conn->out)
- queue_next_event(watches[0]->conn);
-}
-
-/* We're done with this event: see if anyone else wants it. */
-static void move_event_onwards(struct watch_event *event)
-{
- list_del(&event->list);
-
- event->num_watches--;
- event->watches++;
- if (!event->num_watches) {
- talloc_free(event);
- return;
- }
-
- list_add_tail(&event->list, &event->watches[0]->events);
-
- /* If connection not doing anything, queue this. */
- if (!event->watches[0]->conn->out)
- queue_next_event(event->watches[0]->conn);
-}
-
-static void remove_watch_from_events(struct watch *dying_watch)
-{
- struct watch *watch;
- struct watch_event *event;
- unsigned int i;
-
- list_for_each_entry(watch, &watches, list) {
- list_for_each_entry(event, &watch->events, list) {
- for (i = 0; i < event->num_watches; i++) {
- if (event->watches[i] != dying_watch)
- continue;
-
- assert(i != 0);
- memmove(event->watches+i,
- event->watches+i+1,
- (event->num_watches - (i+1))
- * sizeof(struct watch *));
- event->num_watches--;
- }
+ if (conn->transaction)
+ return;
+
+ /* Create an event for each watch. Don't send to self. */
+ list_for_each_entry(i, &connections, list) {
+ if (i == conn)
+ continue;
+
+ list_for_each_entry(watch, &i->watches, list) {
+ if (is_child(node, watch->node))
+ add_event(watch, node);
+ else if (recurse && is_child(watch->node, node))
+ add_event(watch, watch->node);
+ else
+ continue;
+ /* If connection not doing anything, queue this. */
+ if (!i->out)
+ queue_next_event(i);
}
}
}
static int destroy_watch(void *_watch)
{
- struct watch *watch = _watch;
- struct watch_event *event;
-
- /* If we have pending events, pass them on to others. */
- while ((event = list_top(&watch->events, struct watch_event, list)))
- move_event_onwards(event);
-
- /* Remove from global list. */
- list_del(&watch->list);
-
- /* Other events which match this watch must be cleared. */
- remove_watch_from_events(watch);
-
- trace_destroy(watch, "watch");
+ trace_destroy(_watch, "watch");
return 0;
}
-/* We keep watches in priority order. */
-static void insert_watch(struct watch *watch)
-{
- struct watch *i;
-
- list_for_each_entry(i, &watches, list) {
- if (i->priority <= watch->priority) {
- list_add_tail(&watch->list, &i->list);
- return;
- }
- }
-
- list_add_tail(&watch->list, &watches);
-}
-
void shortest_watch_ack_timeout(struct timeval *tv)
{
+ (void)tv;
+#if 0 /* FIXME */
struct watch *watch;
list_for_each_entry(watch, &watches, list) {
@@ -285,10 +165,12 @@
*tv = i->timeout;
}
}
+#endif
}
void check_watch_ack_timeout(void)
{
+#if 0
struct watch *watch;
struct timeval now;
@@ -307,82 +189,97 @@
}
}
}
-}
-
-bool do_watch(struct connection *conn, struct buffered_data *in)
-{
- struct watch *watch;
- char *vec[3];
+#endif
+}
+
+void do_watch(struct connection *conn, struct buffered_data *in)
+{
+ struct watch *watch;
+ char *vec[2];
bool relative;
- if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
- return send_error(conn, EINVAL);
+ if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
+ send_error(conn, EINVAL);
+ return;
+ }
relative = !strstarts(vec[0], "/");
vec[0] = canonicalize(conn, vec[0]);
- if (!check_node_perms(conn, vec[0], XS_PERM_READ))
- return send_error(conn, errno);
+ if (!check_node_perms(conn, vec[0], XS_PERM_READ)) {
+ send_error(conn, errno);
+ return;
+ }
watch = talloc(conn, struct watch);
watch->node = talloc_strdup(watch, vec[0]);
watch->token = talloc_strdup(watch, vec[1]);
- watch->conn = conn;
- watch->priority = strtoul(vec[2], NULL, 0);
- watch->relative = relative;
+ if (relative)
+ watch->relative_path = get_implicit_path(conn);
+ else
+ watch->relative_path = NULL;
+
INIT_LIST_HEAD(&watch->events);
- insert_watch(watch);
+ list_add_tail(&watch->list, &conn->watches);
+ trace_create(watch, "watch");
talloc_set_destructor(watch, destroy_watch);
- trace_create(watch, "watch");
- return send_ack(conn, XS_WATCH);
-}
-
-bool do_watch_ack(struct connection *conn, const char *token)
+ send_ack(conn, XS_WATCH);
+}
+
+void do_watch_ack(struct connection *conn, const char *token)
{
struct watch_event *event;
- if (!token)
- return send_error(conn, EINVAL);
-
- if (!conn->waiting_for_ack)
- return send_error(conn, ENOENT);
-
- event = list_top(&conn->waiting_for_ack->events,
- struct watch_event, list);
- assert(event->watches[0] == conn->waiting_for_ack);
+ if (!token) {
+ send_error(conn, EINVAL);
+ return;
+ }
+
+ if (!conn->waiting_for_ack) {
+ send_error(conn, ENOENT);
+ return;
+ }
+
if (!streq(conn->waiting_for_ack->token, token)) {
/* They're confused: this will cause us to send event again */
conn->waiting_for_ack = NULL;
- return send_error(conn, EINVAL);
- }
-
- move_event_onwards(event);
+ send_error(conn, EINVAL);
+ return;
+ }
+
+ /* Remove event: after ack sent, core will call queue_next_event */
+ event = list_top(&conn->waiting_for_ack->events, struct watch_event,
+ list);
+ list_del(&event->list);
+ talloc_free(event);
+
conn->waiting_for_ack = NULL;
- return send_ack(conn, XS_WATCH_ACK);
-}
-
-bool do_unwatch(struct connection *conn, struct buffered_data *in)
+ send_ack(conn, XS_WATCH_ACK);
+}
+
+void do_unwatch(struct connection *conn, struct buffered_data *in)
{
struct watch *watch;
char *node, *vec[2];
- if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
- return send_error(conn, EINVAL);
+ if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
+ send_error(conn, EINVAL);
+ return;
+ }
/* We don't need to worry if we're waiting for an ack for the
* watch we're deleting: conn->waiting_for_ack was reset by
* this command in consider_message anyway. */
node = canonicalize(conn, vec[0]);
- list_for_each_entry(watch, &watches, list) {
- if (watch->conn != conn)
- continue;
-
+ list_for_each_entry(watch, &conn->watches, list) {
if (streq(watch->node, node) && streq(watch->token, vec[1])) {
+ list_del(&watch->list);
talloc_free(watch);
- return send_ack(conn, XS_UNWATCH);
- }
- }
- return send_error(conn, ENOENT);
+ send_ack(conn, XS_UNWATCH);
+ return;
+ }
+ }
+ send_error(conn, ENOENT);
}
#ifdef TESTING
@@ -391,15 +288,16 @@
struct watch *watch;
struct watch_event *event;
- /* Find first watch with an event. */
- list_for_each_entry(watch, &watches, list) {
- if (watch->conn != conn)
- continue;
-
- printf(" watch on %s token %s prio %i\n",
- watch->node, watch->token, watch->priority);
+ if (conn->waiting_for_ack)
+ printf(" waiting_for_ack for watch on %s token %s\n",
+ conn->waiting_for_ack->node,
+ conn->waiting_for_ack->token);
+
+ list_for_each_entry(watch, &conn->watches, list) {
+ printf(" watch on %s token %s\n",
+ watch->node, watch->token);
list_for_each_entry(event, &watch->events, list)
- printf(" event: %s\n", event->node);
+ printf(" event: %s\n", event->data);
}
}
#endif
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_watch.h
--- a/tools/xenstore/xenstored_watch.h Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/xenstored_watch.h Thu Aug 4 11:39:03 2005
@@ -22,9 +22,9 @@
#include "xenstored_core.h"
-bool do_watch(struct connection *conn, struct buffered_data *in);
-bool do_watch_ack(struct connection *conn, const char *token);
-bool do_unwatch(struct connection *conn, struct buffered_data *in);
+void do_watch(struct connection *conn, struct buffered_data *in);
+void do_watch_ack(struct connection *conn, const char *token);
+void do_unwatch(struct connection *conn, struct buffered_data *in);
/* Is this a watch event message for this connection? */
bool is_watch_event(struct connection *conn, struct buffered_data *out);
@@ -32,8 +32,9 @@
/* Look through our watches: if any of them have an event, queue it. */
void queue_next_event(struct connection *conn);
-/* Fire all watches: recurse means all the children are effected (ie. rm) */
-void fire_watches(struct transaction *trans, const char *node, bool recurse);
+/* Fire all watches: recurse means all the children are effected (ie. rm).
+ */
+void fire_watches(struct connection *conn, const char *node, bool recurse);
/* Find shortest timeout: if any, reduce tv (may already be set). */
void shortest_watch_ack_timeout(struct timeval *tv);
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xs.c
--- a/tools/xenstore/xs.c Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/xs.c Thu Aug 4 11:39:03 2005
@@ -401,22 +401,16 @@
/* Watch a node for changes (poll on fd to detect, or call read_watch()).
* When the node (or any child) changes, fd will become readable.
* Token is returned when watch is read, to allow matching.
- * Priority indicates order if multiple watchers: higher is first.
* Returns false on failure.
*/
-bool xs_watch(struct xs_handle *h, const char *path, const char *token,
- unsigned int priority)
-{
- char prio[MAX_STRLEN(priority)];
- struct iovec iov[3];
-
- sprintf(prio, "%u", priority);
+bool xs_watch(struct xs_handle *h, const char *path, const char *token)
+{
+ struct iovec iov[2];
+
iov[0].iov_base = (void *)path;
iov[0].iov_len = strlen(path) + 1;
iov[1].iov_base = (void *)token;
iov[1].iov_len = strlen(token) + 1;
- iov[2].iov_base = prio;
- iov[2].iov_len = strlen(prio) + 1;
return xs_bool(xs_talkv(h, XS_WATCH, iov, ARRAY_SIZE(iov), NULL));
}
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xs.h
--- a/tools/xenstore/xs.h Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/xs.h Thu Aug 4 11:39:03 2005
@@ -82,11 +82,9 @@
/* Watch a node for changes (poll on fd to detect, or call read_watch()).
* When the node (or any child) changes, fd will become readable.
* Token is returned when watch is read, to allow matching.
- * Priority indicates order if multiple watchers: higher is first.
* Returns false on failure.
*/
-bool xs_watch(struct xs_handle *h, const char *path, const char *token,
- unsigned int priority);
+bool xs_watch(struct xs_handle *h, const char *path, const char *token);
/* Return the FD to poll on to see if a watch has fired. */
int xs_fileno(struct xs_handle *h);
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xs_test.c
--- a/tools/xenstore/xs_test.c Thu Aug 4 10:43:03 2005
+++ b/tools/xenstore/xs_test.c Thu Aug 4 11:39:03 2005
@@ -20,6 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
@@ -33,6 +34,9 @@
#define XSTEST
static struct xs_handle *handles[10] = { NULL };
+
+static bool timeout = true;
+static bool readonly = false;
struct ringbuf_head
{
@@ -184,7 +188,7 @@
" getperm <path>\n"
" setperm <path> <id> <flags> ...\n"
" shutdown\n"
- " watch <path> <token> <prio>\n"
+ " watch <path> <token>\n"
" waitwatch\n"
" ackwatch <token>\n"
" unwatch <path> <token>\n"
@@ -197,22 +201,34 @@
" dump\n");
}
+static int argpos(const char *line, unsigned int num)
+{
+ unsigned int i, len = 0, off = 0;
+
+ for (i = 0; i <= num; i++) {
+ off += len;
+ off += strspn(line + off, " \t\n");
+ len = strcspn(line + off, " \t\n");
+ if (!len)
+ return off;
+ }
+ return off;
+}
+
static char *arg(char *line, unsigned int num)
{
static char *args[10];
- unsigned int i, len = 0;
-
- for (i = 0; i <= num; i++) {
- line += len;
- line += strspn(line, " \t\n");
- len = strcspn(line, " \t\n");
- if (!len)
- barf("Can't get arg %u", num);
- }
+ unsigned int off, len;
+
+ off = argpos(line, num);
+ len = strcspn(line + off, " \t\n");
+
+ if (!len)
+ barf("Can't get arg %u", num);
free(args[num]);
args[num] = malloc(len + 1);
- memcpy(args[num], line, len);
+ memcpy(args[num], line+off, len);
args[num][len] = '\0';
return args[num];
}
@@ -371,10 +387,9 @@
failed(handle);
}
-static void do_watch(unsigned int handle, const char *node, const char *token,
- const char *pri)
-{
- if (!xs_watch(handles[handle], node, token, atoi(pri)))
+static void do_watch(unsigned int handle, const char *node, const char *token)
+{
+ if (!xs_watch(handles[handle], node, token))
failed(handle);
}
@@ -544,23 +559,102 @@
free(subdirs);
}
+static int handle;
+
+static void alarmed(int sig __attribute__((unused)))
+{
+ if (handle) {
+ char handlename[10];
+ sprintf(handlename, "%u:", handle);
+ write(STDOUT_FILENO, handlename, strlen(handlename));
+ }
+ write(STDOUT_FILENO, command, strlen(command));
+ write(STDOUT_FILENO, " timeout\n", strlen(" timeout\n"));
+ exit(1);
+}
+
+static void do_command(unsigned int default_handle, char *line)
+{
+ char *endp;
+
+ if (strspn(line, " \n") == strlen(line))
+ return;
+ if (strstarts(line, "#"))
+ return;
+
+ handle = strtoul(line, &endp, 10);
+ if (endp != line)
+ memmove(line, endp+1, strlen(endp));
+ else
+ handle = default_handle;
+
+ if (!handles[handle]) {
+ if (readonly)
+ handles[handle] = xs_daemon_open_readonly();
+ else
+ handles[handle] = xs_daemon_open();
+ if (!handles[handle])
+ barf_perror("Opening connection to daemon");
+ }
+ command = arg(line, 0);
+
+ if (timeout)
+ alarm(1);
+
+ if (streq(command, "dir"))
+ do_dir(handle, arg(line, 1));
+ else if (streq(command, "read"))
+ do_read(handle, arg(line, 1));
+ else if (streq(command, "write"))
+ do_write(handle,
+ arg(line, 1), arg(line, 2), arg(line, 3));
+ else if (streq(command, "setid"))
+ do_setid(handle, arg(line, 1));
+ else if (streq(command, "mkdir"))
+ do_mkdir(handle, arg(line, 1));
+ else if (streq(command, "rm"))
+ do_rm(handle, arg(line, 1));
+ else if (streq(command, "getperm"))
+ do_getperm(handle, arg(line, 1));
+ else if (streq(command, "setperm"))
+ do_setperm(handle, arg(line, 1), line);
+ else if (streq(command, "shutdown"))
+ do_shutdown(handle);
+ else if (streq(command, "watch"))
+ do_watch(handle, arg(line, 1), arg(line, 2));
+ else if (streq(command, "waitwatch"))
+ do_waitwatch(handle);
+ else if (streq(command, "ackwatch"))
+ do_ackwatch(handle, arg(line, 1));
+ else if (streq(command, "unwatch"))
+ do_unwatch(handle, arg(line, 1), arg(line, 2));
+ else if (streq(command, "close")) {
+ xs_daemon_close(handles[handle]);
+ handles[handle] = NULL;
+ } else if (streq(command, "start"))
+ do_start(handle, arg(line, 1));
+ else if (streq(command, "commit"))
+ do_end(handle, false);
+ else if (streq(command, "abort"))
+ do_end(handle, true);
+ else if (streq(command, "introduce"))
+ 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));
+ else if (streq(command, "dump"))
+ dump(handle);
+ else if (streq(command, "sleep"))
+ sleep(atoi(arg(line, 1)));
+ else
+ barf("Unknown command %s", command);
+ fflush(stdout);
+ alarm(0);
+}
+
int main(int argc, char *argv[])
{
char line[1024];
- bool readonly = false, timeout = true;
- int handle;
-
- static void alarmed(int sig __attribute__((unused)))
- {
- if (handle) {
- char handlename[10];
- sprintf(handlename, "%u:", handle);
- write(STDOUT_FILENO, handlename, strlen(handlename));
- }
- write(STDOUT_FILENO, command, strlen(command));
- write(STDOUT_FILENO, " timeout\n", strlen(" timeout\n"));
- exit(1);
- }
if (argc > 1 && streq(argv[1], "--readonly")) {
readonly = true;
@@ -568,7 +662,7 @@
argv++;
}
- if (argc > 1 && streq(argv[1], "--notimeout")) {
+ if (argc > 1 && streq(argv[1], "--no-timeout")) {
timeout = false;
argc--;
argv++;
@@ -581,81 +675,8 @@
ringbuf_datasize = getpagesize() / 2 - sizeof(struct ringbuf_head);
signal(SIGALRM, alarmed);
- while (fgets(line, sizeof(line), stdin)) {
- char *endp;
-
- if (strspn(line, " \n") == strlen(line))
- continue;
- if (strstarts(line, "#"))
- continue;
-
- handle = strtoul(line, &endp, 10);
- if (endp != line)
- memmove(line, endp+1, strlen(endp));
- else
- handle = 0;
-
- if (!handles[handle]) {
- if (readonly)
- handles[handle] = xs_daemon_open_readonly();
- else
- handles[handle] = xs_daemon_open();
- if (!handles[handle])
- barf_perror("Opening connection to daemon");
- }
- command = arg(line, 0);
-
- if (timeout)
- alarm(5);
- if (streq(command, "dir"))
- do_dir(handle, arg(line, 1));
- else if (streq(command, "read"))
- do_read(handle, arg(line, 1));
- else if (streq(command, "write"))
- do_write(handle,
- arg(line, 1), arg(line, 2), arg(line, 3));
- else if (streq(command, "setid"))
- do_setid(handle, arg(line, 1));
- else if (streq(command, "mkdir"))
- do_mkdir(handle, arg(line, 1));
- else if (streq(command, "rm"))
- do_rm(handle, arg(line, 1));
- else if (streq(command, "getperm"))
- do_getperm(handle, arg(line, 1));
- else if (streq(command, "setperm"))
- do_setperm(handle, arg(line, 1), line);
- else if (streq(command, "shutdown"))
- do_shutdown(handle);
- else if (streq(command, "watch"))
- do_watch(handle, arg(line, 1), arg(line, 2), arg(line,
3));
- else if (streq(command, "waitwatch"))
- do_waitwatch(handle);
- else if (streq(command, "ackwatch"))
- do_ackwatch(handle, arg(line, 1));
- else if (streq(command, "unwatch"))
- do_unwatch(handle, arg(line, 1), arg(line, 2));
- else if (streq(command, "close")) {
- xs_daemon_close(handles[handle]);
- handles[handle] = NULL;
- } else if (streq(command, "start"))
- do_start(handle, arg(line, 1));
- else if (streq(command, "commit"))
- do_end(handle, false);
- else if (streq(command, "abort"))
- do_end(handle, true);
- else if (streq(command, "introduce"))
- 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));
- else if (streq(command, "dump"))
- dump(handle);
- else if (streq(command, "sleep"))
- sleep(atoi(arg(line, 1)));
- else
- barf("Unknown command %s", command);
- fflush(stdout);
- alarm(0);
- }
+ while (fgets(line, sizeof(line), stdin))
+ do_command(0, line);
+
return 0;
}
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xs_watch_stress.c
--- a/tools/xenstore/xs_watch_stress.c Thu Aug 4 10:43:03 2005
+++ /dev/null Thu Aug 4 11:39:03 2005
@@ -1,120 +0,0 @@
-/* Stress test for watch code: two processes communicating by watches */
-#include "xs.h"
-#include "utils.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-int main(int argc __attribute__((unused)), char *argv[])
-{
- int childpid, status, fds[2];
- bool parent;
- unsigned int i, acks = 0;
- struct xs_handle *h;
- char *data;
- unsigned int len;
- const char *path, *otherpath;
-
- pipe(fds);
- childpid = fork();
- if (childpid == -1)
- barf_perror("Failed fork");
- parent = (childpid != 0);
-
- h = xs_daemon_open();
- if (!h)
- barf_perror("Could not connect to daemon");
-
- if (!xs_watch(h, "/", "token", 0))
- barf_perror("Could not set watch");
-
- if (parent) {
- char c;
-
- if (read(fds[0], &c, 1) != 1)
- barf("Child exited");
-
- path = "/parent";
- otherpath = "/child";
- /* Create initial node. */
- if (!xs_write(h, path, "0", 2, O_CREAT))
- barf_perror("Write to %s failed", path);
- } else {
- path = "/child";
- otherpath = "/parent";
-
- if (write(fds[1], "", 1) != 1)
- barf_perror("Write to parent failed");
- }
-
- for (i = 0; i < (argv[1] ? (unsigned)atoi(argv[1]) : 100);) {
- char **vec;
-
- vec = xs_read_watch(h);
- if (!vec)
- barf_perror("Read watch failed");
-
- if (!streq(vec[1], "token"))
- barf("Watch token %s bad", vec[1]);
- if (streq(vec[0], otherpath)) {
- char number[32];
-
- data = xs_read(h, otherpath, &len);
- if (!data)
- barf_perror("reading %s", otherpath);
- sprintf(number, "%i", atoi(data) + 1);
- free(data);
- if (!xs_write(h, path, number, strlen(number) + 1,
- O_CREAT))
- barf_perror("writing %s", path);
- i++;
- } else if (!streq(vec[0], path))
- barf_perror("Watch fired on unknown path %s", vec[0]);
- xs_acknowledge_watch(h, vec[1]);
- acks++;
- free(vec);
- }
-
- if (!parent) {
- while (acks != 2 * i - 1) {
- char **vec;
- vec = xs_read_watch(h);
- if (!vec)
- barf_perror("Watch failed");
- if (!streq(vec[0], path))
- barf_perror("Watch fired path %s", vec[0]);
- if (!streq(vec[1], "token"))
- barf("Watch token %s bad", vec[1]);
- free(vec);
-
- printf("Expect %i events, only got %i\n",
- 2 * i - 1, acks);
- acks++;
- }
- exit(0);
- }
-
- if (acks != 2 * i)
- barf("Parent got %i watch events\n", acks);
-
- printf("Waiting for %i\n", childpid);
- if (waitpid(childpid, &status, 0) != childpid)
- barf_perror("Child wait failed");
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- barf_perror("Child status %i", status);
-
- data = xs_read(h, path, &len);
- if (atoi(data) != 2 * (int)i)
- barf("%s count is %s\n", path, data);
- free(data);
- data = xs_read(h, otherpath, &len);
- if (atoi(data) != 2 * (int)i - 1)
- barf("%s count is %s\n", otherpath, data);
- free(data);
- printf("Success!\n");
- exit(0);
-}
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|