KEYS: Do preallocation for __key_link()
[pandora-kernel.git] / security / keys / key.c
index c70da6f..c1eac80 100644 (file)
@@ -398,7 +398,8 @@ static int __key_instantiate_and_link(struct key *key,
                                      const void *data,
                                      size_t datalen,
                                      struct key *keyring,
-                                     struct key *authkey)
+                                     struct key *authkey,
+                                     struct keyring_list **_prealloc)
 {
        int ret, awaken;
 
@@ -425,7 +426,7 @@ static int __key_instantiate_and_link(struct key *key,
 
                        /* and link it into the destination keyring */
                        if (keyring)
-                               ret = __key_link(keyring, key);
+                               __key_link(keyring, key, _prealloc);
 
                        /* disable the authorisation key */
                        if (authkey)
@@ -453,15 +454,21 @@ int key_instantiate_and_link(struct key *key,
                             struct key *keyring,
                             struct key *authkey)
 {
+       struct keyring_list *prealloc;
        int ret;
 
-       if (keyring)
-               down_write(&keyring->sem);
+       if (keyring) {
+               ret = __key_link_begin(keyring, key->type, key->description,
+                                      &prealloc);
+               if (ret < 0)
+                       return ret;
+       }
 
-       ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey);
+       ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey,
+                                        &prealloc);
 
        if (keyring)
-               up_write(&keyring->sem);
+               __key_link_end(keyring, key->type, prealloc);
 
        return ret;
 
@@ -478,8 +485,9 @@ int key_negate_and_link(struct key *key,
                        struct key *keyring,
                        struct key *authkey)
 {
+       struct keyring_list *prealloc;
        struct timespec now;
-       int ret, awaken;
+       int ret, awaken, link_ret = 0;
 
        key_check(key);
        key_check(keyring);
@@ -488,7 +496,8 @@ int key_negate_and_link(struct key *key,
        ret = -EBUSY;
 
        if (keyring)
-               down_write(&keyring->sem);
+               link_ret = __key_link_begin(keyring, key->type,
+                                           key->description, &prealloc);
 
        mutex_lock(&key_construction_mutex);
 
@@ -508,8 +517,8 @@ int key_negate_and_link(struct key *key,
                ret = 0;
 
                /* and link it into the destination keyring */
-               if (keyring)
-                       ret = __key_link(keyring, key);
+               if (keyring && link_ret == 0)
+                       __key_link(keyring, key, &prealloc);
 
                /* disable the authorisation key */
                if (authkey)
@@ -519,13 +528,13 @@ int key_negate_and_link(struct key *key,
        mutex_unlock(&key_construction_mutex);
 
        if (keyring)
-               up_write(&keyring->sem);
+               __key_link_end(keyring, key->type, prealloc);
 
        /* wake up anyone waiting for a key to be constructed */
        if (awaken)
                wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
 
-       return ret;
+       return ret == 0 ? link_ret : ret;
 
 } /* end key_negate_and_link() */
 
@@ -749,6 +758,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
                               key_perm_t perm,
                               unsigned long flags)
 {
+       struct keyring_list *prealloc;
        const struct cred *cred = current_cred();
        struct key_type *ktype;
        struct key *keyring, *key = NULL;
@@ -775,7 +785,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
        if (keyring->type != &key_type_keyring)
                goto error_2;
 
-       down_write(&keyring->sem);
+       ret = __key_link_begin(keyring, ktype, description, &prealloc);
+       if (ret < 0)
+               goto error_2;
 
        /* if we're going to allocate a new key, we're going to have
         * to modify the keyring */
@@ -817,7 +829,8 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
        }
 
        /* instantiate it and link it into the target keyring */
-       ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL);
+       ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL,
+                                        &prealloc);
        if (ret < 0) {
                key_put(key);
                key_ref = ERR_PTR(ret);
@@ -827,7 +840,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
        key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
 
  error_3:
-       up_write(&keyring->sem);
+       __key_link_end(keyring, ktype, prealloc);
  error_2:
        key_type_put(ktype);
  error:
@@ -837,7 +850,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
        /* we found a matching key, so we're going to try to update it
         * - we can drop the locks first as we have the key pinned
         */
-       up_write(&keyring->sem);
+       __key_link_end(keyring, ktype, prealloc);
        key_type_put(ktype);
 
        key_ref = __key_update(key_ref, payload, plen);