diff options
| author | K. Y. Srinivasan <kys@microsoft.com> | 2015-02-28 14:18:17 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-03-01 22:31:02 -0500 |
| commit | ed6cfcc5fdf2ebca320b6f74c836e555e18216e1 (patch) | |
| tree | 004638600297de1f56cef2fc075ab1a7c8f52e26 | |
| parent | d15a0301c4157884d1a48a5d76b9ac3e36d71242 (diff) | |
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: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| -rw-r--r-- | drivers/hv/channel.c | 9 | ||||
| -rw-r--r-- | drivers/hv/channel_mgmt.c | 49 | ||||
| -rw-r--r-- | drivers/hv/vmbus_drv.c | 11 | ||||
| -rw-r--r-- | include/linux/hyperv.h | 1 |
4 files changed, 50 insertions, 20 deletions
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index bf0cf8f3bcaf..9b79aca7e565 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c | |||
| @@ -501,6 +501,15 @@ static int vmbus_close_internal(struct vmbus_channel *channel) | |||
| 501 | put_cpu(); | 501 | put_cpu(); |
| 502 | } | 502 | } |
| 503 | 503 | ||
| 504 | /* | ||
| 505 | * If the channel has been rescinded; process device removal. | ||
| 506 | */ | ||
| 507 | if (channel->rescind) { | ||
| 508 | hv_process_channel_removal(channel, | ||
| 509 | channel->offermsg.child_relid); | ||
| 510 | return 0; | ||
| 511 | } | ||
| 512 | |||
| 504 | /* Send a closing message */ | 513 | /* Send a closing message */ |
| 505 | 514 | ||
| 506 | msg = &channel->close_msg.msg; | 515 | msg = &channel->close_msg.msg; |
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 0ba6b5c303e6..b93389124ec4 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c | |||
| @@ -207,33 +207,21 @@ static void percpu_channel_deq(void *arg) | |||
| 207 | list_del(&channel->percpu_list); | 207 | list_del(&channel->percpu_list); |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | /* | 210 | |
| 211 | * vmbus_process_rescind_offer - | 211 | void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) |
| 212 | * Rescind the offer by initiating a device removal | ||
| 213 | */ | ||
| 214 | static void vmbus_process_rescind_offer(struct work_struct *work) | ||
| 215 | { | 212 | { |
| 216 | struct vmbus_channel *channel = container_of(work, | 213 | struct vmbus_channel_relid_released msg; |
| 217 | struct vmbus_channel, | ||
| 218 | work); | ||
| 219 | unsigned long flags; | 214 | unsigned long flags; |
| 220 | struct vmbus_channel *primary_channel; | 215 | struct vmbus_channel *primary_channel; |
| 221 | struct vmbus_channel_relid_released msg; | ||
| 222 | struct device *dev; | ||
| 223 | |||
| 224 | if (channel->device_obj) { | ||
| 225 | dev = get_device(&channel->device_obj->device); | ||
| 226 | if (dev) { | ||
| 227 | vmbus_device_unregister(channel->device_obj); | ||
| 228 | put_device(dev); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | 216 | ||
| 232 | memset(&msg, 0, sizeof(struct vmbus_channel_relid_released)); | 217 | memset(&msg, 0, sizeof(struct vmbus_channel_relid_released)); |
| 233 | msg.child_relid = channel->offermsg.child_relid; | 218 | msg.child_relid = relid; |
| 234 | msg.header.msgtype = CHANNELMSG_RELID_RELEASED; | 219 | msg.header.msgtype = CHANNELMSG_RELID_RELEASED; |
| 235 | vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released)); | 220 | vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released)); |
| 236 | 221 | ||
| 222 | if (channel == NULL) | ||
| 223 | return; | ||
| 224 | |||
| 237 | if (channel->target_cpu != get_cpu()) { | 225 | if (channel->target_cpu != get_cpu()) { |
| 238 | put_cpu(); | 226 | put_cpu(); |
| 239 | smp_call_function_single(channel->target_cpu, | 227 | smp_call_function_single(channel->target_cpu, |
| @@ -256,6 +244,29 @@ static void vmbus_process_rescind_offer(struct work_struct *work) | |||
| 256 | free_channel(channel); | 244 | free_channel(channel); |
| 257 | } | 245 | } |
| 258 | 246 | ||
| 247 | /* | ||
| 248 | * vmbus_process_rescind_offer - | ||
| 249 | * Rescind the offer by initiating a device removal | ||
| 250 | */ | ||
| 251 | static void vmbus_process_rescind_offer(struct work_struct *work) | ||
| 252 | { | ||
| 253 | struct vmbus_channel *channel = container_of(work, | ||
| 254 | struct vmbus_channel, | ||
| 255 | work); | ||
| 256 | struct device *dev; | ||
| 257 | |||
| 258 | if (channel->device_obj) { | ||
| 259 | dev = get_device(&channel->device_obj->device); | ||
| 260 | if (dev) { | ||
| 261 | vmbus_device_unregister(channel->device_obj); | ||
| 262 | put_device(dev); | ||
| 263 | } | ||
| 264 | } else { | ||
| 265 | hv_process_channel_removal(channel, | ||
| 266 | channel->offermsg.child_relid); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 259 | void vmbus_free_channels(void) | 270 | void vmbus_free_channels(void) |
| 260 | { | 271 | { |
| 261 | struct vmbus_channel *channel; | 272 | struct vmbus_channel *channel; |
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index a12666d075ea..2b7b51d264f1 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c | |||
| @@ -510,14 +510,23 @@ static int vmbus_remove(struct device *child_device) | |||
| 510 | { | 510 | { |
| 511 | struct hv_driver *drv; | 511 | struct hv_driver *drv; |
| 512 | struct hv_device *dev = device_to_hv_device(child_device); | 512 | struct hv_device *dev = device_to_hv_device(child_device); |
| 513 | u32 relid = dev->channel->offermsg.child_relid; | ||
| 513 | 514 | ||
| 514 | if (child_device->driver) { | 515 | if (child_device->driver) { |
| 515 | drv = drv_to_hv_drv(child_device->driver); | 516 | drv = drv_to_hv_drv(child_device->driver); |
| 516 | if (drv->remove) | 517 | if (drv->remove) |
| 517 | drv->remove(dev); | 518 | drv->remove(dev); |
| 518 | else | 519 | else { |
| 520 | hv_process_channel_removal(dev->channel, relid); | ||
| 519 | pr_err("remove not set for driver %s\n", | 521 | pr_err("remove not set for driver %s\n", |
| 520 | dev_name(child_device)); | 522 | dev_name(child_device)); |
| 523 | } | ||
| 524 | } else { | ||
| 525 | /* | ||
| 526 | * We don't have a driver for this device; deal with the | ||
| 527 | * rescind message by removing the channel. | ||
| 528 | */ | ||
| 529 | hv_process_channel_removal(dev->channel, relid); | ||
| 521 | } | 530 | } |
| 522 | 531 | ||
| 523 | return 0; | 532 | return 0; |
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 7d976ac01fac..dd92a854c700 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h | |||
| @@ -1226,6 +1226,7 @@ void hv_kvp_onchannelcallback(void *); | |||
| 1226 | int hv_vss_init(struct hv_util_service *); | 1226 | int hv_vss_init(struct hv_util_service *); |
| 1227 | void hv_vss_deinit(void); | 1227 | void hv_vss_deinit(void); |
| 1228 | void hv_vss_onchannelcallback(void *); | 1228 | void hv_vss_onchannelcallback(void *); |
| 1229 | void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid); | ||
| 1229 | 1230 | ||
| 1230 | extern struct resource hyperv_mmio; | 1231 | extern struct resource hyperv_mmio; |
| 1231 | 1232 | ||
