Commit ed6cfcc5 authored by K. Y. Srinivasan's avatar K. Y. Srinivasan Committed by Greg Kroah-Hartman

Drivers: hv: vmbus: Introduce a function to remove a rescinded offer

In response to a rescind message, we need to remove the channel and the
corresponding device. Cleanup this code path by factoring out the code
to remove a channel.
Signed-off-by: default avatarK. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d15a0301
...@@ -501,6 +501,15 @@ static int vmbus_close_internal(struct vmbus_channel *channel) ...@@ -501,6 +501,15 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
put_cpu(); put_cpu();
} }
/*
* If the channel has been rescinded; process device removal.
*/
if (channel->rescind) {
hv_process_channel_removal(channel,
channel->offermsg.child_relid);
return 0;
}
/* Send a closing message */ /* Send a closing message */
msg = &channel->close_msg.msg; msg = &channel->close_msg.msg;
......
...@@ -207,33 +207,21 @@ static void percpu_channel_deq(void *arg) ...@@ -207,33 +207,21 @@ static void percpu_channel_deq(void *arg)
list_del(&channel->percpu_list); list_del(&channel->percpu_list);
} }
/*
* vmbus_process_rescind_offer - void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
* Rescind the offer by initiating a device removal
*/
static void vmbus_process_rescind_offer(struct work_struct *work)
{ {
struct vmbus_channel *channel = container_of(work, struct vmbus_channel_relid_released msg;
struct vmbus_channel,
work);
unsigned long flags; unsigned long flags;
struct vmbus_channel *primary_channel; struct vmbus_channel *primary_channel;
struct vmbus_channel_relid_released msg;
struct device *dev;
if (channel->device_obj) {
dev = get_device(&channel->device_obj->device);
if (dev) {
vmbus_device_unregister(channel->device_obj);
put_device(dev);
}
}
memset(&msg, 0, sizeof(struct vmbus_channel_relid_released)); memset(&msg, 0, sizeof(struct vmbus_channel_relid_released));
msg.child_relid = channel->offermsg.child_relid; msg.child_relid = relid;
msg.header.msgtype = CHANNELMSG_RELID_RELEASED; msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released)); vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
if (channel == NULL)
return;
if (channel->target_cpu != get_cpu()) { if (channel->target_cpu != get_cpu()) {
put_cpu(); put_cpu();
smp_call_function_single(channel->target_cpu, smp_call_function_single(channel->target_cpu,
...@@ -256,6 +244,29 @@ static void vmbus_process_rescind_offer(struct work_struct *work) ...@@ -256,6 +244,29 @@ static void vmbus_process_rescind_offer(struct work_struct *work)
free_channel(channel); free_channel(channel);
} }
/*
* vmbus_process_rescind_offer -
* Rescind the offer by initiating a device removal
*/
static void vmbus_process_rescind_offer(struct work_struct *work)
{
struct vmbus_channel *channel = container_of(work,
struct vmbus_channel,
work);
struct device *dev;
if (channel->device_obj) {
dev = get_device(&channel->device_obj->device);
if (dev) {
vmbus_device_unregister(channel->device_obj);
put_device(dev);
}
} else {
hv_process_channel_removal(channel,
channel->offermsg.child_relid);
}
}
void vmbus_free_channels(void) void vmbus_free_channels(void)
{ {
struct vmbus_channel *channel; struct vmbus_channel *channel;
......
...@@ -510,14 +510,23 @@ static int vmbus_remove(struct device *child_device) ...@@ -510,14 +510,23 @@ static int vmbus_remove(struct device *child_device)
{ {
struct hv_driver *drv; struct hv_driver *drv;
struct hv_device *dev = device_to_hv_device(child_device); struct hv_device *dev = device_to_hv_device(child_device);
u32 relid = dev->channel->offermsg.child_relid;
if (child_device->driver) { if (child_device->driver) {
drv = drv_to_hv_drv(child_device->driver); drv = drv_to_hv_drv(child_device->driver);
if (drv->remove) if (drv->remove)
drv->remove(dev); drv->remove(dev);
else else {
hv_process_channel_removal(dev->channel, relid);
pr_err("remove not set for driver %s\n", pr_err("remove not set for driver %s\n",
dev_name(child_device)); dev_name(child_device));
}
} else {
/*
* We don't have a driver for this device; deal with the
* rescind message by removing the channel.
*/
hv_process_channel_removal(dev->channel, relid);
} }
return 0; return 0;
......
...@@ -1226,6 +1226,7 @@ void hv_kvp_onchannelcallback(void *); ...@@ -1226,6 +1226,7 @@ void hv_kvp_onchannelcallback(void *);
int hv_vss_init(struct hv_util_service *); int hv_vss_init(struct hv_util_service *);
void hv_vss_deinit(void); void hv_vss_deinit(void);
void hv_vss_onchannelcallback(void *); void hv_vss_onchannelcallback(void *);
void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid);
extern struct resource hyperv_mmio; extern struct resource hyperv_mmio;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment