Avoid ext4 auto_da_alloc flush on close (v2).
authorRichard W.M. Jones <rjones@redhat.com>
Wed, 23 Oct 2013 07:26:42 +0000 (08:26 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Wed, 23 Oct 2013 08:24:51 +0000 (09:24 +0100)
This updates commit 68640d56b2ea96401a1355ab56603b0837058d21.

Don't unlink the file: As Florian Weimer pointed out, this would cause
problems if someone uses '-o /dev/null' (it could delete /dev/null).

Don't write a byte.  The exact condition which causes the
auto_da_alloc misbehaviour is truncating a file from a large size to 0
size.  So this write was not necessary.

Thanks: Florian Weimer, Eric Sandeen, Eric Blake.

pxzcat.c

index 7e036d0..1285ed1 100644 (file)
--- a/pxzcat.c
+++ b/pxzcat.c
@@ -166,16 +166,21 @@ xzfile_uncompress (const char *filename, const char *outputfile,
   debug ("uncompressed size = %" PRIu64 " bytes", size);
 
   /* Avoid annoying ext4 auto_da_alloc which causes a flush on close
-   * unless we are very careful about not truncating the file when it
-   * has zero size.  (Thanks Eric Sandeen)
+   * unless we are very careful about not truncating a regular file
+   * from non-zero size to zero size.  (Thanks Eric Sandeen)
    */
-  unlink (outputfile);
-
-  ofd = open (outputfile, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, 0644);
+  ofd = open (outputfile, O_WRONLY|O_CREAT|O_NOCTTY, 0644);
   if (ofd == -1)
     error (EXIT_FAILURE, errno, "open: %s", outputfile);
-  /* See above about auto_da_alloc. */
-  write (ofd, "\0", 1);
+
+  if (ftruncate (ofd, 1) == -1)
+    error (EXIT_FAILURE, errno, "ftruncate (1 byte): %s", outputfile);
+
+  if (lseek (ofd, 0, SEEK_SET) == -1)
+    error (EXIT_FAILURE, errno, "lseek: %s", outputfile);
+
+  if (write (ofd, "\0", 1) == -1)
+    error (EXIT_FAILURE, errno, "write: %s", outputfile);
 
   if (ftruncate (ofd, size) == -1)
     error (EXIT_FAILURE, errno, "ftruncate: %s", outputfile);