]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge branch 'vhost-net-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mst...
authorDavid S. Miller <davem@davemloft.net>
Wed, 6 Oct 2010 20:07:22 +0000 (13:07 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 6 Oct 2010 20:07:22 +0000 (13:07 -0700)
drivers/vhost/net.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h

index 7c8008225ee3a47ebef2cecaf005c0631fa93da1..72ab71fdf05339e311c14d4004f122ed0ef3828e 100644 (file)
@@ -243,7 +243,7 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
        int r, nlogs = 0;
 
        while (datalen > 0) {
-               if (unlikely(seg >= VHOST_NET_MAX_SG)) {
+               if (unlikely(seg >= UIO_MAXIOV)) {
                        r = -ENOBUFS;
                        goto err;
                }
index dd3d6f7406f80092cdd8843acdd06c313e9cf164..344019774ddde5dde56a3ccb43868084fc386eb6 100644 (file)
@@ -212,6 +212,45 @@ static int vhost_worker(void *data)
        }
 }
 
+/* Helper to allocate iovec buffers for all vqs. */
+static long vhost_dev_alloc_iovecs(struct vhost_dev *dev)
+{
+       int i;
+       for (i = 0; i < dev->nvqs; ++i) {
+               dev->vqs[i].indirect = kmalloc(sizeof *dev->vqs[i].indirect *
+                                              UIO_MAXIOV, GFP_KERNEL);
+               dev->vqs[i].log = kmalloc(sizeof *dev->vqs[i].log * UIO_MAXIOV,
+                                         GFP_KERNEL);
+               dev->vqs[i].heads = kmalloc(sizeof *dev->vqs[i].heads *
+                                           UIO_MAXIOV, GFP_KERNEL);
+
+               if (!dev->vqs[i].indirect || !dev->vqs[i].log ||
+                       !dev->vqs[i].heads)
+                       goto err_nomem;
+       }
+       return 0;
+err_nomem:
+       for (; i >= 0; --i) {
+               kfree(dev->vqs[i].indirect);
+               kfree(dev->vqs[i].log);
+               kfree(dev->vqs[i].heads);
+       }
+       return -ENOMEM;
+}
+
+static void vhost_dev_free_iovecs(struct vhost_dev *dev)
+{
+       int i;
+       for (i = 0; i < dev->nvqs; ++i) {
+               kfree(dev->vqs[i].indirect);
+               dev->vqs[i].indirect = NULL;
+               kfree(dev->vqs[i].log);
+               dev->vqs[i].log = NULL;
+               kfree(dev->vqs[i].heads);
+               dev->vqs[i].heads = NULL;
+       }
+}
+
 long vhost_dev_init(struct vhost_dev *dev,
                    struct vhost_virtqueue *vqs, int nvqs)
 {
@@ -229,6 +268,9 @@ long vhost_dev_init(struct vhost_dev *dev,
        dev->worker = NULL;
 
        for (i = 0; i < dev->nvqs; ++i) {
+               dev->vqs[i].log = NULL;
+               dev->vqs[i].indirect = NULL;
+               dev->vqs[i].heads = NULL;
                dev->vqs[i].dev = dev;
                mutex_init(&dev->vqs[i].mutex);
                vhost_vq_reset(dev, dev->vqs + i);
@@ -295,6 +337,10 @@ static long vhost_dev_set_owner(struct vhost_dev *dev)
        if (err)
                goto err_cgroup;
 
+       err = vhost_dev_alloc_iovecs(dev);
+       if (err)
+               goto err_cgroup;
+
        return 0;
 err_cgroup:
        kthread_stop(worker);
@@ -345,6 +391,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
                        fput(dev->vqs[i].call);
                vhost_vq_reset(dev, dev->vqs + i);
        }
+       vhost_dev_free_iovecs(dev);
        if (dev->log_ctx)
                eventfd_ctx_put(dev->log_ctx);
        dev->log_ctx = NULL;
@@ -947,7 +994,7 @@ static int get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq,
        }
 
        ret = translate_desc(dev, indirect->addr, indirect->len, vq->indirect,
-                            ARRAY_SIZE(vq->indirect));
+                            UIO_MAXIOV);
        if (unlikely(ret < 0)) {
                vq_err(vq, "Translation failure %d in indirect.\n", ret);
                return ret;
index afd77295971ce3044117d0d6e5ea8f4e20f655fe..edc892989992bdfed2a9cd015b2593f2b28616b2 100644 (file)
 
 struct vhost_device;
 
-enum {
-       /* Enough place for all fragments, head, and virtio net header. */
-       VHOST_NET_MAX_SG = MAX_SKB_FRAGS + 2,
-};
-
 struct vhost_work;
 typedef void (*vhost_work_fn_t)(struct vhost_work *work);
 
@@ -93,12 +88,15 @@ struct vhost_virtqueue {
        bool log_used;
        u64 log_addr;
 
-       struct iovec indirect[VHOST_NET_MAX_SG];
-       struct iovec iov[VHOST_NET_MAX_SG];
-       struct iovec hdr[VHOST_NET_MAX_SG];
+       struct iovec iov[UIO_MAXIOV];
+       /* hdr is used to store the virtio header.
+        * Since each iovec has >= 1 byte length, we never need more than
+        * header length entries to store the header. */
+       struct iovec hdr[sizeof(struct virtio_net_hdr_mrg_rxbuf)];
+       struct iovec *indirect;
        size_t vhost_hlen;
        size_t sock_hlen;
-       struct vring_used_elem heads[VHOST_NET_MAX_SG];
+       struct vring_used_elem *heads;
        /* We use a kind of RCU to access private pointer.
         * All readers access it from worker, which makes it possible to
         * flush the vhost_work instead of synchronize_rcu. Therefore readers do
@@ -109,7 +107,7 @@ struct vhost_virtqueue {
        void *private_data;
        /* Log write descriptors */
        void __user *log_base;
-       struct vhost_log log[VHOST_NET_MAX_SG];
+       struct vhost_log *log;
 };
 
 struct vhost_dev {