Index: head/sys/dev/hyperv/include/hyperv.h =================================================================== --- head/sys/dev/hyperv/include/hyperv.h +++ head/sys/dev/hyperv/include/hyperv.h @@ -533,7 +533,6 @@ } __packed hv_vmbus_connection_id; typedef struct hv_vmbus_channel { - TAILQ_ENTRY(hv_vmbus_channel) list_entry; struct hv_device* device; struct vmbus_softc *vmbus_sc; hv_vmbus_channel_state state; @@ -627,6 +626,7 @@ void *hv_chan_priv3; struct task ch_detach_task; + TAILQ_ENTRY(hv_vmbus_channel) ch_link; } hv_vmbus_channel; #define HV_VMBUS_CHAN_ISPRIMARY(chan) ((chan)->primary_channel == NULL) Index: head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c =================================================================== --- head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c +++ head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c @@ -108,6 +108,7 @@ static void vmbus_channel_process_offer(hv_vmbus_channel *new_channel) { + struct vmbus_softc *sc = new_channel->vmbus_sc; hv_vmbus_channel* channel; uint32_t relid; @@ -115,7 +116,7 @@ /* * Make sure this is a new offer */ - mtx_lock(&hv_vmbus_g_connection.channel_lock); + mtx_lock(&sc->vmbus_chlist_lock); if (relid == 0) { /* * XXX channel0 will not be processed; skip it. @@ -125,8 +126,7 @@ hv_vmbus_g_connection.channels[relid] = new_channel; } - TAILQ_FOREACH(channel, &hv_vmbus_g_connection.channel_anchor, - list_entry) { + TAILQ_FOREACH(channel, &sc->vmbus_chlist, ch_link) { if (memcmp(&channel->offer_msg.offer.interface_type, &new_channel->offer_msg.offer.interface_type, sizeof(hv_guid)) == 0 && @@ -138,10 +138,9 @@ if (channel == NULL) { /* Install the new primary channel */ - TAILQ_INSERT_TAIL(&hv_vmbus_g_connection.channel_anchor, - new_channel, list_entry); + TAILQ_INSERT_TAIL(&sc->vmbus_chlist, new_channel, ch_link); } - mtx_unlock(&hv_vmbus_g_connection.channel_lock); + mtx_unlock(&sc->vmbus_chlist_lock); if (channel != NULL) { /* @@ -165,11 +164,19 @@ new_channel->offer_msg.offer.sub_channel_index); } - /* Insert new channel into channel_anchor. */ - mtx_lock(&hv_vmbus_g_connection.channel_lock); - TAILQ_INSERT_TAIL(&hv_vmbus_g_connection.channel_anchor, - new_channel, list_entry); - mtx_unlock(&hv_vmbus_g_connection.channel_lock); + /* + * Insert the new channel to the end of the global + * channel list. + * + * NOTE: + * The new sub-channel MUST be inserted AFTER it's + * primary channel, so that the primary channel will + * be found in the above loop for its baby siblings. + */ + mtx_lock(&sc->vmbus_chlist_lock); + TAILQ_INSERT_TAIL(&sc->vmbus_chlist, new_channel, + ch_link); + mtx_unlock(&sc->vmbus_chlist_lock); if(bootverbose) printf("VMBUS: new multi-channel offer <%p>, " @@ -375,16 +382,15 @@ * @brief Release channels that are unattached/unconnected (i.e., no drivers associated) */ void -hv_vmbus_release_unattached_channels(void) +hv_vmbus_release_unattached_channels(struct vmbus_softc *sc) { hv_vmbus_channel *channel; - mtx_lock(&hv_vmbus_g_connection.channel_lock); + mtx_lock(&sc->vmbus_chlist_lock); - while (!TAILQ_EMPTY(&hv_vmbus_g_connection.channel_anchor)) { - channel = TAILQ_FIRST(&hv_vmbus_g_connection.channel_anchor); - TAILQ_REMOVE(&hv_vmbus_g_connection.channel_anchor, - channel, list_entry); + while (!TAILQ_EMPTY(&sc->vmbus_chlist)) { + channel = TAILQ_FIRST(&sc->vmbus_chlist); + TAILQ_REMOVE(&sc->vmbus_chlist, channel, ch_link); if (HV_VMBUS_CHAN_ISPRIMARY(channel)) { /* Only primary channel owns the hv_device */ @@ -394,7 +400,8 @@ } bzero(hv_vmbus_g_connection.channels, sizeof(hv_vmbus_channel*) * VMBUS_CHAN_MAX); - mtx_unlock(&hv_vmbus_g_connection.channel_lock); + + mtx_unlock(&sc->vmbus_chlist_lock); } /** Index: head/sys/dev/hyperv/vmbus/hv_connection.c =================================================================== --- head/sys/dev/hyperv/vmbus/hv_connection.c +++ head/sys/dev/hyperv/vmbus/hv_connection.c @@ -67,10 +67,6 @@ */ hv_vmbus_g_connection.connect_state = HV_CONNECTING; - TAILQ_INIT(&hv_vmbus_g_connection.channel_anchor); - mtx_init(&hv_vmbus_g_connection.channel_lock, "vmbus channel", - NULL, MTX_DEF); - hv_vmbus_g_connection.channels = malloc(sizeof(hv_vmbus_channel*) * VMBUS_CHAN_MAX, M_DEVBUF, M_WAITOK | M_ZERO); Index: head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h =================================================================== --- head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h +++ head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h @@ -38,6 +38,8 @@ #include +struct vmbus_softc; + typedef struct { void* data; uint32_t length; @@ -109,13 +111,6 @@ hv_vmbus_connect_state connect_state; /** - * List of primary channels. Sub channels will be linked - * under their primary channel. - */ - TAILQ_HEAD(, hv_vmbus_channel) channel_anchor; - struct mtx channel_lock; - - /** * channel table for fast lookup through id. */ hv_vmbus_channel **channels; @@ -239,15 +234,14 @@ hv_vmbus_ring_buffer_info *ring_info); void hv_vmbus_free_vmbus_channel(hv_vmbus_channel *channel); -void hv_vmbus_release_unattached_channels(void); +void hv_vmbus_release_unattached_channels( + struct vmbus_softc *); struct hv_device* hv_vmbus_child_device_create( hv_guid device_type, hv_guid device_instance, hv_vmbus_channel *channel); -struct vmbus_softc; - void hv_vmbus_child_device_register(struct vmbus_softc *, struct hv_device *child_dev); int hv_vmbus_child_device_unregister( Index: head/sys/dev/hyperv/vmbus/vmbus.c =================================================================== --- head/sys/dev/hyperv/vmbus/vmbus.c +++ head/sys/dev/hyperv/vmbus/vmbus.c @@ -1130,6 +1130,8 @@ mtx_init(&sc->vmbus_scan_lock, "vmbus scan", NULL, MTX_DEF); sc->vmbus_gpadl = VMBUS_GPADL_START; + mtx_init(&sc->vmbus_chlist_lock, "vmbus chlist", NULL, MTX_DEF); + TAILQ_INIT(&sc->vmbus_chlist); /* * Create context for "post message" Hypercalls @@ -1262,7 +1264,7 @@ { struct vmbus_softc *sc = device_get_softc(dev); - hv_vmbus_release_unattached_channels(); + hv_vmbus_release_unattached_channels(sc); vmbus_disconnect(sc); hv_vmbus_disconnect(); Index: head/sys/dev/hyperv/vmbus/vmbus_var.h =================================================================== --- head/sys/dev/hyperv/vmbus/vmbus_var.h +++ head/sys/dev/hyperv/vmbus/vmbus_var.h @@ -100,6 +100,9 @@ uint32_t vmbus_scan_chcnt; #define VMBUS_SCAN_CHCNT_DONE 0x80000000 uint32_t vmbus_scan_devcnt; + + struct mtx vmbus_chlist_lock; + TAILQ_HEAD(, hv_vmbus_channel) vmbus_chlist; }; #define VMBUS_FLAG_ATTACHED 0x0001 /* vmbus was attached */