rpms/kernel/F-11 linux-2.6-virtio-net-refill-on-out-of-memory.patch, NONE, 1.1 kernel.spec, 1.1748, 1.1749

Justin M. Forbes jforbes at fedoraproject.org
Fri Oct 2 18:58:55 UTC 2009


Author: jforbes

Update of /cvs/pkgs/rpms/kernel/F-11
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv20473

Modified Files:
	kernel.spec 
Added Files:
	linux-2.6-virtio-net-refill-on-out-of-memory.patch 
Log Message:
Add linux-2.6-virtio-net-refill-on-out-of-memory.patch, from 2.6.31 to prevent page allocation failures in guests. (#520119)

linux-2.6-virtio-net-refill-on-out-of-memory.patch:
 virtio_net.c |   62 +++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 46 insertions(+), 16 deletions(-)

--- NEW FILE linux-2.6-virtio-net-refill-on-out-of-memory.patch ---
>From a4ffb0ecbdab9ee46027f457d78b697f425c262e Mon Sep 17 00:00:00 2001
From: Rusty Russell <rusty at rustcorp.com.au>
Date: Wed, 26 Aug 2009 12:22:32 -0700
Subject: [PATCH] virtio: net refill on out-of-memory

If we run out of memory, use keventd to fill the buffer.  There's a
report of this happening: "Page allocation failures in guest",
Message-ID: <20090713115158.0a4892b0 at mjolnir.ossman.eu>

(cherry picked from commit 3161e453e496eb5643faad30fff5a5ab183da0fe)

Signed-off-by: Rusty Russell <rusty at rustcorp.com.au>
Signed-off-by: David S. Miller <davem at davemloft.net>
Signed-off-by: Mark McLoughlin <markmc at redhat.com>
---
 drivers/net/virtio_net.c |   61 ++++++++++++++++++++++++++++++++++-----------
 1 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 4d1d479..6f5cabe 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -70,6 +70,9 @@ struct virtnet_info
 	struct sk_buff_head recv;
 	struct sk_buff_head send;
 
+	/* Work struct for refilling if we run low on memory. */
+	struct delayed_work refill;
+
 	/* Chain pages by the private ptr. */
 	struct page *pages;
 };
@@ -273,19 +276,22 @@ drop:
 	dev_kfree_skb(skb);
 }
 
-static void try_fill_recv_maxbufs(struct virtnet_info *vi)
+static bool try_fill_recv_maxbufs(struct virtnet_info *vi, gfp_t gfp)
 {
 	struct sk_buff *skb;
 	struct scatterlist sg[2+MAX_SKB_FRAGS];
 	int num, err, i;
+	bool oom = false;
 
 	sg_init_table(sg, 2+MAX_SKB_FRAGS);
 	for (;;) {
 		struct virtio_net_hdr *hdr;
 
 		skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN);
-		if (unlikely(!skb))
+		if (unlikely(!skb)) {
+			oom = true;
 			break;
+		}
 
 		skb_put(skb, MAX_PACKET_LEN);
 
@@ -295,7 +301,7 @@ static void try_fill_recv_maxbufs(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 = get_a_page(vi, GFP_ATOMIC);
+				f->page = get_a_page(vi, gfp);
 				if (!f->page)
 					break;
 
@@ -324,31 +330,35 @@ static void try_fill_recv_maxbufs(struct virtnet_info *vi)
 	if (unlikely(vi->num > vi->max))
 		vi->max = vi->num;
 	vi->rvq->vq_ops->kick(vi->rvq);
+	return !oom;
 }
 
-static void try_fill_recv(struct virtnet_info *vi)
+/* Returns false if we couldn't fill entirely (OOM). */
+static bool try_fill_recv(struct virtnet_info *vi, gfp_t gfp)
 {
 	struct sk_buff *skb;
 	struct scatterlist sg[1];
 	int err;
+	bool oom = false;
 
-	if (!vi->mergeable_rx_bufs) {
-		try_fill_recv_maxbufs(vi);
-		return;
-	}
+	if (!vi->mergeable_rx_bufs)
+		return try_fill_recv_maxbufs(vi, gfp);
 
 	for (;;) {
 		skb_frag_t *f;
 
 		skb = netdev_alloc_skb(vi->dev, GOOD_COPY_LEN + NET_IP_ALIGN);
-		if (unlikely(!skb))
+		if (unlikely(!skb)) {
+			oom = true;
 			break;
+		}
 
 		skb_reserve(skb, NET_IP_ALIGN);
 
 		f = &skb_shinfo(skb)->frags[0];
-		f->page = get_a_page(vi, GFP_ATOMIC);
+		f->page = get_a_page(vi, gfp);
 		if (!f->page) {
+			oom = true;
 			kfree_skb(skb);
 			break;
 		}
@@ -372,6 +382,7 @@ static void try_fill_recv(struct virtnet_info *vi)
 	if (unlikely(vi->num > vi->max))
 		vi->max = vi->num;
 	vi->rvq->vq_ops->kick(vi->rvq);
+	return !oom;
 }
 
 static void skb_recv_done(struct virtqueue *rvq)
@@ -384,6 +395,23 @@ static void skb_recv_done(struct virtqueue *rvq)
 	}
 }
 
