Skip to content
GitLab
Explore
Sign in
Commits on Source (4)
fuse integration test setup
· a5a88018
sevenuz
authored
Aug 06, 2025
a5a88018
improve test and fix touch in fuse
· 685ff9ad
sevenuz
authored
Aug 08, 2025
685ff9ad
cleanup and refactoring, fix lookup_count
· 23aeae88
sevenuz
authored
Aug 08, 2025
23aeae88
mkdir causes segvault
· 37d6d804
sevenuz
authored
Aug 08, 2025
37d6d804
Expand all
Show whitespace changes
Inline
Side-by-side
include/client/fuse/fuse_client.hpp
View file @
37d6d804
...
...
@@ -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
src/client/fuse/fuse_client.cpp
View file @
37d6d804
This diff is collapsed.
Click to expand it.
tests/integration/CMakeLists.txt
View file @
37d6d804
...
...
@@ -143,6 +143,15 @@ if (GKFS_RENAME_SUPPORT)
)
endif
()
if
(
GKFS_BUILD_FUSE
)
gkfs_add_python_test
(
NAME test_fuse_client
PYTHON_VERSION 3.6
WORKING_DIRECTORY
${
PROJECT_SOURCE_DIR
}
/tests/integration
SOURCE fuse/
)
endif
()
if
(
GKFS_INSTALL_TESTS
)
install
(
DIRECTORY harness
DESTINATION
${
CMAKE_INSTALL_DATAROOTDIR
}
/gkfs/tests/integration
...
...
tests/integration/conftest.py
View file @
37d6d804
...
...
@@ -34,7 +34,7 @@ from pathlib import Path
from
harness.logger
import
logger
,
initialize_logging
,
finalize_logging
from
harness.cli
import
add_cli_options
,
set_default_log_formatter
from
harness.workspace
import
Workspace
,
FileCreator
from
harness.gkfs
import
Daemon
,
Client
,
ClientLibc
,
Proxy
,
ShellClient
,
ShellClientLibc
,
FwdDaemon
,
FwdClient
,
ShellFwdClient
,
FwdDaemonCreator
,
FwdClientCreator
from
harness.gkfs
import
Daemon
,
Client
,
ClientLibc
,
Proxy
,
ShellClient
,
ShellClientLibc
,
FwdDaemon
,
FwdClient
,
ShellFwdClient
,
FwdDaemonCreator
,
FwdClientCreator
,
FuseClient
from
harness.reporter
import
report_test_status
,
report_test_headline
,
report_assertion_pass
def
pytest_configure
(
config
):
...
...
@@ -225,3 +225,15 @@ def gkfwd_client_factory(test_workspace):
"""
return
FwdClientCreator
(
test_workspace
)
@pytest.fixture
def
fuse_client
(
test_workspace
):
"""
Sets up a gekkofs fuse client environment so that
operations (system calls, library calls, ...) can
be requested from a co-running daemon.
"""
fuse_client
=
FuseClient
(
test_workspace
)
yield
fuse_client
.
run
()
fuse_client
.
shutdown
()
tests/integration/fuse/test_basic_operations.py
0 → 100644
View file @
37d6d804
################################################################################
# Copyright 2018-2025, Barcelona Supercomputing Center (BSC), Spain #
# Copyright 2015-2025, Johannes Gutenberg Universitaet Mainz, Germany #
# #
# This software was partially supported by the #
# EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). #
# #
# This software was partially supported by the #
# ADA-FS project under the SPPEXA project funded by the DFG. #
# #
# This file is part of GekkoFS. #
# #
# GekkoFS is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# GekkoFS is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with GekkoFS. If not, see <https://www.gnu.org/licenses/>. #
# #
# SPDX-License-Identifier: GPL-3.0-or-later #
################################################################################
import
harness
from
pathlib
import
Path
import
errno
import
stat
import
os
import
ctypes
import
sh
import
sys
import
pytest
import
time
from
harness.logger
import
logger
nonexisting
=
"
nonexisting
"
def
test_read
(
gkfs_daemon
,
fuse_client
):
file
=
gkfs_daemon
.
mountdir
/
"
file
"
file2
=
gkfs_daemon
.
mountdir
/
"
file2
"
dir
=
gkfs_daemon
.
mountdir
/
"
dir
"
sh
.
bash
(
"
-c
"
,
"
echo baum >
"
+
str
(
file
))
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
"
sh
.
mkdir
(
str
(
dir
))
tests/integration/harness/gkfs.py
View file @
37d6d804
...
...
@@ -74,6 +74,7 @@ gkfwd_client_log_level = 'all'
gkfwd_client_log_syscall_filter
=
'
epoll_wait,epoll_create
'
gkfwd_daemon_active_log_pattern
=
r
'
Startup successful. Daemon is ready.
'
gkfs_fuse_client
=
'
fuse_client
'
def
get_ip_addr
(
iface
):
return
netifaces
.
ifaddresses
(
iface
)[
netifaces
.
AF_INET
][
0
][
'
addr
'
]
...
...
@@ -1637,3 +1638,78 @@ class ShellFwdClient:
@property
def
cwd
(
self
):
return
self
.
_workspace
.
twd
class
FuseClient
:
def
__init__
(
self
,
workspace
):
self
.
_workspace
=
workspace
#self._cmd = sh.Command("printenv", ["/usr/bin/"])#self._workspace.bindirs)
self
.
_cmd
=
sh
.
Command
(
gkfs_fuse_client
,
self
.
_workspace
.
bindirs
)
self
.
_env
=
os
.
environ
.
copy
()
self
.
_metadir
=
self
.
rootdir
libdirs
=
'
:
'
.
join
(
filter
(
None
,
[
os
.
environ
.
get
(
'
LD_LIBRARY_PATH
'
,
''
)]
+
[
str
(
p
)
for
p
in
self
.
_workspace
.
libdirs
]))
self
.
_patched_env
=
{
'
LD_LIBRARY_PATH
'
:
libdirs
,
'
GKFS_HOSTS_FILE
'
:
str
(
self
.
cwd
/
gkfs_hosts_file
),
'
LIBGKFS_HOSTS_FILE
'
:
str
(
self
.
cwd
/
gkfs_hosts_file
),
# TODO wtf why? see gkfs::env::HOSTS_FILE
}
self
.
_env
.
update
(
self
.
_patched_env
)
def
run
(
self
):
args
=
[
"
-f
"
,
"
-s
"
,
self
.
_workspace
.
mountdir
,
"
-o
"
,
"
auto_unmount
"
]
print
(
f
"
spawning fuse client
"
)
print
(
f
"
cmdline:
{
self
.
_cmd
}
"
+
"
"
.
join
(
map
(
str
,
args
)))
print
(
f
"
patched env:
\n
{
pformat
(
self
.
_patched_env
)
}
"
)
self
.
_proc
=
self
.
_cmd
(
args
,
_env
=
self
.
_env
,
_out
=
'
/dev/null
'
,
_err
=
'
/dev/null
'
,
_bg
=
True
,
_ok_code
=
list
(
range
(
0
,
256
))
)
print
(
f
"
fuse client process spawned (PID=
{
self
.
_proc
.
pid
}
)
"
)
time
.
sleep
(
2
)
# give fuse time to register mount
return
self
def
shutdown
(
self
):
try
:
self
.
_proc
.
terminate
()
err
=
self
.
_proc
.
wait
()
except
sh
.
SignalException_SIGTERM
:
pass
except
Exception
:
raise
@property
def
cwd
(
self
):
return
self
.
_workspace
.
twd
@property
def
rootdir
(
self
):
return
self
.
_workspace
.
rootdir
@property
def
mountdir
(
self
):
return
self
.
_workspace
.
mountdir
@property
def
bindirs
(
self
):
return
self
.
_workspace
.
bindirs
@property
def
logdir
(
self
):
return
self
.
_workspace
.
logdir
@property
def
env
(
self
):
return
self
.
_env