diff options
author | David Howells <dhowells@redhat.com> | 2011-08-22 14:09:11 +0100 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2011-08-23 09:57:36 +1000 |
commit | 8bc16deabce7649e480e94b648c88d4e90c34352 (patch) | |
tree | d9e28a921375e7448801b0b89ff43a7e0d2e61ff /security/keys/gc.c | |
parent | 012146d0728f85f7a5c7c36fb84bba33e2760507 (diff) |
KEYS: Move the unreferenced key reaper to the keys garbage collector file
Move the unreferenced key reaper function to the keys garbage collector file
as that's a more appropriate place with the dead key link reaper.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/keys/gc.c')
-rw-r--r-- | security/keys/gc.c | 87 |
1 files changed, 81 insertions, 6 deletions
diff --git a/security/keys/gc.c b/security/keys/gc.c index 89df6b5f203c..b23db3fbb32d 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -10,6 +10,8 @@ */ #include <linux/module.h> +#include <linux/slab.h> +#include <linux/security.h> #include <keys/keyring-type.h> #include "internal.h" @@ -19,12 +21,18 @@ unsigned key_gc_delay = 5 * 60; /* - * Reaper + * Reaper for unused keys. + */ +static void key_gc_unused_keys(struct work_struct *work); +DECLARE_WORK(key_gc_unused_work, key_gc_unused_keys); + +/* + * Reaper for links from keyrings to dead keys. */ static void key_gc_timer_func(unsigned long); -static void key_garbage_collector(struct work_struct *); +static void key_gc_dead_links(struct work_struct *); static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0); -static DECLARE_WORK(key_gc_work, key_garbage_collector); +static DECLARE_WORK(key_gc_work, key_gc_dead_links); static key_serial_t key_gc_cursor; /* the last key the gc considered */ static bool key_gc_again; static unsigned long key_gc_executing; @@ -108,10 +116,12 @@ do_gc: } /* - * Garbage collector for keys. This involves scanning the keyrings for dead, - * expired and revoked keys that have overstayed their welcome + * Garbage collector for links to dead keys. + * + * This involves scanning the keyrings for dead, expired and revoked keys that + * have overstayed their welcome */ -static void key_garbage_collector(struct work_struct *work) +static void key_gc_dead_links(struct work_struct *work) { struct rb_node *rb; key_serial_t cursor; @@ -220,3 +230,68 @@ reached_the_end: } kleave(" [end]"); } + +/* + * Garbage collector for unused keys. + * + * This is done in process context so that we don't have to disable interrupts + * all over the place. key_put() schedules this rather than trying to do the + * cleanup itself, which means key_put() doesn't have to sleep. + */ +static void key_gc_unused_keys(struct work_struct *work) +{ + struct rb_node *_n; + struct key *key; + +go_again: + /* look for a dead key in the tree */ + spin_lock(&key_serial_lock); + + for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { + key = rb_entry(_n, struct key, serial_node); + + if (atomic_read(&key->usage) == 0) + goto found_dead_key; + } + + spin_unlock(&key_serial_lock); + return; + +found_dead_key: + /* we found a dead key - once we've removed it from the tree, we can + * drop the lock */ + rb_erase(&key->serial_node, &key_serial_tree); + spin_unlock(&key_serial_lock); + + key_check(key); + + security_key_free(key); + + /* deal with the user's key tracking and quota */ + if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { + spin_lock(&key->user->lock); + key->user->qnkeys--; + key->user->qnbytes -= key->quotalen; + spin_unlock(&key->user->lock); + } + + atomic_dec(&key->user->nkeys); + if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) + atomic_dec(&key->user->nikeys); + + key_user_put(key->user); + + /* now throw away the key memory */ + if (key->type->destroy) + key->type->destroy(key); + + kfree(key->description); + +#ifdef KEY_DEBUGGING + key->magic = KEY_DEBUG_MAGIC_X; +#endif + kmem_cache_free(key_jar, key); + + /* there may, of course, be more than one key to destroy */ + goto go_again; +} |