--- /dev/null
+++ b/modules/fallocate-posix
@@ -0,0 +1,43 @@
+Description:
+posix_fallocate function that is glibc compatible.
+
+Files:
+lib/posix_fallocate.c
+m4/fcntl_h.m4
+m4/posix_fallocate.m4
+
+Depends-on:
+errno          [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1]
+fcntl          [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1]
+fstat          [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1]
+ftruncate      [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1]
+pread          [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1]
+pwrite         [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1]
+stdint         [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1]
+sys_stat       [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1]
+unistd         [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1]
+fcntl-h
+
+configure.ac:
+gl_FUNC_POSIX_FALLOCATE
+gl_CONDITIONAL([GL_COND_OBJ_POSIX_FALLOCATE],
+               [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1])
+AM_COND_IF([GL_COND_OBJ_POSIX_FALLOCATE], [
+  gl_PREREQ_POSIX_FALLOCATE
+])
+gl_MODULE_INDICATOR([fallocate-posix])
+gl_FCNTL_MODULE_INDICATOR([fallocate-posix])
+
+Makefile.am:
+if GL_COND_OBJ_POSIX_FALLOCATE
+lib_SOURCES += posix_fallocate.c
+endif
+
+Include:
+<fcntl.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
--- /dev/null
+++ b/m4/posix_fallocate.m4
@@ -0,0 +1,20 @@
+# posix_fallocate.m4 serial 1
+dnl Copyright (C) 2024 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_POSIX_FALLOCATE],
+[
+  AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
+  gl_CHECK_FUNCS_ANDROID([posix_fallocate], [[#include <fcntl.h>]])
+  if test "$ac_cv_func_posix_fallocate" = no; then
+    HAVE_FALLOCATE_POSIX=0
+    case "$gl_cv_onwards_func_posix_fallocate" in
+      future*) REPLACE_FALLOCATE_POSIX=1 ;;
+    esac
+  fi
+])
+
+# Prerequisites of lib/posix_fallocate.c.
+AC_DEFUN([gl_PREREQ_POSIX_FALLOCATE], [:])
--- a/m4/fcntl_h.m4
+++ b/m4/fcntl_h.m4
@@ -23,7 +23,7 @@ AC_DEFUN_ONCE([gl_FCNTL_H],
   dnl corresponding gnulib module is not in use, if it is not common
   dnl enough to be declared everywhere.
   gl_WARN_ON_USE_PREPARE([[#include <fcntl.h>
-    ]], [fcntl openat])
+    ]], [fcntl openat posix_fallocate])
 ])
 
 # gl_FCNTL_MODULE_INDICATOR([modulename])
