diff options
Diffstat (limited to 'arch/ia64/sn/kernel/xpc_channel.c')
-rw-r--r-- | arch/ia64/sn/kernel/xpc_channel.c | 329 |
1 files changed, 195 insertions, 134 deletions
diff --git a/arch/ia64/sn/kernel/xpc_channel.c b/arch/ia64/sn/kernel/xpc_channel.c index 94698bea7be0..abf4fc2a87bb 100644 --- a/arch/ia64/sn/kernel/xpc_channel.c +++ b/arch/ia64/sn/kernel/xpc_channel.c | |||
@@ -57,6 +57,7 @@ xpc_initialize_channels(struct xpc_partition *part, partid_t partid) | |||
57 | 57 | ||
58 | spin_lock_init(&ch->lock); | 58 | spin_lock_init(&ch->lock); |
59 | sema_init(&ch->msg_to_pull_sema, 1); /* mutex */ | 59 | sema_init(&ch->msg_to_pull_sema, 1); /* mutex */ |
60 | sema_init(&ch->wdisconnect_sema, 0); /* event wait */ | ||
60 | 61 | ||
61 | atomic_set(&ch->n_on_msg_allocate_wq, 0); | 62 | atomic_set(&ch->n_on_msg_allocate_wq, 0); |
62 | init_waitqueue_head(&ch->msg_allocate_wq); | 63 | init_waitqueue_head(&ch->msg_allocate_wq); |
@@ -166,6 +167,7 @@ xpc_setup_infrastructure(struct xpc_partition *part) | |||
166 | xpc_initialize_channels(part, partid); | 167 | xpc_initialize_channels(part, partid); |
167 | 168 | ||
168 | atomic_set(&part->nchannels_active, 0); | 169 | atomic_set(&part->nchannels_active, 0); |
170 | atomic_set(&part->nchannels_engaged, 0); | ||
169 | 171 | ||
170 | 172 | ||
171 | /* local_IPI_amo were set to 0 by an earlier memset() */ | 173 | /* local_IPI_amo were set to 0 by an earlier memset() */ |
@@ -555,8 +557,6 @@ xpc_allocate_msgqueues(struct xpc_channel *ch) | |||
555 | sema_init(&ch->notify_queue[i].sema, 0); | 557 | sema_init(&ch->notify_queue[i].sema, 0); |
556 | } | 558 | } |
557 | 559 | ||
558 | sema_init(&ch->teardown_sema, 0); /* event wait */ | ||
559 | |||
560 | spin_lock_irqsave(&ch->lock, irq_flags); | 560 | spin_lock_irqsave(&ch->lock, irq_flags); |
561 | ch->flags |= XPC_C_SETUP; | 561 | ch->flags |= XPC_C_SETUP; |
562 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 562 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
@@ -626,6 +626,55 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags) | |||
626 | 626 | ||
627 | 627 | ||
628 | /* | 628 | /* |
629 | * Notify those who wanted to be notified upon delivery of their message. | ||
630 | */ | ||
631 | static void | ||
632 | xpc_notify_senders(struct xpc_channel *ch, enum xpc_retval reason, s64 put) | ||
633 | { | ||
634 | struct xpc_notify *notify; | ||
635 | u8 notify_type; | ||
636 | s64 get = ch->w_remote_GP.get - 1; | ||
637 | |||
638 | |||
639 | while (++get < put && atomic_read(&ch->n_to_notify) > 0) { | ||
640 | |||
641 | notify = &ch->notify_queue[get % ch->local_nentries]; | ||
642 | |||
643 | /* | ||
644 | * See if the notify entry indicates it was associated with | ||
645 | * a message who's sender wants to be notified. It is possible | ||
646 | * that it is, but someone else is doing or has done the | ||
647 | * notification. | ||
648 | */ | ||
649 | notify_type = notify->type; | ||
650 | if (notify_type == 0 || | ||
651 | cmpxchg(¬ify->type, notify_type, 0) != | ||
652 | notify_type) { | ||
653 | continue; | ||
654 | } | ||
655 | |||
656 | DBUG_ON(notify_type != XPC_N_CALL); | ||
657 | |||
658 | atomic_dec(&ch->n_to_notify); | ||
659 | |||
660 | if (notify->func != NULL) { | ||
661 | dev_dbg(xpc_chan, "notify->func() called, notify=0x%p, " | ||
662 | "msg_number=%ld, partid=%d, channel=%d\n", | ||
663 | (void *) notify, get, ch->partid, ch->number); | ||
664 | |||
665 | notify->func(reason, ch->partid, ch->number, | ||
666 | notify->key); | ||
667 | |||
668 | dev_dbg(xpc_chan, "notify->func() returned, " | ||
669 | "notify=0x%p, msg_number=%ld, partid=%d, " | ||
670 | "channel=%d\n", (void *) notify, get, | ||
671 | ch->partid, ch->number); | ||
672 | } | ||
673 | } | ||
674 | } | ||
675 | |||
676 | |||
677 | /* | ||
629 | * Free up message queues and other stuff that were allocated for the specified | 678 | * Free up message queues and other stuff that were allocated for the specified |
630 | * channel. | 679 | * channel. |
631 | * | 680 | * |
@@ -669,9 +718,6 @@ xpc_free_msgqueues(struct xpc_channel *ch) | |||
669 | ch->remote_msgqueue = NULL; | 718 | ch->remote_msgqueue = NULL; |
670 | kfree(ch->notify_queue); | 719 | kfree(ch->notify_queue); |
671 | ch->notify_queue = NULL; | 720 | ch->notify_queue = NULL; |
672 | |||
673 | /* in case someone is waiting for the teardown to complete */ | ||
674 | up(&ch->teardown_sema); | ||
675 | } | 721 | } |
676 | } | 722 | } |
677 | 723 | ||
@@ -683,7 +729,7 @@ static void | |||
683 | xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) | 729 | xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) |
684 | { | 730 | { |
685 | struct xpc_partition *part = &xpc_partitions[ch->partid]; | 731 | struct xpc_partition *part = &xpc_partitions[ch->partid]; |
686 | u32 ch_flags = ch->flags; | 732 | u32 channel_was_connected = (ch->flags & XPC_C_WASCONNECTED); |
687 | 733 | ||
688 | 734 | ||
689 | DBUG_ON(!spin_is_locked(&ch->lock)); | 735 | DBUG_ON(!spin_is_locked(&ch->lock)); |
@@ -701,12 +747,13 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) | |||
701 | } | 747 | } |
702 | DBUG_ON(atomic_read(&ch->kthreads_assigned) != 0); | 748 | DBUG_ON(atomic_read(&ch->kthreads_assigned) != 0); |
703 | 749 | ||
704 | /* it's now safe to free the channel's message queues */ | 750 | if (part->act_state == XPC_P_DEACTIVATING) { |
705 | 751 | /* can't proceed until the other side disengages from us */ | |
706 | xpc_free_msgqueues(ch); | 752 | if (xpc_partition_engaged(1UL << ch->partid)) { |
707 | DBUG_ON(ch->flags & XPC_C_SETUP); | 753 | return; |
754 | } | ||
708 | 755 | ||
709 | if (part->act_state != XPC_P_DEACTIVATING) { | 756 | } else { |
710 | 757 | ||
711 | /* as long as the other side is up do the full protocol */ | 758 | /* as long as the other side is up do the full protocol */ |
712 | 759 | ||
@@ -724,16 +771,42 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags) | |||
724 | } | 771 | } |
725 | } | 772 | } |
726 | 773 | ||
774 | /* wake those waiting for notify completion */ | ||
775 | if (atomic_read(&ch->n_to_notify) > 0) { | ||
776 | /* >>> we do callout while holding ch->lock */ | ||
777 | xpc_notify_senders(ch, ch->reason, ch->w_local_GP.put); | ||
778 | } | ||
779 | |||
727 | /* both sides are disconnected now */ | 780 | /* both sides are disconnected now */ |
728 | 781 | ||
729 | ch->flags = XPC_C_DISCONNECTED; /* clear all flags, but this one */ | 782 | /* it's now safe to free the channel's message queues */ |
783 | xpc_free_msgqueues(ch); | ||
784 | |||
785 | /* mark disconnected, clear all other flags except XPC_C_WDISCONNECT */ | ||
786 | ch->flags = (XPC_C_DISCONNECTED | (ch->flags & XPC_C_WDISCONNECT)); | ||
730 | 787 | ||
731 | atomic_dec(&part->nchannels_active); | 788 | atomic_dec(&part->nchannels_active); |
732 | 789 | ||
733 | if (ch_flags & XPC_C_WASCONNECTED) { | 790 | if (channel_was_connected) { |
734 | dev_info(xpc_chan, "channel %d to partition %d disconnected, " | 791 | dev_info(xpc_chan, "channel %d to partition %d disconnected, " |
735 | "reason=%d\n", ch->number, ch->partid, ch->reason); | 792 | "reason=%d\n", ch->number, ch->partid, ch->reason); |
736 | } | 793 | } |
794 | |||
795 | if (ch->flags & XPC_C_WDISCONNECT) { | ||
796 | spin_unlock_irqrestore(&ch->lock, *irq_flags); | ||
797 | up(&ch->wdisconnect_sema); | ||
798 | spin_lock_irqsave(&ch->lock, *irq_flags); | ||
799 | |||
800 | } else if (ch->delayed_IPI_flags) { | ||
801 | if (part->act_state != XPC_P_DEACTIVATING) { | ||
802 | /* time to take action on any delayed IPI flags */ | ||
803 | spin_lock(&part->IPI_lock); | ||
804 | XPC_SET_IPI_FLAGS(part->local_IPI_amo, ch->number, | ||
805 | ch->delayed_IPI_flags); | ||
806 | spin_unlock(&part->IPI_lock); | ||
807 | } | ||
808 | ch->delayed_IPI_flags = 0; | ||
809 | } | ||
737 | } | 810 | } |
738 | 811 | ||
739 | 812 | ||
@@ -754,6 +827,19 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, | |||
754 | 827 | ||
755 | spin_lock_irqsave(&ch->lock, irq_flags); | 828 | spin_lock_irqsave(&ch->lock, irq_flags); |
756 | 829 | ||
830 | again: | ||
831 | |||
832 | if ((ch->flags & XPC_C_DISCONNECTED) && | ||
833 | (ch->flags & XPC_C_WDISCONNECT)) { | ||
834 | /* | ||
835 | * Delay processing IPI flags until thread waiting disconnect | ||
836 | * has had a chance to see that the channel is disconnected. | ||
837 | */ | ||
838 | ch->delayed_IPI_flags |= IPI_flags; | ||
839 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
840 | return; | ||
841 | } | ||
842 | |||
757 | 843 | ||
758 | if (IPI_flags & XPC_IPI_CLOSEREQUEST) { | 844 | if (IPI_flags & XPC_IPI_CLOSEREQUEST) { |
759 | 845 | ||
@@ -764,7 +850,7 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, | |||
764 | /* | 850 | /* |
765 | * If RCLOSEREQUEST is set, we're probably waiting for | 851 | * If RCLOSEREQUEST is set, we're probably waiting for |
766 | * RCLOSEREPLY. We should find it and a ROPENREQUEST packed | 852 | * RCLOSEREPLY. We should find it and a ROPENREQUEST packed |
767 | * with this RCLOSEQREUQEST in the IPI_flags. | 853 | * with this RCLOSEREQUEST in the IPI_flags. |
768 | */ | 854 | */ |
769 | 855 | ||
770 | if (ch->flags & XPC_C_RCLOSEREQUEST) { | 856 | if (ch->flags & XPC_C_RCLOSEREQUEST) { |
@@ -779,14 +865,22 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, | |||
779 | 865 | ||
780 | /* both sides have finished disconnecting */ | 866 | /* both sides have finished disconnecting */ |
781 | xpc_process_disconnect(ch, &irq_flags); | 867 | xpc_process_disconnect(ch, &irq_flags); |
868 | DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED)); | ||
869 | goto again; | ||
782 | } | 870 | } |
783 | 871 | ||
784 | if (ch->flags & XPC_C_DISCONNECTED) { | 872 | if (ch->flags & XPC_C_DISCONNECTED) { |
785 | // >>> explain this section | ||
786 | |||
787 | if (!(IPI_flags & XPC_IPI_OPENREQUEST)) { | 873 | if (!(IPI_flags & XPC_IPI_OPENREQUEST)) { |
788 | DBUG_ON(part->act_state != | 874 | if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo, |
789 | XPC_P_DEACTIVATING); | 875 | ch_number) & XPC_IPI_OPENREQUEST)) { |
876 | |||
877 | DBUG_ON(ch->delayed_IPI_flags != 0); | ||
878 | spin_lock(&part->IPI_lock); | ||
879 | XPC_SET_IPI_FLAGS(part->local_IPI_amo, | ||
880 | ch_number, | ||
881 | XPC_IPI_CLOSEREQUEST); | ||
882 | spin_unlock(&part->IPI_lock); | ||
883 | } | ||
790 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 884 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
791 | return; | 885 | return; |
792 | } | 886 | } |
@@ -816,9 +910,13 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, | |||
816 | } | 910 | } |
817 | 911 | ||
818 | XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags); | 912 | XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags); |
819 | } else { | 913 | |
820 | xpc_process_disconnect(ch, &irq_flags); | 914 | DBUG_ON(IPI_flags & XPC_IPI_CLOSEREPLY); |
915 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
916 | return; | ||
821 | } | 917 | } |
918 | |||
919 | xpc_process_disconnect(ch, &irq_flags); | ||
822 | } | 920 | } |
823 | 921 | ||
824 | 922 | ||
@@ -834,7 +932,20 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, | |||
834 | } | 932 | } |
835 | 933 | ||
836 | DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST)); | 934 | DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST)); |
837 | DBUG_ON(!(ch->flags & XPC_C_RCLOSEREQUEST)); | 935 | |
936 | if (!(ch->flags & XPC_C_RCLOSEREQUEST)) { | ||
937 | if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo, ch_number) | ||
938 | & XPC_IPI_CLOSEREQUEST)) { | ||
939 | |||
940 | DBUG_ON(ch->delayed_IPI_flags != 0); | ||
941 | spin_lock(&part->IPI_lock); | ||
942 | XPC_SET_IPI_FLAGS(part->local_IPI_amo, | ||
943 | ch_number, XPC_IPI_CLOSEREPLY); | ||
944 | spin_unlock(&part->IPI_lock); | ||
945 | } | ||
946 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
947 | return; | ||
948 | } | ||
838 | 949 | ||
839 | ch->flags |= XPC_C_RCLOSEREPLY; | 950 | ch->flags |= XPC_C_RCLOSEREPLY; |
840 | 951 | ||
@@ -852,8 +963,14 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, | |||
852 | "channel=%d\n", args->msg_size, args->local_nentries, | 963 | "channel=%d\n", args->msg_size, args->local_nentries, |
853 | ch->partid, ch->number); | 964 | ch->partid, ch->number); |
854 | 965 | ||
855 | if ((ch->flags & XPC_C_DISCONNECTING) || | 966 | if (part->act_state == XPC_P_DEACTIVATING || |
856 | part->act_state == XPC_P_DEACTIVATING) { | 967 | (ch->flags & XPC_C_ROPENREQUEST)) { |
968 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
969 | return; | ||
970 | } | ||
971 | |||
972 | if (ch->flags & (XPC_C_DISCONNECTING | XPC_C_WDISCONNECT)) { | ||
973 | ch->delayed_IPI_flags |= XPC_IPI_OPENREQUEST; | ||
857 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 974 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
858 | return; | 975 | return; |
859 | } | 976 | } |
@@ -867,8 +984,11 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, | |||
867 | * msg_size = size of channel's messages in bytes | 984 | * msg_size = size of channel's messages in bytes |
868 | * local_nentries = remote partition's local_nentries | 985 | * local_nentries = remote partition's local_nentries |
869 | */ | 986 | */ |
870 | DBUG_ON(args->msg_size == 0); | 987 | if (args->msg_size == 0 || args->local_nentries == 0) { |
871 | DBUG_ON(args->local_nentries == 0); | 988 | /* assume OPENREQUEST was delayed by mistake */ |
989 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
990 | return; | ||
991 | } | ||
872 | 992 | ||
873 | ch->flags |= (XPC_C_ROPENREQUEST | XPC_C_CONNECTING); | 993 | ch->flags |= (XPC_C_ROPENREQUEST | XPC_C_CONNECTING); |
874 | ch->remote_nentries = args->local_nentries; | 994 | ch->remote_nentries = args->local_nentries; |
@@ -906,7 +1026,13 @@ xpc_process_openclose_IPI(struct xpc_partition *part, int ch_number, | |||
906 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 1026 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
907 | return; | 1027 | return; |
908 | } | 1028 | } |
909 | DBUG_ON(!(ch->flags & XPC_C_OPENREQUEST)); | 1029 | if (!(ch->flags & XPC_C_OPENREQUEST)) { |
1030 | XPC_DISCONNECT_CHANNEL(ch, xpcOpenCloseError, | ||
1031 | &irq_flags); | ||
1032 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
1033 | return; | ||
1034 | } | ||
1035 | |||
910 | DBUG_ON(!(ch->flags & XPC_C_ROPENREQUEST)); | 1036 | DBUG_ON(!(ch->flags & XPC_C_ROPENREQUEST)); |
911 | DBUG_ON(ch->flags & XPC_C_CONNECTED); | 1037 | DBUG_ON(ch->flags & XPC_C_CONNECTED); |
912 | 1038 | ||
@@ -960,8 +1086,8 @@ xpc_connect_channel(struct xpc_channel *ch) | |||
960 | struct xpc_registration *registration = &xpc_registrations[ch->number]; | 1086 | struct xpc_registration *registration = &xpc_registrations[ch->number]; |
961 | 1087 | ||
962 | 1088 | ||
963 | if (down_interruptible(®istration->sema) != 0) { | 1089 | if (down_trylock(®istration->sema) != 0) { |
964 | return xpcInterrupted; | 1090 | return xpcRetry; |
965 | } | 1091 | } |
966 | 1092 | ||
967 | if (!XPC_CHANNEL_REGISTERED(ch->number)) { | 1093 | if (!XPC_CHANNEL_REGISTERED(ch->number)) { |
@@ -1040,55 +1166,6 @@ xpc_connect_channel(struct xpc_channel *ch) | |||
1040 | 1166 | ||
1041 | 1167 | ||
1042 | /* | 1168 | /* |
1043 | * Notify those who wanted to be notified upon delivery of their message. | ||
1044 | */ | ||
1045 | static void | ||
1046 | xpc_notify_senders(struct xpc_channel *ch, enum xpc_retval reason, s64 put) | ||
1047 | { | ||
1048 | struct xpc_notify *notify; | ||
1049 | u8 notify_type; | ||
1050 | s64 get = ch->w_remote_GP.get - 1; | ||
1051 | |||
1052 | |||
1053 | while (++get < put && atomic_read(&ch->n_to_notify) > 0) { | ||
1054 | |||
1055 | notify = &ch->notify_queue[get % ch->local_nentries]; | ||
1056 | |||
1057 | /* | ||
1058 | * See if the notify entry indicates it was associated with | ||
1059 | * a message who's sender wants to be notified. It is possible | ||
1060 | * that it is, but someone else is doing or has done the | ||
1061 | * notification. | ||
1062 | */ | ||
1063 | notify_type = notify->type; | ||
1064 | if (notify_type == 0 || | ||
1065 | cmpxchg(¬ify->type, notify_type, 0) != | ||
1066 | notify_type) { | ||
1067 | continue; | ||
1068 | } | ||
1069 | |||
1070 | DBUG_ON(notify_type != XPC_N_CALL); | ||
1071 | |||
1072 | atomic_dec(&ch->n_to_notify); | ||
1073 | |||
1074 | if (notify->func != NULL) { | ||
1075 | dev_dbg(xpc_chan, "notify->func() called, notify=0x%p, " | ||
1076 | "msg_number=%ld, partid=%d, channel=%d\n", | ||
1077 | (void *) notify, get, ch->partid, ch->number); | ||
1078 | |||
1079 | notify->func(reason, ch->partid, ch->number, | ||
1080 | notify->key); | ||
1081 | |||
1082 | dev_dbg(xpc_chan, "notify->func() returned, " | ||
1083 | "notify=0x%p, msg_number=%ld, partid=%d, " | ||
1084 | "channel=%d\n", (void *) notify, get, | ||
1085 | ch->partid, ch->number); | ||
1086 | } | ||
1087 | } | ||
1088 | } | ||
1089 | |||
1090 | |||
1091 | /* | ||
1092 | * Clear some of the msg flags in the local message queue. | 1169 | * Clear some of the msg flags in the local message queue. |
1093 | */ | 1170 | */ |
1094 | static inline void | 1171 | static inline void |
@@ -1240,6 +1317,7 @@ xpc_process_channel_activity(struct xpc_partition *part) | |||
1240 | u64 IPI_amo, IPI_flags; | 1317 | u64 IPI_amo, IPI_flags; |
1241 | struct xpc_channel *ch; | 1318 | struct xpc_channel *ch; |
1242 | int ch_number; | 1319 | int ch_number; |
1320 | u32 ch_flags; | ||
1243 | 1321 | ||
1244 | 1322 | ||
1245 | IPI_amo = xpc_get_IPI_flags(part); | 1323 | IPI_amo = xpc_get_IPI_flags(part); |
@@ -1266,8 +1344,9 @@ xpc_process_channel_activity(struct xpc_partition *part) | |||
1266 | xpc_process_openclose_IPI(part, ch_number, IPI_flags); | 1344 | xpc_process_openclose_IPI(part, ch_number, IPI_flags); |
1267 | } | 1345 | } |
1268 | 1346 | ||
1347 | ch_flags = ch->flags; /* need an atomic snapshot of flags */ | ||
1269 | 1348 | ||
1270 | if (ch->flags & XPC_C_DISCONNECTING) { | 1349 | if (ch_flags & XPC_C_DISCONNECTING) { |
1271 | spin_lock_irqsave(&ch->lock, irq_flags); | 1350 | spin_lock_irqsave(&ch->lock, irq_flags); |
1272 | xpc_process_disconnect(ch, &irq_flags); | 1351 | xpc_process_disconnect(ch, &irq_flags); |
1273 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 1352 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
@@ -1278,9 +1357,9 @@ xpc_process_channel_activity(struct xpc_partition *part) | |||
1278 | continue; | 1357 | continue; |
1279 | } | 1358 | } |
1280 | 1359 | ||
1281 | if (!(ch->flags & XPC_C_CONNECTED)) { | 1360 | if (!(ch_flags & XPC_C_CONNECTED)) { |
1282 | if (!(ch->flags & XPC_C_OPENREQUEST)) { | 1361 | if (!(ch_flags & XPC_C_OPENREQUEST)) { |
1283 | DBUG_ON(ch->flags & XPC_C_SETUP); | 1362 | DBUG_ON(ch_flags & XPC_C_SETUP); |
1284 | (void) xpc_connect_channel(ch); | 1363 | (void) xpc_connect_channel(ch); |
1285 | } else { | 1364 | } else { |
1286 | spin_lock_irqsave(&ch->lock, irq_flags); | 1365 | spin_lock_irqsave(&ch->lock, irq_flags); |
@@ -1305,8 +1384,8 @@ xpc_process_channel_activity(struct xpc_partition *part) | |||
1305 | 1384 | ||
1306 | 1385 | ||
1307 | /* | 1386 | /* |
1308 | * XPC's heartbeat code calls this function to inform XPC that a partition has | 1387 | * XPC's heartbeat code calls this function to inform XPC that a partition is |
1309 | * gone down. XPC responds by tearing down the XPartition Communication | 1388 | * going down. XPC responds by tearing down the XPartition Communication |
1310 | * infrastructure used for the just downed partition. | 1389 | * infrastructure used for the just downed partition. |
1311 | * | 1390 | * |
1312 | * XPC's heartbeat code will never call this function and xpc_partition_up() | 1391 | * XPC's heartbeat code will never call this function and xpc_partition_up() |
@@ -1314,7 +1393,7 @@ xpc_process_channel_activity(struct xpc_partition *part) | |||
1314 | * at the same time. | 1393 | * at the same time. |
1315 | */ | 1394 | */ |
1316 | void | 1395 | void |
1317 | xpc_partition_down(struct xpc_partition *part, enum xpc_retval reason) | 1396 | xpc_partition_going_down(struct xpc_partition *part, enum xpc_retval reason) |
1318 | { | 1397 | { |
1319 | unsigned long irq_flags; | 1398 | unsigned long irq_flags; |
1320 | int ch_number; | 1399 | int ch_number; |
@@ -1330,12 +1409,11 @@ xpc_partition_down(struct xpc_partition *part, enum xpc_retval reason) | |||
1330 | } | 1409 | } |
1331 | 1410 | ||
1332 | 1411 | ||
1333 | /* disconnect all channels associated with the downed partition */ | 1412 | /* disconnect channels associated with the partition going down */ |
1334 | 1413 | ||
1335 | for (ch_number = 0; ch_number < part->nchannels; ch_number++) { | 1414 | for (ch_number = 0; ch_number < part->nchannels; ch_number++) { |
1336 | ch = &part->channels[ch_number]; | 1415 | ch = &part->channels[ch_number]; |
1337 | 1416 | ||
1338 | |||
1339 | xpc_msgqueue_ref(ch); | 1417 | xpc_msgqueue_ref(ch); |
1340 | spin_lock_irqsave(&ch->lock, irq_flags); | 1418 | spin_lock_irqsave(&ch->lock, irq_flags); |
1341 | 1419 | ||
@@ -1370,6 +1448,7 @@ xpc_teardown_infrastructure(struct xpc_partition *part) | |||
1370 | * this partition. | 1448 | * this partition. |
1371 | */ | 1449 | */ |
1372 | 1450 | ||
1451 | DBUG_ON(atomic_read(&part->nchannels_engaged) != 0); | ||
1373 | DBUG_ON(atomic_read(&part->nchannels_active) != 0); | 1452 | DBUG_ON(atomic_read(&part->nchannels_active) != 0); |
1374 | DBUG_ON(part->setup_state != XPC_P_SETUP); | 1453 | DBUG_ON(part->setup_state != XPC_P_SETUP); |
1375 | part->setup_state = XPC_P_WTEARDOWN; | 1454 | part->setup_state = XPC_P_WTEARDOWN; |
@@ -1428,19 +1507,11 @@ xpc_initiate_connect(int ch_number) | |||
1428 | if (xpc_part_ref(part)) { | 1507 | if (xpc_part_ref(part)) { |
1429 | ch = &part->channels[ch_number]; | 1508 | ch = &part->channels[ch_number]; |
1430 | 1509 | ||
1431 | if (!(ch->flags & XPC_C_DISCONNECTING)) { | 1510 | /* |
1432 | DBUG_ON(ch->flags & XPC_C_OPENREQUEST); | 1511 | * Initiate the establishment of a connection on the |
1433 | DBUG_ON(ch->flags & XPC_C_CONNECTED); | 1512 | * newly registered channel to the remote partition. |
1434 | DBUG_ON(ch->flags & XPC_C_SETUP); | 1513 | */ |
1435 | 1514 | xpc_wakeup_channel_mgr(part); | |
1436 | /* | ||
1437 | * Initiate the establishment of a connection | ||
1438 | * on the newly registered channel to the | ||
1439 | * remote partition. | ||
1440 | */ | ||
1441 | xpc_wakeup_channel_mgr(part); | ||
1442 | } | ||
1443 | |||
1444 | xpc_part_deref(part); | 1515 | xpc_part_deref(part); |
1445 | } | 1516 | } |
1446 | } | 1517 | } |
@@ -1450,9 +1521,6 @@ xpc_initiate_connect(int ch_number) | |||
1450 | void | 1521 | void |
1451 | xpc_connected_callout(struct xpc_channel *ch) | 1522 | xpc_connected_callout(struct xpc_channel *ch) |
1452 | { | 1523 | { |
1453 | unsigned long irq_flags; | ||
1454 | |||
1455 | |||
1456 | /* let the registerer know that a connection has been established */ | 1524 | /* let the registerer know that a connection has been established */ |
1457 | 1525 | ||
1458 | if (ch->func != NULL) { | 1526 | if (ch->func != NULL) { |
@@ -1465,10 +1533,6 @@ xpc_connected_callout(struct xpc_channel *ch) | |||
1465 | dev_dbg(xpc_chan, "ch->func() returned, reason=xpcConnected, " | 1533 | dev_dbg(xpc_chan, "ch->func() returned, reason=xpcConnected, " |
1466 | "partid=%d, channel=%d\n", ch->partid, ch->number); | 1534 | "partid=%d, channel=%d\n", ch->partid, ch->number); |
1467 | } | 1535 | } |
1468 | |||
1469 | spin_lock_irqsave(&ch->lock, irq_flags); | ||
1470 | ch->flags |= XPC_C_CONNECTCALLOUT; | ||
1471 | spin_unlock_irqrestore(&ch->lock, irq_flags); | ||
1472 | } | 1536 | } |
1473 | 1537 | ||
1474 | 1538 | ||
@@ -1506,8 +1570,12 @@ xpc_initiate_disconnect(int ch_number) | |||
1506 | 1570 | ||
1507 | spin_lock_irqsave(&ch->lock, irq_flags); | 1571 | spin_lock_irqsave(&ch->lock, irq_flags); |
1508 | 1572 | ||
1509 | XPC_DISCONNECT_CHANNEL(ch, xpcUnregistering, | 1573 | if (!(ch->flags & XPC_C_DISCONNECTED)) { |
1574 | ch->flags |= XPC_C_WDISCONNECT; | ||
1575 | |||
1576 | XPC_DISCONNECT_CHANNEL(ch, xpcUnregistering, | ||
1510 | &irq_flags); | 1577 | &irq_flags); |
1578 | } | ||
1511 | 1579 | ||
1512 | spin_unlock_irqrestore(&ch->lock, irq_flags); | 1580 | spin_unlock_irqrestore(&ch->lock, irq_flags); |
1513 | 1581 | ||
@@ -1523,8 +1591,9 @@ xpc_initiate_disconnect(int ch_number) | |||
1523 | /* | 1591 | /* |
1524 | * To disconnect a channel, and reflect it back to all who may be waiting. | 1592 | * To disconnect a channel, and reflect it back to all who may be waiting. |
1525 | * | 1593 | * |
1526 | * >>> An OPEN is not allowed until XPC_C_DISCONNECTING is cleared by | 1594 | * An OPEN is not allowed until XPC_C_DISCONNECTING is cleared by |
1527 | * >>> xpc_free_msgqueues(). | 1595 | * xpc_process_disconnect(), and if set, XPC_C_WDISCONNECT is cleared by |
1596 | * xpc_disconnect_wait(). | ||
1528 | * | 1597 | * |
1529 | * THE CHANNEL IS TO BE LOCKED BY THE CALLER AND WILL REMAIN LOCKED UPON RETURN. | 1598 | * THE CHANNEL IS TO BE LOCKED BY THE CALLER AND WILL REMAIN LOCKED UPON RETURN. |
1530 | */ | 1599 | */ |
@@ -1532,7 +1601,7 @@ void | |||
1532 | xpc_disconnect_channel(const int line, struct xpc_channel *ch, | 1601 | xpc_disconnect_channel(const int line, struct xpc_channel *ch, |
1533 | enum xpc_retval reason, unsigned long *irq_flags) | 1602 | enum xpc_retval reason, unsigned long *irq_flags) |
1534 | { | 1603 | { |
1535 | u32 flags; | 1604 | u32 channel_was_connected = (ch->flags & XPC_C_CONNECTED); |
1536 | 1605 | ||
1537 | 1606 | ||
1538 | DBUG_ON(!spin_is_locked(&ch->lock)); | 1607 | DBUG_ON(!spin_is_locked(&ch->lock)); |
@@ -1547,61 +1616,53 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch, | |||
1547 | 1616 | ||
1548 | XPC_SET_REASON(ch, reason, line); | 1617 | XPC_SET_REASON(ch, reason, line); |
1549 | 1618 | ||
1550 | flags = ch->flags; | 1619 | ch->flags |= (XPC_C_CLOSEREQUEST | XPC_C_DISCONNECTING); |
1551 | /* some of these may not have been set */ | 1620 | /* some of these may not have been set */ |
1552 | ch->flags &= ~(XPC_C_OPENREQUEST | XPC_C_OPENREPLY | | 1621 | ch->flags &= ~(XPC_C_OPENREQUEST | XPC_C_OPENREPLY | |
1553 | XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY | | 1622 | XPC_C_ROPENREQUEST | XPC_C_ROPENREPLY | |
1554 | XPC_C_CONNECTING | XPC_C_CONNECTED); | 1623 | XPC_C_CONNECTING | XPC_C_CONNECTED); |
1555 | 1624 | ||
1556 | ch->flags |= (XPC_C_CLOSEREQUEST | XPC_C_DISCONNECTING); | ||
1557 | xpc_IPI_send_closerequest(ch, irq_flags); | 1625 | xpc_IPI_send_closerequest(ch, irq_flags); |
1558 | 1626 | ||
1559 | if (flags & XPC_C_CONNECTED) { | 1627 | if (channel_was_connected) { |
1560 | ch->flags |= XPC_C_WASCONNECTED; | 1628 | ch->flags |= XPC_C_WASCONNECTED; |
1561 | } | 1629 | } |
1562 | 1630 | ||
1631 | spin_unlock_irqrestore(&ch->lock, *irq_flags); | ||
1632 | |||
1633 | /* wake all idle kthreads so they can exit */ | ||
1563 | if (atomic_read(&ch->kthreads_idle) > 0) { | 1634 | if (atomic_read(&ch->kthreads_idle) > 0) { |
1564 | /* wake all idle kthreads so they can exit */ | ||
1565 | wake_up_all(&ch->idle_wq); | 1635 | wake_up_all(&ch->idle_wq); |
1566 | } | 1636 | } |
1567 | 1637 | ||
1568 | spin_unlock_irqrestore(&ch->lock, *irq_flags); | ||
1569 | |||
1570 | |||
1571 | /* wake those waiting to allocate an entry from the local msg queue */ | 1638 | /* wake those waiting to allocate an entry from the local msg queue */ |
1572 | |||
1573 | if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) { | 1639 | if (atomic_read(&ch->n_on_msg_allocate_wq) > 0) { |
1574 | wake_up(&ch->msg_allocate_wq); | 1640 | wake_up(&ch->msg_allocate_wq); |
1575 | } | 1641 | } |
1576 | 1642 | ||
1577 | /* wake those waiting for notify completion */ | ||
1578 | |||
1579 | if (atomic_read(&ch->n_to_notify) > 0) { | ||
1580 | xpc_notify_senders(ch, reason, ch->w_local_GP.put); | ||
1581 | } | ||
1582 | |||
1583 | spin_lock_irqsave(&ch->lock, *irq_flags); | 1643 | spin_lock_irqsave(&ch->lock, *irq_flags); |
1584 | } | 1644 | } |
1585 | 1645 | ||
1586 | 1646 | ||
1587 | void | 1647 | void |
1588 | xpc_disconnected_callout(struct xpc_channel *ch) | 1648 | xpc_disconnecting_callout(struct xpc_channel *ch) |
1589 | { | 1649 | { |
1590 | /* | 1650 | /* |
1591 | * Let the channel's registerer know that the channel is now | 1651 | * Let the channel's registerer know that the channel is being |
1592 | * disconnected. We don't want to do this if the registerer was never | 1652 | * disconnected. We don't want to do this if the registerer was never |
1593 | * informed of a connection being made, unless the disconnect was for | 1653 | * informed of a connection being made. |
1594 | * abnormal reasons. | ||
1595 | */ | 1654 | */ |
1596 | 1655 | ||
1597 | if (ch->func != NULL) { | 1656 | if (ch->func != NULL) { |
1598 | dev_dbg(xpc_chan, "ch->func() called, reason=%d, partid=%d, " | 1657 | dev_dbg(xpc_chan, "ch->func() called, reason=xpcDisconnecting," |
1599 | "channel=%d\n", ch->reason, ch->partid, ch->number); | 1658 | " partid=%d, channel=%d\n", ch->partid, ch->number); |
1600 | 1659 | ||
1601 | ch->func(ch->reason, ch->partid, ch->number, NULL, ch->key); | 1660 | ch->func(xpcDisconnecting, ch->partid, ch->number, NULL, |
1661 | ch->key); | ||
1602 | 1662 | ||
1603 | dev_dbg(xpc_chan, "ch->func() returned, reason=%d, partid=%d, " | 1663 | dev_dbg(xpc_chan, "ch->func() returned, reason=" |
1604 | "channel=%d\n", ch->reason, ch->partid, ch->number); | 1664 | "xpcDisconnecting, partid=%d, channel=%d\n", |
1665 | ch->partid, ch->number); | ||
1605 | } | 1666 | } |
1606 | } | 1667 | } |
1607 | 1668 | ||
@@ -1848,7 +1909,7 @@ xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type, | |||
1848 | xpc_notify_func func, void *key) | 1909 | xpc_notify_func func, void *key) |
1849 | { | 1910 | { |
1850 | enum xpc_retval ret = xpcSuccess; | 1911 | enum xpc_retval ret = xpcSuccess; |
1851 | struct xpc_notify *notify = NULL; // >>> to keep the compiler happy!! | 1912 | struct xpc_notify *notify = notify; |
1852 | s64 put, msg_number = msg->number; | 1913 | s64 put, msg_number = msg->number; |
1853 | 1914 | ||
1854 | 1915 | ||