[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen staging] tools/libs/store: add support to use watches with a depth parameter



commit 27d908e74edcc7145dd0be61f8aa5978fd42df63
Author:     Juergen Gross <jgross@xxxxxxxx>
AuthorDate: Tue Apr 21 09:42:05 2026 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Wed Apr 22 08:57:44 2026 +0200

    tools/libs/store: add support to use watches with a depth parameter
    
    Add a new xs_watch_depth() function to libxenstore allowing to limit
    the scope of a Xenstore watch. It can be used only in case Xenstore is
    supporting the XENSTORE_SERVER_FEATURE_WATCHDEPTH feature.
    
    For convenience add a xs_watch_try_depth() wrapper, which will call
    xs_watch_depth() if supported and xs_watch() otherwise.
    
    Cache the supported features of Xenstore in order not having to get
    them from Xenstore for each call of one of the new functions.
    
    While touching xs.c fix a whitespace issue there.
    
    Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
    Reviewed-by: Jason Andryuk <jason.andryuk@xxxxxxx>
---
 docs/man/xl.cfg.5.pod.in         |   6 +++
 tools/include/xenstore.h         |  16 ++++++
 tools/libs/store/libxenstore.map |   2 +
 tools/libs/store/xs.c            | 102 ++++++++++++++++++++++++++++++++++-----
 xen/include/public/io/xs_wire.h  |   2 +
 5 files changed, 116 insertions(+), 12 deletions(-)

diff --git a/docs/man/xl.cfg.5.pod.in b/docs/man/xl.cfg.5.pod.in
index 3aac0bc4fb..2f77016ecf 100644
--- a/docs/man/xl.cfg.5.pod.in
+++ b/docs/man/xl.cfg.5.pod.in
@@ -740,6 +740,12 @@ Xenstore is capable to reconnect to a guest.
 Xenstore will present an error value in case it disconnects due to an error
 condition.
 
+=item B<0x00000004>
+
+Xenstore supports to set watches with a limited depth (depth 0 matches
+only the watched node, depth 1 matches the node and its direct children,
+etc.).
+
 =back
 
 The features supported by the running Xenstore instance can be retrieved
diff --git a/tools/include/xenstore.h b/tools/include/xenstore.h
index bf6d767a22..9422ed5657 100644
--- a/tools/include/xenstore.h
+++ b/tools/include/xenstore.h
@@ -177,6 +177,22 @@ bool xs_set_permissions(struct xs_handle *h, 
xs_transaction_t t,
  */
 bool xs_watch(struct xs_handle *h, const char *path, const char *token);
 
+/* Same as xs_watch(), but with limiting the matching for modified
+ * children to a specified depth (depth 0 only matches the node itself,
+ * depth 1 will additionally match direct children of the node, etc.).
+ * Only supported if the XENSTORE_SERVER_FEATURE_WATCHDEPTH (4) is set
+ * in the returned features of xs_get_features_supported().
+ */
+bool xs_watch_depth(struct xs_handle *h, const char *path, const char *token,
+                   unsigned int depth);
+
+/* If supported, same as xs_watch_depth(), use xs_watch() otherwise.
+ * As a result watches might trigger for nodes below the watched path, too.
+ * Not to be used for special watches!
+ */
+bool xs_watch_try_depth(struct xs_handle *h, const char *path,
+                       const char *token, unsigned int depth);
+
 /* Return the FD to poll on to see if a watch has fired. */
 int xs_fileno(struct xs_handle *h);
 
diff --git a/tools/libs/store/libxenstore.map b/tools/libs/store/libxenstore.map
index a08ddd549f..7067068998 100644
--- a/tools/libs/store/libxenstore.map
+++ b/tools/libs/store/libxenstore.map
@@ -52,4 +52,6 @@ VERS_4.2 {
                xs_set_global_quota;
                xs_get_domain_quota;
                xs_set_domain_quota;
+               xs_watch_depth;
+               xs_watch_try_depth;
 } VERS_4.1;
diff --git a/tools/libs/store/xs.c b/tools/libs/store/xs.c
index 06462445e0..cb3508a86a 100644
--- a/tools/libs/store/xs.c
+++ b/tools/libs/store/xs.c
@@ -984,16 +984,8 @@ bool xs_restrict(struct xs_handle *h, unsigned domid)
        return false;
 }
 
