diff options
Diffstat (limited to 'drivers/hv')
-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 |
3 files changed, 49 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; |