summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/hv/channel_mgmt.c16
-rw-r--r--drivers/hv/hyperv_vmbus.h3
-rw-r--r--drivers/hv/vmbus_drv.c7
3 files changed, 15 insertions, 11 deletions
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 7c77ada12b2e..84eb0a6a0b54 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -384,8 +384,18 @@ static void free_channel(struct vmbus_channel *channel)
void vmbus_channel_map_relid(struct vmbus_channel *channel)
{
- if (WARN_ON(channel->offermsg.child_relid >= MAX_CHANNEL_RELIDS))
+ u32 new_relid = channel->offermsg.child_relid;
+
+ if (WARN_ON(new_relid >= MAX_CHANNEL_RELIDS))
return;
+
+ /*
+ * This function is always called in the tasklet for the connect CPU.
+ * So updating the relid hiwater mark does not need to be atomic.
+ */
+ if (new_relid > READ_ONCE(vmbus_connection.relid_hiwater))
+ WRITE_ONCE(vmbus_connection.relid_hiwater, new_relid);
+
/*
* The mapping of the channel's relid is visible from the CPUs that
* execute vmbus_chan_sched() by the time that vmbus_chan_sched() will
@@ -411,9 +421,7 @@ void vmbus_channel_map_relid(struct vmbus_channel *channel)
* of the VMBus driver and vmbus_chan_sched() can not run before
* vmbus_bus_resume() has completed execution (cf. resume_noirq).
*/
- virt_store_mb(
- vmbus_connection.channels[channel->offermsg.child_relid],
- channel);
+ virt_store_mb(vmbus_connection.channels[new_relid], channel);
}
void vmbus_channel_unmap_relid(struct vmbus_channel *channel)
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 7bd8f8486e85..2c90c81a3b0f 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -276,8 +276,9 @@ struct vmbus_connection {
struct list_head chn_list;
struct mutex channel_mutex;
- /* Array of channels */
+ /* Array of channel pointers, indexed by relid */
struct vmbus_channel **channels;
+ u32 relid_hiwater;
/*
* An offer message is handled first on the work_queue, and then
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index bc4fc1951ae1..3d1a58b667db 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -1258,17 +1258,12 @@ static void vmbus_chan_sched(void *event_page_addr)
return;
event = (union hv_synic_event_flags *)event_page_addr + VMBUS_MESSAGE_SINT;
- maxbits = HV_EVENT_FLAGS_COUNT;
+ maxbits = READ_ONCE(vmbus_connection.relid_hiwater) + 1;
recv_int_page = event->flags;
if (unlikely(!recv_int_page))
return;
- /*
- * Suggested-by: Michael Kelley <mhklinux@outlook.com>
- * One possible optimization would be to keep track of the largest relID that's in use,
- * and only scan up to that relID.
- */
for_each_set_bit(relid, recv_int_page, maxbits) {
void (*callback_fn)(void *context);
struct vmbus_channel *channel;