diff mbox series

[net,01/15] can: bcm: use call_rcu() instead of costly synchronize_rcu()

Message ID 20220704122613.1551119-2-mkl@pengutronix.de (mailing list archive)
State Accepted
Commit f1b4e32aca0811aa011c76e5d6cf2fa19224b386
Delegated to: Netdev Maintainers
Headers show
Series [net,01/15] can: bcm: use call_rcu() instead of costly synchronize_rcu() | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net
netdev/fixes_present success Fixes tag present in non-next series
netdev/subject_prefix success Link
netdev/cover_letter success Pull request is its own cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 1 maintainers not CCed: pabeni@redhat.com
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 49 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Marc Kleine-Budde July 4, 2022, 12:25 p.m. UTC
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(-)


base-commit: 280e3a857d96f9ca8e24632788e1e7a0fec4e9f7

Comments

patchwork-bot+netdevbpf@kernel.org July 5, 2022, 3:30 a.m. UTC | #1
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!
diff mbox series

Patch

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 */
 		}