[issue11877] Change os.fsync() to support physical backing store syncs

Steffen Daode Nurpmeso report at bugs.python.org
Thu Apr 21 17:19:25 CEST 2011


Steffen Daode Nurpmeso <sdaoden at googlemail.com> added the comment:

Ok, 11877.3.diff uses either-or.

----------
Added file: http://bugs.python.org/file21749/11877.3.diff

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue11877>
_______________________________________
-------------- next part --------------
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -798,7 +798,7 @@
    Availability: Unix.
 
 
-.. function:: fsync(fd)
+.. function:: fsync(fd, full_fsync=False)
 
    Force write of file with filedescriptor *fd* to disk.  On Unix, this calls the
    native :c:func:`fsync` function; on Windows, the MS :c:func:`_commit` function.
@@ -807,6 +807,14 @@
    ``f.flush()``, and then do ``os.fsync(f.fileno())``, to ensure that all internal
    buffers associated with *f* are written to disk.
 
+   Note that on most operating systems :c:func:`fsync` only ensures that
+   the data is flushed to the disk device, *not* that it has been written
+   by the device itself.  The optional *full_fsync* argument can be used to
+   issue a physical backing store synchronization request on operating
+   systems which do support such an operation, e.g. on NetBSD by calling
+   :c:func:`fsync_range` with the :data:`FDISKSYNC` flag, or on Mac OS X by
+   calling  :c:func:`fcntl` with the :data:`F_FULLFSYNC` command.
+
    Availability: Unix, and Windows.
 
 
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -13,6 +13,9 @@
 
 /* See also ../Dos/dosmodule.c */
 
+#ifdef __linux__
+# define _GNU_SOURCE
+#endif
 #ifdef __APPLE__
    /*
     * Step 1 of support for weak-linking a number of symbols existing on
@@ -2119,13 +2122,66 @@
 
 #ifdef HAVE_FSYNC
 PyDoc_STRVAR(posix_fsync__doc__,
-"fsync(fildes)\n\n\
-force write of file with filedescriptor to disk.");
-
-static PyObject *
-posix_fsync(PyObject *self, PyObject *fdobj)
-{
-    return posix_fildes(fdobj, fsync);
+"fsync(fildes, full_fsync=False)\n\n"
+"force write of file buffers with fildes to disk;\n"
+"if full_fsync is True it is tried to synchronize physical backing store.");
+
+static PyObject *
+posix_fsync(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+    PyObject *retval = NULL;
+    auto PyObject *fdobj;
+    auto int full_fsync = 1;
+    static char *keywords[] = {"fd", "full_fsync", NULL };
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i", keywords,
+                                     &fdobj, &full_fsync))
+        goto jleave;
+
+    /* See issue 11877 discussion (and issue 11277 for OS X sparse file bug) */
+# if (((defined __AIX || defined _AIX) && \
+       defined O_SYNC && defined O_DSYNC) || \
+      (defined __APPLE__ && defined F_FULLFSYNC) || \
+      (defined __NetBSD__ && defined FDISKSYNC) || \
+      (defined __linux__ && defined SYNC_FILE_RANGE_WAIT_AFTER))
+    if (full_fsync != 0) {
+        int res, fd = PyObject_AsFileDescriptor(fdobj);
+        if (fd < 0)
+            goto jleave;
+        if (!_PyVerify_fd(fd)) {
+            retval = posix_error();
+            goto jleave;
+        }
+
+        Py_BEGIN_ALLOW_THREADS
+#  if defined __AIX || defined _AIX
+        res = fsync_range(fd, O_SYNC, 0, 0);
+#  endif
+#  ifdef __APPLE__
+        res = fcntl(fd, F_FULLFSYNC);
+#  endif
+#  ifdef __NetBSD__
+        res = fsync_range(fd, FFILESYNC|FDISKSYNC, 0, 0);
+#  endif
+#  ifdef __linux__
+        res = sync_file_range(fd, 0, 0, (SYNC_FILE_RANGE_WAIT_BEFORE |
+                                         SYNC_FILE_RANGE_WRITE |
+                                         SYNC_FILE_RANGE_WAIT_AFTER));
+#  endif
+        Py_END_ALLOW_THREADS
+
+        if (res < 0) {
+            retval = posix_error();
+            goto jleave;
+        }
+        Py_INCREF(Py_None);
+        retval = Py_None;
+    } else
+# endif
+        retval = posix_fildes(fdobj, fsync);
+
+jleave:
+    return retval;
 }
 #endif /* HAVE_FSYNC */
 
@@ -9484,7 +9540,8 @@
     {"fchdir",          posix_fchdir, METH_O, posix_fchdir__doc__},
 #endif
 #ifdef HAVE_FSYNC
-    {"fsync",       posix_fsync, METH_O, posix_fsync__doc__},
+    {"fsync",           (PyCFunction)posix_fsync, METH_VARARGS|METH_KEYWORDS,
+                        posix_fsync__doc__},
 #endif
 #ifdef HAVE_SYNC
     {"sync",        posix_sync, METH_NOARGS, posix_sync__doc__},


More information about the Python-bugs-list mailing list