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/shm.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/shm.c')
-rw-r--r-- | ipc/shm.c | 23 |
1 files changed, 17 insertions, 6 deletions
@@ -757,31 +757,42 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd, | |||
757 | return -EFAULT; | 757 | return -EFAULT; |
758 | } | 758 | } |
759 | 759 | ||
760 | down_write(&shm_ids(ns).rw_mutex); | ||
761 | rcu_read_lock(); | ||
762 | |||
760 | ipcp = ipcctl_pre_down(ns, &shm_ids(ns), shmid, cmd, | 763 | ipcp = ipcctl_pre_down(ns, &shm_ids(ns), shmid, cmd, |
761 | &shmid64.shm_perm, 0); | 764 | &shmid64.shm_perm, 0); |
762 | if (IS_ERR(ipcp)) | 765 | if (IS_ERR(ipcp)) { |
763 | return PTR_ERR(ipcp); | 766 | err = PTR_ERR(ipcp); |
767 | /* the ipc lock is not held upon failure */ | ||
768 | goto out_unlock1; | ||
769 | } | ||
764 | 770 | ||
765 | shp = container_of(ipcp, struct shmid_kernel, shm_perm); | 771 | shp = container_of(ipcp, struct shmid_kernel, shm_perm); |
766 | 772 | ||
767 | err = security_shm_shmctl(shp, cmd); | 773 | err = security_shm_shmctl(shp, cmd); |
768 | if (err) | 774 | if (err) |
769 | goto out_unlock; | 775 | goto out_unlock0; |
776 | |||
770 | switch (cmd) { | 777 | switch (cmd) { |
771 | case IPC_RMID: | 778 | case IPC_RMID: |
779 | /* do_shm_rmid unlocks the ipc object and rcu */ | ||
772 | do_shm_rmid(ns, ipcp); | 780 | do_shm_rmid(ns, ipcp); |
773 | goto out_up; | 781 | goto out_up; |
774 | case IPC_SET: | 782 | case IPC_SET: |
775 | err = ipc_update_perm(&shmid64.shm_perm, ipcp); | 783 | err = ipc_update_perm(&shmid64.shm_perm, ipcp); |
776 | if (err) | 784 | if (err) |
777 | goto out_unlock; | 785 | goto out_unlock0; |
778 | shp->shm_ctim = get_seconds(); | 786 | shp->shm_ctim = get_seconds(); |
779 | break; | 787 | break; |
780 | default: | 788 | default: |
781 | err = -EINVAL; | 789 | err = -EINVAL; |
782 | } | 790 | } |
783 | out_unlock: | 791 | |
784 | shm_unlock(shp); | 792 | out_unlock0: |
793 | ipc_unlock_object(&shp->shm_perm); | ||
794 | out_unlock1: | ||
795 | rcu_read_unlock(); | ||
785 | out_up: | 796 | out_up: |
786 | up_write(&shm_ids(ns).rw_mutex); | 797 | up_write(&shm_ids(ns).rw_mutex); |
787 | return err; | 798 | return err; |