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@xxxxxx> Index: lio-core/drivers/target/target_core_iblock.c =================================================================== --- lio-core.orig/drivers/target/target_core_iblock.c 2011-12-12 04:51:55.746662134 -0800 +++ lio-core/drivers/target/target_core_iblock.c 2011-12-12 05:25:13.156650201 -0800 @@ -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_v 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_v 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; } @@ -477,24 +478,35 @@ iblock_get_bio(struct se_task *task, sec 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) { @@ -539,6 +551,7 @@ static int iblock_do_task(struct se_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) { /* @@ -548,10 +561,16 @@ static int iblock_do_task(struct se_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 */ @@ -559,11 +578,12 @@ static int iblock_do_task(struct se_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: @@ -615,7 +635,7 @@ static void iblock_bio_done(struct bio * 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: lio-core/drivers/target/target_core_iblock.h =================================================================== --- lio-core.orig/drivers/target/target_core_iblock.h 2011-12-12 04:51:00.333329132 -0800 +++ lio-core/drivers/target/target_core_iblock.h 2011-12-12 05:24:40.423317064 -0800 @@ -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; -- To unsubscribe from this list: send the line "unsubscribe target-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html