[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:
parent
7888e7ff4e
commit
8589b4e00e
2 changed files with 24 additions and 25 deletions
|
@ -1,6 +1,6 @@
|
|||
/* 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)
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/* attach or swap keyrings */
|
||||
/* attach keyring */
|
||||
spin_lock_irqsave(&tsk->sighand->siglock, flags);
|
||||
if (!tsk->signal->process_keyring) {
|
||||
tsk->signal->process_keyring = keyring;
|
||||
|
@ -227,12 +227,14 @@ static int install_session_keyring(struct task_struct *tsk,
|
|||
|
||||
/* install the keyring */
|
||||
spin_lock_irqsave(&tsk->sighand->siglock, flags);
|
||||
old = tsk->signal->session_keyring;
|
||||
tsk->signal->session_keyring = keyring;
|
||||
old = rcu_dereference(tsk->signal->session_keyring);
|
||||
rcu_assign_pointer(tsk->signal->session_keyring, keyring);
|
||||
spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
|
||||
|
||||
ret = 0;
|
||||
|
||||
/* we're using RCU on the pointer */
|
||||
synchronize_kernel();
|
||||
key_put(old);
|
||||
error:
|
||||
return ret;
|
||||
|
@ -245,8 +247,6 @@ static int install_session_keyring(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->process_keyring);
|
||||
|
||||
|
@ -254,10 +254,10 @@ int copy_thread_group_keys(struct task_struct *tsk)
|
|||
tsk->signal->process_keyring = NULL;
|
||||
|
||||
/* same session keyring */
|
||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||
rcu_read_lock();
|
||||
tsk->signal->session_keyring =
|
||||
key_get(current->signal->session_keyring);
|
||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||
key_get(rcu_dereference(current->signal->session_keyring));
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -381,8 +381,7 @@ struct key *search_process_keyrings_aux(struct key_type *type,
|
|||
key_match_func_t match)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
unsigned long flags;
|
||||
struct key *key, *ret, *err, *tmp;
|
||||
struct key *key, *ret, *err;
|
||||
|
||||
/* 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;
|
||||
|
@ -436,17 +435,18 @@ struct key *search_process_keyrings_aux(struct key_type *type,
|
|||
}
|
||||
|
||||
/* 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))
|
||||
goto found;
|
||||
|
||||
|
|
|
@ -175,13 +175,12 @@ static struct key *__request_key_construction(struct key_type *type,
|
|||
key->expiry = now.tv_sec + key_negative_timeout;
|
||||
|
||||
if (current->signal->session_keyring) {
|
||||
unsigned long flags;
|
||||
struct key *keyring;
|
||||
|
||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||
keyring = current->signal->session_keyring;
|
||||
rcu_read_lock();
|
||||
keyring = rcu_dereference(current->signal->session_keyring);
|
||||
atomic_inc(&keyring->usage);
|
||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||
rcu_read_unlock();
|
||||
|
||||
key_link(keyring, key);
|
||||
key_put(keyring);
|
||||
|
|
Loading…
Reference in a new issue