properly drop references of endpoint and activator connection
authorKay Sievers <kay@vrfy.org>
Sat, 18 Jan 2014 14:12:41 +0000 (15:12 +0100)
committerKay Sievers <kay@vrfy.org>
Sat, 18 Jan 2014 14:12:41 +0000 (15:12 +0100)
connection.c
connection.h
handle.c
names.c

index af7c697ba79f3968fa339953a7f4ec5f9bca7dc5..a3229da087138d1aae4008caa74336a9e3912d2b 100644 (file)
@@ -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);
index 1bb6bb731721660d4b6ebaf824f6050ed43ff2d1..f55b3b57ba8ae8875c85668105964cd4aa3b462f 100644 (file)
@@ -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);
index 599fdc6fde7df00a552d24fce300452435035fba..351136b8a0096a0e2745ef6dd0b85a556f4d8d56 100644 (file)
--- 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 7feabd591cb56825424555ef124851f0e4053a50..f8050980536d4c7906a2984e9543d84f7c6bc389 100644 (file)
--- 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;
 }