Commit 8589b4e0 authored by David Howells's avatar David Howells Committed by Linus Torvalds

[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: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 7888e7ff
/* 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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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();
tmp = tsk->signal->session_keyring; key = keyring_search_aux(
if (!tmp) rcu_dereference(tsk->signal->session_keyring),
tmp = tsk->user->session_keyring; type, description, match);
atomic_inc(&tmp->usage); rcu_read_unlock();
}
spin_unlock_irqrestore(&tsk->sighand->siglock, flags); else {
key = keyring_search_aux(tsk->user->session_keyring,
type, description, match);
}
key = keyring_search_aux(tmp, type, description, match);
key_put(tmp);
if (!IS_ERR(key)) if (!IS_ERR(key))
goto found; goto found;
......
...@@ -175,13 +175,12 @@ static struct key *__request_key_construction(struct key_type *type, ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment