]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
can: add drop reasons in CAN protocols receive path
authorDavide Caratti <dcaratti@redhat.com>
Wed, 4 Jun 2025 16:06:05 +0000 (18:06 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Tue, 10 Jun 2025 08:23:56 +0000 (10:23 +0200)
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 <dcaratti@redhat.com>
Link: https://patch.msgid.link/20250604160605.1005704-3-dcaratti@redhat.com
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
net/can/bcm.c
net/can/isotp.c
net/can/j1939/socket.c
net/can/raw.c

index 6bc1cc4c94c5ef360807a61591d0a818fec8853b..5e690a2377e48f49e595ea0ecd5813352e242821 100644 (file)
@@ -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++;
        }
index 1efa377f002ed173ae3589147984c51c6b2c2423..dee1412b3c9c1ffcfc43a109b448701459fcf8b9 100644 (file)
@@ -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)
index 6fefe7a687611679e4adbe9874bd500ef918d4c0..3d8b588822f9d215448e9d62dc3ec514b5af420d 100644 (file)
@@ -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)
index 020f21430b1d84517574cb30f9bf25cfa51e2eed..76b867d21def209f5c6d236604c0e434a1c55a4d 100644 (file)
@@ -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,