From a561379a0a2d8a32d31c9fd1c0c0760d18679a68 Mon Sep 17 00:00:00 2001
From: Sedat Dilek <sedat.dilek@gmail.com>
Date: Fri, 21 Jun 2013 20:34:49 +0200
Subject: [PATCH 2/2] Revert "ipc,msg: shorten critical region in msgrcv"

This reverts commit 62190df4081ee8504e3611d45edb40450cb408ac.

Signed-off-by: Sedat Dilek <sedat.dilek@gmail.com>
---
 ipc/msg.c | 57 +++++++++++++++++++++++++--------------------------------
 1 file changed, 25 insertions(+), 32 deletions(-)

diff --git a/ipc/msg.c b/ipc/msg.c
index e6550f6..f2a1a8f 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -885,19 +885,21 @@ static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode)
 	return ERR_PTR(-EAGAIN);
 }
 
-long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg,
+
+long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
+	       int msgflg,
 	       long (*msg_handler)(void __user *, struct msg_msg *, size_t))
 {
-	int mode;
 	struct msg_queue *msq;
+	struct msg_msg *msg;
+	int mode;
 	struct ipc_namespace *ns;
-	struct msg_msg *msg, *copy = NULL;
+	struct msg_msg *copy = NULL;
 
 	ns = current->nsproxy->ipc_ns;
 
 	if (msqid < 0 || (long) bufsz < 0)
 		return -EINVAL;
-
 	if (msgflg & MSG_COPY) {
 		copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
 		if (IS_ERR(copy))
@@ -905,10 +907,8 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
 	}
 	mode = convert_mode(&msgtyp, msgflg);
 
-	rcu_read_lock();
-	msq = msq_obtain_object_check(ns, msqid);
+	msq = msg_lock_check(ns, msqid);
 	if (IS_ERR(msq)) {
-		rcu_read_unlock();
 		free_copy(copy);
 		return PTR_ERR(msq);
 	}
@@ -918,9 +918,10 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
 
 		msg = ERR_PTR(-EACCES);
 		if (ipcperms(ns, &msq->q_perm, S_IRUGO))
-			goto out_unlock1;
+			goto out_unlock;
 
 		msg = find_msg(msq, &msgtyp, mode);
+
 		if (!IS_ERR(msg)) {
 			/*
 			 * Found a suitable message.
@@ -928,7 +929,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
 			 */
 			if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
 				msg = ERR_PTR(-E2BIG);
-				goto out_unlock1;
+				goto out_unlock;
 			}
 			/*
 			 * If we are copying, then do not unlink message and do
@@ -936,10 +937,8 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
 			 */
 			if (msgflg & MSG_COPY) {
 				msg = copy_msg(msg, copy);
-				goto out_unlock1;
+				goto out_unlock;
 			}
-
-			ipc_lock_object(&msq->q_perm);
 			list_del(&msg->m_list);
 			msq->q_qnum--;
 			msq->q_rtime = get_seconds();
@@ -948,17 +947,14 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
 			atomic_sub(msg->m_ts, &ns->msg_bytes);
 			atomic_dec(&ns->msg_hdrs);
 			ss_wakeup(&msq->q_senders, 0);
-
-			goto out_unlock0;
+			msg_unlock(msq);
+			break;
 		}
-
 		/* No message waiting. Wait for a message */
 		if (msgflg & IPC_NOWAIT) {
 			msg = ERR_PTR(-ENOMSG);
-			goto out_unlock1;
+			goto out_unlock;
 		}
-
-		ipc_lock_object(&msq->q_perm);
 		list_add_tail(&msr_d.r_list, &msq->q_receivers);
 		msr_d.r_tsk = current;
 		msr_d.r_msgtype = msgtyp;
@@ -969,9 +965,8 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
 			msr_d.r_maxsize = bufsz;
 		msr_d.r_msg = ERR_PTR(-EAGAIN);
 		current->state = TASK_INTERRUPTIBLE;
+		msg_unlock(msq);
 
-		ipc_unlock_object(&msq->q_perm);
-		rcu_read_unlock();
 		schedule();
 
 		/* Lockless receive, part 1:
@@ -1001,34 +996,32 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
 		 * If there is a message or an error then accept it without
 		 * locking.
 		 */
-		if (msg != ERR_PTR(-EAGAIN))
-			goto out_unlock1;
+		if (msg != ERR_PTR(-EAGAIN)) {
+			rcu_read_unlock();
+			break;
+		}
 
 		/* Lockless receive, part 3:
 		 * Acquire the queue spinlock.
 		 */
-		ipc_lock_object(&msq->q_perm);
+		ipc_lock_by_ptr(&msq->q_perm);
+		rcu_read_unlock();
 
 		/* Lockless receive, part 4:
 		 * Repeat test after acquiring the spinlock.
 		 */
 		msg = (struct msg_msg*)msr_d.r_msg;
 		if (msg != ERR_PTR(-EAGAIN))
-			goto out_unlock0;
+			goto out_unlock;
 
 		list_del(&msr_d.r_list);
 		if (signal_pending(current)) {
 			msg = ERR_PTR(-ERESTARTNOHAND);
-			goto out_unlock0;
+out_unlock:
+			msg_unlock(msq);
+			break;
 		}
-
-		ipc_unlock_object(&msq->q_perm);
 	}
-
-out_unlock0:
-	ipc_unlock_object(&msq->q_perm);
-out_unlock1:
-	rcu_read_unlock();
 	if (IS_ERR(msg)) {
 		free_copy(copy);
 		return PTR_ERR(msg);
-- 
1.8.3.1

