diff options
author | Davidlohr Bueso <davidlohr.bueso@hp.com> | 2013-07-08 19:01:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-09 13:33:27 -0400 |
commit | 3dd1f784ed6603d7ab1043e51e6371235edf2313 (patch) | |
tree | 21bd41e3f445ca3ba3b96b24f53e9e4adc2ea1fb /ipc/msg.c | |
parent | ac0ba20ea6f2201a1589d6dc26ad1a4f0f967bb8 (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.c | 37 |
1 files changed, 24 insertions, 13 deletions
@@ -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 | ||
767 | out_unlock_free: | 777 | out_unlock0: |
768 | msg_unlock(msq); | 778 | ipc_unlock_object(&msq->q_perm); |
769 | out_free: | 779 | out_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; |