rndis.c: move ifup in setconfig to the work queue#18428
rndis.c: move ifup in setconfig to the work queue#18428zhhyu7 wants to merge 1 commit intoapache:masterfrom
Conversation
| priv->netdev.d_flags |= IFF_UP; | ||
| } | ||
|
|
||
| /* Schedule to work queue because netdev_carrier_on API can't be used in |
There was a problem hiding this comment.
but where rndis call netdev_carrier_on?
There was a problem hiding this comment.
but where rndis call netdev_carrier_on?
@xiaoxiang781216 The call chain is as follows:
usbclass_setconfig -> rndis_ifup_work -> priv->netdev.d_ifup -> rndis_ifup -> netdev_carrier_on
There was a problem hiding this comment.
it's better to run priv->netdev.d_flags |= IFF_UP here, but move notify to work queue
There was a problem hiding this comment.
it's better to run
priv->netdev.d_flags |= IFF_UPhere, but move notify to work queue
@xiaoxiang781216 Done.
| * Name: rndis_ifup_work | ||
| * | ||
| * Description: | ||
| * Schedule to work queue because netdev_carrier_on API can't be used in |
There was a problem hiding this comment.
how about move the interrupt context check and queue wwork inisde netdev_carrier_on/netdev_carrier_off
There was a problem hiding this comment.
how about move the interrupt context check and queue wwork inisde netdev_carrier_on/netdev_carrier_off
@xiaoxiang781216 Add an additional struct work specifically for netdev_carrier_on/netdev_carrier_off in the net_driver_s structure?
| * reused. | ||
| */ | ||
|
|
||
| work_queue(LPWORK, &priv->pollwork, rndis_carrier_on_work, priv, 0); |
There was a problem hiding this comment.
let's call work_queue inside rndis_ifup/rndis_ifdown instead
drivers/usbdev/rndis.c
Outdated
|
|
||
| static void rndis_carrier_on_work(FAR void *arg) | ||
| { | ||
| FAR struct rndis_dev_s *priv = (FAR struct rndis_dev_s *)arg; |
There was a problem hiding this comment.
| FAR struct rndis_dev_s *priv = (FAR struct rndis_dev_s *)arg; | |
| FAR struct rndis_dev_s *priv = arg; |
I don't understand this PR. Is it because netlink can't be used in interrupt context?
There was a problem hiding this comment.
@anchao Done. Yes, netlink_lock() will be called in netlink_device_notify, If trigger the wait of sem_wait will causes a crash.
There was a problem hiding this comment.
how about change netlink_device_notify() ISR safe?
diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h
index 23a3f2f5e5..25394f48a0 100644
--- a/include/nuttx/net/netdev.h
+++ b/include/nuttx/net/netdev.h
@@ -535,6 +535,10 @@ struct net_driver_s
struct timespec d_rxtime;
#endif
+#ifndef CONFIG_NETLINK_DISABLE_GETLINK
+ struct work_s d_nlwork;
+#endif
+
/* Application callbacks:
*
* Network device event handlers are retained in a 'list' and are called
diff --git a/net/netlink/netlink_route.c b/net/netlink/netlink_route.c
index b8f3293a84..d264496937 100644
--- a/net/netlink/netlink_route.c
+++ b/net/netlink/netlink_route.c
@@ -1510,11 +1510,10 @@ ssize_t netlink_route_sendto(NETLINK_HANDLE handle,
****************************************************************************/
#ifndef CONFIG_NETLINK_DISABLE_GETLINK
-void netlink_device_notify(FAR struct net_driver_s *dev)
+static void netlink_device_notify_internal(FAR void *arg)
{
FAR struct netlink_response_s *resp;
-
- DEBUGASSERT(dev != NULL);
+ FAR struct net_driver_s *dev = arg;
resp = netlink_get_device(dev, NULL);
if (resp != NULL)
@@ -1523,6 +1522,21 @@ void netlink_device_notify(FAR struct net_driver_s *dev)
netlink_add_terminator(NULL, NULL, RTNLGRP_LINK);
}
}
+
+void netlink_device_notify(FAR struct net_driver_s *dev)
+{
+ DEBUGASSERT(dev != NULL);
+
+ if (up_interrupt_context())
+ {
+ work_queue(LPWORK, &dev->d_nlwork,
+ netlink_device_notify_internal, dev, 0);
+ }
+ else
+ {
+ netlink_device_notify_internal(dev);
+ }
+}
#endif
/****************************************************************************
There was a problem hiding this comment.
how about change netlink_device_notify() ISR safe?
@anchao Okay, if we make this change, I won't need to submit this PR. Will you directly submit this modification?
There was a problem hiding this comment.
@anchao Isn't this solution more chaotic? netdev_carrier API was never intended to run in interrupt context, and all other netdevs follow this convention (or at least they should).
This PR is a bugfix for a previous PR that misused the API. The correct fix is to use the API correctly, not to change the API behavior.
There was a problem hiding this comment.
@raiden00pl
My intention is to fix this issue at the most critical point. Because in RNDIS, we have modified netdev_carrier_on() to be invoked from a workqueue. If other network drivers also need to call netdev_carrier_on() in interrupt context, developers would have to make similar changes.
There was a problem hiding this comment.
Move network interface up operation (ifup) to work queue in RNDIS USB device driver to avoid calling netdev_carrier_on API in interrupt context. Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
Summary
Move network interface up operation (ifup) to work queue in RNDIS USB device driver to avoid calling netdev_carrier_on API in interrupt context.
This PR addresses a threading context issue in the RNDIS USB device driver where network interface initialization was being performed in interrupt context.
Impact
Modified usbclass_setconfig() to schedule ifup operation via work_queue() instead of calling it directly;
Reused existing pollwork work structure since the network card is not yet in RUNNING state at this point.
Testing
sim:usbdev
NuttX test log: