bus: improve user quota accounting and domain locking
authorDjalal Harouni <tixxdz@opendz.org>
Wed, 30 Jul 2014 20:11:56 +0000 (21:11 +0100)
committerKay Sievers <kay@vrfy.org>
Thu, 31 Jul 2014 14:29:57 +0000 (16:29 +0200)
Currently kdbus_bus_new() execution path might take the domain lock
three times on success, four times on failure.

kdbus_bus_new():
  => kdbus_domain_user_find_or_new(): takes it 2 times (and it is racy)
  +
  kdbus_bus_new(): take it an extra time to account the user and link
  the bus into the domain bus_list.

And as discussed in the previous patch kdbus_domain_user_find_or_new()
is racy, so convert to __kdbus_domain_user_account()

This allows also to improve the execution path to take the domain lock
only one time in case of success. On failure the domain lock will be
taken two times.

kdbus_bus_new():
  => take domain lock
  => check if domain is still active/connected
     => __kdbus_domain_user_account()
  ...

Signed-off-by: Djalal Harouni <tixxdz@opendz.org>
bus.c

diff --git a/bus.c b/bus.c
index d09e3c66283598bfc466a90fea3abdae8a1ec89f..9e2f41ba5f0bf5c777073665de6b3ec930ba956f 100644 (file)
--- a/bus.c
+++ b/bus.c
@@ -269,13 +269,6 @@ int kdbus_bus_new(struct kdbus_domain *domain,
        if (ret < 0)
                goto exit_free_reg;
 
-       /* account the bus against the user */
-       b->user = kdbus_domain_user_find_or_new(domain, uid);
-       if (!b->user) {
-               ret = -ENOMEM;
-               goto exit_ep_unref;
-       }
-
        /* link into domain */
        mutex_lock(&domain->lock);
        if (domain->disconnected) {
@@ -283,6 +276,11 @@ int kdbus_bus_new(struct kdbus_domain *domain,
                goto exit_unref_user_unlock;
        }
 
+       /* account the bus against the user */
+       ret = __kdbus_domain_user_account(domain, uid, &b->user);
+       if (ret < 0)
+               goto exit_unref_user_unlock;
+
        if (!capable(CAP_IPC_OWNER) &&
            atomic_inc_return(&b->user->buses) > KDBUS_USER_MAX_BUSES) {
                atomic_dec(&b->user->buses);
@@ -300,7 +298,6 @@ int kdbus_bus_new(struct kdbus_domain *domain,
 exit_unref_user_unlock:
        mutex_unlock(&domain->lock);
        kdbus_domain_user_unref(b->user);
-exit_ep_unref:
        kdbus_ep_unref(b->ep);
 exit_free_reg:
        kdbus_name_registry_free(b->name_registry);