Skip to content

Commit e988840

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 22b6f45 commit e988840

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
@@ -1811,6 +1811,11 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device,
18111811

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

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

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

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

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

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

18661865
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)