mirror of https://gitee.com/openkylin/linux.git
xen-netfront: do not use ~0U as error return value for xennet_fill_frags()
xennet_fill_frags() uses ~0U as return value when the sk_buff is not able to cache extra fragments. This is incorrect because the return type of xennet_fill_frags() is RING_IDX and 0xffffffff is an expected value for ring buffer index. In the situation when the rsp_cons is approaching 0xffffffff, the return value of xennet_fill_frags() may become 0xffffffff which xennet_poll() (the caller) would regard as error. As a result, queue->rx.rsp_cons is set incorrectly because it is updated only when there is error. If there is no error, xennet_poll() would be responsible to update queue->rx.rsp_cons. Finally, queue->rx.rsp_cons would point to the rx ring buffer entries whose queue->rx_skbs[i] and queue->grant_rx_ref[i] are already cleared to NULL. This leads to NULL pointer access in the next iteration to process rx ring buffer entries. The symptom is similar to the one fixed in commit00b368502d
("xen-netfront: do not assume sk_buff_head list is empty in error handling"). This patch changes the return type of xennet_fill_frags() to indicate whether it is successful or failed. The queue->rx.rsp_cons will be always updated inside this function. Fixes:ad4f15dc2c
("xen/netfront: don't bug in case of too many frags") Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com> Reviewed-by: Juergen Gross <jgross@suse.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a3ce2a21bb
commit
a761129e36
|
@ -887,9 +887,9 @@ static int xennet_set_skb_gso(struct sk_buff *skb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static RING_IDX xennet_fill_frags(struct netfront_queue *queue,
|
||||
struct sk_buff *skb,
|
||||
struct sk_buff_head *list)
|
||||
static int xennet_fill_frags(struct netfront_queue *queue,
|
||||
struct sk_buff *skb,
|
||||
struct sk_buff_head *list)
|
||||
{
|
||||
RING_IDX cons = queue->rx.rsp_cons;
|
||||
struct sk_buff *nskb;
|
||||
|
@ -908,7 +908,7 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue,
|
|||
if (unlikely(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) {
|
||||
queue->rx.rsp_cons = ++cons + skb_queue_len(list);
|
||||
kfree_skb(nskb);
|
||||
return ~0U;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
|
||||
|
@ -919,7 +919,9 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue,
|
|||
kfree_skb(nskb);
|
||||
}
|
||||
|
||||
return cons;
|
||||
queue->rx.rsp_cons = cons;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
|
||||
|
@ -1045,8 +1047,7 @@ static int xennet_poll(struct napi_struct *napi, int budget)
|
|||
skb->data_len = rx->status;
|
||||
skb->len += rx->status;
|
||||
|
||||
i = xennet_fill_frags(queue, skb, &tmpq);
|
||||
if (unlikely(i == ~0U))
|
||||
if (unlikely(xennet_fill_frags(queue, skb, &tmpq)))
|
||||
goto err;
|
||||
|
||||
if (rx->flags & XEN_NETRXF_csum_blank)
|
||||
|
@ -1056,7 +1057,7 @@ static int xennet_poll(struct napi_struct *napi, int budget)
|
|||
|
||||
__skb_queue_tail(&rxq, skb);
|
||||
|
||||
queue->rx.rsp_cons = ++i;
|
||||
i = ++queue->rx.rsp_cons;
|
||||
work_done++;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue