Loading include/client/hooks.hpp +14 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,8 @@ extern "C" { #include <sys/syscall.h> } #include <unordered_map> #include <libsyscall_intercept_hook_point.h> #include <client/intercept.hpp> Loading @@ -73,6 +75,18 @@ syscall_no_intercept_wrapper(long syscall_number, Args... args) { struct statfs; struct fd_state { off_t last_off = -1; size_t last_size = -1; int seq_count = 0; int random_count = 0; bool is_random = false; }; static std::unordered_map<unsigned int, fd_state> fd_state_map; /// returns false to stay in syscall intercept, true to go to fuse static bool update_fd_state(unsigned int fd, off_t offset, size_t size); namespace gkfs::hook { int Loading src/client/hooks.cpp +126 −8 Original line number Diff line number Diff line Loading @@ -69,6 +69,56 @@ with_errno(T ret) { } // namespace static bool update_fd_state(unsigned int fd, off_t offset, size_t size) { auto it = fd_state_map.find(fd); if(it == fd_state_map.end()) { // No state for this FD, stay in syscall intercept return false; } auto& st = it->second; if(st.last_off == -1) { // first observation st.last_off = offset; st.last_size = size; return false; } const off_t expected = st.last_off + st.last_size; const off_t diff = offset - expected; // configurable thresholds constexpr off_t small_delta = 4096; // ≤4 KB jump = still sequential constexpr off_t big_jump_threshold = 128 * 1024; // >128 KB = definitely random if(std::abs(diff) <= small_delta) { st.seq_count++; } else if(std::abs(diff) > big_jump_threshold) { st.random_count++; } else { // medium jump: weak indication of randomness st.random_count++; } if(st.random_count > st.seq_count * 2) { st.is_random = true; } else { st.is_random = false; } st.last_off = offset; st.last_size = size; return !st.is_random; } static size_t total_iovec_size(const struct iovec* iov, int iovcnt) { size_t total = 0; for(int i = 0; i < iovcnt; ++i) total += iov[i].iov_len; return total; } namespace gkfs::hook { int Loading Loading @@ -107,6 +157,7 @@ hook_openat(int dirfd, const char* cpath, int flags, mode_t mode) { CTX->file_map()->add( fd, std::make_shared<gkfs::filemap::OpenFile>(resolved, flags)); fd_state_map[fd] = fd_state{}; return with_errno(fd); } } Loading @@ -122,6 +173,7 @@ hook_close(int fd) { LOG(DEBUG, "{}() called with fd: {}", __func__, fd); auto ret = gkfs::syscall::gkfs_close(fd); fd_state_map.erase(fd); if(ret < 0) LOG(DEBUG, "{}() close failed with fd: {}, errno {}", __func__, fd, Loading Loading @@ -257,7 +309,19 @@ hook_read(unsigned int fd, void* buf, size_t count) { fmt::ptr(buf), count); if(CTX->file_map()->exist(fd)) { auto gkfs_fd = CTX->file_map()->get(fd); // retrieve the current offset auto pos = gkfs_fd->pos(); bool use_syscall = update_fd_state(fd, pos, count); if(use_syscall) { return with_errno(gkfs::syscall::gkfs_read(fd, buf, count)); } else { int ret = syscall_no_intercept_wrapper(SYS_pread64, fd, buf, count, pos); if(ret > 0) { gkfs_fd->pos(pos + ret); } return ret; } } return syscall_no_intercept_wrapper(SYS_read, fd, buf, count); } Loading @@ -269,8 +333,11 @@ hook_pread(unsigned int fd, char* buf, size_t count, loff_t pos) { fd, fmt::ptr(buf), count, pos); if(CTX->file_map()->exist(fd)) { bool use_syscall = update_fd_state(fd, pos, count); if(use_syscall) { return with_errno(gkfs::syscall::gkfs_pread(fd, buf, count, pos)); } } /* Since kernel 2.6: pread() became pread64(), and pwrite() became * pwrite64(). */ return syscall_no_intercept_wrapper(SYS_pread64, fd, buf, count, pos); Loading @@ -283,7 +350,20 @@ hook_readv(unsigned long fd, const struct iovec* iov, unsigned long iovcnt) { fmt::ptr(iov), iovcnt); if(CTX->file_map()->exist(fd)) { auto gkfs_fd = CTX->file_map()->get(fd); // retrieve the current offset auto pos = gkfs_fd->pos(); bool use_syscall = update_fd_state(fd, pos, total_iovec_size(iov, iovcnt)); if(use_syscall) { return with_errno(gkfs::syscall::gkfs_readv(fd, iov, iovcnt)); } else { int ret = syscall_no_intercept_wrapper(SYS_preadv, fd, iov, iovcnt, pos); if(ret > 0) { gkfs_fd->pos(pos + ret); } return ret; } } return syscall_no_intercept_wrapper(SYS_readv, fd, iov, iovcnt); } Loading @@ -299,7 +379,12 @@ hook_preadv(unsigned long fd, const struct iovec* iov, unsigned long iovcnt, __func__, fd, fmt::ptr(iov), iovcnt, pos_l, pos_h); if(CTX->file_map()->exist(fd)) { return with_errno(gkfs::syscall::gkfs_preadv(fd, iov, iovcnt, pos_l)); bool use_syscall = update_fd_state(fd, pos_l, total_iovec_size(iov, iovcnt)); if(use_syscall) { return with_errno( gkfs::syscall::gkfs_preadv(fd, iov, iovcnt, pos_l)); } } return syscall_no_intercept_wrapper(SYS_preadv, fd, iov, iovcnt, pos_l); } Loading @@ -311,7 +396,19 @@ hook_write(unsigned int fd, const char* buf, size_t count) { fmt::ptr(buf), count); if(CTX->file_map()->exist(fd)) { auto gkfs_fd = CTX->file_map()->get(fd); // retrieve the current offset auto pos = gkfs_fd->pos(); bool use_syscall = update_fd_state(fd, pos, count); if(use_syscall) { return with_errno(gkfs::syscall::gkfs_write(fd, buf, count)); } else { int ret = syscall_no_intercept_wrapper(SYS_pwrite64, fd, buf, count, pos); if(ret > 0) { gkfs_fd->pos(pos + ret); } return ret; } } return syscall_no_intercept_wrapper(SYS_write, fd, buf, count); } Loading @@ -323,8 +420,11 @@ hook_pwrite(unsigned int fd, const char* buf, size_t count, loff_t pos) { fd, fmt::ptr(buf), count, pos); if(CTX->file_map()->exist(fd)) { bool use_syscall = update_fd_state(fd, pos, count); if(use_syscall) { return with_errno(gkfs::syscall::gkfs_pwrite(fd, buf, count, pos)); } } /* Since kernel 2.6: pread() became pread64(), and pwrite() became * pwrite64(). */ return syscall_no_intercept_wrapper(SYS_pwrite64, fd, buf, count, pos); Loading @@ -337,7 +437,20 @@ hook_writev(unsigned long fd, const struct iovec* iov, unsigned long iovcnt) { fmt::ptr(iov), iovcnt); if(CTX->file_map()->exist(fd)) { auto gkfs_fd = CTX->file_map()->get(fd); // retrieve the current offset auto pos = gkfs_fd->pos(); bool use_syscall = update_fd_state(fd, pos, total_iovec_size(iov, iovcnt)); if(use_syscall) { return with_errno(gkfs::syscall::gkfs_writev(fd, iov, iovcnt)); } else { int ret = syscall_no_intercept_wrapper(SYS_pwritev, fd, iov, iovcnt, pos); if(ret > 0) { gkfs_fd->pos(pos + ret); } return ret; } } return syscall_no_intercept_wrapper(SYS_writev, fd, iov, iovcnt); } Loading @@ -353,7 +466,12 @@ hook_pwritev(unsigned long fd, const struct iovec* iov, unsigned long iovcnt, __func__, fd, fmt::ptr(iov), iovcnt, pos_l, pos_h); if(CTX->file_map()->exist(fd)) { return with_errno(gkfs::syscall::gkfs_pwritev(fd, iov, iovcnt, pos_l)); bool use_syscall = update_fd_state(fd, pos_l, total_iovec_size(iov, iovcnt)); if(use_syscall) { return with_errno( gkfs::syscall::gkfs_pwritev(fd, iov, iovcnt, pos_l)); } } return syscall_no_intercept_wrapper(SYS_pwritev, fd, iov, iovcnt, pos_l); } Loading Loading
include/client/hooks.hpp +14 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,8 @@ extern "C" { #include <sys/syscall.h> } #include <unordered_map> #include <libsyscall_intercept_hook_point.h> #include <client/intercept.hpp> Loading @@ -73,6 +75,18 @@ syscall_no_intercept_wrapper(long syscall_number, Args... args) { struct statfs; struct fd_state { off_t last_off = -1; size_t last_size = -1; int seq_count = 0; int random_count = 0; bool is_random = false; }; static std::unordered_map<unsigned int, fd_state> fd_state_map; /// returns false to stay in syscall intercept, true to go to fuse static bool update_fd_state(unsigned int fd, off_t offset, size_t size); namespace gkfs::hook { int Loading
src/client/hooks.cpp +126 −8 Original line number Diff line number Diff line Loading @@ -69,6 +69,56 @@ with_errno(T ret) { } // namespace static bool update_fd_state(unsigned int fd, off_t offset, size_t size) { auto it = fd_state_map.find(fd); if(it == fd_state_map.end()) { // No state for this FD, stay in syscall intercept return false; } auto& st = it->second; if(st.last_off == -1) { // first observation st.last_off = offset; st.last_size = size; return false; } const off_t expected = st.last_off + st.last_size; const off_t diff = offset - expected; // configurable thresholds constexpr off_t small_delta = 4096; // ≤4 KB jump = still sequential constexpr off_t big_jump_threshold = 128 * 1024; // >128 KB = definitely random if(std::abs(diff) <= small_delta) { st.seq_count++; } else if(std::abs(diff) > big_jump_threshold) { st.random_count++; } else { // medium jump: weak indication of randomness st.random_count++; } if(st.random_count > st.seq_count * 2) { st.is_random = true; } else { st.is_random = false; } st.last_off = offset; st.last_size = size; return !st.is_random; } static size_t total_iovec_size(const struct iovec* iov, int iovcnt) { size_t total = 0; for(int i = 0; i < iovcnt; ++i) total += iov[i].iov_len; return total; } namespace gkfs::hook { int Loading Loading @@ -107,6 +157,7 @@ hook_openat(int dirfd, const char* cpath, int flags, mode_t mode) { CTX->file_map()->add( fd, std::make_shared<gkfs::filemap::OpenFile>(resolved, flags)); fd_state_map[fd] = fd_state{}; return with_errno(fd); } } Loading @@ -122,6 +173,7 @@ hook_close(int fd) { LOG(DEBUG, "{}() called with fd: {}", __func__, fd); auto ret = gkfs::syscall::gkfs_close(fd); fd_state_map.erase(fd); if(ret < 0) LOG(DEBUG, "{}() close failed with fd: {}, errno {}", __func__, fd, Loading Loading @@ -257,7 +309,19 @@ hook_read(unsigned int fd, void* buf, size_t count) { fmt::ptr(buf), count); if(CTX->file_map()->exist(fd)) { auto gkfs_fd = CTX->file_map()->get(fd); // retrieve the current offset auto pos = gkfs_fd->pos(); bool use_syscall = update_fd_state(fd, pos, count); if(use_syscall) { return with_errno(gkfs::syscall::gkfs_read(fd, buf, count)); } else { int ret = syscall_no_intercept_wrapper(SYS_pread64, fd, buf, count, pos); if(ret > 0) { gkfs_fd->pos(pos + ret); } return ret; } } return syscall_no_intercept_wrapper(SYS_read, fd, buf, count); } Loading @@ -269,8 +333,11 @@ hook_pread(unsigned int fd, char* buf, size_t count, loff_t pos) { fd, fmt::ptr(buf), count, pos); if(CTX->file_map()->exist(fd)) { bool use_syscall = update_fd_state(fd, pos, count); if(use_syscall) { return with_errno(gkfs::syscall::gkfs_pread(fd, buf, count, pos)); } } /* Since kernel 2.6: pread() became pread64(), and pwrite() became * pwrite64(). */ return syscall_no_intercept_wrapper(SYS_pread64, fd, buf, count, pos); Loading @@ -283,7 +350,20 @@ hook_readv(unsigned long fd, const struct iovec* iov, unsigned long iovcnt) { fmt::ptr(iov), iovcnt); if(CTX->file_map()->exist(fd)) { auto gkfs_fd = CTX->file_map()->get(fd); // retrieve the current offset auto pos = gkfs_fd->pos(); bool use_syscall = update_fd_state(fd, pos, total_iovec_size(iov, iovcnt)); if(use_syscall) { return with_errno(gkfs::syscall::gkfs_readv(fd, iov, iovcnt)); } else { int ret = syscall_no_intercept_wrapper(SYS_preadv, fd, iov, iovcnt, pos); if(ret > 0) { gkfs_fd->pos(pos + ret); } return ret; } } return syscall_no_intercept_wrapper(SYS_readv, fd, iov, iovcnt); } Loading @@ -299,7 +379,12 @@ hook_preadv(unsigned long fd, const struct iovec* iov, unsigned long iovcnt, __func__, fd, fmt::ptr(iov), iovcnt, pos_l, pos_h); if(CTX->file_map()->exist(fd)) { return with_errno(gkfs::syscall::gkfs_preadv(fd, iov, iovcnt, pos_l)); bool use_syscall = update_fd_state(fd, pos_l, total_iovec_size(iov, iovcnt)); if(use_syscall) { return with_errno( gkfs::syscall::gkfs_preadv(fd, iov, iovcnt, pos_l)); } } return syscall_no_intercept_wrapper(SYS_preadv, fd, iov, iovcnt, pos_l); } Loading @@ -311,7 +396,19 @@ hook_write(unsigned int fd, const char* buf, size_t count) { fmt::ptr(buf), count); if(CTX->file_map()->exist(fd)) { auto gkfs_fd = CTX->file_map()->get(fd); // retrieve the current offset auto pos = gkfs_fd->pos(); bool use_syscall = update_fd_state(fd, pos, count); if(use_syscall) { return with_errno(gkfs::syscall::gkfs_write(fd, buf, count)); } else { int ret = syscall_no_intercept_wrapper(SYS_pwrite64, fd, buf, count, pos); if(ret > 0) { gkfs_fd->pos(pos + ret); } return ret; } } return syscall_no_intercept_wrapper(SYS_write, fd, buf, count); } Loading @@ -323,8 +420,11 @@ hook_pwrite(unsigned int fd, const char* buf, size_t count, loff_t pos) { fd, fmt::ptr(buf), count, pos); if(CTX->file_map()->exist(fd)) { bool use_syscall = update_fd_state(fd, pos, count); if(use_syscall) { return with_errno(gkfs::syscall::gkfs_pwrite(fd, buf, count, pos)); } } /* Since kernel 2.6: pread() became pread64(), and pwrite() became * pwrite64(). */ return syscall_no_intercept_wrapper(SYS_pwrite64, fd, buf, count, pos); Loading @@ -337,7 +437,20 @@ hook_writev(unsigned long fd, const struct iovec* iov, unsigned long iovcnt) { fmt::ptr(iov), iovcnt); if(CTX->file_map()->exist(fd)) { auto gkfs_fd = CTX->file_map()->get(fd); // retrieve the current offset auto pos = gkfs_fd->pos(); bool use_syscall = update_fd_state(fd, pos, total_iovec_size(iov, iovcnt)); if(use_syscall) { return with_errno(gkfs::syscall::gkfs_writev(fd, iov, iovcnt)); } else { int ret = syscall_no_intercept_wrapper(SYS_pwritev, fd, iov, iovcnt, pos); if(ret > 0) { gkfs_fd->pos(pos + ret); } return ret; } } return syscall_no_intercept_wrapper(SYS_writev, fd, iov, iovcnt); } Loading @@ -353,7 +466,12 @@ hook_pwritev(unsigned long fd, const struct iovec* iov, unsigned long iovcnt, __func__, fd, fmt::ptr(iov), iovcnt, pos_l, pos_h); if(CTX->file_map()->exist(fd)) { return with_errno(gkfs::syscall::gkfs_pwritev(fd, iov, iovcnt, pos_l)); bool use_syscall = update_fd_state(fd, pos_l, total_iovec_size(iov, iovcnt)); if(use_syscall) { return with_errno( gkfs::syscall::gkfs_pwritev(fd, iov, iovcnt, pos_l)); } } return syscall_no_intercept_wrapper(SYS_pwritev, fd, iov, iovcnt, pos_l); } Loading