Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 105764
b: refs/heads/master
c: fb6813f
h: refs/heads/master
v: v3
  • Loading branch information
Rusty Russell committed Jul 25, 2008
1 parent 57067a5 commit 48e68a6
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 97402b96f87c6e32f75f1bffdd91a5ee144b679d
refs/heads/master: fb6813f480806d62361719e84777c8e00d3e86a8
36 changes: 35 additions & 1 deletion trunk/drivers/net/virtio_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ struct virtnet_info
/* Receive & send queues. */
struct sk_buff_head recv;
struct sk_buff_head send;

/* Chain pages by the private ptr. */
struct page *pages;
};

static inline struct virtio_net_hdr *skb_vnet_hdr(struct sk_buff *skb)
Expand All @@ -73,6 +76,23 @@ static inline void vnet_hdr_to_sg(struct scatterlist *sg, struct sk_buff *skb)
sg_init_one(sg, skb_vnet_hdr(skb), sizeof(struct virtio_net_hdr));
}

static void give_a_page(struct virtnet_info *vi, struct page *page)
{
page->private = (unsigned long)vi->pages;
vi->pages = page;
}

static struct page *get_a_page(struct virtnet_info *vi, gfp_t gfp_mask)
{
struct page *p = vi->pages;

if (p)
vi->pages = (struct page *)p->private;
else
p = alloc_page(gfp_mask);
return p;
}

static void skb_xmit_done(struct virtqueue *svq)
{
struct virtnet_info *vi = svq->vdev->priv;
Expand Down Expand Up @@ -101,6 +121,15 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
}
len -= sizeof(struct virtio_net_hdr);

if (len <= MAX_PACKET_LEN) {
unsigned int i;

for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
give_a_page(dev->priv, skb_shinfo(skb)->frags[i].page);
skb->data_len = 0;
skb_shinfo(skb)->nr_frags = 0;
}

err = pskb_trim(skb, len);
if (err) {
pr_debug("%s: pskb_trim failed %i %d\n", dev->name, len, err);
Expand Down Expand Up @@ -183,7 +212,7 @@ static void try_fill_recv(struct virtnet_info *vi)
if (vi->big_packets) {
for (i = 0; i < MAX_SKB_FRAGS; i++) {
skb_frag_t *f = &skb_shinfo(skb)->frags[i];
f->page = alloc_page(GFP_ATOMIC);
f->page = get_a_page(vi, GFP_ATOMIC);
if (!f->page)
break;

Expand Down Expand Up @@ -506,6 +535,7 @@ static int virtnet_probe(struct virtio_device *vdev)
vi->dev = dev;
vi->vdev = vdev;
vdev->priv = vi;
vi->pages = NULL;

/* If they give us a callback when all buffers are done, we don't need
* the timer. */
Expand Down Expand Up @@ -591,6 +621,10 @@ static void virtnet_remove(struct virtio_device *vdev)
vdev->config->del_vq(vi->svq);
vdev->config->del_vq(vi->rvq);
unregister_netdev(vi->dev);

while (vi->pages)
__free_pages(get_a_page(vi, GFP_KERNEL), 0);

free_netdev(vi->dev);
}

Expand Down

0 comments on commit 48e68a6

Please sign in to comment.