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] xenstored updates.

# HG changeset patch
# User cl349@xxxxxxxxxxxxxxxxxxxx
# Node ID 57a5441b323b747b90db089c303e8e79ae7a36b0
# Parent  43f224c33281d981b08f8bd350fdd89d86ae7f38

xenstored updates.
- add trace file support.
- update permissions code.
- trigger watches on children of nodes being removed.
- update test cases.
Signed-off-by: Rusty Russel <rusty@xxxxxxxxxxxxxxx>
Signed-off-by: Christian Limpach <Christian.Limpach@xxxxxxxxxxxx>

diff -r 43f224c33281 -r 57a5441b323b tools/xenstore/xenstored_core.c
--- a/tools/xenstore/xenstored_core.c   Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/xenstored_core.c   Tue Jul 12 10:16:33 2005
@@ -52,6 +52,7 @@
 
 static bool verbose;
 static LIST_HEAD(connections);
+static int tracefd = -1;
 
 #ifdef TESTING
 static bool failtest = false;
@@ -149,6 +150,86 @@
        }
 }
 
+static void trace_io(const struct connection *conn,
+                    const char *prefix,
+                    const struct buffered_data *data)
+{
+       char string[64];
+       unsigned int i;
+
+       if (tracefd < 0)
+               return;
+
+       write(tracefd, prefix, strlen(prefix));
+       sprintf(string, " %p ", conn);
+       write(tracefd, string, strlen(string));
+       write(tracefd, sockmsg_string(data->hdr.msg.type),
+             strlen(sockmsg_string(data->hdr.msg.type)));
+       write(tracefd, " (", 2);
+       for (i = 0; i < data->hdr.msg.len; i++) {
+               if (data->buffer[i] == '\0')
+                       write(tracefd, " ", 1);
+               else
+                       write(tracefd, data->buffer + i, 1);
+       }
+       write(tracefd, ")\n", 2);
+}
+
+void trace_create(const void *data, const char *type)
+{
+       char string[64];
+       if (tracefd < 0)
+               return;
+
+       write(tracefd, "CREATE ", strlen("CREATE "));
+       write(tracefd, type, strlen(type));
+       sprintf(string, " %p\n", data);
+       write(tracefd, string, strlen(string));
+}
+
+void trace_destroy(const void *data, const char *type)
+{
+       char string[64];
+       if (tracefd < 0)
+               return;
+
+       write(tracefd, "DESTROY ", strlen("DESTROY "));
+       write(tracefd, type, strlen(type));
+       sprintf(string, " %p\n", data);
+       write(tracefd, string, strlen(string));
+}
+
+void trace_watch_timeout(const struct connection *conn, const char *node, 
const char *token)
+{
+       char string[64];
+       if (tracefd < 0)
+               return;
+       write(tracefd, "WATCH_TIMEOUT ", strlen("WATCH_TIMEOUT "));
+       sprintf(string, " %p ", conn);
+       write(tracefd, string, strlen(string));
+       write(tracefd, " (", 2);
+       write(tracefd, node, strlen(node));
+       write(tracefd, " ", 1);
+       write(tracefd, token, strlen(token));
+       write(tracefd, ")\n", 2);
+}
+
+static void trace_blocked(const struct connection *conn,
+                         const struct buffered_data *data)
+{
+       char string[64];
+
+       if (tracefd < 0)
+               return;
+
+       write(tracefd, "BLOCKED", strlen("BLOCKED"));
+       sprintf(string, " %p (", conn);
+       write(tracefd, string, strlen(string));
+       write(tracefd, sockmsg_string(data->hdr.msg.type),
+             strlen(sockmsg_string(data->hdr.msg.type)));
+       write(tracefd, ")\n", 2);
+}
+
 static bool write_message(struct connection *conn)
 {
        int ret;
@@ -186,6 +267,7 @@
        if (out->used != out->hdr.msg.len)
                return true;
 
+       trace_io(conn, "OUT", out);
        conn->out = NULL;
        talloc_free(out);
 
@@ -213,6 +295,7 @@
                close(conn->fd);
        }
        list_del(&conn->list);
+       trace_destroy(conn, "connection");
        return 0;
 }
 
