Skip to content

Commit

Permalink
xen-netback: Fix releasing header slot on error path
Browse files Browse the repository at this point in the history
This patch makes this function aware that the first frag and the header might
share the same ring slot. That could happen if the first slot is bigger than
PKT_PROT_LEN. Due to this the error path might release that slot twice or never,
depending on the error scenario.
xenvif_idx_release is also removed from xenvif_idx_unmap, and called separately.

Signed-off-by: Zoltan Kiss <zoltan.kiss@citrix.com>
Reported-by: Armin Zentai <armin.zentai@ezit.hu>
Cc: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: xen-devel@lists.xenproject.org
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Zoltan Kiss authored and David S. Miller committed Jul 21, 2014
1 parent b42cc6e commit 1b860da
Showing 1 changed file with 33 additions and 5 deletions.
38 changes: 33 additions & 5 deletions drivers/net/xen-netback/netback.c
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,8 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue,
*/
struct skb_shared_info *first_shinfo = NULL;
int nr_frags = shinfo->nr_frags;
const bool sharedslot = nr_frags &&
frag_get_pending_idx(&shinfo->frags[0]) == pending_idx;
int i, err;

/* Check status of header. */
Expand All @@ -1051,7 +1053,10 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue,
(*gopp_copy)->status,
pending_idx,
(*gopp_copy)->source.u.ref);
xenvif_idx_release(queue, pending_idx, XEN_NETIF_RSP_ERROR);
/* The first frag might still have this slot mapped */
if (!sharedslot)
xenvif_idx_release(queue, pending_idx,
XEN_NETIF_RSP_ERROR);
}

check_frags:
Expand All @@ -1068,8 +1073,19 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue,
pending_idx,
gop_map->handle);
/* Had a previous error? Invalidate this fragment. */
if (unlikely(err))
if (unlikely(err)) {
xenvif_idx_unmap(queue, pending_idx);
/* If the mapping of the first frag was OK, but
* the header's copy failed, and they are
* sharing a slot, send an error
*/
if (i == 0 && sharedslot)
xenvif_idx_release(queue, pending_idx,
XEN_NETIF_RSP_ERROR);
else
xenvif_idx_release(queue, pending_idx,
XEN_NETIF_RSP_OKAY);
}
continue;
}

Expand All @@ -1081,15 +1097,27 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue,
gop_map->status,
pending_idx,
gop_map->ref);

xenvif_idx_release(queue, pending_idx, XEN_NETIF_RSP_ERROR);

/* Not the first error? Preceding frags already invalidated. */
if (err)
continue;
/* First error: invalidate preceding fragments. */

/* First error: if the header haven't shared a slot with the
* first frag, release it as well.
*/
if (!sharedslot)
xenvif_idx_release(queue,
XENVIF_TX_CB(skb)->pending_idx,
XEN_NETIF_RSP_OKAY);

/* Invalidate preceding fragments of this skb. */
for (j = 0; j < i; j++) {
pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
xenvif_idx_unmap(queue, pending_idx);
xenvif_idx_release(queue, pending_idx,
XEN_NETIF_RSP_OKAY);
}

/* And if we found the error while checking the frag_list, unmap
Expand All @@ -1099,6 +1127,8 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue,
for (j = 0; j < first_shinfo->nr_frags; j++) {
pending_idx = frag_get_pending_idx(&first_shinfo->frags[j]);
xenvif_idx_unmap(queue, pending_idx);
xenvif_idx_release(queue, pending_idx,
XEN_NETIF_RSP_OKAY);
}
}

Expand Down Expand Up @@ -1834,8 +1864,6 @@ void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx)
tx_unmap_op.status);
BUG();
}

xenvif_idx_release(queue, pending_idx, XEN_NETIF_RSP_OKAY);
}

static inline int rx_work_todo(struct xenvif_queue *queue)
Expand Down

0 comments on commit 1b860da

Please sign in to comment.