Skip to content

Commit

Permalink
Merge #19315
Browse files Browse the repository at this point in the history
19315: cpu/native: add host fs access via VFS r=benpicco a=benpicco



Co-authored-by: Benjamin Valentin <benpicco@beuth-hochschule.de>
Co-authored-by: Benjamin Valentin <benjamin.valentin@ml-pa.com>
  • Loading branch information
3 people authored Apr 25, 2023
2 parents 46af92d + 5bf83c2 commit 23f7087
Show file tree
Hide file tree
Showing 15 changed files with 424 additions and 6 deletions.
6 changes: 3 additions & 3 deletions boards/native/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ ifneq (,$(filter periph_can,$(FEATURES_USED)))
USEPKG += libsocketcan
endif

# default to using littlefs2 on the virtual flash if no other fs was selected
# default to host fs pass-through if no other fs was selected
ifneq (,$(filter vfs_default,$(USEMODULE)))
ifeq (,$(filter lwext%_vfs spiffs littlefs fatfs_vfs,$(USEMODULE)))
USEMODULE += littlefs2
ifeq (,$(filter lwext%_vfs spiffs littlefs% fatfs_vfs,$(USEMODULE)))
USEMODULE += fs_native
endif
USEMODULE += mtd
endif
Expand Down
4 changes: 4 additions & 0 deletions boards/native/board_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ VFS_AUTO_MOUNT(fatfs, VFS_MTD(mtd0_dev), VFS_DEFAULT_NVM(0), 0);
#elif defined(MODULE_LWEXT4)
VFS_AUTO_MOUNT(lwext4, VFS_MTD(mtd0_dev), VFS_DEFAULT_NVM(0), 0);

/* host fs pass-through */
#elif defined(MODULE_FS_NATIVE)
VFS_AUTO_MOUNT(native, { .hostpath = FS_NATIVE_DIR }, VFS_DEFAULT_NVM(0), 0);

#endif
#endif /* MODULE_VFS_DEFAULT */

Expand Down
9 changes: 9 additions & 0 deletions boards/native/include/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ void _native_LED_RED_TOGGLE(void);
extern mtd_dev_t *mtd0;
#endif

/**
* @name Host FS access configuration
* @{
*/
#ifndef FS_NATIVE_DIR
#define FS_NATIVE_DIR "native" /**< Folder on the host fs exported to RIOT */
#endif
/** @} */

#if defined(MODULE_SPIFFS) || DOXYGEN
/**
* @name SPIFFS default configuration
Expand Down
4 changes: 4 additions & 0 deletions cpu/native/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ ifneq (,$(filter mtd_native,$(USEMODULE)))
DIRS += mtd
endif

ifneq (,$(filter fs_native,$(USEMODULE)))
DIRS += fs
endif

ifneq (,$(filter backtrace,$(USEMODULE)))
DIRS += backtrace
endif
Expand Down
3 changes: 3 additions & 0 deletions cpu/native/fs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MODULE := fs_native

include $(RIOTBASE)/Makefile.base
291 changes: 291 additions & 0 deletions cpu/native/fs/native_fs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
/*
* Copyright (C) 2023 ML!PA Consulting GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup sys_fs_native
* @{
*
* @file
* @brief native integration with vfs
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*
* @}
*/

#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

#include "mutex.h"
#include "native_internal.h"
#include "fs/native_fs.h"
#include "vfs.h"

#define ENABLE_DEBUG 0
#include <debug.h>

/**
* @brief Assign each native instance a sub-sirectory based on `_native_id`
*/
#ifndef CONFIG_NATIVE_ISOLATE_FS
#define CONFIG_NATIVE_ISOLATE_FS 0
#endif

/* Not using static inline functions here because they are also assigned to. */
#define FD(filep) filp->private_data.value
#define DIRP(dirp) dirp->private_data.ptr

/* Reentrancy guard required by the various static locals of the implementation */
static mutex_t _lock;

