Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions boards/native/native_sim/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -676,21 +676,26 @@ crashes, you can cleanup the stale mount point by using the program

$ fusermount -u flash

Note that this feature requires a 32-bit version of the FUSE library, with a
minimal version of 2.6, on the host system and ``pkg-config`` settings to
correctly pickup the FUSE install path and compiler flags.
You can chose to use the v2 FUSE host library or the v3 with
:kconfig:option:`CONFIG_FUSE_LIBRARY_VERSION`.
When using the v2, a minimal version of 2.6 is necessary. For v3, 3.0 should suffice.
You will also need ``pkg-config`` setup to correctly pickup the FUSE install path and compiler flags.
Note that using this feature with the 32-bit native_sim variant requires the 32-bit version of the
corresponding FUSE library.

On a Ubuntu 22.04 host system, for example, install the ``pkg-config`` and
``libfuse-dev:i386`` packages, and configure the pkg-config search path with
these commands:
For example, to use the v2 of the library, on a Ubuntu 24.04 host system, install the ``pkg-config``
and ``libfuse-dev:i386`` for 32-bit builds, and ``libfuse-dev`` for 64-bit builds:

.. code-block:: console

$ sudo dpkg --add-architecture i386
$ sudo apt update
$ sudo apt-get install pkg-config libfuse-dev:i386
$ sudo apt-get install pkg-config libfuse-dev:i386 libfuse-dev
$ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig

Similarly ``libfuse3-dev:i386`` and ``libfuse3-dev`` provide the 32 and 64-bit FUSE v3 library
and headers.

.. _native_sim_peripherals_c_compat:

Peripherals and backends C library compatibility
Expand Down
13 changes: 10 additions & 3 deletions subsys/fs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,16 @@ add_subdirectory_ifdef(CONFIG_ZMS ./zms)
if(CONFIG_FUSE_FS_ACCESS)
zephyr_library_named(FS_FUSE)
find_package(PkgConfig REQUIRED)
pkg_search_module(FUSE REQUIRED fuse)
zephyr_include_directories(${FUSE_INCLUDE_DIRS})
target_link_options(native_simulator INTERFACE "-l${FUSE_LIBRARIES}")
if (CONFIG_FUSE_LIBRARY_V3)
pkg_search_module(FUSE REQUIRED fuse3)
target_compile_options(native_simulator INTERFACE "-DCONFIG_FUSE_LIBRARY_V3")
else()
pkg_search_module(FUSE REQUIRED fuse)
endif()
list(TRANSFORM FUSE_INCLUDE_DIRS PREPEND "-I")
target_compile_options(native_simulator INTERFACE ${FUSE_INCLUDE_DIRS})
list(TRANSFORM FUSE_LIBRARIES PREPEND "-l")
target_link_options(native_simulator INTERFACE ${FUSE_LIBRARIES})
target_sources(native_simulator INTERFACE fuse_fs_access_bottom.c)
target_compile_options(native_simulator INTERFACE "-D_FILE_OFFSET_BITS=64")
zephyr_library_sources(fuse_fs_access.c)
Expand Down
17 changes: 17 additions & 0 deletions subsys/fs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,23 @@ config FUSE_FS_ACCESS
help
Expose file system partitions to the host system through FUSE.

choice FUSE_LIBRARY_VERSION
prompt "Host FUSE library version"
depends on FUSE_FS_ACCESS
default FUSE_LIBRARY_V2

config FUSE_LIBRARY_V2
bool "Use libfuse(2)"
help
Use v2 of the host FUSE library.

config FUSE_LIBRARY_V3
bool "Use libfuse3"
help
Use the host fuse3 library. This may not be available in older distributions.

endchoice

endif # FILE_SYSTEM

if FILE_SYSTEM_LIB_LINK
Expand Down
108 changes: 100 additions & 8 deletions subsys/fs/fuse_fs_access_bottom.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
* SPDX-License-Identifier: Apache-2.0
*/

#if defined(CONFIG_FUSE_LIBRARY_V3)
#define FUSE_USE_VERSION 30
#else
#define FUSE_USE_VERSION 26
#endif

#undef _XOPEN_SOURCE
#define _XOPEN_SOURCE 700
Expand Down Expand Up @@ -40,6 +44,9 @@

