summaryrefslogtreecommitdiffstats
path: root/ipc/msg.c
diff options
context:
space:
mode:
authorDavidlohr Bueso <davidlohr.bueso@hp.com>2013-07-08 19:01:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-09 13:33:27 -0400
commit3dd1f784ed6603d7ab1043e51e6371235edf2313 (patch)
tree21bd41e3f445ca3ba3b96b24f53e9e4adc2ea1fb /ipc/msg.c
parentac0ba20ea6f2201a1589d6dc26ad1a4f0f967bb8 (diff)
ipc,msg: shorten critical region in msgsnd
do_msgsnd() is another function that does too many things with the ipc object lock acquired. Take it only when needed when actually updating msq. 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>
Diffstat (limited to 'ipc/msg.c')
-rw-r--r--ipc/msg.c37
1 files changed, 24 insertions, 13 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index c218328b5980..f2a1a8f30cd4 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -698,10 +698,11 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
698 msg->m_type = mtype; 698 msg->m_type = mtype;
699 msg->m_ts = msgsz; 699 msg->m_ts = msgsz;
700 700
701 msq = msg_lock_check(ns, msqid); 701 rcu_read_lock();
702 msq = msq_obtain_object_check(ns, msqid);
702 if (IS_ERR(msq)) { 703 if (IS_ERR(msq)) {
703 err = PTR_ERR(msq); 704 err = PTR_ERR(msq);
704 goto out_free; 705 goto out_unlock1;
705 } 706 }
706 707
707 for (;;) { 708 for (;;) {
@@ -709,11 +710,11 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
709 710
710 err = -EACCES; 711 err = -EACCES;
711 if (ipcperms(ns, &msq->q_perm, S_IWUGO)) 712 if (ipcperms(ns, &msq->q_perm, S_IWUGO))
712 goto out_unlock_free; 713 goto out_unlock1;
713 714
714 err = security_msg_queue_msgsnd(msq, msg, msgflg); 715 err = security_msg_queue_msgsnd(msq, msg, msgflg);
715 if (err) 716 if (err)
716 goto out_unlock_free; 717 goto out_unlock1;
717 718
718 if (msgsz + msq->q_cbytes <= msq->q_qbytes && 719 if (msgsz + msq->q_cbytes <= msq->q_qbytes &&
719 1 + msq->q_qnum <= msq->q_qbytes) { 720 1 + msq->q_qnum <= msq->q_qbytes) {
@@ -723,32 +724,41 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
723 /* queue full, wait: */ 724 /* queue full, wait: */
724 if (msgflg & IPC_NOWAIT) { 725 if (msgflg & IPC_NOWAIT) {
725 err = -EAGAIN; 726 err = -EAGAIN;
726 goto out_unlock_free; 727 goto out_unlock1;
727 } 728 }
729
730 ipc_lock_object(&msq->q_perm);
728 ss_add(msq, &s); 731 ss_add(msq, &s);
729 732
730 if (!ipc_rcu_getref(msq)) { 733 if (!ipc_rcu_getref(msq)) {
731 err = -EIDRM; 734 err = -EIDRM;
732 goto out_unlock_free; 735 goto out_unlock0;
733 } 736 }
734 737
735 msg_unlock(msq); 738 ipc_unlock_object(&msq->q_perm);
739 rcu_read_unlock();
736 schedule(); 740 schedule();
737 741
738 ipc_lock_by_ptr(&msq->q_perm); 742 rcu_read_lock();
743 ipc_lock_object(&msq->q_perm);
744
739 ipc_rcu_putref(msq); 745 ipc_rcu_putref(msq);
740 if (msq->q_perm.deleted) { 746 if (msq->q_perm.deleted) {
741 err = -EIDRM; 747 err = -EIDRM;
742 goto out_unlock_free; 748 goto out_unlock0;
743 } 749 }
750
744 ss_del(&s); 751 ss_del(&s);
745 752
746 if (signal_pending(current)) { 753 if (signal_pending(current)) {
747 err = -ERESTARTNOHAND; 754 err = -ERESTARTNOHAND;
748 goto out_unlock_free; 755 goto out_unlock0;
749 } 756 }
757
758 ipc_unlock_object(&msq->q_perm);
750 } 759 }
751 760
761 ipc_lock_object(&msq->q_perm);
752 msq->q_lspid = task_tgid_vnr(current); 762 msq->q_lspid = task_tgid_vnr(current);
753 msq->q_stime = get_seconds(); 763 msq->q_stime = get_seconds();
754 764
@@ -764,9 +774,10 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
764 err = 0; 774 err = 0;
765 msg = NULL; 775 msg = NULL;
766 776
767out_unlock_free: 777out_unlock0:
768 msg_unlock(msq); 778 ipc_unlock_object(&msq->q_perm);
769out_free: 779out_unlock1:
780 rcu_read_unlock();
770 if (msg != NULL) 781 if (msg != NULL)
771 free_msg(msg); 782 free_msg(msg);
772 return err; 783 return err;