librdmacm: Add support for fcntl64 Add preload interception for fcntl64 so rsocket file descriptors support the same flag semantics as the glibc fcntl64 API. Signed-off-by: Batsheva Black <bblack@nvidia.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt index 9165fa2..d694e3e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -449,6 +449,52 @@ add_definitions("-D_FILE_OFFSET_BITS=64") endif() +# librspreload: probe libc for fcntl64; CMake sets RDMA_PRELOAD_WRAP_LFS64 when +# preload should implement the fcntl64 wrapper (see RDMA_PRELOAD_WRAP_LFS64 below). +set(CMAKE_REQUIRED_QUIET 1) +set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") +set(CMAKE_REQUIRED_DEFINITIONS "") +CHECK_C_SOURCE_COMPILES(" +#include <fcntl.h> +int main(void) { + (void)&fcntl64; + return 0; +} +" RDMA_PRELOAD_LIBC_HAS_FCNTL64_SENDFILE64) +set(CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") +set(CMAKE_REQUIRED_QUIET 0) +if(RDMA_PRELOAD_LIBC_HAS_FCNTL64_SENDFILE64) + set(RDMA_PRELOAD_HAVE_LFS_WRAPPER_SYMS 1) +else() + set(RDMA_PRELOAD_HAVE_LFS_WRAPPER_SYMS 0) +endif() + +# Single gate for preload.c fcntl64 wrapper: need libc symbol and must not compile +# preload with _FILE_OFFSET_BITS=64 (CMake adds that when HAVE_LARGE_FILES is false). +if(RDMA_PRELOAD_HAVE_LFS_WRAPPER_SYMS AND HAVE_LARGE_FILES) + set(RDMA_PRELOAD_WRAP_LFS64 1) +else() + set(RDMA_PRELOAD_WRAP_LFS64 0) +endif() + +set(RDMA_PRELOAD_FCNTL64_IN_HEADER 0) +set(RDMA_PRELOAD_SENDFILE64_IN_HEADER 0) +if(RDMA_PRELOAD_HAVE_LFS_WRAPPER_SYMS) + set(CMAKE_REQUIRED_QUIET 1) + set(SAFE_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") + set(CMAKE_REQUIRED_FLAGS "${CMAKE_C_FLAGS}") + CHECK_C_SOURCE_COMPILES(" +#define _GNU_SOURCE +#include <fcntl.h> +int fcntl64(int socket, int cmd, ...) { (void)socket;(void)cmd; return 0; } +" RDMA_PRELOAD_FCNTL64_DECLARED_IN_HEADER) + if(RDMA_PRELOAD_FCNTL64_DECLARED_IN_HEADER) + set(RDMA_PRELOAD_FCNTL64_IN_HEADER 1) + endif() + set(CMAKE_REQUIRED_FLAGS "${SAFE_CMAKE_REQUIRED_FLAGS}") + set(CMAKE_REQUIRED_QUIET 0) +endif() + # Provide a shim if C11 stdatomic.h is not supported. if (NOT HAVE_SPARSE) CHECK_INCLUDE_FILE("stdatomic.h" HAVE_STDATOMIC)
diff --git a/buildlib/rdma_functions.cmake b/buildlib/rdma_functions.cmake index ef77d95..8d48612 100644 --- a/buildlib/rdma_functions.cmake +++ b/buildlib/rdma_functions.cmake
@@ -120,6 +120,18 @@ install(TARGETS ${DEST} DESTINATION "${CMAKE_INSTALL_LIBDIR}") endfunction() +# rsocket LD_PRELOAD module. Requires RDMA_PRELOAD_* variables from top-level +# CMakeLists.txt (RDMA_PRELOAD_WRAP_LFS64 and fcntl64 header probe). +function(rdma_rspreload_module DEST VERSION_SCRIPT) + add_library(${DEST} MODULE ${ARGN}) + target_compile_definitions(${DEST} PRIVATE + RDMA_PRELOAD_WRAP_LFS64=${RDMA_PRELOAD_WRAP_LFS64} + RDMA_PRELOAD_FCNTL64_IN_HEADER=${RDMA_PRELOAD_FCNTL64_IN_HEADER}) + set_target_properties(${DEST} PROPERTIES LINK_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}) + set_target_properties(${DEST} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${BUILD_LIB}") + rdma_set_library_map(${DEST} ${VERSION_SCRIPT}) +endfunction() + # Create a special provider with exported symbols in it The shared provider # exists as a normal system library with the normal shared library SONAME and # other convections. The system library is symlinked into the
diff --git a/librdmacm/CMakeLists.txt b/librdmacm/CMakeLists.txt index ea1d155..cba925a 100644 --- a/librdmacm/CMakeLists.txt +++ b/librdmacm/CMakeLists.txt
@@ -27,14 +27,10 @@ # The preload library is a bit special, it needs to be open coded # Since it is a LD_PRELOAD it has no soname, and is installed in sub dir -add_library(rspreload MODULE +rdma_rspreload_module(rspreload librspreload.map preload.c indexer.c ) -# Even though this is a module we still want to use Wl,--no-undefined -set_target_properties(rspreload PROPERTIES LINK_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}) -set_target_properties(rspreload PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${BUILD_LIB}") -rdma_set_library_map(rspreload librspreload.map) target_link_libraries(rspreload LINK_PRIVATE rdmacm ${CMAKE_THREAD_LIBS_INIT}
diff --git a/librdmacm/librspreload.map b/librdmacm/librspreload.map index 23a54d4..4e27671 100644 --- a/librdmacm/librspreload.map +++ b/librdmacm/librspreload.map
@@ -10,6 +10,7 @@ connect; dup2; fcntl; + fcntl64; getpeername; getsockname; getsockopt;
diff --git a/librdmacm/preload.c b/librdmacm/preload.c index 952e546..b8ae0ca 100644 --- a/librdmacm/preload.c +++ b/librdmacm/preload.c
@@ -59,6 +59,12 @@ #include "cma.h" #include "indexer.h" +#if RDMA_PRELOAD_WRAP_LFS64 +#if !RDMA_PRELOAD_FCNTL64_IN_HEADER +int fcntl64(int socket, int cmd, ... /* arg */); +#endif +#endif + struct socket_calls { int (*socket)(int domain, int type, int protocol); int (*bind)(int socket, const struct sockaddr *addr, socklen_t addrlen); @@ -88,6 +94,9 @@ int (*getsockopt)(int socket, int level, int optname, void *optval, socklen_t *optlen); int (*fcntl)(int socket, int cmd, ... /* arg */); +#if RDMA_PRELOAD_WRAP_LFS64 + int (*fcntl64)(int socket, int cmd, ... /* arg */); +#endif int (*dup2)(int oldfd, int newfd); ssize_t (*sendfile)(int out_fd, int in_fd, off_t *offset, size_t count); int (*fxstat)(int ver, int fd, struct stat *buf); @@ -410,6 +419,9 @@ real.setsockopt = dlsym(RTLD_NEXT, "setsockopt"); real.getsockopt = dlsym(RTLD_NEXT, "getsockopt"); real.fcntl = dlsym(RTLD_NEXT, "fcntl"); +#if RDMA_PRELOAD_WRAP_LFS64 + real.fcntl64 = dlsym(RTLD_NEXT, "fcntl64"); +#endif real.dup2 = dlsym(RTLD_NEXT, "dup2"); real.sendfile = dlsym(RTLD_NEXT, "sendfile"); real.fxstat = dlsym(RTLD_NEXT, "__fxstat"); @@ -647,7 +659,6 @@ if (cur_flags == -1) goto close; } - return fd; close: close(fd); @@ -1163,6 +1174,48 @@ return ret; } +#if RDMA_PRELOAD_WRAP_LFS64 +int fcntl64(int socket, int cmd, ... /* arg */) +{ + va_list args; + long lparam; + void *pparam; + int fd, ret; + + init_preload(); + va_start(args, cmd); + switch (cmd) { + case F_GETFD: + case F_GETFL: + case F_GETOWN: + case F_GETSIG: + case F_GETLEASE: + ret = (fd_get(socket, &fd) == fd_rsocket) ? + rfcntl(fd, cmd) : real.fcntl64(fd, cmd); + break; + case F_DUPFD: + /*case F_DUPFD_CLOEXEC:*/ + case F_SETFD: + case F_SETFL: + case F_SETOWN: + case F_SETSIG: + case F_SETLEASE: + case F_NOTIFY: + lparam = va_arg(args, long); + ret = (fd_get(socket, &fd) == fd_rsocket) ? + rfcntl(fd, cmd, lparam) : real.fcntl64(fd, cmd, lparam); + break; + default: + pparam = va_arg(args, void *); + ret = (fd_get(socket, &fd) == fd_rsocket) ? + rfcntl(fd, cmd, pparam) : real.fcntl64(fd, cmd, pparam); + break; + } + va_end(args); + return ret; +} +#endif + /* * dup2 is not thread safe */