diff mbox

[V9fs-developer,net/9p] Introduce basic flow-control for VirtIO transport.

Message ID 1300488588-29965-1-git-send-email-jvrao@linux.vnet.ibm.com (mailing list archive)
State Accepted, archived
Delegated to: Eric Van Hensbergen
Headers show

Commit Message

jvrao March 18, 2011, 10:49 p.m. UTC
None
diff mbox

Patch

diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index c6e1ae2..8693d18 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -43,6 +43,7 @@ 
 #include <net/9p/client.h>
 #include <net/9p/transport.h>
 #include <linux/scatterlist.h>
+#include <linux/swap.h>
 #include <linux/virtio.h>
 #include <linux/virtio_9p.h>
 #include "trans_common.h"
@@ -51,6 +52,8 @@ 
 
 /* a single mutex to manage channel initialization and attachment */
 static DEFINE_MUTEX(virtio_9p_lock);
+static DECLARE_WAIT_QUEUE_HEAD(vp_wq);
+static atomic_t vp_pinned = ATOMIC_INIT(0);
 
 /**
  * struct virtio_chan - per-instance transport information
@@ -78,7 +81,10 @@  struct virtio_chan {
 	struct virtqueue *vq;
 	int ring_bufs_avail;
 	wait_queue_head_t *vc_wq;
-
+	/* This is global limit. Since we don't have a global structure,
+	 * will be placing it in each channel.
+	 */
+	int p9_max_pages;
 	/* Scatterlist: can be too big for stack. */
 	struct scatterlist sg[VIRTQUEUE_NUM];
 
@@ -159,8 +165,11 @@  static void req_done(struct virtqueue *vq)
 		req = p9_tag_lookup(chan->client, rc->tag);
 		if (req->tc->private) {
 			struct trans_rpage_info *rp = req->tc->private;
+			int p = rp->rp_nr_pages;
 			/*Release pages */
 			p9_release_req_pages(rp);
+			atomic_sub(p, &vp_pinned);
+			wake_up(&vp_wq);
 			if (rp->rp_alloc)
 				kfree(rp);
 			req->tc->private = NULL;
@@ -269,6 +278,14 @@  p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
 		int rpinfo_size = sizeof(struct trans_rpage_info) +
 			sizeof(struct page *) * nr_pages;
 
+		if (atomic_read(&vp_pinned) >= chan->p9_max_pages) {
+			err = wait_event_interruptible(vp_wq,
+				atomic_read(&vp_pinned) < chan->p9_max_pages);
+			if (err  == -ERESTARTSYS)
+				return err;
+			P9_DPRINTK(P9_DEBUG_TRANS, "9p: May gup pages now.\n");
+		}
+
 		if (rpinfo_size <= (req->tc->capacity - req->tc->size)) {
 			/* We can use sdata */
 			req->tc->private = req->tc->sdata + req->tc->size;
@@ -291,6 +308,8 @@  p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
 			if (rpinfo->rp_alloc)
 				kfree(rpinfo);
 			return err;
+		} else {
+			atomic_add(rpinfo->rp_nr_pages, &vp_pinned);
 		}
 	}
 
@@ -452,6 +471,8 @@  static int p9_virtio_probe(struct virtio_device *vdev)
 	}
 	init_waitqueue_head(chan->vc_wq);
 	chan->ring_bufs_avail = 1;
+	/* Ceiling limit to avoid denial of service attacks */
+	chan->p9_max_pages = nr_free_pagecache_pages()/4;
 
 	mutex_lock(&virtio_9p_lock);
 	list_add_tail(&chan->chan_list, &virtio_chan_list);