Skip to content

Commit 1c80dd8

Browse files
mhklinuxliuw
authored andcommitted
Drivers: hv: vmbus: Limit channel interrupt scan to relid high water mark
When checking for VMBus channel interrupts, current code always scans the full SynIC receive interrupt bit array to get the relid of the interrupting channels. The array has HV_EVENT_FLAGS_COUNT (2048) bits. But VMs rarely have more than 100 channels, and the relid is typically a small integer that is densely assigned by the Hyper-V host. It's wasteful to scan 2048 bits when it is highly unlikely that anything will be found past bit 100. The waste is double with Confidential VMBus because there are two receive interrupt arrays that must be scanned: one for the hypervisor SynIC and one for the paravisor SynIC. Improve the scanning by tracking the largest relid that has been offered by the Hyper-V host. Then when checking for VMBus channel interrupts, only scan up to this high water mark. When channels are rescinded, it's not worth the complexity to recalculate the high water mark. Hyper-V tends to reuse the rescinded relids for any new channels that are subsequently added, and the performance benefit of exactly tracking the high water mark would be minimal. Signed-off-by: Michael Kelley <mhklinux@outlook.com> Tested-by: Roman Kisel <vdso@mailbox.org> Reviewed-by: Roman Kisel <vdso@mailbox.org> Signed-off-by: Wei Liu <wei.liu@kernel.org>
1 parent 028ef9c commit 1c80dd8

3 files changed

Lines changed: 15 additions & 11 deletions

File tree

drivers/hv/channel_mgmt.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,18 @@ static void free_channel(struct vmbus_channel *channel)
384384

385385
void vmbus_channel_map_relid(struct vmbus_channel *channel)
386386
{
387-
if (WARN_ON(channel->offermsg.child_relid >= MAX_CHANNEL_RELIDS))
387+
u32 new_relid = channel->offermsg.child_relid;
388+
389+
if (WARN_ON(new_relid >= MAX_CHANNEL_RELIDS))
388390
return;
391+
392+
/*
393+
* This function is always called in the tasklet for the connect CPU.
394+
* So updating the relid hiwater mark does not need to be atomic.
395+
*/
396+
if (new_relid > READ_ONCE(vmbus_connection.relid_hiwater))
397+
WRITE_ONCE(vmbus_connection.relid_hiwater, new_relid);
398+
389399
/*
390400
* The mapping of the channel's relid is visible from the CPUs that
391401
* 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)
411421
* of the VMBus driver and vmbus_chan_sched() can not run before
412422
* vmbus_bus_resume() has completed execution (cf. resume_noirq).
413423
*/
414-
virt_store_mb(
415-
vmbus_connection.channels[channel->offermsg.child_relid],
416-
channel);
424+
virt_store_mb(vmbus_connection.channels[new_relid], channel);
417425
}
418426

419427
void vmbus_channel_unmap_relid(struct vmbus_channel *channel)

drivers/hv/hyperv_vmbus.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,9 @@ struct vmbus_connection {
276276
struct list_head chn_list;
277277
struct mutex channel_mutex;
278278

279-
/* Array of channels */
279+
/* Array of channel pointers, indexed by relid */
280280
struct vmbus_channel **channels;
281+
u32 relid_hiwater;
281282

282283
/*
283284
* An offer message is handled first on the work_queue, and then

drivers/hv/vmbus_drv.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,17 +1258,12 @@ static void vmbus_chan_sched(void *event_page_addr)
12581258
return;
12591259
event = (union hv_synic_event_flags *)event_page_addr + VMBUS_MESSAGE_SINT;
12601260

1261-
maxbits = HV_EVENT_FLAGS_COUNT;
1261+
maxbits = READ_ONCE(vmbus_connection.relid_hiwater) + 1;
12621262
recv_int_page = event->flags;
12631263

12641264
if (unlikely(!recv_int_page))
12651265
return;
12661266

1267-
/*
1268-
* Suggested-by: Michael Kelley <mhklinux@outlook.com>
1269-
* One possible optimization would be to keep track of the largest relID that's in use,
1270-
* and only scan up to that relID.
1271-
*/
12721267
for_each_set_bit(relid, recv_int_page, maxbits) {
12731268
void (*callback_fn)(void *context);
12741269
struct vmbus_channel *channel;

0 commit comments

Comments
 (0)