Commit 34197e5f authored by Marc Vef's avatar Marc Vef
Browse files

ifs-preload: stability, and bug fixes

parent 2064d9ab
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ margo_instance_id ld_margo_id();

hg_addr_t daemon_addr();

void init_passthrough_if_needed();

void init_preload(void) __attribute__((constructor));

+1 −1
Original line number Diff line number Diff line
@@ -15,4 +15,4 @@ set(SOURCE_FILES_PRELOAD preload.cpp open_file_map.cpp ../../include/preload/pre
add_library(iointer SHARED ${SOURCE_FILES_PRELOAD})
target_link_libraries(iointer dl ${BMI_LIBRARIES} ${MERCURY_LIBRARIES} ${MERCURY_UTIL_LIBRARIES} ${ABT_LIBRARIES}
        ${ABT_SNOOZER_LIBRARIES} ${MARGO_LIBRARIES}
        -lboost_system)
 No newline at end of file
        -lpthread -lboost_system)
 No newline at end of file
+143 −87
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@
#include <sys/stat.h>
#include "../../main.hpp"

static pthread_once_t init_lib_thread = PTHREAD_ONCE_INIT;

// Mercury Client
hg_class_t* mercury_hg_class_;
hg_context_t* mercury_hg_context_;
@@ -25,7 +27,7 @@ static hg_id_t ipc_stat_id;
static hg_id_t ipc_unlink_id;

// misc
bool is_lib_initialized = false;
static std::atomic<bool> is_env_initialized(false);

// external variables
FILE* debug_fd;
@@ -36,9 +38,11 @@ void* libc;

void* libc_open;
//void* libc_open64; //unused
void* libc_fopen;
void* libc_fopen; // XXX Does not work with streaming pointers. If used will block forever
void* libc_fopen64; // XXX Does not work with streaming pointers. If used will block forever

//void* libc_creat; //unused
//void* libc_creat64; //unused
void* libc_unlink;

void* libc_close;
@@ -75,8 +79,9 @@ void* libc_dup2;

static OpenFileMap file_map{};

