WARNING - OLD ARCHIVES

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

xen-changelog

[Xen-changelog] 1) More testing: include tests which I forgot in previou

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] 1) More testing: include tests which I forgot in previous patch, remove
From: Xen patchbot -unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Mon, 08 Aug 2005 05:12:11 -0400
Delivery-date: Mon, 08 Aug 2005 09:12:42 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID a9ee400a5da98acc8da566a24ecae05902b2bed2
# Parent  b60643391488ccc7b3d0c304c1a3a522a18671eb
1) More testing: include tests which I forgot in previous patch, remove
xs_watch_stress, reduce cycles in "make check" random test.
2) xs_crashme: corrupt random packets going to xenstored, watch it
crash.
3) Handle second input from before we finished output on first one.
4) Fix bug where one-arg operations are given zero args.
5) Fix bug where SET_PERMS fails after blocking on transaction.
6) Fix memory leak when DIRECTORY op given no argument.
7) Fail on first memory leak, for better testing.
8) Fix missing waiting_for_ack initialization for new connections.
9) Ensure all input and output is handled for domains so we don't stall.
10) Fix overrun bug in xs_count_strings on non-nul-terminated strings.
11) New test for clients which write without waiting for response.

Signed-off-by: Rusty Russell <rusty@xxxxxxxxxxxxxxx>

diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/Makefile
--- a/tools/xenstore/Makefile   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/Makefile   Mon Aug  8 09:13:19 2005
@@ -41,9 +41,9 @@
 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_crashme: xs_crashme.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 xs_crashme.o: CFLAGS=$(BASECFLAGS) $(TESTFLAGS)
 
 xenstored_%_test.o: xenstored_%.c
        $(COMPILE.c) -o $@ $<
@@ -65,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 xs_crashme
        rm -f xs_test xenstored_test xs_dom0_test
        -$(RM) $(PROG_DEP)
 
@@ -96,14 +96,18 @@
        $(TESTENV) ./xs_random --fast /tmp/xs_random 100000 $(RANDSEED) && echo
        $(TESTENV) ./xs_random --fail /tmp/xs_random 10000 $(RANDSEED)
 
+crashme:  xs_crashme xenstored_test
+       rm -rf $(TESTDIR)/store $(TESTDIR)/transactions /tmp/xs_crashme.vglog* 
/tmp/trace
+       export $(TESTENV); ./xs_crashme 5000 $(RANDSEED) 2>/dev/null
+       if [ -n "`cat /tmp/xs_crashme.vglog*`" ]; then echo Valgrind 
complained; cat /tmp/xs_crashme.vglog*; exit 1; fi
+       rm -rf $(TESTDIR)/store $(TESTDIR)/transactions /tmp/xs_crashme.vglog* 
/tmp/trace
+
 randomcheck-fast: xs_random xenstored_test
-       @$(TESTENV) ./xs_random --fast /tmp/xs_random 10000 $(RANDSEED)
+       @$(TESTENV) ./xs_random --fast /tmp/xs_random 2000 $(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 b60643391488 -r a9ee400a5da9 tools/xenstore/utils.c
--- a/tools/xenstore/utils.c    Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/utils.c    Mon Aug  8 09:13:19 2005
@@ -84,9 +84,6 @@
 void daemonize(void)
 {
        pid_t pid;
-       int fd;
-       size_t len;
-       char buf[100];
 
        /* Separate from our parent via fork, so init inherits us. */
        if ((pid = fork()) < 0)
@@ -104,18 +101,6 @@
        chdir("/");
        /* Discard our parent's old-fashioned umask prejudices. */
        umask(0);
-
-       fd = open("/var/run/xenstored.pid", O_RDWR | O_CREAT);
-       if (fd == -1) {
-               exit(1);
-       }
-
-       if (lockf(fd, F_TLOCK, 0) == -1) {
-               exit(1);
-       }
-
-       len = sprintf(buf, "%d\n", getpid());
-       write(fd, buf, len);
 }
 
 
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xenstored_core.c
--- a/tools/xenstore/xenstored_core.c   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xenstored_core.c   Mon Aug  8 09:13:19 2005
@@ -252,6 +252,7 @@
        int ret;
        struct buffered_data *out = conn->out;
 
+       assert(conn->state != BLOCKED);
        if (out->inhdr) {
                if (verbose)
                        xprintf("Writing msg %s (%s) out to %p\n",
@@ -289,6 +290,10 @@
        talloc_free(out);
 
        queue_next_event(conn);
+
+       /* No longer busy? */
+       if (!conn->out)
+               conn->state = OK;
        return true;
 }
 
@@ -492,6 +497,8 @@
                conn->waiting_reply = bdata;
        } else
                conn->out = bdata;
+       assert(conn->state != BLOCKED);
+       conn->state = BUSY;
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
@@ -544,7 +551,7 @@
 /* We expect one arg in the input: return NULL otherwise. */
 static const char *onearg(struct buffered_data *in)
 {
-       if (get_string(in, 0) != in->used)
+       if (!in->used || get_string(in, 0) != in->used)
                return NULL;
        return in->buffer;
 }
@@ -807,7 +814,7 @@
 
 static void send_directory(struct connection *conn, const char *node)
 {
-       char *path, *reply = talloc_strdup(node, "");
+       char *path, *reply;
        unsigned int reply_len = 0;
        DIR **dir;
        struct dirent *dirent;
@@ -825,6 +832,7 @@
                return;
        }
 
+       reply = talloc_strdup(node, "");
        while ((dirent = readdir(*dir)) != NULL) {
                int len = strlen(dirent->d_name) + 1;
 
@@ -1082,7 +1090,7 @@
 static void do_set_perms(struct connection *conn, struct buffered_data *in)
 {
        unsigned int num;
-       char *node;
+       char *node, *permstr;
        struct xs_permissions *perms;
 
        num = xs_count_strings(in->buffer, in->used);
@@ -1093,7 +1101,7 @@
 
        /* First arg is node name. */
        node = canonicalize(conn, in->buffer);
-       in->buffer += strlen(in->buffer) + 1;
+       permstr = in->buffer + strlen(in->buffer) + 1;
        num--;
 
        if (!within_transaction(conn->transaction, node)) {
@@ -1111,7 +1119,7 @@
        }
 
        perms = talloc_array(node, struct xs_permissions, num);
-       if (!xs_strings_to_perms(perms, num, in->buffer)) {
+       if (!xs_strings_to_perms(perms, num, permstr)) {
                send_error(conn, errno);
                return;
        }
@@ -1280,8 +1288,10 @@
        talloc_free(in);
        talloc_set_fail_handler(NULL, NULL);
        if (talloc_total_blocks(NULL)
-           != talloc_total_blocks(talloc_autofree_context()) + 1)
+           != talloc_total_blocks(talloc_autofree_context()) + 1) {
                talloc_report_full(NULL, stderr);
+               abort();
+       }
 }
 
 /* Errors in reading or allocating here mean we get out of sync, so we
@@ -1305,8 +1315,10 @@
                        return;
 
                if (in->hdr.msg.len > PATH_MAX) {
+#ifndef TESTING
                        syslog(LOG_DAEMON, "Client tried to feed us %i",
                               in->hdr.msg.len);
+#endif
                        goto bad_client;
                }
 
@@ -1357,6 +1369,7 @@
                                consider_message(i);
                        }
                        break;
+               case BUSY:
                case OK:
                        break;
                }
@@ -1382,6 +1395,7 @@
        new->state = OK;
        new->blocked_by = NULL;
        new->out = new->waiting_reply = NULL;
+       new->waiting_for_ack = NULL;
        new->fd = -1;
        new->id = 0;
        new->domain = NULL;
@@ -1461,6 +1475,7 @@
                printf("    state = %s\n",
                       i->state == OK ? "OK"
                       : i->state == BLOCKED ? "BLOCKED"
+                      : i->state == BUSY ? "BUSY"
                       : "INVALID");
                if (i->id)
                        printf("    id = %i\n", i->id);
@@ -1631,6 +1646,7 @@
        max = initialize_set(&inset, &outset, *sock, *ro_sock, event_fd);
 
        /* Main loop. */
+       /* FIXME: Rewrite so noone can starve. */
        for (;;) {
                struct connection *i;
                struct timeval *tvp = NULL, tv;
@@ -1675,10 +1691,22 @@
                        }
                }
 
-               /* Flush output for domain connections,  */
-               list_for_each_entry(i, &connections, list)
-                       if (i->domain && i->out)
+               /* Handle all possible I/O for domain connections. */
+       more:
+               list_for_each_entry(i, &connections, list) {
+                       if (!i->domain)
+                               continue;
+
+                       if (domain_can_read(i)) {
+                               handle_input(i);
+                               goto more;
+                       }
+
+                       if (domain_can_write(i)) {
                                handle_output(i);
+                               goto more;
+                       }
+               }
 
                if (tvp) {
                        check_transaction_timeout();
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xenstored_core.h
--- a/tools/xenstore/xenstored_core.h   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xenstored_core.h   Mon Aug  8 09:13:19 2005
@@ -51,6 +51,8 @@
 {
        /* Blocked by transaction. */
        BLOCKED,
+       /* Doing action, not listening */
+       BUSY,
        /* Completed */
        OK,
 };
@@ -65,7 +67,7 @@
        /* Who am I?  0 for socket connections. */
        domid_t id;
 
-       /* Blocked on transaction? */
+       /* Blocked on transaction?  Busy? */
        enum state state;
 
        /* Node we are waiting for (if state == BLOCKED) */
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xenstored_domain.c
--- a/tools/xenstore/xenstored_domain.c Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xenstored_domain.c Mon Aug  8 09:13:19 2005
@@ -227,32 +227,27 @@
        return NULL;
 }
 
+/* We scan all domains rather than use the information given here. */
 void handle_event(int event_fd)
 {
        u16 port;
-       struct domain *domain;
 
        if (read(event_fd, &port, sizeof(port)) != sizeof(port))
                barf_perror("Failed to read from event fd");
-
-       /* We have to handle *all* the data available before we ack:
-        * careful that handle_input/handle_output can destroy conn.
-        */
-       while ((domain = find_domain(port)) != NULL) {
-               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))
-                       handle_output(domain->conn);
-               else
-                       break;
-       }
-
 #ifndef TESTING
        if (write(event_fd, &port, sizeof(port)) != sizeof(port))
                barf_perror("Failed to write to event fd");
 #endif
