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

cleanup and refactoring, fix lookup_count

parent bafb3d69
Loading
Loading
Loading
Loading
+25 −64
Original line number Diff line number Diff line
@@ -97,6 +97,31 @@ struct __dirstream {
#include <client/preload_context.hpp>
#include <client/user_functions.hpp>

// TODO do we really need the stat here? no i dont think so
struct Inode {
    std::string path;
    struct stat st;
    uint64_t lookup_count;
};

enum {
    CACHE_NEVER,
    CACHE_NORMAL,
    CACHE_ALWAYS,
};

struct u_data {
    pthread_mutex_t mutex;
    int debug;
    int writeback;
    int flock;
    int xattr;
    char* source;
    double timeout;
    int cache;
    int timeout_set;
};

struct GkfsDir { // Hypothetical structure that might be used if DIR is cast
    int fd;
    long int tell_pos; // for telldir/seekdir
@@ -104,68 +129,4 @@ struct GkfsDir { // Hypothetical structure that might be used if DIR is cast
    // other members libc DIR might have
};

/*
 * Creates files on the underlying file system in response to a FUSE_MKNOD
 * operation
 */
static inline int
mknod_wrapper(int dirfd, const char* path, const char* link, int mode,
              dev_t rdev) {
    fuse_log(FUSE_LOG_DEBUG, "mknod_wrapper \n");
    int res = -1;

    if(S_ISREG(mode)) {
        // res = lol_openat(dirfd, path, mode, O_CREAT | O_EXCL | O_WRONLY);
        fuse_log(FUSE_LOG_DEBUG, "lol_openat internal %s\n", res);
        if(res >= 0)
            res = gkfs::syscall::gkfs_close(res);
    } else if(S_ISDIR(mode)) {
        // GKFS_PATH_OPERATION(create, dirfd, path, mode | S_IFDIR)
        //  res = gkfs::syscall::gkfs_create(resolved, mode | S_IFDIR);
        //   res = mkdirat(dirfd, path, mode);
    } else if(S_ISLNK(mode) && link != NULL) {
        fuse_log(FUSE_LOG_ERR, "fifo in mknod_wrapper not supported\n");
        errno = ENOTSUP;
        return -1;
        // res = symlinkat(link, dirfd, path);
    } else if(S_ISFIFO(mode)) {
        fuse_log(FUSE_LOG_ERR, "fifo in mknod_wrapper not supported\n");
        errno = ENOTSUP;
        return -1;
        // res = mkfifoat(dirfd, path, mode);
#ifdef __FreeBSD__
    } else if(S_ISSOCK(mode)) {
        struct sockaddr_un su;
        int fd;

        if(strlen(path) >= sizeof(su.sun_path)) {
            errno = ENAMETOOLONG;
            return -1;
        }
        fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if(fd >= 0) {
            /*
             * We must bind the socket to the underlying file
             * system to create the socket file, even though
             * we'll never listen on this socket.
             */
            su.sun_family = AF_UNIX;
            strncpy(su.sun_path, path, sizeof(su.sun_path));
            res = bindat(dirfd, fd, (struct sockaddr*) &su, sizeof(su));
            if(res == 0)
                close(fd);
        } else {
            res = -1;
        }
#endif
    } else {
        fuse_log(FUSE_LOG_ERR, "mknodat in mknod_wrapper not supported\n");
        errno = ENOTSUP;
        return -1;
        // res = mknodat(dirfd, path, mode, rdev);
    }

    return res;
}

#endif // GKFS_CLIENT_FUSE_CONTEXT_HPP
+243 −264
Original line number Diff line number Diff line
@@ -39,47 +39,44 @@

#include <client/fuse/fuse_client.hpp>

struct lo_inode {
    struct lo_inode* next; /* protected by lo->mutex */
    struct lo_inode* prev; /* protected by lo->mutex */
    int fd;
    ino_t ino;
    dev_t dev;
    uint64_t refcount; /* protected by lo->mutex */
};

enum {
    CACHE_NEVER,
    CACHE_NORMAL,
    CACHE_ALWAYS,
};

struct lo_data {
    pthread_mutex_t mutex;
    int debug;
    int writeback;
    int flock;
    int xattr;
    char* source;
    double timeout;
    int cache;
    int timeout_set;
    struct lo_inode root; /* protected by lo->mutex */
};
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 fuse_ino_t next_ino = 2; // reserve 1 for root

static fuse_ino_t
alloc_inode(const std::string& path) {
    std::lock_guard<std::mutex> lk(ino_mutex);
    fuse_ino_t ino = next_ino++;
    ino_map[ino] = {path, {}, 1};
    return ino;
}

static Inode*
get_inode(fuse_ino_t ino) {
    std::lock_guard<std::mutex> lk(ino_mutex);
    auto it = ino_map.find(ino);
    return it != ino_map.end() ? &it->second : nullptr;
}

static struct u_data*
udata(fuse_req_t req) {
    return (struct u_data*) fuse_req_userdata(req);
}

static const struct fuse_opt lo_opts[] = {
        {"writeback", offsetof(struct lo_data, writeback), 1},
        {"no_writeback", offsetof(struct lo_data, writeback), 0},
        {"source=%s", offsetof(struct lo_data, source), 0},
        {"flock", offsetof(struct lo_data, flock), 1},
        {"no_flock", offsetof(struct lo_data, flock), 0},
        {"xattr", offsetof(struct lo_data, xattr), 1},
        {"no_xattr", offsetof(struct lo_data, xattr), 0},
        {"timeout=%lf", offsetof(struct lo_data, timeout), 0},
        {"timeout=", offsetof(struct lo_data, timeout_set), 1},
        {"cache=never", offsetof(struct lo_data, cache), CACHE_NEVER},
        {"cache=auto", offsetof(struct lo_data, cache), CACHE_NORMAL},
        {"cache=always", offsetof(struct lo_data, cache), CACHE_ALWAYS},
        {"writeback", offsetof(struct u_data, writeback), 1},
        {"no_writeback", offsetof(struct u_data, writeback), 0},
        {"flock", offsetof(struct u_data, flock), 1},
        {"no_flock", offsetof(struct u_data, flock), 0},
        {"xattr", offsetof(struct u_data, xattr), 1},
        {"no_xattr", offsetof(struct u_data, xattr), 0},
        {"timeout=%lf", offsetof(struct u_data, timeout), 0},
        {"timeout=", offsetof(struct u_data, timeout_set), 1},
        {"cache=never", offsetof(struct u_data, cache), CACHE_NEVER},
        {"cache=auto", offsetof(struct u_data, cache), CACHE_NORMAL},
        {"cache=always", offsetof(struct u_data, cache), CACHE_ALWAYS},

        FUSE_OPT_END};

@@ -99,85 +96,59 @@ passthrough_ll_help(void) {
           "    -o cache=always        Cache always\n");
}

static struct lo_data*
lo_data(fuse_req_t req) {
    return (struct lo_data*) fuse_req_userdata(req);
}

static struct lo_inode*
lo_inode(fuse_req_t req, fuse_ino_t ino) {
    if(ino == FUSE_ROOT_ID)
        return &lo_data(req)->root;
    else
        return (struct lo_inode*) (uintptr_t) ino;
}

static int
lo_fd(fuse_req_t req, fuse_ino_t ino) {
    return lo_inode(req, ino)->fd;
}

static bool
lo_debug(fuse_req_t req) {
    return lo_data(req)->debug != 0;
}

static void
lo_init(void* userdata, struct fuse_conn_info* conn) {
    // TODO init gkfs
    struct lo_data* lo = (struct lo_data*) userdata;
    bool has_flag;

    if(lo->writeback) {
        has_flag = fuse_set_feature_flag(conn, FUSE_CAP_WRITEBACK_CACHE);
        if(lo->debug && has_flag)
            fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n");
    }
    if(lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
        has_flag = fuse_set_feature_flag(conn, FUSE_CAP_FLOCK_LOCKS);
        if(lo->debug && has_flag)
            fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n");
    }
init_handler(void* userdata, struct fuse_conn_info* conn) {
    fuse_log(FUSE_LOG_DEBUG, "init handler \n");
    // struct u_data* lo = (struct u_data*) userdata;
    // bool has_flag;

    // TODO check other capabilities e.g. FUSE_CAP_READDIRPLUS
    // if(lo->writeback) {
    //     has_flag = fuse_set_feature_flag(conn, FUSE_CAP_WRITEBACK_CACHE);
    //     if(lo->debug && has_flag)
    //         fuse_log(FUSE_LOG_DEBUG, "init_handler: activating writeback\n");
    // }
    // if(lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
    //     has_flag = fuse_set_feature_flag(conn, FUSE_CAP_FLOCK_LOCKS);
    //     if(lo->debug && has_flag)
    //         fuse_log(FUSE_LOG_DEBUG, "init_handler: activating flock
    //         locks\n");
    // }

    /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    conn->no_interrupt = 1;
    // conn->no_interrupt = 1;
}

// Simplified inode structure
struct Inode {
    std::string path;
    struct stat st;
    uint64_t lookup_count;
};
static std::mutex ino_mutex;
static std::unordered_map<fuse_ino_t, Inode> ino_map;
static fuse_ino_t next_ino = 2; // reserve 1 for root

static fuse_ino_t
alloc_inode(const std::string& path) {
    std::lock_guard<std::mutex> lk(ino_mutex);
    fuse_ino_t ino = next_ino++;
    ino_map[ino] = {path, {}, 1};
    return ino;
}
static Inode*
get_inode(fuse_ino_t ino) {
    std::lock_guard<std::mutex> lk(ino_mutex);
    auto it = ino_map.find(ino);
    return it != ino_map.end() ? &it->second : nullptr;
static void
destroy_handler(void* userdata) {
    fuse_log(FUSE_LOG_DEBUG, "destroy handler \n");
    // userdata is GekkoFuse* if passed
}

static void
lookup_handler(fuse_req_t req, fuse_ino_t parent, const char* name) {
    fuse_log(FUSE_LOG_DEBUG, "lookup handler ino %u\n", parent);
    auto* ud = udata(req);
    auto* parent_inode = get_inode(parent);
    if(!parent_inode) {
        fuse_log(FUSE_LOG_DEBUG, "this error 1 \n", parent);
        fuse_reply_err(req, ENOENT);
        return;
    }
    std::string child = parent_inode->path + name;
    fuse_log(FUSE_LOG_DEBUG, "lookup %s\n", child.c_str());


    // See if we already have this path
    auto it = path_map.find(child);
    fuse_ino_t ino;
    if(it != path_map.end()) {
        ino = it->second;
        ino_map[ino].lookup_count++;
    } else {
        ino = alloc_inode(child);
        path_map[child] = ino;
    }

    struct stat st;
    int rc = gkfs::syscall::gkfs_stat(child, &st);
    if(rc < 0) {
@@ -185,19 +156,19 @@ lookup_handler(fuse_req_t req, fuse_ino_t parent, const char* name) {
        fuse_reply_err(req, ENOENT);
        return;
    }
    fuse_ino_t ino = alloc_inode(child);
    ino_map[ino].st = st;
    fuse_entry_param e = {};
    e.ino = ino;
    e.attr = st;
    e.attr_timeout = 1.0;
    e.entry_timeout = 1.0;
    e.attr_timeout = ud->timeout;
    e.entry_timeout = ud->timeout;
    fuse_reply_entry(req, &e);
}

static void
getattr_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
    fuse_log(FUSE_LOG_DEBUG, "getattr handler \n");
    auto* ud = udata(req);
    auto* inode = get_inode(ino);
    if(!inode) {
        fuse_reply_err(req, ENOENT);
@@ -212,13 +183,14 @@ getattr_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
        return;
    }
    inode->st = st;
    fuse_reply_attr(req, &st, 1.0);
    fuse_reply_attr(req, &st, ud->timeout);
}

static void
setattr_handler(fuse_req_t req, fuse_ino_t ino, struct stat* attr, int to_set,
                struct fuse_file_info* fi) {
    fuse_log(FUSE_LOG_DEBUG, "setattr handler ino %u\n", ino);
    auto* ud = udata(req);
    auto* inode = get_inode(ino);
    if(!inode) {
        fuse_reply_err(req, ENOENT);
@@ -229,7 +201,8 @@ setattr_handler(fuse_req_t req, fuse_ino_t ino, struct stat* attr, int to_set,
        off_t new_size = attr->st_size;
        int res = gkfs::syscall::gkfs_truncate(inode->path, new_size);
        if(res < 0) {
            fuse_log(FUSE_LOG_DEBUG, "setattr truncate failed on %s\n", inode->path.c_str());
            fuse_log(FUSE_LOG_DEBUG, "setattr truncate failed on %s\n",
                     inode->path.c_str());
            fuse_reply_err(req, EIO);
            return;
        }
@@ -244,7 +217,7 @@ setattr_handler(fuse_req_t req, fuse_ino_t ino, struct stat* attr, int to_set,

    // TODO because we cannot save the attributes in gekko, we just return the
    // buffered results of stat
    fuse_reply_attr(req, &inode->st, 1.0);
    fuse_reply_attr(req, &inode->st, ud->timeout);
    return;
}

@@ -320,6 +293,7 @@ static void
create_handler(fuse_req_t req, fuse_ino_t parent, const char* name, mode_t mode,
               struct fuse_file_info* fi) {
    fuse_log(FUSE_LOG_DEBUG, "create handler \n");
    auto* ud = udata(req);
    auto* parent_inode = get_inode(parent);
    if(!parent_inode) {
        fuse_reply_err(req, ENOENT);
@@ -352,8 +326,8 @@ create_handler(fuse_req_t req, fuse_ino_t parent, const char* name, mode_t mode,
    fuse_entry_param e = {};
    e.ino = ino;
    e.attr = st;
    e.attr_timeout = 1.0;
    e.entry_timeout = 1.0;
    e.attr_timeout = ud->timeout;
    e.entry_timeout = ud->timeout;
    fuse_reply_create(req, &e, fi);
}

@@ -429,7 +403,7 @@ readdir_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
    }

    size_t bytes_filled = 0;
    off_t pos = off;
    size_t pos = off;

    while(pos < open_dir->size()) {
        auto de = open_dir->getdent(pos);
@@ -458,23 +432,9 @@ readdir_handler(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
    free(buf);
}

static void
init_handler(void* userdata, struct fuse_conn_info* conn) {
    fuse_log(FUSE_LOG_DEBUG, "init handler \n");
    // userdata is GekkoFuse* if passed
    // optional: adjust conn->max_write, enable writeback etc.
}

static void
destroy_handler(void* userdata) {
    fuse_log(FUSE_LOG_DEBUG, "destroy handler \n");
    // userdata is GekkoFuse* if passed
    // optional: adjust conn->max_write, enable writeback etc.
}

/// releases file descriptor, not connected to lookup_count
static void
release_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
    // TODO decrease inode count
    fuse_log(FUSE_LOG_DEBUG, "release handler \n");
    auto* inode = get_inode(ino);
    if(!inode) {
@@ -492,11 +452,31 @@ release_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
    fuse_reply_err(req, 0);
}

/// decrement lookup count
static void
forget_handler(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) {
    // TODO remove inode at some point if count == 0
    fuse_log(FUSE_LOG_DEBUG, "forget handler \n");
    fuse_reply_err(req, 0);

    auto it = ino_map.find(ino);
    if(it == ino_map.end()) {
        fuse_reply_none(req);
        return;
    }

    Inode& inode = it->second;
    if(inode.lookup_count > nlookup)
        inode.lookup_count -= nlookup;
    else
        inode.lookup_count = 0;

    if(inode.lookup_count == 0) { // && inode.open_count == 0
        path_map.erase(inode.path);
        ino_map.erase(it);
        fuse_log(FUSE_LOG_DEBUG, "reached lookup_count 0 \n");
    }

    fuse_reply_none(req);
    // fuse_reply_err(req, 0);
}

static void
@@ -518,77 +498,8 @@ flush_handler(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) {
    fuse_reply_err(req, 0);
}

static const struct fuse_lowlevel_ops lo_oper = {
        .init = init_handler,
        .destroy = destroy_handler,
        .lookup = lookup_handler,
        .forget = forget_handler,
        .getattr = getattr_handler,
        .setattr = setattr_handler,
        //.readlink = lo_readlink,
        //.mknod = lo_mknod,
        //.mkdir = lo_mkdir,
        //.unlink = lo_unlink,
        //.rmdir = lo_rmdir,
        //.symlink = lo_symlink,
        //.rename = lo_rename,
        //.link = lo_link,
        .open = open_handler,
        .read = read_handler,
        .write = write_handler,
        .flush = flush_handler,
        .release = release_handler,
        //.fsync = lo_fsync,
        .opendir = opendir_handler,
        .readdir = readdir_handler,
        //.releasedir = lo_releasedir,
        //.fsyncdir = lo_fsyncdir,
        //.statfs = lo_statfs,
        //.setxattr = lo_setxattr,
        //.getxattr = lo_getxattr,
        //.listxattr = lo_listxattr,
        //.removexattr = lo_removexattr,
        // access
        .create = create_handler,
// getlk
// setlk
// bmap
// ioctl
//.write_buf = lo_write_buf,
// poll
// retrive_reply
//.forget_multi = lo_forget_multi,
//.flock = lo_flock,
//.fallocate = lo_fallocate,
//.readdirplus = lo_readdirplus,
#ifdef HAVE_COPY_FILE_RANGE
//.copy_file_range = lo_copy_file_range,
#endif
//.lseek = lo_lseek,
//.tmpfile = lo_tmpfile,
#ifdef HAVE_STATX
//.statx = lo_statx,
#endif
};

int
main(int argc, char* argv[]) {
    struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    struct fuse_session* se;
    struct fuse_cmdline_opts opts;
    struct fuse_loop_config* config;
    struct lo_data lo = {.debug = 0, .writeback = 0};
    int ret = -1;

    /* Don't mask creation mode, kernel already did that */
    umask(0); // TODO do we need this and why?

    pthread_mutex_init(&lo.mutex, NULL);
    lo.root.next = lo.root.prev = &lo.root;
    lo.root.fd = -1;
    lo.cache = CACHE_NORMAL;

    // init gekkofs
static void
init_gekkofs() {
    // TODO how to handle mount point
    int res = gkfs_init();
    if(res != 0) {
@@ -612,7 +523,107 @@ main(int argc, char* argv[]) {
    ino_map[FUSE_ROOT_ID] = {root_path, {}, 1};
    ino_map[FUSE_ROOT_ID].st = st;
    std::cout << "root node allocated" << std::endl;
}

static void
init_ll_ops(fuse_lowlevel_ops* ops) {
    // file
    ops->getattr = getattr_handler;
    ops->setattr = setattr_handler;
    ops->open = open_handler;
    ops->create = create_handler;
    // ops->unlink
    ops->forget = forget_handler;
    // ops->forget_multi
    // ops->readlink
    // ops->mknod
    // ops->symlink
    // ops->rename
    // ops->link
    ops->flush = flush_handler;
    ops->release = release_handler;
    // ops->fsync
    // ops->write_buf

    // xattr
    // ops->setxattr
    // ops->getxattr
    // ops->listxattr
    // ops->removexattr

    // directory
    ops->lookup = lookup_handler;
    // ops->mkdir
    // ops->rmdir
    ops->readdir = readdir_handler;
    ops->opendir = opendir_handler;
    // ops->releasedir
    // ops->fsyncdir = nullptr;
    // ops->readdirplus

    // I/O
    ops->write = write_handler;
    ops->read = read_handler;

    // permission
    // ops->access

    // misc
    ops->init = init_handler;
    ops->destroy = destroy_handler;
    ops->statfs = nullptr;

    // ops->flock
    // ops->getlk
    // ops->setlk
    // ops->bmap
    // ops->ioctl
    // ops->poll
    // ops->retrive_reply
    // ops->fallocate
    // ops->copy_file_range
    // ops->lseek
    // ops->tmpfile
    // ops->statx
}

void
err_cleanup1(fuse_cmdline_opts opts, fuse_args& args) {
    free(opts.mountpoint);
    fuse_opt_free_args(&args);
    std::cout << "# Resources released" << std::endl;
}

void
err_cleanup2(fuse_session& se) {
    fuse_session_destroy(&se);
    std::cout << "# Fuse session destroyed" << std::endl;
}

void
err_cleanup3(fuse_session& se) {
    fuse_remove_signal_handlers(&se);
    std::cout << "# Signal handlers removed" << std::endl;
}

int
main(int argc, char* argv[]) {
    init_ll_ops(&ll_ops);

    struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    struct fuse_session* se;
    struct fuse_cmdline_opts opts;
    struct fuse_loop_config* config;
    struct u_data ud{};
    ud.debug = 0;
    ud.writeback = 0;
    int ret = -1;

    /* Don't mask creation mode, kernel already did that */
    umask(0); // TODO do we need this and why?

    pthread_mutex_init(&ud.mutex, NULL);
    ud.cache = CACHE_NORMAL;

    if(fuse_parse_cmdline(&args, &opts) != 0)
        return 1;
@@ -621,86 +632,69 @@ main(int argc, char* argv[]) {
        fuse_cmdline_help();
        fuse_lowlevel_help();
        passthrough_ll_help();
        ret = 0;
        goto err_out1;
        err_cleanup1(opts, args);
        return 0;
    } else if(opts.show_version) {
        printf("FUSE library version %s\n", fuse_pkgversion());
        fuse_lowlevel_version();
        ret = 0;
        goto err_out1;
        err_cleanup1(opts, args);
        return 0;
    }

    if(opts.mountpoint == NULL) {
        printf("usage: %s [options] <mountpoint>\n", argv[0]);
        printf("       %s --help\n", argv[0]);
        ret = 1;
        goto err_out1;
        err_cleanup1(opts, args);
        return 0;
    }

    if(fuse_opt_parse(&args, &lo, lo_opts, NULL) == -1)
    if(fuse_opt_parse(&args, &ud, lo_opts, NULL) == -1)
        return 1;

    lo.debug = opts.debug;
    lo.root.refcount = 2;
    if(lo.source) {
        struct stat stat;
        int res;

        res = lstat(lo.source, &stat);
        if(res == -1) {
            fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
                     lo.source);
            exit(1);
        }
        if(!S_ISDIR(stat.st_mode)) {
            fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
            exit(1);
        }

    } else {
        lo.source = strdup("/");
        if(!lo.source) {
            fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
            exit(1);
        }
    }
    if(!lo.timeout_set) {
        switch(lo.cache) {
    ud.debug = opts.debug;
    if(!ud.timeout_set) {
        switch(ud.cache) {
            case CACHE_NEVER:
                lo.timeout = 0.0;
                ud.timeout = 0.0;
                break;

            case CACHE_NORMAL:
                lo.timeout = 1.0;
                ud.timeout = 1.0;
                break;

            case CACHE_ALWAYS:
                lo.timeout = 86400.0;
                ud.timeout = 86400.0;
                break;
        }
    } else if(lo.timeout < 0) {
        fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n", lo.timeout);
    } else if(ud.timeout < 0) {
        fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n", ud.timeout);
        exit(1);
    }

    // TODO do we still want this? what do we want?
    fuse_log(FUSE_LOG_DEBUG, "hier 1\n");
    lo.root.fd = gkfs::syscall::gkfs_open(lo.source, 755, O_PATH);
    if(lo.root.fd == -1) {
        fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n", lo.source);
        exit(1);
    }

    fuse_log(FUSE_LOG_DEBUG, "hier 2\n");
    se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
    if(se == NULL)
        goto err_out1;
    init_gekkofs();

    if(fuse_set_signal_handlers(se) != 0)
        goto err_out2;

    if(fuse_session_mount(se, opts.mountpoint) != 0)
        goto err_out3;
    se = fuse_session_new(&args, &ll_ops, sizeof(ll_ops), &ud);
    if(se == nullptr) {
        err_cleanup1(opts, args);
        return 0;
    }

    if(fuse_set_signal_handlers(se) != 0) {
        err_cleanup2(*se);
        err_cleanup1(opts, args);
        return 0;
    }

    if(fuse_session_mount(se, opts.mountpoint) != 0) {
        err_cleanup3(*se);
        err_cleanup2(*se);
        err_cleanup1(opts, args);
        return 0;
    }

    fuse_daemonize(opts.foreground);

@@ -724,20 +718,5 @@ main(int argc, char* argv[]) {
    }

    fuse_session_unmount(se);
err_out3:
    fuse_log(FUSE_LOG_DEBUG, "hier 3\n");
    fuse_remove_signal_handlers(se);
err_out2:
    fuse_log(FUSE_LOG_DEBUG, "hier 4\n");
    fuse_session_destroy(se);
err_out1:
    fuse_log(FUSE_LOG_DEBUG, "hier 5\n");
    free(opts.mountpoint);
    fuse_opt_free_args(&args);

    if(lo.root.fd >= 0)
        close(lo.root.fd);

    free(lo.source);
    return ret ? 1 : 0;
}
+3 −0
Original line number Diff line number Diff line
@@ -49,3 +49,6 @@ def test_read(gkfs_daemon, fuse_client):
    assert sh.ls(fuse_client.mountdir) == "file\n"
    assert sh.cat(file) == "baum\n"
    sh.touch(str(file2))
    assert sh.wc("-c", str(file2)) == "0 " + str(file2) + "\n"
    sh.truncate("-s", "20", str(file2))
    assert sh.wc("-c", str(file2)) == "20 " + str(file2) + "\n"