Commit 65bada80 authored by Pavel Begunkov's avatar Pavel Begunkov Committed by Jakub Kicinski

net: add callback for setting a ubuf_info to skb

At the moment an skb can only have one ubuf_info associated with it,
which might be a performance problem for zerocopy sends in cases like
TCP via io_uring. Add a callback for assigning ubuf_info to skb, this
way we will implement smarter assignment later like linking ubuf_info
together.

Note, it's an optional callback, which should be compatible with
skb_zcopy_set(), that's because the net stack might potentially decide
to clone an skb and take another reference to ubuf_info whenever it
wishes. Also, a correct implementation should always be able to bind to
an skb without prior ubuf_info, otherwise we could end up in a situation
when the send would not be able to progress.
Reviewed-by: default avatarJens Axboe <axboe@kernel.dk>
Reviewed-by: default avatarDavid Ahern <dsahern@kernel.org>
Signed-off-by: default avatarPavel Begunkov <asml.silence@gmail.com>
Reviewed-by: default avatarWillem de Bruijn <willemb@google.com>
Link: https://lore.kernel.org/all/b7918aadffeb787c84c9e72e34c729dc04f3a45d.1713369317.git.asml.silence@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 7ab4f16f
...@@ -530,6 +530,8 @@ enum { ...@@ -530,6 +530,8 @@ enum {
struct ubuf_info_ops { struct ubuf_info_ops {
void (*complete)(struct sk_buff *, struct ubuf_info *, void (*complete)(struct sk_buff *, struct ubuf_info *,
bool zerocopy_success); bool zerocopy_success);
/* has to be compatible with skb_zcopy_set() */
int (*link_skb)(struct sk_buff *skb, struct ubuf_info *uarg);
}; };
/* /*
......
...@@ -1880,11 +1880,18 @@ int skb_zerocopy_iter_stream(struct sock *sk, struct sk_buff *skb, ...@@ -1880,11 +1880,18 @@ int skb_zerocopy_iter_stream(struct sock *sk, struct sk_buff *skb,
struct ubuf_info *orig_uarg = skb_zcopy(skb); struct ubuf_info *orig_uarg = skb_zcopy(skb);
int err, orig_len = skb->len; int err, orig_len = skb->len;
/* An skb can only point to one uarg. This edge case happens when if (uarg->ops->link_skb) {
* TCP appends to an skb, but zerocopy_realloc triggered a new alloc. err = uarg->ops->link_skb(skb, uarg);
if (err)
return err;
} else {
/* An skb can only point to one uarg. This edge case happens
* when TCP appends to an skb, but zerocopy_realloc triggered
* a new alloc.
*/ */
if (orig_uarg && uarg != orig_uarg) if (orig_uarg && uarg != orig_uarg)
return -EEXIST; return -EEXIST;
}
err = __zerocopy_sg_from_iter(msg, sk, skb, &msg->msg_iter, len); err = __zerocopy_sg_from_iter(msg, sk, skb, &msg->msg_iter, len);
if (err == -EFAULT || (err == -EMSGSIZE && skb->len == orig_len)) { if (err == -EFAULT || (err == -EMSGSIZE && skb->len == orig_len)) {
...@@ -1898,6 +1905,7 @@ int skb_zerocopy_iter_stream(struct sock *sk, struct sk_buff *skb, ...@@ -1898,6 +1905,7 @@ int skb_zerocopy_iter_stream(struct sock *sk, struct sk_buff *skb,
return err; return err;
} }
if (!uarg->ops->link_skb)
skb_zcopy_set(skb, uarg, NULL); skb_zcopy_set(skb, uarg, NULL);
return skb->len - orig_len; return skb->len - orig_len;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment