Since currently we have no simple but efficient way to implement the
bio-based IO polling in the split-bio tracking style, this patch set
turns to the original implementation mechanism that iterates and
polls all underlying hw queues in polling mode. One optimization is
introduced to mitigate the race of one hw queue among multiple polling
instances.
I'm still open to the split bio tracking mechanism, if there's
reasonable way to implement it.
[Performance Test]
The performance is tested by fio (engine=io_uring) 4k randread on
dm-linear device. The dm-linear device is built upon nvme devices,
and every nvme device has one polling hw queue (nvme.poll_queues=1).
Test Case | IOPS in IRQ mode | IOPS in polling mode | Diff
| (hipri=0) | (hipri=1) |
--------------------------- | ---------------- | -------------------- | ----
3 target nvme, num_jobs = 1 | 198k | 276k | ~40%
3 target nvme, num_jobs = 3 | 608k | 705k | ~16%
6 target nvme, num_jobs = 6 | 1197k | 1347k | ~13%
3 target nvme, num_jobs = 6 | 1285k | 1293k | ~0%
As the number of polling instances (num_jobs) increases, the
performance improvement decreases, though it's still positive
compared to the IRQ mode.
[Optimization]
To mitigate the race when iterating all the underlying hw queues, one
flag is maintained on a per-hw-queue basis. This flag is used to
indicate whether this polling hw queue currently being polled on or
not. Every polling hw queue is exclusive to one polling instance, i.e.,
the polling instance will skip this polling hw queue if this hw queue
currently is being polled by another polling instance, and start
polling on the next hw queue.
This per-hw-queue flag map is currently maintained in dm layer. In
the table load phase, a table describing all underlying polling hw
queues is built and stored in 'struct dm_table'. It is safe when
reloading the mapping table.
changes since v1:
- patch 1,2,4 is the same as v1 and have already been reviewed
- patch 3 is refactored a bit on the basis of suggestions from
Mike Snitzer.
- patch 5 is newly added and introduces one new queue flag
representing if the queue is capable of IO polling. This mainly
simplifies the logic in queue_poll_store().
- patch 6 implements the core mechanism supporting IO polling.
The sanity check checking if the dm device supports IO polling is
also folded into this patch, and the queue flag will be cleared if
it doesn't support, in case of table reloading.
Jeffle Xu (6):
block: move definition of blk_qc_t to types.h
block: add queue_to_disk() to get gendisk from request_queue
block: add iopoll method to support bio-based IO polling
dm: always return BLK_QC_T_NONE for bio-based device
block: add QUEUE_FLAG_POLL_CAP flag
dm: support IO polling for bio-based dm device
block/blk-core.c | 76 +++++++++++++++++++++
block/blk-mq.c | 76 +++------------------
block/blk-sysfs.c | 3 +-
drivers/md/dm-core.h | 21 ++++++
drivers/md/dm-table.c | 127 +++++++++++++++++++++++++++++++++++
drivers/md/dm.c | 61 ++++++++++++-----
include/linux/blk-mq.h | 3 +
include/linux/blk_types.h | 2 +-
include/linux/blkdev.h | 9 +++
include/linux/fs.h | 2 +-
include/linux/types.h | 3 +
include/trace/events/kyber.h | 6 +-
12 files changed, 302 insertions(+), 87 deletions(-)
--
2.27.0
Currently the returned cookie of bio-based device is not used at all.
In the following patch, bio-based device will actually return a
pointer to a specific object as the returned cookie.
Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Mike Snitzer <redacted>
---
drivers/md/dm.c | 26 ++++++++++----------------
1 file changed, 10 insertions(+), 16 deletions(-)
@@ -1252,14 +1252,13 @@ void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors)}EXPORT_SYMBOL_GPL(dm_accept_partial_bio);-staticblk_qc_t__map_bio(structdm_target_io*tio)+staticvoid__map_bio(structdm_target_io*tio){intr;sector_tsector;structbio*clone=&tio->clone;structdm_io*io=tio->io;structdm_target*ti=tio->ti;-blk_qc_tret=BLK_QC_T_NONE;clone->bi_end_io=clone_endio;
@@ -1278,7 +1277,7 @@ static blk_qc_t __map_bio(struct dm_target_io *tio)caseDM_MAPIO_REMAPPED:/* the bio has been remapped so dispatch it */trace_block_bio_remap(clone,bio_dev(io->orig_bio),sector);-ret=submit_bio_noacct(clone);+submit_bio_noacct(clone);break;caseDM_MAPIO_KILL:free_tio(tio);
@@ -1621,13 +1617,11 @@ static blk_qc_t __split_and_process_bio(struct mapped_device *md,/* drop the extra reference count */dec_pending(ci.io,errno_to_blk_status(error));-returnret;}staticblk_qc_tdm_submit_bio(structbio*bio){structmapped_device*md=bio->bi_disk->private_data;-blk_qc_tret=BLK_QC_T_NONE;intsrcu_idx;structdm_table*map;
@@ -1657,10 +1651,10 @@ static blk_qc_t dm_submit_bio(struct bio *bio)if(is_abnormal_io(bio))blk_queue_split(&bio);-ret=__split_and_process_bio(md,map,bio);+__split_and_process_bio(md,map,bio);out:dm_put_live_table(md,srcu_idx);-returnret;+returnBLK_QC_T_NONE;}/*-----------------------------------------------------------------
So that kiocb.ki_cookie can be defined as blk_qc_t, which will enforce
the encapsulation.
Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Mike Snitzer <redacted>
---
include/linux/blk_types.h | 2 +-
include/linux/fs.h | 2 +-
include/linux/types.h | 3 +++
3 files changed, 5 insertions(+), 2 deletions(-)
->poll_fn was introduced in commit ea435e1b9392 ("block: add a poll_fn
callback to struct request_queue") to support bio-based queues such as
nvme multipath, but was later removed in commit 529262d56dbe ("block:
remove ->poll_fn").
Given commit c62b37d96b6e ("block: move ->make_request_fn to struct
block_device_operations") restore the possibility of bio-based IO
polling support by adding an ->iopoll method to gendisk->fops.
Elevate bulk of blk_mq_poll() implementation to blk_poll() and reduce
blk_mq_poll() to blk-mq specific code that is called from blk_poll().
Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
Suggested-by: Mike Snitzer <redacted>
---
block/blk-core.c | 70 +++++++++++++++++++++++++++++++++++++++
block/blk-mq.c | 74 ++++++------------------------------------
include/linux/blk-mq.h | 3 ++
include/linux/blkdev.h | 1 +
4 files changed, 84 insertions(+), 64 deletions(-)
DM will iterate and poll all polling hardware queues of all target mq
devices when polling IO for dm device. To mitigate the race introduced
by iterating all target hw queues, a per-hw-queue flag is maintained
to indicate whether this polling hw queue currently being polled on or
not. Every polling hw queue is exclusive to one polling instance, i.e.,
the polling instance will skip this polling hw queue if this hw queue
currently is being polled by another polling instance, and start
polling on the next hw queue.
IO polling is enabled when all underlying target devices are capable
of IO polling. The sanity check supports the stacked device model, in
which one dm device may be build upon another dm device. In this case,
the mapped device will check if the underlying dm target device
supports IO polling.
Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
---
block/blk-core.c | 8 ++-
drivers/md/dm-core.h | 21 +++++++
drivers/md/dm-table.c | 127 ++++++++++++++++++++++++++++++++++++++++++
drivers/md/dm.c | 37 ++++++++++++
4 files changed, 192 insertions(+), 1 deletion(-)
@@ -1194,6 +1196,114 @@ static int dm_table_register_integrity(struct dm_table *t)return0;}+staticintdevice_supports_poll(structdm_target*ti,structdm_dev*dev,+sector_tstart,sector_tlen,void*data)+{+structrequest_queue*q=bdev_get_queue(dev->bdev);++returnq&&test_bit(QUEUE_FLAG_POLL,&q->queue_flags);+}++staticbooldm_table_supports_poll(structdm_table*t)+{+structdm_target*ti;+unsignedinti;++/* Ensure that all targets support iopoll. */+for(i=0;i<dm_table_get_num_targets(t);i++){+ti=dm_table_get_target(t,i);++if(!ti->type->iterate_devices||+!ti->type->iterate_devices(ti,device_supports_poll,NULL))+returnfalse;+}++returntrue;+}++staticintdm_table_calc_target_ctxs(structdm_target*ti,+structdm_dev*dev,+sector_tstart,sector_tlen,+void*data)+{+int*num=data;+structrequest_queue*q=dev->bdev->bd_disk->queue;++if(queue_is_mq(q))+*num+=q->tag_set->map[HCTX_TYPE_POLL].nr_queues;+else+*num+=1;++return0;+}++staticintdm_table_fill_target_ctxs(structdm_target*ti,+structdm_dev*dev,+sector_tstart,sector_tlen,+void*data)+{+int*index=data;+structtarget_ctx*ctx;+structrequest_queue*q=dev->bdev->bd_disk->queue;++if(queue_is_mq(q)){+inti;+intnum=q->tag_set->map[HCTX_TYPE_POLL].nr_queues;+intoffset=q->tag_set->map[HCTX_TYPE_POLL].queue_offset;++for(i=0;i<num;i++){+ctx=&ti->table->ctxs[(*index)++];+ctx->q=q;+ctx->hctx=q->queue_hw_ctx[offset+i];+ctx->type=TARGET_TYPE_MQ;+/* ctx->busy has been initialized to zero */+}+}else{+structmapped_device*md=dev->bdev->bd_disk->private_data;++ctx=&ti->table->ctxs[(*index)++];+ctx->md=md;+ctx->type=TARGET_TYPE_DM;+}++return0;+}++staticintdm_table_build_target_ctxs(structdm_table*t)+{+inti,num=0,index=0;++if(!__table_type_bio_based(t->type)||!dm_table_supports_poll(t))+return0;++for(i=0;i<t->num_targets;i++){+structdm_target*ti=dm_table_get_target(t,i);++if(ti->type->iterate_devices)+ti->type->iterate_devices(ti,dm_table_calc_target_ctxs,+&num);+}++if(WARN_ON(!num))+return0;++t->num_ctx=num;++t->ctxs=kcalloc(num,sizeof(structtarget_ctx),GFP_KERNEL);+if(!t->ctxs)+return-ENOMEM;++for(i=0;i<t->num_targets;i++){+structdm_target*ti=dm_table_get_target(t,i);++if(ti->type->iterate_devices)+ti->type->iterate_devices(ti,dm_table_fill_target_ctxs,+&index);+}++return0;+}+/**Preparesthetableforusebybuildingtheindices,*settingthetype,andallocatingmempools.
@@ -1224,6 +1334,10 @@ int dm_table_complete(struct dm_table *t)if(r)DMERR("unable to allocate mempools");+r=dm_table_build_target_ctxs(t);+if(r)+DMERR("unable to build target hctxs");+returnr;}
Sometimes we need to get the corresponding gendisk from request_queue.
It is preferred that block drivers store private data in
gendisk->private_data rather than request_queue->queuedata, e.g. see:
commit c4a59c4e5db3 ("dm: stop using ->queuedata").
So if only request_queue is given, we need to get its corresponding
gendisk to get the private data stored in that gendisk.
Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
Review-by: Mike Snitzer [off-list ref]
---
include/linux/blkdev.h | 2 ++
include/trace/events/kyber.h | 6 +++---
2 files changed, 5 insertions(+), 3 deletions(-)
From: Mike Snitzer <hidden> Date: 2021-01-27 17:18:06
On Mon, Jan 25 2021 at 7:13am -0500,
Jeffle Xu [off-list ref] wrote:
->poll_fn was introduced in commit ea435e1b9392 ("block: add a poll_fn
callback to struct request_queue") to support bio-based queues such as
nvme multipath, but was later removed in commit 529262d56dbe ("block:
remove ->poll_fn").
Given commit c62b37d96b6e ("block: move ->make_request_fn to struct
block_device_operations") restore the possibility of bio-based IO
polling support by adding an ->iopoll method to gendisk->fops.
Elevate bulk of blk_mq_poll() implementation to blk_poll() and reduce
blk_mq_poll() to blk-mq specific code that is called from blk_poll().
Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
Suggested-by: Mike Snitzer <redacted>
From: Mike Snitzer <hidden> Date: 2021-01-27 17:23:07
On Mon, Jan 25 2021 at 7:13am -0500,
Jeffle Xu [off-list ref] wrote:
Since currently we have no simple but efficient way to implement the
bio-based IO polling in the split-bio tracking style, this patch set
turns to the original implementation mechanism that iterates and
polls all underlying hw queues in polling mode. One optimization is
introduced to mitigate the race of one hw queue among multiple polling
instances.
I'm still open to the split bio tracking mechanism, if there's
reasonable way to implement it.
[Performance Test]
The performance is tested by fio (engine=io_uring) 4k randread on
dm-linear device. The dm-linear device is built upon nvme devices,
and every nvme device has one polling hw queue (nvme.poll_queues=1).
Test Case | IOPS in IRQ mode | IOPS in polling mode | Diff
| (hipri=0) | (hipri=1) |
--------------------------- | ---------------- | -------------------- | ----
3 target nvme, num_jobs = 1 | 198k | 276k | ~40%
3 target nvme, num_jobs = 3 | 608k | 705k | ~16%
6 target nvme, num_jobs = 6 | 1197k | 1347k | ~13%
3 target nvme, num_jobs = 6 | 1285k | 1293k | ~0%
As the number of polling instances (num_jobs) increases, the
performance improvement decreases, though it's still positive
compared to the IRQ mode.
I think there is serious room for improvement for DM's implementation;
but the block changes for this are all we'd need for DM in the longrun
anyway (famous last words). So on a block interface level I'm OK with
block patches 1-3.
I don't see why patch 5 is needed (said the same in reply to it; but I
just saw your reason below..).
Anyway, I can pick up DM patches 4 and 6 via linux-dm.git if Jens picks
up patches 1-3. Jens, what do you think?
[Optimization]
To mitigate the race when iterating all the underlying hw queues, one
flag is maintained on a per-hw-queue basis. This flag is used to
indicate whether this polling hw queue currently being polled on or
not. Every polling hw queue is exclusive to one polling instance, i.e.,
the polling instance will skip this polling hw queue if this hw queue
currently is being polled by another polling instance, and start
polling on the next hw queue.
This per-hw-queue flag map is currently maintained in dm layer. In
the table load phase, a table describing all underlying polling hw
queues is built and stored in 'struct dm_table'. It is safe when
reloading the mapping table.
changes since v1:
- patch 1,2,4 is the same as v1 and have already been reviewed
- patch 3 is refactored a bit on the basis of suggestions from
Mike Snitzer.
- patch 5 is newly added and introduces one new queue flag
representing if the queue is capable of IO polling. This mainly
simplifies the logic in queue_poll_store().
Ah OK, don't see why we want to eat a queue flag for that though!
- patch 6 implements the core mechanism supporting IO polling.
The sanity check checking if the dm device supports IO polling is
also folded into this patch, and the queue flag will be cleared if
it doesn't support, in case of table reloading.
From: Mike Snitzer <hidden> Date: 2021-01-27 17:23:40
On Mon, Jan 25 2021 at 7:13am -0500,
Jeffle Xu [off-list ref] wrote:
Sometimes we need to get the corresponding gendisk from request_queue.
It is preferred that block drivers store private data in
gendisk->private_data rather than request_queue->queuedata, e.g. see:
commit c4a59c4e5db3 ("dm: stop using ->queuedata").
So if only request_queue is given, we need to get its corresponding
gendisk to get the private data stored in that gendisk.
Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
Review-by: Mike Snitzer [off-list ref]
On Mon, Jan 25 2021 at 7:13am -0500,
Jeffle Xu [off-list ref] wrote:
quoted
Introduce QUEUE_FLAG_POLL_CAP flag representing if the request queue
capable of polling or not.
Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
Why are you adding QUEUE_FLAG_POLL_CAP? Doesn't seem as though DM or
anything else actually needs it.
Users can switch on/off polling on device via
'/sys/block/<dev>/queue/io_poll' at runtime. The requisite for turning
on polling is that the device is **capable** of polling. For mq devices,
the requisite is that there's polling hw queue for the device, i.e.,
But for dm devices, we need to check if all the underlying devices
support polling or not. Without this newly added queue flag, we need to
check again every time users want to turn on polling via 'io_poll', and
thus the dm layer need to export one interface to block layer, checking
if all the underlying target devices support polling or not, maybe just
like the iopoll() method we did in patch 3. Something like,
The newly added queue flag 'QUEUE_FLAG_POLL_CAP' is just used as a cache
representing if the device **capable** of polling, while the original
queue flag 'QUEUE_FLAG_POLL' representing if polling is turned on for
this device **currently**.
But indeed we are short of queue flag resource. Adding a new queue flag
may not be the best resolution.
Any inspiration?
--
Thanks,
Jeffle
On Mon, Jan 25 2021 at 7:13am -0500,
Jeffle Xu [off-list ref] wrote:
quoted
Since currently we have no simple but efficient way to implement the
bio-based IO polling in the split-bio tracking style, this patch set
turns to the original implementation mechanism that iterates and
polls all underlying hw queues in polling mode. One optimization is
introduced to mitigate the race of one hw queue among multiple polling
instances.
I'm still open to the split bio tracking mechanism, if there's
reasonable way to implement it.
[Performance Test]
The performance is tested by fio (engine=io_uring) 4k randread on
dm-linear device. The dm-linear device is built upon nvme devices,
and every nvme device has one polling hw queue (nvme.poll_queues=1).
Test Case | IOPS in IRQ mode | IOPS in polling mode | Diff
| (hipri=0) | (hipri=1) |
--------------------------- | ---------------- | -------------------- | ----
3 target nvme, num_jobs = 1 | 198k | 276k | ~40%
3 target nvme, num_jobs = 3 | 608k | 705k | ~16%
6 target nvme, num_jobs = 6 | 1197k | 1347k | ~13%
3 target nvme, num_jobs = 6 | 1285k | 1293k | ~0%
As the number of polling instances (num_jobs) increases, the
performance improvement decreases, though it's still positive
compared to the IRQ mode.
I think there is serious room for improvement for DM's implementation;
but the block changes for this are all we'd need for DM in the longrun
anyway (famous last words).
Agreed.
So on a block interface level I'm OK with
block patches 1-3.
I don't see why patch 5 is needed (said the same in reply to it; but I
just saw your reason below..).
Anyway, I can pick up DM patches 4 and 6 via linux-dm.git if Jens picks
up patches 1-3. Jens, what do you think?
cc Jens.
Also I will send a new version later, maybe some refactor on patch5 and
some typo modifications.
quoted
[Optimization]
To mitigate the race when iterating all the underlying hw queues, one
flag is maintained on a per-hw-queue basis. This flag is used to
indicate whether this polling hw queue currently being polled on or
not. Every polling hw queue is exclusive to one polling instance, i.e.,
the polling instance will skip this polling hw queue if this hw queue
currently is being polled by another polling instance, and start
polling on the next hw queue.
This per-hw-queue flag map is currently maintained in dm layer. In
the table load phase, a table describing all underlying polling hw
queues is built and stored in 'struct dm_table'. It is safe when
reloading the mapping table.
changes since v1:
- patch 1,2,4 is the same as v1 and have already been reviewed
- patch 3 is refactored a bit on the basis of suggestions from
Mike Snitzer.
- patch 5 is newly added and introduces one new queue flag
representing if the queue is capable of IO polling. This mainly
simplifies the logic in queue_poll_store().
Ah OK, don't see why we want to eat a queue flag for that though!
quoted
- patch 6 implements the core mechanism supporting IO polling.
The sanity check checking if the dm device supports IO polling is
also folded into this patch, and the queue flag will be cleared if
it doesn't support, in case of table reloading.
Can you split the guts of this function into two separate helpers
for the mq vs non-mq case? As is is is a little hard to read and
introduced extra branches in the fast path.
Can you split the guts of this function into two separate helpers
for the mq vs non-mq case? As is is is a little hard to read and
introduced extra branches in the fast path.
I know your consideration, actually I had ever tried.
I can extract some helper functions, but I'm doubted if the extra
function call is acceptable.
Besides, the iteration logic is generic and I'm afraid the branch or
function call is unavoidable. Or if we maintain two separate function
for mq and dm, the code duplication may be unavoidable.
Anyway I'll give a try.
--
Thanks,
Jeffle
Can you split the guts of this function into two separate helpers
for the mq vs non-mq case? As is is is a little hard to read and
introduced extra branches in the fast path.
I know your consideration, actually I had ever tried.
I can extract some helper functions, but I'm doubted if the extra
function call is acceptable.
Besides, the iteration logic is generic and I'm afraid the branch or
function call is unavoidable. Or if we maintain two separate function
for mq and dm, the code duplication may be unavoidable.
I'd just split the functions entirely at the highest level.
DM will iterate and poll all polling hardware queues of all target mq
devices when polling IO for dm device. To mitigate the race introduced
by iterating all target hw queues, a per-hw-queue flag is maintained
to indicate whether this polling hw queue currently being polled on or
not. Every polling hw queue is exclusive to one polling instance, i.e.,
the polling instance will skip this polling hw queue if this hw queue
currently is being polled by another polling instance, and start
polling on the next hw queue.
IO polling is enabled when all underlying target devices are capable
of IO polling. The sanity check supports the stacked device model, in
which one dm device may be build upon another dm device. In this case,
the mapped device will check if the underlying dm target device
supports IO polling.
Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
---
block/blk-core.c | 8 ++-
drivers/md/dm-core.h | 21 +++++++
drivers/md/dm-table.c | 127 ++++++++++++++++++++++++++++++++++++++++++
drivers/md/dm.c | 37 ++++++++++++
4 files changed, 192 insertions(+), 1 deletion(-)
I suddenly realize that this implementation is somehow problematic. This
implementation actually buffers hctx of underlying mq device. This can
be problematic when the hctx of uderlying mq device can be dynamiclly
changed at runtime.
For example, nvme RESET command can trigger this issue. Users can send
nvme RESET command while there's already one dm device built upon this
nvme device. In this case, the hctx map of nvme device will be
reallocated when there's one dm device built upon this nvme device. And
the original old 'struct blk_mq_hw_ctx *hctx' buffered in the dm layer
can be out-of-date.
Maybe we could embed 'atomic_t busy' in 'struct blk_mq_hw_ctx', and
block layer needs to export one interface iterating all hw queues of
given device, just like what I did in the very first RFC version patch:
+#define queue_for_each_poll_hw_ctx(q, hctx, i) \
+for ((i) = 0; ((q)->tag_set->nr_maps > HCTX_TYPE_POLL) && \
+ (i) < (q)->tag_set->map[HCTX_TYPE_POLL].nr_queues && \
+({ hctx =
(q)->queue_hw_ctx[((q)->tag_set->map[HCTX_TYPE_POLL].queue_offset +
(i))]; 1; }); \
+(i)++)
@@ -1194,6 +1196,114 @@ static int dm_table_register_integrity(struct dm_table *t)return0;}+staticintdevice_supports_poll(structdm_target*ti,structdm_dev*dev,+sector_tstart,sector_tlen,void*data)+{+structrequest_queue*q=bdev_get_queue(dev->bdev);++returnq&&test_bit(QUEUE_FLAG_POLL,&q->queue_flags);+}++staticbooldm_table_supports_poll(structdm_table*t)+{+structdm_target*ti;+unsignedinti;++/* Ensure that all targets support iopoll. */+for(i=0;i<dm_table_get_num_targets(t);i++){+ti=dm_table_get_target(t,i);++if(!ti->type->iterate_devices||+!ti->type->iterate_devices(ti,device_supports_poll,NULL))+returnfalse;+}++returntrue;+}++staticintdm_table_calc_target_ctxs(structdm_target*ti,+structdm_dev*dev,+sector_tstart,sector_tlen,+void*data)+{+int*num=data;+structrequest_queue*q=dev->bdev->bd_disk->queue;++if(queue_is_mq(q))+*num+=q->tag_set->map[HCTX_TYPE_POLL].nr_queues;+else+*num+=1;++return0;+}++staticintdm_table_fill_target_ctxs(structdm_target*ti,+structdm_dev*dev,+sector_tstart,sector_tlen,+void*data)+{+int*index=data;+structtarget_ctx*ctx;+structrequest_queue*q=dev->bdev->bd_disk->queue;++if(queue_is_mq(q)){+inti;+intnum=q->tag_set->map[HCTX_TYPE_POLL].nr_queues;+intoffset=q->tag_set->map[HCTX_TYPE_POLL].queue_offset;++for(i=0;i<num;i++){+ctx=&ti->table->ctxs[(*index)++];+ctx->q=q;+ctx->hctx=q->queue_hw_ctx[offset+i];+ctx->type=TARGET_TYPE_MQ;+/* ctx->busy has been initialized to zero */+}+}else{+structmapped_device*md=dev->bdev->bd_disk->private_data;++ctx=&ti->table->ctxs[(*index)++];+ctx->md=md;+ctx->type=TARGET_TYPE_DM;+}++return0;+}++staticintdm_table_build_target_ctxs(structdm_table*t)+{+inti,num=0,index=0;++if(!__table_type_bio_based(t->type)||!dm_table_supports_poll(t))+return0;++for(i=0;i<t->num_targets;i++){+structdm_target*ti=dm_table_get_target(t,i);++if(ti->type->iterate_devices)+ti->type->iterate_devices(ti,dm_table_calc_target_ctxs,+&num);+}++if(WARN_ON(!num))+return0;++t->num_ctx=num;++t->ctxs=kcalloc(num,sizeof(structtarget_ctx),GFP_KERNEL);+if(!t->ctxs)+return-ENOMEM;++for(i=0;i<t->num_targets;i++){+structdm_target*ti=dm_table_get_target(t,i);++if(ti->type->iterate_devices)+ti->type->iterate_devices(ti,dm_table_fill_target_ctxs,+&index);+}++return0;+}+/**Preparesthetableforusebybuildingtheindices,*settingthetype,andallocatingmempools.
@@ -1224,6 +1334,10 @@ int dm_table_complete(struct dm_table *t)if(r)DMERR("unable to allocate mempools");+r=dm_table_build_target_ctxs(t);+if(r)+DMERR("unable to build target hctxs");+returnr;}