ia64/xen-unstable
changeset 7953:0add9fbe93ab
Fix grant-table transfer implementation. Also fix transfer
error paths in network frontend and backend drivers.
Signed-off-by: Keir Fraser <keir@xensource.com>
error paths in network frontend and backend drivers.
Signed-off-by: Keir Fraser <keir@xensource.com>
author | kaf24@firebug.cl.cam.ac.uk |
---|---|
date | Mon Nov 21 14:17:50 2005 +0100 (2005-11-21) |
parents | 675862d22347 |
children | 340effeb64b5 |
files | linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c linux-2.6-xen-sparse/drivers/xen/netback/netback.c linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c xen/common/grant_table.c |
line diff
1.1 --- a/linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c Mon Nov 21 13:17:29 2005 +0100 1.2 +++ b/linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c Mon Nov 21 14:17:50 2005 +0100 1.3 @@ -229,20 +229,29 @@ gnttab_grant_foreign_transfer_ref(grant_ 1.4 unsigned long 1.5 gnttab_end_foreign_transfer_ref(grant_ref_t ref) 1.6 { 1.7 - unsigned long frame = 0; 1.8 + unsigned long frame; 1.9 u16 flags; 1.10 1.11 - flags = shared[ref].flags; 1.12 - 1.13 /* 1.14 - * If a transfer is committed then wait for the frame address to 1.15 - * appear. Otherwise invalidate the grant entry against future use. 1.16 - */ 1.17 - if (likely(flags != GTF_accept_transfer) || 1.18 - (synch_cmpxchg(&shared[ref].flags, flags, 0) != 1.19 - GTF_accept_transfer)) 1.20 - while (unlikely((frame = shared[ref].frame) == 0)) 1.21 - cpu_relax(); 1.22 + * If a transfer is not even yet started, try to reclaim the grant 1.23 + * reference and return failure (== 0). 1.24 + */ 1.25 + while (!((flags = shared[ref].flags) & GTF_transfer_committed)) { 1.26 + if ( synch_cmpxchg(&shared[ref].flags, flags, 0) == flags ) 1.27 + return 0; 1.28 + cpu_relax(); 1.29 + } 1.30 + 1.31 + /* If a transfer is in progress then wait until it is completed. */ 1.32 + while (!(flags & GTF_transfer_completed)) { 1.33 + flags = shared[ref].flags; 1.34 + cpu_relax(); 1.35 + } 1.36 + 1.37 + /* Read the frame number /after/ reading completion status. */ 1.38 + rmb(); 1.39 + frame = shared[ref].frame; 1.40 + BUG_ON(frame == 0); 1.41 1.42 return frame; 1.43 }
2.1 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c Mon Nov 21 13:17:29 2005 +0100 2.2 +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c Mon Nov 21 14:17:50 2005 +0100 2.3 @@ -99,7 +99,6 @@ static unsigned long alloc_mfn(void) 2.4 return mfn; 2.5 } 2.6 2.7 -#if 0 2.8 static void free_mfn(unsigned long mfn) 2.9 { 2.10 unsigned long flags; 2.11 @@ -120,7 +119,6 @@ static void free_mfn(unsigned long mfn) 2.12 } 2.13 spin_unlock_irqrestore(&mfn_lock, flags); 2.14 } 2.15 -#endif 2.16 2.17 static inline void maybe_schedule_tx_action(void) 2.18 { 2.19 @@ -287,28 +285,19 @@ static void net_rx_action(unsigned long 2.20 ret = HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl); 2.21 BUG_ON(ret != 0); 2.22 2.23 + ret = HYPERVISOR_grant_table_op(GNTTABOP_transfer, grant_rx_op, 2.24 + gop - grant_rx_op); 2.25 + BUG_ON(ret != 0); 2.26 + 2.27 mcl = rx_mcl; 2.28 - if( HYPERVISOR_grant_table_op(GNTTABOP_transfer, grant_rx_op, 2.29 - gop - grant_rx_op)) { 2.30 - /* 2.31 - * The other side has given us a bad grant ref, or has no 2.32 - * headroom, or has gone away. Unfortunately the current grant 2.33 - * table code doesn't inform us which is the case, so not much 2.34 - * we can do. 2.35 - */ 2.36 - DPRINTK("net_rx: transfer to DOM%u failed; dropping (up to) " 2.37 - "%d packets.\n", 2.38 - grant_rx_op[0].domid, gop - grant_rx_op); 2.39 - } 2.40 gop = grant_rx_op; 2.41 - 2.42 while ((skb = __skb_dequeue(&rxq)) != NULL) { 2.43 netif = netdev_priv(skb->dev); 2.44 size = skb->tail - skb->data; 2.45 2.46 /* Rederive the machine addresses. */ 2.47 - new_mfn = mcl[0].args[1] >> PAGE_SHIFT; 2.48 - old_mfn = 0; /* XXX Fix this so we can free_mfn() on error! */ 2.49 + new_mfn = mcl->args[1] >> PAGE_SHIFT; 2.50 + old_mfn = gop->mfn; 2.51 atomic_set(&(skb_shinfo(skb)->dataref), 1); 2.52 skb_shinfo(skb)->nr_frags = 0; 2.53 skb_shinfo(skb)->frag_list = NULL; 2.54 @@ -321,10 +310,10 @@ static void net_rx_action(unsigned long 2.55 2.56 /* Check the reassignment error code. */ 2.57 status = NETIF_RSP_OKAY; 2.58 - if(gop->status != 0) { 2.59 + if (gop->status != 0) { 2.60 DPRINTK("Bad status %d from grant transfer to DOM%u\n", 2.61 gop->status, netif->domid); 2.62 - /* XXX SMH: should free 'old_mfn' here */ 2.63 + free_mfn(old_mfn); 2.64 status = NETIF_RSP_ERROR; 2.65 } 2.66 irq = netif->irq;
3.1 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c Mon Nov 21 13:17:29 2005 +0100 3.2 +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c Mon Nov 21 14:17:50 2005 +0100 3.3 @@ -739,14 +739,23 @@ static int netif_poll(struct net_device 3.4 (i != rp) && (work_done < budget); 3.5 i++, work_done++) { 3.6 rx = &np->rx->ring[MASK_NETIF_RX_IDX(i)].resp; 3.7 + 3.8 /* 3.9 - * An error here is very odd. Usually indicates a backend bug, 3.10 - * low-mem condition, or we didn't have reservation headroom. 3.11 - */ 3.12 - if (unlikely(rx->status <= 0)) { 3.13 + * This definitely indicates a bug, either in this driver or 3.14 + * in the backend driver. In future this should flag the bad 3.15 + * situation to the system controller to reboot the backed. 3.16 + */ 3.17 + if ((ref = np->grant_rx_ref[rx->id]) == GRANT_INVALID_REF) { 3.18 + WPRINTK("Bad rx response id %d.\n", rx->id); 3.19 + work_done--; 3.20 + continue; 3.21 + } 3.22 + 3.23 + /* Memory pressure, insufficient buffer headroom, ... */ 3.24 + if ((mfn = gnttab_end_foreign_transfer_ref(ref)) == 0) { 3.25 if (net_ratelimit()) 3.26 - printk(KERN_WARNING "Bad rx buffer " 3.27 - "(memory squeeze?).\n"); 3.28 + WPRINTK("Unfulfilled rx req (id=%d, st=%d).\n", 3.29 + rx->id, rx->status); 3.30 np->rx->ring[MASK_NETIF_RX_IDX(np->rx->req_prod)]. 3.31 req.id = rx->id; 3.32 wmb(); 3.33 @@ -755,23 +764,8 @@ static int netif_poll(struct net_device 3.34 continue; 3.35 } 3.36 3.37 - ref = np->grant_rx_ref[rx->id]; 3.38 - 3.39 - if(ref == GRANT_INVALID_REF) { 3.40 - printk(KERN_WARNING "Bad rx grant reference %d " 3.41 - "from dom %d.\n", 3.42 - ref, np->xbdev->otherend_id); 3.43 - np->rx->ring[MASK_NETIF_RX_IDX(np->rx->req_prod)]. 3.44 - req.id = rx->id; 3.45 - wmb(); 3.46 - np->rx->req_prod++; 3.47 - work_done--; 3.48 - continue; 3.49 - } 3.50 - 3.51 + gnttab_release_grant_reference(&np->gref_rx_head, ref); 3.52 np->grant_rx_ref[rx->id] = GRANT_INVALID_REF; 3.53 - mfn = gnttab_end_foreign_transfer_ref(ref); 3.54 - gnttab_release_grant_reference(&np->gref_rx_head, ref); 3.55 3.56 skb = np->rx_skbs[rx->id]; 3.57 ADD_ID_TO_FREELIST(np->rx_skbs, rx->id);
4.1 --- a/xen/common/grant_table.c Mon Nov 21 13:17:29 2005 +0100 4.2 +++ b/xen/common/grant_table.c Mon Nov 21 14:17:50 2005 +0100 4.3 @@ -706,35 +706,34 @@ gnttab_transfer( 4.4 struct pfn_info *page; 4.5 u32 _d, _nd, x, y; 4.6 int i; 4.7 - int result = GNTST_okay; 4.8 grant_entry_t *sha; 4.9 + gnttab_transfer_t gop; 4.10 4.11 for ( i = 0; i < count; i++ ) 4.12 { 4.13 - gnttab_transfer_t *gop = &uop[i]; 4.14 - 4.15 - page = &frame_table[gop->mfn]; 4.16 - 4.17 - if ( unlikely(IS_XEN_HEAP_FRAME(page))) 4.18 - { 4.19 - printk("gnttab_transfer: xen heap frame mfn=%lx\n", 4.20 - (unsigned long) gop->mfn); 4.21 - gop->status = GNTST_bad_virt_addr; 4.22 - continue; 4.23 - } 4.24 - 4.25 - if ( unlikely(!pfn_valid(page_to_pfn(page))) ) 4.26 + /* Read from caller address space. */ 4.27 + if ( unlikely(__copy_from_user(&gop, &uop[i], sizeof(gop))) ) 4.28 { 4.29 - printk("gnttab_transfer: invalid pfn for mfn=%lx\n", 4.30 - (unsigned long) gop->mfn); 4.31 - gop->status = GNTST_bad_virt_addr; 4.32 - continue; 4.33 + /* Caller error: bail immediately. */ 4.34 + DPRINTK("gnttab_transfer: error reading req %d/%d\n", i, count); 4.35 + return -EFAULT; 4.36 } 4.37 4.38 - if ( unlikely((e = find_domain_by_id(gop->domid)) == NULL) ) 4.39 + /* Check the passed page frame for basic validity. */ 4.40 + page = &frame_table[gop.mfn]; 4.41 + if ( unlikely(!pfn_valid(gop.mfn) || IS_XEN_HEAP_FRAME(page)) ) 4.42 + { 4.43 + /* Caller error: bail immediately. */ 4.44 + DPRINTK("gnttab_transfer: out-of-range or xen frame %lx\n", 4.45 + (unsigned long)gop.mfn); 4.46 + return -EINVAL; 4.47 + } 4.48 + 4.49 + /* Find the target domain. */ 4.50 + if ( unlikely((e = find_domain_by_id(gop.domid)) == NULL) ) 4.51 { 4.52 - printk("gnttab_transfer: can't find domain %d\n", gop->domid); 4.53 - gop->status = GNTST_bad_domain; 4.54 + DPRINTK("gnttab_transfer: can't find domain %d\n", gop.domid); 4.55 + (void)__put_user(GNTST_bad_domain, &uop[i].status); 4.56 continue; 4.57 } 4.58 4.59 @@ -752,15 +751,16 @@ gnttab_transfer( 4.60 do { 4.61 x = y; 4.62 if (unlikely((x & (PGC_count_mask|PGC_allocated)) != 4.63 - (1 | PGC_allocated)) || unlikely(_nd != _d)) { 4.64 - printk("gnttab_transfer: Bad page values %p: ed=%p(%u), sd=%p," 4.65 + (1 | PGC_allocated)) || unlikely(_nd != _d)) { 4.66 + /* Caller error: bail immediately. */ 4.67 + DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u), sd=%p," 4.68 " caf=%08x, taf=%" PRtype_info "\n", 4.69 (void *) page_to_pfn(page), 4.70 d, d->domain_id, unpickle_domptr(_nd), x, 4.71 page->u.inuse.type_info); 4.72 spin_unlock(&d->page_alloc_lock); 4.73 put_domain(e); 4.74 - return 0; 4.75 + return -EINVAL; 4.76 } 4.77 __asm__ __volatile__( 4.78 LOCK_PREFIX "cmpxchg8b %2" 4.79 @@ -788,16 +788,16 @@ gnttab_transfer( 4.80 */ 4.81 if ( unlikely(test_bit(_DOMF_dying, &e->domain_flags)) || 4.82 unlikely(e->tot_pages >= e->max_pages) || 4.83 - unlikely(!gnttab_prepare_for_transfer(e, d, gop->ref)) ) 4.84 + unlikely(!gnttab_prepare_for_transfer(e, d, gop.ref)) ) 4.85 { 4.86 DPRINTK("gnttab_transfer: Transferee has no reservation headroom " 4.87 "(%d,%d) or provided a bad grant ref (%08x) or " 4.88 "is dying (%lx)\n", 4.89 - e->tot_pages, e->max_pages, gop->ref, e->domain_flags); 4.90 + e->tot_pages, e->max_pages, gop.ref, e->domain_flags); 4.91 spin_unlock(&e->page_alloc_lock); 4.92 put_domain(e); 4.93 - gop->status = result = GNTST_general_error; 4.94 - break; 4.95 + (void)__put_user(GNTST_general_error, &uop[i].status); 4.96 + continue; 4.97 } 4.98 4.99 /* Okay, add the page to 'e'. */ 4.100 @@ -805,23 +805,23 @@ gnttab_transfer( 4.101 get_knownalive_domain(e); 4.102 list_add_tail(&page->list, &e->page_list); 4.103 page_set_owner(page, e); 4.104 - 4.105 + 4.106 spin_unlock(&e->page_alloc_lock); 4.107 4.108 TRACE_1D(TRC_MEM_PAGE_GRANT_TRANSFER, e->domain_id); 4.109 - 4.110 + 4.111 /* Tell the guest about its new page frame. */ 4.112 - sha = &e->grant_table->shared[gop->ref]; 4.113 - sha->frame = gop->mfn; 4.114 + sha = &e->grant_table->shared[gop.ref]; 4.115 + sha->frame = gop.mfn; 4.116 wmb(); 4.117 sha->flags |= GTF_transfer_completed; 4.118 - 4.119 + 4.120 put_domain(e); 4.121 - 4.122 - gop->status = GNTST_okay; 4.123 + 4.124 + (void)__put_user(GNTST_okay, &uop[i].status); 4.125 } 4.126 4.127 - return result; 4.128 + return 0; 4.129 } 4.130 4.131 long