Thanks for reporting the problem. It's annoying that gzip must invoke fsync, as that's way overkill compared to the write-ordering that is needed and fsync will slow gzip down, but I don't see any safe and reasonably portable alternative so I installed the attached patch on Savannah, here:

http://git.savannah.gnu.org/cgit/gzip.git/commit/?id=22aac8f8a616a72dbbe0e4119db8ddda0f076c04
From c8367d7660239b1aedce7850c766c0c0f8938d1c Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Mon, 22 Feb 2016 23:21:49 -0800
Subject: [PATCH] fsync output file before closing
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Problem reported by Yanyan Jiang 蒋炎岩 in: http://bugs.gnu.org/22768
* NEWS: Document this.
* bootstrap.conf (gnulib_modules): Add fsync.
* gzip.c (treat_file): Call fsync just before closing the output.
* lib/.gitignore, m4/.gitignore: Add fsync-related gnulib files.
---
 NEWS           |  4 ++++
 bootstrap.conf |  1 +
 gzip.c         | 11 ++++++++++-
 lib/.gitignore |  1 +
 m4/.gitignore  |  1 +
 5 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index a1c668f..31472cc 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,10 @@ GNU gzip NEWS                                    -*- outline 
-*-
 
 ** Changes in behavior
 
+  When acting in-place, gzip now fsyncs the output before closing it.
+  This is slower, but on many file systems it is safer if the system
+  is about to crash.
+
   The GZIP environment variable is now obsolescent; gzip now warns if
   it is used, and rejects attempts to use dangerous options or operands.
   You can use an alias or script instead.
diff --git a/bootstrap.conf b/bootstrap.conf
index 13a485d..b15caa3 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -31,6 +31,7 @@ fcntl-safer
 fdl
 fdopendir
 fprintf-posix
+fsync
 getopt-gnu
 git-version-gen
 gitlog-to-changelog
diff --git a/gzip.c b/gzip.c
index a013540..b872383 100644
--- a/gzip.c
+++ b/gzip.c
@@ -926,8 +926,17 @@ local void treat_file(iname)
 
     if (!to_stdout)
       {
-
         copy_stat (&istat);
+
+        /* Transfer output data to the output file's storage device.
+           Otherwise, if the system crashed now the user might lose
+           both input and output data.  See: Pillai TS et al.  All
+           file systems are not created equal: on the complexity of
+           crafting crash-consistent applications. OSDI'14. 2014:433-48.
+           
https://www.usenix.org/conference/osdi14/technical-sessions/presentation/pillai 
 */
+        if (!keep && fsync (ofd) != 0 && errno != EINVAL)
+          write_error ();
+
         if (close (ofd) != 0)
           write_error ();
 
diff --git a/lib/.gitignore b/lib/.gitignore
index 81d94ff..a368a26 100644
--- a/lib/.gitignore
+++ b/lib/.gitignore
@@ -225,3 +225,4 @@
 /xsize.h
 /yesno.c
 /yesno.h
+/fsync.c
diff --git a/m4/.gitignore b/m4/.gitignore
index 660b926..32f5566 100644
--- a/m4/.gitignore
+++ b/m4/.gitignore
@@ -150,3 +150,4 @@
 /xalloc.m4
 /xsize.m4
 /yesno.m4
+/fsync.m4
-- 
2.5.0

Reply via email to