]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 9 Jun 2018 14:43:56 +0000 (16:43 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 9 Jun 2018 14:43:56 +0000 (16:43 +0200)
added patches:
xfs-fix-incorrect-log_flushed-on-fsync.patch

queue-4.4/series
queue-4.4/xfs-fix-incorrect-log_flushed-on-fsync.patch [new file with mode: 0644]

index 6a36b41933f18577fe947e8af369f6084a6d05d7..a2af7375eb57c0feb8416be0dcd9dfad5febc09a 100644 (file)
@@ -3,3 +3,4 @@ tpm-self-test-failure-should-not-cause-suspend-to-fail.patch
 mmap-introduce-sane-default-mmap-limits.patch
 mmap-relax-file-size-limit-for-regular-files.patch
 kconfig-avoid-format-overflow-warning-from-gcc-8.1.patch
+xfs-fix-incorrect-log_flushed-on-fsync.patch
diff --git a/queue-4.4/xfs-fix-incorrect-log_flushed-on-fsync.patch b/queue-4.4/xfs-fix-incorrect-log_flushed-on-fsync.patch
new file mode 100644 (file)
index 0000000..bf310b7
--- /dev/null
@@ -0,0 +1,96 @@
+From 47c7d0b19502583120c3f396c7559e7a77288a68 Mon Sep 17 00:00:00 2001
+From: Amir Goldstein <amir73il@gmail.com>
+Date: Wed, 30 Aug 2017 09:23:12 -0700
+Subject: xfs: fix incorrect log_flushed on fsync
+
+From: Amir Goldstein <amir73il@gmail.com>
+
+commit 47c7d0b19502583120c3f396c7559e7a77288a68 upstream.
+
+When calling into _xfs_log_force{,_lsn}() with a pointer
+to log_flushed variable, log_flushed will be set to 1 if:
+1. xlog_sync() is called to flush the active log buffer
+AND/OR
+2. xlog_wait() is called to wait on a syncing log buffers
+
+xfs_file_fsync() checks the value of log_flushed after
+_xfs_log_force_lsn() call to optimize away an explicit
+PREFLUSH request to the data block device after writing
+out all the file's pages to disk.
+
+This optimization is incorrect in the following sequence of events:
+
+ Task A                    Task B
+ -------------------------------------------------------
+ xfs_file_fsync()
+   _xfs_log_force_lsn()
+     xlog_sync()
+        [submit PREFLUSH]
+                           xfs_file_fsync()
+                             file_write_and_wait_range()
+                               [submit WRITE X]
+                               [endio  WRITE X]
+                             _xfs_log_force_lsn()
+                               xlog_wait()
+        [endio  PREFLUSH]
+
+The write X is not guarantied to be on persistent storage
+when PREFLUSH request in completed, because write A was submitted
+after the PREFLUSH request, but xfs_file_fsync() of task A will
+be notified of log_flushed=1 and will skip explicit flush.
+
+If the system crashes after fsync of task A, write X may not be
+present on disk after reboot.
+
+This bug was discovered and demonstrated using Josef Bacik's
+dm-log-writes target, which can be used to record block io operations
+and then replay a subset of these operations onto the target device.
+The test goes something like this:
+- Use fsx to execute ops of a file and record ops on log device
+- Every now and then fsync the file, store md5 of file and mark
+  the location in the log
+- Then replay log onto device for each mark, mount fs and compare
+  md5 of file to stored value
+
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Josef Bacik <jbacik@fb.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Amir Goldstein <amir73il@gmail.com>
+Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
+Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/xfs/xfs_log.c |    7 -------
+ 1 file changed, 7 deletions(-)
+
+--- a/fs/xfs/xfs_log.c
++++ b/fs/xfs/xfs_log.c
+@@ -3323,8 +3323,6 @@ maybe_sleep:
+                */
+               if (iclog->ic_state & XLOG_STATE_IOERROR)
+                       return -EIO;
+-              if (log_flushed)
+-                      *log_flushed = 1;
+       } else {
+ no_sleep:
+@@ -3432,8 +3430,6 @@ try_again:
+                               xlog_wait(&iclog->ic_prev->ic_write_wait,
+                                                       &log->l_icloglock);
+-                              if (log_flushed)
+-                                      *log_flushed = 1;
+                               already_slept = 1;
+                               goto try_again;
+                       }
+@@ -3467,9 +3463,6 @@ try_again:
+                        */
+                       if (iclog->ic_state & XLOG_STATE_IOERROR)
+                               return -EIO;
+-
+-                      if (log_flushed)
+-                              *log_flushed = 1;
+               } else {                /* just return */
+                       spin_unlock(&log->l_icloglock);
+               }