diff options
author | Davidlohr Bueso <davidlohr.bueso@hp.com> | 2013-07-08 19:01:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-09 13:33:27 -0400 |
commit | 7b4cc5d8411bd4e9d61d8714f53859740cf830c2 (patch) | |
tree | b95f3b875a5f4c927b0f27cc3c7ddcba5cc8e1e8 /ipc/sem.c | |
parent | cf9d5d78d05bca96df7618dfc3a5ee4414dcae58 (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.c | 27 |
1 files changed, 16 insertions, 11 deletions
@@ -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 | ||
1323 | out_unlock: | 1327 | out_unlock0: |
1324 | sem_unlock(sma, -1); | 1328 | sem_unlock(sma, -1); |
1329 | out_unlock1: | ||
1325 | rcu_read_unlock(); | 1330 | rcu_read_unlock(); |
1326 | out_up: | 1331 | out_up: |
1327 | up_write(&sem_ids(ns).rw_mutex); | 1332 | up_write(&sem_ids(ns).rw_mutex); |