aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/msg.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/msg.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/msg.c')
-rw-r--r--ipc/msg.c41
1 files changed, 29 insertions, 12 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index b7274dbf0917..413bf9c7aec3 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -34,7 +34,7 @@
34#include <linux/syscalls.h> 34#include <linux/syscalls.h>
35#include <linux/audit.h> 35#include <linux/audit.h>
36#include <linux/seq_file.h> 36#include <linux/seq_file.h>
37#include <linux/mutex.h> 37#include <linux/rwsem.h>
38#include <linux/nsproxy.h> 38#include <linux/nsproxy.h>
39 39
40#include <asm/current.h> 40#include <asm/current.h>
@@ -110,7 +110,7 @@ void msg_exit_ns(struct ipc_namespace *ns)
110 int next_id; 110 int next_id;
111 int total, in_use; 111 int total, in_use;
112 112
113 mutex_lock(&msg_ids(ns).mutex); 113 down_write(&msg_ids(ns).rw_mutex);
114 114
115 in_use = msg_ids(ns).in_use; 115 in_use = msg_ids(ns).in_use;
116 116
@@ -122,7 +122,8 @@ void msg_exit_ns(struct ipc_namespace *ns)
122 freeque(ns, msq); 122 freeque(ns, msq);
123 total++; 123 total++;
124 } 124 }
125 mutex_unlock(&msg_ids(ns).mutex); 125
126 up_write(&msg_ids(ns).rw_mutex);
126 127
127 kfree(ns->ids[IPC_MSG_IDS]); 128 kfree(ns->ids[IPC_MSG_IDS]);
128 ns->ids[IPC_MSG_IDS] = NULL; 129 ns->ids[IPC_MSG_IDS] = NULL;
@@ -136,6 +137,22 @@ void __init msg_init(void)
136 IPC_MSG_IDS, sysvipc_msg_proc_show); 137 IPC_MSG_IDS, sysvipc_msg_proc_show);
137} 138}
138 139
140/*
141 * This routine is called in the paths where the rw_mutex is held to protect
142 * access to the idr tree.
143 */
144static inline struct msg_queue *msg_lock_check_down(struct ipc_namespace *ns,
145 int id)
146{
147 struct kern_ipc_perm *ipcp = ipc_lock_check_down(&msg_ids(ns), id);
148
149 return container_of(ipcp, struct msg_queue, q_perm);
150}
151
152/*
153 * msg_lock_(check_) routines are called in the paths where the rw_mutex
154 * is not held.
155 */
139static inline struct msg_queue *msg_lock(struct ipc_namespace *ns, int id) 156static inline struct msg_queue *msg_lock(struct ipc_namespace *ns, int id)
140{ 157{
141 struct kern_ipc_perm *ipcp = ipc_lock(&msg_ids(ns), id); 158 struct kern_ipc_perm *ipcp = ipc_lock(&msg_ids(ns), id);
@@ -161,7 +178,7 @@ static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
161 * @ns: namespace 178 * @ns: namespace
162 * @params: ptr to the structure that contains the key and msgflg 179 * @params: ptr to the structure that contains the key and msgflg
163 * 180 *
164 * Called with msg_ids.mutex held 181 * Called with msg_ids.rw_mutex held (writer)
165 */ 182 */
166static int newque(struct ipc_namespace *ns, struct ipc_params *params) 183static int newque(struct ipc_namespace *ns, struct ipc_params *params)
167{ 184{
@@ -260,8 +277,8 @@ static void expunge_all(struct msg_queue *msq, int res)
260 * removes the message queue from message queue ID IDR, and cleans up all the 277 * removes the message queue from message queue ID IDR, and cleans up all the
261 * messages associated with this queue. 278 * messages associated with this queue.
262 * 279 *
263 * msg_ids.mutex and the spinlock for this message queue are held 280 * msg_ids.rw_mutex (writer) and the spinlock for this message queue are held
264 * before freeque() is called. msg_ids.mutex remains locked on exit. 281 * before freeque() is called. msg_ids.rw_mutex remains locked on exit.
265 */ 282 */
266static void freeque(struct ipc_namespace *ns, struct msg_queue *msq) 283static void freeque(struct ipc_namespace *ns, struct msg_queue *msq)
267{ 284{
@@ -286,7 +303,7 @@ static void freeque(struct ipc_namespace *ns, struct msg_queue *msq)
286} 303}
287 304
288/* 305/*
289 * Called with msg_ids.mutex and ipcp locked. 306 * Called with msg_ids.rw_mutex and ipcp locked.
290 */ 307 */
291static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg) 308static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg)
292{ 309{
@@ -444,7 +461,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
444 msginfo.msgmnb = ns->msg_ctlmnb; 461 msginfo.msgmnb = ns->msg_ctlmnb;
445 msginfo.msgssz = MSGSSZ; 462 msginfo.msgssz = MSGSSZ;
446 msginfo.msgseg = MSGSEG; 463 msginfo.msgseg = MSGSEG;
447 mutex_lock(&msg_ids(ns).mutex); 464 down_read(&msg_ids(ns).rw_mutex);
448 if (cmd == MSG_INFO) { 465 if (cmd == MSG_INFO) {
449 msginfo.msgpool = msg_ids(ns).in_use; 466 msginfo.msgpool = msg_ids(ns).in_use;
450 msginfo.msgmap = atomic_read(&msg_hdrs); 467 msginfo.msgmap = atomic_read(&msg_hdrs);
@@ -455,7 +472,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
455 msginfo.msgtql = MSGTQL; 472 msginfo.msgtql = MSGTQL;
456 } 473 }
457 max_id = ipc_get_maxid(&msg_ids(ns)); 474 max_id = ipc_get_maxid(&msg_ids(ns));
458 mutex_unlock(&msg_ids(ns).mutex); 475 up_read(&msg_ids(ns).rw_mutex);
459 if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) 476 if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
460 return -EFAULT; 477 return -EFAULT;
461 return (max_id < 0) ? 0 : max_id; 478 return (max_id < 0) ? 0 : max_id;
@@ -516,8 +533,8 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
516 return -EINVAL; 533 return -EINVAL;
517 } 534 }
518 535
519 mutex_lock(&msg_ids(ns).mutex); 536 down_write(&msg_ids(ns).rw_mutex);
520 msq = msg_lock_check(ns, msqid); 537 msq = msg_lock_check_down(ns, msqid);
521 if (IS_ERR(msq)) { 538 if (IS_ERR(msq)) {
522 err = PTR_ERR(msq); 539 err = PTR_ERR(msq);
523 goto out_up; 540 goto out_up;
@@ -576,7 +593,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
576 } 593 }
577 err = 0; 594 err = 0;
578out_up: 595out_up:
579 mutex_unlock(&msg_ids(ns).mutex); 596 up_write(&msg_ids(ns).rw_mutex);
580 return err; 597 return err;
581out_unlock_up: 598out_unlock_up:
582 msg_unlock(msq); 599 msg_unlock(msq);