diff options
| -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 | } |
