Skip to content
GitLab
Explore
Sign in
Commits on Source (2)
compilation fix for older fuse versions, remove gkfs_libc header by including __dirstream struct
· 805471ea
sevenuz
authored
Aug 04, 2025
805471ea
uncomplete cleanup and ci requirements
· 1f388c43
sevenuz
authored
Aug 04, 2025
1f388c43
Show whitespace changes
Inline
Side-by-side
.gitlab-ci.yml
View file @
1f388c43
...
...
@@ -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
...
...
include/client/fuse/fuse_client.hpp
View file @
1f388c43
...
...
@@ -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
)
{
...
...
src/client/fuse/fuse_client.cpp
View file @
1f388c43
...
...
@@ -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
);
...
...