ia64/xen-unstable
changeset 667:6c29b3a63599
bitkeeper revision 1.382 (3f27e9e1QG4aZMHik9lRSaa177YIHg)
dev.c, skbuff.h, interrupt.h:
Fix network receive path to use a softirq to avoid deadlock situations.
dev.c, skbuff.h, interrupt.h:
Fix network receive path to use a softirq to avoid deadlock situations.
author | kaf24@scramble.cl.cam.ac.uk |
---|---|
date | Wed Jul 30 15:53:05 2003 +0000 (2003-07-30) |
parents | b2b71842e45e |
children | e924f1dd98f3 |
files | xen/include/xeno/interrupt.h xen/include/xeno/skbuff.h xen/net/dev.c |
line diff
1.1 --- a/xen/include/xeno/interrupt.h Wed Jul 30 14:55:42 2003 +0000 1.2 +++ b/xen/include/xeno/interrupt.h Wed Jul 30 15:53:05 2003 +0000 1.3 @@ -45,6 +45,7 @@ enum { 1.4 enum 1.5 { 1.6 HI_SOFTIRQ=0, 1.7 + NET_RX_SOFTIRQ, 1.8 AC_TIMER_SOFTIRQ, 1.9 TASKLET_SOFTIRQ 1.10 };
2.1 --- a/xen/include/xeno/skbuff.h Wed Jul 30 14:55:42 2003 +0000 2.2 +++ b/xen/include/xeno/skbuff.h Wed Jul 30 15:53:05 2003 +0000 2.3 @@ -236,6 +236,31 @@ static inline void __skb_queue_head(stru 2.4 } 2.5 2.6 /** 2.7 + * __skb_queue_tail - queue a buffer at the list tail 2.8 + * @list: list to use 2.9 + * @newsk: buffer to queue 2.10 + * 2.11 + * Queue a buffer at the end of a list. This function takes no locks 2.12 + * and you must therefore hold required locks before calling it. 2.13 + * 2.14 + * A buffer cannot be placed on two lists at the same time. 2.15 + */ 2.16 + 2.17 +static inline void __skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk) 2.18 +{ 2.19 + struct sk_buff *prev, *next; 2.20 + 2.21 + newsk->list = list; 2.22 + list->qlen++; 2.23 + next = (struct sk_buff *)list; 2.24 + prev = next->prev; 2.25 + newsk->next = next; 2.26 + newsk->prev = prev; 2.27 + next->prev = newsk; 2.28 + prev->next = newsk; 2.29 +} 2.30 + 2.31 +/** 2.32 * __skb_dequeue - remove from the head of the queue 2.33 * @list: list to dequeue from 2.34 *
3.1 --- a/xen/net/dev.c Wed Jul 30 14:55:42 2003 +0000 3.2 +++ b/xen/net/dev.c Wed Jul 30 15:53:05 2003 +0000 3.3 @@ -51,6 +51,8 @@ 3.4 #define TX_RING_ADD(_i,_j) (((_i)+(_j)) & (TX_RING_SIZE-1)) 3.5 #define RX_RING_ADD(_i,_j) (((_i)+(_j)) & (RX_RING_SIZE-1)) 3.6 3.7 +static struct sk_buff_head rx_skb_queue[NR_CPUS] __cacheline_aligned; 3.8 + 3.9 static void make_tx_response(net_vif_t *vif, 3.10 unsigned short id, 3.11 unsigned char st); 3.12 @@ -604,39 +606,68 @@ void deliver_packet(struct sk_buff *skb, 3.13 3.14 int netif_rx(struct sk_buff *skb) 3.15 { 3.16 - int offset, this_cpu = smp_processor_id(); 3.17 + int this_cpu = smp_processor_id(); 3.18 + struct sk_buff_head *q = &rx_skb_queue[this_cpu]; 3.19 unsigned long flags; 3.20 3.21 + /* This oughtn't to happen, really! */ 3.22 + if ( unlikely(skb_queue_len(q) > 100) ) 3.23 + { 3.24 + printk("Congestion -- packet dropped!!\n"); 3.25 + return NET_RX_DROP; 3.26 + } 3.27 + 3.28 local_irq_save(flags); 3.29 + __skb_queue_tail(q, skb); 3.30 + local_irq_restore(flags); 3.31 3.32 - ASSERT(skb->skb_type == SKB_ZERO_COPY); 3.33 + __cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ); 3.34 + 3.35 + return NET_RX_SUCCESS; 3.36 +} 3.37 3.38 - /* 3.39 - * Offset will include 16 bytes padding from dev_alloc_skb, 14 bytes for 3.40 - * ethernet header, plus any other alignment padding added by the driver. 3.41 - */ 3.42 - offset = (int)skb->data & ~PAGE_MASK; 3.43 - skb->head = (u8 *)map_domain_mem(((skb->pf - frame_table) << PAGE_SHIFT)); 3.44 - skb->data = skb->nh.raw = skb->head + offset; 3.45 - skb->tail = skb->data + skb->len; 3.46 - skb_push(skb, ETH_HLEN); 3.47 - skb->mac.raw = skb->data; 3.48 +static void net_rx_action(struct softirq_action *h) 3.49 +{ 3.50 + int offset, this_cpu = smp_processor_id(); 3.51 + struct sk_buff_head *q = &rx_skb_queue[this_cpu]; 3.52 + struct sk_buff *skb; 3.53 + 3.54 + local_irq_disable(); 3.55 + 3.56 + while ( (skb = __skb_dequeue(q)) != NULL ) 3.57 + { 3.58 + ASSERT(skb->skb_type == SKB_ZERO_COPY); 3.59 3.60 - netdev_rx_stat[this_cpu].total++; 3.61 - 3.62 - if ( skb->dst_vif == NULL ) 3.63 - skb->dst_vif = net_get_target_vif(skb->data, skb->len, skb->src_vif); 3.64 + /* 3.65 + * Offset will include 16 bytes padding from dev_alloc_skb, 14 bytes 3.66 + * for ethernet header, plus any other alignment padding added by the 3.67 + * driver. 3.68 + */ 3.69 + offset = (int)skb->data & ~PAGE_MASK; 3.70 + skb->head = (u8 *)map_domain_mem(((skb->pf - frame_table) << 3.71 + PAGE_SHIFT)); 3.72 + skb->data = skb->nh.raw = skb->head + offset; 3.73 + skb->tail = skb->data + skb->len; 3.74 + skb_push(skb, ETH_HLEN); 3.75 + skb->mac.raw = skb->data; 3.76 3.77 - if ( !VIF_LOCAL(skb->dst_vif) ) 3.78 - skb->dst_vif = find_vif_by_id(0); 3.79 + netdev_rx_stat[this_cpu].total++; 3.80 + 3.81 + if ( skb->dst_vif == NULL ) 3.82 + skb->dst_vif = net_get_target_vif( 3.83 + skb->data, skb->len, skb->src_vif); 3.84 + 3.85 + if ( !VIF_LOCAL(skb->dst_vif) ) 3.86 + skb->dst_vif = find_vif_by_id(0); 3.87 + 3.88 + deliver_packet(skb, skb->dst_vif); 3.89 + put_vif(skb->dst_vif); 3.90 + 3.91 + unmap_domain_mem(skb->head); 3.92 + kfree_skb(skb); 3.93 + } 3.94 3.95 - deliver_packet(skb, skb->dst_vif); 3.96 - put_vif(skb->dst_vif); 3.97 - 3.98 - unmap_domain_mem(skb->head); 3.99 - kfree_skb(skb); 3.100 - local_irq_restore(flags); 3.101 - return NET_RX_SUCCESS; 3.102 + local_irq_enable(); 3.103 } 3.104 3.105 3.106 @@ -1770,7 +1801,7 @@ long do_net_update(void) 3.107 net_vif_t *vif; 3.108 net_idx_t *shared_idxs; 3.109 unsigned int i, j, idx; 3.110 - struct sk_buff *skb, *interdom_skb = NULL; 3.111 + struct sk_buff *skb; 3.112 tx_req_entry_t tx; 3.113 rx_req_entry_t rx; 3.114 unsigned long pte_pfn, buf_pfn; 3.115 @@ -1874,11 +1905,7 @@ long do_net_update(void) 3.116 skb->len = tx.size - ETH_HLEN; 3.117 unmap_domain_mem(skb->head); 3.118 3.119 - /* 3.120 - * We must defer netif_rx until we have released the current 3.121 - * domain's page_lock, or we may deadlock on SMP. 3.122 - */ 3.123 - interdom_skb = skb; 3.124 + netif_rx(skb); 3.125 3.126 make_tx_response(vif, tx.id, RING_STATUS_OK); 3.127 } 3.128 @@ -1907,11 +1934,6 @@ long do_net_update(void) 3.129 tx_unmap_and_continue: 3.130 unmap_domain_mem(g_data); 3.131 spin_unlock_irq(¤t->page_lock); 3.132 - if ( interdom_skb != NULL ) 3.133 - { 3.134 - (void)netif_rx(interdom_skb); 3.135 - interdom_skb = NULL; 3.136 - } 3.137 } 3.138 3.139 vif->tx_req_cons = i; 3.140 @@ -2069,7 +2091,7 @@ static void make_rx_response(net_vif_t 3.141 3.142 int setup_network_devices(void) 3.143 { 3.144 - int ret; 3.145 + int i, ret; 3.146 extern char opt_ifname[]; 3.147 struct net_device *dev = dev_get_by_name(opt_ifname); 3.148 3.149 @@ -2088,6 +2110,10 @@ int setup_network_devices(void) 3.150 printk("Device %s opened and ready for use.\n", opt_ifname); 3.151 the_dev = dev; 3.152 3.153 + for ( i = 0; i < smp_num_cpus; i++ ) 3.154 + skb_queue_head_init(&rx_skb_queue[i]); 3.155 + 3.156 + open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL); 3.157 tasklet_enable(&net_tx_tasklet); 3.158 3.159 return 1;