aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipc/msg.c58
1 files changed, 32 insertions, 26 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 15050532c782..725a7b74fad8 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -886,21 +886,19 @@ static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode)
886 return found ?: ERR_PTR(-EAGAIN); 886 return found ?: ERR_PTR(-EAGAIN);
887} 887}
888 888
889 889long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg,
890long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
891 int msgflg,
892 long (*msg_handler)(void __user *, struct msg_msg *, size_t)) 890 long (*msg_handler)(void __user *, struct msg_msg *, size_t))
893{ 891{
894 struct msg_queue *msq;
895 struct msg_msg *msg;
896 int mode; 892 int mode;
893 struct msg_queue *msq;
897 struct ipc_namespace *ns; 894 struct ipc_namespace *ns;
898 struct msg_msg *copy = NULL; 895 struct msg_msg *msg, *copy = NULL;
899 896
900 ns = current->nsproxy->ipc_ns; 897 ns = current->nsproxy->ipc_ns;
901 898
902 if (msqid < 0 || (long) bufsz < 0) 899 if (msqid < 0 || (long) bufsz < 0)
903 return -EINVAL; 900 return -EINVAL;
901
904 if (msgflg & MSG_COPY) { 902 if (msgflg & MSG_COPY) {
905 copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax)); 903 copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
906 if (IS_ERR(copy)) 904 if (IS_ERR(copy))
@@ -908,8 +906,10 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
908 } 906 }
909 mode = convert_mode(&msgtyp, msgflg); 907 mode = convert_mode(&msgtyp, msgflg);
910 908
911 msq = msg_lock_check(ns, msqid); 909 rcu_read_lock();
910 msq = msq_obtain_object_check(ns, msqid);
912 if (IS_ERR(msq)) { 911 if (IS_ERR(msq)) {
912 rcu_read_unlock();
913 free_copy(copy); 913 free_copy(copy);
914 return PTR_ERR(msq); 914 return PTR_ERR(msq);
915 } 915 }
@@ -919,10 +919,10 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
919 919
920 msg = ERR_PTR(-EACCES); 920 msg = ERR_PTR(-EACCES);
921 if (ipcperms(ns, &msq->q_perm, S_IRUGO)) 921 if (ipcperms(ns, &msq->q_perm, S_IRUGO))
922 goto out_unlock; 922 goto out_unlock1;
923 923
924 ipc_lock_object(&msq->q_perm);
924 msg = find_msg(msq, &msgtyp, mode); 925 msg = find_msg(msq, &msgtyp, mode);
925
926 if (!IS_ERR(msg)) { 926 if (!IS_ERR(msg)) {
927 /* 927 /*
928 * Found a suitable message. 928 * Found a suitable message.
@@ -930,7 +930,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
930 */ 930 */
931 if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) { 931 if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
932 msg = ERR_PTR(-E2BIG); 932 msg = ERR_PTR(-E2BIG);
933 goto out_unlock; 933 goto out_unlock0;
934 } 934 }
935 /* 935 /*
936 * If we are copying, then do not unlink message and do 936 * If we are copying, then do not unlink message and do
@@ -938,8 +938,9 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
938 */ 938 */
939 if (msgflg & MSG_COPY) { 939 if (msgflg & MSG_COPY) {
940 msg = copy_msg(msg, copy); 940 msg = copy_msg(msg, copy);
941 goto out_unlock; 941 goto out_unlock0;
942 } 942 }
943
943 list_del(&msg->m_list); 944 list_del(&msg->m_list);
944 msq->q_qnum--; 945 msq->q_qnum--;
945 msq->q_rtime = get_seconds(); 946 msq->q_rtime = get_seconds();
@@ -948,14 +949,16 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
948 atomic_sub(msg->m_ts, &ns->msg_bytes); 949 atomic_sub(msg->m_ts, &ns->msg_bytes);
949 atomic_dec(&ns->msg_hdrs); 950 atomic_dec(&ns->msg_hdrs);
950 ss_wakeup(&msq->q_senders, 0); 951 ss_wakeup(&msq->q_senders, 0);
951 msg_unlock(msq); 952
952 break; 953 goto out_unlock0;
953 } 954 }
955
954 /* No message waiting. Wait for a message */ 956 /* No message waiting. Wait for a message */
955 if (msgflg & IPC_NOWAIT) { 957 if (msgflg & IPC_NOWAIT) {
956 msg = ERR_PTR(-ENOMSG); 958 msg = ERR_PTR(-ENOMSG);
957 goto out_unlock; 959 goto out_unlock0;
958 } 960 }
961
959 list_add_tail(&msr_d.r_list, &msq->q_receivers); 962 list_add_tail(&msr_d.r_list, &msq->q_receivers);
960 msr_d.r_tsk = current; 963 msr_d.r_tsk = current;
961 msr_d.r_msgtype = msgtyp; 964 msr_d.r_msgtype = msgtyp;
@@ -966,8 +969,9 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
966 msr_d.r_maxsize = bufsz; 969 msr_d.r_maxsize = bufsz;
967 msr_d.r_msg = ERR_PTR(-EAGAIN); 970 msr_d.r_msg = ERR_PTR(-EAGAIN);
968 current->state = TASK_INTERRUPTIBLE; 971 current->state = TASK_INTERRUPTIBLE;
969 msg_unlock(msq);
970 972
973 ipc_unlock_object(&msq->q_perm);
974 rcu_read_unlock();
971 schedule(); 975 schedule();
972 976
973 /* Lockless receive, part 1: 977 /* Lockless receive, part 1:
@@ -978,7 +982,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
978 * Prior to destruction, expunge_all(-EIRDM) changes r_msg. 982 * Prior to destruction, expunge_all(-EIRDM) changes r_msg.
979 * Thus if r_msg is -EAGAIN, then the queue not yet destroyed. 983 * Thus if r_msg is -EAGAIN, then the queue not yet destroyed.
980 * rcu_read_lock() prevents preemption between reading r_msg 984 * rcu_read_lock() prevents preemption between reading r_msg
981 * and the spin_lock() inside ipc_lock_by_ptr(). 985 * and acquiring the q_perm.lock in ipc_lock_object().
982 */ 986 */
983 rcu_read_lock(); 987 rcu_read_lock();
984 988
@@ -997,32 +1001,34 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
997 * If there is a message or an error then accept it without 1001 * If there is a message or an error then accept it without
998 * locking. 1002 * locking.
999 */ 1003 */
1000 if (msg != ERR_PTR(-EAGAIN)) { 1004 if (msg != ERR_PTR(-EAGAIN))
1001 rcu_read_unlock(); 1005 goto out_unlock1;
1002 break;
1003 }
1004 1006
1005 /* Lockless receive, part 3: 1007 /* Lockless receive, part 3:
1006 * Acquire the queue spinlock. 1008 * Acquire the queue spinlock.
1007 */ 1009 */
1008 ipc_lock_by_ptr(&msq->q_perm); 1010 ipc_lock_object(&msq->q_perm);
1009 rcu_read_unlock();
1010 1011
1011 /* Lockless receive, part 4: 1012 /* Lockless receive, part 4:
1012 * Repeat test after acquiring the spinlock. 1013 * Repeat test after acquiring the spinlock.
1013 */ 1014 */
1014 msg = (struct msg_msg*)msr_d.r_msg; 1015 msg = (struct msg_msg*)msr_d.r_msg;
1015 if (msg != ERR_PTR(-EAGAIN)) 1016 if (msg != ERR_PTR(-EAGAIN))
1016 goto out_unlock; 1017 goto out_unlock0;
1017 1018
1018 list_del(&msr_d.r_list); 1019 list_del(&msr_d.r_list);
1019 if (signal_pending(current)) { 1020 if (signal_pending(current)) {
1020 msg = ERR_PTR(-ERESTARTNOHAND); 1021 msg = ERR_PTR(-ERESTARTNOHAND);
1021out_unlock: 1022 goto out_unlock0;
1022 msg_unlock(msq);
1023 break;
1024 } 1023 }
1024
1025 ipc_unlock_object(&msq->q_perm);
1025 } 1026 }
1027
1028out_unlock0:
1029 ipc_unlock_object(&msq->q_perm);
1030out_unlock1:
1031 rcu_read_unlock();
1026 if (IS_ERR(msg)) { 1032 if (IS_ERR(msg)) {
1027 free_copy(copy); 1033 free_copy(copy);
1028 return PTR_ERR(msg); 1034 return PTR_ERR(msg);