aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/shm.c
diff options
context:
space:
mode:
authorNadia Derbey <Nadia.Derbey@bull.net>2007-10-19 02:40:54 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-19 14:53:48 -0400
commit3e148c79938aa39035669c1cfa3ff60722134535 (patch)
tree0effb3edfece56ea38a9727ec8f4721d9a4c3ea8 /ipc/shm.c
parentf4566f04854d78acfc74b9acb029744acde9d033 (diff)
fix idr_find() locking
This is a patch that fixes the way idr_find() used to be called in ipc_lock(): in all the paths that don't imply an update of the ipcs idr, it was called without the idr tree being locked. The changes are: . in ipc_ids, the mutex has been changed into a reader/writer semaphore. . ipc_lock() now takes the mutex as a reader during the idr_find(). . a new routine ipc_lock_down() has been defined: it doesn't take the mutex, assuming that it is being held by the caller. This is the routine that is now called in all the update paths. Signed-off-by: Nadia Derbey <Nadia.Derbey@bull.net> Acked-by: Jarek Poplawski <jarkao2@o2.pl> 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.c77
1 files changed, 51 insertions, 26 deletions
diff --git a/ipc/shm.c b/ipc/shm.c
index f28f2a3163e1..b27d31f3aaba 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -35,7 +35,7 @@
35#include <linux/capability.h> 35#include <linux/capability.h>
36#include <linux/ptrace.h> 36#include <linux/ptrace.h>
37#include <linux/seq_file.h> 37#include <linux/seq_file.h>
38#include <linux/mutex.h> 38#include <linux/rwsem.h>
39#include <linux/nsproxy.h> 39#include <linux/nsproxy.h>
40#include <linux/mount.h> 40#include <linux/mount.h>
41 41
@@ -83,8 +83,8 @@ static void __shm_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
83} 83}
84 84
85/* 85/*
86 * Called with shm_ids.mutex and the shp structure locked. 86 * Called with shm_ids.rw_mutex (writer) and the shp structure locked.
87 * Only shm_ids.mutex remains locked on exit. 87 * Only shm_ids.rw_mutex remains locked on exit.
88 */ 88 */
89static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp) 89static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp)
90{ 90{
@@ -115,7 +115,7 @@ void shm_exit_ns(struct ipc_namespace *ns)
115 int next_id; 115 int next_id;
116 int total, in_use; 116 int total, in_use;
117 117
118 mutex_lock(&shm_ids(ns).mutex); 118 down_write(&shm_ids(ns).rw_mutex);
119 119
120 in_use = shm_ids(ns).in_use; 120 in_use = shm_ids(ns).in_use;
121 121
@@ -127,7 +127,7 @@ void shm_exit_ns(struct ipc_namespace *ns)
127 do_shm_rmid(ns, shp); 127 do_shm_rmid(ns, shp);
128 total++; 128 total++;
129 } 129 }
130 mutex_unlock(&shm_ids(ns).mutex); 130 up_write(&shm_ids(ns).rw_mutex);
131 131
132 kfree(ns->ids[IPC_SHM_IDS]); 132 kfree(ns->ids[IPC_SHM_IDS]);
133 ns->ids[IPC_SHM_IDS] = NULL; 133 ns->ids[IPC_SHM_IDS] = NULL;
@@ -141,6 +141,31 @@ void __init shm_init (void)
141 IPC_SHM_IDS, sysvipc_shm_proc_show); 141 IPC_SHM_IDS, sysvipc_shm_proc_show);
142} 142}
143 143
144/*
145 * shm_lock_(check_)down routines are called in the paths where the rw_mutex
146 * is held to protect access to the idr tree.
147 */
148static inline struct shmid_kernel *shm_lock_down(struct ipc_namespace *ns,
149 int id)
150{
151 struct kern_ipc_perm *ipcp = ipc_lock_down(&shm_ids(ns), id);
152
153 return container_of(ipcp, struct shmid_kernel, shm_perm);
154}
155
156static inline struct shmid_kernel *shm_lock_check_down(
157 struct ipc_namespace *ns,
158 int id)
159{
160 struct kern_ipc_perm *ipcp = ipc_lock_check_down(&shm_ids(ns), id);
161
162 return container_of(ipcp, struct shmid_kernel, shm_perm);
163}
164
165/*
166 * shm_lock_(check_) routines are called in the paths where the rw_mutex
167 * is not held.
168 */
144static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id) 169static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
145{ 170{
146 struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id); 171 struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
@@ -189,7 +214,7 @@ static void shm_open(struct vm_area_struct *vma)
189 * @ns: namespace 214 * @ns: namespace
190 * @shp: struct to free 215 * @shp: struct to free
191 * 216 *
192 * It has to be called with shp and shm_ids.mutex locked, 217 * It has to be called with shp and shm_ids.rw_mutex (writer) locked,
193 * but returns with shp unlocked and freed. 218 * but returns with shp unlocked and freed.
194 */ 219 */
195static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) 220static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
@@ -220,9 +245,9 @@ static void shm_close(struct vm_area_struct *vma)
220 struct shmid_kernel *shp; 245 struct shmid_kernel *shp;
221 struct ipc_namespace *ns = sfd->ns; 246 struct ipc_namespace *ns = sfd->ns;
222 247
223 mutex_lock(&shm_ids(ns).mutex); 248 down_write(&shm_ids(ns).rw_mutex);
224 /* remove from the list of attaches of the shm segment */ 249 /* remove from the list of attaches of the shm segment */
225 shp = shm_lock(ns, sfd->id); 250 shp = shm_lock_down(ns, sfd->id);
226 BUG_ON(IS_ERR(shp)); 251 BUG_ON(IS_ERR(shp));
227 shp->shm_lprid = task_tgid_vnr(current); 252 shp->shm_lprid = task_tgid_vnr(current);
228 shp->shm_dtim = get_seconds(); 253 shp->shm_dtim = get_seconds();
@@ -232,7 +257,7 @@ static void shm_close(struct vm_area_struct *vma)
232 shm_destroy(ns, shp); 257 shm_destroy(ns, shp);
233 else 258 else
234 shm_unlock(shp); 259 shm_unlock(shp);
235 mutex_unlock(&shm_ids(ns).mutex); 260 up_write(&shm_ids(ns).rw_mutex);
236} 261}
237 262
238static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 263static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -353,7 +378,7 @@ static struct vm_operations_struct shm_vm_ops = {
353 * @ns: namespace 378 * @ns: namespace
354 * @params: ptr to the structure that contains key, size and shmflg 379 * @params: ptr to the structure that contains key, size and shmflg
355 * 380 *
356 * Called with shm_ids.mutex held 381 * Called with shm_ids.rw_mutex held as a writer.
357 */ 382 */
358 383
359static int newseg(struct ipc_namespace *ns, struct ipc_params *params) 384static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
@@ -442,7 +467,7 @@ no_file:
442} 467}
443 468
444/* 469/*
445 * Called with shm_ids.mutex and ipcp locked. 470 * Called with shm_ids.rw_mutex and ipcp locked.
446 */ 471 */
447static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg) 472static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
448{ 473{
@@ -453,7 +478,7 @@ static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
453} 478}
454 479
455/* 480/*
456 * Called with shm_ids.mutex and ipcp locked. 481 * Called with shm_ids.rw_mutex and ipcp locked.
457 */ 482 */
458static inline int shm_more_checks(struct kern_ipc_perm *ipcp, 483static inline int shm_more_checks(struct kern_ipc_perm *ipcp,
459 struct ipc_params *params) 484 struct ipc_params *params)
@@ -578,7 +603,7 @@ static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminf
578} 603}
579 604
580/* 605/*
581 * Called with shm_ids.mutex held 606 * Called with shm_ids.rw_mutex held as a reader
582 */ 607 */
583static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, 608static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
584 unsigned long *swp) 609 unsigned long *swp)
@@ -649,9 +674,9 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
649 if(copy_shminfo_to_user (buf, &shminfo, version)) 674 if(copy_shminfo_to_user (buf, &shminfo, version))
650 return -EFAULT; 675 return -EFAULT;
651 676
652 mutex_lock(&shm_ids(ns).mutex); 677 down_read(&shm_ids(ns).rw_mutex);
653 err = ipc_get_maxid(&shm_ids(ns)); 678 err = ipc_get_maxid(&shm_ids(ns));
654 mutex_unlock(&shm_ids(ns).mutex); 679 up_read(&shm_ids(ns).rw_mutex);
655 680
656 if(err<0) 681 if(err<0)
657 err = 0; 682 err = 0;
@@ -666,14 +691,14 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
666 return err; 691 return err;
667 692
668 memset(&shm_info,0,sizeof(shm_info)); 693 memset(&shm_info,0,sizeof(shm_info));
669 mutex_lock(&shm_ids(ns).mutex); 694 down_read(&shm_ids(ns).rw_mutex);
670 shm_info.used_ids = shm_ids(ns).in_use; 695 shm_info.used_ids = shm_ids(ns).in_use;
671 shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp); 696 shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp);
672 shm_info.shm_tot = ns->shm_tot; 697 shm_info.shm_tot = ns->shm_tot;
673 shm_info.swap_attempts = 0; 698 shm_info.swap_attempts = 0;
674 shm_info.swap_successes = 0; 699 shm_info.swap_successes = 0;
675 err = ipc_get_maxid(&shm_ids(ns)); 700 err = ipc_get_maxid(&shm_ids(ns));
676 mutex_unlock(&shm_ids(ns).mutex); 701 up_read(&shm_ids(ns).rw_mutex);
677 if(copy_to_user (buf, &shm_info, sizeof(shm_info))) { 702 if(copy_to_user (buf, &shm_info, sizeof(shm_info))) {
678 err = -EFAULT; 703 err = -EFAULT;
679 goto out; 704 goto out;
@@ -786,8 +811,8 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
786 * Instead we set a destroyed flag, and then blow 811 * Instead we set a destroyed flag, and then blow
787 * the name away when the usage hits zero. 812 * the name away when the usage hits zero.
788 */ 813 */
789 mutex_lock(&shm_ids(ns).mutex); 814 down_write(&shm_ids(ns).rw_mutex);
790 shp = shm_lock_check(ns, shmid); 815 shp = shm_lock_check_down(ns, shmid);
791 if (IS_ERR(shp)) { 816 if (IS_ERR(shp)) {
792 err = PTR_ERR(shp); 817 err = PTR_ERR(shp);
793 goto out_up; 818 goto out_up;
@@ -809,7 +834,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
809 goto out_unlock_up; 834 goto out_unlock_up;
810 835
811 do_shm_rmid(ns, shp); 836 do_shm_rmid(ns, shp);
812 mutex_unlock(&shm_ids(ns).mutex); 837 up_write(&shm_ids(ns).rw_mutex);
813 goto out; 838 goto out;
814 } 839 }
815 840
@@ -824,8 +849,8 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
824 err = -EFAULT; 849 err = -EFAULT;
825 goto out; 850 goto out;
826 } 851 }
827 mutex_lock(&shm_ids(ns).mutex); 852 down_write(&shm_ids(ns).rw_mutex);
828 shp = shm_lock_check(ns, shmid); 853 shp = shm_lock_check_down(ns, shmid);
829 if (IS_ERR(shp)) { 854 if (IS_ERR(shp)) {
830 err = PTR_ERR(shp); 855 err = PTR_ERR(shp);
831 goto out_up; 856 goto out_up;
@@ -864,7 +889,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
864out_unlock_up: 889out_unlock_up:
865 shm_unlock(shp); 890 shm_unlock(shp);
866out_up: 891out_up:
867 mutex_unlock(&shm_ids(ns).mutex); 892 up_write(&shm_ids(ns).rw_mutex);
868 goto out; 893 goto out;
869out_unlock: 894out_unlock:
870 shm_unlock(shp); 895 shm_unlock(shp);
@@ -998,8 +1023,8 @@ invalid:
998 fput(file); 1023 fput(file);
999 1024
1000out_nattch: 1025out_nattch:
1001 mutex_lock(&shm_ids(ns).mutex); 1026 down_write(&shm_ids(ns).rw_mutex);
1002 shp = shm_lock(ns, shmid); 1027 shp = shm_lock_down(ns, shmid);
1003 BUG_ON(IS_ERR(shp)); 1028 BUG_ON(IS_ERR(shp));
1004 shp->shm_nattch--; 1029 shp->shm_nattch--;
1005 if(shp->shm_nattch == 0 && 1030 if(shp->shm_nattch == 0 &&
@@ -1007,7 +1032,7 @@ out_nattch:
1007 shm_destroy(ns, shp); 1032 shm_destroy(ns, shp);
1008 else 1033 else
1009 shm_unlock(shp); 1034 shm_unlock(shp);
1010 mutex_unlock(&shm_ids(ns).mutex); 1035 up_write(&shm_ids(ns).rw_mutex);
1011 1036
1012out: 1037out:
1013 return err; 1038 return err;