+}
+
+bool domain_can_read(struct connection *conn)
+{
+       return conn->state == OK && buffer_has_input(conn->domain->input);
+}
+
+bool domain_can_write(struct connection *conn)
+{
+       return conn->out && buffer_has_output_room(conn->domain->output);
 }
 
 static struct domain *new_domain(void *context, domid_t domid,
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xenstored_domain.h
--- a/tools/xenstore/xenstored_domain.h Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xenstored_domain.h Mon Aug  8 09:13:19 2005
@@ -40,4 +40,8 @@
 /* Read existing connection information from store. */
 void restore_existing_connections(void);
 
+/* Can connection attached to domain read/write. */
+bool domain_can_read(struct connection *conn);
+bool domain_can_write(struct connection *conn);
+
 #endif /* _XENSTORED_DOMAIN_H */
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xs.c
--- a/tools/xenstore/xs.c       Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xs.c       Mon Aug  8 09:13:19 2005
@@ -204,13 +204,19 @@
                return NULL;
        }
 
-       assert(msg.type == type);
+       if (msg.type != type) {
+               free(ret);
+               saved_errno = EBADF;
+               goto close_fd;
+               
+       }
        return ret;
 
 fail:
        /* We're in a bad state, so close fd. */
        saved_errno = errno;
        sigaction(SIGPIPE, &oldact, NULL);
+close_fd:
        close(h->fd);
        h->fd = -1;
        errno = saved_errno;
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xs_lib.c
--- a/tools/xenstore/xs_lib.c   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xs_lib.c   Mon Aug  8 09:13:19 2005
@@ -152,8 +152,9 @@
        unsigned int num;
        const char *p;
 
-       for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
-               num++;
+       for (p = strings, num = 0; p < strings + len; p++)
+               if (*p == '\0')
+                       num++;
 
        return num;
 }
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xs_random.c
--- a/tools/xenstore/xs_random.c        Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xs_random.c        Mon Aug  8 09:13:19 2005
@@ -349,19 +349,12 @@
 {
        char *dirname = path_to_name(info, path);
 
-       /* Same effective order as daemon, so error returns are right. */
-       if (mkdir(dirname, 0700) != 0) {
-               if (errno != ENOENT && errno != ENOTDIR)
-                       write_ok(info, path);
-               return false;
-       }
-
-       if (!write_ok(info, path)) {
-               int saved_errno = errno;
-               rmdir(dirname);
-               errno = saved_errno;
-               return false;
-       }
+       if (!write_ok(info, path))
+               return false;
+
+       if (mkdir(dirname, 0700) != 0)
+               return false;
+
        init_perms(dirname);
        return true;
 }
@@ -984,13 +977,15 @@
 
 static void setup_file_ops(const char *dir)
 {
-       char *cmd = talloc_asprintf(NULL, "echo -n r0 > %s/.perms", dir);
+       struct xs_permissions perm = { .id = 0, .perms = XS_PERM_READ };
+       struct file_ops_info *h = file_handle(dir);
        if (mkdir(dir, 0700) != 0)
                barf_perror("Creating directory %s", dir);
-       if (mkdir(talloc_asprintf(cmd, "%s/tool", dir), 0700) != 0)
+       if (mkdir(talloc_asprintf(h, "%s/tool", dir), 0700) != 0)
                barf_perror("Creating directory %s/tool", dir);
-       do_command(cmd);
-       talloc_free(cmd);
+       if (!file_set_perms(h, talloc_strdup(h, "/"), &perm, 1))
+               barf_perror("Setting root perms in %s", dir);
+       file_close(h);
 }
 
 static void setup_xs_ops(void)
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xs_test.c
--- a/tools/xenstore/xs_test.c  Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xs_test.c  Mon Aug  8 09:13:19 2005
@@ -28,13 +28,13 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdlib.h>
+#include <sys/mman.h>
 #include <fnmatch.h>
 #include <stdarg.h>
 #include <string.h>
 #include <getopt.h>
 #include <ctype.h>
 #include <sys/time.h>
