aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/sem.c
diff options
context:
space:
mode:
authorDavidlohr Bueso <davidlohr.bueso@hp.com>2013-07-08 19:01:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-09 13:33:27 -0400
commit7b4cc5d8411bd4e9d61d8714f53859740cf830c2 (patch)
treeb95f3b875a5f4c927b0f27cc3c7ddcba5cc8e1e8 /ipc/sem.c
parentcf9d5d78d05bca96df7618dfc3a5ee4414dcae58 (diff)
ipc: move locking out of ipcctl_pre_down_nolock
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>
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 92ec6c69bab5..b4b892b5c5f8 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1289,39 +1289,44 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
1289 return -EFAULT; 1289 return -EFAULT;
1290 } 1290 }
1291 1291
1292 down_write(&sem_ids(ns).rw_mutex);
1293 rcu_read_lock();
1294
1292 ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd, 1295 ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd,
1293 &semid64.sem_perm, 0); 1296 &semid64.sem_perm, 0);
1294 if (IS_ERR(ipcp)) 1297 if (IS_ERR(ipcp)) {
1295 return PTR_ERR(ipcp); 1298 err = PTR_ERR(ipcp);
1299 /* the ipc lock is not held upon failure */
1300 goto out_unlock1;
1301 }
1296 1302
1297 sma = container_of(ipcp, struct sem_array, sem_perm); 1303 sma = container_of(ipcp, struct sem_array, sem_perm);
1298 1304
1299 err = security_sem_semctl(sma, cmd); 1305 err = security_sem_semctl(sma, cmd);
1300 if (err) { 1306 if (err)
1301 rcu_read_unlock(); 1307 goto out_unlock1;
1302 goto out_up;
1303 }
1304 1308
1305 switch(cmd){ 1309 switch (cmd) {
1306 case IPC_RMID: 1310 case IPC_RMID:
1307 sem_lock(sma, NULL, -1); 1311 sem_lock(sma, NULL, -1);
1312 /* freeary unlocks the ipc object and rcu */
1308 freeary(ns, ipcp); 1313 freeary(ns, ipcp);
1309 goto out_up; 1314 goto out_up;
1310 case IPC_SET: 1315 case IPC_SET:
1311 sem_lock(sma, NULL, -1); 1316 sem_lock(sma, NULL, -1);
1312 err = ipc_update_perm(&semid64.sem_perm, ipcp); 1317 err = ipc_update_perm(&semid64.sem_perm, ipcp);
1313 if (err) 1318 if (err)
1314 goto out_unlock; 1319 goto out_unlock0;
1315 sma->sem_ctime = get_seconds(); 1320 sma->sem_ctime = get_seconds();
1316 break; 1321 break;
1317 default: 1322 default:
1318 rcu_read_unlock();
1319 err = -EINVAL; 1323 err = -EINVAL;
1320 goto out_up; 1324 goto out_unlock1;
1321 } 1325 }
1322 1326
1323out_unlock: 1327out_unlock0:
1324 sem_unlock(sma, -1); 1328 sem_unlock(sma, -1);
1329out_unlock1:
1325 rcu_read_unlock(); 1330 rcu_read_unlock();
1326out_up: 1331out_up:
1327 up_write(&sem_ids(ns).rw_mutex); 1332 up_write(&sem_ids(ns).rw_mutex);