summaryrefslogtreecommitdiff
path: root/ipc/sem.c
diff options
context:
space:
mode:
authorDavidlohr Bueso <davidlohr.bueso@hp.com>2013-07-08 16:01:12 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-10-18 07:45:46 -0700
commitac9bc6e396285ab732dd869c3edb353662134022 (patch)
tree182b0be2e0238d96e02c8669e372c254d6ea81a1 /ipc/sem.c
parent115d40dbef93b70e6f32732b0fdd5903c1f7fce4 (diff)
downloadlinux-3.10-ac9bc6e396285ab732dd869c3edb353662134022.tar.gz
linux-3.10-ac9bc6e396285ab732dd869c3edb353662134022.tar.bz2
linux-3.10-ac9bc6e396285ab732dd869c3edb353662134022.zip
ipc: move locking out of ipcctl_pre_down_nolock
commit 7b4cc5d8411bd4e9d61d8714f53859740cf830c2 upstream. This function currently acquires both the rw_mutex and the rcu lock on successful lookups, leaving the callers to explicitly unlock them, creating another two level locking situation. Make the callers (including those that still use ipcctl_pre_down()) explicitly lock and unlock the rwsem and rcu lock. Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Rik van Riel <riel@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mike Galbraith <efault@gmx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'ipc/sem.c')
-rw-r--r--ipc/sem.c27
1 files changed, 16 insertions, 11 deletions
diff --git a/ipc/sem.c b/ipc/sem.c
index 92ec6c69bab..b4b892b5c5f 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1289,39 +1289,44 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
return -EFAULT;
}
+ down_write(&sem_ids(ns).rw_mutex);
+ rcu_read_lock();
+
ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd,
&semid64.sem_perm, 0);
- if (IS_ERR(ipcp))
- return PTR_ERR(ipcp);
+ if (IS_ERR(ipcp)) {
+ err = PTR_ERR(ipcp);
+ /* the ipc lock is not held upon failure */
+ goto out_unlock1;
+ }
sma = container_of(ipcp, struct sem_array, sem_perm);
err = security_sem_semctl(sma, cmd);
- if (err) {
- rcu_read_unlock();
- goto out_up;
- }
+ if (err)
+ goto out_unlock1;
- switch(cmd){
+ switch (cmd) {
case IPC_RMID:
sem_lock(sma, NULL, -1);
+ /* freeary unlocks the ipc object and rcu */
freeary(ns, ipcp);
goto out_up;
case IPC_SET:
sem_lock(sma, NULL, -1);
err = ipc_update_perm(&semid64.sem_perm, ipcp);
if (err)
- goto out_unlock;
+ goto out_unlock0;
sma->sem_ctime = get_seconds();
break;
default:
- rcu_read_unlock();
err = -EINVAL;
- goto out_up;
+ goto out_unlock1;
}
-out_unlock:
+out_unlock0:
sem_unlock(sma, -1);
+out_unlock1:
rcu_read_unlock();
out_up:
up_write(&sem_ids(ns).rw_mutex);