--- /dev/null
+From: mason@suse.de
+Subject: make sure O_SYNC writes properly return -EIO
+References: bnc#58622
+
+Make sure to honor the error status of synchronous writeback during
+O_SYNC writes
+
+Acked-by: Jeff Mahoney <jeffm@suse.com>
+
+---
+ mm/filemap.c | 17 +++++++++++++++--
+ 1 file changed, 15 insertions(+), 2 deletions(-)
+
+--- a/mm/filemap.c
++++ b/mm/filemap.c
+@@ -2498,7 +2498,7 @@ generic_file_buffered_write(struct kiocb
+
+ if (likely(status >= 0)) {
+ written += status;
+- *ppos = pos + status;
++ pos += status;
+
+ /*
+ * For now, when the user asks for O_SYNC, we'll actually give
+@@ -2516,10 +2516,23 @@ generic_file_buffered_write(struct kiocb
+ * to buffered writes (block instantiation inside i_size). So we sync
+ * the file data here, to try to honour O_DIRECT expectations.
+ */
+- if (unlikely(file->f_flags & O_DIRECT) && written)
++ if (unlikely(file->f_flags & O_DIRECT) && status >= 0 && written)
+ status = filemap_write_and_wait_range(mapping,
+ pos, pos + written - 1);
+
++ /*
++ * We must let know userspace if something hasn't been written
++ * correctly. If we got an I/O error it means we got an hardware
++ * failure, anything can be happening to the on-disk data,
++ * letting know userspace that a bit of data might have been
++ * written correctly on disk is a very low priority, compared
++ * to letting know userspace that some data has _not_ been
++ * written at all.
++ */
++ if (unlikely(status == -EIO))
++ return status;
++ *ppos = pos;
++
+ return written ? written : status;
+ }
+ EXPORT_SYMBOL(generic_file_buffered_write);