From: Greg Kroah-Hartman Date: Mon, 9 Mar 2020 20:14:35 +0000 (+0100) Subject: 5.4-stable patches X-Git-Tag: v4.4.216~40 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=832ec4f0e4015fce1271489ac453cbec424f2630;p=thirdparty%2Fkernel%2Fstable-queue.git 5.4-stable patches added patches: dm-cache-fix-a-crash-due-to-incorrect-work-item-cancelling.patch dm-fix-congested_fn-for-request-based-device.patch dm-integrity-fix-a-deadlock-due-to-offloading-to-an-incorrect-workqueue.patch dm-integrity-fix-invalid-table-returned-due-to-argument-count-mismatch.patch dm-integrity-fix-recalculation-when-moving-from-journal-mode-to-bitmap-mode.patch dm-report-suspended-device-during-destroy.patch dm-writecache-verify-watermark-during-resume.patch dm-zoned-fix-reference-counter-initial-value-of-chunk-works.patch dmaengine-tegra-apb-fix-use-after-free.patch dmaengine-tegra-apb-prevent-race-conditions-of-tasklet-vs-free-list.patch --- diff --git a/queue-5.4/dm-cache-fix-a-crash-due-to-incorrect-work-item-cancelling.patch b/queue-5.4/dm-cache-fix-a-crash-due-to-incorrect-work-item-cancelling.patch new file mode 100644 index 00000000000..e7a7d1c37c4 --- /dev/null +++ b/queue-5.4/dm-cache-fix-a-crash-due-to-incorrect-work-item-cancelling.patch @@ -0,0 +1,51 @@ +From 7cdf6a0aae1cccf5167f3f04ecddcf648b78e289 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Wed, 19 Feb 2020 10:25:45 -0500 +Subject: dm cache: fix a crash due to incorrect work item cancelling + +From: Mikulas Patocka + +commit 7cdf6a0aae1cccf5167f3f04ecddcf648b78e289 upstream. + +The crash can be reproduced by running the lvm2 testsuite test +lvconvert-thin-external-cache.sh for several minutes, e.g.: + while :; do make check T=shell/lvconvert-thin-external-cache.sh; done + +The crash happens in this call chain: +do_waker -> policy_tick -> smq_tick -> end_hotspot_period -> clear_bitset +-> memset -> __memset -- which accesses an invalid pointer in the vmalloc +area. + +The work entry on the workqueue is executed even after the bitmap was +freed. The problem is that cancel_delayed_work doesn't wait for the +running work item to finish, so the work item can continue running and +re-submitting itself even after cache_postsuspend. In order to make sure +that the work item won't be running, we must use cancel_delayed_work_sync. + +Also, change flush_workqueue to drain_workqueue, so that if some work item +submits itself or another work item, we are properly waiting for both of +them. + +Fixes: c6b4fcbad044 ("dm: add cache target") +Cc: stable@vger.kernel.org # v3.9 +Signed-off-by: Mikulas Patocka +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-cache-target.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/md/dm-cache-target.c ++++ b/drivers/md/dm-cache-target.c +@@ -2867,8 +2867,8 @@ static void cache_postsuspend(struct dm_ + prevent_background_work(cache); + BUG_ON(atomic_read(&cache->nr_io_migrations)); + +- cancel_delayed_work(&cache->waker); +- flush_workqueue(cache->wq); ++ cancel_delayed_work_sync(&cache->waker); ++ drain_workqueue(cache->wq); + WARN_ON(cache->tracker.in_flight); + + /* diff --git a/queue-5.4/dm-fix-congested_fn-for-request-based-device.patch b/queue-5.4/dm-fix-congested_fn-for-request-based-device.patch new file mode 100644 index 00000000000..99b6bde608e --- /dev/null +++ b/queue-5.4/dm-fix-congested_fn-for-request-based-device.patch @@ -0,0 +1,80 @@ +From 974f51e8633f0f3f33e8f86bbb5ae66758aa63c7 Mon Sep 17 00:00:00 2001 +From: Hou Tao +Date: Tue, 3 Mar 2020 16:45:01 +0800 +Subject: dm: fix congested_fn for request-based device + +From: Hou Tao + +commit 974f51e8633f0f3f33e8f86bbb5ae66758aa63c7 upstream. + +We neither assign congested_fn for requested-based blk-mq device nor +implement it correctly. So fix both. + +Also, remove incorrect comment from dm_init_normal_md_queue and rename +it to dm_init_congested_fn. + +Fixes: 4aa9c692e052 ("bdi: separate out congested state into a separate struct") +Cc: stable@vger.kernel.org +Signed-off-by: Hou Tao +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm.c | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -1809,7 +1809,8 @@ static int dm_any_congested(void *conges + * With request-based DM we only need to check the + * top-level queue for congestion. + */ +- r = md->queue->backing_dev_info->wb.state & bdi_bits; ++ struct backing_dev_info *bdi = md->queue->backing_dev_info; ++ r = bdi->wb.congested->state & bdi_bits; + } else { + map = dm_get_live_table_fast(md); + if (map) +@@ -1875,15 +1876,6 @@ static const struct dax_operations dm_da + + static void dm_wq_work(struct work_struct *work); + +-static void dm_init_normal_md_queue(struct mapped_device *md) +-{ +- /* +- * Initialize aspects of queue that aren't relevant for blk-mq +- */ +- md->queue->backing_dev_info->congested_data = md; +- md->queue->backing_dev_info->congested_fn = dm_any_congested; +-} +- + static void cleanup_mapped_device(struct mapped_device *md) + { + if (md->wq) +@@ -2270,6 +2262,12 @@ struct queue_limits *dm_get_queue_limits + } + EXPORT_SYMBOL_GPL(dm_get_queue_limits); + ++static void dm_init_congested_fn(struct mapped_device *md) ++{ ++ md->queue->backing_dev_info->congested_data = md; ++ md->queue->backing_dev_info->congested_fn = dm_any_congested; ++} ++ + /* + * Setup the DM device's queue based on md's type + */ +@@ -2286,11 +2284,12 @@ int dm_setup_md_queue(struct mapped_devi + DMERR("Cannot initialize queue for request-based dm-mq mapped device"); + return r; + } ++ dm_init_congested_fn(md); + break; + case DM_TYPE_BIO_BASED: + case DM_TYPE_DAX_BIO_BASED: + case DM_TYPE_NVME_BIO_BASED: +- dm_init_normal_md_queue(md); ++ dm_init_congested_fn(md); + break; + case DM_TYPE_NONE: + WARN_ON_ONCE(true); diff --git a/queue-5.4/dm-integrity-fix-a-deadlock-due-to-offloading-to-an-incorrect-workqueue.patch b/queue-5.4/dm-integrity-fix-a-deadlock-due-to-offloading-to-an-incorrect-workqueue.patch new file mode 100644 index 00000000000..8a582367e6b --- /dev/null +++ b/queue-5.4/dm-integrity-fix-a-deadlock-due-to-offloading-to-an-incorrect-workqueue.patch @@ -0,0 +1,113 @@ +From 53770f0ec5fd417429775ba006bc4abe14002335 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Mon, 17 Feb 2020 07:43:03 -0500 +Subject: dm integrity: fix a deadlock due to offloading to an incorrect workqueue + +From: Mikulas Patocka + +commit 53770f0ec5fd417429775ba006bc4abe14002335 upstream. + +If we need to perform synchronous I/O in dm_integrity_map_continue(), +we must make sure that we are not in the map function - in order to +avoid the deadlock due to bio queuing in generic_make_request. To +avoid the deadlock, we offload the request to metadata_wq. + +However, metadata_wq also processes metadata updates for write requests. +If there are too many requests that get offloaded to metadata_wq at the +beginning of dm_integrity_map_continue, the workqueue metadata_wq +becomes clogged and the system is incapable of processing any metadata +updates. + +This causes a deadlock because all the requests that need to do metadata +updates wait for metadata_wq to proceed and metadata_wq waits inside +wait_and_add_new_range until some existing request releases its range +lock (which doesn't happen because the range lock is released after +metadata update). + +In order to fix the deadlock, we create a new workqueue offload_wq and +offload requests to it - so that processing of offload_wq is independent +from processing of metadata_wq. + +Fixes: 7eada909bfd7 ("dm: add integrity target") +Cc: stable@vger.kernel.org # v4.12+ +Reported-by: Heinz Mauelshagen +Tested-by: Heinz Mauelshagen +Signed-off-by: Heinz Mauelshagen +Signed-off-by: Mikulas Patocka +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-integrity.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -210,6 +210,7 @@ struct dm_integrity_c { + struct list_head wait_list; + wait_queue_head_t endio_wait; + struct workqueue_struct *wait_wq; ++ struct workqueue_struct *offload_wq; + + unsigned char commit_seq; + commit_id_t commit_ids[N_COMMIT_IDS]; +@@ -1434,7 +1435,7 @@ static void dec_in_flight(struct dm_inte + dio->range.logical_sector += dio->range.n_sectors; + bio_advance(bio, dio->range.n_sectors << SECTOR_SHIFT); + INIT_WORK(&dio->work, integrity_bio_wait); +- queue_work(ic->wait_wq, &dio->work); ++ queue_work(ic->offload_wq, &dio->work); + return; + } + do_endio_flush(ic, dio); +@@ -1860,7 +1861,7 @@ static void dm_integrity_map_continue(st + + if (need_sync_io && from_map) { + INIT_WORK(&dio->work, integrity_bio_wait); +- queue_work(ic->metadata_wq, &dio->work); ++ queue_work(ic->offload_wq, &dio->work); + return; + } + +@@ -2496,7 +2497,7 @@ static void bitmap_block_work(struct wor + dio->range.n_sectors, BITMAP_OP_TEST_ALL_SET)) { + remove_range(ic, &dio->range); + INIT_WORK(&dio->work, integrity_bio_wait); +- queue_work(ic->wait_wq, &dio->work); ++ queue_work(ic->offload_wq, &dio->work); + } else { + block_bitmap_op(ic, ic->journal, dio->range.logical_sector, + dio->range.n_sectors, BITMAP_OP_SET); +@@ -2519,7 +2520,7 @@ static void bitmap_block_work(struct wor + + remove_range(ic, &dio->range); + INIT_WORK(&dio->work, integrity_bio_wait); +- queue_work(ic->wait_wq, &dio->work); ++ queue_work(ic->offload_wq, &dio->work); + } + + queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, ic->bitmap_flush_interval); +@@ -3825,6 +3826,14 @@ static int dm_integrity_ctr(struct dm_ta + goto bad; + } + ++ ic->offload_wq = alloc_workqueue("dm-integrity-offload", WQ_MEM_RECLAIM, ++ METADATA_WORKQUEUE_MAX_ACTIVE); ++ if (!ic->offload_wq) { ++ ti->error = "Cannot allocate workqueue"; ++ r = -ENOMEM; ++ goto bad; ++ } ++ + ic->commit_wq = alloc_workqueue("dm-integrity-commit", WQ_MEM_RECLAIM, 1); + if (!ic->commit_wq) { + ti->error = "Cannot allocate workqueue"; +@@ -4129,6 +4138,8 @@ static void dm_integrity_dtr(struct dm_t + destroy_workqueue(ic->metadata_wq); + if (ic->wait_wq) + destroy_workqueue(ic->wait_wq); ++ if (ic->offload_wq) ++ destroy_workqueue(ic->offload_wq); + if (ic->commit_wq) + destroy_workqueue(ic->commit_wq); + if (ic->writer_wq) diff --git a/queue-5.4/dm-integrity-fix-invalid-table-returned-due-to-argument-count-mismatch.patch b/queue-5.4/dm-integrity-fix-invalid-table-returned-due-to-argument-count-mismatch.patch new file mode 100644 index 00000000000..cc41a4927f8 --- /dev/null +++ b/queue-5.4/dm-integrity-fix-invalid-table-returned-due-to-argument-count-mismatch.patch @@ -0,0 +1,36 @@ +From 7fc2e47f40dd77ab1fcbda6db89614a0173d89c7 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Mon, 17 Feb 2020 08:11:35 -0500 +Subject: dm integrity: fix invalid table returned due to argument count mismatch + +From: Mikulas Patocka + +commit 7fc2e47f40dd77ab1fcbda6db89614a0173d89c7 upstream. + +If the flag SB_FLAG_RECALCULATE is present in the superblock, but it was +not specified on the command line (i.e. ic->recalculate_flag is false), +dm-integrity would return invalid table line - the reported number of +arguments would not match the real number. + +Fixes: 468dfca38b1a ("dm integrity: add a bitmap mode") +Cc: stable@vger.kernel.org # v5.2+ +Reported-by: Ondrej Kozina +Signed-off-by: Mikulas Patocka +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-integrity.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -2969,7 +2969,7 @@ static void dm_integrity_status(struct d + DMEMIT(" meta_device:%s", ic->meta_dev->name); + if (ic->sectors_per_block != 1) + DMEMIT(" block_size:%u", ic->sectors_per_block << SECTOR_SHIFT); +- if (ic->recalculate_flag) ++ if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) + DMEMIT(" recalculate"); + DMEMIT(" journal_sectors:%u", ic->initial_sectors - SB_SECTORS); + DMEMIT(" interleave_sectors:%u", 1U << ic->sb->log2_interleave_sectors); diff --git a/queue-5.4/dm-integrity-fix-recalculation-when-moving-from-journal-mode-to-bitmap-mode.patch b/queue-5.4/dm-integrity-fix-recalculation-when-moving-from-journal-mode-to-bitmap-mode.patch new file mode 100644 index 00000000000..3d8b185642c --- /dev/null +++ b/queue-5.4/dm-integrity-fix-recalculation-when-moving-from-journal-mode-to-bitmap-mode.patch @@ -0,0 +1,55 @@ +From d5bdf66108419cdb39da361b58ded661c29ff66e Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Fri, 7 Feb 2020 11:42:30 -0500 +Subject: dm integrity: fix recalculation when moving from journal mode to bitmap mode + +From: Mikulas Patocka + +commit d5bdf66108419cdb39da361b58ded661c29ff66e upstream. + +If we resume a device in bitmap mode and the on-disk format is in journal +mode, we must recalculate anything above ic->sb->recalc_sector. Otherwise, +there would be non-recalculated blocks which would cause I/O errors. + +Fixes: 468dfca38b1a ("dm integrity: add a bitmap mode") +Cc: stable@vger.kernel.org # v5.2+ +Signed-off-by: Mikulas Patocka +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-integrity.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -2883,17 +2883,24 @@ static void dm_integrity_resume(struct d + } else { + replay_journal(ic); + if (ic->mode == 'B') { +- int mode; + ic->sb->flags |= cpu_to_le32(SB_FLAG_DIRTY_BITMAP); + ic->sb->log2_blocks_per_bitmap_bit = ic->log2_blocks_per_bitmap_bit; + r = sync_rw_sb(ic, REQ_OP_WRITE, REQ_FUA); + if (unlikely(r)) + dm_integrity_io_error(ic, "writing superblock", r); + +- mode = ic->recalculate_flag ? BITMAP_OP_SET : BITMAP_OP_CLEAR; +- block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, mode); +- block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, mode); +- block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, mode); ++ block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR); ++ block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR); ++ block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR); ++ if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) && ++ le64_to_cpu(ic->sb->recalc_sector) < ic->provided_data_sectors) { ++ block_bitmap_op(ic, ic->journal, le64_to_cpu(ic->sb->recalc_sector), ++ ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET); ++ block_bitmap_op(ic, ic->recalc_bitmap, le64_to_cpu(ic->sb->recalc_sector), ++ ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET); ++ block_bitmap_op(ic, ic->may_write_bitmap, le64_to_cpu(ic->sb->recalc_sector), ++ ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET); ++ } + rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, 0, + ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL); + } diff --git a/queue-5.4/dm-report-suspended-device-during-destroy.patch b/queue-5.4/dm-report-suspended-device-during-destroy.patch new file mode 100644 index 00000000000..85e219f2cc4 --- /dev/null +++ b/queue-5.4/dm-report-suspended-device-during-destroy.patch @@ -0,0 +1,139 @@ +From adc0daad366b62ca1bce3e2958a40b0b71a8b8b3 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Mon, 24 Feb 2020 10:20:28 +0100 +Subject: dm: report suspended device during destroy + +From: Mikulas Patocka + +commit adc0daad366b62ca1bce3e2958a40b0b71a8b8b3 upstream. + +The function dm_suspended returns true if the target is suspended. +However, when the target is being suspended during unload, it returns +false. + +An example where this is a problem: the test "!dm_suspended(wc->ti)" in +writecache_writeback is not sufficient, because dm_suspended returns +zero while writecache_suspend is in progress. As is, without an +enhanced dm_suspended, simply switching from flush_workqueue to +drain_workqueue still emits warnings: +workqueue writecache-writeback: drain_workqueue() isn't complete after 10 tries +workqueue writecache-writeback: drain_workqueue() isn't complete after 100 tries +workqueue writecache-writeback: drain_workqueue() isn't complete after 200 tries +workqueue writecache-writeback: drain_workqueue() isn't complete after 300 tries +workqueue writecache-writeback: drain_workqueue() isn't complete after 400 tries + +writecache_suspend calls flush_workqueue(wc->writeback_wq) - this function +flushes the current work. However, the workqueue may re-queue itself and +flush_workqueue doesn't wait for re-queued works to finish. Because of +this - the function writecache_writeback continues execution after the +device was suspended and then concurrently with writecache_dtr, causing +a crash in writecache_writeback. + +We must use drain_workqueue - that waits until the work and all re-queued +works finish. + +As a prereq for switching to drain_workqueue, this commit fixes +dm_suspended to return true after the presuspend hook and before the +postsuspend hook - just like during a normal suspend. It allows +simplifying the dm-integrity and dm-writecache targets so that they +don't have to maintain suspended flags on their own. + +With this change use of drain_workqueue() can be used effectively. This +change was tested with the lvm2 testsuite and cryptsetup testsuite and +the are no regressions. + +Fixes: 48debafe4f2f ("dm: add writecache target") +Cc: stable@vger.kernel.org # 4.18+ +Reported-by: Corey Marthaler +Signed-off-by: Mikulas Patocka +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-integrity.c | 12 +++++------- + drivers/md/dm-writecache.c | 2 +- + drivers/md/dm.c | 1 + + 3 files changed, 7 insertions(+), 8 deletions(-) + +--- a/drivers/md/dm-integrity.c ++++ b/drivers/md/dm-integrity.c +@@ -199,12 +199,13 @@ struct dm_integrity_c { + __u8 log2_blocks_per_bitmap_bit; + + unsigned char mode; +- int suspending; + + int failed; + + struct crypto_shash *internal_hash; + ++ struct dm_target *ti; ++ + /* these variables are locked with endio_wait.lock */ + struct rb_root in_progress; + struct list_head wait_list; +@@ -2311,7 +2312,7 @@ static void integrity_writer(struct work + unsigned prev_free_sectors; + + /* the following test is not needed, but it tests the replay code */ +- if (READ_ONCE(ic->suspending) && !ic->meta_dev) ++ if (unlikely(dm_suspended(ic->ti)) && !ic->meta_dev) + return; + + spin_lock_irq(&ic->endio_wait.lock); +@@ -2372,7 +2373,7 @@ static void integrity_recalc(struct work + + next_chunk: + +- if (unlikely(READ_ONCE(ic->suspending))) ++ if (unlikely(dm_suspended(ic->ti))) + goto unlock_ret; + + range.logical_sector = le64_to_cpu(ic->sb->recalc_sector); +@@ -2800,8 +2801,6 @@ static void dm_integrity_postsuspend(str + + del_timer_sync(&ic->autocommit_timer); + +- WRITE_ONCE(ic->suspending, 1); +- + if (ic->recalc_wq) + drain_workqueue(ic->recalc_wq); + +@@ -2830,8 +2829,6 @@ static void dm_integrity_postsuspend(str + #endif + } + +- WRITE_ONCE(ic->suspending, 0); +- + BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress)); + + ic->journal_uptodate = true; +@@ -3615,6 +3612,7 @@ static int dm_integrity_ctr(struct dm_ta + } + ti->private = ic; + ti->per_io_data_size = sizeof(struct dm_integrity_io); ++ ic->ti = ti; + + ic->in_progress = RB_ROOT; + INIT_LIST_HEAD(&ic->wait_list); +--- a/drivers/md/dm-writecache.c ++++ b/drivers/md/dm-writecache.c +@@ -838,7 +838,7 @@ static void writecache_suspend(struct dm + } + wc_unlock(wc); + +- flush_workqueue(wc->writeback_wq); ++ drain_workqueue(wc->writeback_wq); + + wc_lock(wc); + if (flush_on_suspend) +--- a/drivers/md/dm.c ++++ b/drivers/md/dm.c +@@ -2389,6 +2389,7 @@ static void __dm_destroy(struct mapped_d + map = dm_get_live_table(md, &srcu_idx); + if (!dm_suspended_md(md)) { + dm_table_presuspend_targets(map); ++ set_bit(DMF_SUSPENDED, &md->flags); + dm_table_postsuspend_targets(map); + } + /* dm_put_live_table must be before msleep, otherwise deadlock is possible */ diff --git a/queue-5.4/dm-writecache-verify-watermark-during-resume.patch b/queue-5.4/dm-writecache-verify-watermark-during-resume.patch new file mode 100644 index 00000000000..7724677d72e --- /dev/null +++ b/queue-5.4/dm-writecache-verify-watermark-during-resume.patch @@ -0,0 +1,57 @@ +From 41c526c5af46d4c4dab7f72c99000b7fac0b9702 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Mon, 24 Feb 2020 10:20:30 +0100 +Subject: dm writecache: verify watermark during resume + +From: Mikulas Patocka + +commit 41c526c5af46d4c4dab7f72c99000b7fac0b9702 upstream. + +Verify the watermark upon resume - so that if the target is reloaded +with lower watermark, it will start the cleanup process immediately. + +Fixes: 48debafe4f2f ("dm: add writecache target") +Cc: stable@vger.kernel.org # 4.18+ +Signed-off-by: Mikulas Patocka +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-writecache.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/md/dm-writecache.c ++++ b/drivers/md/dm-writecache.c +@@ -625,6 +625,12 @@ static void writecache_add_to_freelist(s + wc->freelist_size++; + } + ++static inline void writecache_verify_watermark(struct dm_writecache *wc) ++{ ++ if (unlikely(wc->freelist_size + wc->writeback_size <= wc->freelist_high_watermark)) ++ queue_work(wc->writeback_wq, &wc->writeback_work); ++} ++ + static struct wc_entry *writecache_pop_from_freelist(struct dm_writecache *wc) + { + struct wc_entry *e; +@@ -646,8 +652,8 @@ static struct wc_entry *writecache_pop_f + list_del(&e->lru); + } + wc->freelist_size--; +- if (unlikely(wc->freelist_size + wc->writeback_size <= wc->freelist_high_watermark)) +- queue_work(wc->writeback_wq, &wc->writeback_work); ++ ++ writecache_verify_watermark(wc); + + return e; + } +@@ -961,6 +967,8 @@ erase_this: + writecache_commit_flushed(wc, false); + } + ++ writecache_verify_watermark(wc); ++ + wc_unlock(wc); + } + diff --git a/queue-5.4/dm-zoned-fix-reference-counter-initial-value-of-chunk-works.patch b/queue-5.4/dm-zoned-fix-reference-counter-initial-value-of-chunk-works.patch new file mode 100644 index 00000000000..c61e4038079 --- /dev/null +++ b/queue-5.4/dm-zoned-fix-reference-counter-initial-value-of-chunk-works.patch @@ -0,0 +1,107 @@ +From ee63634bae02e13c8c0df1209a6a0ca5326f3189 Mon Sep 17 00:00:00 2001 +From: Shin'ichiro Kawasaki +Date: Thu, 27 Feb 2020 09:18:52 +0900 +Subject: dm zoned: Fix reference counter initial value of chunk works + +From: Shin'ichiro Kawasaki + +commit ee63634bae02e13c8c0df1209a6a0ca5326f3189 upstream. + +Dm-zoned initializes reference counters of new chunk works with zero +value and refcount_inc() is called to increment the counter. However, the +refcount_inc() function handles the addition to zero value as an error +and triggers the warning as follows: + +refcount_t: addition on 0; use-after-free. +WARNING: CPU: 7 PID: 1506 at lib/refcount.c:25 refcount_warn_saturate+0x68/0xf0 +... +CPU: 7 PID: 1506 Comm: systemd-udevd Not tainted 5.4.0+ #134 +... +Call Trace: + dmz_map+0x2d2/0x350 [dm_zoned] + __map_bio+0x42/0x1a0 + __split_and_process_non_flush+0x14a/0x1b0 + __split_and_process_bio+0x83/0x240 + ? kmem_cache_alloc+0x165/0x220 + dm_process_bio+0x90/0x230 + ? generic_make_request_checks+0x2e7/0x680 + dm_make_request+0x3e/0xb0 + generic_make_request+0xcf/0x320 + ? memcg_drain_all_list_lrus+0x1c0/0x1c0 + submit_bio+0x3c/0x160 + ? guard_bio_eod+0x2c/0x130 + mpage_readpages+0x182/0x1d0 + ? bdev_evict_inode+0xf0/0xf0 + read_pages+0x6b/0x1b0 + __do_page_cache_readahead+0x1ba/0x1d0 + force_page_cache_readahead+0x93/0x100 + generic_file_read_iter+0x83a/0xe40 + ? __seccomp_filter+0x7b/0x670 + new_sync_read+0x12a/0x1c0 + vfs_read+0x9d/0x150 + ksys_read+0x5f/0xe0 + do_syscall_64+0x5b/0x180 + entry_SYSCALL_64_after_hwframe+0x44/0xa9 +... + +After this warning, following refcount API calls for the counter all fail +to change the counter value. + +Fix this by setting the initial reference counter value not zero but one +for the new chunk works. Instead, do not call refcount_inc() via +dmz_get_chunk_work() for the new chunks works. + +The failure was observed with linux version 5.4 with CONFIG_REFCOUNT_FULL +enabled. Refcount rework was merged to linux version 5.5 by the +commit 168829ad09ca ("Merge branch 'locking-core-for-linus' of +git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip"). After this +commit, CONFIG_REFCOUNT_FULL was removed and the failure was observed +regardless of kernel configuration. + +Linux version 4.20 merged the commit 092b5648760a ("dm zoned: target: use +refcount_t for dm zoned reference counters"). Before this commit, dm +zoned used atomic_t APIs which does not check addition to zero, then this +fix is not necessary. + +Fixes: 092b5648760a ("dm zoned: target: use refcount_t for dm zoned reference counters") +Cc: stable@vger.kernel.org # 5.4+ +Signed-off-by: Shin'ichiro Kawasaki +Reviewed-by: Damien Le Moal +Signed-off-by: Mike Snitzer +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-zoned-target.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/md/dm-zoned-target.c ++++ b/drivers/md/dm-zoned-target.c +@@ -533,8 +533,9 @@ static int dmz_queue_chunk_work(struct d + + /* Get the BIO chunk work. If one is not active yet, create one */ + cw = radix_tree_lookup(&dmz->chunk_rxtree, chunk); +- if (!cw) { +- ++ if (cw) { ++ dmz_get_chunk_work(cw); ++ } else { + /* Create a new chunk work */ + cw = kmalloc(sizeof(struct dm_chunk_work), GFP_NOIO); + if (unlikely(!cw)) { +@@ -543,7 +544,7 @@ static int dmz_queue_chunk_work(struct d + } + + INIT_WORK(&cw->work, dmz_chunk_work); +- refcount_set(&cw->refcount, 0); ++ refcount_set(&cw->refcount, 1); + cw->target = dmz; + cw->chunk = chunk; + bio_list_init(&cw->bio_list); +@@ -556,7 +557,6 @@ static int dmz_queue_chunk_work(struct d + } + + bio_list_add(&cw->bio_list, bio); +- dmz_get_chunk_work(cw); + + dmz_reclaim_bio_acc(dmz->reclaim); + if (queue_work(dmz->chunk_wq, &cw->work)) diff --git a/queue-5.4/dmaengine-tegra-apb-fix-use-after-free.patch b/queue-5.4/dmaengine-tegra-apb-fix-use-after-free.patch new file mode 100644 index 00000000000..253584b2283 --- /dev/null +++ b/queue-5.4/dmaengine-tegra-apb-fix-use-after-free.patch @@ -0,0 +1,62 @@ +From 94788af4ed039476ff3527b0e6a12c1dc42cb022 Mon Sep 17 00:00:00 2001 +From: Dmitry Osipenko +Date: Sun, 9 Feb 2020 19:33:38 +0300 +Subject: dmaengine: tegra-apb: Fix use-after-free + +From: Dmitry Osipenko + +commit 94788af4ed039476ff3527b0e6a12c1dc42cb022 upstream. + +I was doing some experiments with I2C and noticed that Tegra APB DMA +driver crashes sometime after I2C DMA transfer termination. The crash +happens because tegra_dma_terminate_all() bails out immediately if pending +list is empty, and thus, it doesn't release the half-completed descriptors +which are getting re-used before ISR tasklet kicks-in. + + tegra-i2c 7000c400.i2c: DMA transfer timeout + elants_i2c 0-0010: elants_i2c_irq: failed to read data: -110 + ------------[ cut here ]------------ + WARNING: CPU: 0 PID: 142 at lib/list_debug.c:45 __list_del_entry_valid+0x45/0xac + list_del corruption, ddbaac44->next is LIST_POISON1 (00000100) + Modules linked in: + CPU: 0 PID: 142 Comm: kworker/0:2 Not tainted 5.5.0-rc2-next-20191220-00175-gc3605715758d-dirty #538 + Hardware name: NVIDIA Tegra SoC (Flattened Device Tree) + Workqueue: events_freezable_power_ thermal_zone_device_check + [] (unwind_backtrace) from [] (show_stack+0x11/0x14) + [] (show_stack) from [] (dump_stack+0x85/0x94) + [] (dump_stack) from [] (__warn+0xc1/0xc4) + [] (__warn) from [] (warn_slowpath_fmt+0x61/0x78) + [] (warn_slowpath_fmt) from [] (__list_del_entry_valid+0x45/0xac) + [] (__list_del_entry_valid) from [] (tegra_dma_tasklet+0x5b/0x154) + [] (tegra_dma_tasklet) from [] (tasklet_action_common.constprop.0+0x41/0x7c) + [] (tasklet_action_common.constprop.0) from [] (__do_softirq+0xd3/0x2a8) + [] (__do_softirq) from [] (irq_exit+0x7b/0x98) + [] (irq_exit) from [] (__handle_domain_irq+0x45/0x80) + [] (__handle_domain_irq) from [] (gic_handle_irq+0x45/0x7c) + [] (gic_handle_irq) from [] (__irq_svc+0x65/0x94) + Exception stack(0xde2ebb90 to 0xde2ebbd8) + +Signed-off-by: Dmitry Osipenko +Acked-by: Jon Hunter +Cc: +Link: https://lore.kernel.org/r/20200209163356.6439-2-digetx@gmail.com +Signed-off-by: Vinod Koul +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma/tegra20-apb-dma.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- a/drivers/dma/tegra20-apb-dma.c ++++ b/drivers/dma/tegra20-apb-dma.c +@@ -756,10 +756,6 @@ static int tegra_dma_terminate_all(struc + bool was_busy; + + spin_lock_irqsave(&tdc->lock, flags); +- if (list_empty(&tdc->pending_sg_req)) { +- spin_unlock_irqrestore(&tdc->lock, flags); +- return 0; +- } + + if (!tdc->busy) + goto skip_dma_stop; diff --git a/queue-5.4/dmaengine-tegra-apb-prevent-race-conditions-of-tasklet-vs-free-list.patch b/queue-5.4/dmaengine-tegra-apb-prevent-race-conditions-of-tasklet-vs-free-list.patch new file mode 100644 index 00000000000..952a9298032 --- /dev/null +++ b/queue-5.4/dmaengine-tegra-apb-prevent-race-conditions-of-tasklet-vs-free-list.patch @@ -0,0 +1,37 @@ +From c33ee1301c393a241d6424e36eff1071811b1064 Mon Sep 17 00:00:00 2001 +From: Dmitry Osipenko +Date: Sun, 9 Feb 2020 19:33:39 +0300 +Subject: dmaengine: tegra-apb: Prevent race conditions of tasklet vs free list + +From: Dmitry Osipenko + +commit c33ee1301c393a241d6424e36eff1071811b1064 upstream. + +The interrupt handler puts a half-completed DMA descriptor on a free list +and then schedules tasklet to process bottom half of the descriptor that +executes client's callback, this creates possibility to pick up the busy +descriptor from the free list. Thus, let's disallow descriptor's re-use +until it is fully processed. + +Signed-off-by: Dmitry Osipenko +Acked-by: Jon Hunter +Cc: +Link: https://lore.kernel.org/r/20200209163356.6439-3-digetx@gmail.com +Signed-off-by: Vinod Koul +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/dma/tegra20-apb-dma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/dma/tegra20-apb-dma.c ++++ b/drivers/dma/tegra20-apb-dma.c +@@ -281,7 +281,7 @@ static struct tegra_dma_desc *tegra_dma_ + + /* Do not allocate if desc are waiting for ack */ + list_for_each_entry(dma_desc, &tdc->free_dma_desc, node) { +- if (async_tx_test_ack(&dma_desc->txd)) { ++ if (async_tx_test_ack(&dma_desc->txd) && !dma_desc->cb_count) { + list_del(&dma_desc->node); + spin_unlock_irqrestore(&tdc->lock, flags); + dma_desc->txd.flags = 0; diff --git a/queue-5.4/series b/queue-5.4/series index fe11ca907d1..4a3a823c81b 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -101,3 +101,13 @@ s390-pci-fix-unexpected-write-combine-on-resource.patch s390-mm-fix-panic-in-gup_fast-on-large-pud.patch dmaengine-imx-sdma-fix-context-cache.patch dmaengine-imx-sdma-fix-the-event-id-check-to-include-rx-event-for-uart6.patch +dmaengine-tegra-apb-fix-use-after-free.patch +dmaengine-tegra-apb-prevent-race-conditions-of-tasklet-vs-free-list.patch +dm-integrity-fix-recalculation-when-moving-from-journal-mode-to-bitmap-mode.patch +dm-integrity-fix-a-deadlock-due-to-offloading-to-an-incorrect-workqueue.patch +dm-integrity-fix-invalid-table-returned-due-to-argument-count-mismatch.patch +dm-cache-fix-a-crash-due-to-incorrect-work-item-cancelling.patch +dm-report-suspended-device-during-destroy.patch +dm-writecache-verify-watermark-during-resume.patch +dm-zoned-fix-reference-counter-initial-value-of-chunk-works.patch +dm-fix-congested_fn-for-request-based-device.patch