target: increase iblock task sizes
authorChristoph Hellwig <hch@infradead.org>
Wed, 21 Dec 2011 19:20:31 +0000 (14:20 -0500)
committerNicholas Bellinger <nab@linux-iscsi.org>
Sat, 25 Feb 2012 22:37:46 +0000 (14:37 -0800)
There is no real limit for task sizes in the iblock driver given that we
can chain bios.  Increase the maximum size to UINT_MAX, and change the
code to submit bios in a smaller batch size to avoid deadlocks when
having more bios in flight than the pool supports.  Also increase the
pool size to always allow multiple tasks to be in flight.

I also had to change the task refcounting to include one reference for
the submission task, which is a standard practice in this kind of code
in Linux (e.g. XFS I/O submission).  This was wrong before, but couldn't
be hit easily.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
drivers/target/target_core_iblock.c
drivers/target/target_core_iblock.h

index 562e787..2ec299e 100644 (file)
@@ -46,6 +46,9 @@
 
 #include "target_core_iblock.h"
 
+#define IBLOCK_MAX_BIO_PER_TASK         32     /* max # of bios to submit at a time */
+#define IBLOCK_BIO_POOL_SIZE   128
+
 static struct se_subsystem_api iblock_template;
 
 static void iblock_bio_done(struct bio *, int);
@@ -100,10 +103,8 @@ static struct se_device *iblock_create_virtdevice(
                return ERR_PTR(ret);
        }
        memset(&dev_limits, 0, sizeof(struct se_dev_limits));
-       /*
-        * These settings need to be made tunable..
-        */
-       ib_dev->ibd_bio_set = bioset_create(32, 0);
+
+       ib_dev->ibd_bio_set = bioset_create(IBLOCK_BIO_POOL_SIZE, 0);
        if (!ib_dev->ibd_bio_set) {
                pr_err("IBLOCK: Unable to create bioset()\n");
                return ERR_PTR(-ENOMEM);
@@ -129,8 +130,8 @@ static struct se_device *iblock_create_virtdevice(
        q = bdev_get_queue(bd);
        limits = &dev_limits.limits;
        limits->logical_block_size = bdev_logical_block_size(bd);
-       limits->max_hw_sectors = queue_max_hw_sectors(q);
-       limits->max_sectors = queue_max_sectors(q);
+       limits->max_hw_sectors = UINT_MAX;
+       limits->max_sectors = UINT_MAX;
        dev_limits.hw_queue_depth = q->nr_requests;
        dev_limits.queue_depth = q->nr_requests;
 
@@ -204,7 +205,7 @@ iblock_alloc_task(unsigned char *cdb)
                return NULL;
        }
 
-       atomic_set(&ib_req->ib_bio_cnt, 0);
+       atomic_set(&ib_req->pending, 1);
        return &ib_req->ib_task;
 }
 
@@ -484,24 +485,35 @@ iblock_get_bio(struct se_task *task, sector_t lba, u32 sg_num)
        bio->bi_destructor = iblock_bio_destructor;
        bio->bi_end_io = &iblock_bio_done;
        bio->bi_sector = lba;
-       atomic_inc(&ib_req->ib_bio_cnt);
+       atomic_inc(&ib_req->pending);
 
        pr_debug("Set bio->bi_sector: %llu\n", (unsigned long long)bio->bi_sector);
-       pr_debug("Set ib_req->ib_bio_cnt: %d\n",
-                       atomic_read(&ib_req->ib_bio_cnt));
+       pr_debug("Set ib_req->pending: %d\n", atomic_read(&ib_req->pending));
        return bio;
 }
 
+static void iblock_submit_bios(struct bio_list *list, int rw)
+{
+       struct blk_plug plug;
+       struct bio *bio;
+
+       blk_start_plug(&plug);
+       while ((bio = bio_list_pop(list)))
+               submit_bio(rw, bio);
+       blk_finish_plug(&plug);
+}
+
 static int iblock_do_task(struct se_task *task)
 {
        struct se_cmd *cmd = task->task_se_cmd;
        struct se_device *dev = cmd->se_dev;
+       struct iblock_req *ibr = IBLOCK_REQ(task);
        struct bio *bio;
        struct bio_list list;
        struct scatterlist *sg;
        u32 i, sg_num = task->task_sg_nents;
        sector_t block_lba;
-       struct blk_plug plug;
+       unsigned bio_cnt;
        int rw;
 
        if (task->task_data_direction == DMA_TO_DEVICE) {
@@ -546,6 +558,7 @@ static int iblock_do_task(struct se_task *task)
 
        bio_list_init(&list);
        bio_list_add(&list, bio);
+       bio_cnt = 1;
 
        for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
                /*
@@ -555,10 +568,16 @@ static int iblock_do_task(struct se_task *task)
                 */
                while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset)
                                != sg->length) {
+                       if (bio_cnt >= IBLOCK_MAX_BIO_PER_TASK) {
+                               iblock_submit_bios(&list, rw);
+                               bio_cnt = 0;
+                       }
+
                        bio = iblock_get_bio(task, block_lba, sg_num);
                        if (!bio)
                                goto fail;
                        bio_list_add(&list, bio);
+                       bio_cnt++;
                }
 
                /* Always in 512 byte units for Linux/Block */
@@ -566,11 +585,12 @@ static int iblock_do_task(struct se_task *task)
                sg_num--;
        }
 
-       blk_start_plug(&plug);
-       while ((bio = bio_list_pop(&list)))
-               submit_bio(rw, bio);
-       blk_finish_plug(&plug);
+       iblock_submit_bios(&list, rw);
 
+       if (atomic_dec_and_test(&ibr->pending)) {
+               transport_complete_task(task,
+                               !atomic_read(&ibr->ib_bio_err_cnt));
+       }
        return 0;
 
 fail:
@@ -622,7 +642,7 @@ static void iblock_bio_done(struct bio *bio, int err)
 
        bio_put(bio);
 
-       if (!atomic_dec_and_test(&ibr->ib_bio_cnt))
+       if (!atomic_dec_and_test(&ibr->pending))
                return;
 
        pr_debug("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n",
index 3006104..e929370 100644 (file)
@@ -8,7 +8,7 @@
 
 struct iblock_req {
        struct se_task ib_task;
-       atomic_t ib_bio_cnt;
+       atomic_t pending;
        atomic_t ib_bio_err_cnt;
 } ____cacheline_aligned;