mirror of
https://github.com/torvalds/linux.git
synced 2026-05-13 00:28:54 +02:00
net: mctp: avoid copy in fragmentation loop for near-MTU messages
Currently, we incorrectly send messages that are within 4 bytes (a
struct mctp_hdr) smaller than the MTU through mctp_do_fragment_route().
This has no effect on the actual fragmentation, as we will still send as
one packet, but unnecessarily copies the original skb into a new
single-fragment skb.
Instead of having the MTU comparisons in both mctp_local_output() and
mctp_do_fragment_route(), feed all local messages through the latter,
and add the single-packet optimisation there.
This means we can coalesce the routing path of mctp_local_output, so our
out_release path is now solely for errors, so rename the label
accordingly.
Include a check in the route tests for the single-packet case too.
Reported-by: yuanzhaoming <yuanzm2@lenovo.com>
Closes: 269936db5e (r175836230)
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260324-dev-mtu-copy-v1-1-7af6bd7027d3@codeconstruct.com.au
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
2b8e147c00
commit
e1877cf623
|
|
@ -1037,6 +1037,13 @@ static int mctp_do_fragment_route(struct mctp_dst *dst, struct sk_buff *skb,
|
|||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/* within MTU? avoid the copy, send original skb */
|
||||
if (skb->len <= mtu) {
|
||||
hdr->flags_seq_tag = MCTP_HDR_FLAG_SOM |
|
||||
MCTP_HDR_FLAG_EOM | tag;
|
||||
return dst->output(dst, skb);
|
||||
}
|
||||
|
||||
/* keep same headroom as the original skb */
|
||||
headroom = skb_headroom(skb);
|
||||
|
||||
|
|
@ -1111,7 +1118,6 @@ int mctp_local_output(struct sock *sk, struct mctp_dst *dst,
|
|||
struct mctp_hdr *hdr;
|
||||
unsigned long flags;
|
||||
unsigned int netid;
|
||||
unsigned int mtu;
|
||||
mctp_eid_t saddr;
|
||||
int rc;
|
||||
u8 tag;
|
||||
|
|
@ -1133,7 +1139,7 @@ int mctp_local_output(struct sock *sk, struct mctp_dst *dst,
|
|||
netid = READ_ONCE(dst->dev->net);
|
||||
|
||||
if (rc)
|
||||
goto out_release;
|
||||
goto err_free;
|
||||
|
||||
if (req_tag & MCTP_TAG_OWNER) {
|
||||
if (req_tag & MCTP_TAG_PREALLOC)
|
||||
|
|
@ -1145,7 +1151,7 @@ int mctp_local_output(struct sock *sk, struct mctp_dst *dst,
|
|||
|
||||
if (IS_ERR(key)) {
|
||||
rc = PTR_ERR(key);
|
||||
goto out_release;
|
||||
goto err_free;
|
||||
}
|
||||
mctp_skb_set_flow(skb, key);
|
||||
/* done with the key in this scope */
|
||||
|
|
@ -1170,20 +1176,10 @@ int mctp_local_output(struct sock *sk, struct mctp_dst *dst,
|
|||
hdr->dest = daddr;
|
||||
hdr->src = saddr;
|
||||
|
||||
mtu = dst->mtu;
|
||||
|
||||
if (skb->len + sizeof(struct mctp_hdr) <= mtu) {
|
||||
hdr->flags_seq_tag = MCTP_HDR_FLAG_SOM |
|
||||
MCTP_HDR_FLAG_EOM | tag;
|
||||
rc = dst->output(dst, skb);
|
||||
} else {
|
||||
rc = mctp_do_fragment_route(dst, skb, mtu, tag);
|
||||
}
|
||||
|
||||
/* route output functions consume the skb, even on error */
|
||||
skb = NULL;
|
||||
return mctp_do_fragment_route(dst, skb, dst->mtu, tag);
|
||||
|
||||
out_release:
|
||||
err_free:
|
||||
kfree_skb(skb);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ static void mctp_test_fragment(struct kunit *test)
|
|||
if (!skb2)
|
||||
break;
|
||||
|
||||
/* avoid copying single-skb messages */
|
||||
if (first && last)
|
||||
KUNIT_EXPECT_PTR_EQ(test, skb, skb2);
|
||||
|
||||
hdr2 = mctp_hdr(skb2);
|
||||
|
||||
tag_mask = MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user