Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 161362
b: refs/heads/master
c: c08ef80
h: refs/heads/master
v: v3
  • Loading branch information
David Howells authored and James Morris committed Sep 14, 2009
1 parent 44d9083 commit 8c793d7
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 36 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5c84342a3e147a23752276650340801c237d0e56
refs/heads/master: c08ef808ef24df32e25fbd949fe5310172f3c408
78 changes: 51 additions & 27 deletions trunk/security/keys/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ static void key_garbage_collector(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 key_serial_t key_gc_cursor; /* the last key the gc considered */
static bool key_gc_again;
static unsigned long key_gc_executing;
static time_t key_gc_next_run = LONG_MAX;
static time_t key_gc_new_timer;

/*
* Schedule a garbage collection run
Expand All @@ -40,9 +42,7 @@ void key_schedule_gc(time_t gc_at)

kenter("%ld", gc_at - now);

gc_at += key_gc_delay;

if (now >= gc_at) {
if (gc_at <= now) {
schedule_work(&key_gc_work);
} else if (gc_at < key_gc_next_run) {
expires = jiffies + (gc_at - now) * HZ;
Expand Down Expand Up @@ -112,29 +112,38 @@ static void key_garbage_collector(struct work_struct *work)
struct rb_node *rb;
key_serial_t cursor;
struct key *key, *xkey;
time_t new_timer = LONG_MAX, limit;
time_t new_timer = LONG_MAX, limit, now;

kenter("");
now = current_kernel_time().tv_sec;
kenter("[%x,%ld]", key_gc_cursor, key_gc_new_timer - now);

if (test_and_set_bit(0, &key_gc_executing)) {
key_schedule_gc(current_kernel_time().tv_sec);
key_schedule_gc(current_kernel_time().tv_sec + 1);
kleave(" [busy; deferring]");
return;
}

limit = current_kernel_time().tv_sec;
limit = now;
if (limit > key_gc_delay)
limit -= key_gc_delay;
else
limit = key_gc_delay;

spin_lock(&key_serial_lock);

if (RB_EMPTY_ROOT(&key_serial_tree))
goto reached_the_end;
if (unlikely(RB_EMPTY_ROOT(&key_serial_tree))) {
spin_unlock(&key_serial_lock);
clear_bit(0, &key_gc_executing);
return;
}

cursor = key_gc_cursor;
if (cursor < 0)
cursor = 0;
if (cursor > 0)
new_timer = key_gc_new_timer;
else
key_gc_again = false;

/* find the first key above the cursor */
key = NULL;
Expand All @@ -160,35 +169,50 @@ static void key_garbage_collector(struct work_struct *work)

/* trawl through the keys looking for keyrings */
for (;;) {
if (key->expiry > 0 && key->expiry < new_timer)
if (key->expiry > now && key->expiry < new_timer) {
kdebug("will expire %x in %ld",
key_serial(key), key->expiry - now);
new_timer = key->expiry;
}

if (key->type == &key_type_keyring &&
key_gc_keyring(key, limit)) {
/* the gc ate our lock */
schedule_work(&key_gc_work);
goto no_unlock;
}
key_gc_keyring(key, limit))
/* the gc had to release our lock so that the keyring
* could be modified, so we have to get it again */
goto gc_released_our_lock;

rb = rb_next(&key->serial_node);
if (!rb) {
key_gc_cursor = 0;
break;
}
if (!rb)
goto reached_the_end;
key = rb_entry(rb, struct key, serial_node);
}

out:
spin_unlock(&key_serial_lock);
no_unlock:
gc_released_our_lock:
kdebug("gc_released_our_lock");
key_gc_new_timer = new_timer;
key_gc_again = true;
clear_bit(0, &key_gc_executing);
if (new_timer < LONG_MAX)
key_schedule_gc(new_timer);

kleave("");
schedule_work(&key_gc_work);
kleave(" [continue]");
return;

/* when we reach the end of the run, we set the timer for the next one */
reached_the_end:
kdebug("reached_the_end");
spin_unlock(&key_serial_lock);
key_gc_new_timer = new_timer;
key_gc_cursor = 0;
goto out;
clear_bit(0, &key_gc_executing);

if (key_gc_again) {
/* there may have been a key that expired whilst we were
* scanning, so if we discarded any links we should do another
* scan */
new_timer = now + 1;
key_schedule_gc(new_timer);
} else if (new_timer < LONG_MAX) {
new_timer += key_gc_delay;
key_schedule_gc(new_timer);
}
kleave(" [end]");
}
4 changes: 2 additions & 2 deletions trunk/security/keys/key.c
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ int key_negate_and_link(struct key *key,
set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
now = current_kernel_time();
key->expiry = now.tv_sec + timeout;
key_schedule_gc(key->expiry);
key_schedule_gc(key->expiry + key_gc_delay);

if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
awaken = 1;
Expand Down Expand Up @@ -909,7 +909,7 @@ void key_revoke(struct key *key)
time = now.tv_sec;
if (key->revoked_at == 0 || key->revoked_at > time) {
key->revoked_at = time;
key_schedule_gc(key->revoked_at);
key_schedule_gc(key->revoked_at + key_gc_delay);
}

up_write(&key->sem);
Expand Down
2 changes: 1 addition & 1 deletion trunk/security/keys/keyctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1115,7 +1115,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
}

key->expiry = expiry;
key_schedule_gc(key->expiry);
key_schedule_gc(key->expiry + key_gc_delay);

up_write(&key->sem);
key_put(key);
Expand Down
24 changes: 19 additions & 5 deletions trunk/security/keys/keyring.c
Original file line number Diff line number Diff line change
Expand Up @@ -1019,18 +1019,18 @@ void keyring_gc(struct key *keyring, time_t limit)
struct key *key;
int loop, keep, max;

kenter("%x", key_serial(keyring));
kenter("{%x,%s}", key_serial(keyring), keyring->description);

down_write(&keyring->sem);

klist = keyring->payload.subscriptions;
if (!klist)
goto just_return;
goto no_klist;

/* work out how many subscriptions we're keeping */
keep = 0;
for (loop = klist->nkeys - 1; loop >= 0; loop--)
if (!key_is_dead(klist->keys[loop], limit));
if (!key_is_dead(klist->keys[loop], limit))
keep++;

if (keep == klist->nkeys)
Expand All @@ -1041,7 +1041,7 @@ void keyring_gc(struct key *keyring, time_t limit)
new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *),
GFP_KERNEL);
if (!new)
goto just_return;
goto nomem;
new->maxkeys = max;
new->nkeys = 0;
new->delkey = 0;
Expand Down Expand Up @@ -1081,7 +1081,21 @@ void keyring_gc(struct key *keyring, time_t limit)
discard_new:
new->nkeys = keep;
keyring_clear_rcu_disposal(&new->rcu);
up_write(&keyring->sem);
kleave(" [discard]");
return;

just_return:
up_write(&keyring->sem);
kleave(" [no]");
kleave(" [no dead]");
return;

no_klist:
up_write(&keyring->sem);
kleave(" [no_klist]");
return;

nomem:
up_write(&keyring->sem);
kleave(" [oom]");
}

0 comments on commit 8c793d7

Please sign in to comment.