summaryrefslogtreecommitdiffstats
path: root/daemon/sync.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/sync.c')
-rw-r--r--daemon/sync.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/daemon/sync.c b/daemon/sync.c
index fcb887e2..2338a3d4 100644
--- a/daemon/sync.c
+++ b/daemon/sync.c
@@ -23,7 +23,11 @@
#endif
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/types.h>
#include "daemon.h"
#include "actions.h"
@@ -32,6 +36,10 @@
static int sync_win32 (void);
#endif
+#ifdef HAVE_FSYNC
+static void fsync_devices (void);
+#endif
+
int
do_sync (void)
{
@@ -52,6 +60,18 @@ sync_disks (void)
{
#if defined(HAVE_SYNC)
sync ();
+
+ /* On Linux, sync(2) doesn't perform a barrier, so qemu (which may
+ * have a writeback cache, even with cache=none) will still have
+ * some unwritten data. Force the data out of any qemu caches, by
+ * calling fsync on all block devices. Note we still need the
+ * call to sync above in order to schedule the writes.
+ * Thanks to: Avi Kivity, Kevin Wolf.
+ */
+#ifdef HAVE_FSYNC
+ fsync_devices ();
+#endif
+
return 0;
#elif defined(WIN32)
return sync_win32 ();
@@ -60,6 +80,64 @@ sync_disks (void)
#endif
}
+#ifdef HAVE_FSYNC
+static void
+fsync_devices (void)
+{
+ DIR *dir;
+ struct dirent *d;
+ char dev_path[256];
+ int fd;
+
+ dir = opendir ("/sys/block");
+ if (!dir) {
+ perror ("opendir: /sys/block");
+ return;
+ }
+
+ for (;;) {
+ errno = 0;
+ d = readdir(dir);
+ if (!d) break;
+
+ if (STREQLEN (d->d_name, "sd", 2) ||
+ STREQLEN (d->d_name, "hd", 2) ||
+ STREQLEN (d->d_name, "vd", 2) ||
+ STREQLEN (d->d_name, "sr", 2)) {
+ snprintf (dev_path, sizeof dev_path, "/dev/%s", d->d_name);
+
+ /* Ignore the root device. */
+ if (is_root_device (dev_path))
+ continue;
+
+ fd = open (dev_path, O_RDONLY|O_CLOEXEC);
+ if (fd == -1) {
+ perror (dev_path);
+ continue;
+ }
+
+ /* fsync the device. */
+ if (verbose)
+ fprintf (stderr, "fsync %s\n", dev_path);
+
+ if (fsync (fd) == -1)
+ perror ("fsync");
+
+ if (close (fd) == -1)
+ perror ("close");
+ }
+ }
+
+ /* Check readdir didn't fail */
+ if (errno != 0)
+ perror ("readdir: /sys/block");
+
+ /* Close the directory handle */
+ if (closedir (dir) == -1)
+ perror ("closedir");
+}
+#endif /* HAVE_FSYNC */
+
#ifdef WIN32
static int
sync_win32 (void)