ipc,msg: shorten critical region in msgctl_down - kernel/git/torvalds/linux.git (original) (raw)

Instead of holding the ipc lock for the entire function, use the ipcctl_pre_down_nolock and only acquire the lock for specific commands: RMID and SET. 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

diff --git a/ipc/msg.c b/ipc/msg.c
index f62fa5eed84713..de422ff71c8732 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c

@@ -410,11 +410,10 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,

down_write(&msg_ids(ns).rw_mutex);

rcu_read_lock();

- ipcp = ipcctl_pre_down(ns, &msg_ids(ns), msqid, cmd,

- &msqid64.msg_perm, msqid64.msg_qbytes);

+ ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd,

+ &msqid64.msg_perm, msqid64.msg_qbytes);

if (IS_ERR(ipcp)) {

err = PTR_ERR(ipcp);

- /* the ipc lock is not held upon failure */

goto out_unlock1;

}

@@ -422,10 +421,11 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,

err = security_msg_queue_msgctl(msq, cmd);

if (err)

- goto out_unlock0;

+ goto out_unlock1;

switch (cmd) {

case IPC_RMID:

+ ipc_lock_object(&msq->q_perm);

/* freeque unlocks the ipc object and rcu */

freeque(ns, ipcp);

goto out_up;

@@ -433,9 +433,10 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,

if (msqid64.msg_qbytes > ns->msg_ctlmnb &&

!capable(CAP_SYS_RESOURCE)) {

err = -EPERM;

- goto out_unlock0;

+ goto out_unlock1;

}

+ ipc_lock_object(&msq->q_perm);

err = ipc_update_perm(&msqid64.msg_perm, ipcp);

if (err)

goto out_unlock0;

@@ -454,6 +455,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,

break;

default:

err = -EINVAL;

+ goto out_unlock1;

}

out_unlock0: