Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1bdcec8a authored by Vitaly Kuznetsov's avatar Vitaly Kuznetsov Committed by David S. Miller
Browse files

hv_netvsc: use start_remove flag to protect netvsc_link_change()



netvsc_link_change() can race with netvsc_change_mtu() or
netvsc_set_channels() as these functions destroy struct netvsc_device and
rndis filter. Use start_remove flag for syncronization. As
netvsc_change_mtu()/netvsc_set_channels() are called with rtnl lock held
we need to take it before checking start_remove value in
netvsc_link_change().

Reported-by: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: default avatarVitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f580aec4
Loading
Loading
Loading
Loading
+17 −4
Original line number Diff line number Diff line
@@ -838,6 +838,8 @@ static int netvsc_set_channels(struct net_device *net,
 out:
	netvsc_open(net);
	net_device_ctx->start_remove = false;
	/* We may have missed link change notifications */
	schedule_delayed_work(&net_device_ctx->dwork, 0);

	return ret;

@@ -946,6 +948,9 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
	netvsc_open(ndev);
	ndevctx->start_remove = false;

	/* We may have missed link change notifications */
	schedule_delayed_work(&ndevctx->dwork, 0);

	return ret;
}

@@ -1066,6 +1071,11 @@ static void netvsc_link_change(struct work_struct *w)
	unsigned long flags, next_reconfig, delay;

	ndev_ctx = container_of(w, struct net_device_context, dwork.work);

	rtnl_lock();
	if (ndev_ctx->start_remove)
		goto out_unlock;

	net_device = hv_get_drvdata(ndev_ctx->device_ctx);
	rdev = net_device->extension;
	net = net_device->ndev;
@@ -1079,7 +1089,7 @@ static void netvsc_link_change(struct work_struct *w)
		delay = next_reconfig - jiffies;
		delay = delay < LINKCHANGE_INT ? delay : LINKCHANGE_INT;
		schedule_delayed_work(&ndev_ctx->dwork, delay);
		return;
		goto out_unlock;
	}
	ndev_ctx->last_reconfig = jiffies;

@@ -1093,9 +1103,7 @@ static void netvsc_link_change(struct work_struct *w)
	spin_unlock_irqrestore(&ndev_ctx->lock, flags);

	if (!event)
		return;

	rtnl_lock();
		goto out_unlock;

	switch (event->event) {
		/* Only the following events are possible due to the check in
@@ -1144,6 +1152,11 @@ static void netvsc_link_change(struct work_struct *w)
	 */
	if (reschedule)
		schedule_delayed_work(&ndev_ctx->dwork, LINKCHANGE_INT);

	return;

out_unlock:
	rtnl_unlock();
}

static void netvsc_free_netdev(struct net_device *netdev)