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
* 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)
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
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;