From nobody Mon Mar 23 21:32:04 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail(p=quarantine dis=quarantine) header.from=suse.com Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1773388113962669.4305521749094; Fri, 13 Mar 2026 00:48:33 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1253354.1549650 (Exim 4.92) (envelope-from ) id 1w0xFq-0004jd-Kx; Fri, 13 Mar 2026 07:48:18 +0000 Received: by outflank-mailman (output) from mailman id 1253354.1549650; Fri, 13 Mar 2026 07:48:18 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1w0xFq-0004jW-Fq; Fri, 13 Mar 2026 07:48:18 +0000 Received: by outflank-mailman (input) for mailman id 1253354; Fri, 13 Mar 2026 07:48:16 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1w0xFo-0003TG-G4 for xen-devel@lists.xenproject.org; Fri, 13 Mar 2026 07:48:16 +0000 Received: from smtp-out1.suse.de (smtp-out1.suse.de [2a07:de40:b251:101:10:150:64:1]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id fe548862-1eb0-11f1-b164-2bf370ae4941; Fri, 13 Mar 2026 08:48:15 +0100 (CET) Received: from imap1.dmz-prg2.suse.org (imap1.dmz-prg2.suse.org [IPv6:2a07:de40:b281:104:10:150:64:97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 79DA24D656; Fri, 13 Mar 2026 07:48:15 +0000 (UTC) Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id 5794B403F6; Fri, 13 Mar 2026 07:48:15 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id NQ08FD/Bs2m5GAAAD6G6ig (envelope-from ); Fri, 13 Mar 2026 07:48:15 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: fe548862-1eb0-11f1-b164-2bf370ae4941 Authentication-Results: smtp-out1.suse.de; none From: Juergen Gross To: xen-devel@lists.xenproject.org Cc: Juergen Gross , Julien Grall , Anthony PERARD Subject: [PATCH 4/8] tools/xenstored: add depth information to watches Date: Fri, 13 Mar 2026 08:47:47 +0100 Message-ID: <20260313074751.2904215-5-jgross@suse.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260313074751.2904215-1-jgross@suse.com> References: <20260313074751.2904215-1-jgross@suse.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Rspamd-Pre-Result: action=no action; module=replies; Message is reply to one we originated X-Rspamd-Server: rspamd2.dmz-prg2.suse.org X-Spamd-Result: default: False [-4.00 / 50.00]; REPLY(-4.00)[] X-Rspamd-Queue-Id: 79DA24D656 X-Rspamd-Pre-Result: action=no action; module=replies; Message is reply to one we originated X-Rspamd-Action: no action X-Spam-Flag: NO X-Spam-Score: -4.00 X-Spam-Level: X-ZM-MESSAGEID: 1773388114983158500 Content-Type: text/plain; charset="utf-8" Add the depth for matching subdirectories of a watch to the watch handling. A depth value of -1 is used for the current model of no limit. Signed-off-by: Juergen Gross --- tools/xenstored/lu.c | 3 ++ tools/xenstored/watch.c | 110 ++++++++++++++++++++++++++++------------ tools/xenstored/watch.h | 1 + 3 files changed, 81 insertions(+), 33 deletions(-) diff --git a/tools/xenstored/lu.c b/tools/xenstored/lu.c index eaffdbc69e..7d9f086a59 100644 --- a/tools/xenstored/lu.c +++ b/tools/xenstored/lu.c @@ -183,6 +183,9 @@ void lu_read_state(void) case XS_STATE_TYPE_WATCH: read_state_watch(ctx, state.buf); break; + case XS_STATE_TYPE_WATCH_EXT: + read_state_watch_ext(ctx, state.buf); + break; case XS_STATE_TYPE_TA: xprintf("live-update: ignore transaction record\n"); break; diff --git a/tools/xenstored/watch.c b/tools/xenstored/watch.c index 36e4d33f22..3f1049911b 100644 --- a/tools/xenstored/watch.c +++ b/tools/xenstored/watch.c @@ -39,26 +39,35 @@ struct watch /* Offset into path for skipping prefix (used for relative paths). */ unsigned int prefix_len; =20 + int depth; /* -1: no depth limit. */ char *token; char *node; }; =20 /* Is child a subnode of parent, or equal? */ -static bool is_child(const char *child, const char *parent) +static bool is_child(const char *child, const char *parent, int depth) { - unsigned int len =3D strlen(parent); - - /* - * / should really be "" for this algorithm to work, but that's a - * usability nightmare. - */ - if (streq(parent, "/")) - return true; + unsigned int len =3D strlen(parent); /* len =3D=3D 1 if parent is "/". */ + unsigned int sub_levels =3D (len =3D=3D 1) ? 1 : 0; =20 if (strncmp(child, parent, len) !=3D 0) return false; =20 - return child[len] =3D=3D '/' || child[len] =3D=3D '\0'; + if (child[len] !=3D '/' && child[len] !=3D '\0' && len > 1) + return false; + + if (depth < 0 || child[len] =3D=3D '\0') + return true; + + while (sub_levels <=3D depth) { + if (child[len] =3D=3D '\0') + return true; + if (child[len] =3D=3D '/') + sub_levels++; + len++; + } + + return false; } =20 static const char *get_watch_path(const struct watch *watch, const char *n= ame) @@ -145,7 +154,7 @@ void fire_watches(struct connection *conn, const void *= ctx, const char *name, get_watch_path(watch, name), watch->token); } else { - if (is_child(name, watch->node)) + if (is_child(name, watch->node, watch->depth)) send_event(req, i, get_watch_path(watch, name), watch->token); @@ -170,7 +179,7 @@ static int check_watch_path(struct connection *conn, co= nst void *ctx, } =20 static struct watch *add_watch(struct connection *conn, const char *path, - const char *token, bool relative, + const char *token, int depth, bool relative, bool no_quota_check) { struct watch *watch; @@ -178,6 +187,7 @@ static struct watch *add_watch(struct connection *conn,= const char *path, watch =3D talloc(conn, struct watch); if (!watch) goto nomem; + watch->depth =3D depth; watch->node =3D talloc_strdup(watch, path); watch->token =3D talloc_strdup(watch, token); if (!watch->node || !watch->token) @@ -204,6 +214,7 @@ int do_watch(const void *ctx, struct connection *conn, = struct buffered_data *in) { struct watch *watch; const char *vec[2]; + int depth =3D -1; bool relative; =20 if (get_strings(in, vec, ARRAY_SIZE(vec)) !=3D ARRAY_SIZE(vec)) @@ -223,7 +234,7 @@ int do_watch(const void *ctx, struct connection *conn, = struct buffered_data *in) if (domain_check_quota_add(conn->domain, ACC_WATCH, 1)) return ENOSPC; =20 - watch =3D add_watch(conn, vec[0], vec[1], relative, false); + watch =3D add_watch(conn, vec[0], vec[1], depth, relative, false); if (!watch) return errno; =20 @@ -287,28 +298,47 @@ const char *dump_state_watches(FILE *fp, struct conne= ction *conn, const char *ret =3D NULL; struct watch *watch; struct xs_state_watch sw; + struct xs_state_watch_ext swe; struct xs_state_record_header head; const char *path; - - head.type =3D XS_STATE_TYPE_WATCH; + size_t path_len, token_len; =20 list_for_each_entry(watch, &conn->watches, list) { - head.length =3D sizeof(sw); - - sw.conn_id =3D conn_id; path =3D get_watch_path(watch, watch->node); - sw.path_length =3D strlen(path) + 1; - sw.token_length =3D strlen(watch->token) + 1; - head.length +=3D sw.path_length + sw.token_length; + path_len =3D strlen(path) + 1; + token_len =3D strlen(watch->token) + 1; + + if (watch->depth >=3D 0) { + head.type =3D XS_STATE_TYPE_WATCH_EXT; + head.length =3D sizeof(swe); + swe.conn_id =3D conn_id; + swe.path_length =3D path_len; + swe.token_length =3D token_len; + swe.depth =3D watch->depth; + } else { + head.type =3D XS_STATE_TYPE_WATCH; + head.length =3D sizeof(sw); + sw.conn_id =3D conn_id; + sw.path_length =3D path_len; + sw.token_length =3D token_len; + } + + head.length +=3D path_len + token_len; head.length =3D ROUNDUP(head.length, 3); if (fwrite(&head, sizeof(head), 1, fp) !=3D 1) return "Dump watch state error"; - if (fwrite(&sw, sizeof(sw), 1, fp) !=3D 1) - return "Dump watch state error"; =20 - if (fwrite(path, sw.path_length, 1, fp) !=3D 1) + if (watch->depth >=3D 0) { + if (fwrite(&swe, sizeof(sw), 1, fp) !=3D 1) + return "Dump watch state ext error"; + } else { + if (fwrite(&sw, sizeof(sw), 1, fp) !=3D 1) + return "Dump watch state error"; + } + + if (fwrite(path, path_len, 1, fp) !=3D 1) return "Dump watch path error"; - if (fwrite(watch->token, sw.token_length, 1, fp) !=3D 1) + if (fwrite(watch->token, token_len, 1, fp) !=3D 1) return "Dump watch token error"; =20 ret =3D dump_state_align(fp); @@ -319,27 +349,41 @@ const char *dump_state_watches(FILE *fp, struct conne= ction *conn, return ret; } =20 -void read_state_watch(const void *ctx, const void *state) +static void process_state_watch(const void *ctx, unsigned int conn_id, + const char *path, const char *token, + int depth) { - const struct xs_state_watch *sw =3D state; struct connection *conn; - const char *path, *token; bool relative; =20 - conn =3D get_connection_by_id(sw->conn_id); + conn =3D get_connection_by_id(conn_id); if (!conn) barf("connection not found for read watch"); =20 - path =3D (char *)sw->data; - token =3D path + sw->path_length; - /* Don't check success, we want the relative information only. */ check_watch_path(conn, ctx, &path, &relative); if (!path) barf("allocation error for read watch"); =20 - if (!add_watch(conn, path, token, relative, true)) + if (!add_watch(conn, path, token, depth, relative, true)) barf("error adding watch"); + +} + +void read_state_watch(const void *ctx, const void *state) +{ + const struct xs_state_watch *sw =3D state; + + process_state_watch(ctx, sw->conn_id, (char *)sw->data, + (char *)sw->data + sw->path_length, -1); +} + +void read_state_watch_ext(const void *ctx, const void *state) +{ + const struct xs_state_watch_ext *swe =3D state; + + process_state_watch(ctx, swe->conn_id, (char *)swe->data, + (char *)swe->data + swe->path_length, swe->depth); } =20 /* diff --git a/tools/xenstored/watch.h b/tools/xenstored/watch.h index d9ac6a334a..afdfdc6b2f 100644 --- a/tools/xenstored/watch.h +++ b/tools/xenstored/watch.h @@ -37,5 +37,6 @@ const char *dump_state_watches(FILE *fp, struct connectio= n *conn, unsigned int conn_id); =20 void read_state_watch(const void *ctx, const void *state); +void read_state_watch_ext(const void *ctx, const void *state); =20 #endif /* _XENSTORED_WATCH_H */ --=20 2.53.0