Hi,

Raphael Hertzog wrote:

>     Instead of making yet another exception for hardlinks, it's time
>     to decide that deferred rename is the norm and only directories
>     should be exempted from this.

Makes perfect sense.  Thanks!

Here's the remainder of the train of thought I sent before.  I don't
see any reason to apply it unless we have some information (e.g., perf
data) that suggests it helps.

-- >8 --
Subject: dpkg: try opening files for reading when fsync-ing

fsync() is not supposed to affect the file descriptor but the
underlying inode, so on most modern operating systems it does not care
whether it is passed a file descriptor open for reading or for
writing.  Opening for reading can be slightly more lightweight --- for
example, on Linux it avoids having to allocate structures related to
quota.

However, some OSes (e.g., AIX) do require a descriptor open for
writing.

Therefore open files for reading, not writing, before fsyncing them
and only fall back to opening for writing if the system requires it.  

Signed-off-by: Jonathan Nieder <jrnie...@gmail.com>
---
 debian/changelog |    4 ++++
 src/archives.c   |   51 ++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index 7c6343d3..2b255171 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -186,6 +186,10 @@ dpkg (1.16.1) UNRELEASED; urgency=low
   * Add new --raw-extract option to dpkg-deb combining --control and
     --extract. Closes: #552123
 
+  [ Jonathan Nieder ]
+  * Open extracted files for reading, not writing, before fsyncing them.
+    Only fall back to opening for writing if fsync fails with errno == EBADF.
+
   [ Updated dpkg translations ]
   * German (Sven Joachim). Closes: #620312
   * Swedish (Peter Krefting).
diff --git a/src/archives.c b/src/archives.c
index c8d80aad..c0dac081 100644
--- a/src/archives.c
+++ b/src/archives.c
@@ -911,6 +911,47 @@ tar_writeback_barrier(struct fileinlist *files, struct 
pkginfo *pkg)
 }
 #endif
 
+static int
+open_checked(const char *path, int flags)
+{
+  int fd = open(path, flags);
+  if (fd < 0)
+    ohshite(_("unable to open '%.255s'"), path);
+  return fd;
+}
+
+static void
+close_checked(int fd, const char *path)
+{
+  if (close(fd))
+    ohshite(_("error closing/writing `%.255s'"), path);
+}
+
+static void
+fsync_path(const char *path)
+{
+  int fd;
+
+  fd = open_checked(path, O_RDONLY);
+  if (fsync(fd) == 0) {
+    close_checked(fd, path);
+    return;
+  }
+  if (errno != EBADF)
+    ohshite(_("unable to sync file '%.255s'"), path);
+
+  /*
+   * fsync() on some Unixen (e.g., AIX) requires "fd" to be
+   * open for writing, failing with EBADF when otherwise.
+   * Try again with O_WRONLY for their sake.
+   */
+  close(fd);
+  fd = open_checked(path, O_WRONLY);
+  if (fsync(fd))
+    ohshite(_("unable to sync file '%.255s'"), path);
+  close_checked(fd, path);
+}
+
 void
 tar_deferred_extract(struct fileinlist *files, struct pkginfo *pkg)
 {
@@ -935,15 +976,7 @@ tar_deferred_extract(struct fileinlist *files, struct 
pkginfo *pkg)
       int fd;
 
       debug(dbg_eachfiledetail, "deferred extract needs fsync");
-
-      fd = open(fnamenewvb.buf, O_WRONLY);
-      if (fd < 0)
-        ohshite(_("unable to open '%.255s'"), fnamenewvb.buf);
-      if (fsync(fd))
-        ohshite(_("unable to sync file '%.255s'"), fnamenewvb.buf);
-      if (close(fd))
-        ohshite(_("error closing/writing `%.255s'"), fnamenewvb.buf);
-
+      fsync_path(fnamenewvb.buf);
       cfile->namenode->flags &= ~fnnf_deferred_fsync;
     }
 
-- 
1.7.6





-- 
To UNSUBSCRIBE, email to debian-dpkg-bugs-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org

Reply via email to