diff --git a/tools/xenstored/core.c b/tools/xenstored/core.c index 807a8e6710..f92fca6e9e 100644 --- a/tools/xenstored/core.c +++ b/tools/xenstored/core.c @@ -1613,7 +1613,7 @@ static int do_write(const void *ctx, struct connection *conn, return errno; } - fire_watches(conn, ctx, name, node, false, NULL); + fire_watches(conn, ctx, name, node, MATCH_SUBTREE, NULL); send_ack(conn, XS_WRITE); return 0; @@ -1637,7 +1637,7 @@ static int do_mkdir(const void *ctx, struct connection *conn, node = create_node(conn, ctx, name, NULL, 0); if (!node) return errno; - fire_watches(conn, ctx, name, node, false, NULL); + fire_watches(conn, ctx, name, node, MATCH_SUBTREE, NULL); } send_ack(conn, XS_MKDIR); @@ -1683,7 +1683,7 @@ static int delnode_sub(const void *ctx, struct connection *conn, struct node *node, void *arg) { const char *root = arg; - bool watch_exact; + enum watch_match watch_match; int ret; const char *db_name; @@ -1703,8 +1703,8 @@ static int delnode_sub(const void *ctx, struct connection *conn, * This fine as we are single threaded and the next possible read will * be handled only after the node has been really removed. */ - watch_exact = strcmp(root, node->name); - fire_watches(conn, ctx, node->name, node, watch_exact, NULL); + watch_match = strcmp(root, node->name) ? MATCH_EXACT : MATCH_SUBTREE; + fire_watches(conn, ctx, node->name, node, watch_match, NULL); return WALK_TREE_RM_CHILDENTRY; } @@ -1858,7 +1858,7 @@ static int do_set_perms(const void *ctx, struct connection *conn, if (write_node(conn, node, NODE_MODIFY, false)) return errno; - fire_watches(conn, ctx, name, node, false, &old_perms); + fire_watches(conn, ctx, name, node, MATCH_SUBTREE, &old_perms); send_ack(conn, XS_SET_PERMS); return 0; diff --git a/tools/xenstored/transaction.c b/tools/xenstored/transaction.c index 47cd6ecd3c..ec5b122a3f 100644 --- a/tools/xenstored/transaction.c +++ b/tools/xenstored/transaction.c @@ -134,7 +134,7 @@ struct accessed_node /* Watch event flags. */ bool fire_watch; - bool watch_exact; + enum watch_match watch_match; }; struct transaction @@ -327,8 +327,10 @@ err: * A watch event should be fired for a node modified inside a transaction. * Set the corresponding information. A non-exact event is replacing an exact * one, but not the other way round. + * No special watch handling needed here, so MATCH_DEPTH is no issue. */ -void queue_watches(struct connection *conn, const char *name, bool watch_exact) +void queue_watches(struct connection *conn, const char *name, + enum watch_match watch_match) { struct accessed_node *i; @@ -340,9 +342,9 @@ void queue_watches(struct connection *conn, const char *name, bool watch_exact) if (!i->fire_watch) { i->fire_watch = true; - i->watch_exact = watch_exact; - } else if (!watch_exact) { - i->watch_exact = false; + i->watch_match = watch_match; + } else if (watch_match == MATCH_SUBTREE) { + i->watch_match = MATCH_SUBTREE; } } @@ -419,7 +421,7 @@ static int finalize_transaction(struct connection *conn, db_delete(conn, i->node, NULL); } if (i->fire_watch) - fire_watches(conn, trans, i->node, NULL, i->watch_exact, + fire_watches(conn, trans, i->node, NULL, i->watch_match, i->perms.p ? &i->perms : NULL); list_del(&i->list); diff --git a/tools/xenstored/transaction.h b/tools/xenstored/transaction.h index 90435b4fc9..b4f5f757e2 100644 --- a/tools/xenstored/transaction.h +++ b/tools/xenstored/transaction.h @@ -18,6 +18,7 @@ #ifndef _XENSTORED_TRANSACTION_H #define _XENSTORED_TRANSACTION_H #include "core.h" +#include "watch.h" enum node_access_type { NODE_ACCESS_READ, @@ -44,7 +45,8 @@ int __must_check access_node(struct connection *conn, struct node *node, enum node_access_type type, const char **db_name); /* Queue watches for a modified node. */ -void queue_watches(struct connection *conn, const char *name, bool watch_exact); +void queue_watches(struct connection *conn, const char *name, + enum watch_match watch_match); /* Prepend the transaction to name if appropriate. */ const char *transaction_prepend(struct connection *conn, const char *name); diff --git a/tools/xenstored/watch.c b/tools/xenstored/watch.c index 860c219f29..a9a06e9e48 100644 --- a/tools/xenstored/watch.c +++ b/tools/xenstored/watch.c @@ -128,7 +128,8 @@ static bool watch_permitted(struct connection *conn, const void *ctx, * watch event, too. */ void fire_watches(struct connection *conn, const void *ctx, const char *name, - const struct node *node, bool exact, struct node_perms *perms) + const struct node *node, enum watch_match match, + struct node_perms *perms) { struct connection *i; struct buffered_data *req; @@ -136,7 +137,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name, /* During transactions, don't fire watches, but queue them. */ if (conn && conn->transaction) { - queue_watches(conn, name, exact); + queue_watches(conn, name, match); return; } @@ -148,17 +149,34 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name, continue; list_for_each_entry(watch, &i->watches, list) { - if (exact) { - if (streq(name, watch->node)) - send_event(req, i, - get_watch_path(watch, name), - watch->token); - } else { - if (is_child(name, watch->node, watch->depth)) - send_event(req, i, - get_watch_path(watch, name), - watch->token); + bool send = false; + + switch (match) { + case MATCH_EXACT: + send = streq(name, watch->node); + break; + + case MATCH_SUBTREE: + send = is_child(name, watch->node, + watch->depth); + break; + + case MATCH_DEPTH: + send = streq(name, watch->node) || + (watch->depth > 0 && + is_child(name, watch->node, + watch->depth)); + break; + + case MATCH_NODEPTH: + send = streq(name, watch->node) && + watch->depth < 0; + break; } + + if (send) + send_event(req, i, get_watch_path(watch, name), + watch->token); } } } diff --git a/tools/xenstored/watch.h b/tools/xenstored/watch.h index afdfdc6b2f..692343389f 100644 --- a/tools/xenstored/watch.h +++ b/tools/xenstored/watch.h @@ -27,8 +27,15 @@ int do_unwatch(const void *ctx, struct connection *conn, struct buffered_data *in); /* Fire all watches: !exact means all the children are affected (ie. rm). */ +enum watch_match { + MATCH_EXACT, + MATCH_SUBTREE, + MATCH_DEPTH, /* watches with depth > 0, MATCH_SUBTREE semantics */ + MATCH_NODEPTH /* watches with no depth, MATCH_EXACT semantics */ +}; + void fire_watches(struct connection *conn, const void *tmp, const char *name, - const struct node *node, bool exact, + const struct node *node, enum watch_match match, struct node_perms *perms); void conn_delete_all_watches(struct connection *conn);