Skip to content

Commit

Permalink
dm table: fix 'all_blk_mq' inconsistency when an empty table is loaded
Browse files Browse the repository at this point in the history
An earlier DM multipath table could have been build ontop of underlying
devices that were all using blk-mq.  In that case, if that active
multipath table is replaced with an empty DM multipath table (that
reflects all paths have failed) then it is important that the
'all_blk_mq' state of the active table is transfered to the new empty DM
table.  Otherwise dm-rq.c:dm_old_prep_tio() will incorrectly clone a
request that isn't needed by the DM multipath target when it is to issue
IO to an underlying blk-mq device.

Fixes: e83068a ("dm mpath: add optional "queue_mode" feature")
Cc: [email protected] # 4.8+
Reported-by: Bart Van Assche <[email protected]>
Tested-by: Bart Van Assche <[email protected]>
Signed-off-by: Mike Snitzer <[email protected]>
  • Loading branch information
snitm committed Dec 8, 2016
1 parent 6599c84 commit 6936c12
Showing 1 changed file with 13 additions and 6 deletions.
19 changes: 13 additions & 6 deletions drivers/md/dm-table.c
Original file line number Diff line number Diff line change
Expand Up @@ -924,12 +924,6 @@ static int dm_table_determine_type(struct dm_table *t)

BUG_ON(!request_based); /* No targets in this table */

if (list_empty(devices) && __table_type_request_based(live_md_type)) {
/* inherit live MD type */
t->type = live_md_type;
return 0;
}

/*
* The only way to establish DM_TYPE_MQ_REQUEST_BASED is by
* having a compatible target use dm_table_set_type.
Expand All @@ -948,6 +942,19 @@ static int dm_table_determine_type(struct dm_table *t)
return -EINVAL;
}

if (list_empty(devices)) {
int srcu_idx;
struct dm_table *live_table = dm_get_live_table(t->md, &srcu_idx);

/* inherit live table's type and all_blk_mq */
if (live_table) {
t->type = live_table->type;
t->all_blk_mq = live_table->all_blk_mq;
}
dm_put_live_table(t->md, srcu_idx);
return 0;
}

/* Non-request-stackable devices can't be used for request-based dm */
list_for_each_entry(dd, devices, list) {
struct request_queue *q = bdev_get_queue(dd->dm_dev->bdev);
Expand Down

0 comments on commit 6936c12

Please sign in to comment.