diff options
Diffstat (limited to 'drivers/hv/channel_mgmt.c')
-rw-r--r-- | drivers/hv/channel_mgmt.c | 78 |
1 files changed, 54 insertions, 24 deletions
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index bcbb031f7263..ec5454f3f4a6 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -159,7 +159,7 @@ static void vmbus_rescind_cleanup(struct vmbus_channel *channel) spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); - + channel->rescind = true; list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list, msglistentry) { @@ -350,7 +350,7 @@ static void free_channel(struct vmbus_channel *channel) { tasklet_kill(&channel->callback_event); - kfree_rcu(channel, rcu); + kobject_put(&channel->kobj); } static void percpu_channel_enq(void *arg) @@ -373,22 +373,32 @@ static void percpu_channel_deq(void *arg) static void vmbus_release_relid(u32 relid) { struct vmbus_channel_relid_released msg; + int ret; memset(&msg, 0, sizeof(struct vmbus_channel_relid_released)); msg.child_relid = relid; msg.header.msgtype = CHANNELMSG_RELID_RELEASED; - vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released), - true); + ret = vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released), + true); + + trace_vmbus_release_relid(&msg, ret); } -void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) +void hv_process_channel_removal(u32 relid) { unsigned long flags; - struct vmbus_channel *primary_channel; + struct vmbus_channel *primary_channel, *channel; - BUG_ON(!channel->rescind); BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex)); + /* + * Make sure channel is valid as we may have raced. + */ + channel = relid2channel(relid); + if (!channel) + return; + + BUG_ON(!channel->rescind); if (channel->target_cpu != get_cpu()) { put_cpu(); smp_call_function_single(channel->target_cpu, @@ -513,8 +523,17 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) newchannel->state = CHANNEL_OPEN_STATE; if (!fnew) { + struct hv_device *dev + = newchannel->primary_channel->device_obj; + + if (vmbus_add_channel_kobj(dev, newchannel)) { + atomic_dec(&vmbus_connection.offer_in_progress); + goto err_free_chan; + } + if (channel->sc_creation_callback != NULL) channel->sc_creation_callback(newchannel); + newchannel->probe_done = true; return; } @@ -797,6 +816,8 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) offer = (struct vmbus_channel_offer_channel *)hdr; + trace_vmbus_onoffer(offer); + /* Allocate the channel object and save this offer. */ newchannel = alloc_channel(); if (!newchannel) { @@ -834,11 +855,12 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) { struct vmbus_channel_rescind_offer *rescind; struct vmbus_channel *channel; - unsigned long flags; struct device *dev; rescind = (struct vmbus_channel_rescind_offer *)hdr; + trace_vmbus_onoffer_rescind(rescind); + /* * The offer msg and the corresponding rescind msg * from the host are guranteed to be ordered - @@ -873,16 +895,6 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) return; } - spin_lock_irqsave(&channel->lock, flags); - channel->rescind = true; - spin_unlock_irqrestore(&channel->lock, flags); - - /* - * Now that we have posted the rescind state, perform - * rescind related cleanup. - */ - vmbus_rescind_cleanup(channel); - /* * Now wait for offer handling to complete. */ @@ -901,6 +913,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) if (channel->device_obj) { if (channel->chn_rescind_callback) { channel->chn_rescind_callback(channel); + vmbus_rescind_cleanup(channel); return; } /* @@ -909,6 +922,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) */ dev = get_device(&channel->device_obj->device); if (dev) { + vmbus_rescind_cleanup(channel); vmbus_device_unregister(channel->device_obj); put_device(dev); } @@ -921,16 +935,16 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) * 1. Close all sub-channels first * 2. Then close the primary channel. */ + mutex_lock(&vmbus_connection.channel_mutex); + vmbus_rescind_cleanup(channel); if (channel->state == CHANNEL_OPEN_STATE) { /* * The channel is currently not open; * it is safe for us to cleanup the channel. */ - mutex_lock(&vmbus_connection.channel_mutex); - hv_process_channel_removal(channel, - channel->offermsg.child_relid); - mutex_unlock(&vmbus_connection.channel_mutex); + hv_process_channel_removal(rescind->child_relid); } + mutex_unlock(&vmbus_connection.channel_mutex); } } @@ -938,7 +952,10 @@ void vmbus_hvsock_device_unregister(struct vmbus_channel *channel) { BUG_ON(!is_hvsock_channel(channel)); - channel->rescind = true; + /* We always get a rescind msg when a connection is closed. */ + while (!READ_ONCE(channel->probe_done) || !READ_ONCE(channel->rescind)) + msleep(1); + vmbus_device_unregister(channel->device_obj); } EXPORT_SYMBOL_GPL(vmbus_hvsock_device_unregister); @@ -972,6 +989,8 @@ static void vmbus_onopen_result(struct vmbus_channel_message_header *hdr) result = (struct vmbus_channel_open_result *)hdr; + trace_vmbus_onopen_result(result); + /* * Find the open msg, copy the result and signal/unblock the wait event */ @@ -1016,6 +1035,8 @@ static void vmbus_ongpadl_created(struct vmbus_channel_message_header *hdr) gpadlcreated = (struct vmbus_channel_gpadl_created *)hdr; + trace_vmbus_ongpadl_created(gpadlcreated); + /* * Find the establish msg, copy the result and signal/unblock the wait * event @@ -1064,6 +1085,8 @@ static void vmbus_ongpadl_torndown( gpadl_torndown = (struct vmbus_channel_gpadl_torndown *)hdr; + trace_vmbus_ongpadl_torndown(gpadl_torndown); + /* * Find the open msg, copy the result and signal/unblock the wait event */ @@ -1107,6 +1130,9 @@ static void vmbus_onversion_response( unsigned long flags; version_response = (struct vmbus_channel_version_response *)hdr; + + trace_vmbus_onversion_response(version_response); + spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list, @@ -1166,6 +1192,8 @@ void vmbus_onmessage(void *context) hdr = (struct vmbus_channel_message_header *)msg->u.payload; size = msg->header.payload_size; + trace_vmbus_on_message(hdr); + if (hdr->msgtype >= CHANNELMSG_COUNT) { pr_err("Received invalid channel message type %d size %d\n", hdr->msgtype, size); @@ -1199,9 +1227,11 @@ int vmbus_request_offers(void) msg->msgtype = CHANNELMSG_REQUESTOFFERS; - ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_message_header), true); + + trace_vmbus_request_offers(ret); + if (ret != 0) { pr_err("Unable to request offers - %d\n", ret); |