diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c index 3bd805f7ce85bffacbd07ffd7c4c65a15a4f901e..288064e94e52611b32965a8643d111de5949eeb4 100644 --- a/drivers/md/dm-rq.c +++ b/drivers/md/dm-rq.c @@ -755,11 +755,9 @@ static blk_status_t dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx, struct dm_table *map; map = dm_get_live_table(md, &srcu_idx); - if (!map) { - DMERR_LIMIT("%s: mapping table unavailable, erroring io", - dm_device_name(md)); + if (unlikely(!map)) { dm_put_live_table(md, srcu_idx); - return BLK_STS_IOERR; + return BLK_STS_RESOURCE; } ti = dm_table_find_target(map, 0); dm_put_live_table(md, srcu_idx); diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index e37f468cdbf0da159792dd8dd63aa0fef8ca1f24..bd9466dc94009cc39ebde88ae1b3278914d29caa 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -1711,13 +1711,15 @@ int dm_thin_remove_range(struct dm_thin_device *td, int dm_pool_block_is_shared(struct dm_pool_metadata *pmd, dm_block_t b, bool *result) { - int r; + int r = -EINVAL; uint32_t ref_count; down_read(&pmd->root_lock); - r = dm_sm_get_count(pmd->data_sm, b, &ref_count); - if (!r) - *result = (ref_count > 1); + if (!pmd->fail_io) { + r = dm_sm_get_count(pmd->data_sm, b, &ref_count); + if (!r) + *result = (ref_count > 1); + } up_read(&pmd->root_lock); return r; @@ -1728,10 +1730,14 @@ int dm_pool_inc_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_ int r = 0; down_write(&pmd->root_lock); - for (; b != e; b++) { - r = dm_sm_inc_block(pmd->data_sm, b); - if (r) - break; + if (!pmd->fail_io) { + for (; b != e; b++) { + r = dm_sm_inc_block(pmd->data_sm, b); + if (r) + break; + } + } else { + r = -EINVAL; } up_write(&pmd->root_lock); @@ -1743,10 +1749,14 @@ int dm_pool_dec_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_ int r = 0; down_write(&pmd->root_lock); - for (; b != e; b++) { - r = dm_sm_dec_block(pmd->data_sm, b); - if (r) - break; + if (!pmd->fail_io) { + for (; b != e; b++) { + r = dm_sm_dec_block(pmd->data_sm, b); + if (r) + break; + } + } else { + r = -EINVAL; } up_write(&pmd->root_lock); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index ea1baea3a11d41fa7b0088ee61e1eb949a1b2861..0aa6fd33abf1aeece9c8f14979b573cf7b3928db 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1781,8 +1781,9 @@ static blk_qc_t dm_make_request(struct request_queue *q, struct bio *bio) map = dm_get_live_table(md, &srcu_idx); - /* if we're suspended, we have to queue this io for later */ - if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags))) { + /* If suspended, or map not yet available, queue this IO for later */ + if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) || + unlikely(!map)) { dm_put_live_table(md, srcu_idx); if (!(bio->bi_opf & REQ_RAHEAD)) @@ -2746,6 +2747,10 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) } map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock)); + if (!map) { + /* avoid deadlock with fs/namespace.c:do_mount() */ + suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG; + } r = __dm_suspend(md, map, suspend_flags, TASK_INTERRUPTIBLE, DMF_SUSPENDED); if (r) diff --git a/drivers/md/md.c b/drivers/md/md.c index 5a5e1f1fdb52642bba80d38ddd4841c3f8e148c6..d16fdfa1aada3c77d604c7828660d0b60da9b0a8 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5462,6 +5462,7 @@ static int md_alloc(dev_t dev, char *name) * completely removed (mddev_delayed_delete). */ flush_workqueue(md_misc_wq); + flush_workqueue(md_rdev_misc_wq); mutex_lock(&disks_mutex); error = -EEXIST;