@@ -756,9 +839,9 @@
 static bool new_directory(struct connection *conn,
                          const char *node, void *data, unsigned int datalen)
 {
-       struct xs_permissions perms;
+       struct xs_permissions *perms;
        char *permstr;
-       unsigned int len;
+       unsigned int num, len;
        int *fd;
        char *dir = node_dir(conn->transaction, node);
 
@@ -768,11 +851,12 @@
        /* Set destructor so we clean up if neccesary. */
        talloc_set_destructor(dir, destroy_path);
 
-       /* Default permisisons: we own it, noone else has permission. */
-       perms.id = conn->id;
-       perms.perms = XS_PERM_NONE;
-
-       permstr = perms_to_strings(dir, &perms, 1, &len);
+       perms = get_perms(conn->transaction, get_parent(node), &num);
+       /* Domains own what they create. */
+       if (conn->id)
+               perms->id = conn->id;
+
+       permstr = perms_to_strings(dir, perms, num, &len);
        fd = talloc_open(node_permfile(conn->transaction, node),
                         O_WRONLY|O_CREAT|O_EXCL, 0640);
        if (!fd || !xs_write_all(*fd, permstr, len))
@@ -805,7 +889,8 @@
                return send_error(conn, EINVAL);
 
        node = canonicalize(conn, vec[0]);
-       if (!within_transaction(conn->transaction, node))
+       if (/*suppress error on write outside transaction*/ 0 &&
+            !within_transaction(conn->transaction, node))
                return send_error(conn, EROFS);
 
        if (transaction_block(conn, node))
@@ -850,9 +935,9 @@
                commit_tempfile(tmppath);
        }
 
-       add_change_node(conn->transaction, node);
+       add_change_node(conn->transaction, node, false);
        send_ack(conn, XS_WRITE);
-       fire_watches(conn->transaction, node);
+       fire_watches(conn->transaction, node, false);
        return false;
 }
 
@@ -871,9 +956,9 @@
        if (!new_directory(conn, node, NULL, 0))
                return send_error(conn, errno);
 
-       add_change_node(conn->transaction, node);
+       add_change_node(conn->transaction, node, false);
        send_ack(conn, XS_MKDIR);
-       fire_watches(conn->transaction, node);
+       fire_watches(conn->transaction, node, false);
        return false;
 }
 
@@ -902,10 +987,9 @@
        if (rename(path, tmppath) != 0)
                return send_error(conn, errno);
 
-       add_change_node(conn->transaction, node);
+       add_change_node(conn->transaction, node, true);
        send_ack(conn, XS_RM);
-       /* FIXME: traverse and fire watches for ALL of them! */
-       fire_watches(conn->transaction, node);
+       fire_watches(conn->transaction, node, true);
        return false;
 }
 
@@ -961,9 +1045,9 @@
 
        if (!set_perms(conn->transaction, node, perms, num))
                return send_error(conn, errno);
-       add_change_node(conn->transaction, node);
+       add_change_node(conn->transaction, node, false);
        send_ack(conn, XS_SET_PERMS);
-       fire_watches(conn->transaction, node);
+       fire_watches(conn->transaction, node, false);
        return false;
 }
 
@@ -1006,8 +1090,12 @@
                /* 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));
+                       return false;
+               }
 #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));
@@ -1018,9 +1106,8 @@
                        send_ack(conn, XS_DEBUG);
                        failtest = true;
                }
+#endif /* TESTING */
                return false;
-       }
-#endif /* TESTING */
 
        case XS_WATCH:
                return do_watch(conn, in);
@@ -1092,6 +1179,7 @@
                talloc_free(conn->in);
                conn->in = in;
                in = NULL;
+               trace_blocked(conn, conn->in);
        }
 
 end:
@@ -1145,6 +1233,7 @@
        if (in->used != in->hdr.msg.len)
                return;
 
+       trace_io(conn, "IN ", in);
        consider_message(conn);
        return;
 
@@ -1212,6 +1301,7 @@
 
        list_add_tail(&new->list, &connections);
        talloc_set_destructor(new, destroy_conn);
+       trace_create(new, "connection");
        return new;
 }
 
@@ -1299,6 +1389,7 @@
 static struct option options[] = { { "no-fork", 0, NULL, 'N' },
                                   { "verbose", 0, NULL, 'V' },
                                   { "output-pid", 0, NULL, 'P' },
+                                  { "trace-file", 1, NULL, 'T' },
                                   { NULL, 0, NULL, 0 } };
 
 int main(int argc, char *argv[])
@@ -1309,7 +1400,7 @@
        bool dofork = true;
        bool outputpid = false;
 
