* [PATCH RFC] can: bcm: use call_rcu() instead of costly synchronize_rcu()
@ 2022-05-20 18:32 Oliver Hartkopp
2022-07-04 4:37 ` Oliver Hartkopp
0 siblings, 1 reply; 2+ messages in thread
From: Oliver Hartkopp @ 2022-05-20 18:32 UTC (permalink / raw)
To: linux-can
Cc: Oliver Hartkopp, Eric Dumazet, Norbert Slusarek,
Thadeu Lima de Souza Cascardo
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
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>
---
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
@@ -98,10 +98,11 @@ static inline u64 get_u64(const struct canfd_frame *cp, int offset)
return *(u64 *)(cp->data + offset);
}
struct bcm_op {
struct list_head list;
+ struct rcu_head rcu;
int ifindex;
canid_t can_id;
u32 flags;
unsigned long frames_abs, frames_filtered;
struct bcm_timeval ival1, ival2;
@@ -716,24 +717,31 @@ 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);
if ((op->last_frames) && (op->last_frames != &op->last_sframe))
kfree(op->last_frames);
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) {
can_rx_unregister(dev_net(dev), dev, op->can_id,
REGMASK(op->can_id), bcm_rx_handler, op);
@@ -755,10 +763,13 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
list_for_each_entry_safe(op, n, ops, list) {
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
* thing to do here.
*/
@@ -783,11 +794,10 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op);
list_del(&op->list);
- synchronize_rcu();
bcm_remove_op(op);
return 1; /* done */
}
}
--
2.30.2
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH RFC] can: bcm: use call_rcu() instead of costly synchronize_rcu()
2022-05-20 18:32 [PATCH RFC] can: bcm: use call_rcu() instead of costly synchronize_rcu() Oliver Hartkopp
@ 2022-07-04 4:37 ` Oliver Hartkopp
0 siblings, 0 replies; 2+ messages in thread
From: Oliver Hartkopp @ 2022-07-04 4:37 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: Eric Dumazet, Norbert Slusarek, Thadeu Lima de Souza Cascardo, linux-can
Hello Marc,
unfortunately I did not get any feedback/review on this patch from the
original authors.
But I think this fix should go into Linux 5.4+
Best regards,
Oliver
On 20.05.22 20:32, Oliver Hartkopp wrote:
> 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
> 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>
> ---
> 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
> @@ -98,10 +98,11 @@ static inline u64 get_u64(const struct canfd_frame *cp, int offset)
> return *(u64 *)(cp->data + offset);
> }
>
> struct bcm_op {
> struct list_head list;
> + struct rcu_head rcu;
> int ifindex;
> canid_t can_id;
> u32 flags;
> unsigned long frames_abs, frames_filtered;
> struct bcm_timeval ival1, ival2;
> @@ -716,24 +717,31 @@ 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);
>
> if ((op->last_frames) && (op->last_frames != &op->last_sframe))
> kfree(op->last_frames);
>
> 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) {
> can_rx_unregister(dev_net(dev), dev, op->can_id,
> REGMASK(op->can_id), bcm_rx_handler, op);
> @@ -755,10 +763,13 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
>
> list_for_each_entry_safe(op, n, ops, list) {
> 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
> * thing to do here.
> */
> @@ -783,11 +794,10 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
> op->can_id,
> REGMASK(op->can_id),
> bcm_rx_handler, op);
>
> list_del(&op->list);
> - synchronize_rcu();
> bcm_remove_op(op);
> return 1; /* done */
> }
> }
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2022-07-04 4:37 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-20 18:32 [PATCH RFC] can: bcm: use call_rcu() instead of costly synchronize_rcu() Oliver Hartkopp
2022-07-04 4:37 ` Oliver Hartkopp
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).