xenstore: use temporary memory context for firing watches
authorJuergen Gross <jgross@suse.com>
Tue, 19 Jul 2016 11:30:46 +0000 (13:30 +0200)
committerWei Liu <wei.liu2@citrix.com>
Tue, 19 Jul 2016 11:56:59 +0000 (12:56 +0100)
Use a temporary memory context for memory allocations when firing
watches. This will avoid leaking memory in case of long living
connections and/or xenstore entries.

This requires adding a new parameter to fire_watches() and add_event()
to specify the memory context to use for allocations.

Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Wei Liu <wei.liu2@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
tools/xenstore/xenstored_core.c
tools/xenstore/xenstored_domain.c
tools/xenstore/xenstored_transaction.c
tools/xenstore/xenstored_watch.c
tools/xenstore/xenstored_watch.h

index 7575dd94d5cf44792055031f86e1cbf52787f6ae..758a649491b3e8f67c7ee1c87518203c5bba3206 100644 (file)
@@ -971,7 +971,7 @@ static void do_write(struct connection *conn, struct buffered_data *in)
        }
 
        add_change_node(conn->transaction, name, false);
-       fire_watches(conn, name, false);
+       fire_watches(conn, in, name, false);
        send_ack(conn, XS_WRITE);
 }
 
@@ -996,7 +996,7 @@ static void do_mkdir(struct connection *conn, struct buffered_data *in)
                        return;
                }
                add_change_node(conn->transaction, name, false);
-               fire_watches(conn, name, false);
+               fire_watches(conn, in, name, false);
        }
        send_ack(conn, XS_MKDIR);
 }
@@ -1122,7 +1122,7 @@ static void do_rm(struct connection *conn, struct buffered_data *in)
 
        if (_rm(conn, node, name)) {
                add_change_node(conn->transaction, name, true);
-               fire_watches(conn, name, true);
+               fire_watches(conn, in, name, true);
                send_ack(conn, XS_RM);
        }
 }
@@ -1198,7 +1198,7 @@ static void do_set_perms(struct connection *conn, struct buffered_data *in)
        }
 
        add_change_node(conn->transaction, name, false);
-       fire_watches(conn, name, false);
+       fire_watches(conn, in, name, false);
        send_ack(conn, XS_SET_PERMS);
 }
 
index c66539a6efea087995072ef6f6eef940fdb0bd07..5de93d467f3801de29e7aebfe2866fbe777fc97c 100644 (file)
@@ -204,7 +204,7 @@ static int destroy_domain(void *_domain)
                        unmap_interface(domain->interface);
        }
 
-       fire_watches(NULL, "@releaseDomain", false);
+       fire_watches(NULL, domain, "@releaseDomain", false);
 
        return 0;
 }
@@ -232,7 +232,7 @@ static void domain_cleanup(void)
        }
 
        if (notify)
-               fire_watches(NULL, "@releaseDomain", false);
+               fire_watches(NULL, NULL, "@releaseDomain", false);
 }
 
 /* We scan all domains rather than use the information given here. */
@@ -389,7 +389,7 @@ void do_introduce(struct connection *conn, struct buffered_data *in)
                /* Now domain belongs to its connection. */
                talloc_steal(domain->conn, domain);
 
-               fire_watches(NULL, "@introduceDomain", false);
+               fire_watches(NULL, in, "@introduceDomain", false);
        } else if ((domain->mfn == mfn) && (domain->conn != conn)) {
                /* Use XS_INTRODUCE for recreating the xenbus event-channel. */
                if (domain->port)
index 3cde26e532426f139f711e3633254b0cfcfcc8f0..34720fa6d4305732d305f3f9e7b801d1bc842751 100644 (file)
@@ -227,7 +227,7 @@ void do_transaction_end(struct connection *conn, struct buffered_data *in)
 
                /* Fire off the watches for everything that changed. */
                list_for_each_entry(i, &trans->changes, list)
-                       fire_watches(conn, i->node, i->recurse);
+                       fire_watches(conn, in, i->node, i->recurse);
                generation++;
        }
        send_ack(conn, XS_TRANSACTION_END);
index beefd6cbe33b8c73101f11a3c55c0e626475edc0..856750ebcd9bb1766f5b41c8e944418a477633c8 100644 (file)
@@ -47,7 +47,12 @@ struct watch
        char *node;
 };
 
+/*
+ * Send a watch event.
+ * Temporary memory allocations are done with ctx.
+ */
 static void add_event(struct connection *conn,
+                     void *ctx,
                      struct watch *watch,
                      const char *name)
 {
@@ -57,7 +62,7 @@ static void add_event(struct connection *conn,
 
        if (!check_event_node(name)) {
                /* Can this conn load node, or see that it doesn't exist? */
-               struct node *node = get_node(conn, name, name, XS_PERM_READ);
+               struct node *node = get_node(conn, ctx, name, XS_PERM_READ);
                /*
                 * XXX We allow EACCES here because otherwise a non-dom0
                 * backend driver cannot watch for disappearance of a frontend
@@ -78,14 +83,19 @@ static void add_event(struct connection *conn,
        }
 
        len = strlen(name) + 1 + strlen(watch->token) + 1;
-       data = talloc_array(watch, char, len);
+       data = talloc_array(ctx, char, len);
        strcpy(data, name);
        strcpy(data + strlen(name) + 1, watch->token);
        send_reply(conn, XS_WATCH_EVENT, data, len);
        talloc_free(data);
 }
 
-void fire_watches(struct connection *conn, const char *name, bool recurse)
+/*
+ * Check whether any watch events are to be sent.
+ * Temporary memory allocations are done with ctx.
+ */
+void fire_watches(struct connection *conn, void *ctx, const char *name,
+                 bool recurse)
 {
        struct connection *i;
        struct watch *watch;
@@ -98,9 +108,9 @@ void fire_watches(struct connection *conn, const char *name, bool recurse)
        list_for_each_entry(i, &connections, list) {
                list_for_each_entry(watch, &i->watches, list) {
                        if (is_child(name, watch->node))
-                               add_event(i, watch, name);
+                               add_event(i, ctx, watch, name);
                        else if (recurse && is_child(watch->node, name))
-                               add_event(i, watch, watch->node);
+                               add_event(i, ctx, watch, watch->node);
                }
        }
 }
@@ -169,7 +179,7 @@ void do_watch(struct connection *conn, struct buffered_data *in)
        send_ack(conn, XS_WATCH);
 
        /* We fire once up front: simplifies clients and restart. */
-       add_event(conn, watch, watch->node);
+       add_event(conn, in, watch, watch->node);
 }
 
 void do_unwatch(struct connection *conn, struct buffered_data *in)
index 5bc4f8847ea836395179065cef8b494d89a90b75..8ed1ddef612e52168f9f45c9228e9453c9ec0cec 100644 (file)
@@ -25,7 +25,8 @@ void do_watch(struct connection *conn, struct buffered_data *in);
 void do_unwatch(struct connection *conn, struct buffered_data *in);
 
 /* Fire all watches: recurse means all the children are affected (ie. rm). */
-void fire_watches(struct connection *conn, const char *name, bool recurse);
+void fire_watches(struct connection *conn, void *tmp, const char *name,
+                 bool recurse);
 
 void dump_watches(struct connection *conn);