-       while ((opt = getopt_long(argc, argv, "DV", options, NULL)) != -1) {
+       while ((opt = getopt_long(argc, argv, "DVT:", options, NULL)) != -1) {
                switch (opt) {
                case 'N':
                        dofork = false;
@@ -1319,6 +1410,13 @@
                        break;
                case 'P':
                        outputpid = true;
+                       break;
+               case 'T':
+                       tracefd = open(optarg, O_WRONLY|O_CREAT|O_APPEND, 0600);
+                       if (tracefd < 0)
+                               barf_perror("Could not open tracefile %s",
+                                           optarg);
+                        write(tracefd, "\n***\n", strlen("\n***\n"));
                        break;
                }
        }
diff -r 43f224c33281 -r 57a5441b323b tools/xenstore/xenstored_core.h
--- a/tools/xenstore/xenstored_core.h   Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/xenstored_core.h   Tue Jul 12 10:16:33 2005
@@ -143,4 +143,9 @@
 /* Read entire contents of a talloced fd. */
 void *read_all(int *fd, unsigned int *size);
 
+/* Tracing infrastructure. */
+void trace_create(const void *data, const char *type);
+void trace_destroy(const void *data, const char *type);
+void trace_watch_timeout(const struct connection *conn, const char *node, 
const char *token);
+
 #endif /* _XENSTORED_CORE_H */
diff -r 43f224c33281 -r 57a5441b323b 
tools/xenstore/testsuite/10domain-homedir.sh
--- a/tools/xenstore/testsuite/10domain-homedir.sh      Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/testsuite/10domain-homedir.sh      Tue Jul 12 10:16:33 2005
@@ -10,3 +10,11 @@
 contents
 entry1" ]
 
+# Place a watch using a relative path: expect relative answer.
+[ "`echo 'introduce 1 100 7 /home
+1 mkdir foo
+1 watch foo token 0
+write /home/foo/bar create contents
+1 waitwatch
+1 ackwatch token' | ./xs_test 2>&1`" = "handle is 1
+1:foo/bar:token" ]
diff -r 43f224c33281 -r 57a5441b323b tools/xenstore/xenstored_watch.h
--- a/tools/xenstore/xenstored_watch.h  Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/xenstored_watch.h  Tue Jul 12 10:16:33 2005
@@ -32,8 +32,8 @@
 /* Look through our watches: if any of them have an event, queue it. */
 void queue_next_event(struct connection *conn);
 
-/* Fire all watches. */
-void fire_watches(struct transaction *trans, const char *node);
+/* Fire all watches: recurse means all the children are effected (ie. rm) */
+void fire_watches(struct transaction *trans, 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 43f224c33281 -r 57a5441b323b tools/xenstore/xenstored_transaction.h
--- a/tools/xenstore/xenstored_transaction.h    Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/xenstored_transaction.h    Tue Jul 12 10:16:33 2005
@@ -40,7 +40,7 @@
 char *node_dir_inside_transaction(struct transaction *t, const char *node);
 
 /* This node was changed: can fail and longjmp. */
-void add_change_node(struct transaction *trans, const char *node);
+void add_change_node(struct transaction *trans, const char *node, bool 
recurse);
 
 /* Get shortest timeout: leave tv unset if none. */
 void shortest_transaction_timeout(struct timeval *tv);
diff -r 43f224c33281 -r 57a5441b323b tools/xenstore/xenstored_transaction.c
--- a/tools/xenstore/xenstored_transaction.c    Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/xenstored_transaction.c    Tue Jul 12 10:16:33 2005
@@ -41,6 +41,9 @@
 
        /* The name of the node. */
        char *node;
+
+       /* And the children? (ie. rm) */
+       bool recurse;
 };
 
 struct transaction
@@ -119,7 +122,7 @@
 
 /* Callers get a change node (which can fail) and only commit after they've
  * finished.  This way they don't have to unwind eg. a write. */
-void add_change_node(struct transaction *trans, const char *node)
+void add_change_node(struct transaction *trans, const char *node, bool recurse)
 {
        struct changed_node *i;
 
@@ -132,7 +135,7 @@
 
        i = talloc(trans, struct changed_node);
        i->node = talloc_strdup(i, node);
-       INIT_LIST_HEAD(&i->list);
+       i->recurse = recurse;
        list_add_tail(&i->list, &trans->changes);
 }
 
@@ -176,6 +179,7 @@
        struct transaction *trans = _transaction;
 
        list_del(&trans->list);
+       trace_destroy(trans, "transaction");
        return destroy_path(trans->divert);
 }
 
@@ -263,13 +267,14 @@
        timerclear(&transaction->timeout);
        transaction->destined_to_fail = false;
        list_add_tail(&transaction->list, &transactions);
-       conn->transaction = transaction;
        talloc_set_destructor(transaction, destroy_transaction);
+       trace_create(transaction, "transaction");
 
        if (!copy_dir(dir, transaction->divert))
                return send_error(conn, errno);
 
        talloc_steal(conn, transaction);
+       conn->transaction = transaction;
        return send_ack(transaction->conn, XS_TRANSACTION_START);
 }
 
@@ -292,7 +297,7 @@
 
        /* Fire off the watches for everything that changed. */
        list_for_each_entry(i, &trans->changes, list)
-               fire_watches(NULL, i->node);
+               fire_watches(NULL, i->node, i->recurse);
        return true;
 }
 
diff -r 43f224c33281 -r 57a5441b323b tools/xenstore/xs.h
--- a/tools/xenstore/xs.h       Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/xs.h       Tue Jul 12 10:16:33 2005
@@ -47,7 +47,7 @@
 
 /* Get the value of a single file, nul terminated.
  * Returns a malloced value: call free() on it after use.
- * len indicates length in bytes, not including the nul.
+ * len indicates length in bytes, not including terminator.
  */
 void *xs_read(struct xs_handle *h, const char *path, unsigned int *len);
 
