Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

release parent lock when disconnecting children objects

  • Loading branch information...
commit 2d172b8677abd9de67a5d4e17b810cd08279fbf2 1 parent 9511a29
@kaysievers kaysievers authored zonque committed
View
64 bus.c
@@ -58,7 +58,7 @@ static void __kdbus_bus_free(struct kref *kref)
{
struct kdbus_bus *bus = container_of(kref, struct kdbus_bus, kref);
- kdbus_bus_disconnect(bus, false);
+ kdbus_bus_disconnect(bus);
atomic_dec(&bus->user->buses);
kdbus_domain_user_unref(bus->user);
kdbus_name_registry_free(bus->name_registry);
@@ -112,46 +112,70 @@ struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id)
/**
* kdbus_bus_disconnect() - disconnect a bus
* @bus: The kdbus reference
- * @parent: The domain disconnects this bus
*
* The passed bus will be disconnected and the associated endpoint will be
* unref'ed.
*/
-void kdbus_bus_disconnect(struct kdbus_bus *bus, bool parent)
+void kdbus_bus_disconnect(struct kdbus_bus *bus)
{
- struct kdbus_ep *ep, *tmp;
- struct hlist_node *conn_tmp;
- struct kdbus_conn *conn;
- unsigned int i;
-
mutex_lock(&bus->lock);
if (bus->disconnected) {
mutex_unlock(&bus->lock);
return;
}
-
bus->disconnected = true;
mutex_unlock(&bus->lock);
/* disconnect from domain */
- if (!parent)
- mutex_lock(&bus->domain->lock);
+ mutex_lock(&bus->domain->lock);
list_del(&bus->domain_entry);
- if (!parent)
- mutex_unlock(&bus->domain->lock);
+ mutex_unlock(&bus->domain->lock);
/* disconnect all endpoints attached to this bus */
- mutex_lock(&bus->lock);
- list_for_each_entry_safe(ep, tmp, &bus->ep_list, bus_entry)
- kdbus_ep_disconnect(ep, true);
+ for (;;) {
+ struct kdbus_ep *ep;
+
+ mutex_lock(&bus->lock);
+ ep = list_first_entry_or_null(&bus->ep_list,
+ struct kdbus_ep,
+ bus_entry);
+ if (!ep) {
+ mutex_unlock(&bus->lock);
+ break;
+ }
+
+ kdbus_ep_ref(ep);
+ mutex_unlock(&bus->lock);
+
+ kdbus_ep_disconnect(ep);
+ kdbus_ep_unref(ep);
+ }
+
/* disconnect all connections to this bus */
- hash_for_each_safe(bus->conn_hash, i, conn_tmp, conn, hentry)
- kdbus_conn_disconnect(conn, true, false);
- mutex_unlock(&bus->lock);
+ for (;;) {
+ struct kdbus_conn *conn = NULL, *c;
+ unsigned int i;
+
+ mutex_lock(&bus->lock);
+ hash_for_each(bus->conn_hash, i, c, hentry) {
+ conn = c;
+ break;
+ }
+ if (!conn) {
+ mutex_unlock(&bus->lock);
+ break;
+ }
+
+ kdbus_conn_ref(conn);
+ mutex_unlock(&bus->lock);
+
+ kdbus_conn_disconnect(conn, false);
+ kdbus_conn_unref(conn);
+ }
/* drop reference for our "bus" endpoint after we disconnected */
- kdbus_ep_unref(bus->ep);
+ bus->ep = kdbus_ep_unref(bus->ep);
}
static struct kdbus_bus *kdbus_bus_find(struct kdbus_domain *domain, const char *name)
View
2  bus.h
@@ -79,7 +79,7 @@ int kdbus_bus_new(struct kdbus_domain *domain,
struct kdbus_bus **bus);
struct kdbus_bus *kdbus_bus_ref(struct kdbus_bus *bus);
struct kdbus_bus *kdbus_bus_unref(struct kdbus_bus *bus);
-void kdbus_bus_disconnect(struct kdbus_bus *bus, bool parent);
+void kdbus_bus_disconnect(struct kdbus_bus *bus);
bool kdbus_bus_uid_is_privileged(const struct kdbus_bus *bus);
struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id);
View
29 connection.c
@@ -1068,6 +1068,13 @@ int kdbus_conn_kmsg_send(struct kdbus_ep *ep,
bool sync;
int ret;
+ mutex_lock(&ep->bus->lock);
+ if (unlikely(ep->bus->disconnected)) {
+ mutex_unlock(&ep->bus->lock);
+ return -ESHUTDOWN;
+ }
+ mutex_unlock(&ep->bus->lock);
+
sync = msg->flags & KDBUS_MSG_FLAGS_SYNC_REPLY;
/* assign domain-global message sequence number */
@@ -1346,7 +1353,6 @@ int kdbus_conn_kmsg_list_send(struct kdbus_ep *ep,
/**
* kdbus_conn_disconnect() - disconnect a connection
- * @parent: The bus terminates the connection
* @conn: The connection to disconnect
* @ensure_queue_empty: Flag to indicate if the call should fail in
* case the connection's message list is not
@@ -1357,8 +1363,7 @@ int kdbus_conn_kmsg_list_send(struct kdbus_ep *ep,
*
* Return: 0 on success, negative errno on failure
*/
-int kdbus_conn_disconnect(struct kdbus_conn *conn, bool parent,
- bool ensure_queue_empty)
+int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_queue_empty)
{
struct kdbus_conn_reply *reply, *reply_tmp;
struct kdbus_conn_queue *queue, *tmp;
@@ -1382,12 +1387,10 @@ int kdbus_conn_disconnect(struct kdbus_conn *conn, bool parent,
cancel_delayed_work_sync(&conn->work);
/* remove from bus */
- if (!parent)
- mutex_lock(&conn->bus->lock);
+ mutex_lock(&conn->bus->lock);
hash_del(&conn->hentry);
list_del(&conn->monitor_entry);
- if (!parent)
- mutex_unlock(&conn->bus->lock);
+ mutex_unlock(&conn->bus->lock);
/* if we die while other connections wait for our reply, notify them */
mutex_lock(&conn->lock);
@@ -1419,16 +1422,6 @@ int kdbus_conn_disconnect(struct kdbus_conn *conn, bool parent,
kdbus_conn_reply_finish(reply, -EPIPE);
}
- /*
- * The bus disconnects us; there is no point in cleaning up bus
- * properties or sending notifications to other peers which also
- * got disconnected at this moment.
- */
- if (parent) {
- kdbus_conn_kmsg_list_free(&notify_list);
- return 0;
- }
-
/* remove all names associated with this connection */
kdbus_name_remove_by_conn(conn->bus->name_registry, conn);
@@ -1460,7 +1453,7 @@ static void __kdbus_conn_free(struct kref *kref)
{
struct kdbus_conn *conn = container_of(kref, struct kdbus_conn, kref);
- kdbus_conn_disconnect(conn, false, false);
+ kdbus_conn_disconnect(conn, false);
atomic_dec(&conn->user->connections);
kdbus_domain_user_unref(conn->user);
View
3  connection.h
@@ -90,8 +90,7 @@ int kdbus_conn_new(struct kdbus_ep *ep,
struct kdbus_conn **conn);
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 parent,
- bool ensure_queue_empty);
+int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_queue_empty);
bool kdbus_conn_active(struct kdbus_conn *conn);
int kdbus_cmd_msg_recv(struct kdbus_conn *conn,
View
59 domain.c
@@ -81,27 +81,22 @@ struct kdbus_domain *kdbus_domain_ref(struct kdbus_domain *domain)
/**
* kdbus_domain_disconnect() - invalidate a domain
* @domain: Domain
- * @parent: The parent disconnects this domain
*/
-void kdbus_domain_disconnect(struct kdbus_domain *domain, bool parent)
+void kdbus_domain_disconnect(struct kdbus_domain *domain)
{
- struct kdbus_domain *dom, *dom_tmp;
- struct kdbus_bus *bus, *bus_tmp;
-
- mutex_lock_nested(&domain->lock, domain->nest);
+ mutex_lock(&domain->lock);
if (domain->disconnected) {
mutex_unlock(&domain->lock);
return;
}
domain->disconnected = true;
+ mutex_unlock(&domain->lock);
/* disconnect from parent domain */
if (domain->parent) {
- if (!parent)
- mutex_lock(&domain->parent->lock);
+ mutex_lock(&domain->parent->lock);
list_del(&domain->domain_entry);
- if (!parent)
- mutex_unlock(&domain->parent->lock);
+ mutex_unlock(&domain->parent->lock);
}
mutex_lock(&kdbus_subsys_lock);
@@ -118,14 +113,44 @@ void kdbus_domain_disconnect(struct kdbus_domain *domain, bool parent)
mutex_unlock(&kdbus_subsys_lock);
/* disconnect all sub-domains */
- list_for_each_entry_safe(dom, dom_tmp, &domain->domain_list, domain_entry)
- kdbus_domain_disconnect(dom, true);
+ for (;;) {
+ struct kdbus_domain *dom;
+
+ mutex_lock(&domain->lock);
+ dom = list_first_entry_or_null(&domain->domain_list,
+ struct kdbus_domain,
+ domain_entry);
+ if (!dom) {
+ mutex_unlock(&domain->lock);
+ break;
+ }
+
+ kdbus_domain_ref(dom);
+ mutex_unlock(&domain->lock);
+
+ kdbus_domain_disconnect(dom);
+ kdbus_domain_unref(dom);
+ }
/* disconnect all buses in this domain */
- list_for_each_entry_safe(bus, bus_tmp, &domain->bus_list, domain_entry)
- kdbus_bus_disconnect(bus, true);
+ for (;;) {
+ struct kdbus_bus *bus;
+
+ mutex_lock(&domain->lock);
+ bus = list_first_entry_or_null(&domain->bus_list,
+ struct kdbus_bus,
+ domain_entry);
+ if (!bus) {
+ mutex_unlock(&domain->lock);
+ break;
+ }
- mutex_unlock(&domain->lock);
+ kdbus_bus_ref(bus);
+ mutex_unlock(&domain->lock);
+
+ kdbus_bus_disconnect(bus);
+ kdbus_bus_unref(bus);
+ }
}
static void __kdbus_domain_free(struct kref *kref)
@@ -133,7 +158,7 @@ static void __kdbus_domain_free(struct kref *kref)
struct kdbus_domain *domain =
container_of(kref, struct kdbus_domain, kref);
- kdbus_domain_disconnect(domain, false);
+ kdbus_domain_disconnect(domain);
kdbus_domain_unref(domain->parent);
kfree(domain->name);
kfree(domain->devpath);
@@ -264,8 +289,6 @@ int kdbus_domain_new(struct kdbus_domain *parent, const char *name,
ret = -ENOMEM;
goto exit_unlock;
}
-
- d->nest = parent->nest + 1;
}
/* get dynamic major */
View
4 domain.h
@@ -26,7 +26,6 @@
* @id: Global id of this domain
* @devpath: /dev base directory path
* @major: Device major number for all nodes
- * @nest: Nesting level in stacked domain tree
* @mode: Device node access mode
* @idr: Map of endpoint minors to buses
* @dev: Control device node, minor == 0
@@ -56,7 +55,6 @@ struct kdbus_domain {
u64 id;
const char *devpath;
unsigned int major;
- unsigned int nest;
umode_t mode;
struct idr idr;
struct device *dev;
@@ -91,7 +89,7 @@ extern struct bus_type kdbus_subsys;
struct kdbus_domain *kdbus_domain_ref(struct kdbus_domain *domain);
struct kdbus_domain *kdbus_domain_unref(struct kdbus_domain *domain);
-void kdbus_domain_disconnect(struct kdbus_domain *domain, bool parent);
+void kdbus_domain_disconnect(struct kdbus_domain *domain);
int kdbus_domain_new(struct kdbus_domain *parent, const char *name,
umode_t mode, struct kdbus_domain **domain);
int kdbus_domain_make_user(struct kdbus_cmd_make *cmd, char **name);
View
11 endpoint.c
@@ -60,10 +60,9 @@ struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep)
/**
* kdbus_ep_disconnect() - disconnect an endpoint
- * @parent: The bus disconnect this endpoint
* @ep: Endpoint
*/
-void kdbus_ep_disconnect(struct kdbus_ep *ep, bool parent)
+void kdbus_ep_disconnect(struct kdbus_ep *ep)
{
mutex_lock(&ep->lock);
if (ep->disconnected) {
@@ -74,11 +73,9 @@ void kdbus_ep_disconnect(struct kdbus_ep *ep, bool parent)
mutex_unlock(&ep->lock);
/* disconnect from bus */
- if (!parent)
- mutex_lock(&ep->bus->lock);
+ mutex_lock(&ep->bus->lock);
list_del(&ep->bus_entry);
- if (!parent)
- mutex_unlock(&ep->bus->lock);
+ mutex_unlock(&ep->bus->lock);
if (ep->dev) {
device_unregister(ep->dev);
@@ -100,7 +97,7 @@ static void __kdbus_ep_free(struct kref *kref)
{
struct kdbus_ep *ep = container_of(kref, struct kdbus_ep, kref);
- kdbus_ep_disconnect(ep, false);
+ kdbus_ep_disconnect(ep);
if (ep->policy_db)
kdbus_policy_db_free(ep->policy_db);
kdbus_bus_unref(ep->bus);
View
2  endpoint.h
@@ -61,6 +61,6 @@ int kdbus_ep_new(struct kdbus_bus *bus, const char *name,
bool policy, struct kdbus_ep **ep);
struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep);
struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep);
-void kdbus_ep_disconnect(struct kdbus_ep *ep, bool parent);
+void kdbus_ep_disconnect(struct kdbus_ep *ep);
int kdbus_ep_make_user(struct kdbus_cmd_make *make, char **name);
#endif
View
10 handle.c
@@ -160,22 +160,22 @@ static int kdbus_handle_release(struct inode *inode, struct file *file)
switch (handle->type) {
case KDBUS_HANDLE_CONTROL_DOMAIN_OWNER:
- kdbus_domain_disconnect(handle->domain_owner, false);
+ kdbus_domain_disconnect(handle->domain_owner);
kdbus_domain_unref(handle->domain_owner);
break;
case KDBUS_HANDLE_CONTROL_BUS_OWNER:
- kdbus_bus_disconnect(handle->bus_owner, false);
+ kdbus_bus_disconnect(handle->bus_owner);
kdbus_bus_unref(handle->bus_owner);
break;
case KDBUS_HANDLE_EP_OWNER:
- kdbus_ep_disconnect(handle->ep_owner, false);
+ kdbus_ep_disconnect(handle->ep_owner);
kdbus_ep_unref(handle->ep_owner);
break;
case KDBUS_HANDLE_EP_CONNECTED:
- kdbus_conn_disconnect(handle->conn, false, false);
+ kdbus_conn_disconnect(handle->conn, false);
kdbus_conn_unref(handle->conn);
/* fall through */
@@ -524,7 +524,7 @@ static long kdbus_handle_ioctl_ep_connected(struct file *file, unsigned int cmd,
switch (cmd) {
case KDBUS_CMD_BYEBYE:
- ret = kdbus_conn_disconnect(conn, false, true);
+ ret = kdbus_conn_disconnect(conn, true);
break;
case KDBUS_CMD_EP_POLICY_SET:
View
2  kdbus.h
@@ -947,7 +947,7 @@ enum kdbus_ioctl_type {
* @EPIPE: When sending a message, a synchronous reply from the
* receiving connection was expected but the connection
* died before answering.
- * @ESHUTDOWN: A domain or endpoint is currently shutting down;
+ * @ESHUTDOWN: A domain, bus or endpoint is currently shutting down;
* no further operations will be possible.
* @ESRCH: A requested well-known bus name is not found.
* @ETIMEDOUT: A synchronous wait for a message reply did not arrive
View
2  main.c
@@ -47,7 +47,7 @@ static int __init kdbus_init(void)
static void __exit kdbus_exit(void)
{
- kdbus_domain_disconnect(kdbus_domain_init, false);
+ kdbus_domain_disconnect(kdbus_domain_init);
kdbus_domain_unref(kdbus_domain_init);
bus_unregister(&kdbus_subsys);
}
Please sign in to comment.
Something went wrong with that request. Please try again.