@@ -50,6 +50,7 @@ AC_DEFUN([gl_FCNTL_H_REQUIRE_DEFAULTS],
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_NONBLOCKING])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OPEN])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OPENAT])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FALLOCATE_POSIX])
     dnl Support Microsoft deprecated alias function names by default.
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_CREAT], [1])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_OPEN], [1])
@@ -61,10 +62,12 @@ AC_DEFUN([gl_FCNTL_H_REQUIRE_DEFAULTS],
 AC_DEFUN([gl_FCNTL_H_DEFAULTS],
 [
   dnl Assume proper GNU behavior unless another module says otherwise.
-  HAVE_FCNTL=1;          AC_SUBST([HAVE_FCNTL])
-  HAVE_OPENAT=1;         AC_SUBST([HAVE_OPENAT])
-  REPLACE_CREAT=0;       AC_SUBST([REPLACE_CREAT])
-  REPLACE_FCNTL=0;       AC_SUBST([REPLACE_FCNTL])
-  REPLACE_OPEN=0;        AC_SUBST([REPLACE_OPEN])
-  REPLACE_OPENAT=0;      AC_SUBST([REPLACE_OPENAT])
+  HAVE_FCNTL=1;              AC_SUBST([HAVE_FCNTL])
+  HAVE_OPENAT=1;             AC_SUBST([HAVE_OPENAT])
+  HAVE_FALLOCATE_POSIX=1;    AC_SUBST([HAVE_FALLOCATE_POSIX])
+  REPLACE_CREAT=0;           AC_SUBST([REPLACE_CREAT])
+  REPLACE_FCNTL=0;           AC_SUBST([REPLACE_FCNTL])
+  REPLACE_OPEN=0;            AC_SUBST([REPLACE_OPEN])
+  REPLACE_OPENAT=0;          AC_SUBST([REPLACE_OPENAT])
+  REPLACE_FALLOCATE_POSIX=0; AC_SUBST([REPLACE_FALLOCATE_POSIX])
 ])
--- a/modules/fcntl-h
+++ b/modules/fcntl-h
@@ -40,14 +40,17 @@ fcntl.h: fcntl.in.h $(top_builddir)/conf
 	      -e 's/@''GNULIB_NONBLOCKING''@/$(GNULIB_NONBLOCKING)/g' \
 	      -e 's/@''GNULIB_OPEN''@/$(GNULIB_OPEN)/g' \
 	      -e 's/@''GNULIB_OPENAT''@/$(GNULIB_OPENAT)/g' \
+	      -e 's/@''GNULIB_FALLOCATE_POSIX''@/$(GNULIB_FALLOCATE_POSIX)/g' \
 	      -e 's/@''GNULIB_MDA_CREAT''@/$(GNULIB_MDA_CREAT)/g' \
 	      -e 's/@''GNULIB_MDA_OPEN''@/$(GNULIB_MDA_OPEN)/g' \
 	      -e 's|@''HAVE_FCNTL''@|$(HAVE_FCNTL)|g' \
 	      -e 's|@''HAVE_OPENAT''@|$(HAVE_OPENAT)|g' \
+	      -e 's|@''HAVE_FALLOCATE_POSIX''@|$(HAVE_FALLOCATE_POSIX)|g' \
 	      -e 's|@''REPLACE_CREAT''@|$(REPLACE_CREAT)|g' \
 	      -e 's|@''REPLACE_FCNTL''@|$(REPLACE_FCNTL)|g' \
 	      -e 's|@''REPLACE_OPEN''@|$(REPLACE_OPEN)|g' \
 	      -e 's|@''REPLACE_OPENAT''@|$(REPLACE_OPENAT)|g' \
+	      -e 's|@''REPLACE_FALLOCATE_POSIX''@|$(REPLACE_FALLOCATE_POSIX)|g' \
 	      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
 	      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
 	      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
--- a/lib/fcntl.in.h
+++ b/lib/fcntl.in.h
@@ -238,6 +238,33 @@ _GL_WARN_ON_USE (openat, "openat is not
 # endif
 #endif
 
+#if @GNULIB_FALLOCATE_POSIX@
+# if @REPLACE_FALLOCATE_POSIX@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef posix_fallocate
+#   define posix_fallocate rpl_posix_fallocate
+#  endif
+_GL_FUNCDECL_RPL (posix_fallocate, int,
+                  (int fd, off_t offset, off_t len));
+_GL_CXXALIAS_RPL (posix_fallocate, int,
+                  (int fd, off_t offset, off_t len));
+# else
+#  if !@HAVE_FALLOCATE_POSIX@
+_GL_FUNCDECL_SYS (posix_fallocate, int,
+                  (int fd, off_t offset, off_t len));
+#  endif
+_GL_CXXALIAS_SYS (posix_fallocate, int,
+                  (int fd, off_t offset, off_t len));
+# endif
+_GL_CXXALIASWARN (posix_fallocate);
+#elif defined GNULIB_POSIXCHECK
+# undef posix_fallocate
+# if HAVE_RAW_DECL_POSIX_FALLOCATE
+_GL_WARN_ON_USE (posix_fallocate, "posix_fallocate is not portable - "
+                 "use gnulib module fallocate-posix for portability");
+# endif
+#endif
+
 
 /* Fix up the FD_* macros, only known to be missing on mingw.  */
 
--- /dev/null
+++ b/lib/posix_fallocate.c
@@ -0,0 +1,150 @@
+/* posix_fallocate function that is glibc compatible.
+
+   Copyright (C) 2024 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+
+#ifdef __APPLE__
+# include <sys/param.h>
+# include <sys/mount.h>
+#else
+# include <sys/statfs.h>
+#endif
+
+/* Reserve storage for the data of the file associated with FD.  This
+   emulation is far from perfect, but the kernel cannot do not much
+   better for network file systems, either.  */
+
+int
+posix_fallocate (int fd, off_t offset, off_t len)
+{
+  int ret;
+  struct stat st;
+
+  if (fd < 0 || offset < 0 || len < 0)
+    return EINVAL;
+
+  /* Perform overflow check.  The outer cast relies on a GCC
+     extension.  */
+  if ((off_t) ((uint64_t) offset + (uint64_t) len) < 0)
+    return EFBIG;
+
+  /* pwrite below will not do the right thing in O_APPEND mode.  */
+  {
+    int flags = fcntl (fd, F_GETFL, 0);
+    if (flags < 0 || (flags & O_APPEND) != 0)
+      return EBADF;
+  }
+
+  /* We have to make sure that this is really a regular file.  */
+  if (fstat (fd, &st) != 0)
+    return EBADF;
+  if (S_ISFIFO (st.st_mode))
+    return ESPIPE;
+  if (! S_ISREG (st.st_mode))
+    return ENODEV;
+
+  if (len == 0)
+    {
+      /* This is racy, but there is no good way to satisfy a
+	 zero-length allocation request.  */
+      if (st.st_size < offset)
+	{
+	  ret = ftruncate (fd, offset);
+
+	  if (ret != 0)
+	    ret = errno;
+	  return ret;
+	}
+      return ret;
+    }
+
+#ifdef __APPLE__
+    fstore_t sto = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, offset + len, 0};
+    /* allocate continuous */
+    ret = fcntl (fd, F_PREALLOCATE, &sto);
+    if (ret < 0)
+      {
+        /* allocate non-continuous */
+        sto.fst_flags = F_ALLOCATEALL;
+        ret = fcntl (fd, F_PREALLOCATE, &sto);
+        if (ret < 0)
+          {
+            return ret;
+          }
+      }
+    ret = ftruncate(fd, offset + len);
+#else
+
+  /* Minimize data transfer for network file systems, by issuing
+     single-byte write requests spaced by the file system block size.
+     (Most local file systems have fallocate support, so this fallback
+     code is not used there.)  */
+
+  unsigned increment;
+  {
+    struct statfs f;
+
+    if (fstatfs (fd, &f) != 0)
+      return errno;
+    if (f.f_bsize == 0)
+      increment = 512;
+    else if (f.f_bsize < 4096)
+      increment = f.f_bsize;
+    else
+      /* NFS does not propagate the block size of the underlying
+	 storage and may report a much larger value which would still
+	 leave holes after the loop below, so we cap the increment at
+	 4096.  */
+      increment = 4096;
+  }
+
+  /* Write a null byte to every block.  This is racy; we currently
+     lack a better option.  Compare-and-swap against a file mapping
+     might additional local races, but requires interposition of a
+     signal handler to catch SIGBUS.  */
+  for (offset += (len - 1) % increment; len > 0; offset += increment)
+    {
+      len -= increment;
+
+      if (offset < st.st_size)
+	{
+	  unsigned char c;
+	  ssize_t rsize = pread (fd, &c, 1, offset);
+
+	  if (rsize < 0)
+	    return errno;
+	  /* If there is a non-zero byte, the block must have been
+	     allocated already.  */
+	  else if (rsize == 1 && c != 0)
+	    continue;
+	}
+
+      if (pwrite (fd, "", 1, offset) != 1)
+	return errno;
+    }
+
+#endif /* __APPLE__ */
+
+  return ret;
+}
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -2552,6 +2552,7 @@ func_all_modules ()
   func_module execve
   func_module execvp
   func_module execvpe
+  func_module fallocate-posix
   func_module fchdir
   func_module fclose
   func_module fcntl-h