static void _do_prefix(vfs_mount_t *mountp, const char *name, char *buffer, size_t len)
{
const native_desc_t *fs_desc = mountp->private_data;
size_t res;

assert(len > strlen(fs_desc->hostpath));

if (CONFIG_NATIVE_ISOLATE_FS) {
res = snprintf(buffer, len, "%s/%u%s", fs_desc->hostpath, _native_id, name);
} else {
res = snprintf(buffer, len, "%s%s", fs_desc->hostpath, name);
}

#ifdef NDEBUG
if (res > len) {
puts("fs_native: path larger than PATH_MAX");
exit(ENOBUFS);
}
#else
assert(res <= len);
#endif
}

static char *_prefix_path(vfs_mount_t *mountp, const char *name)
{
static char buffer[PATH_MAX];

_do_prefix(mountp, name, buffer, sizeof(buffer));

return buffer;
}

static int _mount(vfs_mount_t *mountp)
{
int res;
mutex_lock(&_lock);

/* create common root dir first */
if (CONFIG_NATIVE_ISOLATE_FS) {
char *parent = _prefix_path(mountp, "");
/* remove node specific suffix */
char *end = strrchr(parent, '/');
*end = '\0';

/* Ignoring errors: they're caught by the subsequent real_mkdir */
real_mkdir(parent, 0777);
}

real_mkdir(_prefix_path(mountp, ""), 0777);
res = errno == EEXIST ? 0 : -errno;

mutex_unlock(&_lock);
return res;
}

static int _unmount(vfs_mount_t *mountp)
{
mutex_lock(&_lock);

/* Ignoring errors: directories with any content are left in place. */
real_rmdir(_prefix_path(mountp, ""));

mutex_unlock(&_lock);
return 0;
}

static int _mkdir(vfs_mount_t *mountp, const char *name, mode_t mode)
{
int res = 0;
mutex_lock(&_lock);

if (real_mkdir(_prefix_path(mountp, name), mode) < 0) {
res = -errno;
}

mutex_unlock(&_lock);
return res;
}

static int _rmdir(vfs_mount_t *mountp, const char *name)
{
int res = 0;
mutex_lock(&_lock);

if (real_rmdir(_prefix_path(mountp, name)) < 0) {
res = -errno;
}

mutex_unlock(&_lock);
return res;
}

static int _statvfs(vfs_mount_t *mountp, const char *restrict path, struct statvfs *restrict buf)
{
int res = 0;
mutex_lock(&_lock);

if (real_statvfs(_prefix_path(mountp, path), buf) < 0) {
res = -errno;
}

mutex_unlock(&_lock);
return res;
}

static int _open(vfs_file_t *filp, const char *name, int flags, mode_t mode)
{
int res = 0;
mutex_lock(&_lock);

if ((FD(filep) = real_open(_prefix_path(filp->mp, name), flags, mode)) < 0) {
res = -errno;
}

mutex_unlock(&_lock);
return res;
}

static ssize_t _read(vfs_file_t *filp, void *dest, size_t nbytes)
{
return real_read(FD(filep), dest, nbytes);
}

static ssize_t _write(vfs_file_t *filp, const void *src, size_t nbytes)
{
return real_write(FD(filep), src, nbytes);
}

static off_t _lseek(vfs_file_t *filp, off_t off, int whence)
{
return real_lseek(FD(filep), off, whence);
}

static int _fstat(vfs_file_t *filp, struct stat *buf)
{
return real_fstat(FD(filep), buf);
}

static int _fsync(vfs_file_t *filp)
{
return real_fsync(FD(filep));
}

static int _close(vfs_file_t *filp)
{
return real_close(FD(filep));
}

static int _unlink(vfs_mount_t *mountp, const char *name)
{
int res = 0;
mutex_lock(&_lock);

if (real_unlink(_prefix_path(mountp, name)) < 0) {
res = -errno;
}

mutex_unlock(&_lock);
return res;
}

