| From 68b795015c9be8cdaf9881ff77e7f8bd161fdcc6 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 13 Sep 2024 15:05:18 +0200 |
| Subject: Revert "dm: requeue IO if mapping table not yet available" |
| |
| From: Mikulas Patocka <mpatocka@redhat.com> |
| |
| [ Upstream commit c8691cd0fc11197515ed148de0780d927bfca38b ] |
| |
| This reverts commit fa247089de9936a46e290d4724cb5f0b845600f5. |
| |
| The following sequence of commands causes a livelock - there will be |
| workqueue process looping and consuming 100% CPU: |
| |
| dmsetup create --notable test |
| truncate -s 1MiB testdata |
| losetup /dev/loop0 testdata |
| dmsetup load test --table '0 2048 linear /dev/loop0 0' |
| dd if=/dev/zero of=/dev/dm-0 bs=16k count=1 conv=fdatasync |
| |
| The livelock is caused by the commit fa247089de99. The commit claims that |
| it fixes a race condition, however, it is unknown what the actual race |
| condition is and what program is involved in the race condition. |
| |
| When the inactive table is loaded, the nodes /dev/dm-0 and |
| /sys/block/dm-0 are created. /dev/dm-0 has zero size at this point. When |
| the device is suspended and resumed, the nodes /dev/mapper/test and |
| /dev/disk/* are created. |
| |
| If some program opens a block device before it is created by dmsetup or |
| lvm, the program is buggy, so dm could just report an error as it used to |
| do before. |
| |
| Reported-by: Zdenek Kabelac <zkabelac@redhat.com> |
| Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> |
| Fixes: fa247089de99 ("dm: requeue IO if mapping table not yet available") |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/md/dm-rq.c | 4 +++- |
| drivers/md/dm.c | 11 ++++++++--- |
| 2 files changed, 11 insertions(+), 4 deletions(-) |
| |
| diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c |
| index 5f933dbb0152c..7762bde40963e 100644 |
| --- a/drivers/md/dm-rq.c |
| +++ b/drivers/md/dm-rq.c |
| @@ -496,8 +496,10 @@ static blk_status_t dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx, |
| |
| map = dm_get_live_table(md, &srcu_idx); |
| if (unlikely(!map)) { |
| + DMERR_LIMIT("%s: mapping table unavailable, erroring io", |
| + dm_device_name(md)); |
| dm_put_live_table(md, srcu_idx); |
| - return BLK_STS_RESOURCE; |
| + return BLK_STS_IOERR; |
| } |
| ti = dm_table_find_target(map, 0); |
| dm_put_live_table(md, srcu_idx); |
| diff --git a/drivers/md/dm.c b/drivers/md/dm.c |
| index b56ea42ab7d2b..4fdf0e666777a 100644 |
| --- a/drivers/md/dm.c |
| +++ b/drivers/md/dm.c |
| @@ -1696,10 +1696,15 @@ static blk_qc_t dm_submit_bio(struct bio *bio) |
| struct dm_table *map; |
| |
| map = dm_get_live_table(md, &srcu_idx); |
| + if (unlikely(!map)) { |
| + DMERR_LIMIT("%s: mapping table unavailable, erroring io", |
| + dm_device_name(md)); |
| + bio_io_error(bio); |
| + goto out; |
| + } |
| |
| - /* 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)) { |
| + /* If suspended, queue this IO for later */ |
| + if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags))) { |
| if (bio->bi_opf & REQ_NOWAIT) |
| bio_wouldblock_error(bio); |
| else if (bio->bi_opf & REQ_RAHEAD) |
| -- |
| 2.43.0 |
| |