ia64/xen-unstable

changeset 234:682fc9ed30dc

bitkeeper revision 1.92 (3e5a3f34hhxCW-jAvvD9l1pqUdV3PQ)

dev.c, vif.h, xen_block.c:
More robust handling of ring indexes in network code.
author kaf24@labyrinth.cl.cam.ac.uk
date Mon Feb 24 15:50:12 2003 +0000 (2003-02-24)
parents 4c0c962a443f
children d7d0a23b2e07
files xen-2.4.16/drivers/block/xen_block.c xen-2.4.16/include/xeno/vif.h xen-2.4.16/net/dev.c
line diff
     1.1 --- a/xen-2.4.16/drivers/block/xen_block.c	Mon Feb 24 15:15:51 2003 +0000
     1.2 +++ b/xen-2.4.16/drivers/block/xen_block.c	Mon Feb 24 15:50:12 2003 +0000
     1.3 @@ -17,7 +17,7 @@
     1.4  #include <xeno/keyhandler.h>
     1.5  #include <xeno/interrupt.h>
     1.6  
     1.7 -#if 1
     1.8 +#if 0
     1.9  #define DPRINTK(_f, _a...) printk( _f , ## _a )
    1.10  #else
    1.11  #define DPRINTK(_f, _a...) ((void)0)
     2.1 --- a/xen-2.4.16/include/xeno/vif.h	Mon Feb 24 15:15:51 2003 +0000
     2.2 +++ b/xen-2.4.16/include/xeno/vif.h	Mon Feb 24 15:50:12 2003 +0000
     2.3 @@ -42,8 +42,26 @@ typedef struct tx_shadow_entry_st {
     2.4  typedef struct net_shadow_ring_st {
     2.5      rx_shadow_entry_t *rx_ring;
     2.6      tx_shadow_entry_t *tx_ring;
     2.7 -    unsigned int rx_prod, rx_cons, rx_idx;
     2.8 -    unsigned int tx_prod, tx_cons, tx_idx;
     2.9 +
    2.10 +    /*
    2.11 +     * Private copy of producer. Follows guest OS version, but never
    2.12 +     * catches up with our consumer index.
    2.13 +     */
    2.14 +    unsigned int rx_prod;
    2.15 +    /* Points at next buffer to be filled by NIC. Chases rx_prod. */
    2.16 +    unsigned int rx_idx;
    2.17 +    /* Points at next buffer to be returned to the guest OS. Chases rx_idx. */
    2.18 +    unsigned int rx_cons;
    2.19 +
    2.20 +    /*
    2.21 +     * Private copy of producer. Follows guest OS version, but never
    2.22 +     * catches up with our consumer index.
    2.23 +     */
    2.24 +    unsigned int tx_prod;
    2.25 +    /* Points at next buffer to be scheduled. Chases tx_prod. */
    2.26 +    unsigned int tx_idx;
    2.27 +    /* Points at next buffer to be returned to the guest OS. Chases tx_idx. */
    2.28 +    unsigned int tx_cons;
    2.29  } net_shadow_ring_t;
    2.30  
    2.31  typedef struct net_vif_st {
     3.1 --- a/xen-2.4.16/net/dev.c	Mon Feb 24 15:15:51 2003 +0000
     3.2 +++ b/xen-2.4.16/net/dev.c	Mon Feb 24 15:50:12 2003 +0000
     3.3 @@ -38,7 +38,7 @@
     3.4  #define rtnl_lock() ((void)0)
     3.5  #define rtnl_unlock() ((void)0)
     3.6  
     3.7 -#if 0
     3.8 +#if 1
     3.9  #define DPRINTK(_f, _a...) printk(_f , ## _a)
    3.10  #else 
    3.11  #define DPRINTK(_f, _a...) ((void)0)
    3.12 @@ -497,7 +497,7 @@ void deliver_packet(struct sk_buff *skb,
    3.13      }
    3.14      shadow_ring = vif->shadow_ring;
    3.15  
    3.16 -    if ( (i = shadow_ring->rx_cons) == shadow_ring->rx_prod )
    3.17 +    if ( (i = shadow_ring->rx_idx) == shadow_ring->rx_prod )
    3.18      {
    3.19          return;
    3.20      }
    3.21 @@ -505,7 +505,7 @@ void deliver_packet(struct sk_buff *skb,
    3.22      if ( shadow_ring->rx_ring[i].status != RING_STATUS_OK )
    3.23      {
    3.24          DPRINTK("Bad buffer in deliver_packet()\n");
    3.25 -        shadow_ring->rx_cons = RX_RING_INC(i);
    3.26 +        shadow_ring->rx_idx = RX_RING_INC(i);
    3.27          return;
    3.28      }
    3.29  
    3.30 @@ -537,7 +537,7 @@ void deliver_packet(struct sk_buff *skb,
    3.31      /* Our skbuff now points at the guest's old frame. */
    3.32      skb->pf = g_pfn;
    3.33          
    3.34 -    shadow_ring->rx_cons = RX_RING_INC(i);
    3.35 +    shadow_ring->rx_idx = RX_RING_INC(i);
    3.36  }
    3.37  
    3.38  /**
    3.39 @@ -684,7 +684,7 @@ static void add_to_net_schedule_list_tai
    3.40  static void tx_skb_release(struct sk_buff *skb)
    3.41  {
    3.42      int i;
    3.43 -    net_ring_t *ring;
    3.44 +    net_vif_t *vif = sys_vif_list[skb->src_vif];
    3.45      
    3.46      for ( i = 0; i < skb_shinfo(skb)->nr_frags; i++ )
    3.47          put_page_tot(skb_shinfo(skb)->frags[i].page);
    3.48 @@ -694,16 +694,20 @@ static void tx_skb_release(struct sk_buf
    3.49  
    3.50      skb_shinfo(skb)->nr_frags = 0; 
    3.51  
    3.52 +    /* This would mean that the guest OS has fiddled with our index. */
    3.53 +    if ( vif->shadow_ring->tx_cons != vif->net_ring->tx_cons )
    3.54 +        DPRINTK("Shadow and shared rings out of sync (%d/%d)\n",
    3.55 +                vif->shadow_ring->tx_cons, vif->net_ring->tx_cons);
    3.56 +
    3.57      /*
    3.58       * XXX This assumes that, per vif, SKBs are processed in-order!
    3.59       * Also assumes no concurrency. This is safe because each vif
    3.60       * maps to one NIC. This is executed in NIC interrupt code, so we have
    3.61       * mutual exclusion from do_IRQ().
    3.62       */
    3.63 -    ring = sys_vif_list[skb->src_vif]->net_ring;
    3.64 -    ring->tx_cons = TX_RING_INC(ring->tx_cons);
    3.65 -
    3.66 -    if ( ring->tx_cons == ring->tx_event )
    3.67 +    vif->shadow_ring->tx_cons = TX_RING_INC(vif->shadow_ring->tx_cons);
    3.68 +    vif->net_ring->tx_cons = vif->shadow_ring->tx_cons;
    3.69 +    if ( vif->net_ring->tx_cons == vif->net_ring->tx_event )
    3.70          set_bit(_EVENT_NET_TX, 
    3.71                  &sys_vif_list[skb->src_vif]->domain->shared_info->events);
    3.72  }
    3.73 @@ -803,29 +807,27 @@ void update_shared_ring(void)
    3.74      {
    3.75          net_ring = current->net_vif_list[nvif]->net_ring;
    3.76          shadow_ring = current->net_vif_list[nvif]->shadow_ring;
    3.77 -        
    3.78 -        if ( shadow_ring->rx_idx != net_ring->rx_cons )
    3.79 -        {
    3.80 +
    3.81 +        /* This would mean that the guest OS has fiddled with our index. */
    3.82 +        if ( shadow_ring->rx_cons != net_ring->rx_cons )
    3.83              DPRINTK("Shadow and shared rings out of sync (%d/%d)\n",
    3.84 -                    shadow_ring->rx_idx, net_ring->rx_cons);
    3.85 -        }
    3.86 +                    shadow_ring->rx_cons, net_ring->rx_cons);
    3.87  
    3.88 -        while ( (shadow_ring->rx_idx != shadow_ring->rx_cons) &&
    3.89 -                (net_ring->rx_cons != net_ring->rx_prod) )
    3.90 +        while ( shadow_ring->rx_cons != shadow_ring->rx_idx )
    3.91          {
    3.92 -            rx = shadow_ring->rx_ring + shadow_ring->rx_idx;
    3.93 +            rx = shadow_ring->rx_ring + shadow_ring->rx_cons;
    3.94              copy_to_user(net_ring->rx_ring + net_ring->rx_cons, rx, 
    3.95                           sizeof(rx_entry_t));
    3.96  
    3.97 -            shadow_ring->rx_idx = RX_RING_INC(shadow_ring->rx_idx);
    3.98 -            net_ring->rx_cons   = RX_RING_INC(net_ring->rx_cons);
    3.99 -            
   3.100              if ( rx->flush_count == tlb_flush_count[smp_processor_id()] )
   3.101                  __flush_tlb();
   3.102  
   3.103 -            if ( net_ring->rx_cons == net_ring->rx_event )
   3.104 +            shadow_ring->rx_cons = RX_RING_INC(shadow_ring->rx_cons);
   3.105 +
   3.106 +            if ( shadow_ring->rx_cons == net_ring->rx_event )
   3.107                  set_bit(_EVENT_NET_RX, &s->events);
   3.108          }
   3.109 +        net_ring->rx_cons = shadow_ring->rx_cons;
   3.110      }
   3.111  }
   3.112  
   3.113 @@ -1820,8 +1822,14 @@ long do_net_update(void)
   3.114           * PHASE 1 -- TRANSMIT RING
   3.115           */
   3.116  
   3.117 +        /*
   3.118 +         * Collect up new transmit buffers. We collect up to the guest OS's
   3.119 +         * new producer index, but take care not to catch up with our own
   3.120 +         * consumer index.
   3.121 +         */
   3.122          for ( i = shadow_ring->tx_prod; 
   3.123 -              i != net_ring->tx_prod; 
   3.124 +              (i != net_ring->tx_prod) && 
   3.125 +                  (((shadow_ring->tx_cons-i) & (TX_RING_SIZE-1)) != 1); 
   3.126                i = TX_RING_INC(i) )
   3.127          {
   3.128              if ( copy_from_user(&tx, net_ring->tx_ring+i, sizeof(tx)) )
   3.129 @@ -1836,13 +1844,13 @@ long do_net_update(void)
   3.130  
   3.131              if ( tx.size < PKT_PROT_LEN )
   3.132              {
   3.133 -                DPRINTK("Runt packet %ld\n", tx.size);
   3.134 +                DPRINTK("Runt packet %d\n", tx.size);
   3.135                  continue; 
   3.136              }
   3.137  
   3.138              if ( ((tx.addr & ~PAGE_MASK) + tx.size) >= PAGE_SIZE ) 
   3.139              {
   3.140 -                DPRINTK("tx.addr: %lx, size: %lu, end: %lu\n", 
   3.141 +                DPRINTK("tx.addr: %lx, size: %u, end: %lu\n", 
   3.142                          tx.addr, tx.size, (tx.addr &~PAGE_MASK) + tx.size);
   3.143                  continue;
   3.144              }
   3.145 @@ -1906,15 +1914,23 @@ long do_net_update(void)
   3.146          }
   3.147          smp_wmb(); /* Let other CPUs see new descriptors first. */
   3.148          shadow_ring->tx_prod = i;
   3.149 +
   3.150 +        /* XXX: This should be more consevative. */
   3.151          add_to_net_schedule_list_tail(current_vif);
   3.152 -        tasklet_schedule(&net_tx_tasklet); /* XXX */
   3.153 +        tasklet_schedule(&net_tx_tasklet);
   3.154  
   3.155          /*
   3.156           * PHASE 2 -- RECEIVE RING
   3.157           */
   3.158  
   3.159 +        /*
   3.160 +         * Collect up new receive buffers. We collect up to the guest OS's
   3.161 +         * new producer index, but take care not to catch up with our own
   3.162 +         * consumer index.
   3.163 +         */
   3.164          for ( i = shadow_ring->rx_prod; 
   3.165 -              i != net_ring->rx_prod; 
   3.166 +              (i != net_ring->rx_prod) && 
   3.167 +                  (((shadow_ring->rx_cons-i) & (RX_RING_SIZE-1)) != 1); 
   3.168                i = RX_RING_INC(i) )
   3.169          {
   3.170              /*