[PATCH] Keys: Use RCU to manage session keyring pointer

The attached patch uses RCU to manage the session keyring pointer in struct
signal_struct.  This means that searching need not disable interrupts and get
a the sighand spinlock to access this pointer.  Furthermore, by judicious use
of rcu_read_(un)lock(), this patch also avoids the need to take and put
refcounts on the session keyring itself, thus saving on even more atomic ops.

Signed-Off-By: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
David Howells 2005-06-23 22:00:53 -07:00 committed by Linus Torvalds
parent 7888e7ff4e
commit 8589b4e00e
2 changed files with 24 additions and 25 deletions

View File

@ -1,6 +1,6 @@
/* process_keys.c: management of a process's keyrings /* process_keys.c: management of a process's keyrings
* *
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com) * Written by David Howells (dhowells@redhat.com)
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -181,7 +181,7 @@ static int install_process_keyring(struct task_struct *tsk)
goto error; goto error;
} }
/* attach or swap keyrings */ /* attach keyring */
spin_lock_irqsave(&tsk->sighand->siglock, flags); spin_lock_irqsave(&tsk->sighand->siglock, flags);
if (!tsk->signal->process_keyring) { if (!tsk->signal->process_keyring) {
tsk->signal->process_keyring = keyring; tsk->signal->process_keyring = keyring;
@ -227,12 +227,14 @@ static int install_session_keyring(struct task_struct *tsk,
/* install the keyring */ /* install the keyring */
spin_lock_irqsave(&tsk->sighand->siglock, flags); spin_lock_irqsave(&tsk->sighand->siglock, flags);
old = tsk->signal->session_keyring; old = rcu_dereference(tsk->signal->session_keyring);
tsk->signal->session_keyring = keyring; rcu_assign_pointer(tsk->signal->session_keyring, keyring);
spin_unlock_irqrestore(&tsk->sighand->siglock, flags); spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
ret = 0; ret = 0;
/* we're using RCU on the pointer */
synchronize_kernel();
key_put(old); key_put(old);
error: error:
return ret; return ret;
@ -245,8 +247,6 @@ static int install_session_keyring(struct task_struct *tsk,
*/ */
int copy_thread_group_keys(struct task_struct *tsk) int copy_thread_group_keys(struct task_struct *tsk)
{ {
unsigned long flags;
key_check(current->thread_group->session_keyring); key_check(current->thread_group->session_keyring);
key_check(current->thread_group->process_keyring); key_check(current->thread_group->process_keyring);
@ -254,10 +254,10 @@ int copy_thread_group_keys(struct task_struct *tsk)
tsk->signal->process_keyring = NULL; tsk->signal->process_keyring = NULL;
/* same session keyring */ /* same session keyring */
spin_lock_irqsave(&current->sighand->siglock, flags); rcu_read_lock();
tsk->signal->session_keyring = tsk->signal->session_keyring =
key_get(current->signal->session_keyring); key_get(rcu_dereference(current->signal->session_keyring));
spin_unlock_irqrestore(&current->sighand->siglock, flags); rcu_read_unlock();
return 0; return 0;
@ -381,8 +381,7 @@ struct key *search_process_keyrings_aux(struct key_type *type,
key_match_func_t match) key_match_func_t match)
{ {
struct task_struct *tsk = current; struct task_struct *tsk = current;
unsigned long flags; struct key *key, *ret, *err;
struct key *key, *ret, *err, *tmp;
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* searchable, but we failed to find a key or we found a negative key; * searchable, but we failed to find a key or we found a negative key;
@ -436,17 +435,18 @@ struct key *search_process_keyrings_aux(struct key_type *type,
} }
/* search the session keyring last */ /* search the session keyring last */
spin_lock_irqsave(&tsk->sighand->siglock, flags); if (tsk->signal->session_keyring) {
rcu_read_lock();
key = keyring_search_aux(
rcu_dereference(tsk->signal->session_keyring),
type, description, match);
rcu_read_unlock();
}
else {
key = keyring_search_aux(tsk->user->session_keyring,
type, description, match);
}
tmp = tsk->signal->session_keyring;
if (!tmp)
tmp = tsk->user->session_keyring;
atomic_inc(&tmp->usage);
spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
key = keyring_search_aux(tmp, type, description, match);
key_put(tmp);
if (!IS_ERR(key)) if (!IS_ERR(key))
goto found; goto found;

View File

@ -175,13 +175,12 @@ static struct key *__request_key_construction(struct key_type *type,
key->expiry = now.tv_sec + key_negative_timeout; key->expiry = now.tv_sec + key_negative_timeout;
if (current->signal->session_keyring) { if (current->signal->session_keyring) {
unsigned long flags;
struct key *keyring; struct key *keyring;
spin_lock_irqsave(&current->sighand->siglock, flags); rcu_read_lock();
keyring = current->signal->session_keyring; keyring = rcu_dereference(current->signal->session_keyring);
atomic_inc(&keyring->usage); atomic_inc(&keyring->usage);
spin_unlock_irqrestore(&current->sighand->siglock, flags); rcu_read_unlock();
key_link(keyring, key); key_link(keyring, key);
key_put(keyring); key_put(keyring);