summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavidlohr Bueso <davidlohr.bueso@hp.com>2013-07-08 16:01:16 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-09 10:33:27 -0700
commitac0ba20ea6f2201a1589d6dc26ad1a4f0f967bb8 (patch)
treebc3e2e4c4140f07ee1861b724ba7e1b295d7bbc6
parenta5001a0d9768568de5d613c3b3a5b9c7721299da (diff)
ipc,msg: make msgctl_nolock lockless
While the INFO cmd doesn't take the ipc lock, the STAT commands do acquire it unnecessarily. We can do the permissions and security checks only holding the rcu lock. This function now mimics semctl_nolock(). Signed-off-by: Davidlohr Bueso <davidlohr.bueso@hp.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Rik van Riel <riel@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--ipc/msg.c27
1 files changed, 17 insertions, 10 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index c53c13716064..c218328b5980 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -545,17 +545,25 @@ static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
if (!buf)
return -EFAULT;
+ memset(&tbuf, 0, sizeof(tbuf));
+
+ rcu_read_lock();
if (cmd == MSG_STAT) {
- msq = msg_lock(ns, msqid);
- if (IS_ERR(msq))
- return PTR_ERR(msq);
+ msq = msq_obtain_object(ns, msqid);
+ if (IS_ERR(msq)) {
+ err = PTR_ERR(msq);
+ goto out_unlock;
+ }
success_return = msq->q_perm.id;
} else {
- msq = msg_lock_check(ns, msqid);
- if (IS_ERR(msq))
- return PTR_ERR(msq);
+ msq = msq_obtain_object_check(ns, msqid);
+ if (IS_ERR(msq)) {
+ err = PTR_ERR(msq);
+ goto out_unlock;
+ }
success_return = 0;
}
+
err = -EACCES;
if (ipcperms(ns, &msq->q_perm, S_IRUGO))
goto out_unlock;
@@ -564,8 +572,6 @@ static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
if (err)
goto out_unlock;
- memset(&tbuf, 0, sizeof(tbuf));
-
kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm);
tbuf.msg_stime = msq->q_stime;
tbuf.msg_rtime = msq->q_rtime;
@@ -575,7 +581,8 @@ static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
tbuf.msg_qbytes = msq->q_qbytes;
tbuf.msg_lspid = msq->q_lspid;
tbuf.msg_lrpid = msq->q_lrpid;
- msg_unlock(msq);
+ rcu_read_unlock();
+
if (copy_msqid_to_user(buf, &tbuf, version))
return -EFAULT;
return success_return;
@@ -587,7 +594,7 @@ static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
return err;
out_unlock:
- msg_unlock(msq);
+ rcu_read_unlock();
return err;
}