Commit 8bc16dea authored by David Howells's avatar David Howells Committed by James Morris
Browse files

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: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 012146d0
Loading
Loading
Loading
Loading
+81 −6
Original line number Diff line number Diff line
@@ -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;
}
+2 −0
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ extern unsigned key_quota_maxbytes;
#define KEYQUOTA_LINK_BYTES	4		/* a link in a keyring is worth 4 bytes */


extern struct kmem_cache *key_jar;
extern struct rb_root key_serial_tree;
extern spinlock_t key_serial_lock;
extern struct mutex key_construction_mutex;
@@ -146,6 +147,7 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,

extern long join_session_keyring(const char *name);

extern struct work_struct key_gc_unused_work;
extern unsigned key_gc_delay;
extern void keyring_gc(struct key *keyring, time_t limit);
extern void key_schedule_gc(time_t expiry_at);
+2 −70
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@
#include <linux/user_namespace.h>
#include "internal.h"

static struct kmem_cache	*key_jar;
struct kmem_cache *key_jar;
struct rb_root		key_serial_tree; /* tree of keys indexed by serial */
DEFINE_SPINLOCK(key_serial_lock);

@@ -36,9 +36,6 @@ unsigned int key_quota_maxbytes = 20000; /* general key space quota */
static LIST_HEAD(key_types_list);
static DECLARE_RWSEM(key_types_sem);

static void key_cleanup(struct work_struct *work);
static DECLARE_WORK(key_cleanup_task, key_cleanup);

/* We serialise key instantiation and link */
DEFINE_MUTEX(key_construction_mutex);

@@ -591,71 +588,6 @@ int key_reject_and_link(struct key *key,
}
EXPORT_SYMBOL(key_reject_and_link);

/*
 * Garbage collect keys 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_cleanup(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;
}

/**
 * key_put - Discard a reference to a key.
 * @key: The key to discard a reference from.
@@ -670,7 +602,7 @@ void key_put(struct key *key)
		key_check(key);

		if (atomic_dec_and_test(&key->usage))
			schedule_work(&key_cleanup_task);
			schedule_work(&key_gc_unused_work);
	}
}
EXPORT_SYMBOL(key_put);