-#include <sys/mman.h>
 #include "utils.h"
 #include "xs_lib.h"
 #include "list.h"
@@ -43,7 +43,7 @@
 
 static struct xs_handle *handles[10] = { NULL };
 
-static unsigned int timeout_ms = 50;
+static unsigned int timeout_ms = 200;
 static bool timeout_suppressed = true;
 static bool readonly = false;
 static bool print_input = false;
@@ -213,6 +213,8 @@
             "  notimeout\n"
             "  readonly\n"
             "  readwrite\n"
+            "  noackwrite <path> <flags> <value>...\n"
+            "  readack\n"
             "  dump\n");
 }
 
@@ -365,6 +367,45 @@
                failed(handle);
 }
 
+static void do_noackwrite(unsigned int handle,
+                         char *path, const char *flags, char *data)
+{
+       struct xsd_sockmsg msg;
+
+       /* Format: Flags (as string), path, data. */
+       if (streq(flags, "none"))
+               flags = XS_WRITE_NONE;
+       else if (streq(flags, "create"))
+               flags = XS_WRITE_CREATE;
+       else if (streq(flags, "excl"))
+               flags = XS_WRITE_CREATE_EXCL;
+       else
+               barf("noackwrite flags 'none', 'create' or 'excl' only");
+
+       msg.len = strlen(path) + 1 + strlen(flags) + 1 + strlen(data);
+       msg.type = XS_WRITE;
+       if (!write_all_choice(handles[handle]->fd, &msg, sizeof(msg)))
+               failed(handle);
+       if (!write_all_choice(handles[handle]->fd, path, strlen(path) + 1))
+               failed(handle);
+       if (!write_all_choice(handles[handle]->fd, flags, strlen(flags) + 1))
+               failed(handle);
+       if (!write_all_choice(handles[handle]->fd, data, strlen(data)))
+               failed(handle);
+       /* Do not wait for ack. */
+}
+
+static void do_readack(unsigned int handle)
+{
+       enum xsd_sockmsg_type type;
+       char *ret;
+
+       ret = read_reply(handles[handle]->fd, &type, NULL);
+       if (!ret)
+               failed(handle);
+       free(ret);
+}
+
 static void do_setid(unsigned int handle, char *id)
 {
        if (!xs_bool(xs_debug_command(handles[handle], "setid", id,
@@ -466,6 +507,25 @@
                failed(handle);
 }
 
+static void set_timeout(void)
+{
+       struct itimerval timeout;
+
+       timeout.it_value.tv_sec = timeout_ms / 1000;
+       timeout.it_value.tv_usec = (timeout_ms * 1000) % 1000000;
+       timeout.it_interval.tv_sec = timeout.it_interval.tv_usec = 0;
+       setitimer(ITIMER_REAL, &timeout, NULL);
+}
+
+static void disarm_timeout(void)
+{
+       struct itimerval timeout;
+
+       timeout.it_value.tv_sec = 0;
+       timeout.it_value.tv_usec = 0;
+       setitimer(ITIMER_REAL, &timeout, NULL);
+}
+
 static void do_waitwatch(unsigned int handle)
 {
        char **vec;
@@ -474,14 +534,17 @@
        fd_set set;
 
        if (xs_fileno(handles[handle]) != -2) {
+               /* Manually select here so we can time out gracefully. */
                FD_ZERO(&set);
                FD_SET(xs_fileno(handles[handle]), &set);
+               disarm_timeout();
                if (select(xs_fileno(handles[handle])+1, &set,
                           NULL, NULL, &tv) == 0) {
                        errno = ETIMEDOUT;
                        failed(handle);
                        return;
                }
+               set_timeout();
        }
 
        vec = xs_read_watch(handles[handle]);
@@ -529,6 +592,9 @@
 {
        unsigned int i;
        int fd;
+
+       /* This mechanism is v. slow w. valgrind running. */
+       timeout_ms = 5000;
 
        /* We poll, so ignore signal */
        signal(SIGUSR2, SIG_IGN);
@@ -669,24 +735,6 @@
        write(STDOUT_FILENO, command, strlen(command));
        write(STDOUT_FILENO, " timeout\n", strlen(" timeout\n"));
        exit(1);
-}
-
-static void set_timeout(void)
-{
-       struct itimerval timeout;
-
-       timeout.it_interval.tv_sec = timeout_ms / 1000;
-       timeout.it_interval.tv_usec = (timeout_ms * 1000) % 1000000;
-       setitimer(ITIMER_REAL, &timeout, NULL);
-}
-
-static void disarm_timeout(void)
-{
-       struct itimerval timeout;
-
-       timeout.it_interval.tv_sec = 0;
-       timeout.it_interval.tv_usec = 0;
-       setitimer(ITIMER_REAL, &timeout, NULL);
 }
 
 static void do_command(unsigned int default_handle, char *line)
@@ -779,7 +827,11 @@
                readonly = false;
                xs_daemon_close(handles[handle]);
                handles[handle] = NULL;
-       } else
+       } else if (streq(command, "noackwrite"))
+               do_noackwrite(handle, arg(line,1), arg(line,2), arg(line,3));
+       else if (streq(command, "readack"))
+               do_readack(handle);
+       else
                barf("Unknown command %s", command);
        fflush(stdout);
        disarm_timeout();
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/01simple.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/01simple.test    Mon Aug  8 09:13:19 2005
@@ -0,0 +1,4 @@
+# Create an entry, read it.
+write /test create contents
+expect contents
+read /test
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/02directory.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/02directory.test Mon Aug  8 09:13:19 2005
@@ -0,0 +1,34 @@
+# Root directory has only tool dir in it.
+expect tool
+dir /
+
+# Create a file.
+write /test create contents
+
+# Directory shows it.
+expect test
+expect tool
+dir /
+
+# Make a new directory, check it's there
+mkdir /dir
+expect dir
+expect test
+expect tool
+dir /
+
+# Check it's empty.
+dir /dir
+
+# Create a file, check it exists.
+write /dir/test2 create contents2
+expect test2
+dir /dir
+expect contents2
+read /dir/test2
+
+# Creating dir over the top should fail.
+expect mkdir failed: File exists
+mkdir /dir
+expect mkdir failed: File exists
+mkdir /dir/test2
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/03write.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/03write.test     Mon Aug  8 09:13:19 2005
@@ -0,0 +1,20 @@
+# Write without create fails.
+expect write failed: No such file or directory
+write /test none contents
+
+# Exclusive write succeeds
+write /test excl contents
+expect contents
+read /test
+
+# Exclusive write fails to overwrite.
+expect write failed: File exists
+write /test excl contents
+
+# Non-exclusive overwrite succeeds.
+write /test none contents2
+expect contents2
+read /test
+write /test create contents3
+expect contents3
+read /test
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/04rm.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/04rm.test        Mon Aug  8 09:13:19 2005
@@ -0,0 +1,18 @@
+# Remove non-existant fails.
+expect rm failed: No such file or directory
+rm /test
+expect rm failed: No such file or directory
+rm /dir/test
+
+# Create file and remove it
+write /test excl contents
+rm /test
+
+# Create directory and remove it.
+mkdir /dir
+rm /dir
+
+# Create directory, create file, remove all.
+mkdir /dir
+write /dir/test excl contents
+rm /dir
diff -r b60643391488 -r a9ee400a5da9 
tools/xenstore/testsuite/05filepermissions.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/05filepermissions.test   Mon Aug  8 09:13:19 2005
@@ -0,0 +1,81 @@
+# Fail to get perms on non-existent file.
+expect getperm failed: No such file or directory
+getperm /test
+expect getperm failed: No such file or directory
+getperm /dir/test
+
+# Create file: inherits from root (0 READ)
+write /test excl contents
+expect 0 READ
+getperm /test
+setid 1
+expect 0 READ
+getperm /test
+expect contents
+read /test
+expect write failed: Permission denied
+write /test none contents
+
+# Take away read access to file.
+setid 0
+setperm /test 0 NONE
+setid 1
+expect getperm failed: Permission denied
+getperm /test
+expect read failed: Permission denied
+read /test
+expect write failed: Permission denied
+write /test none contents
+
+# Grant everyone write access to file.
+setid 0
+setperm /test 0 WRITE
+setid 1
+expect getperm failed: Permission denied
+getperm /test
+expect read failed: Permission denied
+read /test
+write /test none contents2
+setid 0
+expect contents2
+read /test
+
+# Grant everyone both read and write access.
+setperm /test 0 READ/WRITE
+setid 1
+expect 0 READ/WRITE
+getperm /test
+expect contents2
+read /test
+write /test none contents3
+expect contents3
+read /test
+
+# Change so that user 1 owns it, noone else can do anything.
+setid 0
+setperm /test 1 NONE
+setid 1
+expect 1 NONE
+getperm /test
+expect contents3
+read /test
+write /test none contents4
+
+# User 2 can do nothing.
+setid 2
+expect setperm failed: Permission denied
+setperm /test 2 NONE
+expect getperm failed: Permission denied
+getperm /test
+expect read failed: Permission denied
+read /test
+expect write failed: Permission denied
+write /test none contents4
+
+# Tools can always access things.
+setid 0
+expect 1 NONE
+getperm /test
+expect contents4
+read /test
+write /test none contents5
diff -r b60643391488 -r a9ee400a5da9 
tools/xenstore/testsuite/06dirpermissions.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/06dirpermissions.test    Mon Aug  8 09:13:19 2005
@@ -0,0 +1,119 @@
+# Root directory: owned by tool, everyone has read access.
+expect 0 READ
+getperm /
+
+# Create directory: inherits from root.
+mkdir /dir
+expect 0 READ
+getperm /dir
+setid 1
+expect 0 READ
+getperm /dir
+dir /dir
+expect write failed: Permission denied
+write /dir/test create contents2
+
+# Remove everyone's read access to directoy.
+setid 0
+setperm /dir 0 NONE
+setid 1
+expect dir failed: Permission denied
+dir /dir
+expect read failed: Permission denied
+read /dir/test create contents2
+expect write failed: Permission denied
+write /dir/test create contents2
+
+# Grant everyone write access to directory.
+setid 0
+setperm /dir 0 WRITE
+setid 1
+expect getperm failed: Permission denied
+getperm /dir
+expect dir failed: Permission denied
+dir /dir
+write /dir/test create contents
+setid 0
+expect 1 WRITE
+getperm /dir/test
+setperm /dir/test 0 NONE
+expect contents
+read /dir/test
+
+# Grant everyone both read and write access.
+setperm /dir 0 READ/WRITE
+setid 1
+expect 0 READ/WRITE
+getperm /dir
+expect test
+dir /dir
+write /dir/test2 create contents
+expect contents
+read /dir/test2
+setperm /dir/test2 1 NONE
+
+# Change so that user 1 owns it, noone else can do anything.
+setid 0
+setperm /dir 1 NONE
+expect 1 NONE
+getperm /dir
+expect test
+expect test2
+dir /dir
+write /dir/test3 create contents
+
+# User 2 can do nothing.  Can't even tell if file exists.
+setid 2
+expect setperm failed: Permission denied
+setperm /dir 2 NONE
+expect getperm failed: Permission denied
+getperm /dir
+expect dir failed: Permission denied
+dir /dir
+expect read failed: Permission denied
+read /dir/test
+expect read failed: Permission denied
+read /dir/test2
+expect read failed: Permission denied
+read /dir/test3
+expect read failed: Permission denied
+read /dir/test4
+expect write failed: Permission denied
+write /dir/test none contents
+expect write failed: Permission denied
+write /dir/test create contents
+expect write failed: Permission denied
+write /dir/test excl contents
+expect write failed: Permission denied
+write /dir/test4 none contents
+expect write failed: Permission denied
+write /dir/test4 create contents
+expect write failed: Permission denied
+write /dir/test4 excl contents
+
+# Tools can always access things.
+setid 0
+expect 1 NONE
+getperm /dir
+expect test
+expect test2
+expect test3
+dir /dir
+write /dir/test4 create contents
+
+# Inherited by child.
+mkdir /dir/subdir
+expect 1 NONE
+getperm /dir/subdir
+write /dir/subfile excl contents
+expect 1 NONE
+getperm /dir/subfile
+
+# But for domains, they own it.
+setperm /dir/subdir 2 READ/WRITE
+expect 2 READ/WRITE
+getperm /dir/subdir
+setid 3
+write /dir/subdir/subfile excl contents
+expect 3 READ/WRITE
+getperm /dir/subdir/subfile
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/07watch.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/07watch.test     Mon Aug  8 09:13:19 2005
@@ -0,0 +1,194 @@
+# Watch something, write to it, check watch has fired.
+write /test create contents
+
+1 watch /test token
+2 write /test create contents2
+expect 1:/test:token
+1 waitwatch
+1 ackwatch token
+1 close
+
+# Check that reads don't set it off.
+1 watch /test token
+expect 2:contents2
+2 read /test
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
+1 close
+
+# mkdir, setperm and rm should (also tests watching dirs)
+mkdir /dir
+1 watch /dir token
+2 mkdir /dir/newdir
+expect 1:/dir/newdir:token
+1 waitwatch
+1 ackwatch token
+2 setperm /dir/newdir 0 READ
+expect 1:/dir/newdir:token
+1 waitwatch
+1 ackwatch token
+2 rm /dir/newdir
+expect 1:/dir/newdir:token
+1 waitwatch
+1 ackwatch token
+1 close
+2 close
+
+# We don't get a watch from our own commands.
+watch /dir token
+mkdir /dir/newdir
+expect waitwatch failed: Connection timed out
+waitwatch
+close
+
+# ignore watches while doing commands, should work.
+watch /dir token
+1 write /dir/test create contents
+expect contents
+read /dir/test
+expect /dir/test:token
+waitwatch
+ackwatch token
+close
+
+# watch priority test: all simultaneous
+1 watch /dir token1
+3 watch /dir token3
+2 watch /dir token2
+write /dir/test create contents
+expect 3:/dir/test:token3
+3 waitwatch
+3 ackwatch token3
+expect 2:/dir/test:token2
+2 waitwatch
+2 ackwatch token2
+expect 1:/dir/test:token1
+1 waitwatch
+1 ackwatch token1
+1 close
+2 close
+3 close
+
+# If one dies (without acking), the other should still get ack.
+1 watch /dir token1
+2 watch /dir token2
+write /dir/test create contents
+expect 2:/dir/test:token2
+2 waitwatch
+2 close
+expect 1:/dir/test:token1
+1 waitwatch
+1 ackwatch token1
+1 close
+
+# If one dies (without reading at all), the other should still get ack.
+1 watch /dir token1
+2 watch /dir token2
+write /dir/test create contents
+2 close
+expect 1:/dir/test:token1
+1 waitwatch
+1 ackwatch token1
+1 close
+2 close
+
+# unwatch
+1 watch /dir token1
+1 unwatch /dir token1
+1 watch /dir token2
+2 write /dir/test2 create contents
+expect 1:/dir/test2:token2
+1 waitwatch
+1 unwatch /dir token2
+1 close
+2 close
+
+# unwatch while watch pending.  Other watcher still gets the event.
+1 watch /dir token1
+2 watch /dir token2
+write /dir/test create contents
+2 unwatch /dir token2
+expect 1:/dir/test:token1
+1 waitwatch
+1 ackwatch token1
+1 close
+2 close
+
+# unwatch while watch pending.  Should clear this so we get next event.
+1 watch /dir token1
+write /dir/test create contents
+1 unwatch /dir token1
+1 watch /dir/test token2
+write /dir/test none contents2
+expect 1:/dir/test:token2
+1 waitwatch
+1 ackwatch token2
+
+# check we only get notified once.
+1 watch /test token
+2 write /test create contents2
+expect 1:/test:token
+1 waitwatch
+1 ackwatch token
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
+1 close
+
+# watches are queued in order.
+1 watch / token
+2 write /test1 create contents
+2 write /test2 create contents
+2 write /test3 create contents
+expect 1:/test1:token
+1 waitwatch
+1 ackwatch token
+expect 1:/test2:token
+1 waitwatch
+1 ackwatch token
+expect 1:/test3:token
+1 waitwatch
+1 ackwatch token
+1 close
+
+# Creation of subpaths should be covered correctly.
+1 watch / token
+2 write /test/subnode create contents2
+2 write /test/subnode/subnode create contents2
+expect 1:/test/subnode:token
+1 waitwatch
+1 ackwatch token
+expect 1:/test/subnode/subnode:token
+1 waitwatch
+1 ackwatch token
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
+1 close
+
+# Watch event must have happened before we registered interest.
+1 watch / token
+2 write /test/subnode create contents2
+1 watch / token2 0
+expect 1:/test/subnode:token
+1 waitwatch
+1 ackwatch token
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
+1 close
+
+# Rm fires notification on child.
+1 watch /test/subnode token
+2 rm /test
+expect 1:/test/subnode:token
+1 waitwatch
+1 ackwatch token
+
+# Watch should not double-send after we ack, even if we did something in 
between.
+1 watch /test2 token
+2 write /test2/foo create contents2
+expect 1:/test2/foo:token
+1 waitwatch
+expect 1:contents2
+1 read /test2/foo
+1 ackwatch token
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
diff -r b60643391488 -r a9ee400a5da9 
tools/xenstore/testsuite/08transaction.slowtest
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/08transaction.slowtest   Mon Aug  8 09:13:19 2005
@@ -0,0 +1,21 @@
+# Test transaction timeouts.  Take a second each.
+
+mkdir /test
+write /test/entry1 create contents
+
+# Transactions can take as long as the want...
+start /test
+sleep 1100
+rm /test/entry1
+commit
+dir /test
+
+# ... as long as noone is waiting.
+1 start /test
+notimeout
+2 mkdir /test/dir
+1 mkdir /test/dir
+expect 1:dir
+1 dir /test
+expect 1: commit failed: Connection timed out
+1 commit
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/08transaction.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/08transaction.test       Mon Aug  8 09:13:19 2005
@@ -0,0 +1,96 @@
+# Test transactions.
+
+mkdir /test
+
+# Simple transaction: create a file inside transaction.
+1 start /test
+1 write /test/entry1 create contents
+2 dir /test
+expect 1:entry1
+1 dir /test
+1 commit
+expect 2:contents
+2 read /test/entry1
+
+rm /test/entry1
+
+# Create a file and abort transaction.
+1 start /test
+1 write /test/entry1 create contents
+2 dir /test
+expect 1:entry1
+1 dir /test
+1 abort
+2 dir /test
+
+write /test/entry1 create contents
+# Delete in transaction, commit
+1 start /test
+1 rm /test/entry1
+expect 2:entry1
+2 dir /test
+1 dir /test
+1 commit
+2 dir /test
+
+# Delete in transaction, abort.
+write /test/entry1 create contents
+1 start /test
+1 rm /test/entry1
+expect 2:entry1
+2 dir /test
+1 dir /test
+1 abort
+expect 2:entry1
+2 dir /test
+
+# Events inside transactions don't trigger watches until (successful) commit.
+mkdir /test/dir
+1 watch /test token
+2 start /test
+2 mkdir /test/dir/sub
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
+2 close
+1 close
+
+1 watch /test token
+2 start /test
+2 mkdir /test/dir/sub
+2 abort
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
+1 close
+
+1 watch /test token
+2 start /test
+2 mkdir /test/dir/sub
+2 commit
+expect 1:/test/dir/sub:token
+1 waitwatch
+1 ackwatch token
+1 close
+
+# Rm inside transaction works like rm outside: children get notified.
+1 watch /test/dir/sub token
+2 start /test
+2 rm /test/dir
+2 commit
+expect 1:/test/dir/sub:token
+1 waitwatch
+1 ackwatch token
+1 close
+
+# Multiple events from single transaction don't trigger assert
+1 watch /test token
+2 start /test
+2 write /test/1 create contents
+2 write /test/2 create contents
+2 commit
+expect 1:/test/1:token
+1 waitwatch
+1 ackwatch token
+expect 1:/test/2:token
+1 waitwatch
+1 ackwatch token
+1 close
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/09domain.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/09domain.test    Mon Aug  8 09:13:19 2005
@@ -0,0 +1,19 @@
+# Test domain communication.
+
+# Create a domain, write an entry.
+expect handle is 1
+introduce 1 100 7 /my/home
+1 write /entry1 create contents
+expect entry1
+expect tool
+dir /
+close
+
+# Release that domain.
+release 1
+close
+
+# Introduce and release by same connection.
+expect handle is 2
+introduce 1 100 7 /my/home
+release 1
diff -r b60643391488 -r a9ee400a5da9 
tools/xenstore/testsuite/10domain-homedir.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/10domain-homedir.test    Mon Aug  8 09:13:19 2005
@@ -0,0 +1,19 @@
+# Test domain "implicit" paths.
+
+# Create a domain, write an entry using implicit path, read using implicit
+mkdir /home
+expect handle is 1
+introduce 1 100 7 /home
+1 write entry1 create contents
+expect contents
+read /home/entry1
+expect entry1
+dir /home
+
+# Place a watch using a relative path: expect relative answer.
+1 mkdir foo
+1 watch foo token
+write /home/foo/bar create contents
+expect 1:foo/bar:token
+1 waitwatch
+1 ackwatch token
diff -r b60643391488 -r a9ee400a5da9 
tools/xenstore/testsuite/11domain-watch.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/11domain-watch.test      Mon Aug  8 09:13:19 2005
@@ -0,0 +1,52 @@
+# Test watching from a domain.
+
+# Watch something, write to it, check watch has fired.
+write /test create contents
+mkdir /dir
+
+expect handle is 1
+introduce 1 100 7 /my/home
+1 watch /test token
+write /test create contents2
+expect 1:/test:token
+1 waitwatch
+1 ackwatch token
+1 unwatch /test token
+release 1
+1 close
+
+# ignore watches while doing commands, should work.
+expect handle is 1
+introduce 1 100 7 /my/home
+1 watch /dir token
+write /dir/test create contents
+1 write /dir/test2 create contents2
+1 write /dir/test3 create contents3
+1 write /dir/test4 create contents4
+expect 1:/dir/test:token
+1 waitwatch
+1 ackwatch token
+release 1
+1 close
+
+# unwatch
+expect handle is 1
+introduce 1 100 7 /my/home
+1 watch /dir token1
+1 unwatch /dir token1
+1 watch /dir token2
+write /dir/test2 create contents
+expect 1:/dir/test2:token2
+1 waitwatch
+1 unwatch /dir token2
+release 1
+1 close
+
+# unwatch while watch pending.
+expect handle is 1
+introduce 1 100 7 /my/home
+1 watch /dir token1
+write /dir/test2 create contents
+1 unwatch /dir token1
+release 1
+1 close
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/12readonly.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/12readonly.test  Mon Aug  8 09:13:19 2005
@@ -0,0 +1,41 @@
+# Test that read only connection can't alter store.
+
+write /test create contents
+
+readonly
+expect test
+expect tool
+dir /
+
+expect contents
+read /test
+expect 0 READ
+getperm /test
+watch /test token
+unwatch /test token 
+start /
+commit
+start /
+abort
+
+# These don't work
+expect write failed: Read-only file system
+write /test2 create contents
+expect write failed: Read-only file system
+write /test create contents
+expect setperm failed: Read-only file system
+setperm /test 100 NONE
+expect setperm failed: Read-only file system
+setperm /test 100 NONE
+expect shutdown failed: Read-only file system
+shutdown
+expect introduce failed: Read-only file system
+introduce 1 100 7 /home
+
+# Check that watches work like normal.
+watch / token
+1 readwrite
+1 write /test create contents
+expect /test:token
+waitwatch
+ackwatch token
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/13watch-ack.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/13watch-ack.test Mon Aug  8 09:13:19 2005
@@ -0,0 +1,22 @@
+# This demonstrates a bug where an xs_acknowledge_watch returns
+# EINVAL, because the daemon doesn't track what watch event it sent
+# and relies on it being the "first" watch which has an event.
+# Watches firing after the first event is sent out will change this.
+
+# Create three things to watch.
+mkdir /test
+mkdir /test/1
+mkdir /test/2
+mkdir /test/3
+
+# Watch all three, fire event on 2, read watch, fire event on 1 and 3, ack 2.
+1 watch /test/1 token1
+1 watch /test/2 token2
+1 watch /test/3 token3
+2 write /test/2 create contents2
+expect 1:/test/2:token2
+1 waitwatch
+3 write /test/1 create contents1
+4 write /test/3 create contents3
+1 ackwatch token2
+1 close
diff -r b60643391488 -r a9ee400a5da9 
tools/xenstore/testsuite/14complexperms.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/14complexperms.test      Mon Aug  8 09:13:19 2005
@@ -0,0 +1,99 @@
+# We should not be able to tell the difference between a node which
+# doesn't exist, and a node we don't have permission on, if we don't
+# have permission on it directory.
+
+mkdir /dir
+setperm /dir 0 NONE
+
+# First when it doesn't exist
+setid 1
+expect *Permission denied
+dir /dir/file
+expect *Permission denied
+read /dir/file 
+expect *Permission denied
+write /dir/file none value 
+expect *Permission denied
+write /dir/file create value 
+expect *Permission denied
+write /dir/file excl value 
+expect write failed: Invalid argument
+write /dir/file crap value 
+expect *Permission denied
+mkdir /dir/file 
+expect *Permission denied
+rm /dir/file 
+expect *Permission denied
+rm /dir 
+expect *Permission denied
+getperm /dir/file 
+expect *Permission denied
+setperm /dir/file 0 NONE 
+watch /dir/file token 
+setid 0
+write /dir/file create contents
+rm /dir/file
+setid 1
+expect waitwatch failed: Connection timed out
+waitwatch
+unwatch /dir/file token 
+expect *No such file or directory
+unwatch /dir/file token 
+expect *Permission denied
+start /dir/file
+expect *No such file or directory
+abort
+expect *Permission denied
+start /dir/file
+expect *No such file or directory
+commit
+expect *Permission denied
+introduce 2 100 7 /dir/file
+
+# Now it exists
+setid 0
+write /dir/file create contents
+
+setid 1
+expect *Permission denied
+dir /dir/file
+expect *Permission denied
+read /dir/file 
+expect *Permission denied
+write /dir/file none value 
+expect *Permission denied
+write /dir/file create value 
+expect *Permission denied
+write /dir/file excl value 
+expect write failed: Invalid argument
+write /dir/file crap value 
+expect *Permission denied
+mkdir /dir/file 
+expect *Permission denied
+rm /dir/file 
+expect *Permission denied
+rm /dir 
+expect *Permission denied
+getperm /dir/file 
+expect *Permission denied
+setperm /dir/file 0 NONE 
+watch /dir/file token 
+setid 0
+write /dir/file create contents
+rm /dir/file
+setid 1
+expect waitwatch failed: Connection timed out
+waitwatch
+unwatch /dir/file token 
+expect *No such file or directory
+unwatch /dir/file token 
+expect *Permission denied
+start /dir/file
+expect *No such file or directory
+abort
+expect *Permission denied
+start /dir/file
+expect *No such file or directory
+commit
+expect *Permission denied
+introduce 2 100 7 /dir/file
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/15nowait.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/15nowait.test    Mon Aug  8 09:13:19 2005
@@ -0,0 +1,25 @@
+# If we don't wait for an ack, we can crash daemon as it never expects to be
+# sending out two replies on top of each other.
+noackwrite /1 create 1
+noackwrite /2 create 2
+noackwrite /3 create 3
+noackwrite /4 create 4
+noackwrite /5 create 5
+readack
+readack
+readack
+readack
+readack
+
+expect handle is 1
+introduce 1 100 7 /my/home
+1 noackwrite /1 create 1
+1 noackwrite /2 create 2
+1 noackwrite /3 create 3
+1 noackwrite /4 create 4
+1 noackwrite /5 create 5
+1 readack
+1 readack
+1 readack
+1 readack
+1 readack
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xs_crashme.c
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xs_crashme.c       Mon Aug  8 09:13:19 2005
@@ -0,0 +1,413 @@
+/* Code which randomly corrupts bits going to the daemon.
+    Copyright (C) 2005 Rusty Russell IBM Corporation
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/time.h>
+#include "xs.h"
+#include "talloc.h"
+#include <errno.h>
+#include "xenstored.h"
+
+#define XSTEST
+#define RAND_FREQ 128          /* One char in 32 is corrupted. */
+
+/* jhash.h: Jenkins hash support.
+ *
+ * Copyright (C) 1996 Bob Jenkins (bob_jenkins@xxxxxxxxxxxxxxxx)
+ *
+ * http://burtleburtle.net/bob/hash/
+ *
+ * These are the credits from Bob's sources:
+ *
+ * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
+ * hash(), hash2(), hash3, and mix() are externally useful functions.
+ * Routines to test the hash are included if SELF_TEST is defined.
+ * You can use this free for any purpose.  It has no warranty.
+ *
+ * Copyright (C) 2003 David S. Miller (davem@xxxxxxxxxx)
+ *
+ * I've modified Bob's hash to be useful in the Linux kernel, and
+ * any bugs present are surely my fault.  -DaveM
+ */
+
+/* NOTE: Arguments are modified. */
+#define __jhash_mix(a, b, c) \
+{ \
+  a -= b; a -= c; a ^= (c>>13); \
+  b -= c; b -= a; b ^= (a<<8); \
+  c -= a; c -= b; c ^= (b>>13); \
+  a -= b; a -= c; a ^= (c>>12);  \
+  b -= c; b -= a; b ^= (a<<16); \
+  c -= a; c -= b; c ^= (b>>5); \
+  a -= b; a -= c; a ^= (c>>3);  \
+  b -= c; b -= a; b ^= (a<<10); \
+  c -= a; c -= b; c ^= (b>>15); \
+}
+
+/* The golden ration: an arbitrary value */
+#define JHASH_GOLDEN_RATIO     0x9e3779b9
+
+/* The most generic version, hashes an arbitrary sequence
+ * of bytes.  No alignment or length assumptions are made about
+ * the input key.
+ */
+static inline u32 jhash(const void *key, u32 length, u32 initval)
+{
+       u32 a, b, c, len;
+       const u8 *k = key;
+
+       len = length;
+       a = b = JHASH_GOLDEN_RATIO;
+       c = initval;
+
+       while (len >= 12) {
+               a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
+               b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
+               c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
+
+               __jhash_mix(a,b,c);
+
+               k += 12;
+               len -= 12;
+       }
+
+       c += length;
+       switch (len) {
+       case 11: c += ((u32)k[10]<<24);
+       case 10: c += ((u32)k[9]<<16);
+       case 9 : c += ((u32)k[8]<<8);
+       case 8 : b += ((u32)k[7]<<24);
+       case 7 : b += ((u32)k[6]<<16);
+       case 6 : b += ((u32)k[5]<<8);
+       case 5 : b += k[4];
+       case 4 : a += ((u32)k[3]<<24);
+       case 3 : a += ((u32)k[2]<<16);
+       case 2 : a += ((u32)k[1]<<8);
+       case 1 : a += k[0];
+       };
+
+       __jhash_mix(a,b,c);
+
+       return c;
+}
+
+/* A special optimized version that handles 1 or more of u32s.
+ * The length parameter here is the number of u32s in the key.
+ */
+static inline u32 jhash2(u32 *k, u32 length, u32 initval)
+{
+       u32 a, b, c, len;
+
+       a = b = JHASH_GOLDEN_RATIO;
+       c = initval;
+       len = length;
+
+       while (len >= 3) {
+               a += k[0];
+               b += k[1];
+               c += k[2];
+               __jhash_mix(a, b, c);
+               k += 3; len -= 3;
+       }
+
+       c += length * 4;
+
+       switch (len) {
+       case 2 : b += k[1];
+       case 1 : a += k[0];
+       };
+
+       __jhash_mix(a,b,c);
+
+       return c;
+}
+
+
+/* A special ultra-optimized versions that knows they are hashing exactly
+ * 3, 2 or 1 word(s).
+ *
+ * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
+ *       done at the end is not done here.
+ */
+static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
+{
+       a += JHASH_GOLDEN_RATIO;
+       b += JHASH_GOLDEN_RATIO;
+       c += initval;
+
+       __jhash_mix(a, b, c);
+
+       return c;
+}
+
+static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
+{
+       return jhash_3words(a, b, 0, initval);
+}
+
+static inline u32 jhash_1word(u32 a, u32 initval)
+{
+       return jhash_3words(a, 0, 0, initval);
+}
+
+static unsigned int get_randomness(int *state)
+{
+       return jhash_1word((*state)++, *state * 1103515243);
+}
+
+static int state;
+
+/* Lengthening headers is pointless: other end will just wait for more
+ * data and timeout.  We merely shorten the length. */
+static void corrupt_header(char *output, const struct xsd_sockmsg *msg,
+                          unsigned int *next_bit)
+{
+       struct xsd_sockmsg newmsg = *msg;
+
+       while (*next_bit < sizeof(*msg)) {
+               if (newmsg.len)
+                       newmsg.len = get_randomness(&state) % newmsg.len;
+               *next_bit += get_randomness(&state) % RAND_FREQ;
+       }
+       memcpy(output, &newmsg, sizeof(newmsg));
+}
+
+#define read_all_choice read_all
+static bool write_all_choice(int fd, const void *data, unsigned int len)
+{
+       char corrupt_data[len];
+       bool ret;
+       static unsigned int next_bit;
+
+       if (len == sizeof(struct xsd_sockmsg)
+           && ((unsigned long)data % __alignof__(struct xsd_sockmsg)) == 0)
+               corrupt_header(corrupt_data, data, &next_bit);
+       else {
+               memcpy(corrupt_data, data, len);
+               while (next_bit < len * CHAR_BIT) {
+                       corrupt_data[next_bit/CHAR_BIT]
+                               ^= (1 << (next_bit%CHAR_BIT));
+                       next_bit += get_randomness(&state) % RAND_FREQ;
+               }
+       }
+
+       ret = xs_write_all(fd, corrupt_data, len);
+       next_bit -= len * CHAR_BIT;
+       return ret;
+}
+
+#include "xs.c"
+
+static char *random_path(void)
+{
+       unsigned int i;
+       char *ret = NULL;
+
+       if (get_randomness(&state) % 20 == 0)
+               return talloc_strdup(NULL, "/");
+
+       for (i = 0; i < 1 || (get_randomness(&state) % 2); i++) {
+               ret = talloc_asprintf_append(ret, "/%i", 
+                                            get_randomness(&state) % 15);
+       }
+       return ret;
+}
+
+static int random_flags(int *state)
+{
+       switch (get_randomness(state) % 4) {
+       case 0:
+               return 0;
+       case 1:
+               return O_CREAT;
+       case 2:
+               return O_CREAT|O_EXCL;
+       default:
+               return get_randomness(state);
+       }
+}
+
+/* Do the next operation, return the results. */
+static void do_next_op(struct xs_handle *h, bool verbose)
+{
+       char *name;
+       unsigned int num;
+
+       if (verbose)
+               printf("State %i: ", state);
+
+       name = random_path();
+       switch (get_randomness(&state) % 9) {
+       case 0:
+               if (verbose)
+                       printf("DIR %s\n", name);
+               free(xs_directory(h, name, &num));
+               break;
+       case 1:
+               if (verbose)
+                       printf("READ %s\n", name);
+               free(xs_read(h, name, &num));
+               break;
+       case 2: {
+               int flags = random_flags(&state);
+               char *contents = talloc_asprintf(NULL, "%i",
+                                                get_randomness(&state));
+               unsigned int len = get_randomness(&state)%(strlen(contents)+1);
+               if (verbose)
+                       printf("WRITE %s %s %.*s\n", name,
+                              flags == O_CREAT ? "O_CREAT" 
+                              : flags == (O_CREAT|O_EXCL) ? "O_CREAT|O_EXCL"
+                              : flags == 0 ? "0" : "CRAPFLAGS",
+                              len, contents);
+               xs_write(h, name, contents, len, flags);
+               break;
+       }
+       case 3:
+               if (verbose)
+                       printf("MKDIR %s\n", name);
+               xs_mkdir(h, name);
+               break;
+       case 4:
+               if (verbose)
+                       printf("RM %s\n", name);
+               xs_rm(h, name);
+               break;
+       case 5:
+               if (verbose)
+                       printf("GETPERMS %s\n", name);
+               free(xs_get_permissions(h, name, &num));
+               break;
+       case 6: {
+               unsigned int i, num = get_randomness(&state)%8;
+               struct xs_permissions perms[num];
+
+               if (verbose)
+                       printf("SETPERMS %s: ", name);
+               for (i = 0; i < num; i++) {
+                       perms[i].id = get_randomness(&state)%8;
+                       perms[i].perms = get_randomness(&state)%4;
+                       if (verbose)
+                               printf("%i%c ", perms[i].id,
+                                      perms[i].perms == XS_PERM_WRITE ? 'W'
+                                      : perms[i].perms == XS_PERM_READ ? 'R'
+                                      : perms[i].perms == 
+                                      (XS_PERM_READ|XS_PERM_WRITE) ? 'B'
+                                      : 'N');
+               }
+               if (verbose)
+                       printf("\n");
+               xs_set_permissions(h, name, perms, num);
+               break;
+       }
+       case 7: {
+               if (verbose)
+                       printf("START %s\n", name);
+               xs_transaction_start(h, name);
+               break;
+       }
+       case 8: {
+               bool abort = (get_randomness(&state) % 2);
+
+               if (verbose)
+                       printf("STOP %s\n", abort ? "ABORT" : "COMMIT");
+               xs_transaction_end(h, abort);
+               break;
+       }
+       default:
+               barf("Impossible randomness");
+       }
+}
+
+static struct xs_handle *h;
+static void alarmed(int sig __attribute__((unused)))
+{
+       /* We force close on timeout. */
+       close(h->fd);
+}
+
+static int start_daemon(void)
+{
+       int fds[2];
+       int daemon_pid;
+
+       /* Start daemon. */
+       pipe(fds);
+       if ((daemon_pid = fork())) {
+               /* Child writes PID when its ready: we wait for that. */
+               char buffer[20];
+               close(fds[1]);
+               if (read(fds[0], buffer, sizeof(buffer)) < 0)
+                       barf("Failed to summon daemon");
+               close(fds[0]);
+               return daemon_pid;
+       } else {
+               dup2(fds[1], STDOUT_FILENO);
+               close(fds[0]);
+#if 1
+               execlp("valgrind", "valgrind", 
"--log-file=/tmp/xs_crashme.vglog", "-q", "./xenstored_test", "--output-pid",
+                      "--no-fork", "--trace-file=/tmp/trace", NULL);
+#else
+               execlp("./xenstored_test", "xenstored_test", "--output-pid",
+                      "--no-fork", NULL);
+#endif
+               exit(1);
+       }
+}
+
+
+int main(int argc, char **argv)
+{
+       unsigned int i;
+       int pid;
+
+       if (argc != 3 && argc != 4)
+               barf("Usage: xs_crashme <iterations> <seed> [pid]");
+
+       if (argc == 3)
+               pid = start_daemon();
+       else
+               pid = atoi(argv[3]);
+
+       state = atoi(argv[2]);
+       h = xs_daemon_open();
+       if (!h)
+               barf_perror("Opening connection to daemon");
+       signal(SIGALRM, alarmed);
+       for (i = 0; i < (unsigned)atoi(argv[1]); i++) {
+               alarm(1);
+               do_next_op(h, false);
+               if (i % (atoi(argv[1]) / 72 ?: 1) == 0) {
+                       printf(".");
+                       fflush(stdout);
+               }
+               if (kill(pid, 0) != 0)
+                       barf_perror("Pinging daemon on iteration %i", i);
+               if (h->fd < 0) {
+                       xs_daemon_close(h);
+                       h = xs_daemon_open();
+                       if (!h)
+                               barf_perror("Connecting on iteration %i", i);
+               }
+       }
+       kill(pid, SIGTERM);
+       return 0;
+}
+

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] 1) More testing: include tests which I forgot in previous patch, remove, Xen patchbot -unstable <=