From: Davide Caratti Date: Wed, 4 Jun 2025 16:06:05 +0000 (+0200) Subject: can: add drop reasons in CAN protocols receive path X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=81807451c2a6af59bbc58adfd0da69870c30d4ab;p=thirdparty%2Fkernel%2Flinux.git can: add drop reasons in CAN protocols receive path sock_queue_rcv_skb() can fail because of lack of memory resources: use drop reasons and pass the receiving socket to the tracepoint, so that it's possible to better locate/debug such events. Tested with: | # modprobe vcan echo=1 | # ip link add name vcan2 type vcan | # ip link set dev vcan2 up | # ./netlayer/tst-proc 1 & | # bg | # while true ; do perf record -e skb:kfree_skb -aR -- \ | > ./raw/tst-raw-sendto vcan2 ; perf script ; done | [...] | tst-raw-sendto 10942 [000] 506428.431856: skb:kfree_skb: skbaddr=0xffff97cec38b4200 rx_sk=0xffff97cf0f75a800 protocol=12 location=raw_rcv+0x20e reason: SOCKET_RCVBUF Signed-off-by: Davide Caratti Link: https://patch.msgid.link/20250604160605.1005704-3-dcaratti@redhat.com Signed-off-by: Marc Kleine-Budde --- diff --git a/net/can/bcm.c b/net/can/bcm.c index 6bc1cc4c94c5e..5e690a2377e48 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -359,6 +359,7 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, unsigned int datalen = head->nframes * op->cfsiz; int err; unsigned int *pflags; + enum skb_drop_reason reason; skb = alloc_skb(sizeof(*head) + datalen, gfp_any()); if (!skb) @@ -413,11 +414,11 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, addr->can_family = AF_CAN; addr->can_ifindex = op->rx_ifindex; - err = sock_queue_rcv_skb(sk, skb); + err = sock_queue_rcv_skb_reason(sk, skb, &reason); if (err < 0) { struct bcm_sock *bo = bcm_sk(sk); - kfree_skb(skb); + sk_skb_reason_drop(sk, skb, reason); /* don't care about overflows in this statistic */ bo->dropped_usr_msgs++; } diff --git a/net/can/isotp.c b/net/can/isotp.c index 1efa377f002ed..dee1412b3c9c1 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -278,6 +278,7 @@ static int isotp_send_fc(struct sock *sk, int ae, u8 flowstatus) static void isotp_rcv_skb(struct sk_buff *skb, struct sock *sk) { struct sockaddr_can *addr = (struct sockaddr_can *)skb->cb; + enum skb_drop_reason reason; BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct sockaddr_can)); @@ -285,8 +286,8 @@ static void isotp_rcv_skb(struct sk_buff *skb, struct sock *sk) addr->can_family = AF_CAN; addr->can_ifindex = skb->dev->ifindex; - if (sock_queue_rcv_skb(sk, skb) < 0) - kfree_skb(skb); + if (sock_queue_rcv_skb_reason(sk, skb, &reason) < 0) + sk_skb_reason_drop(sk, skb, reason); } static u8 padlen(u8 datalen) diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c index 6fefe7a687611..3d8b588822f9d 100644 --- a/net/can/j1939/socket.c +++ b/net/can/j1939/socket.c @@ -311,6 +311,7 @@ static void j1939_sk_recv_one(struct j1939_sock *jsk, struct sk_buff *oskb) { const struct j1939_sk_buff_cb *oskcb = j1939_skb_to_cb(oskb); struct j1939_sk_buff_cb *skcb; + enum skb_drop_reason reason; struct sk_buff *skb; if (oskb->sk == &jsk->sk) @@ -331,8 +332,8 @@ static void j1939_sk_recv_one(struct j1939_sock *jsk, struct sk_buff *oskb) if (skb->sk) skcb->msg_flags |= MSG_DONTROUTE; - if (sock_queue_rcv_skb(&jsk->sk, skb) < 0) - kfree_skb(skb); + if (sock_queue_rcv_skb_reason(&jsk->sk, skb, &reason) < 0) + sk_skb_reason_drop(&jsk->sk, skb, reason); } bool j1939_sk_recv_match(struct j1939_priv *priv, struct j1939_sk_buff_cb *skcb) diff --git a/net/can/raw.c b/net/can/raw.c index 020f21430b1d8..76b867d21def2 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -129,6 +129,7 @@ static void raw_rcv(struct sk_buff *oskb, void *data) { struct sock *sk = (struct sock *)data; struct raw_sock *ro = raw_sk(sk); + enum skb_drop_reason reason; struct sockaddr_can *addr; struct sk_buff *skb; unsigned int *pflags; @@ -205,8 +206,8 @@ static void raw_rcv(struct sk_buff *oskb, void *data) if (oskb->sk == sk) *pflags |= MSG_CONFIRM; - if (sock_queue_rcv_skb(sk, skb) < 0) - kfree_skb(skb); + if (sock_queue_rcv_skb_reason(sk, skb, &reason) < 0) + sk_skb_reason_drop(sk, skb, reason); } static int raw_enable_filters(struct net *net, struct net_device *dev,