ipc,msg: introduce msgctl_nolock

Similar to semctl, when calling msgctl, the *_INFO and *_STAT commands
can be performed without acquiring the ipc object.

Add a msgctl_nolock() function and move the logic of *_INFO and *_STAT
out of msgctl().  This change still takes the lock and it will be
properly lockless in the next patch

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>
This commit is contained in:
Davidlohr Bueso 2013-07-08 16:01:14 -07:00 committed by Linus Torvalds
parent 15724ecb7e
commit 2cafed30f1

View File

@ -467,17 +467,11 @@ out_up:
return err; return err;
} }
SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf) static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
int cmd, int version, void __user *buf)
{ {
int err;
struct msg_queue *msq; struct msg_queue *msq;
int err, version;
struct ipc_namespace *ns;
if (msqid < 0 || cmd < 0)
return -EINVAL;
version = ipc_parse_version(&cmd);
ns = current->nsproxy->ipc_ns;
switch (cmd) { switch (cmd) {
case IPC_INFO: case IPC_INFO:
@ -488,6 +482,7 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
if (!buf) if (!buf)
return -EFAULT; return -EFAULT;
/* /*
* We must not return kernel stack data. * We must not return kernel stack data.
* due to padding, it's not enough * due to padding, it's not enough
@ -519,7 +514,8 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
return -EFAULT; return -EFAULT;
return (max_id < 0) ? 0 : max_id; return (max_id < 0) ? 0 : max_id;
} }
case MSG_STAT: /* msqid is an index rather than a msg queue id */
case MSG_STAT:
case IPC_STAT: case IPC_STAT:
{ {
struct msqid64_ds tbuf; struct msqid64_ds tbuf;
@ -563,19 +559,42 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
return -EFAULT; return -EFAULT;
return success_return; return success_return;
} }
case IPC_SET:
case IPC_RMID:
err = msgctl_down(ns, msqid, cmd, buf, version);
return err;
default: default:
return -EINVAL; return -EINVAL;
} }
return err;
out_unlock: out_unlock:
msg_unlock(msq); msg_unlock(msq);
return err; return err;
} }
SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
{
int version;
struct ipc_namespace *ns;
if (msqid < 0 || cmd < 0)
return -EINVAL;
version = ipc_parse_version(&cmd);
ns = current->nsproxy->ipc_ns;
switch (cmd) {
case IPC_INFO:
case MSG_INFO:
case MSG_STAT: /* msqid is an index rather than a msg queue id */
case IPC_STAT:
return msgctl_nolock(ns, msqid, cmd, version, buf);
case IPC_SET:
case IPC_RMID:
return msgctl_down(ns, msqid, cmd, buf, version);
default:
return -EINVAL;
}
}
static int testmsg(struct msg_msg *msg, long type, int mode) static int testmsg(struct msg_msg *msg, long type, int mode)
{ {
switch(mode) switch(mode)