Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] ibmveth fix buffer replenishing

This patch removes the allocation of RX skb's buffers from a workqueue
to be called directly at RX processing time. This change was suggested
by Dave Miller when the driver was starving the RX buffers and
deadlocking under heavy traffic:

> Allocating RX SKBs via tasklet is, IMHO, the worst way to
> do it. It is no surprise that there are starvation cases.
>
> If tasklets or work queues get delayed in any way, you lose,
> and it's very easy for a card to catch up with the driver RX'ing
> packets very fast, no matter how aggressive you make the
> replenishing. By the time you detect that you need to be
> "more aggressive" it is already too late.
> The only pseudo-reliable way is to allocate at RX processing time.
>

Signed-off-by: Santiago Leon <santil@us.ibm.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>

authored by

Santiago Leon and committed by
Jeff Garzik
e2adbcb4 b6d35182

+8 -44
+8 -40
drivers/net/ibmveth.c
··· 96 96 static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); 97 97 static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); 98 98 static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs); 99 - static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter*); 100 99 static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); 101 100 102 101 #ifdef CONFIG_PROC_FS ··· 256 257 atomic_add(buffers_added, &(pool->available)); 257 258 } 258 259 259 - /* check if replenishing is needed. */ 260 - static inline int ibmveth_is_replenishing_needed(struct ibmveth_adapter *adapter) 261 - { 262 - int i; 263 - 264 - for(i = 0; i < IbmVethNumBufferPools; i++) 265 - if(adapter->rx_buff_pool[i].active && 266 - (atomic_read(&adapter->rx_buff_pool[i].available) < 267 - adapter->rx_buff_pool[i].threshold)) 268 - return 1; 269 - return 0; 270 - } 271 - 272 - /* kick the replenish tasklet if we need replenishing and it isn't already running */ 273 - static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter *adapter) 274 - { 275 - if(ibmveth_is_replenishing_needed(adapter) && 276 - (atomic_dec_if_positive(&adapter->not_replenishing) == 0)) { 277 - schedule_work(&adapter->replenish_task); 278 - } 279 - } 280 - 281 - /* replenish tasklet routine */ 260 + /* replenish routine */ 282 261 static void ibmveth_replenish_task(struct ibmveth_adapter *adapter) 283 262 { 284 263 int i; ··· 269 292 &adapter->rx_buff_pool[i]); 270 293 271 294 adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8); 272 - 273 - atomic_inc(&adapter->not_replenishing); 274 - 275 - ibmveth_schedule_replenishing(adapter); 276 295 } 277 296 278 297 /* empty and free ana buffer pool - also used to do cleanup in error paths */ ··· 536 563 return rc; 537 564 } 538 565 539 - netif_start_queue(netdev); 566 + ibmveth_debug_printk("initial replenish cycle\n"); 567 + ibmveth_replenish_task(adapter); 540 568 541 - ibmveth_debug_printk("scheduling initial replenish cycle\n"); 542 - ibmveth_schedule_replenishing(adapter); 569 + netif_start_queue(netdev); 543 570 544 571 ibmveth_debug_printk("open complete\n"); 545 572 ··· 556 583 netif_stop_queue(netdev); 557 584 558 585 free_irq(netdev->irq, netdev); 559 - 560 - cancel_delayed_work(&adapter->replenish_task); 561 - flush_scheduled_work(); 562 586 563 587 do { 564 588 lpar_rc = h_free_logical_lan(adapter->vdev->unit_address); ··· 765 795 } 766 796 } while(more_work && (frames_processed < max_frames_to_process)); 767 797 768 - ibmveth_schedule_replenishing(adapter); 798 + ibmveth_replenish_task(adapter); 769 799 770 800 if(more_work) { 771 801 /* more work to do - return that we are not done yet */ ··· 901 931 902 932 } 903 933 934 + /* kick the interrupt handler so that the new buffer pools get 935 + replenished or deallocated */ 936 + ibmveth_interrupt(dev->irq, dev, NULL); 904 937 905 - ibmveth_schedule_replenishing(adapter); 906 938 dev->mtu = new_mtu; 907 939 return 0; 908 940 } ··· 989 1017 990 1018 ibmveth_debug_printk("adapter @ 0x%p\n", adapter); 991 1019 992 - INIT_WORK(&adapter->replenish_task, (void*)ibmveth_replenish_task, (void*)adapter); 993 - 994 1020 adapter->buffer_list_dma = DMA_ERROR_CODE; 995 1021 adapter->filter_list_dma = DMA_ERROR_CODE; 996 1022 adapter->rx_queue.queue_dma = DMA_ERROR_CODE; 997 - 998 - atomic_set(&adapter->not_replenishing, 1); 999 1023 1000 1024 ibmveth_debug_printk("registering netdev...\n"); 1001 1025
-4
drivers/net/ibmveth.h
··· 118 118 dma_addr_t filter_list_dma; 119 119 struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools]; 120 120 struct ibmveth_rx_q rx_queue; 121 - atomic_t not_replenishing; 122 - 123 - /* helper tasks */ 124 - struct work_struct replenish_task; 125 121 126 122 /* adapter specific stats */ 127 123 u64 replenish_task_cycles;