|
@@ -3313,6 +3313,7 @@ int netdev_rx_handler_register(struct net_device *dev,
|
|
|
if (dev->rx_handler)
|
|
if (dev->rx_handler)
|
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
|
|
|
|
|
|
|
|
+ /* Note: rx_handler_data must be set before rx_handler */
|
|
|
rcu_assign_pointer(dev->rx_handler_data, rx_handler_data);
|
|
rcu_assign_pointer(dev->rx_handler_data, rx_handler_data);
|
|
|
rcu_assign_pointer(dev->rx_handler, rx_handler);
|
|
rcu_assign_pointer(dev->rx_handler, rx_handler);
|
|
|
|
|
|
|
@@ -3333,6 +3334,11 @@ void netdev_rx_handler_unregister(struct net_device *dev)
|
|
|
|
|
|
|
|
ASSERT_RTNL();
|
|
ASSERT_RTNL();
|
|
|
RCU_INIT_POINTER(dev->rx_handler, NULL);
|
|
RCU_INIT_POINTER(dev->rx_handler, NULL);
|
|
|
|
|
+ /* a reader seeing a non NULL rx_handler in a rcu_read_lock()
|
|
|
|
|
+ * section has a guarantee to see a non NULL rx_handler_data
|
|
|
|
|
+ * as well.
|
|
|
|
|
+ */
|
|
|
|
|
+ synchronize_net();
|
|
|
RCU_INIT_POINTER(dev->rx_handler_data, NULL);
|
|
RCU_INIT_POINTER(dev->rx_handler_data, NULL);
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
|
|
EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
|