]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.5-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 9 Mar 2020 20:14:08 +0000 (21:14 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 9 Mar 2020 20:14:08 +0000 (21:14 +0100)
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

queue-5.5/dm-cache-fix-a-crash-due-to-incorrect-work-item-cancelling.patch [new file with mode: 0644]
queue-5.5/dm-fix-congested_fn-for-request-based-device.patch [new file with mode: 0644]
queue-5.5/dm-integrity-fix-a-deadlock-due-to-offloading-to-an-incorrect-workqueue.patch [new file with mode: 0644]
queue-5.5/dm-integrity-fix-invalid-table-returned-due-to-argument-count-mismatch.patch [new file with mode: 0644]
queue-5.5/dm-integrity-fix-recalculation-when-moving-from-journal-mode-to-bitmap-mode.patch [new file with mode: 0644]
queue-5.5/dm-report-suspended-device-during-destroy.patch [new file with mode: 0644]
queue-5.5/dm-writecache-verify-watermark-during-resume.patch [new file with mode: 0644]
queue-5.5/dm-zoned-fix-reference-counter-initial-value-of-chunk-works.patch [new file with mode: 0644]
queue-5.5/dmaengine-tegra-apb-fix-use-after-free.patch [new file with mode: 0644]
queue-5.5/dmaengine-tegra-apb-prevent-race-conditions-of-tasklet-vs-free-list.patch [new file with mode: 0644]
queue-5.5/series

diff --git a/queue-5.5/dm-cache-fix-a-crash-due-to-incorrect-work-item-cancelling.patch b/queue-5.5/dm-cache-fix-a-crash-due-to-incorrect-work-item-cancelling.patch
new file mode 100644 (file)
index 0000000..ec4a6d8
--- /dev/null
@@ -0,0 +1,51 @@
+From 7cdf6a0aae1cccf5167f3f04ecddcf648b78e289 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Wed, 19 Feb 2020 10:25:45 -0500
+Subject: dm cache: fix a crash due to incorrect work item cancelling
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -2846,8 +2846,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.5/dm-fix-congested_fn-for-request-based-device.patch b/queue-5.5/dm-fix-congested_fn-for-request-based-device.patch
new file mode 100644 (file)
index 0000000..7af8d8a
--- /dev/null
@@ -0,0 +1,80 @@
+From 974f51e8633f0f3f33e8f86bbb5ae66758aa63c7 Mon Sep 17 00:00:00 2001
+From: Hou Tao <houtao1@huawei.com>
+Date: Tue, 3 Mar 2020 16:45:01 +0800
+Subject: dm: fix congested_fn for request-based device
+
+From: Hou Tao <houtao1@huawei.com>
+
+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 <houtao1@huawei.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/dm.c |   21 ++++++++++-----------
+ 1 file changed, 10 insertions(+), 11 deletions(-)
+
+--- a/drivers/md/dm.c
++++ b/drivers/md/dm.c
+@@ -1788,7 +1788,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)
+@@ -1854,15 +1855,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)
+@@ -2249,6 +2241,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
+  */
+@@ -2265,11 +2263,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.5/dm-integrity-fix-a-deadlock-due-to-offloading-to-an-incorrect-workqueue.patch b/queue-5.5/dm-integrity-fix-a-deadlock-due-to-offloading-to-an-incorrect-workqueue.patch
new file mode 100644 (file)
index 0000000..4897fbf
--- /dev/null
@@ -0,0 +1,113 @@
+From 53770f0ec5fd417429775ba006bc4abe14002335 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+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 <mpatocka@redhat.com>
+
+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 <heinzm@redhat.com>
+Tested-by: Heinz Mauelshagen <heinzm@redhat.com>
+Signed-off-by: Heinz Mauelshagen <heinzm@redhat.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -212,6 +212,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];
+@@ -1439,7 +1440,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);
+@@ -1865,7 +1866,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;
+       }
+@@ -2501,7 +2502,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);
+@@ -2524,7 +2525,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);
+@@ -3843,6 +3844,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";
+@@ -4147,6 +4156,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.5/dm-integrity-fix-invalid-table-returned-due-to-argument-count-mismatch.patch b/queue-5.5/dm-integrity-fix-invalid-table-returned-due-to-argument-count-mismatch.patch
new file mode 100644 (file)
index 0000000..70d634d
--- /dev/null
@@ -0,0 +1,36 @@
+From 7fc2e47f40dd77ab1fcbda6db89614a0173d89c7 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Mon, 17 Feb 2020 08:11:35 -0500
+Subject: dm integrity: fix invalid table returned due to argument count mismatch
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <okozina@redhat.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -2975,7 +2975,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.5/dm-integrity-fix-recalculation-when-moving-from-journal-mode-to-bitmap-mode.patch b/queue-5.5/dm-integrity-fix-recalculation-when-moving-from-journal-mode-to-bitmap-mode.patch
new file mode 100644 (file)
index 0000000..43f837b
--- /dev/null
@@ -0,0 +1,55 @@
+From d5bdf66108419cdb39da361b58ded661c29ff66e Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+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 <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -2888,17 +2888,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.5/dm-report-suspended-device-during-destroy.patch b/queue-5.5/dm-report-suspended-device-during-destroy.patch
new file mode 100644 (file)
index 0000000..6632da1
--- /dev/null
@@ -0,0 +1,139 @@
+From adc0daad366b62ca1bce3e2958a40b0b71a8b8b3 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Mon, 24 Feb 2020 10:20:28 +0100
+Subject: dm: report suspended device during destroy
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <cmarthal@redhat.com>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -201,12 +201,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;
+@@ -2316,7 +2317,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);
+@@ -2377,7 +2378,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);
+@@ -2805,8 +2806,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);
+@@ -2835,8 +2834,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;
+@@ -3631,6 +3628,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
+@@ -2368,6 +2368,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.5/dm-writecache-verify-watermark-during-resume.patch b/queue-5.5/dm-writecache-verify-watermark-during-resume.patch
new file mode 100644 (file)
index 0000000..7724677
--- /dev/null
@@ -0,0 +1,57 @@
+From 41c526c5af46d4c4dab7f72c99000b7fac0b9702 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Mon, 24 Feb 2020 10:20:30 +0100
+Subject: dm writecache: verify watermark during resume
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+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 <mpatocka@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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.5/dm-zoned-fix-reference-counter-initial-value-of-chunk-works.patch b/queue-5.5/dm-zoned-fix-reference-counter-initial-value-of-chunk-works.patch
new file mode 100644 (file)
index 0000000..c61e403
--- /dev/null
@@ -0,0 +1,107 @@
+From ee63634bae02e13c8c0df1209a6a0ca5326f3189 Mon Sep 17 00:00:00 2001
+From: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Date: Thu, 27 Feb 2020 09:18:52 +0900
+Subject: dm zoned: Fix reference counter initial value of chunk works
+
+From: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+
+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 <shinichiro.kawasaki@wdc.com>
+Reviewed-by: Damien Le Moal <damien.lemoal@wdc.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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.5/dmaengine-tegra-apb-fix-use-after-free.patch b/queue-5.5/dmaengine-tegra-apb-fix-use-after-free.patch
new file mode 100644 (file)
index 0000000..253584b
--- /dev/null
@@ -0,0 +1,62 @@
+From 94788af4ed039476ff3527b0e6a12c1dc42cb022 Mon Sep 17 00:00:00 2001
+From: Dmitry Osipenko <digetx@gmail.com>
+Date: Sun, 9 Feb 2020 19:33:38 +0300
+Subject: dmaengine: tegra-apb: Fix use-after-free
+
+From: Dmitry Osipenko <digetx@gmail.com>
+
+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
+ [<c010e5c5>] (unwind_backtrace) from [<c010a1c5>] (show_stack+0x11/0x14)
+ [<c010a1c5>] (show_stack) from [<c0973925>] (dump_stack+0x85/0x94)
+ [<c0973925>] (dump_stack) from [<c011f529>] (__warn+0xc1/0xc4)
+ [<c011f529>] (__warn) from [<c011f7e9>] (warn_slowpath_fmt+0x61/0x78)
+ [<c011f7e9>] (warn_slowpath_fmt) from [<c042497d>] (__list_del_entry_valid+0x45/0xac)
+ [<c042497d>] (__list_del_entry_valid) from [<c047a87f>] (tegra_dma_tasklet+0x5b/0x154)
+ [<c047a87f>] (tegra_dma_tasklet) from [<c0124799>] (tasklet_action_common.constprop.0+0x41/0x7c)
+ [<c0124799>] (tasklet_action_common.constprop.0) from [<c01022ab>] (__do_softirq+0xd3/0x2a8)
+ [<c01022ab>] (__do_softirq) from [<c0124683>] (irq_exit+0x7b/0x98)
+ [<c0124683>] (irq_exit) from [<c0168c19>] (__handle_domain_irq+0x45/0x80)
+ [<c0168c19>] (__handle_domain_irq) from [<c043e429>] (gic_handle_irq+0x45/0x7c)
+ [<c043e429>] (gic_handle_irq) from [<c0101aa5>] (__irq_svc+0x65/0x94)
+ Exception stack(0xde2ebb90 to 0xde2ebbd8)
+
+Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
+Acked-by: Jon Hunter <jonathanh@nvidia.com>
+Cc: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20200209163356.6439-2-digetx@gmail.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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.5/dmaengine-tegra-apb-prevent-race-conditions-of-tasklet-vs-free-list.patch b/queue-5.5/dmaengine-tegra-apb-prevent-race-conditions-of-tasklet-vs-free-list.patch
new file mode 100644 (file)
index 0000000..952a929
--- /dev/null
@@ -0,0 +1,37 @@
+From c33ee1301c393a241d6424e36eff1071811b1064 Mon Sep 17 00:00:00 2001
+From: Dmitry Osipenko <digetx@gmail.com>
+Date: Sun, 9 Feb 2020 19:33:39 +0300
+Subject: dmaengine: tegra-apb: Prevent race conditions of tasklet vs free list
+
+From: Dmitry Osipenko <digetx@gmail.com>
+
+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 <digetx@gmail.com>
+Acked-by: Jon Hunter <jonathanh@nvidia.com>
+Cc: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20200209163356.6439-3-digetx@gmail.com
+Signed-off-by: Vinod Koul <vkoul@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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;
index 6fac66b313b67f617b656226f5f91291581eee89..7ba0c74d00ce3207345ec47cf2007b37d2cfdc2d 100644 (file)
@@ -115,3 +115,13 @@ drm-amdgpu-disable-3d-pipe-1-on-navi1x.patch
 drm-amd-powerplay-fix-pre-check-condition-for-setting-clock-range.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