Skip to content

Commit 8809883

Browse files
vittyvkdavem330
authored andcommitted
hv_netvsc: set nvdev link after populating chn_table
Crash in netvsc_send() is observed when netvsc device is re-created on mtu change/set channels. The crash is caused by dereferencing of NULL channel pointer which comes from chn_table. The root cause is a mixture of two facts: - we set nvdev pointer in net_device_context in alloc_net_device() before we populate chn_table. - we populate chn_table[0] only. The issue could be papered over by checking channel != NULL in netvsc_send() but populating the whole chn_table and writing the nvdev pointer afterwards seems more appropriate. Signed-off-by: Vitaly Kuznetsov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6da7225 commit 8809883

File tree

1 file changed

+18
-11
lines changed

1 file changed

+18
-11
lines changed

drivers/net/hyperv/netvsc.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,9 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf)
6060
}
6161

6262

63-
static struct netvsc_device *alloc_net_device(struct hv_device *device)
63+
static struct netvsc_device *alloc_net_device(void)
6464
{
6565
struct netvsc_device *net_device;
66-
struct net_device *ndev = hv_get_drvdata(device);
67-
struct net_device_context *net_device_ctx = netdev_priv(ndev);
6866

6967
net_device = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL);
7068
if (!net_device)
@@ -86,8 +84,6 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
8684
net_device->vf_netdev = NULL;
8785
net_device->vf_inject = false;
8886

89-
net_device_ctx->nvdev = net_device;
90-
9187
return net_device;
9288
}
9389

@@ -1240,20 +1236,19 @@ void netvsc_channel_cb(void *context)
12401236
*/
12411237
int netvsc_device_add(struct hv_device *device, void *additional_info)
12421238
{
1243-
int ret = 0;
1239+
int i, ret = 0;
12441240
int ring_size =
12451241
((struct netvsc_device_info *)additional_info)->ring_size;
12461242
struct netvsc_device *net_device;
1247-
struct net_device *ndev;
1243+
struct net_device *ndev = hv_get_drvdata(device);
1244+
struct net_device_context *net_device_ctx = netdev_priv(ndev);
12481245

1249-
net_device = alloc_net_device(device);
1246+
net_device = alloc_net_device();
12501247
if (!net_device)
12511248
return -ENOMEM;
12521249

12531250
net_device->ring_size = ring_size;
12541251

1255-
ndev = hv_get_drvdata(device);
1256-
12571252
/* Initialize the NetVSC channel extension */
12581253
init_completion(&net_device->channel_init_wait);
12591254

@@ -1272,7 +1267,19 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
12721267
/* Channel is opened */
12731268
pr_info("hv_netvsc channel opened successfully\n");
12741269

1275-
net_device->chn_table[0] = device->channel;
1270+
/* If we're reopening the device we may have multiple queues, fill the
1271+
* chn_table with the default channel to use it before subchannels are
1272+
* opened.
1273+
*/
1274+
for (i = 0; i < VRSS_CHANNEL_MAX; i++)
1275+
net_device->chn_table[i] = device->channel;
1276+
1277+
/* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is
1278+
* populated.
1279+
*/
1280+
wmb();
1281+
1282+
net_device_ctx->nvdev = net_device;
12761283

12771284
/* Connect with the NetVsp */
12781285
ret = netvsc_connect_vsp(device);

0 commit comments

Comments
 (0)