Re: [PATCH v2 1/3] core.fsyncmethod: add writeout-only mode
- From
Patrick Steinhardt <ps@pks.im>
- Date
- Dec 7, 2021, 11:44 UTC
- Message-ID
- <Ya9JJlItvDJCLHqj@ncase>
- In-Reply-To
- <e79522cbdd4feb45b062b75225475f34039d1866.1638845211.git.gitgitgadget@gmail.com>
On Tue, Dec 07, 2021 at 02:46:49AM +0000, Neeraj Singh via GitGitGadget wrote:
> From: Neeraj Singh <neerajsi@microsoft.com>
[snip]
Show 36 quoted lines
> --- a/compat/mingw.h
> +++ b/compat/mingw.h
> @@ -329,6 +329,9 @@ int mingw_getpagesize(void);
> #define getpagesize mingw_getpagesize
> #endif
>
> +int win32_fsync_no_flush(int fd);
> +#define fsync_no_flush win32_fsync_no_flush
> +
> struct rlimit {
> unsigned int rlim_cur;
> };
> diff --git a/compat/win32/flush.c b/compat/win32/flush.c
> new file mode 100644
> index 00000000000..75324c24ee7
> --- /dev/null
> +++ b/compat/win32/flush.c
> @@ -0,0 +1,28 @@
> +#include "../../git-compat-util.h"
> +#include <winternl.h>
> +#include "lazyload.h"
> +
> +int win32_fsync_no_flush(int fd)
> +{
> + IO_STATUS_BLOCK io_status;
> +
> +#define FLUSH_FLAGS_FILE_DATA_ONLY 1
> +
> + DECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NtFlushBuffersFileEx,
> + HANDLE FileHandle, ULONG Flags, PVOID Parameters, ULONG ParameterSize,
> + PIO_STATUS_BLOCK IoStatusBlock);
> +
> + if (!INIT_PROC_ADDR(NtFlushBuffersFileEx)) {
> + errno = ENOSYS;
> + return -1;
> + }I'm wondering whether it would make sense to fall back to fsync(3P) in case we cannot use writeout-only, but I see that were doing essentially that in `fsync_or_die()`. There is no indicator to the user though that writeout-only doesn't work -- do we want to print a one-time warning?
Show 9 quoted lines
> + memset(&io_status, 0, sizeof(io_status));
> + if (NtFlushBuffersFileEx((HANDLE)_get_osfhandle(fd), FLUSH_FLAGS_FILE_DATA_ONLY,
> + NULL, 0, &io_status)) {
> + errno = EINVAL;
> + return -1;
> + }
> +
> + return 0;
> +}[snip]
Show 19 quoted lines
> diff --git a/wrapper.c b/wrapper.c
> index 36e12119d76..1c5f2c87791 100644
> --- a/wrapper.c
> +++ b/wrapper.c
> @@ -546,6 +546,62 @@ int xmkstemp_mode(char *filename_template, int mode)
> return fd;
> }
>
> +int git_fsync(int fd, enum fsync_action action)
> +{
> + switch (action) {
> + case FSYNC_WRITEOUT_ONLY:
> +
> +#ifdef __APPLE__
> + /*
> + * on macOS, fsync just causes filesystem cache writeback but does not
> + * flush hardware caches.
> + */
> + return fsync(fd);Below we're looping around `EINTR` -- are Apple systems never returning it?
Patrick
Show 72 quoted lines
> +#endif
> +
> +#ifdef HAVE_SYNC_FILE_RANGE
> + /*
> + * On linux 2.6.17 and above, sync_file_range is the way to issue
> + * a writeback without a hardware flush. An offset of 0 and size of 0
> + * indicates writeout of the entire file and the wait flags ensure that all
> + * dirty data is written to the disk (potentially in a disk-side cache)
> + * before we continue.
> + */
> +
> + return sync_file_range(fd, 0, 0, SYNC_FILE_RANGE_WAIT_BEFORE |
> + SYNC_FILE_RANGE_WRITE |
> + SYNC_FILE_RANGE_WAIT_AFTER);
> +#endif
> +
> +#ifdef fsync_no_flush
> + return fsync_no_flush(fd);
> +#endif
> +
> + errno = ENOSYS;
> + return -1;
> +
> + case FSYNC_HARDWARE_FLUSH:
> + /*
> + * On some platforms fsync may return EINTR. Try again in this
> + * case, since callers asking for a hardware flush may die if
> + * this function returns an error.
> + */
> + for (;;) {
> + int err;
> +#ifdef __APPLE__
> + err = fcntl(fd, F_FULLFSYNC);
> +#else
> + err = fsync(fd);
> +#endif
> + if (err >= 0 || errno != EINTR)
> + return err;
> + }
> +
> + default:
> + BUG("unexpected git_fsync(%d) call", action);
> + }
> +}
> +
> static int warn_if_unremovable(const char *op, const char *file, int rc)
> {
> int err;
> diff --git a/write-or-die.c b/write-or-die.c
> index 0b1ec8190b6..0702acdd5e8 100644
> --- a/write-or-die.c
> +++ b/write-or-die.c
> @@ -57,10 +57,12 @@ void fprintf_or_die(FILE *f, const char *fmt, ...)
>
> void fsync_or_die(int fd, const char *msg)
> {
> - while (fsync(fd) < 0) {
> - if (errno != EINTR)
> - die_errno("fsync error on '%s'", msg);
> - }
> + if (fsync_method == FSYNC_METHOD_WRITEOUT_ONLY &&
> + git_fsync(fd, FSYNC_WRITEOUT_ONLY) >= 0)
> + return;
> +
> + if (git_fsync(fd, FSYNC_HARDWARE_FLUSH) < 0)
> + die_errno("fsync error on '%s'", msg);
> }
>
> void write_or_die(int fd, const void *buf, size_t count)
> --
> gitgitgadget
>