]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 7 Feb 2020 12:55:55 +0000 (13:55 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 7 Feb 2020 12:55:55 +0000 (13:55 +0100)
added patches:
dm-writecache-fix-incorrect-flush-sequence-when-doing-ssd-mode-commit.patch

queue-4.19/dm-writecache-fix-incorrect-flush-sequence-when-doing-ssd-mode-commit.patch [new file with mode: 0644]
queue-4.19/series

diff --git a/queue-4.19/dm-writecache-fix-incorrect-flush-sequence-when-doing-ssd-mode-commit.patch b/queue-4.19/dm-writecache-fix-incorrect-flush-sequence-when-doing-ssd-mode-commit.patch
new file mode 100644 (file)
index 0000000..67c1510
--- /dev/null
@@ -0,0 +1,166 @@
+From aa9509209c5ac2f0b35d01a922bf9ae072d0c2fc Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Wed, 8 Jan 2020 10:46:05 -0500
+Subject: dm writecache: fix incorrect flush sequence when doing SSD mode commit
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit aa9509209c5ac2f0b35d01a922bf9ae072d0c2fc upstream.
+
+When committing state, the function writecache_flush does the following:
+1. write metadata (writecache_commit_flushed)
+2. flush disk cache (writecache_commit_flushed)
+3. wait for data writes to complete (writecache_wait_for_ios)
+4. increase superblock seq_count
+5. write the superblock
+6. flush disk cache
+
+It may happen that at step 3, when we wait for some write to finish, the
+disk may report the write as finished, but the write only hit the disk
+cache and it is not yet stored in persistent storage. At step 5 we write
+the superblock - it may happen that the superblock is written before the
+write that we waited for in step 3. If the machine crashes, it may result
+in incorrect data being returned after reboot.
+
+In order to fix the bug, we must swap steps 2 and 3 in the above sequence,
+so that we first wait for writes to complete and then flush the disk
+cache.
+
+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 |   41 +++++++++++++++++++++--------------------
+ 1 file changed, 21 insertions(+), 20 deletions(-)
+
+--- a/drivers/md/dm-writecache.c
++++ b/drivers/md/dm-writecache.c
+@@ -447,7 +447,13 @@ static void writecache_notify_io(unsigne
+               complete(&endio->c);
+ }
+-static void ssd_commit_flushed(struct dm_writecache *wc)
++static void writecache_wait_for_ios(struct dm_writecache *wc, int direction)
++{
++      wait_event(wc->bio_in_progress_wait[direction],
++                 !atomic_read(&wc->bio_in_progress[direction]));
++}
++
++static void ssd_commit_flushed(struct dm_writecache *wc, bool wait_for_ios)
+ {
+       struct dm_io_region region;
+       struct dm_io_request req;
+@@ -493,17 +499,20 @@ static void ssd_commit_flushed(struct dm
+       writecache_notify_io(0, &endio);
+       wait_for_completion_io(&endio.c);
++      if (wait_for_ios)
++              writecache_wait_for_ios(wc, WRITE);
++
+       writecache_disk_flush(wc, wc->ssd_dev);
+       memset(wc->dirty_bitmap, 0, wc->dirty_bitmap_size);
+ }
+-static void writecache_commit_flushed(struct dm_writecache *wc)
++static void writecache_commit_flushed(struct dm_writecache *wc, bool wait_for_ios)
+ {
+       if (WC_MODE_PMEM(wc))
+               wmb();
+       else
+-              ssd_commit_flushed(wc);
++              ssd_commit_flushed(wc, wait_for_ios);
+ }
+ static void writecache_disk_flush(struct dm_writecache *wc, struct dm_dev *dev)
+@@ -527,12 +536,6 @@ static void writecache_disk_flush(struct
+               writecache_error(wc, r, "error flushing metadata: %d", r);
+ }
+-static void writecache_wait_for_ios(struct dm_writecache *wc, int direction)
+-{
+-      wait_event(wc->bio_in_progress_wait[direction],
+-                 !atomic_read(&wc->bio_in_progress[direction]));
+-}
+-
+ #define WFE_RETURN_FOLLOWING  1
+ #define WFE_LOWEST_SEQ                2
+@@ -730,14 +733,12 @@ static void writecache_flush(struct dm_w
+               e = e2;
+               cond_resched();
+       }
+-      writecache_commit_flushed(wc);
+-
+-      writecache_wait_for_ios(wc, WRITE);
++      writecache_commit_flushed(wc, true);
+       wc->seq_count++;
+       pmem_assign(sb(wc)->seq_count, cpu_to_le64(wc->seq_count));
+       writecache_flush_region(wc, &sb(wc)->seq_count, sizeof sb(wc)->seq_count);
+-      writecache_commit_flushed(wc);
++      writecache_commit_flushed(wc, false);
+       wc->overwrote_committed = false;
+@@ -761,7 +762,7 @@ static void writecache_flush(struct dm_w
+       }
+       if (need_flush_after_free)
+-              writecache_commit_flushed(wc);
++              writecache_commit_flushed(wc, false);
+ }
+ static void writecache_flush_work(struct work_struct *work)
+@@ -814,7 +815,7 @@ static void writecache_discard(struct dm
+       }
+       if (discarded_something)
+-              writecache_commit_flushed(wc);
++              writecache_commit_flushed(wc, false);
+ }
+ static bool writecache_wait_for_writeback(struct dm_writecache *wc)
+@@ -963,7 +964,7 @@ erase_this:
+       if (need_flush) {
+               writecache_flush_all_metadata(wc);
+-              writecache_commit_flushed(wc);
++              writecache_commit_flushed(wc, false);
+       }
+       wc_unlock(wc);
+@@ -1347,7 +1348,7 @@ static void __writecache_endio_pmem(stru
+                       wc->writeback_size--;
+                       n_walked++;
+                       if (unlikely(n_walked >= ENDIO_LATENCY)) {
+-                              writecache_commit_flushed(wc);
++                              writecache_commit_flushed(wc, false);
+                               wc_unlock(wc);
+                               wc_lock(wc);
+                               n_walked = 0;
+@@ -1428,7 +1429,7 @@ pop_from_list:
+                       writecache_wait_for_ios(wc, READ);
+               }
+-              writecache_commit_flushed(wc);
++              writecache_commit_flushed(wc, false);
+               wc_unlock(wc);
+       }
+@@ -1759,10 +1760,10 @@ static int init_memory(struct dm_writeca
+               write_original_sector_seq_count(wc, &wc->entries[b], -1, -1);
+       writecache_flush_all_metadata(wc);
+-      writecache_commit_flushed(wc);
++      writecache_commit_flushed(wc, false);
+       pmem_assign(sb(wc)->magic, cpu_to_le32(MEMORY_SUPERBLOCK_MAGIC));
+       writecache_flush_region(wc, &sb(wc)->magic, sizeof sb(wc)->magic);
+-      writecache_commit_flushed(wc);
++      writecache_commit_flushed(wc, false);
+       return 0;
+ }
index 7f8c873fec35a8cce9b4265a396feae85b0fae89..028fdc9c05a103c1268e3ff57482631d35b23be6 100644 (file)
@@ -87,3 +87,4 @@ dm-zoned-support-zone-sizes-smaller-than-128mib.patch
 dm-space-map-common-fix-to-ensure-new-block-isn-t-already-in-use.patch
 dm-crypt-fix-benbi-iv-constructor-crash-if-used-in-authenticated-mode.patch
 dm-fix-potential-for-q-make_request_fn-null-pointer.patch
+dm-writecache-fix-incorrect-flush-sequence-when-doing-ssd-mode-commit.patch