aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/msg.c')
-rw-r--r--ipc/msg.c46
1 files changed, 32 insertions, 14 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 558aa91186b6..649853105a5d 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -253,8 +253,14 @@ static void expunge_all(struct msg_queue *msq, int res)
253 struct msg_receiver *msr, *t; 253 struct msg_receiver *msr, *t;
254 254
255 list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) { 255 list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
256 msr->r_msg = NULL; 256 msr->r_msg = NULL; /* initialize expunge ordering */
257 wake_up_process(msr->r_tsk); 257 wake_up_process(msr->r_tsk);
258 /*
259 * Ensure that the wakeup is visible before setting r_msg as
260 * the receiving end depends on it: either spinning on a nil,
261 * or dealing with -EAGAIN cases. See lockless receive part 1
262 * and 2 in do_msgrcv().
263 */
258 smp_mb(); 264 smp_mb();
259 msr->r_msg = ERR_PTR(res); 265 msr->r_msg = ERR_PTR(res);
260 } 266 }
@@ -318,7 +324,7 @@ SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg)
318static inline unsigned long 324static inline unsigned long
319copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) 325copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
320{ 326{
321 switch(version) { 327 switch (version) {
322 case IPC_64: 328 case IPC_64:
323 return copy_to_user(buf, in, sizeof(*in)); 329 return copy_to_user(buf, in, sizeof(*in));
324 case IPC_OLD: 330 case IPC_OLD:
@@ -363,7 +369,7 @@ copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
363static inline unsigned long 369static inline unsigned long
364copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) 370copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
365{ 371{
366 switch(version) { 372 switch (version) {
367 case IPC_64: 373 case IPC_64:
368 if (copy_from_user(out, buf, sizeof(*out))) 374 if (copy_from_user(out, buf, sizeof(*out)))
369 return -EFAULT; 375 return -EFAULT;
@@ -375,9 +381,9 @@ copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
375 if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old))) 381 if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
376 return -EFAULT; 382 return -EFAULT;
377 383
378 out->msg_perm.uid = tbuf_old.msg_perm.uid; 384 out->msg_perm.uid = tbuf_old.msg_perm.uid;
379 out->msg_perm.gid = tbuf_old.msg_perm.gid; 385 out->msg_perm.gid = tbuf_old.msg_perm.gid;
380 out->msg_perm.mode = tbuf_old.msg_perm.mode; 386 out->msg_perm.mode = tbuf_old.msg_perm.mode;
381 387
382 if (tbuf_old.msg_qbytes == 0) 388 if (tbuf_old.msg_qbytes == 0)
383 out->msg_qbytes = tbuf_old.msg_lqbytes; 389 out->msg_qbytes = tbuf_old.msg_lqbytes;
@@ -606,13 +612,13 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
606 612
607static int testmsg(struct msg_msg *msg, long type, int mode) 613static int testmsg(struct msg_msg *msg, long type, int mode)
608{ 614{
609 switch(mode) 615 switch (mode)
610 { 616 {
611 case SEARCH_ANY: 617 case SEARCH_ANY:
612 case SEARCH_NUMBER: 618 case SEARCH_NUMBER:
613 return 1; 619 return 1;
614 case SEARCH_LESSEQUAL: 620 case SEARCH_LESSEQUAL:
615 if (msg->m_type <=type) 621 if (msg->m_type <= type)
616 return 1; 622 return 1;
617 break; 623 break;
618 case SEARCH_EQUAL: 624 case SEARCH_EQUAL:
@@ -638,15 +644,22 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
638 644
639 list_del(&msr->r_list); 645 list_del(&msr->r_list);
640 if (msr->r_maxsize < msg->m_ts) { 646 if (msr->r_maxsize < msg->m_ts) {
647 /* initialize pipelined send ordering */
641 msr->r_msg = NULL; 648 msr->r_msg = NULL;
642 wake_up_process(msr->r_tsk); 649 wake_up_process(msr->r_tsk);
643 smp_mb(); 650 smp_mb(); /* see barrier comment below */
644 msr->r_msg = ERR_PTR(-E2BIG); 651 msr->r_msg = ERR_PTR(-E2BIG);
645 } else { 652 } else {
646 msr->r_msg = NULL; 653 msr->r_msg = NULL;
647 msq->q_lrpid = task_pid_vnr(msr->r_tsk); 654 msq->q_lrpid = task_pid_vnr(msr->r_tsk);
648 msq->q_rtime = get_seconds(); 655 msq->q_rtime = get_seconds();
649 wake_up_process(msr->r_tsk); 656 wake_up_process(msr->r_tsk);
657 /*
658 * Ensure that the wakeup is visible before
659 * setting r_msg, as the receiving end depends
660 * on it. See lockless receive part 1 and 2 in
661 * do_msgrcv().
662 */
650 smp_mb(); 663 smp_mb();
651 msr->r_msg = msg; 664 msr->r_msg = msg;
652 665
@@ -654,6 +667,7 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
654 } 667 }
655 } 668 }
656 } 669 }
670
657 return 0; 671 return 0;
658} 672}
659 673
@@ -696,7 +710,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
696 goto out_unlock0; 710 goto out_unlock0;
697 711
698 /* raced with RMID? */ 712 /* raced with RMID? */
699 if (msq->q_perm.deleted) { 713 if (!ipc_valid_object(&msq->q_perm)) {
700 err = -EIDRM; 714 err = -EIDRM;
701 goto out_unlock0; 715 goto out_unlock0;
702 } 716 }
@@ -716,6 +730,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
716 goto out_unlock0; 730 goto out_unlock0;
717 } 731 }
718 732
733 /* enqueue the sender and prepare to block */
719 ss_add(msq, &s); 734 ss_add(msq, &s);
720 735
721 if (!ipc_rcu_getref(msq)) { 736 if (!ipc_rcu_getref(msq)) {
@@ -731,7 +746,8 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
731 ipc_lock_object(&msq->q_perm); 746 ipc_lock_object(&msq->q_perm);
732 747
733 ipc_rcu_putref(msq, ipc_rcu_free); 748 ipc_rcu_putref(msq, ipc_rcu_free);
734 if (msq->q_perm.deleted) { 749 /* raced with RMID? */
750 if (!ipc_valid_object(&msq->q_perm)) {
735 err = -EIDRM; 751 err = -EIDRM;
736 goto out_unlock0; 752 goto out_unlock0;
737 } 753 }
@@ -885,6 +901,8 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
885 return -EINVAL; 901 return -EINVAL;
886 902
887 if (msgflg & MSG_COPY) { 903 if (msgflg & MSG_COPY) {
904 if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT))
905 return -EINVAL;
888 copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax)); 906 copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
889 if (IS_ERR(copy)) 907 if (IS_ERR(copy))
890 return PTR_ERR(copy); 908 return PTR_ERR(copy);
@@ -909,7 +927,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
909 ipc_lock_object(&msq->q_perm); 927 ipc_lock_object(&msq->q_perm);
910 928
911 /* raced with RMID? */ 929 /* raced with RMID? */
912 if (msq->q_perm.deleted) { 930 if (!ipc_valid_object(&msq->q_perm)) {
913 msg = ERR_PTR(-EIDRM); 931 msg = ERR_PTR(-EIDRM);
914 goto out_unlock0; 932 goto out_unlock0;
915 } 933 }
@@ -983,7 +1001,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
983 * wake_up_process(). There is a race with exit(), see 1001 * wake_up_process(). There is a race with exit(), see
984 * ipc/mqueue.c for the details. 1002 * ipc/mqueue.c for the details.
985 */ 1003 */
986 msg = (struct msg_msg*)msr_d.r_msg; 1004 msg = (struct msg_msg *)msr_d.r_msg;
987 while (msg == NULL) { 1005 while (msg == NULL) {
988 cpu_relax(); 1006 cpu_relax();
989 msg = (struct msg_msg *)msr_d.r_msg; 1007 msg = (struct msg_msg *)msr_d.r_msg;
@@ -1004,7 +1022,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
1004 /* Lockless receive, part 4: 1022 /* Lockless receive, part 4:
1005 * Repeat test after acquiring the spinlock. 1023 * Repeat test after acquiring the spinlock.
1006 */ 1024 */
1007 msg = (struct msg_msg*)msr_d.r_msg; 1025 msg = (struct msg_msg *)msr_d.r_msg;
1008 if (msg != ERR_PTR(-EAGAIN)) 1026 if (msg != ERR_PTR(-EAGAIN))
1009 goto out_unlock0; 1027 goto out_unlock0;
1010 1028