static pthread_t fuse_thread;
static struct ffa_op_callbacks *op_callbacks;
#if defined(CONFIG_FUSE_LIBRARY_V3)
static sem_t fuse_started; /* semaphore to signal fuse_main has started */
#endif

/* Pending operation the bottom/fuse thread is queuing into the Zephyr thread */
struct {
Expand Down Expand Up @@ -197,8 +204,14 @@ static bool is_mount_point(const char *path)
return strcmp(dirname(dir_path), "/") == 0;
}

#if defined(CONFIG_FUSE_LIBRARY_V3)
static int fuse_fs_access_getattr(const char *path, struct stat *st, struct fuse_file_info *fi)
{
NSI_ARG_UNUSED(fi);
#else
static int fuse_fs_access_getattr(const char *path, struct stat *st)
{
#endif
struct ffa_dirent entry;
int err;

Expand Down Expand Up @@ -266,8 +279,13 @@ static int fuse_fs_access_readmount(void *buf, fuse_fill_dir_t filler)
st.st_blksize = 0;
st.st_blocks = 0;

#if defined(CONFIG_FUSE_LIBRARY_V3)
filler(buf, ".", &st, 0, 0);
filler(buf, "..", NULL, 0, 0);
#else
filler(buf, ".", &st, 0);
filler(buf, "..", NULL, 0);
#endif

do {
struct op_args_readmount args;
Expand All @@ -282,7 +300,11 @@ static int fuse_fs_access_readmount(void *buf, fuse_fill_dir_t filler)
break;
}

#if defined(CONFIG_FUSE_LIBRARY_V3)
filler(buf, &mnt_name[1], &st, 0, 0);
#else
filler(buf, &mnt_name[1], &st, 0);
#endif

} while (true);

Expand All @@ -293,9 +315,16 @@ static int fuse_fs_access_readmount(void *buf, fuse_fill_dir_t filler)
return err;
}

