Merge branch 'Avoid-local_irq_save-and-use-napi_alloc_frag-where-possible'
Sebastian Andrzej says: ==================== Avoid local_irq_save() and use napi_alloc_frag() where possible The first two patches remove local_irq_save() around `netdev_alloc_cache' which does not work on -RT. Besides helping -RT it whould benefit the users of the function since they can avoid disabling interrupts and save a few cycles. The remaining patches are from a time when I tried to remove `netdev_alloc_cache' but then noticed that we still have non-NAPI drivers using netdev_alloc_skb() and I dropped that idea. Using napi_alloc_frag() over netdev_alloc_frag() would skip the not required local_bh_disable() around the allocation. v1…v2: - 1/7 + 2/7 use now "(in_irq() || irqs_disabled())" instead just "irqs_disabled()" to align with __dev_kfree_skb_any(). Pointed out by Eric Dumazet. - 6/7 has a typo less. Pointed out by Sergei Shtylyov. - 3/7 + 4/7 added acks from Ioana Radulescu. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
e8a492cd53
|
@ -684,7 +684,7 @@ static void *bnx2x_frag_alloc(const struct bnx2x_fastpath *fp, gfp_t gfp_mask)
|
|||
if (unlikely(gfpflags_allow_blocking(gfp_mask)))
|
||||
return (void *)__get_free_page(gfp_mask);
|
||||
|
||||
return netdev_alloc_frag(fp->rx_frag_size);
|
||||
return napi_alloc_frag(fp->rx_frag_size);
|
||||
}
|
||||
|
||||
return kmalloc(fp->rx_buf_size + NET_SKB_PAD, gfp_mask);
|
||||
|
|
|
@ -6710,7 +6710,7 @@ static int tg3_alloc_rx_data(struct tg3 *tp, struct tg3_rx_prodring_set *tpr,
|
|||
skb_size = SKB_DATA_ALIGN(data_size + TG3_RX_OFFSET(tp)) +
|
||||
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
if (skb_size <= PAGE_SIZE) {
|
||||
data = netdev_alloc_frag(skb_size);
|
||||
data = napi_alloc_frag(skb_size);
|
||||
*frag_size = skb_size;
|
||||
} else {
|
||||
data = kmalloc(skb_size, GFP_ATOMIC);
|
||||
|
|
|
@ -555,7 +555,7 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv,
|
|||
/* Prepare the HW SGT structure */
|
||||
sgt_buf_size = priv->tx_data_offset +
|
||||
sizeof(struct dpaa2_sg_entry) * num_dma_bufs;
|
||||
sgt_buf = netdev_alloc_frag(sgt_buf_size + DPAA2_ETH_TX_BUF_ALIGN);
|
||||
sgt_buf = napi_alloc_frag(sgt_buf_size + DPAA2_ETH_TX_BUF_ALIGN);
|
||||
if (unlikely(!sgt_buf)) {
|
||||
err = -ENOMEM;
|
||||
goto sgt_buf_alloc_failed;
|
||||
|
@ -997,13 +997,6 @@ static int seed_pool(struct dpaa2_eth_priv *priv, u16 bpid)
|
|||
int i, j;
|
||||
int new_count;
|
||||
|
||||
/* This is the lazy seeding of Rx buffer pools.
|
||||
* dpaa2_add_bufs() is also used on the Rx hotpath and calls
|
||||
* napi_alloc_frag(). The trouble with that is that it in turn ends up
|
||||
* calling this_cpu_ptr(), which mandates execution in atomic context.
|
||||
* Rather than splitting up the code, do a one-off preempt disable.
|
||||
*/
|
||||
preempt_disable();
|
||||
for (j = 0; j < priv->num_channels; j++) {
|
||||
for (i = 0; i < DPAA2_ETH_NUM_BUFS;
|
||||
i += DPAA2_ETH_BUFS_PER_CMD) {
|
||||
|
@ -1011,12 +1004,10 @@ static int seed_pool(struct dpaa2_eth_priv *priv, u16 bpid)
|
|||
priv->channel[j]->buf_count += new_count;
|
||||
|
||||
if (new_count < DPAA2_ETH_BUFS_PER_CMD) {
|
||||
preempt_enable();
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
preempt_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1119,7 +1119,7 @@ static void mvneta_bm_update_mtu(struct mvneta_port *pp, int mtu)
|
|||
SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(bm_pool->pkt_size));
|
||||
|
||||
/* Fill entire long pool */
|
||||
num = hwbm_pool_add(hwbm_pool, hwbm_pool->size, GFP_ATOMIC);
|
||||
num = hwbm_pool_add(hwbm_pool, hwbm_pool->size);
|
||||
if (num != hwbm_pool->size) {
|
||||
WARN(1, "pool %d: %d of %d allocated\n",
|
||||
bm_pool->id, num, hwbm_pool->size);
|
||||
|
|
|
@ -190,7 +190,7 @@ struct mvneta_bm_pool *mvneta_bm_pool_use(struct mvneta_bm *priv, u8 pool_id,
|
|||
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
||||
hwbm_pool->construct = mvneta_bm_construct;
|
||||
hwbm_pool->priv = new_pool;
|
||||
spin_lock_init(&hwbm_pool->lock);
|
||||
mutex_init(&hwbm_pool->buf_lock);
|
||||
|
||||
/* Create new pool */
|
||||
err = mvneta_bm_pool_create(priv, new_pool);
|
||||
|
@ -201,7 +201,7 @@ struct mvneta_bm_pool *mvneta_bm_pool_use(struct mvneta_bm *priv, u8 pool_id,
|
|||
}
|
||||
|
||||
/* Allocate buffers for this pool */
|
||||
num = hwbm_pool_add(hwbm_pool, hwbm_pool->size, GFP_ATOMIC);
|
||||
num = hwbm_pool_add(hwbm_pool, hwbm_pool->size);
|
||||
if (num != hwbm_pool->size) {
|
||||
WARN(1, "pool %d: %d of %d allocated\n",
|
||||
new_pool->id, num, hwbm_pool->size);
|
||||
|
|
|
@ -12,18 +12,18 @@ struct hwbm_pool {
|
|||
/* constructor called during alocation */
|
||||
int (*construct)(struct hwbm_pool *bm_pool, void *buf);
|
||||
/* protect acces to the buffer counter*/
|
||||
spinlock_t lock;
|
||||
struct mutex buf_lock;
|
||||
/* private data */
|
||||
void *priv;
|
||||
};
|
||||
#ifdef CONFIG_HWBM
|
||||
void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf);
|
||||
int hwbm_pool_refill(struct hwbm_pool *bm_pool, gfp_t gfp);
|
||||
int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num, gfp_t gfp);
|
||||
int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num);
|
||||
#else
|
||||
void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf) {}
|
||||
int hwbm_pool_refill(struct hwbm_pool *bm_pool, gfp_t gfp) { return 0; }
|
||||
int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num, gfp_t gfp)
|
||||
int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num)
|
||||
{ return 0; }
|
||||
#endif /* CONFIG_HWBM */
|
||||
#endif /* _HWBM_H */
|
||||
|
|
|
@ -43,34 +43,33 @@ int hwbm_pool_refill(struct hwbm_pool *bm_pool, gfp_t gfp)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(hwbm_pool_refill);
|
||||
|
||||
int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num, gfp_t gfp)
|
||||
int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num)
|
||||
{
|
||||
int err, i;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&bm_pool->lock, flags);
|
||||
mutex_lock(&bm_pool->buf_lock);
|
||||
if (bm_pool->buf_num == bm_pool->size) {
|
||||
pr_warn("pool already filled\n");
|
||||
spin_unlock_irqrestore(&bm_pool->lock, flags);
|
||||
mutex_unlock(&bm_pool->buf_lock);
|
||||
return bm_pool->buf_num;
|
||||
}
|
||||
|
||||
if (buf_num + bm_pool->buf_num > bm_pool->size) {
|
||||
pr_warn("cannot allocate %d buffers for pool\n",
|
||||
buf_num);
|
||||
spin_unlock_irqrestore(&bm_pool->lock, flags);
|
||||
mutex_unlock(&bm_pool->buf_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((buf_num + bm_pool->buf_num) < bm_pool->buf_num) {
|
||||
pr_warn("Adding %d buffers to the %d current buffers will overflow\n",
|
||||
buf_num, bm_pool->buf_num);
|
||||
spin_unlock_irqrestore(&bm_pool->lock, flags);
|
||||
mutex_unlock(&bm_pool->buf_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < buf_num; i++) {
|
||||
err = hwbm_pool_refill(bm_pool, gfp);
|
||||
err = hwbm_pool_refill(bm_pool, GFP_KERNEL);
|
||||
if (err < 0)
|
||||
break;
|
||||
}
|
||||
|
@ -79,7 +78,7 @@ int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num, gfp_t gfp)
|
|||
bm_pool->buf_num += i;
|
||||
|
||||
pr_debug("hwpm pool: %d of %d buffers added\n", i, buf_num);
|
||||
spin_unlock_irqrestore(&bm_pool->lock, flags);
|
||||
mutex_unlock(&bm_pool->buf_lock);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
|
|
@ -366,34 +366,6 @@ struct napi_alloc_cache {
|
|||
static DEFINE_PER_CPU(struct page_frag_cache, netdev_alloc_cache);
|
||||
static DEFINE_PER_CPU(struct napi_alloc_cache, napi_alloc_cache);
|
||||
|
||||
static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask)
|
||||
{
|
||||
struct page_frag_cache *nc;
|
||||
unsigned long flags;
|
||||
void *data;
|
||||
|
||||
local_irq_save(flags);
|
||||
nc = this_cpu_ptr(&netdev_alloc_cache);
|
||||
data = page_frag_alloc(nc, fragsz, gfp_mask);
|
||||
local_irq_restore(flags);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* netdev_alloc_frag - allocate a page fragment
|
||||
* @fragsz: fragment size
|
||||
*
|
||||
* Allocates a frag from a page for receive buffer.
|
||||
* Uses GFP_ATOMIC allocations.
|
||||
*/
|
||||
void *netdev_alloc_frag(unsigned int fragsz)
|
||||
{
|
||||
fragsz = SKB_DATA_ALIGN(fragsz);
|
||||
|
||||
return __netdev_alloc_frag(fragsz, GFP_ATOMIC);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_alloc_frag);
|
||||
|
||||
static void *__napi_alloc_frag(unsigned int fragsz, gfp_t gfp_mask)
|
||||
{
|
||||
struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache);
|
||||
|
@ -409,6 +381,31 @@ void *napi_alloc_frag(unsigned int fragsz)
|
|||
}
|
||||
EXPORT_SYMBOL(napi_alloc_frag);
|
||||
|
||||
/**
|
||||
* netdev_alloc_frag - allocate a page fragment
|
||||
* @fragsz: fragment size
|
||||
*
|
||||
* Allocates a frag from a page for receive buffer.
|
||||
* Uses GFP_ATOMIC allocations.
|
||||
*/
|
||||
void *netdev_alloc_frag(unsigned int fragsz)
|
||||
{
|
||||
struct page_frag_cache *nc;
|
||||
void *data;
|
||||
|
||||
fragsz = SKB_DATA_ALIGN(fragsz);
|
||||
if (in_irq() || irqs_disabled()) {
|
||||
nc = this_cpu_ptr(&netdev_alloc_cache);
|
||||
data = page_frag_alloc(nc, fragsz, GFP_ATOMIC);
|
||||
} else {
|
||||
local_bh_disable();
|
||||
data = __napi_alloc_frag(fragsz, GFP_ATOMIC);
|
||||
local_bh_enable();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_alloc_frag);
|
||||
|
||||
/**
|
||||
* __netdev_alloc_skb - allocate an skbuff for rx on a specific device
|
||||
* @dev: network device to receive on
|
||||
|
@ -426,7 +423,6 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,
|
|||
gfp_t gfp_mask)
|
||||
{
|
||||
struct page_frag_cache *nc;
|
||||
unsigned long flags;
|
||||
struct sk_buff *skb;
|
||||
bool pfmemalloc;
|
||||
void *data;
|
||||
|
@ -447,13 +443,17 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,
|
|||
if (sk_memalloc_socks())
|
||||
gfp_mask |= __GFP_MEMALLOC;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
nc = this_cpu_ptr(&netdev_alloc_cache);
|
||||
data = page_frag_alloc(nc, len, gfp_mask);
|
||||
pfmemalloc = nc->pfmemalloc;
|
||||
|
||||
local_irq_restore(flags);
|
||||
if (in_irq() || irqs_disabled()) {
|
||||
nc = this_cpu_ptr(&netdev_alloc_cache);
|
||||
data = page_frag_alloc(nc, len, gfp_mask);
|
||||
pfmemalloc = nc->pfmemalloc;
|
||||
} else {
|
||||
local_bh_disable();
|
||||
nc = this_cpu_ptr(&napi_alloc_cache.page);
|
||||
data = page_frag_alloc(nc, len, gfp_mask);
|
||||
pfmemalloc = nc->pfmemalloc;
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
if (unlikely(!data))
|
||||
return NULL;
|
||||
|
|
Загрузка…
Ссылка в новой задаче