+static void refill_work(struct work_struct *work)
+{
+	struct virtnet_info *vi;
+	bool still_empty;
+
+	vi = container_of(work, struct virtnet_info, refill.work);
+	napi_disable(&vi->napi);
+	try_fill_recv(vi, GFP_KERNEL);
+	still_empty = (vi->num == 0);
+	napi_enable(&vi->napi);
+
+	/* In theory, this can happen: if we don't get any buffers in
+	 * we will *never* try to fill again. */
+	if (still_empty)
+		schedule_delayed_work(&vi->refill, HZ/2);
+}
+
 static int virtnet_poll(struct napi_struct *napi, int budget)
 {
 	struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
@@ -399,10 +427,10 @@ again:
 		received++;
 	}
 
-	/* FIXME: If we oom and completely run out of inbufs, we need
-	 * to start a timer trying to fill more. */
-	if (vi->num < vi->max / 2)
-		try_fill_recv(vi);
+	if (vi->num < vi->max / 2) {
+		if (!try_fill_recv(vi, GFP_ATOMIC))
+			schedule_delayed_work(&vi->refill, 0);
+	}
 
 	/* Out of packets? */
 	if (received < budget) {
@@ -891,6 +919,7 @@ static int virtnet_probe(struct virtio_device *vdev)
 	vi->vdev = vdev;
 	vdev->priv = vi;
 	vi->pages = NULL;
+	INIT_DELAYED_WORK(&vi->refill, refill_work);
 
 	/* If they give us a callback when all buffers are done, we don't need
 	 * the timer. */
@@ -945,7 +974,7 @@ static int virtnet_probe(struct virtio_device *vdev)
 	}
 
 	/* Last of all, set up some receive buffers. */
-	try_fill_recv(vi);
+	try_fill_recv(vi, GFP_KERNEL);
 
 	/* If we didn't even get one input buffer, we're useless. */
 	if (vi->num == 0) {
@@ -962,6 +991,7 @@ static int virtnet_probe(struct virtio_device *vdev)
 
 unregister:
 	unregister_netdev(dev);
+	cancel_delayed_work_sync(&vi->refill);
 free_ctrl:
 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
 		vdev->config->del_vq(vi->cvq);
@@ -999,6 +1029,7 @@ static void virtnet_remove(struct virtio_device *vdev)
 	if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ))
 		vdev->config->del_vq(vi->cvq);
 	unregister_netdev(vi->dev);
+	cancel_delayed_work_sync(&vi->refill);
 
 	while (vi->pages)
 		__free_pages(get_a_page(vi, GFP_KERNEL), 0);
-- 
1.6.2.5



Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/F-11/kernel.spec,v
retrieving revision 1.1748
retrieving revision 1.1749
diff -u -p -r1.1748 -r1.1749
--- kernel.spec	28 Sep 2009 16:54:12 -0000	1.1748
+++ kernel.spec	2 Oct 2009 18:58:55 -0000	1.1749
@@ -657,6 +657,7 @@ Patch1000: linux-2.6-neigh_-fix-state-tr
 Patch1200: linux-2.6-xen-fix-brkpoints-hw-watchpoints.patch
 Patch1201: linux-2.6-xen-clean-up-warnings.patch
 Patch1202: linux-2.6-virtio_blk-revert-QUEUE_FLAG_VIRT-addition.patch
+Patch1203: linux-2.6-virtio-net-refill-on-out-of-memory.patch
 
 Patch1515: lirc-2.6.31.patch
 Patch1517: hid-ignore-all-recent-imon-devices.patch
@@ -1297,6 +1298,7 @@ ApplyPatch linux-2.6-xen-clean-up-warnin
 
 # Misc Virt
 ApplyPatch linux-2.6-virtio_blk-revert-QUEUE_FLAG_VIRT-addition.patch
+ApplyPatch linux-2.6-virtio-net-refill-on-out-of-memory.patch
 
 # Misc fixes
 # The input layer spews crap no-one cares about.
@@ -2026,6 +2028,10 @@ fi
 # and build.
 
 %changelog
+* Fri Oct  2 2009  Justin M. Forbes <jforbes at redhat.com>  2.6.30.8-70
+- Add linux-2.6-virtio-net-refill-on-out-of-memory.patch, from 2.6.31
+  to prevent page allocation failures in guests. (#520119)
+
 * Mon Sep 28 2009  Chuck Ebbert <cebbert at redhat.com>  2.6.30.8-69
 - Add linux-2.6-kvm-revert-x86-check-for-cr3-validity.patch, from
   2.6.32-rc, fixes bug #525743




More information about the fedora-extras-commits mailing list