From dcbeca51a8838f2bfa68774e2c3185c185ac8401 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 18 Jan 2014 15:12:41 +0100 Subject: [PATCH] properly drop references of endpoint and activator connection --- connection.c | 23 +++++++++++--- connection.h | 1 + handle.c | 8 ++--- names.c | 90 +++++++++++++++++++++++++++------------------------- 4 files changed, 69 insertions(+), 53 deletions(-) diff --git a/connection.c b/connection.c index af7c697..a3229da 100644 --- a/connection.c +++ b/connection.c @@ -689,7 +689,6 @@ static int kdbus_conn_get_conn_dst(struct kdbus_bus *bus, { const struct kdbus_msg *msg = &kmsg->msg; struct kdbus_conn *c; - bool disconnected; int ret = 0; if (msg->dst_id == KDBUS_DST_ID_NAME) { @@ -737,10 +736,7 @@ static int kdbus_conn_get_conn_dst(struct kdbus_bus *bus, } } - mutex_lock(&c->lock); - disconnected = c->disconnected; - mutex_unlock(&c->lock); - if (disconnected) { + if (!kdbus_conn_active(c)) { ret = -ECONNRESET; goto exit_unref; } @@ -1334,6 +1330,23 @@ int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_msg_list_empty) return 0; } +/** + * kdbus_conn_active() - connection is not disconnected + * @conn: Connection to check + * + * Returns: true if the connection is still active + */ +bool kdbus_conn_active(struct kdbus_conn *conn) +{ + bool active; + + mutex_lock(&conn->lock); + active = !conn->disconnected; + mutex_unlock(&conn->lock); + + return active; +} + static void __kdbus_conn_free(struct kref *kref) { struct kdbus_conn *conn = container_of(kref, struct kdbus_conn, kref); diff --git a/connection.h b/connection.h index 1bb6bb7..f55b3b5 100644 --- a/connection.h +++ b/connection.h @@ -89,6 +89,7 @@ int kdbus_conn_new(struct kdbus_ep *ep, struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn); struct kdbus_conn *kdbus_conn_unref(struct kdbus_conn *conn); int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_msg_list_empty); +bool kdbus_conn_active(struct kdbus_conn *conn); int kdbus_conn_recv_msg_user(struct kdbus_conn *conn, struct kdbus_cmd_recv __user *recv); diff --git a/handle.c b/handle.c index 599fdc6..351136b 100644 --- a/handle.c +++ b/handle.c @@ -174,13 +174,13 @@ static int kdbus_handle_release(struct inode *inode, struct file *file) kdbus_ep_unref(handle->ep_owner); break; - case KDBUS_HANDLE_EP: - kdbus_ep_unref(handle->ep); - break; - case KDBUS_HANDLE_EP_CONNECTED: kdbus_conn_disconnect(handle->conn, false); kdbus_conn_unref(handle->conn); + /* fall through */ + + case KDBUS_HANDLE_EP: + kdbus_ep_unref(handle->ep); break; default: diff --git a/names.c b/names.c index 7feabd5..f805098 100644 --- a/names.c +++ b/names.c @@ -144,59 +144,61 @@ static void kdbus_name_entry_set_owner(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 (list_empty(&e->queue_list)) { - /* 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; + /* give it to first waiter in the queue */ + if (!list_empty(&e->queue_list)) { + struct kdbus_name_queue_item *q; + + q = list_first_entry(&e->queue_list, + struct kdbus_name_queue_item, + entry_entry); + kdbus_notify_name_change(KDBUS_ITEM_NAME_CHANGE, + e->conn->id, q->conn->id, + e->flags, q->flags, e->name, notify_list); + e->flags = q->flags; + kdbus_name_entry_remove_owner(e); + kdbus_name_entry_set_owner(e, q->conn); + kdbus_name_queue_item_free(q); - e->flags = flags; - kdbus_name_entry_remove_owner(e); - kdbus_name_entry_set_owner(e, e->activator); + return 0; + } - return 0; - } + /* hand it back to the active activator connection */ + if (e->activator && e->activator != e->conn && + kdbus_conn_active(e->activator)) { + 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; - /* release the name */ - kdbus_notify_name_change(KDBUS_ITEM_NAME_REMOVE, - e->conn->id, 0, - e->flags, 0, e->name, - notify_list); + e->flags = flags; kdbus_name_entry_remove_owner(e); - kdbus_name_entry_free(e); + kdbus_name_entry_set_owner(e, e->activator); return 0; } - /* give it to first waiter in the queue */ - q = list_first_entry(&e->queue_list, - struct kdbus_name_queue_item, - entry_entry); - kdbus_notify_name_change(KDBUS_ITEM_NAME_CHANGE, - e->conn->id, q->conn->id, - e->flags, q->flags, e->name, notify_list); - e->flags = q->flags; + /* release the name */ + kdbus_notify_name_change(KDBUS_ITEM_NAME_REMOVE, + e->conn->id, 0, + e->flags, 0, e->name, + notify_list); kdbus_name_entry_remove_owner(e); - kdbus_name_entry_set_owner(e, q->conn); - kdbus_name_queue_item_free(q); + kdbus_conn_unref(e->activator); + kdbus_name_entry_free(e); return 0; } -- 2.34.1