connection: move messages addressed to a name back to the activator
authorKay Sievers <kay@vrfy.org>
Tue, 24 Dec 2013 04:59:42 +0000 (05:59 +0100)
committerKay Sievers <kay@vrfy.org>
Tue, 24 Dec 2013 05:03:38 +0000 (06:03 +0100)
TODO
connection.c
connection.h
message.h
names.c
names.h

diff --git a/TODO b/TODO
index eb9d9d13e9797f29ec26dc05d66e01aa6994de4c..d6d19f19f2654341c77f33db95c59eac9cf18c19 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,6 +1,4 @@
 Features:
-  - move queued messages addressed to a name back to the
-    name's activator if the current owner goes away
   - allow to update the metadata subscription bit mask
   - support the creation of anonymous buses
 
index 0a9410b82ee6d87c031ea30179f82514289056b5..639fd0f513527807217c0116d9a06aaff1883064 100644 (file)
@@ -53,6 +53,8 @@
  * @deadline_ns:       Timeout for this message, used for replies
  * @src_id:            The ID of the sender
  * @cookie:            Message cookie, used for replies
+ * @src_name_id:       The sequence number of the name this message is
+ *                     addressed to, 0 for messages sent to an ID
  */
 struct kdbus_conn_queue {
        struct list_head entry;
@@ -70,6 +72,7 @@ struct kdbus_conn_queue {
        u64 deadline_ns;
        u64 src_id;
        u64 cookie;
+       u64 dst_name_id;
 };
 
 /**
@@ -364,6 +367,7 @@ static int kdbus_conn_queue_insert(struct kdbus_conn *conn,
        if (kmsg->dst_name) {
                dst_name_len = strlen(kmsg->dst_name) + 1;
                msg_size += KDBUS_ITEM_SIZE(dst_name_len);
+               queue->dst_name_id = kmsg->dst_name_id;
        }
 
        /* space for PAYLOAD items */
@@ -577,7 +581,7 @@ static void kdbus_conn_timer_func(unsigned long val)
 
 /* find and pin destination connection */
 static int kdbus_conn_get_conn_dst(struct kdbus_bus *bus,
-                                  const struct kdbus_kmsg *kmsg,
+                                  struct kdbus_kmsg *kmsg,
                                   struct kdbus_conn **conn)
 {
        const struct kdbus_msg *msg = &kmsg->msg;
@@ -594,6 +598,14 @@ static int kdbus_conn_get_conn_dst(struct kdbus_bus *bus,
                if (!name_entry)
                        return -ESRCH;
 
+               /*
+                * Record the sequence number of the registered name;
+                * it will be passed on to the queue, in case messages
+                * addressed to a name need to be moved from or to
+                * activator connections of the same name.
+                */
+               kmsg->dst_name_id = name_entry->name_id;
+
                if (!name_entry->conn && name_entry->activator)
                        c = kdbus_conn_ref(name_entry->activator);
                else
@@ -625,7 +637,6 @@ static int kdbus_conn_get_conn_dst(struct kdbus_bus *bus,
        mutex_lock(&c->lock);
        disconnected = c->disconnected;
        mutex_unlock(&c->lock);
-
        if (disconnected) {
                ret = -ECONNRESET;
                goto exit_unref;
@@ -1229,6 +1240,8 @@ struct kdbus_conn *kdbus_conn_unref(struct kdbus_conn *conn)
  * kdbus_conn_move_messages() - move a message from one connection to another
  * @conn_dst:          Connection to copy to
  * @conn_src:          Connection to copy from
+ * @name_id:           Filter for the sequence number of the registered
+ *                     name, 0 means no filtering.
  *
  * Move all messages from one connection to another. This is used when
  * an ordinary connection is taking over a well-known name from a
@@ -1237,9 +1250,10 @@ struct kdbus_conn *kdbus_conn_unref(struct kdbus_conn *conn)
  * Returns: 0 on success, negative errno on failure.
  */
 int kdbus_conn_move_messages(struct kdbus_conn *conn_dst,
-                            struct kdbus_conn *conn_src)
+                            struct kdbus_conn *conn_src,
+                            u64 name_id)
 {
-       struct kdbus_conn_queue *queue, *tmp;
+       struct kdbus_conn_queue *q, *tmp;
        LIST_HEAD(msg_list);
        int ret = 0;
 
@@ -1255,13 +1269,18 @@ int kdbus_conn_move_messages(struct kdbus_conn *conn_dst,
        mutex_unlock(&conn_src->lock);
 
        mutex_lock(&conn_dst->lock);
-       list_for_each_entry_safe(queue, tmp, &msg_list, entry) {
+       list_for_each_entry_safe(q, tmp, &msg_list, entry) {
+
+               /* filter messages for a specific name */
+               if (name_id > 0 && q->dst_name_id != name_id)
+                       continue;
+
                ret = kdbus_pool_move(conn_dst->pool, conn_src->pool,
-                                     &queue->off, queue->size);
+                                     &q->off, q->size);
                if (ret < 0)
                        goto exit_unlock_dst;
 
-               list_add_tail(&queue->entry, &conn_dst->msg_list);
+               list_add_tail(&q->entry, &conn_dst->msg_list);
                conn_dst->msg_count++;
        }
 
index 37b4220e2bec230f5640fec012f507eeb8ab54d8..043dbcafcf1609fad12396593a439e5ad00f7b4f 100644 (file)
@@ -91,6 +91,7 @@ void kdbus_conn_kmsg_list_free(struct list_head *kmsg_list);
 int kdbus_conn_kmsg_list_send(struct kdbus_ep *ep,
                              struct list_head *kmsg_list);
 int kdbus_conn_move_messages(struct kdbus_conn *conn_dst,
-                            struct kdbus_conn *conn_src);
+                            struct kdbus_conn *conn_src,
+                            u64 name_id);
 bool kdbus_conn_has_name(struct kdbus_conn *conn, const char *name);
 #endif
index 3a9e3751cba50432f65d3bac5867e8859af133d6..1180d38c1ac2187b0db276a879f68e339e7303be 100644 (file)
--- a/message.h
+++ b/message.h
@@ -22,6 +22,7 @@
  * @notify_id:         Short-cut for faster lookup
  * @notify_name:       Short-cut for faster lookup
  * @dst_name:          Short-cut to msg for faster lookup
+ * @dst_name_id:       Short-cut to msg for faster lookup
  * @bloom:             Short-cut to msg for faster lookup
  * @bloom_size:                Short-cut to msg for faster lookup
  * @fds:               Array of file descriptors to pass
@@ -40,6 +41,7 @@ struct kdbus_kmsg {
        const char *notify_name;
 
        const char *dst_name;
+       u64 dst_name_id;
        const u64 *bloom;
        unsigned int bloom_size;
        const int *fds;
diff --git a/names.c b/names.c
index e9d90f6c0f41985151e361bf1597d4df03ad54b1..f5d226b05bb68a571d380d496f423cebf3081d5e 100644 (file)
--- a/names.c
+++ b/names.c
@@ -88,6 +88,7 @@ int kdbus_name_registry_new(struct kdbus_name_registry **reg)
 
        hash_init(r->entries_hash);
        mutex_init(&r->entries_lock);
+       r->name_id_next = 1;
 
        *reg = r;
 
@@ -141,7 +142,7 @@ static void kdbus_name_entry_set_owner(struct kdbus_name_entry *e,
        mutex_unlock(&conn->lock);
 }
 
-static void kdbus_name_entry_release(struct kdbus_name_entry *e,
+static int kdbus_name_entry_release(struct kdbus_name_entry *e,
                                     struct list_head *notify_list)
 {
        struct kdbus_name_queue_item *q;
@@ -150,15 +151,29 @@ static void kdbus_name_entry_release(struct kdbus_name_entry *e,
                /* if the name has an activator connection, hand it back */
                if (e->activator && e->activator != e->conn) {
                        u64 flags = KDBUS_NAME_ACTIVATOR;
+                       int ret;
 
                        kdbus_notify_name_change(KDBUS_ITEM_NAME_CHANGE,
                                                 e->conn->id, e->activator->id,
                                                 e->flags, flags,
                                                 e->name, notify_list);
+
+                       /*
+                        * Move messages still queued in the old connection
+                        * and addressed to that name to the new connection.
+                        * This allows a race and loss-free name and message
+                        * takeover and exit-on-idle services.
+                        */
+                       ret = kdbus_conn_move_messages(e->activator, e->conn,
+                                                      e->name_id);
+                       if (ret < 0)
+                               return ret;
+
                        e->flags = flags;
                        kdbus_name_entry_remove_owner(e);
                        kdbus_name_entry_set_owner(e, e->activator);
-                       return;
+
+                       return 0;
                }
 
                /* release the name */
@@ -168,7 +183,8 @@ static void kdbus_name_entry_release(struct kdbus_name_entry *e,
                                         notify_list);
                kdbus_name_entry_remove_owner(e);
                kdbus_name_entry_free(e);
-               return;
+
+               return 0;
        }
 
        /* give it to first waiter in the queue */
@@ -182,6 +198,8 @@ static void kdbus_name_entry_release(struct kdbus_name_entry *e,
        kdbus_name_entry_remove_owner(e);
        kdbus_name_entry_set_owner(e, q->conn);
        kdbus_name_queue_item_free(q);
+
+       return 0;
 }
 
 static int kdbus_name_release(struct kdbus_name_entry *e,
@@ -395,8 +413,11 @@ int kdbus_name_acquire(struct kdbus_name_registry *reg,
                /* take over the name of an activator connection */
                if (e->flags & KDBUS_NAME_ACTIVATOR) {
 
-                       /* take over already queued messages from the activator connection */
-                       ret = kdbus_conn_move_messages(conn, e->activator);
+                       /*
+                        * Take over the messages queued in the activator
+                        * connection, the activator itself never reads them.
+                        */
+                       ret = kdbus_conn_move_messages(conn, e->activator, 0);
                        if (ret < 0)
                                goto exit_unlock;
 
@@ -458,6 +479,7 @@ int kdbus_name_acquire(struct kdbus_name_registry *reg,
 
        e->flags = *flags;
        INIT_LIST_HEAD(&e->queue_list);
+       e->name_id = reg->name_id_next++;
        hash_add(reg->entries_hash, &e->hentry, hash);
        kdbus_name_entry_set_owner(e, conn);
 
diff --git a/names.h b/names.h
index 98a81042841fbc168b45271c8c3c7d36f8b4c91d..460d09bf2989627b469a2e5cca7da2cd73e68452 100644 (file)
--- a/names.h
+++ b/names.h
  * struct kdbus_name_registry - names registered for a bus
  * @entries_hash:      Map of entries
  * @entries_lock:      Registry data lock
+ * @name_id_next:      Next sequence number to assign to a name entry
  */
 struct kdbus_name_registry {
        DECLARE_HASHTABLE(entries_hash, 6);
        struct mutex            entries_lock;
+       u64 name_id_next;
 };
 
 /**
  * struct kdbus_name_entry - well-know name entry
  * @name:              The well-known name
+ * @name_id:           Sequence number of name entry to be able to uniquely
+ *                     identify a name over its registration lifetime
  * @flags:             KDBUS_NAME_* flags
  * @queue_list:                List of queued waiters for the well-known name
  * @conn_entry:                Entry in connection
@@ -37,6 +41,7 @@ struct kdbus_name_registry {
  */
 struct kdbus_name_entry {
        char                    *name;
+       u64                     name_id;
        u64                     flags;
        struct list_head        queue_list;
        struct list_head        conn_entry;