Skip to content

[libc] Add Linux mman extension remap_file_pages. #110307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libc/config/linux/aarch64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.mman.munlock
libc.src.sys.mman.munlockall
libc.src.sys.mman.munmap
libc.src.sys.mman.remap_file_pages
libc.src.sys.mman.posix_madvise
libc.src.sys.mman.shm_open
libc.src.sys.mman.shm_unlink
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/riscv/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.mman.munlock
libc.src.sys.mman.munlockall
libc.src.sys.mman.munmap
libc.src.sys.mman.remap_file_pages
libc.src.sys.mman.posix_madvise
libc.src.sys.mman.shm_open
libc.src.sys.mman.shm_unlink
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.sys.mman.munlock
libc.src.sys.mman.munlockall
libc.src.sys.mman.munmap
libc.src.sys.mman.remap_file_pages
libc.src.sys.mman.posix_madvise
libc.src.sys.mman.shm_open
libc.src.sys.mman.shm_unlink
Expand Down
10 changes: 10 additions & 0 deletions libc/newhdrgen/yaml/sys/mman.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,16 @@ functions:
- type: void *
- type: size_t
- type: int
- name: remap_file_pages
standards:
- Linux
return_type: int
arguments:
- type: void *
- type: size_t
- type: int
- type: size_t
- type: int
- name: shm_open
standards:
- POSIX
Expand Down
11 changes: 11 additions & 0 deletions libc/spec/linux.td
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ def Linux : StandardSpec<"Linux"> {
ArgSpec<UnsignedIntType>,
]
>,
FunctionSpec<
"remap_file_pages",
RetValSpec<IntType>,
[
ArgSpec<VoidPtr>,
ArgSpec<SizeTType>,
ArgSpec<IntType>,
ArgSpec<SizeTType>,
ArgSpec<IntType>,
]
>,
] // Functions
>;

Expand Down
7 changes: 7 additions & 0 deletions libc/src/sys/mman/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.msync
)

add_entrypoint_object(
remap_file_pages
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.remap_file_pages
)

add_entrypoint_object(
shm_open
ALIAS
Expand Down
13 changes: 13 additions & 0 deletions libc/src/sys/mman/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,19 @@ add_entrypoint_object(
libc.src.errno.errno
)

add_entrypoint_object(
remap_file_pages
SRCS
remap_file_pages.cpp
HDRS
../remap_file_pages.h
DEPENDS
libc.include.sys_mman
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)

add_header_library(
shm_common
HDRS
Expand Down
40 changes: 40 additions & 0 deletions libc/src/sys/mman/linux/remap_file_pages.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===------- Linux implementation of the remap_file_pages function --------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "src/sys/mman/remap_file_pages.h"

#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/errno/libc_errno.h"
#include <sys/syscall.h> // For syscall numbers.

namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(int, remap_file_pages,
(void *addr, size_t size, int prot, size_t pgoff,
int flags)) {
#ifdef SYS_remap_file_pages
int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_remap_file_pages,
reinterpret_cast<long>(addr),
size, prot, pgoff, flags);
#else
#error "remap_file_pages syscall is not available."
#endif

// A negative return value indicates an error with the magnitude of the
// value being the error code.
if (ret < 0) {
libc_errno = -ret;
return -1;
}

return 0;
}

} // namespace LIBC_NAMESPACE_DECL
22 changes: 22 additions & 0 deletions libc/src/sys/mman/remap_file_pages.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===-- Implementation header for remap_file_pages function -----*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_SYS_MMAN_REMAP_FILE_PAGES_H
#define LLVM_LIBC_SRC_SYS_MMAN_REMAP_FILE_PAGES_H

#include "src/__support/macros/config.h"
#include <stddef.h>