-/* Watch a node for changes (poll on fd to detect, or call read_watch()).
- * When the node (or any child) changes, fd will become readable.
- * Token is returned when watch is read, to allow matching.
- * Returns false on failure.
- */
-bool xs_watch(struct xs_handle *h, const char *path, const char *token)
+static bool xs_watch_helper(struct xs_handle *h)
 {
-       struct xsd_sockmsg msg = { .type = XS_WATCH };
-       struct iovec iov[3];
-
 #ifdef USE_PTHREAD
 #define DEFAULT_THREAD_STACKSIZE (16 * 1024)
 /* NetBSD doesn't have PTHREAD_STACK_MIN. */
@@ -1001,8 +993,8 @@ bool xs_watch(struct xs_handle *h, const char *path, const 
char *token)
 # define PTHREAD_STACK_MIN 0
 #endif
 
-#define READ_THREAD_STACKSIZE                                  \
-       ((DEFAULT_THREAD_STACKSIZE < PTHREAD_STACK_MIN) ?       \
+#define READ_THREAD_STACKSIZE                                  \
+       ((DEFAULT_THREAD_STACKSIZE < PTHREAD_STACK_MIN) ?       \
         PTHREAD_STACK_MIN : DEFAULT_THREAD_STACKSIZE)
 
        /* We dynamically create a reader thread on demand. */
@@ -1050,16 +1042,89 @@ bool xs_watch(struct xs_handle *h, const char *path, 
const char *token)
        mutex_unlock(&h->request_mutex);
 #endif
 
+       return true;
+}
+
+/* Watch a node for changes (poll on fd to detect, or call read_watch()).
+ * When the node (or any child) changes, fd will become readable.
+ * Token is returned when watch is read, to allow matching.
+ * Returns false on failure.
+ */
+bool xs_watch(struct xs_handle *h, const char *path, const char *token)
+{
+       struct xsd_sockmsg msg = { .type = XS_WATCH };
+       struct iovec iov[3];
+
+       if (!xs_watch_helper(h))
+               return false;
+
+       iov[0].iov_base = &msg;
+       iov[0].iov_len  = sizeof(msg);
+       iov[1].iov_base = (void *)path;
+       iov[1].iov_len  = strlen(path) + 1;
+       iov[2].iov_base = (void *)token;
+       iov[2].iov_len  = strlen(token) + 1;
+
+       return xs_bool(xs_talkv(h, iov, ARRAY_SIZE(iov), NULL));
+}
+
+/* Same as xs_watch(), but with limiting the matching for modified
+ * children to a specified depth (depth 0 only matches the node itself,
+ * depth 1 will additionally match direct children of the node, etc.).
+ * Only supported if the XENSTORE_SERVER_FEATURE_WATCHDEPTH (4) is set
+ * in the returned features of xs_get_features_supported().
+ */
+bool xs_watch_depth(struct xs_handle *h, const char *path, const char *token,
+                   unsigned int depth)
+{
+       struct xsd_sockmsg msg = { .type = XS_WATCH };
+       struct iovec iov[4];
+       char depthstr[MAX_STRLEN(depth)];
+       static bool depth_supported;
+
+       if (!xs_watch_helper(h))
+               return false;
+
+       if (!depth_supported) {
+               unsigned int features;
+
+               if (!xs_get_features_supported(h, &features))
+                       return false;
+               if (!(features & XENSTORE_SERVER_FEATURE_WATCHDEPTH))
+                       return false;
+               depth_supported = true;
+       }
+
+       snprintf(depthstr, sizeof(depthstr), "%u", depth);
+
        iov[0].iov_base = &msg;
        iov[0].iov_len  = sizeof(msg);
        iov[1].iov_base = (void *)path;
        iov[1].iov_len  = strlen(path) + 1;
        iov[2].iov_base = (void *)token;
        iov[2].iov_len  = strlen(token) + 1;
+       iov[3].iov_base = depthstr;
+       iov[3].iov_len = strlen(depthstr) + 1;
 
        return xs_bool(xs_talkv(h, iov, ARRAY_SIZE(iov), NULL));
 }
 
+/* If supported, same as xs_watch_depth(), use xs_watch() otherwise.
+ * As a result watches might trigger for nodes below the watched path, too.
+ * Not to be used for special watches!
+ */
+bool xs_watch_try_depth(struct xs_handle *h, const char *path,
+                       const char *token, unsigned int depth)
+{
+       unsigned int features;
+
+       if (xs_get_features_supported(h, &features) &&
+           (features & XENSTORE_SERVER_FEATURE_WATCHDEPTH) &&
+           xs_watch_depth(h, path, token, depth))
+               return true;
+
+       return xs_watch(h, path, token);
+}
 
 /* Clear the pipe token if there are no more pending watchs.
  * We suppose the watch_mutex is already taken.
@@ -1420,13 +1485,26 @@ static bool xs_uint(char *reply, unsigned int *uintval)
 
 bool xs_get_features_supported(struct xs_handle *h, unsigned int *features)
 {
+       static unsigned int own_features = 0;
+       static bool features_valid = false;
        struct xsd_sockmsg msg = { .type = XS_GET_FEATURE };
        struct iovec iov[1];
 
+       if (features_valid) {
+               *features = own_features;
+               return true;
+       }
+
        iov[0].iov_base = &msg;
        iov[0].iov_len  = sizeof(msg);
 
-       return xs_uint(xs_talkv(h, iov, ARRAY_SIZE(iov), NULL), features);
+       if (!xs_uint(xs_talkv(h, iov, ARRAY_SIZE(iov), NULL), &own_features))
+               return false;
+
+       features_valid = true;
+       *features = own_features;
+
+       return true;
 }
 
 bool xs_get_features_domain(struct xs_handle *h, unsigned int domid,
diff --git a/xen/include/public/io/xs_wire.h b/xen/include/public/io/xs_wire.h
index d2e2b8b9eb..2e763bc877 100644
--- a/xen/include/public/io/xs_wire.h
+++ b/xen/include/public/io/xs_wire.h
@@ -124,6 +124,8 @@ struct xenstore_domain_interface {
 #define XENSTORE_SERVER_FEATURE_RECONNECTION 1
 /* The presence of the "error" field in the ring page */
 #define XENSTORE_SERVER_FEATURE_ERROR        2
+/* The XS_WATCH command can be used with a <depth> parameter */
+#define XENSTORE_SERVER_FEATURE_WATCHDEPTH   4
 
 /* Valid values for the connection field */
 #define XENSTORE_CONNECTED 0 /* the steady-state */
--
generated by git-patchbot for /home/xen/git/xen.git#staging



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.