struct key *authkey)
 {
        struct key_preparsed_payload prep;
-       struct assoc_array_edit *edit;
+       struct assoc_array_edit *edit = NULL;
        int ret;
 
        memset(&prep, 0, sizeof(prep));
        }
 
        if (keyring) {
-               ret = __key_link_begin(keyring, &key->index_key, &edit);
+               ret = __key_link_lock(keyring, &key->index_key);
                if (ret < 0)
                        goto error;
 
+               ret = __key_link_begin(keyring, &key->index_key, &edit);
+               if (ret < 0)
+                       goto error_link_end;
+
                if (keyring->restrict_link && keyring->restrict_link->check) {
                        struct key_restriction *keyres = keyring->restrict_link;
 
                        struct key *keyring,
                        struct key *authkey)
 {
-       struct assoc_array_edit *edit;
+       struct assoc_array_edit *edit = NULL;
        int ret, awaken, link_ret = 0;
 
        key_check(key);
                if (keyring->restrict_link)
                        return -EPERM;
 
-               link_ret = __key_link_begin(keyring, &key->index_key, &edit);
+               link_ret = __key_link_lock(keyring, &key->index_key);
+               if (link_ret == 0) {
+                       link_ret = __key_link_begin(keyring, &key->index_key, &edit);
+                       if (link_ret < 0)
+                               __key_link_end(keyring, &key->index_key, edit);
+               }
        }
 
        mutex_lock(&key_construction_mutex);
                .description    = description,
        };
        struct key_preparsed_payload prep;
-       struct assoc_array_edit *edit;
+       struct assoc_array_edit *edit = NULL;
        const struct cred *cred = current_cred();
        struct key *keyring, *key = NULL;
        key_ref_t key_ref;
        }
        index_key.desc_len = strlen(index_key.description);
 
-       ret = __key_link_begin(keyring, &index_key, &edit);
+       ret = __key_link_lock(keyring, &index_key);
        if (ret < 0) {
                key_ref = ERR_PTR(ret);
                goto error_free_prep;
        }
 
+       ret = __key_link_begin(keyring, &index_key, &edit);
+       if (ret < 0) {
+               key_ref = ERR_PTR(ret);
+               goto error_link_end;
+       }
+
        if (restrict_link && restrict_link->check) {
                ret = restrict_link->check(keyring, index_key.type,
                                           &prep.payload, restrict_link->key);
 
        return PTR_ERR(ctx.result) == -EAGAIN ? 0 : PTR_ERR(ctx.result);
 }
 
+/*
+ * Lock keyring for link.
+ */
+int __key_link_lock(struct key *keyring,
+                   const struct keyring_index_key *index_key)
+       __acquires(&keyring->sem)
+       __acquires(&keyring_serialise_link_lock)
+{
+       if (keyring->type != &key_type_keyring)
+               return -ENOTDIR;
+
+       down_write(&keyring->sem);
+
+       /* Serialise link/link calls to prevent parallel calls causing a cycle
+        * when linking two keyring in opposite orders.
+        */
+       if (index_key->type == &key_type_keyring)
+               mutex_lock(&keyring_serialise_link_lock);
+
+       return 0;
+}
+
 /*
  * Preallocate memory so that a key can be linked into to a keyring.
  */
 int __key_link_begin(struct key *keyring,
                     const struct keyring_index_key *index_key,
                     struct assoc_array_edit **_edit)
-       __acquires(&keyring->sem)
-       __acquires(&keyring_serialise_link_lock)
 {
        struct assoc_array_edit *edit;
        int ret;
               keyring->serial, index_key->type->name, index_key->description);
 
        BUG_ON(index_key->desc_len == 0);
+       BUG_ON(*_edit != NULL);
 
-       if (keyring->type != &key_type_keyring)
-               return -ENOTDIR;
-
-       down_write(&keyring->sem);
+       *_edit = NULL;
 
        ret = -EKEYREVOKED;
        if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
-               goto error_krsem;
-
-       /* serialise link/link calls to prevent parallel calls causing a cycle
-        * when linking two keyring in opposite orders */
-       if (index_key->type == &key_type_keyring)
-               mutex_lock(&keyring_serialise_link_lock);
+               goto error;
 
        /* Create an edit script that will insert/replace the key in the
         * keyring tree.
                                  NULL);
        if (IS_ERR(edit)) {
                ret = PTR_ERR(edit);
-               goto error_sem;
+               goto error;
        }
 
        /* If we're not replacing a link in-place then we're going to need some
 
 error_cancel:
        assoc_array_cancel_edit(edit);
-error_sem:
-       if (index_key->type == &key_type_keyring)
-               mutex_unlock(&keyring_serialise_link_lock);
-error_krsem:
-       up_write(&keyring->sem);
+error:
        kleave(" = %d", ret);
        return ret;
 }
        BUG_ON(index_key->type == NULL);
        kenter("%d,%s,", keyring->serial, index_key->type->name);
 
-       if (index_key->type == &key_type_keyring)
-               mutex_unlock(&keyring_serialise_link_lock);
-
        if (edit) {
                if (!edit->dead_leaf) {
                        key_payload_reserve(keyring,
                assoc_array_cancel_edit(edit);
        }
        up_write(&keyring->sem);
+
+       if (index_key->type == &key_type_keyring)
+               mutex_unlock(&keyring_serialise_link_lock);
 }
 
 /*
  */
 int key_link(struct key *keyring, struct key *key)
 {
-       struct assoc_array_edit *edit;
+       struct assoc_array_edit *edit = NULL;
        int ret;
 
        kenter("{%d,%d}", keyring->serial, refcount_read(&keyring->usage));
        key_check(keyring);
        key_check(key);
 
+       ret = __key_link_lock(keyring, &key->index_key);
+       if (ret < 0)
+               goto error;
+
        ret = __key_link_begin(keyring, &key->index_key, &edit);
-       if (ret == 0) {
-               kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage));
-               ret = __key_link_check_restriction(keyring, key);
-               if (ret == 0)
-                       ret = __key_link_check_live_key(keyring, key);
-               if (ret == 0)
-                       __key_link(key, &edit);
-               __key_link_end(keyring, &key->index_key, edit);
-       }
+       if (ret < 0)
+               goto error_end;
+
+       kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage));
+       ret = __key_link_check_restriction(keyring, key);
+       if (ret == 0)
+               ret = __key_link_check_live_key(keyring, key);
+       if (ret == 0)
+               __key_link(key, &edit);
 
+error_end:
+       __key_link_end(keyring, &key->index_key, edit);
+error:
        kleave(" = %d {%d,%d}", ret, keyring->serial, refcount_read(&keyring->usage));
        return ret;
 }