aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/sn/kernel/xpc_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/sn/kernel/xpc_main.c')
-rw-r--r--arch/ia64/sn/kernel/xpc_main.c64
1 files changed, 43 insertions, 21 deletions
diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c
index fa96dfc0e1aa..7a387d237363 100644
--- a/arch/ia64/sn/kernel/xpc_main.c
+++ b/arch/ia64/sn/kernel/xpc_main.c
@@ -681,7 +681,7 @@ xpc_activate_kthreads(struct xpc_channel *ch, int needed)
681 dev_dbg(xpc_chan, "create %d new kthreads, partid=%d, channel=%d\n", 681 dev_dbg(xpc_chan, "create %d new kthreads, partid=%d, channel=%d\n",
682 needed, ch->partid, ch->number); 682 needed, ch->partid, ch->number);
683 683
684 xpc_create_kthreads(ch, needed); 684 xpc_create_kthreads(ch, needed, 0);
685} 685}
686 686
687 687
@@ -775,26 +775,28 @@ xpc_daemonize_kthread(void *args)
775 xpc_kthread_waitmsgs(part, ch); 775 xpc_kthread_waitmsgs(part, ch);
776 } 776 }
777 777
778 if (atomic_dec_return(&ch->kthreads_assigned) == 0) { 778 /* let registerer know that connection is disconnecting */
779 spin_lock_irqsave(&ch->lock, irq_flags);
780 if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
781 !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
782 ch->flags |= XPC_C_DISCONNECTINGCALLOUT;
783 spin_unlock_irqrestore(&ch->lock, irq_flags);
784 779
785 xpc_disconnect_callout(ch, xpcDisconnecting); 780 spin_lock_irqsave(&ch->lock, irq_flags);
786 781 if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
787 spin_lock_irqsave(&ch->lock, irq_flags); 782 !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
788 ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE; 783 ch->flags |= XPC_C_DISCONNECTINGCALLOUT;
789 }
790 spin_unlock_irqrestore(&ch->lock, irq_flags); 784 spin_unlock_irqrestore(&ch->lock, irq_flags);
785
786 xpc_disconnect_callout(ch, xpcDisconnecting);
787
788 spin_lock_irqsave(&ch->lock, irq_flags);
789 ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE;
790 }
791 spin_unlock_irqrestore(&ch->lock, irq_flags);
792
793 if (atomic_dec_return(&ch->kthreads_assigned) == 0) {
791 if (atomic_dec_return(&part->nchannels_engaged) == 0) { 794 if (atomic_dec_return(&part->nchannels_engaged) == 0) {
792 xpc_mark_partition_disengaged(part); 795 xpc_mark_partition_disengaged(part);
793 xpc_IPI_send_disengage(part); 796 xpc_IPI_send_disengage(part);
794 } 797 }
795 } 798 }
796 799
797
798 xpc_msgqueue_deref(ch); 800 xpc_msgqueue_deref(ch);
799 801
800 dev_dbg(xpc_chan, "kthread exiting, partid=%d, channel=%d\n", 802 dev_dbg(xpc_chan, "kthread exiting, partid=%d, channel=%d\n",
@@ -818,7 +820,8 @@ xpc_daemonize_kthread(void *args)
818 * partition. 820 * partition.
819 */ 821 */
820void 822void
821xpc_create_kthreads(struct xpc_channel *ch, int needed) 823xpc_create_kthreads(struct xpc_channel *ch, int needed,
824 int ignore_disconnecting)
822{ 825{
823 unsigned long irq_flags; 826 unsigned long irq_flags;
824 pid_t pid; 827 pid_t pid;
@@ -833,16 +836,38 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed)
833 * kthread. That kthread is responsible for doing the 836 * kthread. That kthread is responsible for doing the
834 * counterpart to the following before it exits. 837 * counterpart to the following before it exits.
835 */ 838 */
839 if (ignore_disconnecting) {
840 if (!atomic_inc_not_zero(&ch->kthreads_assigned)) {
841 /* kthreads assigned had gone to zero */
842 BUG_ON(!(ch->flags &
843 XPC_C_DISCONNECTINGCALLOUT_MADE));
844 break;
845 }
846
847 } else if (ch->flags & XPC_C_DISCONNECTING) {
848 break;
849
850 } else if (atomic_inc_return(&ch->kthreads_assigned) == 1) {
851 if (atomic_inc_return(&part->nchannels_engaged) == 1)
852 xpc_mark_partition_engaged(part);
853 }
836 (void) xpc_part_ref(part); 854 (void) xpc_part_ref(part);
837 xpc_msgqueue_ref(ch); 855 xpc_msgqueue_ref(ch);
838 if (atomic_inc_return(&ch->kthreads_assigned) == 1 &&
839 atomic_inc_return(&part->nchannels_engaged) == 1) {
840 xpc_mark_partition_engaged(part);
841 }
842 856
843 pid = kernel_thread(xpc_daemonize_kthread, (void *) args, 0); 857 pid = kernel_thread(xpc_daemonize_kthread, (void *) args, 0);
844 if (pid < 0) { 858 if (pid < 0) {
845 /* the fork failed */ 859 /* the fork failed */
860
861 /*
862 * NOTE: if (ignore_disconnecting &&
863 * !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) is true,
864 * then we'll deadlock if all other kthreads assigned
865 * to this channel are blocked in the channel's
866 * registerer, because the only thing that will unblock
867 * them is the xpcDisconnecting callout that this
868 * failed kernel_thread would have made.
869 */
870
846 if (atomic_dec_return(&ch->kthreads_assigned) == 0 && 871 if (atomic_dec_return(&ch->kthreads_assigned) == 0 &&
847 atomic_dec_return(&part->nchannels_engaged) == 0) { 872 atomic_dec_return(&part->nchannels_engaged) == 0) {
848 xpc_mark_partition_disengaged(part); 873 xpc_mark_partition_disengaged(part);
@@ -857,9 +882,6 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed)
857 * Flag this as an error only if we have an 882 * Flag this as an error only if we have an
858 * insufficient #of kthreads for the channel 883 * insufficient #of kthreads for the channel
859 * to function. 884 * to function.
860 *
861 * No xpc_msgqueue_ref() is needed here since
862 * the channel mgr is doing this.
863 */ 885 */
864 spin_lock_irqsave(&ch->lock, irq_flags); 886 spin_lock_irqsave(&ch->lock, irq_flags);
865 XPC_DISCONNECT_CHANNEL(ch, xpcLackOfResources, 887 XPC_DISCONNECT_CHANNEL(ch, xpcLackOfResources,