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

[PATCH 3/8] 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.

Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
---
 docs/man/xl.cfg.5.pod.in         |   6 ++
 tools/include/xenstore.h         |  16 +++++
 tools/libs/store/libxenstore.map |   2 +
 tools/libs/store/xs.c            | 116 ++++++++++++++++++++++++++-----
 xen/include/public/io/xs_wire.h  |   2 +
 5 files changed, 123 insertions(+), 19 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 6b661e5895..8a6afd97f5 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 dda37f7526..0bea464a33 100644
--- a/tools/libs/store/xs.c
+++ b/tools/libs/store/xs.c
@@ -984,37 +984,29 @@ 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
+       sigset_t set, old_set;
+       pthread_attr_t attr;
+       static size_t stack_size;
+#ifdef USE_DLSYM
+       size_t (*getsz)(pthread_attr_t *attr);
+#endif
+
 #define DEFAULT_THREAD_STACKSIZE (16 * 1024)
 /* NetBSD doesn't have PTHREAD_STACK_MIN. */
 #ifndef PTHREAD_STACK_MIN
 # 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. */
        mutex_lock(&h->request_mutex);
        if (!h->read_thr_exists) {
-               sigset_t set, old_set;
-               pthread_attr_t attr;
-               static size_t stack_size;
-#ifdef USE_DLSYM
-               size_t (*getsz)(pthread_attr_t *attr);
-#endif
-
                if (pthread_attr_init(&attr) != 0) {
                        mutex_unlock(&h->request_mutex);
                        return false;
@@ -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 */
-- 
2.53.0




 


Rackspace

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