[libc-commits] [libc] d569554 - [libc] Implement fallocate (#222843)
via libc-commits
libc-commits at lists.llvm.org
Fri Sep 18 05:15:19 PDT 2026
Author: yahia
Date: 2026-09-18T12:15:13Z
New Revision: d569554ee8db7de233e0a866ba1df6cc7e5a1a72
URL: https://github.com/llvm/llvm-project/commit/d569554ee8db7de233e0a866ba1df6cc7e5a1a72
DIFF: https://github.com/llvm/llvm-project/commit/d569554ee8db7de233e0a866ba1df6cc7e5a1a72.diff
LOG: [libc] Implement fallocate (#222843)
Implement fallocate function by adding a syscall wrapper.
Assisted-by: gemini (for the tests and macros)
Added:
libc/src/__support/OSUtil/linux/syscall_wrappers/fallocate.h
libc/src/fcntl/fallocate.h
libc/src/fcntl/linux/fallocate.cpp
libc/test/src/fcntl/linux/CMakeLists.txt
libc/test/src/fcntl/linux/fallocate_test.cpp
Modified:
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/riscv/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/include/fcntl.yaml
libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
libc/src/fcntl/CMakeLists.txt
libc/src/fcntl/linux/CMakeLists.txt
libc/test/src/fcntl/CMakeLists.txt
libc/utils/docgen/fcntl.yaml
Removed:
################################################################################
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 4de8ce85b0569..f87ba3437fb6c 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -38,6 +38,7 @@ set(TARGET_LIBC_ENTRYPOINTS
# fcntl.h entrypoints
libc.src.fcntl.creat
+ libc.src.fcntl.fallocate
libc.src.fcntl.fcntl
libc.src.fcntl.open
libc.src.fcntl.openat
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 889b4c5c79dbb..51587056fb02d 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -49,6 +49,7 @@ set(TARGET_LIBC_ENTRYPOINTS
# fcntl.h entrypoints
libc.src.fcntl.creat
+ libc.src.fcntl.fallocate
libc.src.fcntl.fcntl
libc.src.fcntl.open
libc.src.fcntl.openat
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 8e748287a2469..8b77efa648c43 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -49,6 +49,7 @@ set(TARGET_LIBC_ENTRYPOINTS
# fcntl.h entrypoints
libc.src.fcntl.creat
+ libc.src.fcntl.fallocate
libc.src.fcntl.fcntl
libc.src.fcntl.open
libc.src.fcntl.openat
diff --git a/libc/include/fcntl.yaml b/libc/include/fcntl.yaml
index 2b73c8da1e989..49aac448e7076 100644
--- a/libc/include/fcntl.yaml
+++ b/libc/include/fcntl.yaml
@@ -40,6 +40,15 @@ functions:
arguments:
- type: const char *
- type: mode_t
+ - name: fallocate
+ standards:
+ - linux
+ return_type: int
+ arguments:
+ - type: int
+ - type: int
+ - type: off_t
+ - type: off_t
- name: fcntl
standards:
- posix
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index 8455b5f405006..95abcfa59d3de 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -1304,3 +1304,19 @@ add_header_library(
libc.src.__support.macros.config
libc.src.__support.OSUtil.osutil
)
+
+add_header_library(
+ fallocate
+ HDRS
+ fallocate.h
+ DEPENDS
+ libc.src.__support.macros.config
+ libc.src.__support.common
+ libc.src.__support.OSUtil.osutil
+ libc.include.sys_syscall
+ libc.hdr.types.off_t
+ libc.hdr.errno_macros
+ libc.src.__support.CPP.limits
+ libc.src.__support.CPP.bit
+ libc.src.__support.error_or
+)
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/fallocate.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/fallocate.h
new file mode 100644
index 0000000000000..2d80c7256dec0
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/fallocate.h
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declaration of the fallocate, which is the
+/// base syscall wrapper for all fallocate dependent calls.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FALLOCATE_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_FALLOCATE_H
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/off_t.h"
+#include "src/__support/CPP/bit.h"
+#include "src/__support/CPP/limits.h"
+#include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> fallocate(int fd, int mode, off_t offset, off_t size) {
+ if constexpr (sizeof(long) == sizeof(uint32_t) &&
+ sizeof(off_t) == sizeof(uint64_t)) {
+ uint64_t offset_bits = cpp::bit_cast<uint64_t>(offset);
+ long offset_low = static_cast<long>(offset_bits & UINT32_MAX);
+ long offset_high = static_cast<long>(offset_bits >> 32);
+ uint64_t len_bits = cpp::bit_cast<uint64_t>(size);
+ long len_low = static_cast<long>(len_bits & UINT32_MAX);
+ long len_high = static_cast<long>(len_bits >> 32);
+ return syscall_checked<int>(SYS_fallocate, fd, mode, offset_low,
+ offset_high, len_low, len_high);
+ } else {
+ return syscall_checked<int>(SYS_fallocate, fd, mode, offset, size);
+ }
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+#endif
diff --git a/libc/src/fcntl/CMakeLists.txt b/libc/src/fcntl/CMakeLists.txt
index 09afab57b7aa5..99fb047cdc8c3 100644
--- a/libc/src/fcntl/CMakeLists.txt
+++ b/libc/src/fcntl/CMakeLists.txt
@@ -16,6 +16,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.fcntl
)
+add_entrypoint_object(
+ fallocate
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.fallocate
+)
+
add_entrypoint_object(
open
ALIAS
diff --git a/libc/src/fcntl/fallocate.h b/libc/src/fcntl/fallocate.h
new file mode 100644
index 0000000000000..2924637c3a696
--- /dev/null
+++ b/libc/src/fcntl/fallocate.h
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for fallocate
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_FCNTL_FALLOCATE_H
+#define LLVM_LIBC_SRC_FCNTL_FALLOCATE_H
+
+#include "hdr/types/off_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int fallocate(int fd, int mode, off_t offset, off_t size);
+
+}
+
+#endif
diff --git a/libc/src/fcntl/linux/CMakeLists.txt b/libc/src/fcntl/linux/CMakeLists.txt
index e50cc45c9ea7a..fa41eeb1b2f1e 100644
--- a/libc/src/fcntl/linux/CMakeLists.txt
+++ b/libc/src/fcntl/linux/CMakeLists.txt
@@ -11,6 +11,18 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ fallocate
+ SRCS
+ fallocate.cpp
+ HDRS
+ ../fallocate.h
+ DEPENDS
+ libc.src.errno.errno
+ libc.src.__support.OSUtil.linux.syscall_wrappers.fallocate
+ libc.hdr.types.off_t
+)
+
add_entrypoint_object(
fcntl
SRCS
diff --git a/libc/src/fcntl/linux/fallocate.cpp b/libc/src/fcntl/linux/fallocate.cpp
new file mode 100644
index 0000000000000..21e9c276d500c
--- /dev/null
+++ b/libc/src/fcntl/linux/fallocate.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declaration of the fallocate, which is the
+/// fcntl fallocate function for linux.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/fcntl/fallocate.h"
+
+#include "hdr/types/off_t.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/fallocate.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, fallocate,
+ (int fd, int mode, off_t offset, off_t size)) {
+ auto result = linux_syscalls::fallocate(fd, mode, offset, size);
+ if (!result.has_value()) {
+ libc_errno = result.error();
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/fcntl/CMakeLists.txt b/libc/test/src/fcntl/CMakeLists.txt
index 6a2acd9578697..085fda5762704 100644
--- a/libc/test/src/fcntl/CMakeLists.txt
+++ b/libc/test/src/fcntl/CMakeLists.txt
@@ -99,3 +99,7 @@ add_libc_test(
libc.test.UnitTest.ErrnoCheckingTest
libc.test.UnitTest.ErrnoSetterMatcher
)
+
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+ add_subdirectory(${LIBC_TARGET_OS})
+endif()
diff --git a/libc/test/src/fcntl/linux/CMakeLists.txt b/libc/test/src/fcntl/linux/CMakeLists.txt
new file mode 100644
index 0000000000000..a280fdbac652c
--- /dev/null
+++ b/libc/test/src/fcntl/linux/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_libc_test(
+ fallocate_test
+ SUITE
+ libc_fcntl_unittests
+ SRCS
+ fallocate_test.cpp
+ DEPENDS
+ libc.include.fcntl
+ libc.src.fcntl.fallocate
+ libc.src.fcntl.open
+ libc.src.unistd.close
+ libc.src.unistd.unlink
+ libc.src.sys.stat.fstat
+ libc.src.__support.libc_errno
+)
diff --git a/libc/test/src/fcntl/linux/fallocate_test.cpp b/libc/test/src/fcntl/linux/fallocate_test.cpp
new file mode 100644
index 0000000000000..a7cbb44d011d1
--- /dev/null
+++ b/libc/test/src/fcntl/linux/fallocate_test.cpp
@@ -0,0 +1,93 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the tests for the fallocate POSIX functions
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/fcntl_macros.h"
+#include "src/__support/CPP/scope.h"
+#include "src/__support/libc_errno.h"
+#include "src/fcntl/fallocate.h"
+#include "src/fcntl/open.h"
+#include "src/sys/stat/fstat.h"
+#include "src/sys/stat/stat.h"
+#include "src/unistd/close.h"
+#include "src/unistd/unlink.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+#include <linux/falloc.h>
+
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+
+TEST(LlvmLibcFallocateTest, BasicAllocate) {
+ constexpr char TEST_FILE[] = "fallocate_basic.test";
+
+ int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0600);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_GT(fd, 0);
+ LIBC_NAMESPACE::cpp::scope_exit cleanup_fd([&] {
+ EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE), Succeeds(0));
+ EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ });
+
+ // Mode 0: expand file size to offset + len (4096 bytes)
+ ASSERT_THAT(LIBC_NAMESPACE::fallocate(fd, 0, 1024, 3072), Succeeds(0));
+
+ struct stat st;
+ ASSERT_EQ(LIBC_NAMESPACE::fstat(fd, &st), 0);
+ ASSERT_EQ(static_cast<off_t>(st.st_size), static_cast<off_t>(4096));
+}
+
+TEST(LlvmLibcFallocateTest, KeepSize) {
+ constexpr char TEST_FILE[] = "fallocate_keep_size.test";
+
+ int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0600);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_GT(fd, 0);
+ LIBC_NAMESPACE::cpp::scope_exit cleanup_fd([&] {
+ EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE), Succeeds(0));
+ EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ });
+
+ // Pre-allocate space at offset 8192, length 4096, but keep file size at 0
+ ASSERT_THAT(LIBC_NAMESPACE::fallocate(fd, FALLOC_FL_KEEP_SIZE, 8192, 4096),
+ Succeeds(0));
+
+ struct stat st;
+ ASSERT_EQ(LIBC_NAMESPACE::fstat(fd, &st), 0);
+ ASSERT_EQ(static_cast<off_t>(st.st_size), static_cast<off_t>(0));
+}
+
+TEST(LlvmLibcFallocateTest, InvalidFd) {
+ // Passing an invalid file descriptor should fail with EBADF
+ ASSERT_THAT(LIBC_NAMESPACE::fallocate(-1, 0, 0, 4096), Fails(EBADF));
+}
+
+TEST(LlvmLibcFallocateTest, InvalidMode) {
+ constexpr char TEST_FILE[] = "fallocate_invalid_mode.test";
+
+ int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0600);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_GT(fd, 0);
+ LIBC_NAMESPACE::cpp::scope_exit cleanup_fd([&] {
+ EXPECT_THAT(LIBC_NAMESPACE::unlink(TEST_FILE), Succeeds(0));
+ EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+ });
+
+ ASSERT_EQ(LIBC_NAMESPACE::fallocate(fd, -1, 0, 4096), -1);
+ // Could be any one of those and potentially more depending on the file system
+ ASSERT_TRUE(libc_errno == EINVAL || libc_errno == ENOTSUP ||
+ libc_errno == EOPNOTSUPP);
+ // for the cleanup to work
+ libc_errno = 0;
+}
diff --git a/libc/utils/docgen/fcntl.yaml b/libc/utils/docgen/fcntl.yaml
index 7a6b656cc0a80..1053f357901d9 100644
--- a/libc/utils/docgen/fcntl.yaml
+++ b/libc/utils/docgen/fcntl.yaml
@@ -11,6 +11,8 @@ functions:
in-latest-posix: ''
posix_fallocate:
in-latest-posix: ''
+ fallocate:
+ c-definition: ''
macros:
AT_EACCESS:
More information about the libc-commits
mailing list