@@ -103,7 +103,7 @@
  */
 bool xs_acknowledge_watch(struct xs_handle *h, const char *token);
 
-/* Remove a watch on a node.
+/* Remove a watch on a node: implicitly acks any outstanding watch.
  * Returns false on failure (no watch on that node).
  */
 bool xs_unwatch(struct xs_handle *h, const char *path, const char *token);
diff -r 43f224c33281 -r 57a5441b323b tools/xenstore/testsuite/07watch.sh
--- a/tools/xenstore/testsuite/07watch.sh       Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/testsuite/07watch.sh       Tue Jul 12 10:16:33 2005
@@ -77,13 +77,22 @@
 1 waitwatch
 1 unwatch /dir token2' | ./xs_test 2>&1`" = "1:/dir/test2:token2" ]
 
-# unwatch while watch pending.
+# unwatch while watch pending.  Next watcher gets the event.
 [ "`echo -e '1 watch /dir token1 0
 2 watch /dir token2 1
 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
+write /dir/test create contents
+1 unwatch /dir token1
+1 watch /dir/test token2 0
+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
@@ -118,3 +127,28 @@
 1 waitwatch' | ./xs_test 2>&1`" = "1:/test/subnode:token
 1:/test/subnode/subnode:token
 1:waitwatch timeout" ]
+
+# Watch event must have happened before we registered interest.
+[ "`echo -e '1 watch / token 100
+2 write /test/subnode create contents2
+2 watch / token2 0
+1 waitwatch
+1 ackwatch token
+2 waitwatch' | ./xs_test 2>&1`" = "1:/test/subnode:token
+2:waitwatch timeout" ]
+
+# Rm fires notification on child.
+[ "`echo -e '1 watch /test/subnode token 100
+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
+2 write /test2/foo create contents2
+1 waitwatch
+1 read /test2/foo
+1 ackwatch token
+1 waitwatch' | ./xs_test 2>&1`" = "1:/test2/foo:token
+1:contents2
+1:waitwatch timeout" ]
diff -r 43f224c33281 -r 57a5441b323b tools/xenstore/xs_random.c
--- a/tools/xenstore/xs_random.c        Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/xs_random.c        Tue Jul 12 10:16:33 2005
@@ -201,7 +201,6 @@
        unsigned long size;
        struct stat st;
 
-       /* No permfile: we didn't bother, return defaults. */
        if (lstat(filename, &st) != 0)
                return NULL;
 
@@ -211,18 +210,8 @@
                permfile = talloc_asprintf(path, "%s.perms", filename);
 
        perms = grab_file(permfile, &size);
-       if (!perms) {
-               ret = new(struct xs_permissions);
-               ret[0].id = 0;
-               /* Default for root is readable. */
-               if (streq(path, "/"))
-                       ret[0].perms = XS_PERM_READ;
-               else
-                       ret[0].perms = XS_PERM_NONE;
-               *num = 1;
-               release_file(perms, size);
-               return ret;
-       }
+       if (!perms)
+               barf("Grabbing permissions for %s", permfile);
        *num = xs_count_strings(perms, size);
 
        ret = new_array(struct xs_permissions, *num);
@@ -231,6 +220,39 @@
        release_file(perms, size);
        return ret;
 }
+
+static void do_command(const char *cmd)
+{
+       int ret;
+
+       ret = system(cmd);
+       if (ret == -1 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0)
+               barf_perror("Failed '%s': %i", cmd, ret);
+}
+
+static void init_perms(const char *filename)
+{
+       struct stat st;
+       char *permfile, *command;
+
+       if (lstat(filename, &st) != 0)
+               barf_perror("Failed to stat %s", filename);
+
+       if (S_ISDIR(st.st_mode)) 
+               permfile = talloc_asprintf(filename, "%s/.perms", filename);
+       else
+               permfile = talloc_asprintf(filename, "%s.perms", filename);
+
+       /* Leave permfile if it already exists. */
+       if (lstat(permfile, &st) == 0)
+               return;
+
+       /* Copy permissions from parent */
+       command = talloc_asprintf(filename, "cp %.*s/.perms %s",
+                                 strrchr(filename, '/') - filename,
+                                 filename, permfile);
+       do_command(command);
+}      
 
 static bool file_set_perms(struct file_ops_info *info,
                           const char *path,
@@ -318,6 +340,7 @@
        if (write(fd, data, len) != (int)len)
                barf_perror("Bad write to %s", filename);
 
+       init_perms(filename);
        close(fd);
        return true;
 }
@@ -339,16 +362,8 @@
                errno = saved_errno;
                return false;
        }
+       init_perms(dirname);
        return true;
-}
-
-static void do_command(const char *cmd)
-{
-       int ret;
-
-       ret = system(cmd);
-       if (ret == -1 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0)
-               barf_perror("Failed '%s': %i", cmd, ret);
 }
 
 static bool file_rm(struct file_ops_info *info, const char *path)
