Skip to content

Commit 732e498

Browse files
shemmingerdavem330
authored andcommitted
netvsc: fix race on sub channel creation
The existing sub channel code did not wait for all the sub-channels to completely initialize. This could lead to race causing crash in napi_netif_del() from bad list. The existing code would send an init message, then wait only for the initial response that the init message was received. It thought it was waiting for sub channels but really the init response did the wakeup. The new code keeps track of the number of open channels and waits until that many are open. Other issues here were: * host might return less sub-channels than was requested. * the new init status is not valid until after init was completed. Fixes: b3e6b82 ("hv_netvsc: Wait for sub-channels to be processed during probe") Signed-off-by: Stephen Hemminger <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2c46062 commit 732e498

File tree

3 files changed

+11
-7
lines changed

3 files changed

+11
-7
lines changed

drivers/net/hyperv/hyperv_net.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,8 @@ struct netvsc_device {
765765
u32 max_chn;
766766
u32 num_chn;
767767

768-
refcount_t sc_offered;
768+
atomic_t open_chn;
769+
wait_queue_head_t subchan_open;
769770

770771
struct rndis_device *extension;
771772

drivers/net/hyperv/netvsc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ static struct netvsc_device *alloc_net_device(void)
7878
net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT;
7979
net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT;
8080
init_completion(&net_device->channel_init_wait);
81+
init_waitqueue_head(&net_device->subchan_open);
8182

8283
return net_device;
8384
}

drivers/net/hyperv/rndis_filter.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,8 +1048,8 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc)
10481048
else
10491049
netif_napi_del(&nvchan->napi);
10501050

1051-
if (refcount_dec_and_test(&nvscdev->sc_offered))
1052-
complete(&nvscdev->channel_init_wait);
1051+
atomic_inc(&nvscdev->open_chn);
1052+
wake_up(&nvscdev->subchan_open);
10531053
}
10541054

10551055
int rndis_filter_device_add(struct hv_device *dev,
@@ -1090,8 +1090,6 @@ int rndis_filter_device_add(struct hv_device *dev,
10901090
net_device->max_chn = 1;
10911091
net_device->num_chn = 1;
10921092

1093-
refcount_set(&net_device->sc_offered, 0);
1094-
10951093
net_device->extension = rndis_device;
10961094
rndis_device->ndev = net;
10971095

@@ -1221,11 +1219,11 @@ int rndis_filter_device_add(struct hv_device *dev,
12211219
rndis_device->ind_table[i] = ethtool_rxfh_indir_default(i,
12221220
net_device->num_chn);
12231221

1222+
atomic_set(&net_device->open_chn, 1);
12241223
num_rss_qs = net_device->num_chn - 1;
12251224
if (num_rss_qs == 0)
12261225
return 0;
12271226

1228-
refcount_set(&net_device->sc_offered, num_rss_qs);
12291227
vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open);
12301228

12311229
init_packet = &net_device->channel_init_pkt;
@@ -1242,15 +1240,19 @@ int rndis_filter_device_add(struct hv_device *dev,
12421240
if (ret)
12431241
goto out;
12441242

1243+
wait_for_completion(&net_device->channel_init_wait);
12451244
if (init_packet->msg.v5_msg.subchn_comp.status != NVSP_STAT_SUCCESS) {
12461245
ret = -ENODEV;
12471246
goto out;
12481247
}
1249-
wait_for_completion(&net_device->channel_init_wait);
12501248

12511249
net_device->num_chn = 1 +
12521250
init_packet->msg.v5_msg.subchn_comp.num_subchannels;
12531251

1252+
/* wait for all sub channels to open */
1253+
wait_event(net_device->subchan_open,
1254+
atomic_read(&net_device->open_chn) == net_device->num_chn);
1255+
12541256
/* ignore failues from setting rss parameters, still have channels */
12551257
rndis_filter_set_rss_param(rndis_device, netvsc_hash_key,
12561258
net_device->num_chn);

0 commit comments

Comments
 (0)