static int _rename(vfs_mount_t *mountp, const char *from_path, const char *to_path)
{
static char path_a[PATH_MAX];
static char path_b[PATH_MAX];

int res = 0;
mutex_lock(&_lock);

_do_prefix(mountp, from_path, path_a, sizeof(path_a));
_do_prefix(mountp, to_path, path_b, sizeof(path_b));

if (real_rename(path_a, path_b) < 0) {
res = -errno;
}

mutex_unlock(&_lock);
return res;
}

static int _opendir(vfs_DIR *dirp, const char *dirname)
{
int res = 0;
mutex_lock(&_lock);

if ((DIRP(dirp) = real_opendir(_prefix_path(dirp->mp, dirname))) == NULL) {
res = -errno;
}

mutex_unlock(&_lock);
return res;
}

static int _readdir(vfs_DIR *dirp, vfs_dirent_t *entry)
{
struct dirent *dirent = real_readdir(DIRP(dirp));

if (dirent == NULL) {
return 0;
}

entry->d_ino = dirent->d_ino;
strncpy(entry->d_name, (char *)dirent->d_name, sizeof(entry->d_name));

return 1;
}

static int _closedir(vfs_DIR *dirp)
{
return real_closedir(DIRP(dirp));
}

static const vfs_file_system_ops_t native_fs_ops = {
.mount = _mount,
.umount = _unmount,
.unlink = _unlink,
.mkdir = _mkdir,
.rmdir = _rmdir,
.rename = _rename,
.stat = vfs_sysop_stat_from_fstat,
.statvfs = _statvfs,
};

static const vfs_file_ops_t native_file_ops = {
.open = _open,
.close = _close,
.read = _read,
.write = _write,
.lseek = _lseek,
.fstat = _fstat,
.fsync = _fsync,
};

static const vfs_dir_ops_t native_dir_ops = {
.opendir = _opendir,
.readdir = _readdir,
.closedir = _closedir,
};

const vfs_file_system_t native_file_system = {
.fs_op = &native_fs_ops,
.f_op = &native_file_ops,
.d_op = &native_dir_ops,
};
12 changes: 12 additions & 0 deletions cpu/native/include/native_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@
#include <time.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/uio.h>
#include <dirent.h>

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -90,6 +92,10 @@ void _native_init_syscalls(void);
*/
extern ssize_t (*real_read)(int fd, void *buf, size_t count);
extern ssize_t (*real_write)(int fd, const void *buf, size_t count);
extern off_t (*real_lseek)(int fd, off_t offset, int whence);
extern off_t (*real_fstat)(int fd, struct stat *statbuf);
extern int (*real_statvfs)(const char *restrict path, struct statvfs *restrict buf);
extern int (*real_fsync)(int fd);
extern size_t (*real_fread)(void *ptr, size_t size, size_t nmemb, FILE *stream);
extern void (*real_clearerr)(FILE *stream);
extern __attribute__((noreturn)) void (*real_exit)(int status);
Expand Down Expand Up @@ -124,6 +130,11 @@ extern int (*real_gettimeofday)(struct timeval *t, ...);
extern int (*real_ioctl)(int fildes, int request, ...);
extern int (*real_listen)(int socket, int backlog);
extern int (*real_open)(const char *path, int oflag, ...);
extern int (*real_mkdir)(const char *pathname, mode_t mode);
extern int (*real_rmdir)(const char *pathname);
extern DIR *(*real_opendir)(const char *name);
extern struct dirent *(*real_readdir)(DIR *dirp);
extern int (*real_closedir)(DIR *dirp);
extern int (*real_pause)(void);
extern int (*real_pipe)(int[2]);
/* The ... is a hack to save includes: */
Expand All @@ -136,6 +147,7 @@ extern int (*real_setsockopt)(int socket, ...);
extern int (*real_socket)(int domain, int type, int protocol);
extern int (*real_printf)(const char *format, ...);
extern int (*real_unlink)(const char *);
extern int (*real_rename)(const char *, const char *);
extern long int (*real_random)(void);
extern const char* (*real_gai_strerror)(int errcode);
extern FILE* (*real_fopen)(const char *path, const char *mode);
Expand Down
Loading

0 comments on commit 23f7087

Please sign in to comment.