namespace LIBC_NAMESPACE_DECL {

int remap_file_pages(void *addr, size_t size, int prot, size_t pgoff,
int flags);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_SYS_MMAN_REMAP_FILE_PAGES_H
17 changes: 17 additions & 0 deletions libc/test/src/sys/mman/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,23 @@ add_libc_unittest(
libc.test.UnitTest.ErrnoSetterMatcher
)

add_libc_unittest(
remap_file_pages_test
SUITE
libc_sys_mman_unittests
SRCS
remap_file_pages_test.cpp
DEPENDS
libc.include.sys_mman
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
libc.include.sys_mman
libc.include.sys_mman
libc.include.sys_stat

libc.include.sys_stat
libc.src.unistd.sysconf
libc.test.UnitTest.ErrnoSetterMatcher
libc.src.sys.mman.remap_file_pages
libc.src.errno.errno
libc.src.sys.mman.mmap
libc.src.sys.mman.munmap
)

add_libc_unittest(
shm_test
SUITE
Expand Down
93 changes: 93 additions & 0 deletions libc/test/src/sys/mman/linux/remap_file_pages_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//===-- Unittests for remap_file_pages ------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "src/errno/libc_errno.h"
#include "src/fcntl/open.h"
#include "src/sys/mman/mmap.h"
#include "src/sys/mman/munmap.h"
#include "src/sys/mman/remap_file_pages.h"
#include "src/unistd/close.h"
#include "src/unistd/sysconf.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"

#include <sys/mman.h>
#include <sys/stat.h> // For S_IRWXU

using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;

TEST(LlvmLibcRemapFilePagesTest, NoError) {
size_t page_size = sysconf(_SC_PAGE_SIZE);
ASSERT_GT(page_size, size_t(0));

// Create a file-backed mapping
constexpr const char *file_name = "remap_file_pages.test.noerror";
auto test_file = libc_make_test_file_path(file_name);
int fd = LIBC_NAMESPACE::open(test_file, O_RDWR | O_CREAT, S_IRWXU);
ASSERT_GT(fd, 0);

// First, allocate some memory using mmap
size_t alloc_size = 2 * page_size;
LIBC_NAMESPACE::libc_errno = 0;
void *addr = LIBC_NAMESPACE::mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
ASSERT_ERRNO_SUCCESS();
EXPECT_NE(addr, MAP_FAILED);

// Now try to remap the pages
EXPECT_THAT(LIBC_NAMESPACE::remap_file_pages(addr, page_size, 0, 1, 0),
Succeeds());

// Reset error number for the new function
LIBC_NAMESPACE::libc_errno = 0;

// Clean up
EXPECT_THAT(LIBC_NAMESPACE::munmap(addr, alloc_size), Succeeds());
EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds());
}

TEST(LlvmLibcRemapFilePagesTest, ErrorInvalidFlags) {
size_t page_size = sysconf(_SC_PAGE_SIZE);
ASSERT_GT(page_size, size_t(0));

// Create a file-backed mapping
constexpr const char *file_name = "remap_file_pages.test.error";
auto test_file = libc_make_test_file_path(file_name);
int fd = LIBC_NAMESPACE::open(test_file, O_RDWR | O_CREAT, S_IRWXU);
ASSERT_GT(fd, 0);

// First, allocate some memory using mmap
size_t alloc_size = 2 * page_size;
LIBC_NAMESPACE::libc_errno = 0;
void *addr = LIBC_NAMESPACE::mmap(nullptr, alloc_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
ASSERT_ERRNO_SUCCESS();
EXPECT_NE(addr, MAP_FAILED);

// Try to remap pages with an invalid flag MAP_PRIVATE
EXPECT_THAT(LIBC_NAMESPACE::remap_file_pages(addr, page_size, PROT_READ, 0,
MAP_PRIVATE),
Fails(EINVAL));

// Clean up
EXPECT_THAT(LIBC_NAMESPACE::munmap(addr, page_size), Succeeds());
EXPECT_THAT(LIBC_NAMESPACE::close(fd), Succeeds());
}

TEST(LlvmLibcRemapFilePagesTest, ErrorInvalidAddress) {
size_t page_size = sysconf(_SC_PAGESIZE);
ASSERT_GT(page_size, size_t(0));

// Use an address that we haven't mapped
void *invalid_addr = reinterpret_cast<void *>(0x12345000);

EXPECT_THAT(LIBC_NAMESPACE::remap_file_pages(invalid_addr, page_size,
PROT_READ, 0, 0),
Fails(EINVAL));
}
Loading