static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb) { struct skb_shared_info *shinfo = skb_shinfo(skb); int nr_frags = shinfo->nr_frags; int i; for (i = 0; i < nr_frags; i++) { skb_frag_t *frag = shinfo->frags + i; struct xen_netif_tx_request *txp; struct page *page; u16 pending_idx; pending_idx = frag_get_pending_idx(frag); txp = &vif->pending_tx_info[pending_idx].req; page = virt_to_page(idx_to_kaddr(vif, pending_idx)); __skb_fill_page_desc(skb, i, page, txp->offset, txp->size); skb->len += txp->size; skb->data_len += txp->size; skb->truesize += txp->size; /* Take an extra reference to offset xenvif_idx_release */ get_page(vif->mmap_pages[pending_idx]); xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); } }
static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif, struct sk_buff *skb, struct xen_netif_tx_request *txp, struct gnttab_map_grant_ref *gop) { struct skb_shared_info *shinfo = skb_shinfo(skb); skb_frag_t *frags = shinfo->frags; u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx; int start; pending_ring_idx_t index; unsigned int nr_slots, frag_overflow = 0; /* At this point shinfo->nr_frags is in fact the number of * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX. */ if (shinfo->nr_frags > MAX_SKB_FRAGS) { frag_overflow = shinfo->nr_frags - MAX_SKB_FRAGS; BUG_ON(frag_overflow > MAX_SKB_FRAGS); shinfo->nr_frags = MAX_SKB_FRAGS; } nr_slots = shinfo->nr_frags; /* Skip first skb fragment if it is on same page as header fragment. */ start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx); for (shinfo->nr_frags = start; shinfo->nr_frags < nr_slots; shinfo->nr_frags++, txp++, gop++) { index = pending_index(vif->pending_cons++); pending_idx = vif->pending_ring[index]; xenvif_tx_create_map_op(vif, pending_idx, txp, gop); frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx); } if (frag_overflow) { struct sk_buff *nskb = xenvif_alloc_skb(0); if (unlikely(nskb == NULL)) { if (net_ratelimit()) netdev_err(vif->dev, "Can't allocate the frag_list skb.\n"); return NULL; } shinfo = skb_shinfo(nskb); frags = shinfo->frags; for (shinfo->nr_frags = 0; shinfo->nr_frags < frag_overflow; shinfo->nr_frags++, txp++, gop++) { index = pending_index(vif->pending_cons++); pending_idx = vif->pending_ring[index]; xenvif_tx_create_map_op(vif, pending_idx, txp, gop); frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx); } skb_shinfo(skb)->frag_list = nskb; } return gop; }
static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb) { struct skb_shared_info *shinfo = skb_shinfo(skb); int nr_frags = shinfo->nr_frags; int i; u16 prev_pending_idx = INVALID_PENDING_IDX; for (i = 0; i < nr_frags; i++) { skb_frag_t *frag = shinfo->frags + i; struct xen_netif_tx_request *txp; struct page *page; u16 pending_idx; pending_idx = frag_get_pending_idx(frag); /* If this is not the first frag, chain it to the previous*/ if (prev_pending_idx == INVALID_PENDING_IDX) skb_shinfo(skb)->destructor_arg = &callback_param(vif, pending_idx); else callback_param(vif, prev_pending_idx).ctx = &callback_param(vif, pending_idx); callback_param(vif, pending_idx).ctx = NULL; prev_pending_idx = pending_idx; txp = &vif->pending_tx_info[pending_idx].req; page = virt_to_page(idx_to_kaddr(vif, pending_idx)); __skb_fill_page_desc(skb, i, page, txp->offset, txp->size); skb->len += txp->size; skb->data_len += txp->size; skb->truesize += txp->size; /* Take an extra reference to offset network stack's put_page */ get_page(vif->mmap_pages[pending_idx]); } /* FIXME: __skb_fill_page_desc set this to true because page->pfmemalloc * overlaps with "index", and "mapping" is not set. I think mapping * should be set. If delivered to local stack, it would drop this * skb in sk_filter unless the socket has the right to use it. */ skb->pfmemalloc = false; }
static int xenvif_tx_check_gop(struct xenvif *vif, struct sk_buff *skb, struct gnttab_map_grant_ref **gopp_map, struct gnttab_copy **gopp_copy) { struct gnttab_map_grant_ref *gop_map = *gopp_map; u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx; struct skb_shared_info *shinfo = skb_shinfo(skb); int nr_frags = shinfo->nr_frags; int i, err; struct sk_buff *first_skb = NULL; /* Check status of header. */ err = (*gopp_copy)->status; (*gopp_copy)++; if (unlikely(err)) { if (net_ratelimit()) netdev_dbg(vif->dev, "Grant copy of header failed! status: %d pending_idx: %u ref: %u\n", (*gopp_copy)->status, pending_idx, (*gopp_copy)->source.u.ref); xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR); } check_frags: for (i = 0; i < nr_frags; i++, gop_map++) { int j, newerr; pending_idx = frag_get_pending_idx(&shinfo->frags[i]); /* Check error status: if okay then remember grant handle. */ newerr = gop_map->status; if (likely(!newerr)) { xenvif_grant_handle_set(vif, pending_idx, gop_map->handle); /* Had a previous error? Invalidate this fragment. */ if (unlikely(err)) xenvif_idx_unmap(vif, pending_idx); continue; } /* Error on this fragment: respond to client with an error. */ if (net_ratelimit()) netdev_dbg(vif->dev, "Grant map of %d. frag failed! status: %d pending_idx: %u ref: %u\n", i, gop_map->status, pending_idx, gop_map->ref); xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR); /* Not the first error? Preceding frags already invalidated. */ if (err) continue; /* First error: invalidate preceding fragments. */ for (j = 0; j < i; j++) { pending_idx = frag_get_pending_idx(&shinfo->frags[j]); xenvif_idx_unmap(vif, pending_idx); } /* Remember the error: invalidate all subsequent fragments. */ err = newerr; } if (skb_has_frag_list(skb)) { first_skb = skb; skb = shinfo->frag_list; shinfo = skb_shinfo(skb); nr_frags = shinfo->nr_frags; goto check_frags; } /* There was a mapping error in the frag_list skb. We have to unmap * the first skb's frags */ if (first_skb && err) { int j; shinfo = skb_shinfo(first_skb); for (j = 0; j < shinfo->nr_frags; j++) { pending_idx = frag_get_pending_idx(&shinfo->frags[j]); xenvif_idx_unmap(vif, pending_idx); } } *gopp_map = gop_map; return err; }
static int xenvif_tx_check_gop(struct xenvif *vif, struct sk_buff *skb, struct gnttab_copy **gopp) { struct gnttab_copy *gop = *gopp; u16 pending_idx = *((u16 *)skb->data); struct skb_shared_info *shinfo = skb_shinfo(skb); struct pending_tx_info *tx_info; int nr_frags = shinfo->nr_frags; int i, err, start; u16 peek; /* peek into next tx request */ /* Check status of header. */ err = gop->status; if (unlikely(err)) xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR); /* Skip first skb fragment if it is on same page as header fragment. */ start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx); for (i = start; i < nr_frags; i++) { int j, newerr; pending_ring_idx_t head; pending_idx = frag_get_pending_idx(&shinfo->frags[i]); tx_info = &vif->pending_tx_info[pending_idx]; head = tx_info->head; /* Check error status: if okay then remember grant handle. */ do { newerr = (++gop)->status; if (newerr) break; peek = vif->pending_ring[pending_index(++head)]; } while (!pending_tx_is_head(vif, peek)); if (likely(!newerr)) { /* Had a previous error? Invalidate this fragment. */ if (unlikely(err)) xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); continue; } /* Error on this fragment: respond to client with an error. */ xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR); /* Not the first error? Preceding frags already invalidated. */ if (err) continue; /* First error: invalidate header and preceding fragments. */ pending_idx = *((u16 *)skb->data); xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); for (j = start; j < i; j++) { pending_idx = frag_get_pending_idx(&shinfo->frags[j]); xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); } /* Remember the error: invalidate all subsequent fragments. */ err = newerr; } *gopp = gop + 1; return err; }
static struct gnttab_copy *xenvif_get_requests(struct xenvif *vif, struct sk_buff *skb, struct xen_netif_tx_request *txp, struct gnttab_copy *gop) { struct skb_shared_info *shinfo = skb_shinfo(skb); skb_frag_t *frags = shinfo->frags; u16 pending_idx = *((u16 *)skb->data); u16 head_idx = 0; int slot, start; struct page *page; pending_ring_idx_t index, start_idx = 0; uint16_t dst_offset; unsigned int nr_slots; struct pending_tx_info *first = NULL; /* At this point shinfo->nr_frags is in fact the number of * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX. */ nr_slots = shinfo->nr_frags; /* Skip first skb fragment if it is on same page as header fragment. */ start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx); /* Coalesce tx requests, at this point the packet passed in * should be <= 64K. Any packets larger than 64K have been * handled in xenvif_count_requests(). */ for (shinfo->nr_frags = slot = start; slot < nr_slots; shinfo->nr_frags++) { struct pending_tx_info *pending_tx_info = vif->pending_tx_info; page = alloc_page(GFP_ATOMIC|__GFP_COLD); if (!page) goto err; dst_offset = 0; first = NULL; while (dst_offset < PAGE_SIZE && slot < nr_slots) { gop->flags = GNTCOPY_source_gref; gop->source.u.ref = txp->gref; gop->source.domid = vif->domid; gop->source.offset = txp->offset; gop->dest.domid = DOMID_SELF; gop->dest.offset = dst_offset; gop->dest.u.gmfn = virt_to_mfn(page_address(page)); if (dst_offset + txp->size > PAGE_SIZE) { /* This page can only merge a portion * of tx request. Do not increment any * pointer / counter here. The txp * will be dealt with in future * rounds, eventually hitting the * `else` branch. */ gop->len = PAGE_SIZE - dst_offset; txp->offset += gop->len; txp->size -= gop->len; dst_offset += gop->len; /* quit loop */ } else { /* This tx request can be merged in the page */ gop->len = txp->size; dst_offset += gop->len; index = pending_index(vif->pending_cons++); pending_idx = vif->pending_ring[index]; memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp)); /* Poison these fields, corresponding * fields for head tx req will be set * to correct values after the loop. */ vif->mmap_pages[pending_idx] = (void *)(~0UL); pending_tx_info[pending_idx].head = INVALID_PENDING_RING_IDX; if (!first) { first = &pending_tx_info[pending_idx]; start_idx = index; head_idx = pending_idx; } txp++; slot++; } gop++; } first->req.offset = 0; first->req.size = dst_offset; first->head = start_idx; vif->mmap_pages[head_idx] = page; frag_set_pending_idx(&frags[shinfo->nr_frags], head_idx); } BUG_ON(shinfo->nr_frags > MAX_SKB_FRAGS); return gop; err: /* Unwind, freeing all pages and sending error responses. */ while (shinfo->nr_frags-- > start) { xenvif_idx_release(vif, frag_get_pending_idx(&frags[shinfo->nr_frags]), XEN_NETIF_RSP_ERROR); } /* The head too, if necessary. */ if (start) xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR); return NULL; }