git » libjio » commit 1bd4aa9

Use sync_file_range() instead of fdatasync(), if available

author Alberto Bertogli
2009-04-03 04:23:37 UTC
committer Alberto Bertogli
2009-04-12 13:51:04 UTC
parent 0d244b37ba24ec7564d15a23e7fa1c864c5bd0bb

Use sync_file_range() instead of fdatasync(), if available

Signed-off-by: Alberto Bertogli <albertito@blitiri.com.ar>

libjio/Makefile +1 -1
libjio/compat.c +56 -0
libjio/compat.h +8 -0
libjio/trans.c +22 -0

diff --git a/libjio/Makefile b/libjio/Makefile
index 192a18e..72e4e18 100644
--- a/libjio/Makefile
+++ b/libjio/Makefile
@@ -39,7 +39,7 @@ endif
 
 
 # objects to build
-OBJS = checksum.o common.o trans.o check.o journal.o unix.o ansi.o
+OBJS = checksum.o common.o compat.o trans.o check.o journal.o unix.o ansi.o
 
 # rules
 default: all
diff --git a/libjio/compat.c b/libjio/compat.c
new file mode 100644
index 0000000..80c2300
--- /dev/null
+++ b/libjio/compat.c
@@ -0,0 +1,56 @@
+
+
+/* To get sync_file_range() we need to temporarily define _GNU_SOURCE, which
+ * is not the nicest thing, but is not worth defining globally */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#define _REMOVE_GNU_SOURCE
+#endif
+
+#include <fcntl.h>		/* sync_range_submit(), if possible */
+#include "compat.h"
+
+
+/*
+ * sync_file_range() support through an internal similar API
+ */
+
+#ifdef SYNC_FILE_RANGE_WRITE
+const int have_sync_range = 1;
+
+/* Initiate write-out of the dirty pages in the range. */
+int sync_range_submit(int fd, off_t offset, size_t nbytes)
+{
+	/* We don't need SYNC_FILE_RANGE_WAIT_BEFORE because we have exclusive
+	 * access to the range (guaranteed by the caller) */
+	return sync_file_range(fd, offset, nbytes, SYNC_FILE_RANGE_WRITE);
+}
+
+/* Wait for completion of the previously-submitted I/O in the given ranges.
+ * Does NOT force the submission of any new I/O. */
+int sync_range_wait(int fd, off_t offset, size_t nbytes)
+{
+	return sync_file_range(fd, offset, nbytes, SYNC_FILE_RANGE_WAIT_BEFORE);
+}
+
+#else
+
+#warning "No sync_file_range()"
+const int have_sync_range = 0;
+
+int sync_range_submit(int fd, off_t offset, size_t nbytes)
+{
+	return -1;
+}
+
+int sync_range_wait(int fd, off_t offset, size_t nbytes)
+{
+	return -1;
+}
+
+#endif /* defined SYNC_FILE_RANGE_WRITE */
+
+#ifdef _REMOVE_GNU_SOURCE
+#undef _GNU_SOURCE
+#endif
+
diff --git a/libjio/compat.h b/libjio/compat.h
index ecc742a..4f9d98d 100644
--- a/libjio/compat.h
+++ b/libjio/compat.h
@@ -4,6 +4,14 @@
 #ifndef _COMPAT_H
 #define _COMPAT_H
 
+/* sync_file_range() is linux-specific, so we provide an internal similar API,
+ * with a constant to be able to check for its presence; the implementation is
+ * in compat.c */
+extern const int have_sync_range;
+int sync_range_submit(int fd, off_t offset, size_t nbytes);
+int sync_range_wait(int fd, off_t offset, size_t nbytes);
+
+
 /* posix_fadvise() was introduced in SUSv3. Because it's the only SUSv3
  * function we rely on so far (everything else is SUSv2), we define a void
  * fallback for systems that do not implement it.
diff --git a/libjio/trans.c b/libjio/trans.c
index 306a6d0..e4a6e98 100644
--- a/libjio/trans.c
+++ b/libjio/trans.c
@@ -194,6 +194,14 @@ ssize_t jtrans_commit(struct jtrans *ts)
 			goto rollback_exit;
 
 		written += rv;
+
+		if (have_sync_range && !(ts->flags & J_LINGER)) {
+			rv = sync_range_submit(ts->fs->fd, op->len,
+					op->offset);
+			if (rv != 0)
+				goto rollback_exit;
+		}
+
 		fiu_exit_on("jio/commit/wrote_op");
 	}
 
@@ -211,6 +219,20 @@ ssize_t jtrans_commit(struct jtrans *ts)
 		ts->fs->ltrans = linger;
 		pthread_mutex_unlock(&(ts->fs->ltlock));
 	} else {
+		if (have_sync_range) {
+			for (op = ts->op; op != NULL; op = op->next) {
+				rv = sync_range_wait(ts->fs->fd, op->len,
+						op->offset);
+				if (rv != 0)
+					goto rollback_exit;
+			}
+		} else {
+			if (fdatasync(ts->fs->fd) != 0)
+				goto rollback_exit;
+		}
+
+		/* the transaction has been applied, so we cleanup and remove
+		 * it from the disk */
 		rv = journal_free(jop);
 		if (rv != 0)
 			goto rollback_exit;