Commit 076660ab authored by Julius Athenstaedt's avatar Julius Athenstaedt
Browse files

big refactor with shared locks

parent ea6862d4
Loading
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ extern "C" {
#include <unistd.h>
#include <unordered_map>
#include <string>
#include <mutex>
#include <shared_mutex>
#include <cstdlib>

#ifdef __FreeBSD__
+137 −100
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@
#include <client/fuse/fuse_client.hpp>

static struct fuse_lowlevel_ops ll_ops;
static std::mutex ino_mutex;
static std::shared_mutex ino_mutex;
static Inode root_inode;
static std::unordered_map<fuse_ino_t, Inode> ino_map;
static std::unordered_map<std::string, fuse_ino_t> path_map;
@@ -61,7 +61,7 @@ static const std::string fifo_path = "/tmp/gekkofs_fifos/";

static fuse_ino_t
alloc_inode(const std::string& path) {
    std::lock_guard<std::mutex> lk(ino_mutex);
    std::unique_lock<std::shared_mutex> lk(ino_mutex);
    fuse_ino_t ino;
    if(gkfs::config::fuse::pointertrick) {
        Inode* inode = new Inode{path, 1};
@@ -74,6 +74,26 @@ alloc_inode(const std::string& path) {
    return ino;
}

/**
 * Returns a copy of the path, empty string if inode was not find.
 */
static std::string
get_inode_path(fuse_ino_t ino) {
    std::shared_lock<std::shared_mutex> lk(ino_mutex);
    if(ino == FUSE_ROOT_ID) {
        return root_inode.path;
    }
    if(gkfs::config::fuse::pointertrick) {
        return ((Inode*) ino)->path;
    } else {
        auto it = ino_map.find(ino);
        return it != ino_map.end() ? it->second.path : "";
    }
}

/**
 * HAS TO BE USED WITHIN A LOCK!!!
 */
static Inode*
get_inode(fuse_ino_t ino) {
    if(ino == FUSE_ROOT_ID) {
@@ -82,24 +102,30 @@ get_inode(fuse_ino_t ino) {
    if(gkfs::config::fuse::pointertrick) {
        return (Inode*) ino;
    } else {
        std::lock_guard<std::mutex> lk(ino_mutex);
        auto it = ino_map.find(ino);
        return it != ino_map.end() ? &it->second : nullptr;
    }
}

// only called if lookup reaches 0
static void
remove_inode_by_path(const std::string path) {
    std::lock_guard<std::mutex> lk(ino_mutex);
    auto it_src = path_map.find(path);
    if(it_src != path_map.end()) {
        path_map.erase(it_src);
free_inode_memory(fuse_ino_t ino) {
    std::unique_lock<std::shared_mutex> lk(ino_mutex);

    if(gkfs::config::fuse::pointertrick) {
            delete get_inode(it_src->second);
        // In pointer trick, ino IS the pointer.
        Inode* inode = (Inode*) ino;
        delete inode;
    } else {
            ino_map.erase(it_src->second);
        ino_map.erase(ino);
    }
}

// Only removes the link between Path string and Inode ID.
static void
disconnect_path_mapping(const std::string& path) {
    std::unique_lock<std::shared_mutex> lk(ino_mutex);
    path_map.erase(path);
}

static int
@@ -117,7 +143,7 @@ fill_fuse_entry_param(const u_data* ud, const std::string path,

    // CRITICAL SECTION
    {
        std::lock_guard<std::mutex> lk(ino_mutex);
        std::shared_lock<std::shared_mutex> lk(ino_mutex);
        if(check_path_map) {
            auto it = path_map.find(path);
            if(it != path_map.end()) {
@@ -128,11 +154,9 @@ fill_fuse_entry_param(const u_data* ud, const std::string path,
    } // Lock releases here

    if(found) {
        std::unique_lock<std::shared_mutex> lk(ino_mutex);
        auto inode = get_inode(ino);
        if(inode) {
            // Note: This increment is technically racy (read-modify-write)
            // because get_inode returns a raw pointer and doesn't lock the
            // inode itself. But the SEGFAULT comes from the map iterator above.
            inode->lookup_count++;
        }
    } else {
@@ -153,14 +177,14 @@ udata(fuse_req_t req) {
}

static std::string
get_path(const Inode* inode, const char* name) {
get_path(const std::string inode_path, const char* name) {
    if(name[0] == '/') {
        return std::string(name);
    }
    if(inode->path == "/") {
        return inode->path + name;
    if(inode_path == "/") {
        return inode_path + name;
    } else {
        return inode->path + "/" + name;
        return inode_path + "/" + name;
    }
}

@@ -289,12 +313,12 @@ static void
lookup_handler(fuse_req_t req, fuse_ino_t parent, const char* name) {
    auto* ud = udata(req);
    DEBUG_INFO(ud, "lookup handler ino %u", parent);
    auto* parent_inode = get_inode(parent);
    if(!parent_inode) {
    auto parent_inode_path = get_inode_path(parent);
    if(parent_inode_path.empty()) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    std::string child = get_path(parent_inode, name);
    std::string child = get_path(parent_inode_path, name);
    DEBUG_INFO(ud, "lookup %s", child.c_str());

    if(ud->fifo) {
@@ -326,14 +350,14 @@ static void
getattr_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
    auto* ud = udata(req);
    DEBUG_INFO(ud, "getattr handler");
    auto* inode = get_inode(ino);
    if(!inode) {
    auto inode_path = get_inode_path(ino);
    if(inode_path.empty()) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    // query GekkoFS for latest attr
    struct stat st;
    int rc = gkfs::syscall::gkfs_stat(inode->path, &st);
    int rc = gkfs::syscall::gkfs_stat(inode_path, &st);
    if(rc) {
        DEBUG_INFO(ud, "getattr error %u", rc);
        fuse_reply_err(req, errno);
@@ -347,25 +371,24 @@ setattr_handler(fuse_req_t req, fuse_ino_t ino, struct stat* attr, int to_set,
                struct fuse_file_info* fi) {
    auto* ud = udata(req);
    DEBUG_INFO(ud, "setattr handler ino %u", ino);
    auto* inode = get_inode(ino);
    if(!inode) {
    auto inode_path = get_inode_path(ino);
    if(inode_path.empty()) {
        fuse_reply_err(req, ENOENT);
        return;
    }

    if(to_set & FUSE_SET_ATTR_SIZE) {
        off_t new_size = attr->st_size;
        int res = gkfs::syscall::gkfs_truncate(inode->path, new_size);
        int res = gkfs::syscall::gkfs_truncate(inode_path, new_size);
        if(res < 0) {
            DEBUG_INFO(ud, "setattr truncate failed on %s",
                       inode->path.c_str());
            DEBUG_INFO(ud, "setattr truncate failed on %s", inode_path.c_str());
            fuse_reply_err(req, EIO);
            return;
        }
    }

    struct stat st;
    int rc = gkfs::syscall::gkfs_stat(inode->path, &st);
    int rc = gkfs::syscall::gkfs_stat(inode_path, &st);
    if(rc) {
        DEBUG_INFO(ud, "getattr error %u", rc);
        fuse_reply_err(req, errno);
@@ -382,13 +405,13 @@ static void
open_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
    auto* ud = udata(req);
    DEBUG_INFO(ud, "open handler");
    auto* inode = get_inode(ino);
    if(!inode) {
    auto inode_path = get_inode_path(ino);
    if(inode_path.empty()) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    const int mode = 0644; // -rw-r--r--    I think that doesnt matter anyway
    int fd = gkfs::syscall::gkfs_open(inode->path, mode,
    int fd = gkfs::syscall::gkfs_open(inode_path, mode,
                                      fi->flags); // TODO mode!
    if(fd < 0) {
        fuse_reply_err(req, ENOENT);
@@ -418,8 +441,8 @@ read_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
    auto* ud = udata(req);
    DEBUG_INFO(ud, "read handler");
    if(gkfs::config::fuse::check_inode) {
        auto* inode = get_inode(ino);
        if(!inode) {
        auto inode_path = get_inode_path(ino);
        if(inode_path.empty()) {
            fuse_reply_err(req, ENOENT);
            return;
        }
@@ -440,8 +463,8 @@ write_handler(fuse_req_t req, fuse_ino_t ino, const char* buf, size_t size,
    auto* ud = udata(req);
    DEBUG_INFO(ud, "write handler");
    if(gkfs::config::fuse::check_inode) {
        auto* inode = get_inode(ino);
        if(!inode) {
        auto inode_path = get_inode_path(ino);
        if(inode_path.empty()) {
            fuse_reply_err(req, ENOENT);
            return;
        }
@@ -459,12 +482,12 @@ static void
create_handler(fuse_req_t req, fuse_ino_t parent, const char* name, mode_t mode,
               struct fuse_file_info* fi) {
    auto* ud = udata(req);
    auto* parent_inode = get_inode(parent);
    if(!parent_inode) {
    auto parent_inode_path = get_inode_path(parent);
    if(parent_inode_path.empty()) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    std::string path = get_path(parent_inode, name);
    std::string path = get_path(parent_inode_path, name);
    // This is the code of commit: d79429bd1f188a3a87d0d9b00c773965c82c714d
    // somehow the changes there break vim but on the other side with this,
    // compss has some errors
@@ -503,12 +526,12 @@ static void
unlink_handler(fuse_req_t req, fuse_ino_t parent, const char* name) {
    auto* ud = udata(req);
    DEBUG_INFO(ud, "unlink handler");
    auto* parent_inode = get_inode(parent);
    if(!parent_inode) {
    auto parent_inode_path = get_inode_path(parent);
    if(parent_inode_path.empty()) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    std::string path = get_path(parent_inode, name);
    std::string path = get_path(parent_inode_path, name);

    if(ud->fifo) {
        auto it = local_fifos.find(path);
@@ -522,7 +545,7 @@ unlink_handler(fuse_req_t req, fuse_ino_t parent, const char* name) {
    }

    int rc = gkfs::syscall::gkfs_remove(path);
    remove_inode_by_path(path);
    disconnect_path_mapping(path);
    if(rc == -1) {
        fuse_reply_err(req, 1);
        return;
@@ -534,14 +557,14 @@ static void
opendir_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
    auto* ud = udata(req);
    DEBUG_INFO(ud, "opendir handler");
    auto* inode = get_inode(ino);
    if(!inode) {
    auto inode_path = get_inode_path(ino);
    if(inode_path.empty()) {
        fuse_reply_err(req, ENOTDIR);
        return;
    }
    DEBUG_INFO(ud, "open dir %s", inode->path.c_str());
    DEBUG_INFO(ud, "open dir %s", inode_path.c_str());

    const int fd = gkfs::syscall::gkfs_opendir(inode->path);
    const int fd = gkfs::syscall::gkfs_opendir(inode_path);

    DEBUG_INFO(ud, "\t with fd %i \n", fd);

@@ -753,11 +776,13 @@ static void
release_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
    auto* ud = udata(req);
    DEBUG_INFO(ud, "release handler");
    auto* inode = get_inode(ino);
    if(!inode) {
    if(gkfs::config::fuse::check_inode) {
        auto inode_path = get_inode_path(ino);
        if(inode_path.empty()) {
            fuse_reply_err(req, ENOENT);
            return;
        }
    }
    int lc = gkfs::syscall::gkfs_close(fi->fh);
    if(lc < 0) {
        fuse_reply_err(req, 1);
@@ -772,6 +797,9 @@ forget_handler(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) {
    auto* ud = udata(req);
    DEBUG_INFO(ud, "forget handler");

    uint64_t lc = 0;
    {
        std::unique_lock<std::shared_mutex> lk(ino_mutex);
        Inode* inode = get_inode(ino);
        if(!inode) {
            fuse_reply_none(req);
@@ -782,9 +810,11 @@ forget_handler(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) {
            inode->lookup_count -= nlookup;
        else
            inode->lookup_count = 0;
        lc = inode->lookup_count;
    }

    if(inode->lookup_count == 0) { // && inode.open_count == 0
        remove_inode_by_path(inode->path);
    if(lc == 0) {
        free_inode_memory(ino);
        DEBUG_INFO(ud, "reached lookup_count 0");
    }

@@ -797,8 +827,8 @@ flush_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
    auto* ud = udata(req);
    DEBUG_INFO(ud, "flush handler");
    if(gkfs::config::fuse::check_inode) {
        auto* inode = get_inode(ino);
        if(!inode) {
        auto inode_path = get_inode_path(ino);
        if(inode_path.empty()) {
            fuse_reply_err(req, ENOENT);
            return;
        }
@@ -823,12 +853,12 @@ access_handler(fuse_req_t req, fuse_ino_t ino, int mask) {
    auto* ud = udata(req);
    DEBUG_INFO(ud, "access handler");
    if(ud->access && !ud->fifo) {
        auto* inode = get_inode(ino);
        if(!inode) {
        auto inode_path = get_inode_path(ino);
        if(inode_path.empty()) {
            fuse_reply_err(req, ENOENT);
            return;
        }
        int lc = gkfs::syscall::gkfs_access(inode->path, mask, true);
        int lc = gkfs::syscall::gkfs_access(inode_path, mask, true);
        if(lc < 0) {
            fuse_reply_err(req, 1);
            return;
@@ -845,13 +875,13 @@ static void
mkdir_handler(fuse_req_t req, fuse_ino_t parent, const char* name,
              mode_t mode) {
    auto* ud = udata(req);
    auto* parent_inode = get_inode(parent);
    if(!parent_inode) {
    auto parent_inode_path = get_inode_path(parent);
    if(parent_inode_path.empty()) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    std::string path = get_path(parent_inode, name);
    DEBUG_INFO(ud, "mkdir parent %s name %s", parent_inode->path.c_str(), name);
    std::string path = get_path(parent_inode_path, name);
    DEBUG_INFO(ud, "mkdir parent %s name %s", parent_inode_path.c_str(), name);
    int rc = gkfs::syscall::gkfs_create(path, mode | S_IFDIR);
    if(rc == -1) {
        fuse_reply_err(req, 1);
@@ -870,32 +900,32 @@ mkdir_handler(fuse_req_t req, fuse_ino_t parent, const char* name,
static void
rmdir_handler(fuse_req_t req, fuse_ino_t parent, const char* name) {
    auto* ud = udata(req);
    auto* parent_inode = get_inode(parent);
    if(!parent_inode) {
    auto parent_inode_path = get_inode_path(parent);
    if(parent_inode_path.empty()) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    std::string path = get_path(parent_inode, name);
    std::string path = get_path(parent_inode_path, name);
    DEBUG_INFO(ud, "rmdir %s", path.c_str());
    int rc = gkfs::syscall::gkfs_rmdir(path);
    if(rc == -1) {
        fuse_reply_err(req, errno);
        return;
    }
    remove_inode_by_path(path);
    disconnect_path_mapping(path);
    fuse_reply_err(req, 0);
}

static void
readlink_handler(fuse_req_t req, fuse_ino_t ino) {
#ifdef HAS_SYMLINKS
    auto* inode = get_inode(ino);
    if(!inode) {
    auto inode_path = get_inode_path(ino);
    if(inode_path.empty()) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    char link[PATH_MAX];
    int rc = gkfs::syscall::gkfs_readlink(inode->path, link, PATH_MAX);
    int rc = gkfs::syscall::gkfs_readlink(inode_path, link, PATH_MAX);
    if(rc == -1) {
        fuse_reply_err(req, 1);
        return;
@@ -913,19 +943,19 @@ symlink_handler(fuse_req_t req, const char* linkname, fuse_ino_t parent,
#ifdef HAS_SYMLINKS
    auto* ud = udata(req);
    DEBUG_INFO(ud, "symlink handler linkname %s name %s", linkname, name);
    auto* parent_inode = get_inode(parent);
    if(!parent_inode) {
    auto parent_inode_path = get_inode_path(parent);
    if(parent_inode_path.empty()) {
        DEBUG_INFO(ud, "symlink parent inode ino %i", parent);
        fuse_reply_err(req, ENOENT);
        return;
    }

    std::string path = get_path(parent_inode, name);
    std::string target = get_path(parent_inode, linkname);
    std::string path = get_path(parent_inode_path, name);
    std::string target = get_path(parent_inode_path, linkname);

    if(target.rfind(ud->mountpoint, 0) == 0) {
        // starts with mount path
        target = get_path(parent_inode,
        target = get_path(parent_inode_path,
                          target.substr(strlen(ud->mountpoint)).c_str());
    }

@@ -961,18 +991,18 @@ rename_handler(fuse_req_t req, fuse_ino_t old_parent, const char* old_name,
               unsigned int flags) {

#ifdef HAS_RENAME
    auto* old_parent_inode = get_inode(old_parent);
    if(!old_parent_inode) {
    auto old_parent_inode_path = get_inode_path(old_parent);
    if(old_parent_inode_path.empty()) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    auto* new_parent_inode = get_inode(new_parent);
    if(!new_parent_inode) {
    auto new_parent_inode_path = get_inode_path(new_parent);
    if(new_parent_inode_path.empty()) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    std::string old_path = get_path(old_parent_inode, old_name);
    std::string new_path = get_path(new_parent_inode, new_name);
    std::string old_path = get_path(old_parent_inode_path, old_name);
    std::string new_path = get_path(new_parent_inode_path, new_name);

    struct stat st_src{};
    if(gkfs::syscall::gkfs_stat(old_path, &st_src) < 0) {
@@ -999,10 +1029,9 @@ rename_handler(fuse_req_t req, fuse_ino_t old_parent, const char* old_name,
        return;
    }

    ino_mutex.lock();
    std::unique_lock<std::shared_mutex> lk(ino_mutex);
    auto it_end = path_map.end();
    auto it_src = path_map.find(old_path);
    ino_mutex.unlock();

    fuse_ino_t src_ino = 0;

@@ -1011,8 +1040,15 @@ rename_handler(fuse_req_t req, fuse_ino_t old_parent, const char* old_name,
        path_map.erase(it_src);
        path_map[new_path] = src_ino;
    } else {
        src_ino = alloc_inode(new_path);
        path_map[new_path] = src_ino;
        fuse_ino_t ino;
        if(gkfs::config::fuse::pointertrick) {
            Inode* inode = new Inode{new_path, 1};
            ino = (fuse_ino_t) inode;
        } else {
            ino = next_ino++;
            ino_map[ino] = {new_path, 1};
        }
        path_map[new_path] = ino;
    }
    auto* inode = get_inode(src_ino);
    if(inode) {
@@ -1048,8 +1084,8 @@ mknod_handler(fuse_req_t req, fuse_ino_t parent, const char* name, mode_t mode,
        fuse_reply_err(req, ENOTSUP);
        return;
    }
    auto* parent_inode = get_inode(parent);
    if(!parent_inode) {
    auto parent_inode_path = get_inode_path(parent);
    if(parent_inode_path.empty()) {
        fuse_reply_err(req, ENOENT);
        return;
    }
@@ -1075,7 +1111,8 @@ mknod_handler(fuse_req_t req, fuse_ino_t parent, const char* name, mode_t mode,
    }

    // save synthetic entry
    std::string vpath = get_path(parent_inode, name); // path in mount namespace
    std::string vpath =
            get_path(parent_inode_path, name); // path in mount namespace
    local_fifos[vpath] = st;

    fuse_entry_param e{};