#if defined(CONFIG_FUSE_LIBRARY_V3)
static int fuse_fs_access_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t off,
struct fuse_file_info *fi, enum fuse_readdir_flags flags)
{
NSI_ARG_UNUSED(flags);
#else
static int fuse_fs_access_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t off,
struct fuse_file_info *fi)
{
#endif
NSI_ARG_UNUSED(off);
NSI_ARG_UNUSED(fi);

Expand Down Expand Up @@ -345,8 +374,13 @@ static int fuse_fs_access_readdir(const char *path, void *buf, fuse_fill_dir_t f
st.st_blksize = 0;
st.st_blocks = 0;

#if defined(CONFIG_FUSE_LIBRARY_V3)
filler(buf, ".", &st, 0, 0);
filler(buf, "..", &st, 0, 0);
#else
filler(buf, ".", &st, 0);
filler(buf, "..", &st, 0);
#endif

do {
err = queue_op(OP_READDIR_READ_NEXT, (void *)&entry);
Expand All @@ -366,7 +400,13 @@ static int fuse_fs_access_readdir(const char *path, void *buf, fuse_fill_dir_t f
st.st_size = entry.size;
}

if (filler(buf, entry.name, &st, 0)) {
#if defined(CONFIG_FUSE_LIBRARY_V3)
bool full = filler(buf, entry.name, &st, 0, 0);
#else
bool full = filler(buf, entry.name, &st, 0);
#endif

if (full) {
break;
}
} while (1);
Expand Down Expand Up @@ -468,6 +508,7 @@ static int fuse_fs_access_write(const char *path, const char *buf, size_t size,
return -nsi_errno_from_mid(err);
}

#if !defined(CONFIG_FUSE_LIBRARY_V3)
static int fuse_fs_access_ftruncate(const char *path, off_t size, struct fuse_file_info *fi)
{
struct op_args_ftruncate args;
Expand All @@ -486,9 +527,16 @@ static int fuse_fs_access_ftruncate(const char *path, off_t size, struct fuse_fi

return -nsi_errno_from_mid(err);
}
#endif

#if defined(CONFIG_FUSE_LIBRARY_V3)
static int fuse_fs_access_truncate(const char *path, off_t size, struct fuse_file_info *fi)
{
NSI_ARG_UNUSED(fi);
#else
static int fuse_fs_access_truncate(const char *path, off_t size)
{
#endif
struct op_args_truncate args;
int err;

Expand Down Expand Up @@ -521,18 +569,35 @@ static int fuse_fs_access_statfs(const char *path, struct statvfs *buf)
return 0;
}

#if defined(CONFIG_FUSE_LIBRARY_V3)
static int fuse_fs_access_utimens(const char *path, const struct timespec tv[2],
struct fuse_file_info *fi)
{
NSI_ARG_UNUSED(fi);
#else
static int fuse_fs_access_utimens(const char *path, const struct timespec tv[2])
{
#endif
/* dummy */
NSI_ARG_UNUSED(path);
NSI_ARG_UNUSED(tv);
return 0;
}

#if defined(CONFIG_FUSE_LIBRARY_V3)
static void *fuse_fs_access_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
{
NSI_ARG_UNUSED(conn);
NSI_ARG_UNUSED(cfg);

sem_post(&fuse_started);
return NULL;
}
#endif

static struct fuse_operations fuse_fs_access_oper = {
.getattr = fuse_fs_access_getattr,
.readlink = NULL,
.getdir = NULL,
.mknod = NULL,
.mkdir = fuse_fs_access_mkdir,
.unlink = fuse_fs_access_unlink,
Expand All @@ -543,7 +608,6 @@ static struct fuse_operations fuse_fs_access_oper = {
.chmod = NULL,
.chown = NULL,
.truncate = fuse_fs_access_truncate,
.utime = NULL,
.open = fuse_fs_access_open,
.read = fuse_fs_access_read,
.write = fuse_fs_access_write,
Expand All @@ -559,19 +623,24 @@ static struct fuse_operations fuse_fs_access_oper = {
.readdir = fuse_fs_access_readdir,
.releasedir = NULL,
.fsyncdir = NULL,
.init = NULL,
#if defined(CONFIG_FUSE_LIBRARY_V3)
.init = fuse_fs_access_init,
#endif
.destroy = NULL,
.access = NULL,
.create = fuse_fs_access_create,
#if !defined(CONFIG_FUSE_LIBRARY_V3)
.ftruncate = fuse_fs_access_ftruncate,
.fgetattr = NULL,
#endif
.lock = NULL,
.utimens = fuse_fs_access_utimens,
.bmap = NULL,
#if !defined(CONFIG_FUSE_LIBRARY_V3)
.flag_nullpath_ok = 0,
.flag_nopath = 0,
.flag_utime_omit_ok = 0,
.flag_reserved = 0,
#endif
.ioctl = NULL,
.poll = NULL,
.write_buf = NULL,
Expand Down Expand Up @@ -615,15 +684,38 @@ void ffsa_init_bottom(const char *fuse_mountpoint, struct ffa_op_callbacks *op_c
nsi_print_error_and_exit("%s is not a directory\n", fuse_mountpoint);
}

err = pthread_create(&fuse_thread, NULL, ffsa_main, (void *)fuse_mountpoint);
if (err < 0) {
nsi_print_error_and_exit("Failed to create thread for fuse_fs_access_main\n");
#if defined(CONFIG_FUSE_LIBRARY_V3)
/* Fuse3's fuse_daemonize() changes the cwd to "/" which is a quite undesirable
* side-effect, so we will revert back to where we were once it has initialized
*/
char *cwd = getcwd(NULL, 0);

err = sem_init(&fuse_started, 0, 0);
if (err) {
nsi_print_error_and_exit("Failed to initialize semaphore\n");
}
#endif

err = sem_init(&op_queue.op_done, 0, 0);
if (err) {
nsi_print_error_and_exit("Failed to initialize semaphore\n");
}

err = pthread_create(&fuse_thread, NULL, ffsa_main, (void *)fuse_mountpoint);
if (err < 0) {
nsi_print_error_and_exit("Failed to create thread for ffsa_main()\n");
}

#if defined(CONFIG_FUSE_LIBRARY_V3)
if (cwd != NULL) {
sem_wait(&fuse_started);
if (chdir(cwd)) {
nsi_print_error_and_exit("Failed to change directory back to %s "
"after starting FUSE\n");
}
free(cwd);
}
#endif
}

void ffsa_cleanup_bottom(const char *fuse_mountpoint)
Expand Down