Commit 1f58333b authored by sevenuz's avatar sevenuz Committed by Julius Athenstaedt
Browse files

fuse: fifo support for local nodes

parent ff5457df
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -76,7 +76,9 @@ struct __dirstream {
#include <sys/xattr.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <filesystem>
#include <unistd.h>
#include <unordered_map>
#include <string>
@@ -117,7 +119,8 @@ struct u_data {
    int writeback;
    int direct_io;
    int max_readahead;
    int flock;
    int fifo;
    int access;
    int xattr;
    char* mountpoint;
    double timeout;
+134 −17
Original line number Diff line number Diff line
@@ -43,7 +43,9 @@ static struct fuse_lowlevel_ops ll_ops;
static std::mutex ino_mutex;
static std::unordered_map<fuse_ino_t, Inode> ino_map;
static std::unordered_map<std::string, fuse_ino_t> path_map;
static std::unordered_map<std::string, struct stat> local_fifos;
static fuse_ino_t next_ino = 2; // reserve 1 for root
static const std::string fifo_path = "/tmp/gekkofs_fifos/";

static fuse_ino_t
alloc_inode(const std::string& path) {
@@ -84,8 +86,10 @@ static const struct fuse_opt lo_opts[] = {
        {"direct_io", offsetof(struct u_data, direct_io), 1},
        {"no_direct_io", offsetof(struct u_data, direct_io), 0},
        {"max_readahead=%ui", offsetof(struct u_data, max_readahead), 0},
        {"flock", offsetof(struct u_data, flock), 1},
        {"no_flock", offsetof(struct u_data, flock), 0},
        {"fifo", offsetof(struct u_data, fifo), 1},
        {"no_fifo", offsetof(struct u_data, fifo), 0},
        {"access", offsetof(struct u_data, access), 1},
        {"no_access", offsetof(struct u_data, access), 0},
        {"xattr", offsetof(struct u_data, xattr), 1},
        {"no_xattr", offsetof(struct u_data, xattr), 0},
        {"timeout=%lf", offsetof(struct u_data, timeout), 0},
@@ -103,8 +107,10 @@ passthrough_ll_help(void) {
           "    -o direct_io           Enables direct io\n"
           "    -o no_direct_io        Disable direct io\n"
           "    -o max_readahead=1     Amount of allowed readaheads\n"
           "    -o flock               Enable flock\n"
           "    -o no_flock            Disable flock\n"
           "    -o fifo                Enable fifo, disables GekkoFS access check\n"
           "    -o no_fifo             Disable fifo\n"
           "    -o access              Enable GekkoFS access check if fifo is deactivated\n"
           "    -o no_access           Disable access handler\n"
           "    -o xattr               Enable xattr\n"
           "    -o no_xattr            Disable xattr\n"
           "    -o timeout=1.0         Caching timeout\n"
@@ -117,7 +123,8 @@ passthrough_ll_help(void) {
static void
init_handler(void* userdata, struct fuse_conn_info* conn) {
    struct u_data* ud = (struct u_data*) userdata;
    fuse_log(FUSE_LOG_DEBUG, "init handler readahead %i direct_io %i \n", ud->max_readahead, ud->direct_io);
    fuse_log(FUSE_LOG_DEBUG, "init handler readahead %i direct_io %i \n",
             ud->max_readahead, ud->direct_io);
    // bool has_flag;

    // TODO check other capabilities e.g. FUSE_CAP_READDIRPLUS
@@ -156,6 +163,21 @@ lookup_handler(fuse_req_t req, fuse_ino_t parent, const char* name) {
    std::string child = get_path(parent_inode, name);
    fuse_log(FUSE_LOG_DEBUG, "lookup %s\n", child.c_str());

    if(ud->fifo) {
        auto iit = local_fifos.find(child);
        if(iit != local_fifos.end()) {
            const struct stat& st = iit->second;

            fuse_entry_param e{};
            e.ino = st.st_ino;
            e.attr = st;
            e.attr_timeout = ud->timeout;
            e.entry_timeout = ud->timeout;

            fuse_reply_entry(req, &e);
            return;
        }
    }

    // See if we already have this path
    auto it = path_map.find(child);
@@ -366,12 +388,25 @@ tmpfile_handler(fuse_req_t req, fuse_ino_t parent, mode_t mode,
static void
unlink_handler(fuse_req_t req, fuse_ino_t parent, const char* name) {
    fuse_log(FUSE_LOG_DEBUG, "unlink handler \n");
    auto* ud = udata(req);
    auto* parent_inode = get_inode(parent);
    if(!parent_inode) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    std::string path = get_path(parent_inode, name);

    if(ud->fifo) {
        auto it = local_fifos.find(path);
        if(it != local_fifos.end()) {
            std::string real = fifo_path + std::string(name);
            unlink(real.c_str());
            local_fifos.erase(it);
            fuse_reply_err(req, 0);
            return;
        }
    }

    int rc = gkfs::syscall::gkfs_remove(path);
    if(rc == -1) {
        fuse_reply_err(req, 1);
@@ -429,6 +464,7 @@ static void
readdir_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
                struct fuse_file_info* fi) {
    fuse_log(FUSE_LOG_DEBUG, "readdir handler \n");
    auto* ud = udata(req);
    auto* dir_ptr = reinterpret_cast<GkfsDir*>(fi->fh);
    if(!dir_ptr) {
        fuse_reply_err(req, EBADF);
@@ -458,7 +494,7 @@ readdir_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
        auto de = open_dir->getdent(pos);

        struct stat st{};
        // TODO cannot be right, right?
        // TODO cannot be right, right? no stat?
        st.st_ino =
                std::hash<std::string>()(open_dir->path() + "/" + de.name());
        st.st_mode = (de.type() == gkfs::filemap::FileType::regular) ? S_IFREG
@@ -475,6 +511,34 @@ readdir_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
        pos += 1;
    }

    if(ud->fifo) {
        int i = 0;
        for(auto const& kv : local_fifos) {
            if(i < off) {
                i++;
                continue;
            }
            std::filesystem::path vpath = kv.first;
            const struct stat& st = kv.second;

            // check if FIFO belongs to this directory
            if(vpath.parent_path() != open_dir->path())
                continue;

            std::string fname = vpath.filename();

            size_t entry_size = fuse_add_direntry(req, buf + bytes_filled,
                                                  size - bytes_filled,
                                                  fname.c_str(), &st, pos + 1);

            if(entry_size > size - bytes_filled)
                break;

            bytes_filled += entry_size;
            pos += 1;
        }
    }

    open_dir->pos(pos); // update internal position if needed

    fuse_reply_buf(req, buf, bytes_filled);
@@ -572,6 +636,8 @@ fsync_handler(fuse_req_t req, fuse_ino_t ino, int datasync,
static void
access_handler(fuse_req_t req, fuse_ino_t ino, int mask) {
    fuse_log(FUSE_LOG_DEBUG, "access handler \n");
    auto* ud = udata(req);
    if(ud->access && !ud->fifo) {
        auto* inode = get_inode(ino);
        if(!inode) {
            fuse_reply_err(req, ENOENT);
@@ -583,6 +649,11 @@ access_handler(fuse_req_t req, fuse_ino_t ino, int mask) {
            return;
        }
        fuse_reply_err(req, 0);
    } else {
        // deactivates following access requests and it is always treated as
        // success
        fuse_reply_err(req, ENOSYS);
    }
}

static void
@@ -795,6 +866,52 @@ rename_handler(fuse_req_t req, fuse_ino_t old_parent, const char* old_name,
#endif
}

void
mknod_handler(fuse_req_t req, fuse_ino_t parent, const char* name, mode_t mode,
              dev_t rdev) {
    auto* ud = udata(req);
    if(!ud->fifo) {
        fuse_reply_err(req, ENOTSUP);
        return;
    }
    auto* parent_inode = get_inode(parent);
    if(!parent_inode) {
        fuse_reply_err(req, ENOENT);
        return;
    }

    mkdir(fifo_path.c_str(), 0700);
    std::string path = fifo_path + "/" + name;

    if(!S_ISFIFO(mode)) {
        fuse_reply_err(req, EINVAL);
        return;
    }

    if(mkfifo(path.c_str(), mode) == -1) {
        fuse_reply_err(req, errno);
        return;
    }

    struct stat st{};
    if(stat(path.c_str(), &st) == -1) {
        fuse_reply_err(req, errno);
        return;
    }

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

    fuse_entry_param e{};
    e.ino = st.st_ino;
    e.attr = st;
    e.attr_timeout = ud->timeout;
    e.entry_timeout = ud->timeout;

    fuse_reply_entry(req, &e);
}

static void
init_gekkofs() {
    // TODO how to handle mount point
@@ -834,7 +951,7 @@ init_ll_ops(fuse_lowlevel_ops* ops) {
    ops->forget = forget_handler;
    // ops->forget_multi
    ops->readlink = readlink_handler;
    // ops->mknod
    ops->mknod = mknod_handler;
    ops->symlink = symlink_handler;
    ops->rename = rename_handler;
    // ops->link