Commit 1a26feb9 authored by David Howells's avatar David Howells Committed by Linus Torvalds

[PATCH] Keys: Improve usage of memory barriers and remove IRQ disablement

Remove an unnecessary memory barrier (implicit in rcu_dereference()) from
install_session_keyring().

install_session_keyring() is also rearranged a little to make it slightly
more efficient.

As install_*_keyring() may schedule (in synchronize_rcu() or
keyring_alloc()), they may not be entered with interrupts disabled - and so
there's no point saving the interrupt disablement state over the critical
section.

exec_keys() will also be invoked with interrupts enabled, and so that doesn't
need to save the interrupt state either.
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 25a80759
...@@ -168,11 +168,12 @@ error: ...@@ -168,11 +168,12 @@ error:
*/ */
int install_process_keyring(struct task_struct *tsk) int install_process_keyring(struct task_struct *tsk)
{ {
unsigned long flags;
struct key *keyring; struct key *keyring;
char buf[20]; char buf[20];
int ret; int ret;
might_sleep();
if (!tsk->signal->process_keyring) { if (!tsk->signal->process_keyring) {
sprintf(buf, "_pid.%u", tsk->tgid); sprintf(buf, "_pid.%u", tsk->tgid);
...@@ -183,12 +184,12 @@ int install_process_keyring(struct task_struct *tsk) ...@@ -183,12 +184,12 @@ int install_process_keyring(struct task_struct *tsk)
} }
/* attach keyring */ /* attach keyring */
spin_lock_irqsave(&tsk->sighand->siglock, flags); spin_lock_irq(&tsk->sighand->siglock);
if (!tsk->signal->process_keyring) { if (!tsk->signal->process_keyring) {
tsk->signal->process_keyring = keyring; tsk->signal->process_keyring = keyring;
keyring = NULL; keyring = NULL;
} }
spin_unlock_irqrestore(&tsk->sighand->siglock, flags); spin_unlock_irq(&tsk->sighand->siglock);
key_put(keyring); key_put(keyring);
} }
...@@ -207,38 +208,37 @@ error: ...@@ -207,38 +208,37 @@ error:
static int install_session_keyring(struct task_struct *tsk, static int install_session_keyring(struct task_struct *tsk,
struct key *keyring) struct key *keyring)
{ {
unsigned long flags;
struct key *old; struct key *old;
char buf[20]; char buf[20];
int ret;
might_sleep();
/* create an empty session keyring */ /* create an empty session keyring */
if (!keyring) { if (!keyring) {
sprintf(buf, "_ses.%u", tsk->tgid); sprintf(buf, "_ses.%u", tsk->tgid);
keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
if (IS_ERR(keyring)) { if (IS_ERR(keyring))
ret = PTR_ERR(keyring); return PTR_ERR(keyring);
goto error;
}
} }
else { else {
atomic_inc(&keyring->usage); atomic_inc(&keyring->usage);
} }
/* install the keyring */ /* install the keyring */
spin_lock_irqsave(&tsk->sighand->siglock, flags); spin_lock_irq(&tsk->sighand->siglock);
old = rcu_dereference(tsk->signal->session_keyring); old = tsk->signal->session_keyring;
rcu_assign_pointer(tsk->signal->session_keyring, keyring); rcu_assign_pointer(tsk->signal->session_keyring, keyring);
spin_unlock_irqrestore(&tsk->sighand->siglock, flags); spin_unlock_irq(&tsk->sighand->siglock);
ret = 0; /* we're using RCU on the pointer, but there's no point synchronising
* on it if it didn't previously point to anything */
if (old) {
synchronize_rcu();
key_put(old);
}
/* we're using RCU on the pointer */ return 0;
synchronize_rcu();
key_put(old);
error:
return ret;
} /* end install_session_keyring() */ } /* end install_session_keyring() */
...@@ -311,7 +311,6 @@ void exit_keys(struct task_struct *tsk) ...@@ -311,7 +311,6 @@ void exit_keys(struct task_struct *tsk)
*/ */
int exec_keys(struct task_struct *tsk) int exec_keys(struct task_struct *tsk)
{ {
unsigned long flags;
struct key *old; struct key *old;
/* newly exec'd tasks don't get a thread keyring */ /* newly exec'd tasks don't get a thread keyring */
...@@ -323,10 +322,10 @@ int exec_keys(struct task_struct *tsk) ...@@ -323,10 +322,10 @@ int exec_keys(struct task_struct *tsk)
key_put(old); key_put(old);
/* discard the process keyring from a newly exec'd task */ /* discard the process keyring from a newly exec'd task */
spin_lock_irqsave(&tsk->sighand->siglock, flags); spin_lock_irq(&tsk->sighand->siglock);
old = tsk->signal->process_keyring; old = tsk->signal->process_keyring;
tsk->signal->process_keyring = NULL; tsk->signal->process_keyring = NULL;
spin_unlock_irqrestore(&tsk->sighand->siglock, flags); spin_unlock_irq(&tsk->sighand->siglock);
key_put(old); key_put(old);
......
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