[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen stable-4.15] tools/xenstore: reduce number of watch events
commit 8999db805e5ef55172a85d67695429edc3d78771 Author: Juergen Gross <jgross@xxxxxxxx> AuthorDate: Tue Sep 13 07:35:07 2022 +0200 Commit: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> CommitDate: Tue Nov 1 15:03:25 2022 +0000 tools/xenstore: reduce number of watch events When removing a watched node outside of a transaction, two watch events are being produced instead of just a single one. When finalizing a transaction watch events can be generated for each node which is being modified, even if outside a transaction such modifications might not have resulted in a watch event. This happens e.g.: - for nodes which are only modified due to added/removed child entries - for nodes being removed or created implicitly (e.g. creation of a/b/c is implicitly creating a/b, resulting in watch events for a, a/b and a/b/c instead of a/b/c only) Avoid these additional watch events, in order to reduce the needed memory inside Xenstore for queueing them. This is being achieved by adding event flags to struct accessed_node specifying whether an event should be triggered, and whether it should be an exact match of the modified path. Both flags can be set from fire_watches() instead of implying them only. This is part of XSA-326. Signed-off-by: Juergen Gross <jgross@xxxxxxxx> Reviewed-by: Julien Grall <jgrall@xxxxxxxxxx> (cherry picked from commit 3a96013a3e17baa07410b1b9776225d1d9a74297) --- tools/xenstore/xenstored_core.c | 19 ++++++++-------- tools/xenstore/xenstored_transaction.c | 41 ++++++++++++++++++++++++++++------ tools/xenstore/xenstored_transaction.h | 3 +++ tools/xenstore/xenstored_watch.c | 7 ++++-- 4 files changed, 51 insertions(+), 19 deletions(-) diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_core.c index 6498bf6036..5157a7527f 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -1261,7 +1261,7 @@ static void delete_child(struct connection *conn, } static int delete_node(struct connection *conn, const void *ctx, - struct node *parent, struct node *node) + struct node *parent, struct node *node, bool watch_exact) { char *name; @@ -1273,7 +1273,7 @@ static int delete_node(struct connection *conn, const void *ctx, node->children); child = name ? read_node(conn, node, name) : NULL; if (child) { - if (delete_node(conn, ctx, node, child)) + if (delete_node(conn, ctx, node, child, true)) return errno; } else { trace("delete_node: Error deleting child '%s/%s'!\n", @@ -1285,7 +1285,12 @@ static int delete_node(struct connection *conn, const void *ctx, talloc_free(name); } - fire_watches(conn, ctx, node->name, node, true, NULL); + /* + * Fire the watches now, when we can still see the node permissions. + * This fine as we are single threaded and the next possible read will + * be handled only after the node has been really removed. + */ + fire_watches(conn, ctx, node->name, node, watch_exact, NULL); delete_node_single(conn, node); delete_child(conn, parent, basename(node->name)); talloc_free(node); @@ -1311,13 +1316,7 @@ static int _rm(struct connection *conn, const void *ctx, struct node *node, return (errno == ENOMEM) ? ENOMEM : EINVAL; node->parent = parent; - /* - * Fire the watches now, when we can still see the node permissions. - * This fine as we are single threaded and the next possible read will - * be handled only after the node has been really removed. - */ - fire_watches(conn, ctx, name, node, false, NULL); - return delete_node(conn, ctx, parent, node); + return delete_node(conn, ctx, parent, node, false); } diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xenstored_transaction.c index faf6c930e4..54432907fc 100644 --- a/tools/xenstore/xenstored_transaction.c +++ b/tools/xenstore/xenstored_transaction.c @@ -130,6 +130,10 @@ struct accessed_node /* Transaction node in data base? */ bool ta_node; + + /* Watch event flags. */ + bool fire_watch; + bool watch_exact; }; struct changed_domain @@ -323,6 +327,29 @@ err: return ret; } +/* + * 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. + */ +void queue_watches(struct connection *conn, const char *name, bool watch_exact) +{ + struct accessed_node *i; + + i = find_accessed_node(conn->transaction, name); + if (!i) { + conn->transaction->fail = true; + return; + } + + if (!i->fire_watch) { + i->fire_watch = true; + i->watch_exact = watch_exact; + } else if (!watch_exact) { + i->watch_exact = false; + } +} + /* * Finalize transaction: * Walk through accessed nodes and check generation against global data. @@ -377,15 +404,15 @@ static int finalize_transaction(struct connection *conn, ret = tdb_store(tdb_ctx, key, data, TDB_REPLACE); talloc_free(data.dptr); - if (ret) - goto err; - fire_watches(conn, trans, i->node, NULL, false, - i->perms.p ? &i->perms : NULL); } else { - fire_watches(conn, trans, i->node, NULL, false, + ret = tdb_delete(tdb_ctx, key); + } + if (ret) + goto err; + if (i->fire_watch) { + fire_watches(conn, trans, i->node, NULL, + i->watch_exact, i->perms.p ? &i->perms : NULL); - if (tdb_delete(tdb_ctx, key)) - goto err; } } diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xenstored_transaction.h index 14062730e3..0093cac807 100644 --- a/tools/xenstore/xenstored_transaction.h +++ b/tools/xenstore/xenstored_transaction.h @@ -42,6 +42,9 @@ void transaction_entry_dec(struct transaction *trans, unsigned int domid); int access_node(struct connection *conn, struct node *node, enum node_access_type type, TDB_DATA *key); +/* Queue watches for a modified node. */ +void queue_watches(struct connection *conn, const char *name, bool watch_exact); + /* Prepend the transaction to name if appropriate. */ int transaction_prepend(struct connection *conn, const char *name, TDB_DATA *key); diff --git a/tools/xenstore/xenstored_watch.c b/tools/xenstore/xenstored_watch.c index a116f967dc..bc6d833028 100644 --- a/tools/xenstore/xenstored_watch.c +++ b/tools/xenstore/xenstored_watch.c @@ -29,6 +29,7 @@ #include "xenstore_lib.h" #include "utils.h" #include "xenstored_domain.h" +#include "xenstored_transaction.h" extern int quota_nb_watch_per_domain; @@ -143,9 +144,11 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name, struct connection *i; struct watch *watch; - /* During transactions, don't fire watches. */ - if (conn && conn->transaction) + /* During transactions, don't fire watches, but queue them. */ + if (conn && conn->transaction) { + queue_watches(conn, name, exact); return; + } /* Create an event for each watch. */ list_for_each_entry(i, &connections, list) { -- generated by git-patchbot for /home/xen/git/xen.git#stable-4.15
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |