aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorDavidlohr Bueso <dave@stgolabs.net>2016-10-11 16:54:56 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-11 18:06:33 -0400
commite3658538bf3727383b4e563fbab83c04d615508a (patch)
tree55b66ab4eebb097928d8790b0be6add58ba64656 /ipc
parentee51636ca54f9d4d01ae49b1740742e9db54d868 (diff)
ipc/msg: batch queue sender wakeups
Currently the use of wake_qs in sysv msg queues are only for the receiver tasks that are blocked on the queue. But blocked sender tasks (due to queue size constraints) still are awoken with the ipc object lock held, which can be a problem particularly for small sized queues and far from gracious for -rt (just like it was for the receiver side). The paths that actually wakeup a sender are obviously related to when we are either getting rid of the queue or after (some) space is freed-up after a receiver takes the msg (msgrcv). Furthermore, with the exception of msgrcv, we can always piggy-back on expunge_all that has its own tasks lined-up for waking. Finally, upon unlinking the message, it should be no problem delaying the wakeups a bit until after we've released the lock. Link: http://lkml.kernel.org/r/1469748819-19484-3-git-send-email-dave@stgolabs.net Signed-off-by: Davidlohr Bueso <dbueso@suse.de> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Manfred Spraul <manfred@colorfullife.com> Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc')
-rw-r--r--ipc/msg.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index b1fb06a6a75b..d320024d6a5b 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -166,14 +166,15 @@ static inline void ss_del(struct msg_sender *mss)
166 list_del(&mss->list); 166 list_del(&mss->list);
167} 167}
168 168
169static void ss_wakeup(struct list_head *h, int kill) 169static void ss_wakeup(struct list_head *h,
170 struct wake_q_head *wake_q, int kill)
170{ 171{
171 struct msg_sender *mss, *t; 172 struct msg_sender *mss, *t;
172 173
173 list_for_each_entry_safe(mss, t, h, list) { 174 list_for_each_entry_safe(mss, t, h, list) {
174 if (kill) 175 if (kill)
175 mss->list.next = NULL; 176 mss->list.next = NULL;
176 wake_up_process(mss->tsk); 177 wake_q_add(wake_q, mss->tsk);
177 } 178 }
178} 179}
179 180
@@ -203,7 +204,7 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
203 WAKE_Q(wake_q); 204 WAKE_Q(wake_q);
204 205
205 expunge_all(msq, -EIDRM, &wake_q); 206 expunge_all(msq, -EIDRM, &wake_q);
206 ss_wakeup(&msq->q_senders, 1); 207 ss_wakeup(&msq->q_senders, &wake_q, 1);
207 msg_rmid(ns, msq); 208 msg_rmid(ns, msq);
208 ipc_unlock_object(&msq->q_perm); 209 ipc_unlock_object(&msq->q_perm);
209 wake_up_q(&wake_q); 210 wake_up_q(&wake_q);
@@ -331,7 +332,6 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
331 struct kern_ipc_perm *ipcp; 332 struct kern_ipc_perm *ipcp;
332 struct msqid64_ds uninitialized_var(msqid64); 333 struct msqid64_ds uninitialized_var(msqid64);
333 struct msg_queue *msq; 334 struct msg_queue *msq;
334 WAKE_Q(wake_q);
335 int err; 335 int err;
336 336
337 if (cmd == IPC_SET) { 337 if (cmd == IPC_SET) {
@@ -362,6 +362,9 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
362 freeque(ns, ipcp); 362 freeque(ns, ipcp);
363 goto out_up; 363 goto out_up;
364 case IPC_SET: 364 case IPC_SET:
365 {
366 WAKE_Q(wake_q);
367
365 if (msqid64.msg_qbytes > ns->msg_ctlmnb && 368 if (msqid64.msg_qbytes > ns->msg_ctlmnb &&
366 !capable(CAP_SYS_RESOURCE)) { 369 !capable(CAP_SYS_RESOURCE)) {
367 err = -EPERM; 370 err = -EPERM;
@@ -376,15 +379,21 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
376 msq->q_qbytes = msqid64.msg_qbytes; 379 msq->q_qbytes = msqid64.msg_qbytes;
377 380
378 msq->q_ctime = get_seconds(); 381 msq->q_ctime = get_seconds();
379 /* sleeping receivers might be excluded by 382 /*
383 * Sleeping receivers might be excluded by
380 * stricter permissions. 384 * stricter permissions.
381 */ 385 */
382 expunge_all(msq, -EAGAIN, &wake_q); 386 expunge_all(msq, -EAGAIN, &wake_q);
383 /* sleeping senders might be able to send 387 /*
388 * Sleeping senders might be able to send
384 * due to a larger queue size. 389 * due to a larger queue size.
385 */ 390 */
386 ss_wakeup(&msq->q_senders, 0); 391 ss_wakeup(&msq->q_senders, &wake_q, 0);
387 break; 392 ipc_unlock_object(&msq->q_perm);
393 wake_up_q(&wake_q);
394
395 goto out_unlock1;
396 }
388 default: 397 default:
389 err = -EINVAL; 398 err = -EINVAL;
390 goto out_unlock1; 399 goto out_unlock1;
@@ -392,7 +401,6 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
392 401
393out_unlock0: 402out_unlock0:
394 ipc_unlock_object(&msq->q_perm); 403 ipc_unlock_object(&msq->q_perm);
395 wake_up_q(&wake_q);
396out_unlock1: 404out_unlock1:
397 rcu_read_unlock(); 405 rcu_read_unlock();
398out_up: 406out_up:
@@ -809,6 +817,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
809 struct msg_queue *msq; 817 struct msg_queue *msq;
810 struct ipc_namespace *ns; 818 struct ipc_namespace *ns;
811 struct msg_msg *msg, *copy = NULL; 819 struct msg_msg *msg, *copy = NULL;
820 WAKE_Q(wake_q);
812 821
813 ns = current->nsproxy->ipc_ns; 822 ns = current->nsproxy->ipc_ns;
814 823
@@ -873,7 +882,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
873 msq->q_cbytes -= msg->m_ts; 882 msq->q_cbytes -= msg->m_ts;
874 atomic_sub(msg->m_ts, &ns->msg_bytes); 883 atomic_sub(msg->m_ts, &ns->msg_bytes);
875 atomic_dec(&ns->msg_hdrs); 884 atomic_dec(&ns->msg_hdrs);
876 ss_wakeup(&msq->q_senders, 0); 885 ss_wakeup(&msq->q_senders, &wake_q, 0);
877 886
878 goto out_unlock0; 887 goto out_unlock0;
879 } 888 }
@@ -945,6 +954,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
945 954
946out_unlock0: 955out_unlock0:
947 ipc_unlock_object(&msq->q_perm); 956 ipc_unlock_object(&msq->q_perm);
957 wake_up_q(&wake_q);
948out_unlock1: 958out_unlock1:
949 rcu_read_unlock(); 959 rcu_read_unlock();
950 if (IS_ERR(msg)) { 960 if (IS_ERR(msg)) {