sock: enable MSG_ZEROCOPY
Prepare the datapath for refcounted ubuf_info. Clone ubuf_info with skb_zerocopy_clone() wherever needed due to skb split, merge, resize or clone. Split skb_orphan_frags into two variants. The split, merge, .. paths support reference counted zerocopy buffers, so do not do a deep copy. Add skb_orphan_frags_rx for paths that may loop packets to receive sockets. That is not allowed, as it may cause unbounded latency. Deep copy all zerocopy copy buffers, ref-counted or not, in this path. The exact locations to modify were chosen by exhaustively searching through all code that might modify skb_frag references and/or the the SKBTX_DEV_ZEROCOPY tx_flags bit. The changes err on the safe side, in two ways. (1) legacy ubuf_info paths virtio and tap are not modified. They keep a 1:1 ubuf_info to sk_buff relationship. Calls to skb_orphan_frags still call skb_copy_ubufs and thus copy frags in this case. (2) not all copies deep in the stack are addressed yet. skb_shift, skb_split and skb_try_coalesce can be refined to avoid copying. These are not in the hot path and this patch is hairy enough as is, so that is left for future refinement. Signed-off-by: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
76851d1212
commit
1f8b977ab3
@@ -2512,7 +2512,17 @@ static inline void skb_orphan(struct sk_buff *skb)
|
||||
*/
|
||||
static inline int skb_orphan_frags(struct sk_buff *skb, gfp_t gfp_mask)
|
||||
{
|
||||
if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY)))
|
||||
if (likely(!skb_zcopy(skb)))
|
||||
return 0;
|
||||
if (skb_uarg(skb)->callback == sock_zerocopy_callback)
|
||||
return 0;
|
||||
return skb_copy_ubufs(skb, gfp_mask);
|
||||
}
|
||||
|
||||
/* Frags must be orphaned, even if refcounted, if skb might loop to rx path */
|
||||
static inline int skb_orphan_frags_rx(struct sk_buff *skb, gfp_t gfp_mask)
|
||||
{
|
||||
if (likely(!skb_zcopy(skb)))
|
||||
return 0;
|
||||
return skb_copy_ubufs(skb, gfp_mask);
|
||||
}
|
||||
@@ -2944,6 +2954,8 @@ static inline int skb_add_data(struct sk_buff *skb,
|
||||
static inline bool skb_can_coalesce(struct sk_buff *skb, int i,
|
||||
const struct page *page, int off)
|
||||
{
|
||||
if (skb_zcopy(skb))
|
||||
return false;
|
||||
if (i) {
|
||||
const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i - 1];
|
||||
|
||||
|
Reference in New Issue
Block a user