Skip to content

Commit 0a463c7

Browse files
Paolo Abenidavem330
authored andcommitted
udp: avoid a cache miss on dequeue
Since UDP no more uses sk->destructor, we can clear completely the skb head state before enqueuing. Amend and use skb_release_head_state() for that. All head states share a single cacheline, which is not normally used/accesses on dequeue. We can avoid entirely accessing such cacheline implementing and using in the UDP code a specialized skb free helper which ignores the skb head state. This saves a cacheline miss at skb deallocation time. v1 -> v2: replaced secpath_reset() with skb_release_head_state() Signed-off-by: Paolo Abeni <[email protected]> Acked-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3889a80 commit 0a463c7

File tree

3 files changed

+27
-5
lines changed

3 files changed

+27
-5
lines changed

include/linux/skbuff.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,10 +880,12 @@ static inline bool skb_unref(struct sk_buff *skb)
880880
return true;
881881
}
882882

883+
void skb_release_head_state(struct sk_buff *skb);
883884
void kfree_skb(struct sk_buff *skb);
884885
void kfree_skb_list(struct sk_buff *segs);
885886
void skb_tx_error(struct sk_buff *skb);
886887
void consume_skb(struct sk_buff *skb);
888+
void consume_stateless_skb(struct sk_buff *skb);
887889
void __kfree_skb(struct sk_buff *skb);
888890
extern struct kmem_cache *skbuff_head_cache;
889891

net/core/skbuff.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -643,12 +643,10 @@ static void kfree_skbmem(struct sk_buff *skb)
643643
kmem_cache_free(skbuff_fclone_cache, fclones);
644644
}
645645

646-
static void skb_release_head_state(struct sk_buff *skb)
646+
void skb_release_head_state(struct sk_buff *skb)
647647
{
648648
skb_dst_drop(skb);
649-
#ifdef CONFIG_XFRM
650-
secpath_put(skb->sp);
651-
#endif
649+
secpath_reset(skb);
652650
if (skb->destructor) {
653651
WARN_ON(in_irq());
654652
skb->destructor(skb);
@@ -751,6 +749,24 @@ void consume_skb(struct sk_buff *skb)
751749
}
752750
EXPORT_SYMBOL(consume_skb);
753751

752+
/**
753+
* consume_stateless_skb - free an skbuff, assuming it is stateless
754+
* @skb: buffer to free
755+
*
756+
* Works like consume_skb(), but this variant assumes that all the head
757+
* states have been already dropped.
758+
*/
759+
void consume_stateless_skb(struct sk_buff *skb)
760+
{
761+
if (!skb_unref(skb))
762+
return;
763+
764+
trace_consume_skb(skb);
765+
if (likely(skb->head))
766+
skb_release_data(skb);
767+
kfree_skbmem(skb);
768+
}
769+
754770
void __kfree_skb_flush(void)
755771
{
756772
struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache);

net/ipv4/udp.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1359,7 +1359,8 @@ void skb_consume_udp(struct sock *sk, struct sk_buff *skb, int len)
13591359
sk_peek_offset_bwd(sk, len);
13601360
unlock_sock_fast(sk, slow);
13611361
}
1362-
consume_skb(skb);
1362+
1363+
consume_stateless_skb(skb);
13631364
}
13641365
EXPORT_SYMBOL_GPL(skb_consume_udp);
13651366

@@ -1739,6 +1740,9 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
17391740
sk_mark_napi_id_once(sk, skb);
17401741
}
17411742

1743+
/* clear all pending head states while they are hot in the cache */
1744+
skb_release_head_state(skb);
1745+
17421746
rc = __udp_enqueue_schedule_skb(sk, skb);
17431747
if (rc < 0) {
17441748
int is_udplite = IS_UDPLITE(sk);

0 commit comments

Comments
 (0)