@@ -969,8 +984,11 @@
 
 static void setup_file_ops(const char *dir)
 {
+       char *cmd = talloc_asprintf(NULL, "echo -n r0 > %s/.perms", dir);
        if (mkdir(dir, 0700) != 0)
                barf_perror("Creating directory %s", dir);
+       do_command(cmd);
+       talloc_free(cmd);
 }
 
 static void setup_xs_ops(void)
diff -r 43f224c33281 -r 57a5441b323b tools/xenstore/testsuite/08transaction.sh
--- a/tools/xenstore/testsuite/08transaction.sh Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/testsuite/08transaction.sh Tue Jul 12 10:16:33 2005
@@ -52,3 +52,28 @@
 1 dir /
 1 commit' | ./xs_test 2>&1`" = "1:dir
 FATAL: 1: commit: Connection timed out" ]
+
+# Events inside transactions don't trigger watches until (successful) commit.
+[ "`echo -e '1 watch / token 100
+2 start /
+2 mkdir /dir/sub
+1 waitwatch' | ./xs_test 2>&1`" = "1:waitwatch timeout" ]
+[ "`echo -e '1 watch / token 100
+2 start /
+2 mkdir /dir/sub
+2 abort
+1 waitwatch' | ./xs_test 2>&1`" = "1:waitwatch timeout" ]
+[ "`echo -e '1 watch / token 100
+2 start /
+2 mkdir /dir/sub
+2 commit
+1 waitwatch
+1 ackwatch token' | ./xs_test 2>&1`" = "1:/dir/sub:token" ]
+
+# Rm inside transaction works like rm outside: children get notified.
+[ "`echo -e '1 watch /dir/sub token 100
+2 start /
+2 rm /dir
+2 commit
+1 waitwatch
+1 ackwatch token' | ./xs_test 2>&1`" = "1:/dir/sub:token" ]
diff -r 43f224c33281 -r 57a5441b323b tools/xenstore/xenstored_domain.c
--- a/tools/xenstore/xenstored_domain.c Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/xenstored_domain.c Tue Jul 12 10:16:33 2005
@@ -273,7 +273,7 @@
        domain = talloc(in, struct domain);
        domain->domid = atoi(vec[0]);
        domain->port = atoi(vec[2]);
-       if (!domain->port || !domain->domid || !is_valid_nodename(vec[3]))
+       if ((domain->port <= 0) || !is_valid_nodename(vec[3]))
                return send_error(conn, EINVAL);
        domain->path = talloc_strdup(domain, vec[3]);
        domain->page = xc_map_foreign_range(*xc_handle, domain->domid,
@@ -349,7 +349,7 @@
                return send_error(conn, EINVAL);
 
        domid = atoi(domid_str);
-       if (domid == 0)
+       if (domid == DOMID_SELF)
                domain = conn->domain;
        else
                domain = find_domain_by_domid(domid);
diff -r 43f224c33281 -r 57a5441b323b tools/xenstore/Makefile
--- a/tools/xenstore/Makefile   Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/Makefile   Tue Jul 12 10:16:33 2005
@@ -87,7 +87,7 @@
 
 stresstest: xs_stress xs_watch_stress xenstored_test
        rm -rf $(TESTDIR)/store
-       export $(TESTENV); PID=`./xenstored_test --output-pid`; ./xs_stress 
5000; ret=$$?; kill $$PID; exit $$ret
+       export $(TESTENV); PID=`./xenstored_test --output-pid 
--trace-file=/tmp/trace`; ./xs_stress 5000; ret=$$?; kill $$PID; exit $$ret
        rm -rf $(TESTDIR)/store
        export $(TESTENV); PID=`./xenstored_test --output-pid`; 
./xs_watch_stress; ret=$$?; kill $$PID; exit $$ret
 
diff -r 43f224c33281 -r 57a5441b323b 
tools/xenstore/testsuite/06dirpermissions.sh
--- a/tools/xenstore/testsuite/06dirpermissions.sh      Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/testsuite/06dirpermissions.sh      Tue Jul 12 10:16:33 2005
@@ -3,17 +3,17 @@
 # Root directory: owned by tool, everyone has read access.
 [ "`echo -e 'getperm /' | ./xs_test 2>&1`" = "0 READ" ]
 
-# Create directory: we own it, noone has access.
+# Create directory: inherits from root.
 [ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ]
-[ "`echo -e 'getperm /dir' | ./xs_test 2>&1`" = "0 NONE" ]
+[ "`echo -e 'getperm /dir' | ./xs_test 2>&1`" = "0 READ" ]
+[ "`echo -e 'setid 1\ngetperm /dir' | ./xs_test 2>&1`" = "0 READ" ]
+[ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1`" = "" ]
+[ "`echo -e 'setid 1\nwrite /dir/test create contents2' | ./xs_test 2>&1`" = 
"FATAL: write: Permission denied" ]
+
+# Remove everyone's read access to directoy.
+[ "`echo -e 'setperm /dir 0 NONE' | ./xs_test 2>&1`" = "" ]
 [ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1`" = "FATAL: dir: Permission 
denied" ]
 [ "`echo -e 'setid 1\nread /dir/test create contents2' | ./xs_test 2>&1`" = 
"FATAL: read: Permission denied" ]
-[ "`echo -e 'setid 1\nwrite /dir/test create contents2' | ./xs_test 2>&1`" = 
"FATAL: write: Permission denied" ]
-
-# Grant everyone read access to directoy.
-[ "`echo -e 'setperm /dir 0 READ' | ./xs_test 2>&1`" = "" ]
-[ "`echo -e 'setid 1\ngetperm /dir' | ./xs_test 2>&1`" = "0 READ" ]
-[ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1`" = "" ]
 [ "`echo -e 'setid 1\nwrite /dir/test create contents2' | ./xs_test 2>&1`" = 
"FATAL: write: Permission denied" ]
 
 # Grant everyone write access to directory.
@@ -21,6 +21,8 @@
 [ "`echo -e 'setid 1\ngetperm /dir' | ./xs_test 2>&1`" = "FATAL: getperm: 
Permission denied" ]
 [ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1`" = "FATAL: dir: Permission 
denied" ]
 [ "`echo -e 'setid 1\nwrite /dir/test create contents' | ./xs_test 2>&1`" = "" 
]
+[ "`echo -e 'getperm /dir/test' | ./xs_test 2>&1`" = "1 WRITE" ]
+[ "`echo -e 'setperm /dir/test 0 NONE' | ./xs_test 2>&1`" = "" ]
 [ "`echo -e 'read /dir/test' | ./xs_test 2>&1`" = "contents" ]
 
 # Grant everyone both read and write access.
@@ -29,6 +31,7 @@
 [ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1`" = "test" ]
 [ "`echo -e 'setid 1\nwrite /dir/test2 create contents' | ./xs_test 2>&1`" = 
"" ]
 [ "`echo -e 'setid 1\nread /dir/test2' | ./xs_test 2>&1`" = "contents" ]
+[ "`echo -e 'setid 1\nsetperm /dir/test2 1 NONE' | ./xs_test 2>&1`" = "" ]
 
 # Change so that user 1 owns it, noone else can do anything.
 [ "`echo -e 'setperm /dir 1 NONE' | ./xs_test 2>&1`" = "" ]
@@ -59,3 +62,14 @@
 test3" ]
 [ "`echo -e 'write /dir/test4 create contents' | ./xs_test 2>&1`" = "" ]
 
+# Inherited by child.
+[ "`echo -e 'mkdir /dir/subdir' | ./xs_test 2>&1`" = "" ]
+[ "`echo -e 'getperm /dir/subdir' | ./xs_test 2>&1`" = "1 NONE" ]
+[ "`echo -e 'write /dir/subfile excl contents' | ./xs_test 2>&1`" = "" ]
+[ "`echo -e 'getperm /dir/subfile' | ./xs_test 2>&1`" = "1 NONE" ]
+
+# But for domains, they own it.
+[ "`echo -e 'setperm /dir/subdir 2 READ/WRITE' | ./xs_test 2>&1`" = "" ]
+[ "`echo -e 'getperm /dir/subdir' | ./xs_test 2>&1`" = "2 READ/WRITE" ]
+[ "`echo -e 'setid 3\nwrite /dir/subdir/subfile excl contents' | ./xs_test 
2>&1`" = "" ]
+[ "`echo -e 'getperm /dir/subdir/subfile' | ./xs_test 2>&1`" = "3 READ/WRITE" ]
diff -r 43f224c33281 -r 57a5441b323b tools/xenstore/testsuite/12readonly.sh
--- a/tools/xenstore/testsuite/12readonly.sh    Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/testsuite/12readonly.sh    Tue Jul 12 10:16:33 2005
@@ -14,7 +14,7 @@
 start /
 abort' | ./xs_test --readonly 2>&1`" = "test
 contents
-0 NONE" ]
+0 READ" ]
 
 # These don't work
 [ "`echo 'write /test2 create contents' | ./xs_test --readonly 2>&1`" = 
"FATAL: write: Read-only file system" ]
diff -r 43f224c33281 -r 57a5441b323b 
tools/xenstore/testsuite/05filepermissions.sh
--- a/tools/xenstore/testsuite/05filepermissions.sh     Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/testsuite/05filepermissions.sh     Tue Jul 12 10:16:33 2005
@@ -4,17 +4,17 @@
 [ "`echo -e 'getperm /test' | ./xs_test 2>&1`" = "FATAL: getperm: No such file 
or directory" ]
 [ "`echo -e 'getperm /dir/test' | ./xs_test 2>&1`" = "FATAL: getperm: No such 
file or directory" ]
 
-# Create file: we own it, noone has access.
+# Create file: inherits from root (0 READ)
 [ "`echo -e 'write /test excl contents' | ./xs_test 2>&1`" = "" ]
-[ "`echo -e 'getperm /test' | ./xs_test 2>&1`" = "0 NONE" ]
+[ "`echo -e 'getperm /test' | ./xs_test 2>&1`" = "0 READ" ]
+[ "`echo -e 'setid 1\ngetperm /test' | ./xs_test 2>&1`" = "0 READ" ]
+[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "contents" ]
+[ "`echo -e 'setid 1\nwrite /test none contents2' | ./xs_test 2>&1`" = "FATAL: 
write: Permission denied" ]
+
+# Take away read access to file.
+[ "`echo -e 'setperm /test 0 NONE' | ./xs_test 2>&1`" = "" ]
 [ "`echo -e 'setid 1\ngetperm /test' | ./xs_test 2>&1`" = "FATAL: getperm: 
Permission denied" ]
 [ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "FATAL: read: 
Permission denied" ]
-[ "`echo -e 'setid 1\nwrite /test none contents2' | ./xs_test 2>&1`" = "FATAL: 
write: Permission denied" ]
-
-# Grant everyone read access to file.
-[ "`echo -e 'setperm /test 0 READ' | ./xs_test 2>&1`" = "" ]
-[ "`echo -e 'setid 1\ngetperm /test' | ./xs_test 2>&1`" = "0 READ" ]
-[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "contents" ]
 [ "`echo -e 'setid 1\nwrite /test none contents2' | ./xs_test 2>&1`" = "FATAL: 
write: Permission denied" ]
 
 # Grant everyone write access to file.
diff -r 43f224c33281 -r 57a5441b323b tools/xenstore/utils.c
--- a/tools/xenstore/utils.c    Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/utils.c    Tue Jul 12 10:16:33 2005
@@ -13,17 +13,15 @@
 
 void xprintf(const char *fmt, ...)
 {
-        static FILE *out = NULL;
-        va_list args;
-        if (!out)
-                out = fopen("/dev/console", "w");
+       static FILE *out = NULL;
+       va_list args;
        if (!out)
                out = stderr;
 
-        va_start(args, fmt);
-        vfprintf(out, fmt, args);
-        va_end(args);
-        fflush(out);
+       va_start(args, fmt);
+       vfprintf(out, fmt, args);
+       va_end(args);
+       fflush(out);
 }
 
 void barf(const char *fmt, ...)
@@ -61,14 +59,14 @@
 
 void *_realloc_array(void *ptr, size_t size, size_t num)
 {
-        if (num >= SIZE_MAX/size)
-                return NULL;
-        return realloc_nofail(ptr, size * num);
+       if (num >= SIZE_MAX/size)
+               return NULL;
+       return realloc_nofail(ptr, size * num);
 }
 
 void *realloc_nofail(void *ptr, size_t size)
 {
-        ptr = realloc(ptr, size);
+       ptr = realloc(ptr, size);
        if (ptr)
                return ptr;
        barf("realloc of %zu failed", size);
diff -r 43f224c33281 -r 57a5441b323b tools/xenstore/xenstored_watch.c
--- a/tools/xenstore/xenstored_watch.c  Tue Jul 12 10:09:35 2005
+++ b/tools/xenstore/xenstored_watch.c  Tue Jul 12 10:16:33 2005
@@ -23,12 +23,14 @@
 #include <stdlib.h>
 #include <sys/time.h>
 #include <time.h>
+#include <assert.h>
 #include "talloc.h"
 #include "list.h"
 #include "xenstored_watch.h"
 #include "xs_lib.h"
 #include "utils.h"
 #include "xenstored_test.h"
+#include "xenstored_domain.h"
 
 /* FIXME: time out unacked watches. */
 
@@ -40,13 +42,17 @@
        /* The watch we are firing for (watch->events) */
        struct list_head list;
 
-       /* Watch we are currently attached to. */
-       struct watch *watch;
+       /* 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;
 };
 
 struct watch
@@ -56,6 +62,9 @@
 
        /* Current outstanding events applying to this watch. */
        struct list_head events;
+
+       /* Is this relative to connnection's implicit path? */
+       bool relative;
 
        char *token;
        char *node;
@@ -84,6 +93,7 @@
 void queue_next_event(struct connection *conn)
 {
        struct watch_event *event;
+       const char *node;
        char *buffer;
        unsigned int len;
 
@@ -107,53 +117,63 @@
        /* If we decide to cancel, we will reset this. */
        conn->waiting_for_ack = true;
 
+       /* 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 "". */
+                       node++;
+       }
+
        /* Create reply from path and token */
-       len = strlen(event->node) + 1 + strlen(event->watch->token) + 1;
+       len = strlen(node) + 1 + strlen(event->watches[0]->token) + 1;
        buffer = talloc_array(conn, char, len);
-       strcpy(buffer, event->node);
-       strcpy(buffer+strlen(event->node)+1, event->watch->token);
+       strcpy(buffer, node);
+       strcpy(buffer+strlen(node)+1, event->watches[0]->token);
        send_reply(conn, XS_WATCH_EVENT, buffer, len);
        talloc_free(buffer);
 }
 
-/* Watch on DIR applies to DIR, DIR/FILE, but not DIRLONG. */
-static bool watch_applies(const struct watch *watch, const char *node)
-{
-       return is_child(node, watch->node);
-}
-
-static struct watch *find_watch(const char *node)
-{
-       struct watch *watch;
-
-       list_for_each_entry(watch, &watches, list) {
-               if (watch_applies(watch, node))
-                       return watch;
-       }
-       return NULL;
-}
-
-static struct watch *find_next_watch(struct watch *watch, const char *node)
-{
-       list_for_each_entry_continue(watch, &watches, list) {
-               if (watch_applies(watch, node))
-                       return watch;
-       }
-       return NULL;
+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;
 }
 
 /* FIXME: we fail to fire on out of memory.  Should drop connections. */
-void fire_watches(struct transaction *trans, const char *node)
-{
-       struct watch *watch;
-       struct watch_event *event;
+void fire_watches(struct transaction *trans, const char *node, bool recurse)
+{
+       struct watch **watches;
+       struct watch_event *event;
+       unsigned int num_watches;
 
        /* During transactions, don't fire watches. */
        if (trans)
                return;
 
-       watch = find_watch(node);
-       if (!watch)
+       watches = find_watches(node, recurse, &num_watches);
+       if (!watches)
                return;
 
        /* Create and fill in info about event. */
@@ -161,16 +181,19 @@
        event->node = talloc_strdup(event, node);
 
        /* Tie event to this watch. */
-       event->watch = watch;
-       list_add_tail(&event->list, &watch->events);
+       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 (!watch->conn->out)
-               queue_next_event(watch->conn);
+       if (!watches[0]->conn->out)
+               queue_next_event(watches[0]->conn);
 }
 
 /* We're done with this event: see if anyone else wants it. */
@@ -178,18 +201,41 @@
 {
        list_del(&event->list);
 
-       /* Remove from this watch, and find next watch to put this on. */
-       event->watch = find_next_watch(event->watch, event->node);
-       if (!event->watch) {
+       event->num_watches--;
+       event->watches++;
+       if (!event->num_watches) {
                talloc_free(event);
                return;
        }
 
-       list_add_tail(&event->list, &event->watch->events);
+       list_add_tail(&event->list, &event->watches[0]->events);
 
        /* If connection not doing anything, queue this. */
-       if (!event->watch->conn->out)
-               queue_next_event(event->watch->conn);
+       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--;
+                       }
+               }
+       }
 }
 
 static int destroy_watch(void *_watch)
@@ -203,6 +249,11 @@
 
        /* 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");
        return 0;
 }
 
@@ -251,6 +302,8 @@
                                xprintf("Warning: timeout on watch event %s"
                                        " token %s\n",
                                        i->node, watch->token);
+                               trace_watch_timeout(watch->conn, i->node,
+                                                   watch->token);
                                timerclear(&i->timeout);
                        }
                }
@@ -261,10 +314,12 @@
 {
        struct watch *watch;
        char *vec[3];
+       bool relative;
 
        if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
                return send_error(conn, EINVAL);
 
+       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);
@@ -274,22 +329,27 @@
        watch->token = talloc_strdup(watch, vec[1]);
        watch->conn = conn;
        watch->priority = strtoul(vec[2], NULL, 0);
+       watch->relative = relative;
        INIT_LIST_HEAD(&watch->events);
 
        insert_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)
 {
        struct watch_event *event;
+
+       if (!token)
+               return send_error(conn, EINVAL);
 
        if (!conn->waiting_for_ack)
                return send_error(conn, ENOENT);
 
        event = get_first_event(conn);
-       if (!streq(event->watch->token, token))
+       if (!streq(event->watches[0]->token, token))
                return send_error(conn, EINVAL);
 
        move_event_onwards(event);
@@ -305,6 +365,9 @@
        if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
                return send_error(conn, EINVAL);
 
+       /* 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)

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] xenstored updates., Xen patchbot -unstable <=