162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* Key garbage collector 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2009-2011 Red Hat, Inc. All Rights Reserved. 562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/security.h> 1062306a36Sopenharmony_ci#include <keys/keyring-type.h> 1162306a36Sopenharmony_ci#include "internal.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* 1462306a36Sopenharmony_ci * Delay between key revocation/expiry in seconds 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ciunsigned key_gc_delay = 5 * 60; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* 1962306a36Sopenharmony_ci * Reaper for unused keys. 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_cistatic void key_garbage_collector(struct work_struct *work); 2262306a36Sopenharmony_ciDECLARE_WORK(key_gc_work, key_garbage_collector); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * Reaper for links from keyrings to dead keys. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_cistatic void key_gc_timer_func(struct timer_list *); 2862306a36Sopenharmony_cistatic DEFINE_TIMER(key_gc_timer, key_gc_timer_func); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic time64_t key_gc_next_run = TIME64_MAX; 3162306a36Sopenharmony_cistatic struct key_type *key_gc_dead_keytype; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic unsigned long key_gc_flags; 3462306a36Sopenharmony_ci#define KEY_GC_KEY_EXPIRED 0 /* A key expired and needs unlinking */ 3562306a36Sopenharmony_ci#define KEY_GC_REAP_KEYTYPE 1 /* A keytype is being unregistered */ 3662306a36Sopenharmony_ci#define KEY_GC_REAPING_KEYTYPE 2 /* Cleared when keytype reaped */ 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * Any key whose type gets unregistered will be re-typed to this if it can't be 4162306a36Sopenharmony_ci * immediately unlinked. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_cistruct key_type key_type_dead = { 4462306a36Sopenharmony_ci .name = ".dead", 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * Schedule a garbage collection run. 4962306a36Sopenharmony_ci * - time precision isn't particularly important 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_civoid key_schedule_gc(time64_t gc_at) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci unsigned long expires; 5462306a36Sopenharmony_ci time64_t now = ktime_get_real_seconds(); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci kenter("%lld", gc_at - now); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (gc_at <= now || test_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags)) { 5962306a36Sopenharmony_ci kdebug("IMMEDIATE"); 6062306a36Sopenharmony_ci schedule_work(&key_gc_work); 6162306a36Sopenharmony_ci } else if (gc_at < key_gc_next_run) { 6262306a36Sopenharmony_ci kdebug("DEFERRED"); 6362306a36Sopenharmony_ci key_gc_next_run = gc_at; 6462306a36Sopenharmony_ci expires = jiffies + (gc_at - now) * HZ; 6562306a36Sopenharmony_ci mod_timer(&key_gc_timer, expires); 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * Set the expiration time on a key. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_civoid key_set_expiry(struct key *key, time64_t expiry) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci key->expiry = expiry; 7562306a36Sopenharmony_ci if (expiry != TIME64_MAX) { 7662306a36Sopenharmony_ci if (!(key->type->flags & KEY_TYPE_INSTANT_REAP)) 7762306a36Sopenharmony_ci expiry += key_gc_delay; 7862306a36Sopenharmony_ci key_schedule_gc(expiry); 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* 8362306a36Sopenharmony_ci * Schedule a dead links collection run. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_civoid key_schedule_gc_links(void) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); 8862306a36Sopenharmony_ci schedule_work(&key_gc_work); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * Some key's cleanup time was met after it expired, so we need to get the 9362306a36Sopenharmony_ci * reaper to go through a cycle finding expired keys. 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_cistatic void key_gc_timer_func(struct timer_list *unused) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci kenter(""); 9862306a36Sopenharmony_ci key_gc_next_run = TIME64_MAX; 9962306a36Sopenharmony_ci key_schedule_gc_links(); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* 10362306a36Sopenharmony_ci * Reap keys of dead type. 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * We use three flags to make sure we see three complete cycles of the garbage 10662306a36Sopenharmony_ci * collector: the first to mark keys of that type as being dead, the second to 10762306a36Sopenharmony_ci * collect dead links and the third to clean up the dead keys. We have to be 10862306a36Sopenharmony_ci * careful as there may already be a cycle in progress. 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * The caller must be holding key_types_sem. 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_civoid key_gc_keytype(struct key_type *ktype) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci kenter("%s", ktype->name); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci key_gc_dead_keytype = ktype; 11762306a36Sopenharmony_ci set_bit(KEY_GC_REAPING_KEYTYPE, &key_gc_flags); 11862306a36Sopenharmony_ci smp_mb(); 11962306a36Sopenharmony_ci set_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci kdebug("schedule"); 12262306a36Sopenharmony_ci schedule_work(&key_gc_work); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci kdebug("sleep"); 12562306a36Sopenharmony_ci wait_on_bit(&key_gc_flags, KEY_GC_REAPING_KEYTYPE, 12662306a36Sopenharmony_ci TASK_UNINTERRUPTIBLE); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci key_gc_dead_keytype = NULL; 12962306a36Sopenharmony_ci kleave(""); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* 13362306a36Sopenharmony_ci * Garbage collect a list of unreferenced, detached keys 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_cistatic noinline void key_gc_unused_keys(struct list_head *keys) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci while (!list_empty(keys)) { 13862306a36Sopenharmony_ci struct key *key = 13962306a36Sopenharmony_ci list_entry(keys->next, struct key, graveyard_link); 14062306a36Sopenharmony_ci short state = key->state; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci list_del(&key->graveyard_link); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci kdebug("- %u", key->serial); 14562306a36Sopenharmony_ci key_check(key); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#ifdef CONFIG_KEY_NOTIFICATIONS 14862306a36Sopenharmony_ci remove_watch_list(key->watchers, key->serial); 14962306a36Sopenharmony_ci key->watchers = NULL; 15062306a36Sopenharmony_ci#endif 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* Throw away the key data if the key is instantiated */ 15362306a36Sopenharmony_ci if (state == KEY_IS_POSITIVE && key->type->destroy) 15462306a36Sopenharmony_ci key->type->destroy(key); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci security_key_free(key); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* deal with the user's key tracking and quota */ 15962306a36Sopenharmony_ci if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { 16062306a36Sopenharmony_ci spin_lock(&key->user->lock); 16162306a36Sopenharmony_ci key->user->qnkeys--; 16262306a36Sopenharmony_ci key->user->qnbytes -= key->quotalen; 16362306a36Sopenharmony_ci spin_unlock(&key->user->lock); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci atomic_dec(&key->user->nkeys); 16762306a36Sopenharmony_ci if (state != KEY_IS_UNINSTANTIATED) 16862306a36Sopenharmony_ci atomic_dec(&key->user->nikeys); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci key_user_put(key->user); 17162306a36Sopenharmony_ci key_put_tag(key->domain_tag); 17262306a36Sopenharmony_ci kfree(key->description); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci memzero_explicit(key, sizeof(*key)); 17562306a36Sopenharmony_ci kmem_cache_free(key_jar, key); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* 18062306a36Sopenharmony_ci * Garbage collector for unused keys. 18162306a36Sopenharmony_ci * 18262306a36Sopenharmony_ci * This is done in process context so that we don't have to disable interrupts 18362306a36Sopenharmony_ci * all over the place. key_put() schedules this rather than trying to do the 18462306a36Sopenharmony_ci * cleanup itself, which means key_put() doesn't have to sleep. 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_cistatic void key_garbage_collector(struct work_struct *work) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci static LIST_HEAD(graveyard); 18962306a36Sopenharmony_ci static u8 gc_state; /* Internal persistent state */ 19062306a36Sopenharmony_ci#define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */ 19162306a36Sopenharmony_ci#define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */ 19262306a36Sopenharmony_ci#define KEY_GC_REAPING_DEAD_1 0x10 /* - We need to mark dead keys */ 19362306a36Sopenharmony_ci#define KEY_GC_REAPING_DEAD_2 0x20 /* - We need to reap dead key links */ 19462306a36Sopenharmony_ci#define KEY_GC_REAPING_DEAD_3 0x40 /* - We need to reap dead keys */ 19562306a36Sopenharmony_ci#define KEY_GC_FOUND_DEAD_KEY 0x80 /* - We found at least one dead key */ 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci struct rb_node *cursor; 19862306a36Sopenharmony_ci struct key *key; 19962306a36Sopenharmony_ci time64_t new_timer, limit, expiry; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci kenter("[%lx,%x]", key_gc_flags, gc_state); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci limit = ktime_get_real_seconds(); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* Work out what we're going to be doing in this pass */ 20662306a36Sopenharmony_ci gc_state &= KEY_GC_REAPING_DEAD_1 | KEY_GC_REAPING_DEAD_2; 20762306a36Sopenharmony_ci gc_state <<= 1; 20862306a36Sopenharmony_ci if (test_and_clear_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags)) 20962306a36Sopenharmony_ci gc_state |= KEY_GC_REAPING_LINKS; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (test_and_clear_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags)) 21262306a36Sopenharmony_ci gc_state |= KEY_GC_REAPING_DEAD_1; 21362306a36Sopenharmony_ci kdebug("new pass %x", gc_state); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci new_timer = TIME64_MAX; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* As only this function is permitted to remove things from the key 21862306a36Sopenharmony_ci * serial tree, if cursor is non-NULL then it will always point to a 21962306a36Sopenharmony_ci * valid node in the tree - even if lock got dropped. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ci spin_lock(&key_serial_lock); 22262306a36Sopenharmony_ci cursor = rb_first(&key_serial_tree); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cicontinue_scanning: 22562306a36Sopenharmony_ci while (cursor) { 22662306a36Sopenharmony_ci key = rb_entry(cursor, struct key, serial_node); 22762306a36Sopenharmony_ci cursor = rb_next(cursor); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (refcount_read(&key->usage) == 0) 23062306a36Sopenharmony_ci goto found_unreferenced_key; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (unlikely(gc_state & KEY_GC_REAPING_DEAD_1)) { 23362306a36Sopenharmony_ci if (key->type == key_gc_dead_keytype) { 23462306a36Sopenharmony_ci gc_state |= KEY_GC_FOUND_DEAD_KEY; 23562306a36Sopenharmony_ci set_bit(KEY_FLAG_DEAD, &key->flags); 23662306a36Sopenharmony_ci key->perm = 0; 23762306a36Sopenharmony_ci goto skip_dead_key; 23862306a36Sopenharmony_ci } else if (key->type == &key_type_keyring && 23962306a36Sopenharmony_ci key->restrict_link) { 24062306a36Sopenharmony_ci goto found_restricted_keyring; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci expiry = key->expiry; 24562306a36Sopenharmony_ci if (expiry != TIME64_MAX) { 24662306a36Sopenharmony_ci if (!(key->type->flags & KEY_TYPE_INSTANT_REAP)) 24762306a36Sopenharmony_ci expiry += key_gc_delay; 24862306a36Sopenharmony_ci if (expiry > limit && expiry < new_timer) { 24962306a36Sopenharmony_ci kdebug("will expire %x in %lld", 25062306a36Sopenharmony_ci key_serial(key), key->expiry - limit); 25162306a36Sopenharmony_ci new_timer = key->expiry; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) 25662306a36Sopenharmony_ci if (key->type == key_gc_dead_keytype) 25762306a36Sopenharmony_ci gc_state |= KEY_GC_FOUND_DEAD_KEY; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if ((gc_state & KEY_GC_REAPING_LINKS) || 26062306a36Sopenharmony_ci unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) { 26162306a36Sopenharmony_ci if (key->type == &key_type_keyring) 26262306a36Sopenharmony_ci goto found_keyring; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (unlikely(gc_state & KEY_GC_REAPING_DEAD_3)) 26662306a36Sopenharmony_ci if (key->type == key_gc_dead_keytype) 26762306a36Sopenharmony_ci goto destroy_dead_key; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci skip_dead_key: 27062306a36Sopenharmony_ci if (spin_is_contended(&key_serial_lock) || need_resched()) 27162306a36Sopenharmony_ci goto contended; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cicontended: 27562306a36Sopenharmony_ci spin_unlock(&key_serial_lock); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cimaybe_resched: 27862306a36Sopenharmony_ci if (cursor) { 27962306a36Sopenharmony_ci cond_resched(); 28062306a36Sopenharmony_ci spin_lock(&key_serial_lock); 28162306a36Sopenharmony_ci goto continue_scanning; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* We've completed the pass. Set the timer if we need to and queue a 28562306a36Sopenharmony_ci * new cycle if necessary. We keep executing cycles until we find one 28662306a36Sopenharmony_ci * where we didn't reap any keys. 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_ci kdebug("pass complete"); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (new_timer != TIME64_MAX) { 29162306a36Sopenharmony_ci new_timer += key_gc_delay; 29262306a36Sopenharmony_ci key_schedule_gc(new_timer); 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2) || 29662306a36Sopenharmony_ci !list_empty(&graveyard)) { 29762306a36Sopenharmony_ci /* Make sure that all pending keyring payload destructions are 29862306a36Sopenharmony_ci * fulfilled and that people aren't now looking at dead or 29962306a36Sopenharmony_ci * dying keys that they don't have a reference upon or a link 30062306a36Sopenharmony_ci * to. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ci kdebug("gc sync"); 30362306a36Sopenharmony_ci synchronize_rcu(); 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (!list_empty(&graveyard)) { 30762306a36Sopenharmony_ci kdebug("gc keys"); 30862306a36Sopenharmony_ci key_gc_unused_keys(&graveyard); 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (unlikely(gc_state & (KEY_GC_REAPING_DEAD_1 | 31262306a36Sopenharmony_ci KEY_GC_REAPING_DEAD_2))) { 31362306a36Sopenharmony_ci if (!(gc_state & KEY_GC_FOUND_DEAD_KEY)) { 31462306a36Sopenharmony_ci /* No remaining dead keys: short circuit the remaining 31562306a36Sopenharmony_ci * keytype reap cycles. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_ci kdebug("dead short"); 31862306a36Sopenharmony_ci gc_state &= ~(KEY_GC_REAPING_DEAD_1 | KEY_GC_REAPING_DEAD_2); 31962306a36Sopenharmony_ci gc_state |= KEY_GC_REAPING_DEAD_3; 32062306a36Sopenharmony_ci } else { 32162306a36Sopenharmony_ci gc_state |= KEY_GC_REAP_AGAIN; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (unlikely(gc_state & KEY_GC_REAPING_DEAD_3)) { 32662306a36Sopenharmony_ci kdebug("dead wake"); 32762306a36Sopenharmony_ci smp_mb(); 32862306a36Sopenharmony_ci clear_bit(KEY_GC_REAPING_KEYTYPE, &key_gc_flags); 32962306a36Sopenharmony_ci wake_up_bit(&key_gc_flags, KEY_GC_REAPING_KEYTYPE); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (gc_state & KEY_GC_REAP_AGAIN) 33362306a36Sopenharmony_ci schedule_work(&key_gc_work); 33462306a36Sopenharmony_ci kleave(" [end %x]", gc_state); 33562306a36Sopenharmony_ci return; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* We found an unreferenced key - once we've removed it from the tree, 33862306a36Sopenharmony_ci * we can safely drop the lock. 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_cifound_unreferenced_key: 34162306a36Sopenharmony_ci kdebug("unrefd key %d", key->serial); 34262306a36Sopenharmony_ci rb_erase(&key->serial_node, &key_serial_tree); 34362306a36Sopenharmony_ci spin_unlock(&key_serial_lock); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci list_add_tail(&key->graveyard_link, &graveyard); 34662306a36Sopenharmony_ci gc_state |= KEY_GC_REAP_AGAIN; 34762306a36Sopenharmony_ci goto maybe_resched; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* We found a restricted keyring and need to update the restriction if 35062306a36Sopenharmony_ci * it is associated with the dead key type. 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_cifound_restricted_keyring: 35362306a36Sopenharmony_ci spin_unlock(&key_serial_lock); 35462306a36Sopenharmony_ci keyring_restriction_gc(key, key_gc_dead_keytype); 35562306a36Sopenharmony_ci goto maybe_resched; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* We found a keyring and we need to check the payload for links to 35862306a36Sopenharmony_ci * dead or expired keys. We don't flag another reap immediately as we 35962306a36Sopenharmony_ci * have to wait for the old payload to be destroyed by RCU before we 36062306a36Sopenharmony_ci * can reap the keys to which it refers. 36162306a36Sopenharmony_ci */ 36262306a36Sopenharmony_cifound_keyring: 36362306a36Sopenharmony_ci spin_unlock(&key_serial_lock); 36462306a36Sopenharmony_ci keyring_gc(key, limit); 36562306a36Sopenharmony_ci goto maybe_resched; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* We found a dead key that is still referenced. Reset its type and 36862306a36Sopenharmony_ci * destroy its payload with its semaphore held. 36962306a36Sopenharmony_ci */ 37062306a36Sopenharmony_cidestroy_dead_key: 37162306a36Sopenharmony_ci spin_unlock(&key_serial_lock); 37262306a36Sopenharmony_ci kdebug("destroy key %d", key->serial); 37362306a36Sopenharmony_ci down_write(&key->sem); 37462306a36Sopenharmony_ci key->type = &key_type_dead; 37562306a36Sopenharmony_ci if (key_gc_dead_keytype->destroy) 37662306a36Sopenharmony_ci key_gc_dead_keytype->destroy(key); 37762306a36Sopenharmony_ci memset(&key->payload, KEY_DESTROY, sizeof(key->payload)); 37862306a36Sopenharmony_ci up_write(&key->sem); 37962306a36Sopenharmony_ci goto maybe_resched; 38062306a36Sopenharmony_ci} 381