Re: [RFC 2/2] virtio-ring: Allocate indirect buffers from cache when possible

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 18/06/2012 16:09, Sasha Levin wrote:
Currently if VIRTIO_RING_F_INDIRECT_DESC is enabled we will
use indirect descriptors and allocate them using a simple
kmalloc().

This patch adds a cache which will allow indirect buffers under
a configurable size to be allocated from that cache instead.

Signed-off-by: Sasha Levin<levinsasha928@xxxxxxxxx>
---
  drivers/block/virtio_blk.c          |    4 ++++
  drivers/char/hw_random/virtio-rng.c |    4 ++++
  drivers/char/virtio_console.c       |    4 ++++
  drivers/net/virtio_net.c            |    4 ++++
  drivers/virtio/virtio_balloon.c     |    4 ++++
  drivers/virtio/virtio_ring.c        |   28 ++++++++++++++++++++++++----
  include/linux/virtio.h              |    1 +
  net/9p/trans_virtio.c               |    5 +++++
  8 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index a2c8d97..3c6d1bd 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -22,6 +22,9 @@ struct workqueue_struct *virtblk_wq;
  static unsigned int indirect_thresh = 0;
  module_param(indirect_thresh, uint, S_IRUGO);

+static unsigned int indirect_alloc_thresh = 0;
+module_param(indirect_alloc_thresh, uint, S_IRUGO);
+
  struct virtio_blk
  {
  	spinlock_t lock;
@@ -442,6 +445,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
  	INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
  	vblk->config_enable = true;
  	vdev->indirect_thresh = indirect_thresh;
+	vdev->indirect_alloc_thresh = indirect_alloc_thresh;

  	err = init_vq(vblk);
  	if (err)
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index bcaddb9..6a32f76 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -28,6 +28,9 @@
  static unsigned int indirect_thresh = 0;
  module_param(indirect_thresh, uint, S_IRUGO);

+static unsigned int indirect_alloc_thresh = 0;
+module_param(indirect_alloc_thresh, uint, S_IRUGO);
+
  static struct virtqueue *vq;
  static unsigned int data_avail;
  static DECLARE_COMPLETION(have_data);
@@ -94,6 +97,7 @@ static int virtrng_probe(struct virtio_device *vdev)

  	/* We expect a single virtqueue. */
  	vdev->indirect_thresh = indirect_thresh;
+	vdev->indirect_alloc_thresh = indirect_alloc_thresh;
  	vq = virtio_find_single_vq(vdev, random_recv_done, "input");
  	if (IS_ERR(vq))
  		return PTR_ERR(vq);
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 60397a4..7c33714 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -40,6 +40,9 @@
  static unsigned int indirect_thresh = 0;
  module_param(indirect_thresh, uint, S_IRUGO);

+static unsigned int indirect_alloc_thresh = 0;
+module_param(indirect_alloc_thresh, uint, S_IRUGO);
+
  /*
   * This is a global struct for storing common data for all the devices
   * this driver handles.
@@ -1733,6 +1736,7 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
  			&portdev->config.max_nr_ports) == 0)
  		multiport = true;
  	vdev->indirect_thresh = indirect_thresh;
+	vdev->indirect_alloc_thresh = indirect_alloc_thresh;

  	err = init_vqs(portdev);
  	if (err<  0) {
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 5c1be92..441bd2f 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -37,6 +37,9 @@ module_param(gso, bool, 0444);
  static unsigned int indirect_thresh = 0;
  module_param(indirect_thresh, uint, S_IRUGO);

+static unsigned int indirect_alloc_thresh = 0;
+module_param(indirect_alloc_thresh, uint, S_IRUGO);
+
  /* FIXME: MTU in config. */
  #define MAX_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
  #define GOOD_COPY_LEN	128
@@ -1132,6 +1135,7 @@ static int virtnet_probe(struct virtio_device *vdev)
  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
  		vi->mergeable_rx_bufs = true;
  	vdev->indirect_thresh = indirect_thresh;
+	vdev->indirect_alloc_thresh = indirect_alloc_thresh;

  	err = init_vqs(vi);
  	if (err)
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 4fc11ba..6e6313b 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -38,6 +38,9 @@
  static unsigned int indirect_thresh = 0;
  module_param(indirect_thresh, uint, S_IRUGO);

+static unsigned int indirect_alloc_thresh = 0;
+module_param(indirect_alloc_thresh, uint, S_IRUGO);
+
  struct virtio_balloon
  {
  	struct virtio_device *vdev;
@@ -364,6 +367,7 @@ static int virtballoon_probe(struct virtio_device *vdev)
  	vb->vdev = vdev;
  	vb->need_stats_update = 0;
  	vdev->indirect_thresh = indirect_thresh;
+	vdev->indirect_alloc_thresh = indirect_alloc_thresh;

  	err = init_vqs(vb);
  	if (err)
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 99a64a7..f0b0ce3 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -93,6 +93,10 @@ struct vring_virtqueue
  	 */
  	unsigned int indirect_thresh;

+	/* Buffers below this size will be allocated from cache */
+	unsigned int indirect_alloc_thresh;
+	struct kmem_cache *indirect_cache;
+
  	/* Host publishes avail event idx */
  	bool event;

@@ -135,7 +139,10 @@ static int vring_add_indirect(struct vring_virtqueue *vq,
  	unsigned head;
  	int i;

-	desc = kmalloc((out + in) * sizeof(struct vring_desc), gfp);
+	if ((out + in)<= vq->indirect_alloc_thresh)
+		desc = kmem_cache_alloc(vq->indirect_cache, gfp);
+	else
+		desc = kmalloc((out + in) * sizeof(struct vring_desc), gfp);
  	if (!desc)
  		return -ENOMEM;

@@ -384,8 +391,13 @@ static void detach_buf(struct vring_virtqueue *vq, unsigned int head)
  	i = head;

  	/* Free the indirect table */
-	if (vq->vring.desc[i].flags&  VRING_DESC_F_INDIRECT)
-		kfree(phys_to_virt(vq->vring.desc[i].addr));
+	if (vq->vring.desc[i].flags&  VRING_DESC_F_INDIRECT) {
+		if (vq->vring.desc[i].len<  vq->indirect_alloc_thresh)
This should be > instead of <,  no?


+			kfree(phys_to_virt(vq->vring.desc[i].addr));
+		else
+			kmem_cache_free(vq->indirect_cache,
+					phys_to_virt(vq->vring.desc[i].addr));
+	}



  	while (vq->vring.desc[i].flags&  VRING_DESC_F_NEXT) {
  		i = vq->vring.desc[i].next;
@@ -654,14 +666,20 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
  	vq->last_used_idx = 0;
  	vq->num_added = 0;
  	vq->indirect_thresh = 0;
+	vq->indirect_alloc_thresh = 0;
+	vq->indirect_cache = NULL;
  	list_add_tail(&vq->vq.list,&vdev->vqs);
  #ifdef DEBUG
  	vq->in_use = false;
  	vq->last_add_time_valid = false;
  #endif

-	if (virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC))
+	if (virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC)) {
  		vq->indirect_thresh = vdev->indirect_thresh;
+		vq->indirect_alloc_thresh = vdev->indirect_alloc_thresh;
+		if (vq->indirect_alloc_thresh)
+			vq->indirect_cache = KMEM_CACHE(vring_desc[vq->indirect_alloc_thresh], 0);
+	}

  	vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);

@@ -685,6 +703,8 @@ EXPORT_SYMBOL_GPL(vring_new_virtqueue);
  void vring_del_virtqueue(struct virtqueue *vq)
  {
  	list_del(&vq->list);
+	if (to_vvq(vq)->indirect_cache)
+		kmem_cache_destroy(to_vvq(vq)->indirect_cache);
  	kfree(to_vvq(vq));
  }
  EXPORT_SYMBOL_GPL(vring_del_virtqueue);
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index 36019ec..f3f0d3f 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -70,6 +70,7 @@ struct virtio_device {
  	unsigned long features[1];
  	void *priv;
  	unsigned int indirect_thresh;
+	unsigned int indirect_alloc_thresh;
  };

  #define dev_to_virtio(dev) container_of(dev, struct virtio_device, dev)
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index 357bfba..8424b36 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -55,6 +55,9 @@
  static unsigned int indirect_thresh = 0;
  module_param(indirect_thresh, uint, S_IRUGO);

+static unsigned int indirect_alloc_thresh = 0;
+module_param(indirect_alloc_thresh, uint, S_IRUGO);
+
  /* a single mutex to manage channel initialization and attachment */
  static DEFINE_MUTEX(virtio_9p_lock);
  static DECLARE_WAIT_QUEUE_HEAD(vp_wq);
@@ -505,6 +508,8 @@ static int p9_virtio_probe(struct virtio_device *vdev)

  	/* We expect one virtqueue, for requests. */
  	vdev->indirect_thresh = indirect_thresh;
+	vdev->indirect_alloc_thresh = indirect_alloc_thresh;
+
  	chan->vq = virtio_find_single_vq(vdev, req_done, "requests");
  	if (IS_ERR(chan->vq)) {
  		err = PTR_ERR(chan->vq);
Jean-Mickael
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux