diff options
author | Zoltan Kiss <zoltan.kiss@citrix.com> | 2014-07-18 14:08:02 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-20 23:56:05 -0400 |
commit | 1a998d3e6bc1e44f4c0bc7509bdedef8ed3845ec (patch) | |
tree | 343f6de6312d5fa186b808a800bff404a2047367 /drivers/net/xen-netback | |
parent | 7801db8aec957fa6610efe0ee26a6c8bc0f1d73b (diff) |
xen-netback: Fix handling frag_list on grant op error path
The error handling for skb's with frag_list was completely wrong, it caused
double unmap attempts to happen if the error was on the first skb. Move it to
the right place in the loop.
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>
Diffstat (limited to 'drivers/net/xen-netback')
-rw-r--r-- | drivers/net/xen-netback/netback.c | 37 |
1 files changed, 20 insertions, 17 deletions
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 1844a47636b6..a773f2016bad 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c | |||
@@ -1030,10 +1030,16 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue, | |||
1030 | { | 1030 | { |
1031 | struct gnttab_map_grant_ref *gop_map = *gopp_map; | 1031 | struct gnttab_map_grant_ref *gop_map = *gopp_map; |
1032 | u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx; | 1032 | u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx; |
1033 | /* This always points to the shinfo of the skb being checked, which | ||
1034 | * could be either the first or the one on the frag_list | ||
1035 | */ | ||
1033 | struct skb_shared_info *shinfo = skb_shinfo(skb); | 1036 | struct skb_shared_info *shinfo = skb_shinfo(skb); |
1037 | /* If this is non-NULL, we are currently checking the frag_list skb, and | ||
1038 | * this points to the shinfo of the first one | ||
1039 | */ | ||
1040 | struct skb_shared_info *first_shinfo = NULL; | ||
1034 | int nr_frags = shinfo->nr_frags; | 1041 | int nr_frags = shinfo->nr_frags; |
1035 | int i, err; | 1042 | int i, err; |
1036 | struct sk_buff *first_skb = NULL; | ||
1037 | 1043 | ||
1038 | /* Check status of header. */ | 1044 | /* Check status of header. */ |
1039 | err = (*gopp_copy)->status; | 1045 | err = (*gopp_copy)->status; |
@@ -1086,31 +1092,28 @@ check_frags: | |||
1086 | xenvif_idx_unmap(queue, pending_idx); | 1092 | xenvif_idx_unmap(queue, pending_idx); |
1087 | } | 1093 | } |
1088 | 1094 | ||
1095 | /* And if we found the error while checking the frag_list, unmap | ||
1096 | * the first skb's frags | ||
1097 | */ | ||
1098 | if (first_shinfo) { | ||
1099 | for (j = 0; j < first_shinfo->nr_frags; j++) { | ||
1100 | pending_idx = frag_get_pending_idx(&first_shinfo->frags[j]); | ||
1101 | xenvif_idx_unmap(queue, pending_idx); | ||
1102 | } | ||
1103 | } | ||
1104 | |||
1089 | /* Remember the error: invalidate all subsequent fragments. */ | 1105 | /* Remember the error: invalidate all subsequent fragments. */ |
1090 | err = newerr; | 1106 | err = newerr; |
1091 | } | 1107 | } |
1092 | 1108 | ||
1093 | if (skb_has_frag_list(skb)) { | 1109 | if (skb_has_frag_list(skb) && !first_shinfo) { |
1094 | first_skb = skb; | 1110 | first_shinfo = skb_shinfo(skb); |
1095 | skb = shinfo->frag_list; | 1111 | shinfo = skb_shinfo(skb_shinfo(skb)->frag_list); |
1096 | shinfo = skb_shinfo(skb); | ||
1097 | nr_frags = shinfo->nr_frags; | 1112 | nr_frags = shinfo->nr_frags; |
1098 | 1113 | ||
1099 | goto check_frags; | 1114 | goto check_frags; |
1100 | } | 1115 | } |
1101 | 1116 | ||
1102 | /* There was a mapping error in the frag_list skb. We have to unmap | ||
1103 | * the first skb's frags | ||
1104 | */ | ||
1105 | if (first_skb && err) { | ||
1106 | int j; | ||
1107 | shinfo = skb_shinfo(first_skb); | ||
1108 | for (j = 0; j < shinfo->nr_frags; j++) { | ||
1109 | pending_idx = frag_get_pending_idx(&shinfo->frags[j]); | ||
1110 | xenvif_idx_unmap(queue, pending_idx); | ||
1111 | } | ||
1112 | } | ||
1113 | |||
1114 | *gopp_map = gop_map; | 1117 | *gopp_map = gop_map; |
1115 | return err; | 1118 | return err; |
1116 | } | 1119 | } |