diff options
Diffstat (limited to 'ipc/msg.c')
| -rw-r--r-- | ipc/msg.c | 44 | 
1 files changed, 30 insertions, 14 deletions
| @@ -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) | |||
| 318 | static inline unsigned long | 324 | static inline unsigned long | 
| 319 | copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version) | 325 | copy_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) | |||
| 363 | static inline unsigned long | 369 | static inline unsigned long | 
| 364 | copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version) | 370 | copy_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 | ||
| 607 | static int testmsg(struct msg_msg *msg, long type, int mode) | 613 | static 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 | } | 
| @@ -909,7 +925,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl | |||
| 909 | ipc_lock_object(&msq->q_perm); | 925 | ipc_lock_object(&msq->q_perm); | 
| 910 | 926 | ||
| 911 | /* raced with RMID? */ | 927 | /* raced with RMID? */ | 
| 912 | if (msq->q_perm.deleted) { | 928 | if (!ipc_valid_object(&msq->q_perm)) { | 
| 913 | msg = ERR_PTR(-EIDRM); | 929 | msg = ERR_PTR(-EIDRM); | 
| 914 | goto out_unlock0; | 930 | goto out_unlock0; | 
| 915 | } | 931 | } | 
| @@ -983,7 +999,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 | 999 | * wake_up_process(). There is a race with exit(), see | 
| 984 | * ipc/mqueue.c for the details. | 1000 | * ipc/mqueue.c for the details. | 
| 985 | */ | 1001 | */ | 
| 986 | msg = (struct msg_msg*)msr_d.r_msg; | 1002 | msg = (struct msg_msg *)msr_d.r_msg; | 
| 987 | while (msg == NULL) { | 1003 | while (msg == NULL) { | 
| 988 | cpu_relax(); | 1004 | cpu_relax(); | 
| 989 | msg = (struct msg_msg *)msr_d.r_msg; | 1005 | msg = (struct msg_msg *)msr_d.r_msg; | 
| @@ -1004,7 +1020,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl | |||
| 1004 | /* Lockless receive, part 4: | 1020 | /* Lockless receive, part 4: | 
| 1005 | * Repeat test after acquiring the spinlock. | 1021 | * Repeat test after acquiring the spinlock. | 
| 1006 | */ | 1022 | */ | 
| 1007 | msg = (struct msg_msg*)msr_d.r_msg; | 1023 | msg = (struct msg_msg *)msr_d.r_msg; | 
| 1008 | if (msg != ERR_PTR(-EAGAIN)) | 1024 | if (msg != ERR_PTR(-EAGAIN)) | 
| 1009 | goto out_unlock0; | 1025 | goto out_unlock0; | 
| 1010 | 1026 | ||