int ld_open(const char* path, int flags, ...) {
    DAEMON_DEBUG(debug_fd, "ld_open called with path %s\n", path);
int open(const char* path, int flags, ...) {
    init_passthrough_if_needed();
    DAEMON_DEBUG(debug_fd, "open called with path %s\n", path);
    mode_t mode;
    if (flags & O_CREAT) {
        va_list vl;
@@ -84,9 +89,8 @@ int ld_open(const char* path, int flags, ...) {
        mode = va_arg(vl, int);
        va_end(vl);
    }
    if (is_fs_path(path)) {
    if (is_env_initialized && is_fs_path(path)) {
        auto fd = file_map.add(path, (flags & O_APPEND) != 0);
        // TODO call daemon and return if successful return the above fd. if unsuccessful delete fd remove file from map
#ifndef MARGOIPC

#else
@@ -103,8 +107,9 @@ int ld_open(const char* path, int flags, ...) {
    return (reinterpret_cast<decltype(&open)>(libc_open))(path, flags, mode);
}

int ld_open64(__const char* path, int flags, ...) {
    DAEMON_DEBUG(debug_fd, "ld_open64 called with path %s\n", path);
int open64(__const char* path, int flags, ...) {
    init_passthrough_if_needed();
    DAEMON_DEBUG(debug_fd, "open64 called with path %s\n", path);
    mode_t mode;
    if (flags & O_CREAT) {
        va_list ap;
@@ -112,22 +117,42 @@ int ld_open64(__const char* path, int flags, ...) {
        mode = va_arg(ap, mode_t);
        va_end(ap);
    }
    return ld_open(path, flags | O_LARGEFILE, mode);
    return open(path, flags | O_LARGEFILE, mode);
}

FILE* ld_fopen(const char* path, const char* mode) {
//    DAEMON_DEBUG(debug_fd, "ld_fopen called with path %s with mode %d\n", path, mode);
    return (reinterpret_cast<decltype(&fopen)>(libc_fopen))(path, mode);
}
//// TODO This function somehow always blocks forever if one puts anything between the paththru...
//FILE* fopen(const char* path, const char* mode) {
////    init_passthrough_if_needed();
////    DAEMON_DEBUG(debug_fd, "fopen called with path %s\n", path);
//    return (reinterpret_cast<decltype(&fopen)>(libc_fopen))(path, mode);
//}

//// TODO This function somehow always blocks forever if one puts anything between the paththru...
//FILE* fopen64(const char* path, const char* mode) {
////    init_passthrough_if_needed();
////    DAEMON_DEBUG(debug_fd, "fopen64 called with path %s\n", path);
//    return (reinterpret_cast<decltype(&fopen)>(libc_fopen))(path, mode);
//}

#undef creat
int creat(const char* path, mode_t mode) {
    DAEMON_DEBUG(debug_fd, "ld_creat called with path %s with mode %d\n", path, mode);
    return ld_open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
    init_passthrough_if_needed();
    DAEMON_DEBUG(debug_fd, "creat called with path %s with mode %d\n", path, mode);
    return open(path, O_CREAT | O_WRONLY | O_TRUNC, mode);
}

#undef creat64

int creat64(const char* path, mode_t mode) {
    init_passthrough_if_needed();
    DAEMON_DEBUG(debug_fd, "creat64 called with path %s with mode %d\n", path, mode);
    return open(path, O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE, mode);
}

int unlink(const char* path) __THROW {
//    DAEMON_DEBUG(debug_fd, "ld_unlink called with path %s\n", path);
    if (is_fs_path(path)) {
    init_passthrough_if_needed();
//    DAEMON_DEBUG(debug_fd, "unlink called with path %s\n", path);
    if (is_env_initialized && is_fs_path(path)) {
#ifndef MARGOIPC
#else
        return ipc_send_unlink(path, ipc_unlink_id);
@@ -136,8 +161,9 @@ int unlink(const char* path) __THROW {
    return (reinterpret_cast<decltype(&unlink)>(libc_unlink))(path);
}

int ld_close(int fd) {
    if (file_map.exist(fd)) {
int close(int fd) {
    init_passthrough_if_needed();
    if (is_env_initialized && file_map.exist(fd)) {
        // Currently no call to the daemon is required
        file_map.remove(fd);
        return 0;
@@ -145,14 +171,15 @@ int ld_close(int fd) {
    return (reinterpret_cast<decltype(&close)>(libc_close))(fd);
}

int ld___close(int fd) {
    return ld_close(fd);
int __close(int fd) {
    return close(fd);
}


int ld_stat(const char* path, struct stat* buf) __THROW {
int stat(const char* path, struct stat* buf) __THROW {
    init_passthrough_if_needed();
    DAEMON_DEBUG(debug_fd, "stat called with path %s\n", path);
    if (is_fs_path(path)) {
    if (is_env_initialized && is_fs_path(path)) {
        // TODO call daemon and return
#ifndef MARGOIPC

@@ -164,9 +191,10 @@ int ld_stat(const char* path, struct stat* buf) __THROW {
    return (reinterpret_cast<decltype(&stat)>(libc_stat))(path, buf);
}

int ld_fstat(int fd, struct stat* buf) __THROW {
    DAEMON_DEBUG(debug_fd, "ld_fstat called with fd %d\n", fd);
    if (file_map.exist(fd)) {
int fstat(int fd, struct stat* buf) __THROW {
    init_passthrough_if_needed();
    DAEMON_DEBUG(debug_fd, "fstat called with fd %d\n", fd);
    if (is_env_initialized && file_map.exist(fd)) {
        auto path = file_map.get(fd)->path(); // TODO use this to send to the daemon (call directly)
        // TODO call daemon and return
#ifndef MARGOIPC
@@ -179,9 +207,10 @@ int ld_fstat(int fd, struct stat* buf) __THROW {
    return (reinterpret_cast<decltype(&fstat)>(libc_fstat))(fd, buf);
}

int ld___xstat(int ver, const char* path, struct stat* buf) __THROW {
    DAEMON_DEBUG(debug_fd, "ld___xstat called with path %s\n", path);
    if (is_fs_path(path)) {
int __xstat(int ver, const char* path, struct stat* buf) __THROW {
    init_passthrough_if_needed();
    DAEMON_DEBUG(debug_fd, "__xstat called with path %s\n", path);
    if (is_env_initialized && is_fs_path(path)) {
        // TODO call stat
#ifndef MARGOIPC

@@ -192,18 +221,20 @@ int ld___xstat(int ver, const char* path, struct stat* buf) __THROW {
    return (reinterpret_cast<decltype(&__xstat)>(libc___xstat))(ver, path, buf);
}

int ld___xstat64(int ver, const char* path, struct stat64* buf) __THROW {
    DAEMON_DEBUG(debug_fd, "ld___xstat64 called with path %s\n", path);
//    if (is_fs_path(path)) {
//        // Not implemented
//        return -1;
//    }
int __xstat64(int ver, const char* path, struct stat64* buf) __THROW {
    init_passthrough_if_needed();
    DAEMON_DEBUG(debug_fd, "__xstat64 called with path %s\n", path);
    if (is_env_initialized && is_fs_path(path)) {
        // Not implemented
        return -1;
    }
    return (reinterpret_cast<decltype(&__xstat64)>(libc___xstat64))(ver, path, buf);
}

int ld___fxstat(int ver, int fd, struct stat* buf) __THROW {
    DAEMON_DEBUG(debug_fd, "ld___fxstat called with fd %d\n", fd);
    if (file_map.exist(fd)) {
int __fxstat(int ver, int fd, struct stat* buf) __THROW {
    init_passthrough_if_needed();
    DAEMON_DEBUG(debug_fd, "__fxstat called with fd %d\n", fd);
    if (is_env_initialized && file_map.exist(fd)) {
        // TODO call fstat
        auto path = file_map.get(fd)->path();
#ifndef MARGOIPC
@@ -215,9 +246,10 @@ int ld___fxstat(int ver, int fd, struct stat* buf) __THROW {
    return (reinterpret_cast<decltype(&__fxstat)>(libc___fxstat))(ver, fd, buf);
}

int ld___fxstat64(int ver, int fd, struct stat64* buf) __THROW {
    DAEMON_DEBUG(debug_fd, "ld___fxstat64 called with fd %d\n", fd);
    if (file_map.exist(fd)) {
int __fxstat64(int ver, int fd, struct stat64* buf) __THROW {
    init_passthrough_if_needed();
    DAEMON_DEBUG(debug_fd, "__fxstat64 called with fd %d\n", fd);
    if (is_env_initialized && file_map.exist(fd)) {
        // TODO call fstat64
//        auto path = file_map.get(fd)->path();
#ifndef MARGOIPC
@@ -229,24 +261,27 @@ int ld___fxstat64(int ver, int fd, struct stat64* buf) __THROW {
    return (reinterpret_cast<decltype(&__fxstat64)>(libc___fxstat64))(ver, fd, buf);
}

extern int ld___lxstat(int ver, const char* path, struct stat* buf) __THROW {
    if (is_fs_path(path)) {
extern int __lxstat(int ver, const char* path, struct stat* buf) __THROW {
    init_passthrough_if_needed();
    if (is_env_initialized && is_fs_path(path)) {
        // Not implemented
        return -1;
    }
    return (reinterpret_cast<decltype(&__lxstat)>(libc___lxstat))(ver, path, buf);
}

extern int ld___lxstat64(int ver, const char* path, struct stat64* buf) __THROW {
    if (is_fs_path(path)) {
extern int __lxstat64(int ver, const char* path, struct stat64* buf) __THROW {
    init_passthrough_if_needed();
    if (is_env_initialized && is_fs_path(path)) {
        // Not implemented
        return -1;
    }
    return (reinterpret_cast<decltype(&__lxstat64)>(libc___lxstat64))(ver, path, buf);
}

int ld_access(const char* path, int mode) __THROW {
    if (is_fs_path(path)) {
int access(const char* path, int mode) __THROW {
    init_passthrough_if_needed();
    if (is_env_initialized && is_fs_path(path)) {
#ifndef MARGOIPC

#else
@@ -256,12 +291,13 @@ int ld_access(const char* path, int mode) __THROW {
    return (reinterpret_cast<decltype(&access)>(libc_access))(path, mode);
}

int ld_puts(const char* str) {
int puts(const char* str) {
    return (reinterpret_cast<decltype(&puts)>(libc_puts))(str);
}

ssize_t ld_write(int fd, const void* buf, size_t count) {
    if (file_map.exist(fd)) {
ssize_t write(int fd, const void* buf, size_t count) {
    init_passthrough_if_needed();
    if (is_env_initialized && file_map.exist(fd)) {
//        auto adafs_fd = file_map.get(fd);
//        auto path = adafs_fd->path(); // TODO use this to send to the daemon (call directly)
//        auto append_flag = adafs_fd->append_flag();
@@ -276,8 +312,9 @@ ssize_t ld_write(int fd, const void* buf, size_t count) {
    return (reinterpret_cast<decltype(&write)>(libc_write))(fd, buf, count);
}

ssize_t ld_pwrite(int fd, const void* buf, size_t count, off_t offset) {
    if (file_map.exist(fd)) {
ssize_t pwrite(int fd, const void* buf, size_t count, off_t offset) {
    init_passthrough_if_needed();
    if (is_env_initialized && file_map.exist(fd)) {
//        auto adafs_fd = file_map.get(fd);
//        auto path = adafs_fd->path(); // TODO use this to send to the daemon (call directly)
//        auto append_flag = adafs_fd->append_flag();
@@ -292,8 +329,9 @@ ssize_t ld_pwrite(int fd, const void* buf, size_t count, off_t offset) {
    return (reinterpret_cast<decltype(&pwrite)>(libc_pwrite))(fd, buf, count, offset);
}

ssize_t ld_read(int fd, void* buf, size_t count) {
    if (file_map.exist(fd)) {
ssize_t read(int fd, void* buf, size_t count) {
    init_passthrough_if_needed();
    if (is_env_initialized && file_map.exist(fd)) {
//        auto path = file_map.get(fd)->path(); // TODO use this to send to the daemon (call directly)
        // TODO call daemon and return size read
#ifndef MARGOIPC
@@ -306,8 +344,9 @@ ssize_t ld_read(int fd, void* buf, size_t count) {
    return (reinterpret_cast<decltype(&read)>(libc_read))(fd, buf, count);
}

ssize_t ld_pread(int fd, void* buf, size_t count, off_t offset) {
    if (file_map.exist(fd)) {
ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
    init_passthrough_if_needed();
    if (is_env_initialized && file_map.exist(fd)) {
//        auto path = file_map.get(fd)->path(); // TODO use this to send to the daemon (call directly)
        // TODO call daemon and return size written
#ifndef MARGOIPC
@@ -320,8 +359,9 @@ ssize_t ld_pread(int fd, void* buf, size_t count, off_t offset) {
    return (reinterpret_cast<decltype(&pread)>(libc_pread))(fd, buf, count, offset);
}

ssize_t ld_pread64(int fd, void* buf, size_t nbyte, __off64_t offset) {
    if (file_map.exist(fd)) {
ssize_t pread64(int fd, void* buf, size_t nbyte, __off64_t offset) {
    init_passthrough_if_needed();
    if (is_env_initialized && file_map.exist(fd)) {
//        auto path = file_map.get(fd)->path(); // TODO use this to send to the daemon (call directly)
        // TODO call daemon and return size written
#ifndef MARGOIPC
@@ -334,32 +374,38 @@ ssize_t ld_pread64(int fd, void* buf, size_t nbyte, __off64_t offset) {
    return (reinterpret_cast<decltype(&pread64)>(libc_pread64))(fd, buf, nbyte, offset);
}

off_t ld_lseek(int fd, off_t offset, int whence) __THROW {
off_t lseek(int fd, off_t offset, int whence) __THROW {
    init_passthrough_if_needed();
    return (reinterpret_cast<decltype(&lseek)>(libc_lseek))(fd, offset, whence);
}

off_t ld_lseek64(int fd, off_t offset, int whence) __THROW {
    return ld_lseek(fd, offset, whence);
off_t lseek64(int fd, off_t offset, int whence) __THROW {
    init_passthrough_if_needed();
    return lseek(fd, offset, whence);
}

int ld_truncate(const char* path, off_t length) __THROW {
int truncate(const char* path, off_t length) __THROW {
    init_passthrough_if_needed();
    return (reinterpret_cast<decltype(&truncate)>(libc_truncate))(path, length);
}

int ld_ftruncate(int fd, off_t length) __THROW {
int ftruncate(int fd, off_t length) __THROW {
    init_passthrough_if_needed();
    return (reinterpret_cast<decltype(&ftruncate)>(libc_ftruncate))(fd, length);
}

int ld_dup(int oldfd) __THROW {
    if (file_map.exist(oldfd)) {
int dup(int oldfd) __THROW {
    init_passthrough_if_needed();
    if (is_env_initialized && file_map.exist(oldfd)) {
        // Not implemented
        return -1;
    }
    return (reinterpret_cast<decltype(&dup)>(libc_dup))(oldfd);
}

int ld_dup2(int oldfd, int newfd) __THROW {
    if (file_map.exist(oldfd) || file_map.exist(newfd)) {
int dup2(int oldfd, int newfd) __THROW {
    init_passthrough_if_needed();
    if (is_env_initialized && (file_map.exist(oldfd) || file_map.exist(newfd))) {
        // Not implemented
        return -1;
    }
@@ -474,16 +520,27 @@ hg_addr_t daemon_addr() {
}

/**
 * Called initially when preload library is used with the LD_PRELOAD environment variable
 * This function is only called in the preload constructor
 */
void init_preload(void) {
void init_environment() {
#ifdef MARGOIPC
    // init margo client for IPC
    auto err = init_ld_argobots();
    assert(err);
    err = init_ipc_client();
    assert(err);
    err = ipc_send_get_fs_config(ipc_config_id); // get fs configurations the daemon was started with.
    assert(err);
#endif
    is_env_initialized = true;
    DAEMON_DEBUG0(debug_fd, "Environment initialized.\n");
}

    // just a security measure
    if (is_lib_initialized)
        return;
void init_passthrough_() {
    libc = dlopen("libc.so.6", RTLD_LAZY);
    libc_open = dlsym(libc, "open");
    libc_fopen = dlsym(libc, "fopen");
//    libc_fopen = dlsym(libc, "fopen");
//    libc_fopen64 = dlsym(libc, "fopen64");

    libc_unlink = dlsym(libc, "unlink");

@@ -517,21 +574,21 @@ void init_preload(void) {
    libc_dup = dlsym(libc, "dup");
    libc_dup2 = dlsym(libc, "dup2");

    // XXX Continue here. stat is not intercepted because it is not part of libc? investigate.

    debug_fd = fopen(LOG_DAEMON_PATH, "a+");
    fs_config = make_shared<struct FsConfig>();
    DAEMON_DEBUG0(debug_fd, "Preload initialized.\n");
    is_lib_initialized = true;
#ifdef MARGOIPC
    // init margo client for IPC
    auto err = init_ld_argobots();
    assert(err);
    err = init_ipc_client();
    assert(err);
    err = ipc_send_get_fs_config(ipc_config_id); // get fs configurations the daemon was started with.
    assert(err);
#endif
    DAEMON_DEBUG0(debug_fd, "Passthrough initialized.\n");
}

void init_passthrough_if_needed() {
    pthread_once(&init_lib_thread, init_passthrough_);
}

/**
 * Called initially when preload library is used with the LD_PRELOAD environment variable
 */
void init_preload(void) {
    init_passthrough_if_needed();
    init_environment();
    printf("[INFO] preload init successful.\n");
}

@@ -555,6 +612,5 @@ void destroy_preload(void) {
    HG_Finalize(mercury_hg_class_);
    DAEMON_DEBUG0(debug_fd, "Preload library shut down.\n");
#endif

    fclose(debug_fd);
}
 No newline at end of file