Skip to content

Commit e624702

Browse files
edumazetdavem330
authored andcommitted
net: introduce dev_consume_skb_any()
Some network drivers use dev_kfree_skb_any() and dev_kfree_skb_irq() helpers to free skbs, both for dropped packets and TX completed ones. We need to separate the two causes to get better diagnostics given by dropwatch or "perf record -e skb:kfree_skb" This patch provides two new helpers, dev_consume_skb_any() and dev_consume_skb_irq() to be used for consumed skbs. __dev_kfree_skb_irq() is slightly optimized to remove one atomic_dec_and_test() in fast path, and use this_cpu_{r|w} accessors. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent f96eb74 commit e624702

File tree

2 files changed

+74
-24
lines changed

2 files changed

+74
-24
lines changed

include/linux/netdevice.h

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2368,17 +2368,52 @@ static inline int netif_copy_real_num_queues(struct net_device *to_dev,
23682368
#define DEFAULT_MAX_NUM_RSS_QUEUES (8)
23692369
int netif_get_num_default_rss_queues(void);
23702370

2371-
/* Use this variant when it is known for sure that it
2372-
* is executing from hardware interrupt context or with hardware interrupts
2373-
* disabled.
2374-
*/
2375-
void dev_kfree_skb_irq(struct sk_buff *skb);
2371+
enum skb_free_reason {
2372+
SKB_REASON_CONSUMED,
2373+
SKB_REASON_DROPPED,
2374+
};
2375+
2376+
void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason);
2377+
void __dev_kfree_skb_any(struct sk_buff *skb, enum skb_free_reason reason);
23762378

2377-
/* Use this variant in places where it could be invoked
2378-
* from either hardware interrupt or other context, with hardware interrupts
2379-
* either disabled or enabled.
2379+
/*
2380+
* It is not allowed to call kfree_skb() or consume_skb() from hardware
2381+
* interrupt context or with hardware interrupts being disabled.
2382+
* (in_irq() || irqs_disabled())
2383+
*
2384+
* We provide four helpers that can be used in following contexts :
2385+
*
2386+
* dev_kfree_skb_irq(skb) when caller drops a packet from irq context,
2387+
* replacing kfree_skb(skb)
2388+
*
2389+
* dev_consume_skb_irq(skb) when caller consumes a packet from irq context.
2390+
* Typically used in place of consume_skb(skb) in TX completion path
2391+
*
2392+
* dev_kfree_skb_any(skb) when caller doesn't know its current irq context,
2393+
* replacing kfree_skb(skb)
2394+
*
2395+
* dev_consume_skb_any(skb) when caller doesn't know its current irq context,
2396+
* and consumed a packet. Used in place of consume_skb(skb)
23802397
*/
2381-
void dev_kfree_skb_any(struct sk_buff *skb);
2398+
static inline void dev_kfree_skb_irq(struct sk_buff *skb)
2399+
{
2400+
__dev_kfree_skb_irq(skb, SKB_REASON_DROPPED);
2401+
}
2402+
2403+
static inline void dev_consume_skb_irq(struct sk_buff *skb)
2404+
{
2405+
__dev_kfree_skb_irq(skb, SKB_REASON_CONSUMED);
2406+
}
2407+
2408+
static inline void dev_kfree_skb_any(struct sk_buff *skb)
2409+
{
2410+
__dev_kfree_skb_any(skb, SKB_REASON_DROPPED);
2411+
}
2412+
2413+
static inline void dev_consume_skb_any(struct sk_buff *skb)
2414+
{
2415+
__dev_kfree_skb_any(skb, SKB_REASON_CONSUMED);
2416+
}
23822417

23832418
int netif_rx(struct sk_buff *skb);
23842419
int netif_rx_ni(struct sk_buff *skb);

net/core/dev.c

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,30 +2145,42 @@ void __netif_schedule(struct Qdisc *q)
21452145
}
21462146
EXPORT_SYMBOL(__netif_schedule);
21472147

2148-
void dev_kfree_skb_irq(struct sk_buff *skb)
2148+
struct dev_kfree_skb_cb {
2149+
enum skb_free_reason reason;
2150+
};
2151+
2152+
static struct dev_kfree_skb_cb *get_kfree_skb_cb(const struct sk_buff *skb)
2153+
{
2154+
return (struct dev_kfree_skb_cb *)skb->cb;
2155+
}
2156+
2157+
void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason)
21492158
{
2150-
if (atomic_dec_and_test(&skb->users)) {
2151-
struct softnet_data *sd;
2152-
unsigned long flags;
2159+
unsigned long flags;
21532160

2154-
local_irq_save(flags);
2155-
sd = &__get_cpu_var(softnet_data);
2156-
skb->next = sd->completion_queue;
2157-
sd->completion_queue = skb;
2158-
raise_softirq_irqoff(NET_TX_SOFTIRQ);
2159-
local_irq_restore(flags);
2161+
if (likely(atomic_read(&skb->users) == 1)) {
2162+
smp_rmb();
2163+
atomic_set(&skb->users, 0);
2164+
} else if (likely(!atomic_dec_and_test(&skb->users))) {
2165+
return;
21602166
}
2167+
get_kfree_skb_cb(skb)->reason = reason;
2168+
local_irq_save(flags);
2169+
skb->next = __this_cpu_read(softnet_data.completion_queue);
2170+
__this_cpu_write(softnet_data.completion_queue, skb);
2171+
raise_softirq_irqoff(NET_TX_SOFTIRQ);
2172+
local_irq_restore(flags);
21612173
}
2162-
EXPORT_SYMBOL(dev_kfree_skb_irq);
2174+
EXPORT_SYMBOL(__dev_kfree_skb_irq);
21632175

2164-
void dev_kfree_skb_any(struct sk_buff *skb)
2176+
void __dev_kfree_skb_any(struct sk_buff *skb, enum skb_free_reason reason)
21652177
{
21662178
if (in_irq() || irqs_disabled())
2167-
dev_kfree_skb_irq(skb);
2179+
__dev_kfree_skb_irq(skb, reason);
21682180
else
21692181
dev_kfree_skb(skb);
21702182
}
2171-
EXPORT_SYMBOL(dev_kfree_skb_any);
2183+
EXPORT_SYMBOL(__dev_kfree_skb_any);
21722184

21732185

21742186
/**
@@ -3306,7 +3318,10 @@ static void net_tx_action(struct softirq_action *h)
33063318
clist = clist->next;
33073319

33083320
WARN_ON(atomic_read(&skb->users));
3309-
trace_kfree_skb(skb, net_tx_action);
3321+
if (likely(get_kfree_skb_cb(skb)->reason == SKB_REASON_CONSUMED))
3322+
trace_consume_skb(skb);
3323+
else
3324+
trace_kfree_skb(skb, net_tx_action);
33103325
__kfree_skb(skb);
33113326
}
33123327
}

0 commit comments

Comments
 (0)