Commit 4500fc0e authored by Zoltan Kiss's avatar Zoltan Kiss Committed by Greg Kroah-Hartman

xen-netback: Fix releasing header slot on error path

[ Upstream commit 1b860da0 ]

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: default avatarZoltan Kiss <zoltan.kiss@citrix.com>
Reported-by: default avatarArmin 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: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 50b77105
......@@ -1016,6 +1016,8 @@ static int xenvif_tx_check_gop(struct xenvif *vif,
*/
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. */
......@@ -1028,7 +1030,10 @@ static int xenvif_tx_check_gop(struct xenvif *vif,
(*gopp_copy)->status,
pending_idx,
(*gopp_copy)->source.u.ref);
xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR);
/* The first frag might still have this slot mapped */
if (!sharedslot)
xenvif_idx_release(vif, pending_idx,
XEN_NETIF_RSP_ERROR);
}
check_frags:
......@@ -1045,8 +1050,19 @@ static int xenvif_tx_check_gop(struct xenvif *vif,
pending_idx,
gop_map->handle);
/* Had a previous error? Invalidate this fragment. */
if (unlikely(err))
if (unlikely(err)) {
xenvif_idx_unmap(vif, 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(vif, pending_idx,
XEN_NETIF_RSP_ERROR);
else
xenvif_idx_release(vif, pending_idx,
XEN_NETIF_RSP_OKAY);
}
continue;
}
......@@ -1058,15 +1074,27 @@ static int xenvif_tx_check_gop(struct xenvif *vif,
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. */
/* First error: if the header haven't shared a slot with the
* first frag, release it as well.
*/
if (!sharedslot)
xenvif_idx_release(vif,
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(vif, pending_idx);
xenvif_idx_release(vif, pending_idx,
XEN_NETIF_RSP_OKAY);
}
/* And if we found the error while checking the frag_list, unmap
......@@ -1076,6 +1104,8 @@ static int xenvif_tx_check_gop(struct xenvif *vif,
for (j = 0; j < first_shinfo->nr_frags; j++) {
pending_idx = frag_get_pending_idx(&first_shinfo->frags[j]);
xenvif_idx_unmap(vif, pending_idx);
xenvif_idx_release(vif, pending_idx,
XEN_NETIF_RSP_OKAY);
}
}
......@@ -1811,8 +1841,6 @@ void xenvif_idx_unmap(struct xenvif *vif, u16 pending_idx)
tx_unmap_op.status);
BUG();
}
xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
}
static inline int rx_work_todo(struct xenvif *vif)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment