Skip to content
Commits on Source (2)
......@@ -62,6 +62,9 @@ gkfs:
- sed -i 's/constexpr bool use_dentry_cache = false;/constexpr bool use_dentry_cache = true;/g' "${CI_PROJECT_DIR}/include/config.hpp"
#- sed -i 's/constexpr auto zero_buffer_before_read = false;/constexpr auto zero_buffer_before_read = true;/g' "${CI_PROJECT_DIR}/include/config.hpp"
#- sed -i 's/constexpr auto implicit_data_removal = true;/constexpr auto implicit_data_removal = false;/g' "${CI_PROJECT_DIR}/include/config.hpp"
# install libfuse
- apt update
- apt install libfuse3-dev fuse3
# use ccache
- ccache --zero-stats -M 750MiB -F 800 --evict-older-than 10d
- /usr/sbin/update-ccache-symlinks
......
......@@ -45,6 +45,19 @@
extern "C" {
#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
#include <fuse3/fuse_lowlevel.h>
// TODO do we really need this? sizeof(DIR) statement, copied from gkfs_libc.hpp
struct __dirstream {
int fd; // File descriptor.
//__libc_lock_define (, lock) // Mutex lock for this structure. //TODO
size_t allocation; // Space allocated for the block.
size_t size; // Total valid data in the block.
size_t offset; // Current offset into the block.
off_t filepos; // Position of next entry to read.
// Directory block.
char* path;
char data[1] __attribute__((aligned(__alignof__(void*))));
}; // Originally its 0, but C++ does not permit it
}
#include <unistd.h>
......@@ -61,29 +74,10 @@ extern "C" {
#include <pthread.h>
#include <sys/file.h>
#include <sys/xattr.h>
/* We are re-using pointers to our `struct lo_inode` and `struct
lo_dirp` elements as inodes. This means that we must be able to
store uintptr_t values in a fuse_ino_t variable. The following
incantation checks this condition at compile time. */
#if defined(__GNUC__) && \
(__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && \
!defined __cplusplus
_Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t),
"fuse_ino_t too small to hold uintptr_t values!");
#else
struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct {
unsigned _uintptr_to_must_hold_fuse_ino_t
: ((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1);
};
#endif
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <filesystem>
#include <unordered_map>
#include <string>
#include <mutex>
......@@ -102,99 +96,6 @@ struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct {
#include <client/preload.hpp>
#include <client/preload_context.hpp>
#include <client/user_functions.hpp>
#include <client/gkfs_libc.hpp>
static inline int
do_fallocate(int fd, int mode, off_t offset, off_t length) {
#ifdef HAVE_FALLOCATE
if(fallocate(fd, mode, offset, length) == -1)
return -errno;
return 0;
#else // HAVE_FALLOCATE
#ifdef HAVE_POSIX_FALLOCATE
if(mode == 0)
return -posix_fallocate(fd, offset, length);
#endif
#ifdef HAVE_FSPACECTL
// 0x3 == FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE
if(mode == 0x3) {
struct spacectl_range sr;
sr.r_offset = offset;
sr.r_len = length;
if(fspacectl(fd, SPACECTL_DEALLOC, &sr, 0, NULL) == -1)
return -errno;
return 0;
}
#endif
return -EOPNOTSUPP;
#endif // HAVE_FALLOCATE
}
// all from the gkfs_libc
enum class PathStatus { External, Internal, Error };
/**
* @brief Resolves a path in the context of GekkoFS.
* (Details as in original comment)
*/
static inline PathStatus
resolve_gkfs_path(int dirfd, const char* path, std::string& resolved,
int flags = 0, bool resolve_last_link = true) {
const auto status = CTX->relativize_fd_path(dirfd, path, resolved, flags,
resolve_last_link);
switch(status) {
case gkfs::preload::RelativizeStatus::internal:
return PathStatus::Internal;
case gkfs::preload::RelativizeStatus::fd_not_a_dir:
errno = ENOTDIR;
return PathStatus::Error;
case gkfs::preload::RelativizeStatus::fd_unknown:
errno = EBADF;
return PathStatus::Error;
default: // Assuming other statuses mean external or not applicable
return PathStatus::External;
}
}
#define DEBUG_INFO(...) \
do { \
if(CTX->interception_enabled()) \
LOG(DEBUG, __VA_ARGS__); \
} while(0)
#define GKFS_PATH_OPERATION(name, dirfd, path, ...) \
if(CTX->interception_enabled()) { \
std::string resolved; \
switch(resolve_gkfs_path(dirfd, path, resolved)) { \
case PathStatus::Internal: \
fuse_log(FUSE_LOG_DEBUG, "[GKFS] {}(path='{}')\n", #name, \
resolved.c_str()); \
return gkfs::syscall::gkfs_##name(resolved, __VA_ARGS__); \
case PathStatus::Error: \
return -1; \
default: /* External */ \
break; \
} \
}
#define GKFS_PATH_OPERATION1(name, dirfd, path) \
if(CTX->interception_enabled()) { \
std::string resolved; \
switch(resolve_gkfs_path(dirfd, path, resolved)) { \
case PathStatus::Internal: \
fuse_log(FUSE_LOG_DEBUG, "[GKFS] {}(path='{}')\n", #name, \
resolved.c_str()); \
gkfs::syscall::gkfs_##name(resolved); \
case PathStatus::Error: \
fuse_reply_err(req, -1); \
default: /* External */ \
fuse_reply_err(req, -1); \
} \
}
struct GkfsDir { // Hypothetical structure that might be used if DIR is cast
int fd;
......@@ -203,73 +104,6 @@ struct GkfsDir { // Hypothetical structure that might be used if DIR is cast
// other members libc DIR might have
};
static inline std::pair<int, std::string>
lol_path(int dfd, const char* path, int flags) {
std::string resolved = "";
int err = 0;
if(CTX->interception_enabled()) {
// AT_SYMLINK_NOFOLLOW means lstat behavior, otherwise stat behavior.
bool follow_link = !(flags & AT_SYMLINK_NOFOLLOW);
// Path resolution needs to know if it's for lstat or stat context for
// the final component. resolve_gkfs_path's `resolve_last_link`
// parameter handles this.
switch(resolve_gkfs_path(dfd, path, resolved, flags, follow_link)) {
case PathStatus::Internal:
break;
case PathStatus::Error:
err = -1;
break;
default: // External
break;
}
}
return std::make_pair(err, resolved);
}
static inline int
lol_fstatat(int dfd, const char* path, struct stat* buf, int flags) {
if(CTX->interception_enabled()) {
std::string resolved;
// AT_SYMLINK_NOFOLLOW means lstat behavior, otherwise stat behavior.
bool follow_link = !(flags & AT_SYMLINK_NOFOLLOW);
// Path resolution needs to know if it's for lstat or stat context for
// the final component. resolve_gkfs_path's `resolve_last_link`
// parameter handles this.
switch(resolve_gkfs_path(dfd, path, resolved, flags, follow_link)) {
case PathStatus::Internal:
return gkfs::syscall::gkfs_stat(resolved, buf, follow_link);
case PathStatus::Error:
return -1; // errno set
default: // External
break;
}
}
return -1;
}
static inline int
lol_openat(int dfd, const char* path, mode_t mode, int flags) {
if(CTX->interception_enabled()) {
std::string resolved;
// AT_SYMLINK_NOFOLLOW means lstat behavior, otherwise stat behavior.
bool follow_link = !(flags & AT_SYMLINK_NOFOLLOW);
// Path resolution needs to know if it's for lstat or stat context for
// the final component. resolve_gkfs_path's `resolve_last_link`
// parameter handles this.
switch(resolve_gkfs_path(dfd, path, resolved, flags, follow_link)) {
case PathStatus::Internal:
fuse_log(FUSE_LOG_DEBUG, "lol_openat internal\n");
return gkfs::syscall::gkfs_open(resolved, mode, follow_link);
case PathStatus::Error:
return -1; // errno set
default: // External
break;
}
}
return -1;
}
/*
* Creates files on the underlying file system in response to a FUSE_MKNOD
* operation
......@@ -281,12 +115,12 @@ mknod_wrapper(int dirfd, const char* path, const char* link, int mode,
int res = -1;
if(S_ISREG(mode)) {
res = lol_openat(dirfd, path, mode, O_CREAT | O_EXCL | O_WRONLY);
//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)
//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) {
......
......@@ -37,14 +37,7 @@
SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "client/env.hpp"
#include "common/env_util.hpp"
#include <cerrno>
#include <client/fuse/fuse_client.hpp>
#include <cstdio>
#include <cstdlib>
#include <dirent.h>
#include <iostream>
struct lo_inode {
struct lo_inode* next; /* protected by lo->mutex */
......@@ -334,10 +327,17 @@ create_handler(fuse_req_t req, fuse_ino_t parent, const char* name, mode_t mode,
std::string path = parent_inode->path + name;
int rc = gkfs::syscall::gkfs_create(path, mode);
if(rc == -1) {
fuse_log(FUSE_LOG_DEBUG, "here here mode %i flags %i \n", mode, fi->flags);
fuse_log(FUSE_LOG_DEBUG, "here here mode %i flags %i \n", mode,
fi->flags);
fuse_reply_err(req, 1);
return;
}
int fd = gkfs::syscall::gkfs_open(path, mode, fi->flags);
if(fd < 0) {
fuse_reply_err(req, ENOENT);
return;
}
fi->fh = fd;
struct stat st;
int sc = gkfs::syscall::gkfs_stat(path, &st);
if(sc == -1) {
......@@ -525,7 +525,7 @@ main(int argc, char* argv[]) {
int ret = -1;
/* Don't mask creation mode, kernel already did that */
umask(0);
umask(0); // TODO do we need this and why?
pthread_mutex_init(&lo.mutex, NULL);
lo.root.next = lo.root.prev = &lo.root;
......@@ -627,6 +627,7 @@ main(int argc, char* argv[]) {
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) {
......@@ -651,12 +652,19 @@ main(int argc, char* argv[]) {
if(opts.singlethread)
ret = fuse_session_loop(se);
else {
#if FUSE_MAJOR_VERSION > 3 || \
(FUSE_MAJOR_VERSION == 3 && FUSE_MINOR_VERSION >= 12)
config = fuse_loop_cfg_create();
fuse_loop_cfg_set_clone_fd(config, opts.clone_fd);
fuse_loop_cfg_set_max_threads(config, opts.max_threads);
ret = fuse_session_loop_mt(se, config);
fuse_loop_cfg_destroy(config);
config = NULL;
#else
// for older fuse versions like on the ubuntu22
ret = fuse_session_loop_mt(
se, NULL); // second argument should be checked!!!
#endif
}
fuse_session_unmount(se);
......