Skip to content

Commit 1505c0e

Browse files
Dipayaan Roygregkh
authored andcommitted
net: hv_netvsc: fix loss of early receive events from host during channel open.
[ Upstream commit 9448ccd ] The hv_netvsc driver currently enables NAPI after opening the primary and subchannels. This ordering creates a race: if the Hyper-V host places data in the host -> guest ring buffer and signals the channel before napi_enable() has been called, the channel callback will run but napi_schedule_prep() will return false. As a result, the NAPI poller never gets scheduled, the data in the ring buffer is not consumed, and the receive queue may remain permanently stuck until another interrupt happens to arrive. Fix this by enabling NAPI and registering it with the RX/TX queues before vmbus channel is opened. This guarantees that any early host signal after open will correctly trigger NAPI scheduling and the ring buffer will be drained. Fixes: 76bb5db ("netvsc: fix use after free on module removal") Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com> Link: https://patch.msgid.link/20250825115627.GA32189@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 19a592e commit 1505c0e

File tree

2 files changed

+24
-16
lines changed

2 files changed

+24
-16
lines changed

drivers/net/hyperv/netvsc.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1812,6 +1812,11 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device,
18121812

18131813
/* Enable NAPI handler before init callbacks */
18141814
netif_napi_add(ndev, &net_device->chan_table[0].napi, netvsc_poll);
1815+
napi_enable(&net_device->chan_table[0].napi);
1816+
netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_RX,
1817+
&net_device->chan_table[0].napi);
1818+
netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_TX,
1819+
&net_device->chan_table[0].napi);
18151820

18161821
/* Open the channel */
18171822
device->channel->next_request_id_callback = vmbus_next_request_id;
@@ -1831,12 +1836,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device,
18311836
/* Channel is opened */
18321837
netdev_dbg(ndev, "hv_netvsc channel opened successfully\n");
18331838

1834-
napi_enable(&net_device->chan_table[0].napi);
1835-
netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_RX,
1836-
&net_device->chan_table[0].napi);
1837-
netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_TX,
1838-
&net_device->chan_table[0].napi);
1839-
18401839
/* Connect with the NetVsp */
18411840
ret = netvsc_connect_vsp(device, net_device, device_info);
18421841
if (ret != 0) {
@@ -1854,14 +1853,14 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device,
18541853

18551854
close:
18561855
RCU_INIT_POINTER(net_device_ctx->nvdev, NULL);
1857-
netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_TX, NULL);
1858-
netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_RX, NULL);
1859-
napi_disable(&net_device->chan_table[0].napi);
18601856

18611857
/* Now, we can close the channel safely */
18621858
vmbus_close(device->channel);
18631859

18641860
cleanup:
1861+
netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_TX, NULL);
1862+
netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_RX, NULL);
1863+
napi_disable(&net_device->chan_table[0].napi);
18651864
netif_napi_del(&net_device->chan_table[0].napi);
18661865

18671866
cleanup2:

drivers/net/hyperv/rndis_filter.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,17 +1252,26 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc)
12521252
new_sc->rqstor_size = netvsc_rqstor_size(netvsc_ring_bytes);
12531253
new_sc->max_pkt_size = NETVSC_MAX_PKT_SIZE;
12541254

1255+
/* Enable napi before opening the vmbus channel to avoid races
1256+
* as the host placing data on the host->guest ring may be left
1257+
* out if napi was not enabled.
1258+
*/
1259+
napi_enable(&nvchan->napi);
1260+
netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_RX,
1261+
&nvchan->napi);
1262+
netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_TX,
1263+
&nvchan->napi);
1264+
12551265
ret = vmbus_open(new_sc, netvsc_ring_bytes,
12561266
netvsc_ring_bytes, NULL, 0,
12571267
netvsc_channel_cb, nvchan);
1258-
if (ret == 0) {
1259-
napi_enable(&nvchan->napi);
1260-
netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_RX,
1261-
&nvchan->napi);
1262-
netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_TX,
1263-
&nvchan->napi);
1264-
} else {
1268+
if (ret != 0) {
12651269
netdev_notice(ndev, "sub channel open failed: %d\n", ret);
1270+
netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_TX,
1271+
NULL);
1272+
netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_RX,
1273+
NULL);
1274+
napi_disable(&nvchan->napi);
12661275
}
12671276

12681277
if (atomic_inc_return(&nvscdev->open_chn) == nvscdev->num_chn)

0 commit comments

Comments
 (0)