The max number of hardware queues for xen/blkfront is num_online_cpus() or set
by module parameter, while the number xen/blkback supported is notified through
xenstore("multi-queue-max-queues").
The negotiated number was the smaller one, and was written back to
xen/blkback as "multi-queue-num-queues".

Signed-off-by: Bob Liu <bob....@oracle.com>
---
 drivers/block/xen-blkfront.c | 71 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 66 insertions(+), 5 deletions(-)

diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index d551be0..32caf85 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -99,6 +99,10 @@ static unsigned int xen_blkif_max_segments = 32;
 module_param_named(max, xen_blkif_max_segments, int, S_IRUGO);
 MODULE_PARM_DESC(max, "Maximum amount of segments in indirect requests 
(default is 32)");
 
+static unsigned int xenblkif_max_queues;
+module_param_named(max_queues, xenblkif_max_queues, uint, 0644);
+MODULE_PARM_DESC(max_queues, "Maximum number of hardware queues per virtual 
disk");
+
 #define BLK_RING_SIZE __CONST_RING_SIZE(blkif, PAGE_SIZE)
 
 /*
@@ -677,7 +681,7 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 
sector_size,
 
        memset(&info->tag_set, 0, sizeof(info->tag_set));
        info->tag_set.ops = &blkfront_mq_ops;
-       info->tag_set.nr_hw_queues = 1;
+       info->tag_set.nr_hw_queues = info->nr_rings;
        info->tag_set.queue_depth =  BLK_RING_SIZE;
        info->tag_set.numa_node = NUMA_NO_NODE;
        info->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE;
@@ -1338,6 +1342,8 @@ static int talk_to_blkback(struct xenbus_device *dev,
        struct xenbus_transaction xbt;
        int err, i;
        struct blkfront_ring_info *rinfo;
+       char *path;
+       size_t pathsize;
 
        for (i = 0; i < info->nr_rings; i++) {
                rinfo = &info->rinfo[i];
@@ -1354,6 +1360,13 @@ again:
                goto out;
        }
 
+       /* Write the number of queues */
+       err = xenbus_printf(xbt, dev->nodename, "multi-queue-num-queues", "%u", 
info->nr_rings);
+       if (err) {
+               message = "writing multi-queue-num-queues";
+               goto abort_transaction;
+       }
+
        if (info->nr_rings == 1) {
                rinfo = &info->rinfo[0];
                err = xenbus_printf(xbt, dev->nodename,
@@ -1369,8 +1382,33 @@ again:
                        goto abort_transaction;
                }
        } else {
-               /* Not supported at this stage */
-               goto abort_transaction;
+               pathsize = strlen(dev->nodename) + 12;
+               path = kzalloc(pathsize, GFP_KERNEL);
+               if (!path) {
+                       err = -ENOMEM;
+                       message = "ENOMEM while writing ring references";
+                       goto abort_transaction;
+               }
+               for (i = 0; i < info->nr_rings; i++) {
+                       memset(path, 0, pathsize);
+                       snprintf(path, pathsize, "%s/queue-%u", dev->nodename, 
i);
+
+                       err = xenbus_printf(xbt, path,
+                                       "ring-ref", "%u", 
info->rinfo[i].ring_ref);
+                       if (err) {
+                               message = "writing ring-ref";
+                               kfree(path);
+                               goto abort_transaction;
+                       }
+                       err = xenbus_printf(xbt, path,
+                                       "event-channel", "%u", 
info->rinfo[i].evtchn);
+                       if (err) {
+                               message = "writing event-channel";
+                               kfree(path);
+                               goto abort_transaction;
+                       }
+               }
+               kfree(path);
        }
        err = xenbus_printf(xbt, dev->nodename, "protocol", "%s",
                            XEN_IO_PROTO_ABI_NATIVE);
@@ -1420,6 +1458,7 @@ static int blkfront_probe(struct xenbus_device *dev,
        int err, vdevice, i, rindex;
        struct blkfront_info *info;
        struct blkfront_ring_info *rinfo;
+       unsigned int max_queues = 0;
 
        /* FIXME: Use dynamic device id if this is not set. */
        err = xenbus_scanf(XBT_NIL, dev->nodename,
@@ -1473,7 +1512,14 @@ static int blkfront_probe(struct xenbus_device *dev,
        info->vdevice = vdevice;
        info->connected = BLKIF_STATE_DISCONNECTED;
 
-       info->nr_rings = 1;
+       /* Check if backend supports multiple queues */
+       err = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+                          "multi-queue-max-queues", "%u", &max_queues);
+       if (err < 0)
+               max_queues = 1;
+
+       info->nr_rings = min(max_queues, xenblkif_max_queues);
+       printk("xen/blkfront probe info->nr_rings:%d, backend support:%d\n", 
info->nr_rings, max_queues);
        info->rinfo = kzalloc(sizeof(*rinfo) * info->nr_rings, GFP_KERNEL);
        if (!info->rinfo) {
                xenbus_dev_fatal(dev, -ENOMEM, "allocating ring_info 
structure");
@@ -1654,12 +1700,24 @@ static int blkif_recover(struct blkfront_info *info)
 static int blkfront_resume(struct xenbus_device *dev)
 {
        struct blkfront_info *info = dev_get_drvdata(&dev->dev);
-       int err;
+       int err = 0;
+       unsigned int max_queues = 0;
 
        dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
 
        blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
 
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                       "multi-queue-max-queues", "%u", &max_queues, NULL);
+       if (err)
+               max_queues = 1;
+
+       if (info->nr_rings != min(max_queues, xenblkif_max_queues)) {
+               /* At this stage, not support resume to a different hardware 
queue
+                * number */
+               return -1;
+       }
+
        err = talk_to_blkback(dev, info);
 
        /*
@@ -2165,6 +2223,9 @@ static int __init xlblk_init(void)
                return -ENODEV;
        }
 
+       /* Allow as many queues as there are CPUs, by default */
+       xenblkif_max_queues = num_online_cpus();
+
        ret = xenbus_register_frontend(&blkfront_driver);
        if (ret) {
                unregister_blkdev(XENVBD_MAJOR, DEV_NAME);
-- 
1.8.3.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

Reply via email to