From: David Howells Date: Tue, 11 Apr 2006 05:54:26 +0000 (-0700) Subject: [PATCH] Keys: Improve usage of memory barriers and remove IRQ disablement X-Git-Tag: v2.6.17-rc2~179 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1a26feb9622f1b1bc5e4f5f60f65557b73c38cbf;p=linux-2.6 [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: David Howells Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index f6940618e3..217a0bef3c 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -168,11 +168,12 @@ error: */ int install_process_keyring(struct task_struct *tsk) { - unsigned long flags; struct key *keyring; char buf[20]; int ret; + might_sleep(); + if (!tsk->signal->process_keyring) { sprintf(buf, "_pid.%u", tsk->tgid); @@ -183,12 +184,12 @@ int install_process_keyring(struct task_struct *tsk) } /* attach keyring */ - spin_lock_irqsave(&tsk->sighand->siglock, flags); + spin_lock_irq(&tsk->sighand->siglock); if (!tsk->signal->process_keyring) { tsk->signal->process_keyring = keyring; keyring = NULL; } - spin_unlock_irqrestore(&tsk->sighand->siglock, flags); + spin_unlock_irq(&tsk->sighand->siglock); key_put(keyring); } @@ -207,38 +208,37 @@ error: static int install_session_keyring(struct task_struct *tsk, struct key *keyring) { - unsigned long flags; struct key *old; char buf[20]; - int ret; + + might_sleep(); /* create an empty session keyring */ if (!keyring) { sprintf(buf, "_ses.%u", tsk->tgid); keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); - if (IS_ERR(keyring)) { - ret = PTR_ERR(keyring); - goto error; - } + if (IS_ERR(keyring)) + return PTR_ERR(keyring); } else { atomic_inc(&keyring->usage); } /* install the keyring */ - spin_lock_irqsave(&tsk->sighand->siglock, flags); - old = rcu_dereference(tsk->signal->session_keyring); + spin_lock_irq(&tsk->sighand->siglock); + old = tsk->signal->session_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 */ - synchronize_rcu(); - key_put(old); -error: - return ret; + return 0; } /* end install_session_keyring() */ @@ -311,7 +311,6 @@ void exit_keys(struct task_struct *tsk) */ int exec_keys(struct task_struct *tsk) { - unsigned long flags; struct key *old; /* newly exec'd tasks don't get a thread keyring */ @@ -323,10 +322,10 @@ int exec_keys(struct task_struct *tsk) key_put(old); /* 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; tsk->signal->process_keyring = NULL; - spin_unlock_irqrestore(&tsk->sighand->siglock, flags); + spin_unlock_irq(&tsk->sighand->siglock); key_put(old);