kernel: backport fix for hang on napi_disable with threaded NAPI
Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
		| @@ -0,0 +1,53 @@ | |||||||
|  | From: Paolo Abeni <pabeni@redhat.com> | ||||||
|  | Date: Fri, 9 Apr 2021 17:24:17 +0200 | ||||||
|  | Subject: [PATCH] net: fix hangup on napi_disable for threaded napi | ||||||
|  |  | ||||||
|  | napi_disable() is subject to an hangup, when the threaded | ||||||
|  | mode is enabled and the napi is under heavy traffic. | ||||||
|  |  | ||||||
|  | If the relevant napi has been scheduled and the napi_disable() | ||||||
|  | kicks in before the next napi_threaded_wait() completes - so | ||||||
|  | that the latter quits due to the napi_disable_pending() condition, | ||||||
|  | the existing code leaves the NAPI_STATE_SCHED bit set and the | ||||||
|  | napi_disable() loop waiting for such bit will hang. | ||||||
|  |  | ||||||
|  | This patch addresses the issue by dropping the NAPI_STATE_DISABLE | ||||||
|  | bit test in napi_thread_wait(). The later napi_threaded_poll() | ||||||
|  | iteration will take care of clearing the NAPI_STATE_SCHED. | ||||||
|  |  | ||||||
|  | This also addresses a related problem reported by Jakub: | ||||||
|  | before this patch a napi_disable()/napi_enable() pair killed | ||||||
|  | the napi thread, effectively disabling the threaded mode. | ||||||
|  | On the patched kernel napi_disable() simply stops scheduling | ||||||
|  | the relevant thread. | ||||||
|  |  | ||||||
|  | v1 -> v2: | ||||||
|  |   - let the main napi_thread_poll() loop clear the SCHED bit | ||||||
|  |  | ||||||
|  | Reported-by: Jakub Kicinski <kuba@kernel.org> | ||||||
|  | Fixes: 29863d41bb6e ("net: implement threaded-able napi poll loop support") | ||||||
|  | Signed-off-by: Paolo Abeni <pabeni@redhat.com> | ||||||
|  | Reviewed-by: Eric Dumazet <edumazet@google.com> | ||||||
|  | Link: https://lore.kernel.org/r/883923fa22745a9589e8610962b7dc59df09fb1f.1617981844.git.pabeni@redhat.com | ||||||
|  | Signed-off-by: Jakub Kicinski <kuba@kernel.org> | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | --- a/net/core/dev.c | ||||||
|  | +++ b/net/core/dev.c | ||||||
|  | @@ -6951,7 +6951,7 @@ static int napi_thread_wait(struct napi_ | ||||||
|  |   | ||||||
|  |  	set_current_state(TASK_INTERRUPTIBLE); | ||||||
|  |   | ||||||
|  | -	while (!kthread_should_stop() && !napi_disable_pending(napi)) { | ||||||
|  | +	while (!kthread_should_stop()) { | ||||||
|  |  		/* Testing SCHED_THREADED bit here to make sure the current | ||||||
|  |  		 * kthread owns this napi and could poll on this napi. | ||||||
|  |  		 * Testing SCHED bit is not enough because SCHED bit might be | ||||||
|  | @@ -6969,6 +6969,7 @@ static int napi_thread_wait(struct napi_ | ||||||
|  |  		set_current_state(TASK_INTERRUPTIBLE); | ||||||
|  |  	} | ||||||
|  |  	__set_current_state(TASK_RUNNING); | ||||||
|  | + | ||||||
|  |  	return -1; | ||||||
|  |  } | ||||||
|  |   | ||||||
| @@ -42,7 +42,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> | |||||||
|  	if (netif_elide_gro(skb->dev)) |  	if (netif_elide_gro(skb->dev)) | ||||||
|  		goto normal; |  		goto normal; | ||||||
|   |   | ||||||
| @@ -7986,6 +7989,48 @@ static void __netdev_adjacent_dev_unlink | @@ -7987,6 +7990,48 @@ static void __netdev_adjacent_dev_unlink | ||||||
|  					   &upper_dev->adj_list.lower); |  					   &upper_dev->adj_list.lower); | ||||||
|  } |  } | ||||||
|   |   | ||||||
| @@ -91,7 +91,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> | |||||||
|  static int __netdev_upper_dev_link(struct net_device *dev, |  static int __netdev_upper_dev_link(struct net_device *dev, | ||||||
|  				   struct net_device *upper_dev, bool master, |  				   struct net_device *upper_dev, bool master, | ||||||
|  				   void *upper_priv, void *upper_info, |  				   void *upper_priv, void *upper_info, | ||||||
| @@ -8037,6 +8082,7 @@ static int __netdev_upper_dev_link(struc | @@ -8038,6 +8083,7 @@ static int __netdev_upper_dev_link(struc | ||||||
|  	if (ret) |  	if (ret) | ||||||
|  		return ret; |  		return ret; | ||||||
|   |   | ||||||
| @@ -99,7 +99,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> | |||||||
|  	ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, |  	ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, | ||||||
|  					    &changeupper_info.info); |  					    &changeupper_info.info); | ||||||
|  	ret = notifier_to_errno(ret); |  	ret = notifier_to_errno(ret); | ||||||
| @@ -8133,6 +8179,7 @@ static void __netdev_upper_dev_unlink(st | @@ -8134,6 +8180,7 @@ static void __netdev_upper_dev_unlink(st | ||||||
|   |   | ||||||
|  	__netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); |  	__netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); | ||||||
|   |   | ||||||
| @@ -107,7 +107,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> | |||||||
|  	call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, |  	call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, | ||||||
|  				      &changeupper_info.info); |  				      &changeupper_info.info); | ||||||
|   |   | ||||||
| @@ -8919,6 +8966,7 @@ int dev_set_mac_address(struct net_devic | @@ -8920,6 +8967,7 @@ int dev_set_mac_address(struct net_devic | ||||||
|  	if (err) |  	if (err) | ||||||
|  		return err; |  		return err; | ||||||
|  	dev->addr_assign_type = NET_ADDR_SET; |  	dev->addr_assign_type = NET_ADDR_SET; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Felix Fietkau
					Felix Fietkau