mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
tools/xenstored: add depth information to watches
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 <jgross@suse.com> Reviewed-by: Jason Andryuk <jason.andryuk@amd.com>
This commit is contained in:
1 parent
27d908e74e
commit
db98de120c
3 files changed
+81
-33
No files matched your search
@@ -183,6 +183,9 @@ void lu_read_state(void)
|
|||||||
case XS_STATE_TYPE_WATCH:
|
case XS_STATE_TYPE_WATCH:
|
||||||
read_state_watch(ctx, state.buf);
|
read_state_watch(ctx, state.buf);
|
||||||
break;
|
break;
|
||||||
|
case XS_STATE_TYPE_WATCH_EXT:
|
||||||
|
read_state_watch_ext(ctx, state.buf);
|
||||||
|
break;
|
||||||
case XS_STATE_TYPE_TA:
|
case XS_STATE_TYPE_TA:
|
||||||
xprintf("live-update: ignore transaction record\n");
|
xprintf("live-update: ignore transaction record\n");
|
||||||
break;
|
break;
|
||||||
|
|||||||
+77
-33
@@ -39,26 +39,35 @@ struct watch
|
|||||||
/* Offset into path for skipping prefix (used for relative paths). */
|
/* Offset into path for skipping prefix (used for relative paths). */
|
||||||
unsigned int prefix_len;
|
unsigned int prefix_len;
|
||||||
|
|
||||||
|
int depth; /* -1: no depth limit. */
|
||||||
char *token;
|
char *token;
|
||||||
char *node;
|
char *node;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Is child a subnode of parent, or equal? */
|
/* 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 = strlen(parent);
|
unsigned int len = strlen(parent); /* len == 1 if parent is "/". */
|
||||||
|
unsigned int sub_levels = (len == 1) ? 1 : 0;
|
||||||
/*
|
|
||||||
* / should really be "" for this algorithm to work, but that's a
|
|
||||||
* usability nightmare.
|
|
||||||
*/
|
|
||||||
if (streq(parent, "/"))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (strncmp(child, parent, len) != 0)
|
if (strncmp(child, parent, len) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return child[len] == '/' || child[len] == '\0';
|
if (child[len] != '/' && child[len] != '\0' && len > 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (depth < 0 || child[len] == '\0')
|
||||||
|
return true;
|
||||||
|
|
||||||
|
while (sub_levels <= depth) {
|
||||||
|
if (child[len] == '\0')
|
||||||
|
return true;
|
||||||
|
if (child[len] == '/')
|
||||||
|
sub_levels++;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *get_watch_path(const struct watch *watch, const char *name)
|
static const char *get_watch_path(const struct watch *watch, const char *name)
|
||||||
@@ -145,7 +154,7 @@ void fire_watches(struct connection *conn, const void *ctx, const char *name,
|
|||||||
get_watch_path(watch, name),
|
get_watch_path(watch, name),
|
||||||
watch->token);
|
watch->token);
|
||||||
} else {
|
} else {
|
||||||
if (is_child(name, watch->node))
|
if (is_child(name, watch->node, watch->depth))
|
||||||
send_event(req, i,
|
send_event(req, i,
|
||||||
get_watch_path(watch, name),
|
get_watch_path(watch, name),
|
||||||
watch->token);
|
watch->token);
|
||||||
@@ -170,7 +179,7 @@ static int check_watch_path(struct connection *conn, const void *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct watch *add_watch(struct connection *conn, const char *path,
|
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)
|
bool no_quota_check)
|
||||||
{
|
{
|
||||||
struct watch *watch;
|
struct watch *watch;
|
||||||
@@ -178,6 +187,7 @@ static struct watch *add_watch(struct connection *conn, const char *path,
|
|||||||
watch = talloc(conn, struct watch);
|
watch = talloc(conn, struct watch);
|
||||||
if (!watch)
|
if (!watch)
|
||||||
goto nomem;
|
goto nomem;
|
||||||
|
watch->depth = depth;
|
||||||
watch->node = talloc_strdup(watch, path);
|
watch->node = talloc_strdup(watch, path);
|
||||||
watch->token = talloc_strdup(watch, token);
|
watch->token = talloc_strdup(watch, token);
|
||||||
if (!watch->node || !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;
|
struct watch *watch;
|
||||||
const char *vec[2];
|
const char *vec[2];
|
||||||
|
int depth = -1;
|
||||||
bool relative;
|
bool relative;
|
||||||
|
|
||||||
if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
|
if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
|
||||||
@@ -223,7 +234,7 @@ int do_watch(const void *ctx, struct connection *conn, struct buffered_data *in)
|
|||||||
if (domain_quota_add_exceeds(conn->domain, ACC_WATCH, 1))
|
if (domain_quota_add_exceeds(conn->domain, ACC_WATCH, 1))
|
||||||
return ENOSPC;
|
return ENOSPC;
|
||||||
|
|
||||||
watch = add_watch(conn, vec[0], vec[1], relative, false);
|
watch = add_watch(conn, vec[0], vec[1], depth, relative, false);
|
||||||
if (!watch)
|
if (!watch)
|
||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
@@ -287,28 +298,47 @@ const char *dump_state_watches(FILE *fp, struct connection *conn,
|
|||||||
const char *ret = NULL;
|
const char *ret = NULL;
|
||||||
struct watch *watch;
|
struct watch *watch;
|
||||||
struct xs_state_watch sw;
|
struct xs_state_watch sw;
|
||||||
|
struct xs_state_watch_ext swe;
|
||||||
struct xs_state_record_header head;
|
struct xs_state_record_header head;
|
||||||
const char *path;
|
const char *path;
|
||||||
|
size_t path_len, token_len;
|
||||||
head.type = XS_STATE_TYPE_WATCH;
|
|
||||||
|
|
||||||
list_for_each_entry(watch, &conn->watches, list) {
|
list_for_each_entry(watch, &conn->watches, list) {
|
||||||
head.length = sizeof(sw);
|
|
||||||
|
|
||||||
sw.conn_id = conn_id;
|
|
||||||
path = get_watch_path(watch, watch->node);
|
path = get_watch_path(watch, watch->node);
|
||||||
sw.path_length = strlen(path) + 1;
|
path_len = strlen(path) + 1;
|
||||||
sw.token_length = strlen(watch->token) + 1;
|
token_len = strlen(watch->token) + 1;
|
||||||
head.length += sw.path_length + sw.token_length;
|
|
||||||
|
if (watch->depth >= 0) {
|
||||||
|
head.type = XS_STATE_TYPE_WATCH_EXT;
|
||||||
|
head.length = sizeof(swe);
|
||||||
|
swe.conn_id = conn_id;
|
||||||
|
swe.path_length = path_len;
|
||||||
|
swe.token_length = token_len;
|
||||||
|
swe.depth = watch->depth;
|
||||||
|
} else {
|
||||||
|
head.type = XS_STATE_TYPE_WATCH;
|
||||||
|
head.length = sizeof(sw);
|
||||||
|
sw.conn_id = conn_id;
|
||||||
|
sw.path_length = path_len;
|
||||||
|
sw.token_length = token_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
head.length += path_len + token_len;
|
||||||
head.length = ROUNDUP(head.length, 3);
|
head.length = ROUNDUP(head.length, 3);
|
||||||
if (fwrite(&head, sizeof(head), 1, fp) != 1)
|
if (fwrite(&head, sizeof(head), 1, fp) != 1)
|
||||||
return "Dump watch state error";
|
return "Dump watch state error";
|
||||||
if (fwrite(&sw, sizeof(sw), 1, fp) != 1)
|
|
||||||
return "Dump watch state error";
|
|
||||||
|
|
||||||
if (fwrite(path, sw.path_length, 1, fp) != 1)
|
if (watch->depth >= 0) {
|
||||||
|
if (fwrite(&swe, sizeof(sw), 1, fp) != 1)
|
||||||
|
return "Dump watch state ext error";
|
||||||
|
} else {
|
||||||
|
if (fwrite(&sw, sizeof(sw), 1, fp) != 1)
|
||||||
|
return "Dump watch state error";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fwrite(path, path_len, 1, fp) != 1)
|
||||||
return "Dump watch path error";
|
return "Dump watch path error";
|
||||||
if (fwrite(watch->token, sw.token_length, 1, fp) != 1)
|
if (fwrite(watch->token, token_len, 1, fp) != 1)
|
||||||
return "Dump watch token error";
|
return "Dump watch token error";
|
||||||
|
|
||||||
ret = dump_state_align(fp);
|
ret = dump_state_align(fp);
|
||||||
@@ -319,27 +349,41 @@ const char *dump_state_watches(FILE *fp, struct connection *conn,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = state;
|
|
||||||
struct connection *conn;
|
struct connection *conn;
|
||||||
const char *path, *token;
|
|
||||||
bool relative;
|
bool relative;
|
||||||
|
|
||||||
conn = get_connection_by_id(sw->conn_id);
|
conn = get_connection_by_id(conn_id);
|
||||||
if (!conn)
|
if (!conn)
|
||||||
barf("connection not found for read watch");
|
barf("connection not found for read watch");
|
||||||
|
|
||||||
path = (char *)sw->data;
|
|
||||||
token = path + sw->path_length;
|
|
||||||
|
|
||||||
/* Don't check success, we want the relative information only. */
|
/* Don't check success, we want the relative information only. */
|
||||||
check_watch_path(conn, ctx, &path, &relative);
|
check_watch_path(conn, ctx, &path, &relative);
|
||||||
if (!path)
|
if (!path)
|
||||||
barf("allocation error for read watch");
|
barf("allocation error for read watch");
|
||||||
|
|
||||||
if (!add_watch(conn, path, token, relative, true))
|
if (!add_watch(conn, path, token, depth, relative, true))
|
||||||
barf("error adding watch");
|
barf("error adding watch");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_state_watch(const void *ctx, const void *state)
|
||||||
|
{
|
||||||
|
const struct xs_state_watch *sw = 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 = state;
|
||||||
|
|
||||||
|
process_state_watch(ctx, swe->conn_id, (char *)swe->data,
|
||||||
|
(char *)swe->data + swe->path_length, swe->depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -37,5 +37,6 @@ const char *dump_state_watches(FILE *fp, struct connection *conn,
|
|||||||
unsigned int conn_id);
|
unsigned int conn_id);
|
||||||
|
|
||||||
void read_state_watch(const void *ctx, const void *state);
|
void read_state_watch(const void *ctx, const void *state);
|
||||||
|
void read_state_watch_ext(const void *ctx, const void *state);
|
||||||
|
|
||||||
#endif /* _XENSTORED_WATCH_H */
|
#endif /* _XENSTORED_WATCH_H */
|
||||||