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
* @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;
u64 deadline_ns;
u64 src_id;
u64 cookie;
+ u64 dst_name_id;
};
/**
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 */
/* 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;
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
mutex_lock(&c->lock);
disconnected = c->disconnected;
mutex_unlock(&c->lock);
-
if (disconnected) {
ret = -ECONNRESET;
goto exit_unref;
* 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
* 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;
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++;
}
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
* @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
const char *notify_name;
const char *dst_name;
+ u64 dst_name_id;
const u64 *bloom;
unsigned int bloom_size;
const int *fds;
hash_init(r->entries_hash);
mutex_init(&r->entries_lock);
+ r->name_id_next = 1;
*reg = r;
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;
/* 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 */
notify_list);
kdbus_name_entry_remove_owner(e);
kdbus_name_entry_free(e);
- return;
+
+ return 0;
}
/* give it to first waiter in the queue */
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,
/* 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;
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);
* 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
*/
struct kdbus_name_entry {
char *name;
+ u64 name_id;
u64 flags;
struct list_head queue_list;
struct list_head conn_entry;