Skip to content

Commit b3e6b82

Browse files
kattisrinivasandavem330
authored andcommitted
hv_netvsc: Wait for sub-channels to be processed during probe
The current code returns from probe without waiting for the proper handling of subchannels that may be requested. If the netvsc driver were to be rapidly loaded/unloaded, we can trigger a panic as the unload will be tearing down state that may not have been fully setup yet. We fix this issue by making sure that we return from the probe call only after ensuring that the sub-channel offers in flight are properly handled. Reviewed-and-tested-by: Haiyang Zhang <[email protected] Signed-off-by: K. Y. Srinivasan <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 402b764 commit b3e6b82

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

drivers/net/hyperv/hyperv_net.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,8 @@ struct netvsc_device {
671671
u32 send_table[VRSS_SEND_TAB_SIZE];
672672
u32 max_chn;
673673
u32 num_chn;
674+
spinlock_t sc_lock; /* Protects num_sc_offered variable */
675+
u32 num_sc_offered;
674676
atomic_t queue_sends[NR_CPUS];
675677

676678
/* Holds rndis device info */

drivers/net/hyperv/rndis_filter.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,9 +984,16 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc)
984984
struct netvsc_device *nvscdev;
985985
u16 chn_index = new_sc->offermsg.offer.sub_channel_index;
986986
int ret;
987+
unsigned long flags;
987988

988989
nvscdev = hv_get_drvdata(new_sc->primary_channel->device_obj);
989990

991+
spin_lock_irqsave(&nvscdev->sc_lock, flags);
992+
nvscdev->num_sc_offered--;
993+
spin_unlock_irqrestore(&nvscdev->sc_lock, flags);
994+
if (nvscdev->num_sc_offered == 0)
995+
complete(&nvscdev->channel_init_wait);
996+
990997
if (chn_index >= nvscdev->num_chn)
991998
return;
992999

@@ -1015,8 +1022,10 @@ int rndis_filter_device_add(struct hv_device *dev,
10151022
u32 rsscap_size = sizeof(struct ndis_recv_scale_cap);
10161023
u32 mtu, size;
10171024
u32 num_rss_qs;
1025+
u32 sc_delta;
10181026
const struct cpumask *node_cpu_mask;
10191027
u32 num_possible_rss_qs;
1028+
unsigned long flags;
10201029

10211030
rndis_device = get_rndis_device();
10221031
if (!rndis_device)
@@ -1039,6 +1048,8 @@ int rndis_filter_device_add(struct hv_device *dev,
10391048
net_device->max_chn = 1;
10401049
net_device->num_chn = 1;
10411050

1051+
spin_lock_init(&net_device->sc_lock);
1052+
10421053
net_device->extension = rndis_device;
10431054
rndis_device->net_dev = net_device;
10441055

@@ -1116,6 +1127,9 @@ int rndis_filter_device_add(struct hv_device *dev,
11161127
num_possible_rss_qs = cpumask_weight(node_cpu_mask);
11171128
net_device->num_chn = min(num_possible_rss_qs, num_rss_qs);
11181129

1130+
num_rss_qs = net_device->num_chn - 1;
1131+
net_device->num_sc_offered = num_rss_qs;
1132+
11191133
if (net_device->num_chn == 1)
11201134
goto out;
11211135

@@ -1157,11 +1171,25 @@ int rndis_filter_device_add(struct hv_device *dev,
11571171

11581172
ret = rndis_filter_set_rss_param(rndis_device, net_device->num_chn);
11591173

1174+
/*
1175+
* Wait for the host to send us the sub-channel offers.
1176+
*/
1177+
spin_lock_irqsave(&net_device->sc_lock, flags);
1178+
sc_delta = num_rss_qs - (net_device->num_chn - 1);
1179+
net_device->num_sc_offered -= sc_delta;
1180+
spin_unlock_irqrestore(&net_device->sc_lock, flags);
1181+
1182+
while (net_device->num_sc_offered != 0) {
1183+
t = wait_for_completion_timeout(&net_device->channel_init_wait, 10*HZ);
1184+
if (t == 0)
1185+
WARN(1, "Netvsc: Waiting for sub-channel processing");
1186+
}
11601187
out:
11611188
if (ret) {
11621189
net_device->max_chn = 1;
11631190
net_device->num_chn = 1;
11641191
}
1192+
11651193
return 0; /* return 0 because primary channel can be used alone */
11661194

11671195
err_dev_remv:

0 commit comments

Comments
 (0)