mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
[NET] front: Fix tx buffer leak in teardown path. Fix rx-buffer
cleanup: cannot free skbuffs until their memory is remapped by multicall. Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
1 parent
587411253f
commit
8da2f6c59c
1 file changed
+29
-14
@@ -1397,10 +1397,31 @@ err:
|
||||
return more_to_do;
|
||||
}
|
||||
|
||||
static void netif_release_tx_bufs(struct netfront_info *np)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= NET_TX_RING_SIZE; i++) {
|
||||
if ((unsigned long)np->tx_skbs[i] < PAGE_OFFSET)
|
||||
continue;
|
||||
|
||||
skb = np->tx_skbs[i];
|
||||
gnttab_end_foreign_access_ref(
|
||||
np->grant_tx_ref[i], GNTMAP_readonly);
|
||||
gnttab_release_grant_reference(
|
||||
&np->gref_tx_head, np->grant_tx_ref[i]);
|
||||
np->grant_tx_ref[i] = GRANT_INVALID_REF;
|
||||
add_id_to_freelist(np->tx_skbs, i);
|
||||
dev_kfree_skb_irq(skb);
|
||||
}
|
||||
}
|
||||
|
||||
static void netif_release_rx_bufs(struct netfront_info *np)
|
||||
{
|
||||
struct mmu_update *mmu = np->rx_mmu;
|
||||
struct multicall_entry *mcl = np->rx_mcl;
|
||||
struct sk_buff_head free_list;
|
||||
struct sk_buff *skb;
|
||||
unsigned long mfn;
|
||||
int xfer = 0, noxfer = 0, unused = 0;
|
||||
@@ -1411,6 +1432,8 @@ static void netif_release_rx_bufs(struct netfront_info *np)
|
||||
return;
|
||||
}
|
||||
|
||||
skb_queue_head_init(&free_list);
|
||||
|
||||
spin_lock(&np->rx_lock);
|
||||
|
||||
for (id = 0; id < NET_RX_RING_SIZE; id++) {
|
||||
@@ -1451,7 +1474,7 @@ static void netif_release_rx_bufs(struct netfront_info *np)
|
||||
|
||||
set_phys_to_machine(pfn, mfn);
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
__skb_queue_tail(&free_list, skb);
|
||||
xfer++;
|
||||
}
|
||||
|
||||
@@ -1474,6 +1497,9 @@ static void netif_release_rx_bufs(struct netfront_info *np)
|
||||
}
|
||||
}
|
||||
|
||||
while ((skb = __skb_dequeue(&free_list)) != NULL)
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
spin_unlock(&np->rx_lock);
|
||||
}
|
||||
|
||||
@@ -1573,19 +1599,7 @@ static void network_connect(struct net_device *dev)
|
||||
*/
|
||||
|
||||
/* Step 1: Discard all pending TX packet fragments. */
|
||||
for (requeue_idx = 0, i = 1; i <= NET_TX_RING_SIZE; i++) {
|
||||
if ((unsigned long)np->tx_skbs[i] < PAGE_OFFSET)
|
||||
continue;
|
||||
|
||||
skb = np->tx_skbs[i];
|
||||
gnttab_end_foreign_access_ref(
|
||||
np->grant_tx_ref[i], GNTMAP_readonly);
|
||||
gnttab_release_grant_reference(
|
||||
&np->gref_tx_head, np->grant_tx_ref[i]);
|
||||
np->grant_tx_ref[i] = GRANT_INVALID_REF;
|
||||
add_id_to_freelist(np->tx_skbs, i);
|
||||
dev_kfree_skb_irq(skb);
|
||||
}
|
||||
netif_release_tx_bufs(np);
|
||||
|
||||
/* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
|
||||
for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
|
||||
@@ -1632,6 +1646,7 @@ static void network_connect(struct net_device *dev)
|
||||
static void netif_uninit(struct net_device *dev)
|
||||
{
|
||||
struct netfront_info *np = netdev_priv(dev);
|
||||
netif_release_tx_bufs(np);
|
||||
netif_release_rx_bufs(np);
|
||||
gnttab_free_grant_references(np->gref_tx_head);
|
||||
gnttab_free_grant_references(np->gref_rx_head);
|
||||
|
||||