From 2d03793eb03abcdfcb677c80909bc80970074874 Mon Sep 17 00:00:00 2001 From: Chrissie Caulfield Date: Thu, 17 Mar 2022 07:47:39 +0000 Subject: [PATCH] unix: Don't fail on FreeBSD running ZFS (#461) * unix: Don't fail on FreeBSD running ZFS ZFS doesn't support posix_fallocate() so libqb IPC or RB would always fail with EINVAL. As there seems to be no prospect of a more useful return code, trap it in a QB_BSD #ifdef. That way if we do have actual errors in the posix_fallocate() call the Linux tests should still find them. Also, stick a small sleep in the test_ipc_disconnect_after_created test to allow the server to shutdown before killing it with SIGTERM and causing a test failure. all the other uses of it seem to have this sleep! --- lib/unix.c | 71 ++++++++++++++++++++++++++++++++--------------- tests/check_ipc.c | 2 +- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/lib/unix.c b/lib/unix.c index b631cbf5..f59cd0b1 100644 --- a/lib/unix.c +++ b/lib/unix.c @@ -69,6 +69,44 @@ open_mmap_file(char *path, uint32_t file_flags) return open(path, file_flags, 0600); } +#if defined(QB_BSD) || !defined(HAVE_POSIX_FALLOCATE) +static int local_fallocate(int fd, size_t bytes) +{ + long page_size = sysconf(_SC_PAGESIZE); + long write_size = QB_MIN(page_size, bytes); + char *buffer = NULL; + int i; + size_t written; + + if (page_size < 0) { + goto error_exit; + } + buffer = calloc(1, write_size); + if (buffer == NULL) { + goto error_exit; + } + + for (i = 0; i < (bytes / write_size); i++) { + retry_write: + written = write(fd, buffer, write_size); + if (written == -1 && errno == EINTR) { + goto retry_write; + } + if (written != write_size) { + free(buffer); + errno = ENOSPC; + goto error_exit; + } + } + free(buffer); + + return 0; + +error_exit: + return -1; +} +#endif + int32_t qb_sys_mmap_file_open(char *path, const char *file, size_t bytes, uint32_t file_flags) @@ -132,6 +170,16 @@ qb_sys_mmap_file_open(char *path, const char *file, size_t bytes, if (res == EINTR) { qb_util_log(LOG_DEBUG, "got EINTR trying to allocate file %s, retrying...", path); continue; +#ifdef QB_BSD + } else if (res == EINVAL) { /* posix_fallocate() fails on ZFS + https://lists.freebsd.org/pipermail/freebsd-current/2018-February/068448.html */ + qb_util_log(LOG_DEBUG, "posix_fallocate returned EINVAL - running on ZFS?"); + if (file_flags & O_CREAT) { + if (local_fallocate(fd, bytes)) { + goto unlink_exit; + } + } +#endif } else if (res != 0) { errno = res; res = -1 * res; @@ -142,30 +190,9 @@ qb_sys_mmap_file_open(char *path, const char *file, size_t bytes, } while (fallocate_retry > 0); #else if (file_flags & O_CREAT) { - long page_size = sysconf(_SC_PAGESIZE); - long write_size = QB_MIN(page_size, bytes); - if (page_size < 0) { - res = -errno; + if (local_fallocate(fd, bytes)) { goto unlink_exit; } - buffer = calloc(1, write_size); - if (buffer == NULL) { - res = -ENOMEM; - goto unlink_exit; - } - for (i = 0; i < (bytes / write_size); i++) { -retry_write: - written = write(fd, buffer, write_size); - if (written == -1 && errno == EINTR) { - goto retry_write; - } - if (written != write_size) { - res = -ENOSPC; - free(buffer); - goto unlink_exit; - } - } - free(buffer); } #endif /* HAVE_POSIX_FALLOCATE */ diff --git a/tests/check_ipc.c b/tests/check_ipc.c index 1883b85c..10b4a814 100644 --- a/tests/check_ipc.c +++ b/tests/check_ipc.c @@ -1959,8 +1959,8 @@ test_ipc_disconnect_after_created(void) ck_assert_int_eq(res, -ENOTCONN); } ck_assert_int_eq(QB_FALSE, qb_ipcc_is_connected(conn)); - qb_ipcc_disconnect(conn); + sleep(1); /* Give it time to stop */ kill_server(pid); }