Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+9 −0
Original line number Original line Diff line number Diff line
@@ -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;
+30 −19
Original line number Original line Diff line number Diff line
@@ -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)
	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;
+10 −1
Original line number Original line Diff line number Diff line
@@ -510,15 +510,24 @@ 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;
}
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -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;