From: Oliver Hartkopp socketcan@hartkopp.net
In commit d5f9023fa61e ("can: bcm: delay release of struct bcm_op after synchronize_rcu()") Thadeu Lima de Souza Cascardo introduced two synchronize_rcu() calls in bcm_release() (only once at socket close) and in bcm_delete_rx_op() (called on removal of each single bcm_op).
Unfortunately this slow removal of the bcm_op's affects user space applications like cansniffer where the modification of a filter removes 2048 bcm_op's which blocks the cansniffer application for 40(!) seconds.
In commit 181d4447905d ("can: gw: use call_rcu() instead of costly synchronize_rcu()") Eric Dumazet replaced the synchronize_rcu() calls with several call_rcu()'s to safely remove the data structures after the removal of CAN ID subscriptions with can_rx_unregister() calls.
This patch adopts Erics approach for the can-bcm which should be applicable since the removal of tasklet_kill() in bcm_remove_op() and the introduction of the HRTIMER_MODE_SOFT timer handling in Linux 5.4.
Fixes: d5f9023fa61e ("can: bcm: delay release of struct bcm_op after synchronize_rcu()") # >= 5.4 Link: https://lore.kernel.org/all/20220520183239.19111-1-socketcan@hartkopp.net Cc: stable@vger.kernel.org Cc: Eric Dumazet edumazet@google.com Cc: Norbert Slusarek nslusarek@gmx.net Cc: Thadeu Lima de Souza Cascardo cascardo@canonical.com Signed-off-by: Oliver Hartkopp socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de --- net/can/bcm.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/net/can/bcm.c b/net/can/bcm.c index 65ee1b784a30..e60161bec850 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -100,6 +100,7 @@ static inline u64 get_u64(const struct canfd_frame *cp, int offset)
struct bcm_op { struct list_head list; + struct rcu_head rcu; int ifindex; canid_t can_id; u32 flags; @@ -718,10 +719,9 @@ static struct bcm_op *bcm_find_op(struct list_head *ops, return NULL; }
-static void bcm_remove_op(struct bcm_op *op) +static void bcm_free_op_rcu(struct rcu_head *rcu_head) { - hrtimer_cancel(&op->timer); - hrtimer_cancel(&op->thrtimer); + struct bcm_op *op = container_of(rcu_head, struct bcm_op, rcu);
if ((op->frames) && (op->frames != &op->sframe)) kfree(op->frames); @@ -732,6 +732,14 @@ static void bcm_remove_op(struct bcm_op *op) kfree(op); }
+static void bcm_remove_op(struct bcm_op *op) +{ + hrtimer_cancel(&op->timer); + hrtimer_cancel(&op->thrtimer); + + call_rcu(&op->rcu, bcm_free_op_rcu); +} + static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op) { if (op->rx_reg_dev == dev) { @@ -757,6 +765,9 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh, if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) && (op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) {
+ /* disable automatic timer on frame reception */ + op->flags |= RX_NO_AUTOTIMER; + /* * Don't care if we're bound or not (due to netdev * problems) can_rx_unregister() is always a save @@ -785,7 +796,6 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh, bcm_rx_handler, op);
list_del(&op->list); - synchronize_rcu(); bcm_remove_op(op); return 1; /* done */ }
base-commit: 280e3a857d96f9ca8e24632788e1e7a0fec4e9f7
Hello:
This series was applied to netdev/net.git (master) by Marc Kleine-Budde mkl@pengutronix.de:
On Mon, 4 Jul 2022 14:25:59 +0200 you wrote:
From: Oliver Hartkopp socketcan@hartkopp.net
In commit d5f9023fa61e ("can: bcm: delay release of struct bcm_op after synchronize_rcu()") Thadeu Lima de Souza Cascardo introduced two synchronize_rcu() calls in bcm_release() (only once at socket close) and in bcm_delete_rx_op() (called on removal of each single bcm_op).
[...]
Here is the summary with links: - [net,01/15] can: bcm: use call_rcu() instead of costly synchronize_rcu() https://git.kernel.org/netdev/net/c/f1b4e32aca08 - [net,02/15] Revert "can: xilinx_can: Limit CANFD brp to 2" https://git.kernel.org/netdev/net/c/c6da4590fe81 - [net,03/15] can: rcar_canfd: Fix data transmission failed on R-Car V3U https://git.kernel.org/netdev/net/c/374e11f1bde9 - [net,04/15] can: gs_usb: gs_usb_open/close(): fix memory leak https://git.kernel.org/netdev/net/c/2bda24ef95c0 - [net,05/15] can: grcan: grcan_probe(): remove extra of_node_get() https://git.kernel.org/netdev/net/c/562fed945ea4 - [net,06/15] can: m_can: m_can_chip_config(): actually enable internal timestamping https://git.kernel.org/netdev/net/c/5b12933de4e7 - [net,07/15] can: m_can: m_can_{read_fifo,echo_tx_event}(): shift timestamp to full 32 bits https://git.kernel.org/netdev/net/c/4c3333693f07 - [net,08/15] can: kvaser_usb: replace run-time checks with struct kvaser_usb_driver_info https://git.kernel.org/netdev/net/c/49f274c72357 - [net,09/15] can: kvaser_usb: kvaser_usb_leaf: fix CAN clock frequency regression https://git.kernel.org/netdev/net/c/e6c80e601053 - [net,10/15] can: kvaser_usb: kvaser_usb_leaf: fix bittiming limits https://git.kernel.org/netdev/net/c/b3b6df2c56d8 - [net,11/15] can: mcp251xfd: mcp251xfd_regmap_crc_read(): improve workaround handling for mcp2517fd https://git.kernel.org/netdev/net/c/406cc9cdb3e8 - [net,12/15] can: mcp251xfd: mcp251xfd_regmap_crc_read(): update workaround broken CRC on TBC register https://git.kernel.org/netdev/net/c/e3d4ee7d5f7f - [net,13/15] can: mcp251xfd: mcp251xfd_stop(): add missing hrtimer_cancel() https://git.kernel.org/netdev/net/c/d5a972f561a0 - [net,14/15] can: mcp251xfd: mcp251xfd_register_get_dev_id(): use correct length to read dev_id https://git.kernel.org/netdev/net/c/0ff32bfa0e79 - [net,15/15] can: mcp251xfd: mcp251xfd_register_get_dev_id(): fix endianness conversion https://git.kernel.org/netdev/net/c/1c0e78a287e3
You are awesome, thank you!
linux-stable-mirror@lists.linaro.org