fs: add fuse primitives
This commit adds fuse structures, requests and functions to fill them Signed-off-by: Jakub Michalski <jmichalski@antmicro.com>
This commit is contained in:
committed by
Anas Nashif
parent
7e9d994aa3
commit
b28483a3fe
@@ -108,6 +108,15 @@ Python Devicetree library test files
|
||||
|
||||
* Various yaml files under ``scripts/dts/python-devicetree/tests``
|
||||
|
||||
FUSE Interface Definition Header File
|
||||
--------------------------------------
|
||||
|
||||
* *Licensing:* `BSD-2-clause`_
|
||||
* *Impact:* This header is used in Zephyr build only if :kconfig:option:`CONFIG_FUSE_CLIENT` is enabled.
|
||||
* *Files*:
|
||||
|
||||
* :zephyr_file:`subsys/fs/fuse_client/fuse_abi.h`
|
||||
|
||||
.. _Apache 2.0 License:
|
||||
https://github.com/zephyrproject-rtos/zephyr/blob/main/LICENSE
|
||||
|
||||
@@ -120,6 +129,9 @@ Python Devicetree library test files
|
||||
.. _BSD-3-clause:
|
||||
https://opensource.org/license/bsd-3-clause
|
||||
|
||||
.. _BSD-2-clause:
|
||||
https://opensource.org/license/bsd-2-clause
|
||||
|
||||
.. _Coccinelle:
|
||||
https://coccinelle.gitlabpages.inria.fr/website/
|
||||
|
||||
|
||||
@@ -17,12 +17,14 @@ if(CONFIG_FILE_SYSTEM_LIB_LINK)
|
||||
endif()
|
||||
|
||||
add_subdirectory_ifdef(CONFIG_FILE_SYSTEM_EXT2 ext2)
|
||||
add_subdirectory_ifdef(CONFIG_FUSE_CLIENT fuse_client)
|
||||
|
||||
zephyr_library_link_libraries(FS)
|
||||
|
||||
target_link_libraries_ifdef(CONFIG_FAT_FILESYSTEM_ELM FS INTERFACE ELMFAT)
|
||||
target_link_libraries_ifdef(CONFIG_FILE_SYSTEM_LITTLEFS FS INTERFACE LITTLEFS)
|
||||
target_link_libraries_ifdef(CONFIG_FILE_SYSTEM_EXT2 FS INTERFACE EXT2)
|
||||
target_link_libraries_ifdef(CONFIG_FUSE_CLIENT FS INTERFACE FUSE_CLIENT)
|
||||
endif()
|
||||
|
||||
add_subdirectory_ifdef(CONFIG_FCB ./fcb)
|
||||
|
||||
@@ -119,6 +119,7 @@ source "subsys/logging/Kconfig.template.log_config"
|
||||
rsource "Kconfig.fatfs"
|
||||
rsource "Kconfig.littlefs"
|
||||
rsource "ext2/Kconfig"
|
||||
rsource "fuse_client/Kconfig"
|
||||
|
||||
endif # FILE_SYSTEM_LIB_LINK
|
||||
|
||||
|
||||
14
subsys/fs/fuse_client/CMakeLists.txt
Normal file
14
subsys/fs/fuse_client/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2025 Antmicro <www.antmicro.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# This library provides a set of functions for creating FUSE structures
|
||||
|
||||
add_library(FUSE_CLIENT INTERFACE)
|
||||
target_include_directories(FUSE_CLIENT INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
zephyr_library()
|
||||
zephyr_library_sources(
|
||||
fuse_client.c
|
||||
)
|
||||
|
||||
zephyr_library_link_libraries(FUSE_CLIENT)
|
||||
32
subsys/fs/fuse_client/Kconfig
Normal file
32
subsys/fs/fuse_client/Kconfig
Normal file
@@ -0,0 +1,32 @@
|
||||
# Copyright (c) 2025 Antmicro <www.antmicro.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config FUSE_CLIENT
|
||||
bool "FUSE client-side primitives support"
|
||||
help
|
||||
Enable FUSE client-side primitives support.
|
||||
|
||||
config FUSE_CLIENT_UID_VALUE
|
||||
int "FUSE user ID"
|
||||
default 0
|
||||
help
|
||||
Each FUSE request contains user ID, this config allows setting
|
||||
that value. The result is as if user with given UID accessed the file/resource.
|
||||
|
||||
config FUSE_CLIENT_GID_VALUE
|
||||
int "FUSE group ID"
|
||||
default 0
|
||||
help
|
||||
Each FUSE request contains group ID, this config allows setting
|
||||
that value. The result is as if user with given GID accessed the file/resource.
|
||||
|
||||
config FUSE_CLIENT_PID_VALUE
|
||||
int "FUSE process ID"
|
||||
default 0
|
||||
help
|
||||
Each FUSE request contains process ID, this config allows setting
|
||||
that value. The result is as if process with given PID accessed the file/resource.
|
||||
|
||||
module = FUSE_CLIENT
|
||||
module-str = fuse
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
273
subsys/fs/fuse_client/fuse_abi.h
Normal file
273
subsys/fs/fuse_client/fuse_abi.h
Normal file
@@ -0,0 +1,273 @@
|
||||
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */
|
||||
|
||||
/*
|
||||
* This file is based on include/uapi/linux/fuse.h from Linux, and is used
|
||||
* under the BSD-2-Clause license, as per the dual-license option
|
||||
*/
|
||||
/*
|
||||
* This file defines the kernel interface of FUSE
|
||||
* This -- and only this -- header file may also be distributed under
|
||||
* the terms of the BSD Licence as follows:
|
||||
*
|
||||
* Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_SUBSYS_FS_FUSE_ABI_H_
|
||||
#define ZEPHYR_SUBSYS_FS_FUSE_ABI_H_
|
||||
#include <stdint.h>
|
||||
|
||||
#define FUSE_MAJOR_VERSION 7
|
||||
#define FUSE_MINOR_VERSION 31
|
||||
|
||||
#define FUSE_LOOKUP 1
|
||||
#define FUSE_FORGET 2
|
||||
#define FUSE_SETATTR 4
|
||||
#define FUSE_MKDIR 9
|
||||
#define FUSE_UNLINK 10
|
||||
#define FUSE_RMDIR 11
|
||||
#define FUSE_RENAME 12
|
||||
#define FUSE_OPEN 14
|
||||
#define FUSE_READ 15
|
||||
#define FUSE_WRITE 16
|
||||
#define FUSE_STATFS 17
|
||||
#define FUSE_RELEASE 18
|
||||
#define FUSE_FSYNC 20
|
||||
#define FUSE_INIT 26
|
||||
#define FUSE_OPENDIR 27
|
||||
#define FUSE_READDIR 28
|
||||
#define FUSE_RELEASEDIR 29
|
||||
#define FUSE_CREATE 35
|
||||
#define FUSE_DESTROY 38
|
||||
#define FUSE_LSEEK 46
|
||||
|
||||
#define FUSE_ROOT_INODE 1
|
||||
|
||||
struct fuse_in_header {
|
||||
uint32_t len;
|
||||
uint32_t opcode;
|
||||
uint64_t unique;
|
||||
uint64_t nodeid;
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
uint32_t pid;
|
||||
uint16_t total_extlen;
|
||||
uint16_t padding;
|
||||
};
|
||||
|
||||
struct fuse_out_header {
|
||||
uint32_t len;
|
||||
int32_t error;
|
||||
uint64_t unique;
|
||||
};
|
||||
|
||||
struct fuse_init_in {
|
||||
uint32_t major;
|
||||
uint32_t minor;
|
||||
uint32_t max_readahead;
|
||||
uint32_t flags;
|
||||
uint32_t flags2;
|
||||
uint32_t unused[11];
|
||||
};
|
||||
|
||||
struct fuse_init_out {
|
||||
uint32_t major;
|
||||
uint32_t minor;
|
||||
uint32_t max_readahead;
|
||||
uint32_t flags;
|
||||
uint16_t max_background;
|
||||
uint16_t congestion_threshold;
|
||||
uint32_t max_write;
|
||||
uint32_t time_gran;
|
||||
uint16_t max_pages;
|
||||
uint16_t map_alignment;
|
||||
uint32_t flags2;
|
||||
uint32_t max_stack_depth;
|
||||
uint32_t unused[6];
|
||||
};
|
||||
|
||||
struct fuse_open_in {
|
||||
uint32_t flags;
|
||||
uint32_t open_flags;
|
||||
};
|
||||
|
||||
struct fuse_open_out {
|
||||
uint64_t fh;
|
||||
uint32_t open_flags;
|
||||
int32_t backing_id;
|
||||
};
|
||||
|
||||
struct fuse_attr {
|
||||
uint64_t ino;
|
||||
uint64_t size;
|
||||
uint64_t blocks;
|
||||
uint64_t atime;
|
||||
uint64_t mtime;
|
||||
uint64_t ctime;
|
||||
uint32_t atimensec;
|
||||
uint32_t mtimensec;
|
||||
uint32_t ctimensec;
|
||||
uint32_t mode;
|
||||
uint32_t nlink;
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
uint32_t rdev;
|
||||
uint32_t blksize;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct fuse_entry_out {
|
||||
uint64_t nodeid;
|
||||
uint64_t generation;
|
||||
uint64_t entry_valid;
|
||||
uint64_t attr_valid;
|
||||
uint32_t entry_valid_nsec;
|
||||
uint32_t attr_valid_nsec;
|
||||
struct fuse_attr attr;
|
||||
};
|
||||
|
||||
struct fuse_read_in {
|
||||
uint64_t fh;
|
||||
uint64_t offset;
|
||||
uint32_t size;
|
||||
uint32_t read_flags;
|
||||
uint64_t lock_owner;
|
||||
uint32_t flags;
|
||||
uint32_t padding;
|
||||
};
|
||||
|
||||
struct fuse_release_in {
|
||||
uint64_t fh;
|
||||
uint32_t flags;
|
||||
uint32_t release_flags;
|
||||
uint64_t lock_owner;
|
||||
};
|
||||
|
||||
struct fuse_create_in {
|
||||
uint32_t flags;
|
||||
uint32_t mode;
|
||||
uint32_t umask;
|
||||
uint32_t open_flags;
|
||||
};
|
||||
|
||||
struct fuse_create_out {
|
||||
struct fuse_entry_out entry_out;
|
||||
struct fuse_open_out open_out;
|
||||
};
|
||||
|
||||
struct fuse_write_in {
|
||||
uint64_t fh;
|
||||
uint64_t offset;
|
||||
uint32_t size;
|
||||
uint32_t write_flags;
|
||||
uint64_t lock_owner;
|
||||
uint32_t flags;
|
||||
uint32_t padding;
|
||||
};
|
||||
|
||||
struct fuse_write_out {
|
||||
uint32_t size;
|
||||
uint32_t padding;
|
||||
};
|
||||
|
||||
struct fuse_lseek_in {
|
||||
uint64_t fh;
|
||||
uint64_t offset;
|
||||
uint32_t whence;
|
||||
uint32_t padding;
|
||||
};
|
||||
|
||||
struct fuse_lseek_out {
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
/* mask used to set file size, used in fuse_setattr_in::valid */
|
||||
#define FATTR_SIZE (1 << 3)
|
||||
|
||||
struct fuse_setattr_in {
|
||||
uint32_t valid;
|
||||
uint32_t padding;
|
||||
uint64_t fh;
|
||||
uint64_t size;
|
||||
uint64_t lock_owner;
|
||||
uint64_t atime;
|
||||
uint64_t mtime;
|
||||
uint64_t ctime;
|
||||
uint32_t atimensec;
|
||||
uint32_t mtimensec;
|
||||
uint32_t ctimensec;
|
||||
uint32_t mode;
|
||||
uint32_t unused4;
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
uint32_t unused5;
|
||||
};
|
||||
|
||||
struct fuse_attr_out {
|
||||
uint64_t attr_valid;
|
||||
uint32_t attr_valid_nsec;
|
||||
uint32_t dummy;
|
||||
struct fuse_attr attr;
|
||||
};
|
||||
|
||||
struct fuse_fsync_in {
|
||||
uint64_t fh;
|
||||
uint32_t fsync_flags;
|
||||
uint32_t padding;
|
||||
};
|
||||
|
||||
struct fuse_mkdir_in {
|
||||
uint32_t mode;
|
||||
uint32_t umask;
|
||||
};
|
||||
|
||||
struct fuse_rename_in {
|
||||
uint64_t newdir;
|
||||
};
|
||||
|
||||
struct fuse_kstatfs {
|
||||
uint64_t blocks;
|
||||
uint64_t bfree;
|
||||
uint64_t bavail;
|
||||
uint64_t files;
|
||||
uint64_t ffree;
|
||||
uint32_t bsize;
|
||||
uint32_t namelen;
|
||||
uint32_t frsize;
|
||||
uint32_t padding;
|
||||
uint32_t spare[6];
|
||||
};
|
||||
|
||||
struct fuse_dirent {
|
||||
uint64_t ino;
|
||||
uint64_t off;
|
||||
uint32_t namelen;
|
||||
uint32_t type;
|
||||
char name[];
|
||||
};
|
||||
|
||||
struct fuse_forget_in {
|
||||
uint64_t nlookup;
|
||||
};
|
||||
|
||||
#endif /* ZEPHYR_SUBSYS_FS_FUSE_ABI_H_ */
|
||||
429
subsys/fs/fuse_client/fuse_client.c
Normal file
429
subsys/fs/fuse_client/fuse_client.c
Normal file
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Antmicro <www.antmicro.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <fuse_client.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
LOG_MODULE_REGISTER(fuse, CONFIG_FUSE_CLIENT_LOG_LEVEL);
|
||||
|
||||
static uint64_t unique = 1; /* with unique==0 older virtiofsd asserts, so we are starting from 1 */
|
||||
|
||||
static uint64_t fuse_get_unique(void)
|
||||
{
|
||||
return unique++;
|
||||
}
|
||||
|
||||
void fuse_fill_header(struct fuse_in_header *hdr, uint32_t len, uint32_t opcode, uint64_t nodeid)
|
||||
{
|
||||
hdr->len = len;
|
||||
hdr->opcode = opcode;
|
||||
hdr->unique = fuse_get_unique();
|
||||
hdr->nodeid = nodeid;
|
||||
hdr->uid = CONFIG_FUSE_CLIENT_UID_VALUE;
|
||||
hdr->gid = CONFIG_FUSE_CLIENT_GID_VALUE;
|
||||
hdr->pid = CONFIG_FUSE_CLIENT_PID_VALUE;
|
||||
hdr->total_extlen = 0;
|
||||
}
|
||||
|
||||
void fuse_create_init_req(struct fuse_init_req *req)
|
||||
{
|
||||
fuse_fill_header(
|
||||
&req->in_header, sizeof(struct fuse_in_header) + sizeof(struct fuse_init_in),
|
||||
FUSE_INIT, 0
|
||||
);
|
||||
req->init_in.major = FUSE_MAJOR_VERSION;
|
||||
req->init_in.minor = FUSE_MINOR_VERSION;
|
||||
req->init_in.max_readahead = 0;
|
||||
req->init_in.flags = 0;
|
||||
req->init_in.flags2 = 0;
|
||||
}
|
||||
|
||||
void fuse_create_open_req(
|
||||
struct fuse_open_req *req, uint64_t inode, uint32_t flags, enum fuse_object_type type)
|
||||
{
|
||||
fuse_fill_header(
|
||||
&req->in_header, sizeof(struct fuse_in_header) + sizeof(struct fuse_open_in),
|
||||
type == FUSE_DIR ? FUSE_OPENDIR : FUSE_OPEN, inode
|
||||
);
|
||||
req->open_in.flags = flags;
|
||||
req->open_in.open_flags = 0;
|
||||
}
|
||||
|
||||
void fuse_create_lookup_req(struct fuse_lookup_req *req, uint64_t inode, uint32_t fname_len)
|
||||
{
|
||||
fuse_fill_header(
|
||||
&req->in_header, sizeof(struct fuse_in_header) + fname_len, FUSE_LOOKUP,
|
||||
inode
|
||||
);
|
||||
}
|
||||
|
||||
void fuse_create_read_req(
|
||||
struct fuse_read_req *req, uint64_t inode, uint64_t fh, uint64_t offset, uint32_t size,
|
||||
enum fuse_object_type type)
|
||||
{
|
||||
fuse_fill_header(
|
||||
&req->in_header, sizeof(struct fuse_in_header) + sizeof(struct fuse_read_in),
|
||||
type == FUSE_FILE ? FUSE_READ : FUSE_READDIR, inode
|
||||
);
|
||||
req->read_in.fh = fh;
|
||||
req->read_in.offset = offset;
|
||||
req->read_in.size = size;
|
||||
req->read_in.read_flags = 0;
|
||||
req->read_in.lock_owner = 0;
|
||||
req->read_in.flags = 0;
|
||||
}
|
||||
|
||||
void fuse_create_release_req(struct fuse_release_req *req, uint64_t inode, uint64_t fh,
|
||||
enum fuse_object_type type)
|
||||
{
|
||||
fuse_fill_header(
|
||||
&req->in_header, sizeof(struct fuse_in_header) + sizeof(struct fuse_release_in),
|
||||
type == FUSE_DIR ? FUSE_RELEASEDIR : FUSE_RELEASE, inode
|
||||
);
|
||||
req->release_in.fh = fh;
|
||||
req->release_in.flags = 0;
|
||||
req->release_in.release_flags = 0;
|
||||
req->release_in.lock_owner = 0;
|
||||
}
|
||||
|
||||
void fuse_create_destroy_req(struct fuse_destroy_req *req)
|
||||
{
|
||||
fuse_fill_header(&req->in_header, sizeof(struct fuse_in_header), FUSE_DESTROY, 0);
|
||||
}
|
||||
|
||||
void fuse_create_create_req(
|
||||
struct fuse_create_req *req, uint64_t inode, uint32_t fname_len, uint32_t flags,
|
||||
uint32_t mode)
|
||||
{
|
||||
fuse_fill_header(
|
||||
&req->in_header, sizeof(req->in_header) + sizeof(req->create_in) + fname_len,
|
||||
FUSE_CREATE, inode
|
||||
);
|
||||
req->create_in.flags = flags;
|
||||
req->create_in.mode = mode;
|
||||
req->create_in.open_flags = 0;
|
||||
req->create_in.umask = 0;
|
||||
}
|
||||
|
||||
void fuse_create_write_req(
|
||||
struct fuse_write_req *req, uint64_t inode, uint64_t fh, uint64_t offset, uint32_t size)
|
||||
{
|
||||
fuse_fill_header(
|
||||
&req->in_header, sizeof(req->in_header) + sizeof(req->write_in) + size, FUSE_WRITE,
|
||||
inode
|
||||
);
|
||||
req->write_in.fh = fh;
|
||||
req->write_in.offset = offset;
|
||||
req->write_in.size = size;
|
||||
req->write_in.write_flags = 0;
|
||||
req->write_in.lock_owner = 0;
|
||||
req->write_in.flags = 0;
|
||||
}
|
||||
|
||||
void fuse_create_lseek_req(
|
||||
struct fuse_lseek_req *req, uint64_t inode, uint64_t fh, uint64_t offset, uint32_t whence)
|
||||
{
|
||||
fuse_fill_header(
|
||||
&req->in_header, sizeof(req->in_header) + sizeof(req->lseek_in), FUSE_LSEEK, inode
|
||||
);
|
||||
req->lseek_in.fh = fh;
|
||||
req->lseek_in.offset = offset;
|
||||
req->lseek_in.whence = whence;
|
||||
}
|
||||
|
||||
void fuse_create_setattr_req(struct fuse_setattr_req *req, uint64_t inode)
|
||||
{
|
||||
fuse_fill_header(
|
||||
&req->in_header, sizeof(req->in_header) + sizeof(struct fuse_setattr_in),
|
||||
FUSE_SETATTR, inode
|
||||
);
|
||||
}
|
||||
|
||||
void fuse_create_fsync_req(struct fuse_fsync_req *req, uint64_t inode, uint64_t fh)
|
||||
{
|
||||
fuse_fill_header(
|
||||
&req->in_header, sizeof(req->in_header) + sizeof(req->fsync_in), FUSE_FSYNC,
|
||||
inode
|
||||
);
|
||||
req->fsync_in.fh = fh;
|
||||
req->fsync_in.fsync_flags = 0;
|
||||
}
|
||||
|
||||
void fuse_create_mkdir_req(
|
||||
struct fuse_mkdir_req *req, uint64_t inode, uint32_t dirname_len, uint32_t mode)
|
||||
{
|
||||
fuse_fill_header(
|
||||
&req->in_header, sizeof(req->in_header) + sizeof(req->mkdir_in) + dirname_len,
|
||||
FUSE_MKDIR, inode
|
||||
);
|
||||
|
||||
req->mkdir_in.mode = mode;
|
||||
req->mkdir_in.umask = 0;
|
||||
}
|
||||
|
||||
void fuse_create_unlink_req(
|
||||
struct fuse_unlink_req *req, uint32_t fname_len, enum fuse_object_type type)
|
||||
{
|
||||
fuse_fill_header(
|
||||
&req->in_header, sizeof(req->in_header) + fname_len,
|
||||
type == FUSE_DIR ? FUSE_RMDIR : FUSE_UNLINK, FUSE_ROOT_INODE
|
||||
);
|
||||
}
|
||||
|
||||
void fuse_create_rename_req(
|
||||
struct fuse_rename_req *req, uint64_t old_dir_nodeid, uint32_t old_len,
|
||||
uint64_t new_dir_nodeid, uint32_t new_len)
|
||||
{
|
||||
fuse_fill_header(
|
||||
&req->in_header,
|
||||
sizeof(req->in_header) + sizeof(req->rename_in) + old_len + new_len,
|
||||
FUSE_RENAME, old_dir_nodeid
|
||||
);
|
||||
req->rename_in.newdir = new_dir_nodeid;
|
||||
}
|
||||
|
||||
const char *fuse_opcode_to_string(uint32_t opcode)
|
||||
{
|
||||
switch (opcode) {
|
||||
case FUSE_LOOKUP:
|
||||
return "FUSE_LOOKUP";
|
||||
case FUSE_FORGET:
|
||||
return "FUSE_FORGET";
|
||||
case FUSE_SETATTR:
|
||||
return "FUSE_SETATTR";
|
||||
case FUSE_MKDIR:
|
||||
return "FUSE_MKDIR";
|
||||
case FUSE_UNLINK:
|
||||
return "FUSE_UNLINK";
|
||||
case FUSE_RMDIR:
|
||||
return "FUSE_RMDIR";
|
||||
case FUSE_RENAME:
|
||||
return "FUSE_RENAME";
|
||||
case FUSE_OPEN:
|
||||
return "FUSE_OPEN";
|
||||
case FUSE_READ:
|
||||
return "FUSE_READ";
|
||||
case FUSE_WRITE:
|
||||
return "FUSE_WRITE";
|
||||
case FUSE_STATFS:
|
||||
return "FUSE_STATFS";
|
||||
case FUSE_RELEASE:
|
||||
return "FUSE_RELEASE";
|
||||
case FUSE_FSYNC:
|
||||
return "FUSE_FSYNC";
|
||||
case FUSE_INIT:
|
||||
return "FUSE_INIT";
|
||||
case FUSE_OPENDIR:
|
||||
return "FUSE_OPENDIR";
|
||||
case FUSE_READDIR:
|
||||
return "FUSE_READDIR";
|
||||
case FUSE_RELEASEDIR:
|
||||
return "FUSE_RELEASEDIR";
|
||||
case FUSE_CREATE:
|
||||
return "FUSE_CREATE";
|
||||
case FUSE_DESTROY:
|
||||
return "FUSE_DESTROY";
|
||||
case FUSE_LSEEK:
|
||||
return "FUSE_LSEEK";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void fuse_dump_init_req_out(struct fuse_init_req *req)
|
||||
{
|
||||
LOG_INF(
|
||||
"FUSE_INIT response:\n"
|
||||
"major=%" PRIu32 "\n"
|
||||
"minor=%" PRIu32 "\n"
|
||||
"max_readahead=%" PRIu32 "\n"
|
||||
"flags=%" PRIu32 "\n"
|
||||
"max_background=%" PRIu16 "\n"
|
||||
"congestion_threshold=%" PRIu16 "\n"
|
||||
"max_write=%" PRIu32 "\n"
|
||||
"time_gran=%" PRIu32 "\n"
|
||||
"max_pages=%" PRIu16 "\n"
|
||||
"map_alignment=%" PRIu16 "\n"
|
||||
"flags2=%" PRIu32 "\n"
|
||||
"max_stack_depth=%" PRIu32,
|
||||
req->init_out.major,
|
||||
req->init_out.minor,
|
||||
req->init_out.max_readahead,
|
||||
req->init_out.flags,
|
||||
req->init_out.max_background,
|
||||
req->init_out.congestion_threshold,
|
||||
req->init_out.max_write,
|
||||
req->init_out.time_gran,
|
||||
req->init_out.max_pages,
|
||||
req->init_out.map_alignment,
|
||||
req->init_out.flags2,
|
||||
req->init_out.max_stack_depth
|
||||
);
|
||||
}
|
||||
|
||||
void fuse_dump_entry_out(struct fuse_entry_out *eo)
|
||||
{
|
||||
LOG_INF(
|
||||
"FUSE LOOKUP response:\n"
|
||||
"nodeid=%" PRIu64 "\n"
|
||||
"generation=%" PRIu64 "\n"
|
||||
"entry_valid=%" PRIu64 "\n"
|
||||
"attr_valid=%" PRIu64 "\n"
|
||||
"entry_valid_nsec=%" PRIu32 "\n"
|
||||
"attr_valid_nsec=%" PRIu32 "\n"
|
||||
"attr.ino=%" PRIu64 "\n"
|
||||
"attr.size=%" PRIu64 "\n"
|
||||
"attr.blocks=%" PRIu64 "\n"
|
||||
"attr.atime=%" PRIu64 "\n"
|
||||
"attr.mtime=%" PRIu64 "\n"
|
||||
"attr.ctime=%" PRIu64 "\n"
|
||||
"attr.atimensec=%" PRIu32 "\n"
|
||||
"attr.mtimensec=%" PRIu32 "\n"
|
||||
"attr.ctimensec=%" PRIu32 "\n"
|
||||
"attr.mode=%" PRIu32 "\n"
|
||||
"attr.nlink=%" PRIu32 "\n"
|
||||
"attr.uid=%" PRIu32 "\n"
|
||||
"attr.gid=%" PRIu32 "\n"
|
||||
"attr.rdev=%" PRIu32 "\n"
|
||||
"attr.blksize=%" PRIu32 "\n"
|
||||
"attr.flags=%" PRIu32,
|
||||
eo->nodeid,
|
||||
eo->generation,
|
||||
eo->entry_valid,
|
||||
eo->attr_valid,
|
||||
eo->entry_valid_nsec,
|
||||
eo->attr_valid_nsec,
|
||||
eo->attr.ino,
|
||||
eo->attr.size,
|
||||
eo->attr.blocks,
|
||||
eo->attr.atime,
|
||||
eo->attr.mtime,
|
||||
eo->attr.ctime,
|
||||
eo->attr.atimensec,
|
||||
eo->attr.mtimensec,
|
||||
eo->attr.ctimensec,
|
||||
eo->attr.mode,
|
||||
eo->attr.nlink,
|
||||
eo->attr.uid,
|
||||
eo->attr.gid,
|
||||
eo->attr.rdev,
|
||||
eo->attr.blksize,
|
||||
eo->attr.flags
|
||||
);
|
||||
}
|
||||
|
||||
void fuse_dump_open_req_out(struct fuse_open_req *req)
|
||||
{
|
||||
LOG_INF(
|
||||
"FUSE OPEN response:\n"
|
||||
"fh=%" PRIu64 "\n"
|
||||
"open_flags=%" PRIu32 "\n"
|
||||
"backing_id=%" PRIi32,
|
||||
req->open_out.fh,
|
||||
req->open_out.open_flags,
|
||||
req->open_out.backing_id
|
||||
);
|
||||
}
|
||||
|
||||
void fuse_dump_create_req_out(struct fuse_create_out *req)
|
||||
{
|
||||
LOG_INF(
|
||||
"FUSE CREATE response:\n"
|
||||
"nodeid=%" PRIu64 "\n"
|
||||
"generation=%" PRIu64 "\n"
|
||||
"entry_valid=%" PRIu64 "\n"
|
||||
"attr_valid=%" PRIu64 "\n"
|
||||
"entry_valid_nsec=%" PRIu32 "\n"
|
||||
"attr_valid_nsec=%" PRIu32 "\n"
|
||||
"attr.ino=%" PRIu64 "\n"
|
||||
"attr.size=%" PRIu64 "\n"
|
||||
"attr.blocks=%" PRIu64 "\n"
|
||||
"attr.atime=%" PRIu64 "\n"
|
||||
"attr.mtime=%" PRIu64 "\n"
|
||||
"attr.ctime=%" PRIu64 "\n"
|
||||
"attr.atimensec=%" PRIu32 "\n"
|
||||
"attr.mtimensec=%" PRIu32 "\n"
|
||||
"attr.ctimensec=%" PRIu32 "\n"
|
||||
"attr.mode=%" PRIu32 "\n"
|
||||
"attr.nlink=%" PRIu32 "\n"
|
||||
"attr.uid=%" PRIu32 "\n"
|
||||
"attr.gid=%" PRIu32 "\n"
|
||||
"attr.rdev=%" PRIu32 "\n"
|
||||
"attr.blksize=%" PRIu32 "\n"
|
||||
"attr.flags=%" PRIu32 "\n"
|
||||
"fh=%" PRIu64 "\n"
|
||||
"open_flags=%" PRIu32 "\n"
|
||||
"backing_id=%" PRIi32,
|
||||
req->entry_out.nodeid,
|
||||
req->entry_out.generation,
|
||||
req->entry_out.entry_valid,
|
||||
req->entry_out.attr_valid,
|
||||
req->entry_out.entry_valid_nsec,
|
||||
req->entry_out.attr_valid_nsec,
|
||||
req->entry_out.attr.ino,
|
||||
req->entry_out.attr.size,
|
||||
req->entry_out.attr.blocks,
|
||||
req->entry_out.attr.atime,
|
||||
req->entry_out.attr.mtime,
|
||||
req->entry_out.attr.ctime,
|
||||
req->entry_out.attr.atimensec,
|
||||
req->entry_out.attr.mtimensec,
|
||||
req->entry_out.attr.ctimensec,
|
||||
req->entry_out.attr.mode,
|
||||
req->entry_out.attr.nlink,
|
||||
req->entry_out.attr.uid,
|
||||
req->entry_out.attr.gid,
|
||||
req->entry_out.attr.rdev,
|
||||
req->entry_out.attr.blksize,
|
||||
req->entry_out.attr.flags,
|
||||
req->open_out.fh,
|
||||
req->open_out.open_flags,
|
||||
req->open_out.backing_id
|
||||
);
|
||||
}
|
||||
|
||||
void fuse_dump_write_out(struct fuse_write_out *wo)
|
||||
{
|
||||
LOG_INF("FUSE WRITE response:\nsize=%" PRIu32, wo->size);
|
||||
}
|
||||
|
||||
void fuse_dump_lseek_out(struct fuse_lseek_out *lo)
|
||||
{
|
||||
LOG_INF("FUSE WRITE response:\noffset=%" PRIu64, lo->offset);
|
||||
}
|
||||
|
||||
void fuse_dump_attr_out(struct fuse_attr_out *ao)
|
||||
{
|
||||
LOG_INF(
|
||||
"attr_valid=%" PRIu64 "\n"
|
||||
"attr_valid_nsec=%" PRIu32,
|
||||
ao->attr_valid,
|
||||
ao->attr_valid_nsec
|
||||
);
|
||||
}
|
||||
|
||||
void fuse_dump_kstafs(struct fuse_kstatfs *ks)
|
||||
{
|
||||
LOG_INF(
|
||||
"blocks=%" PRIu64 "\n"
|
||||
"bfree=%" PRIu64 "\n"
|
||||
"bavail=%" PRIu64 "\n"
|
||||
"files=%" PRIu64 "\n"
|
||||
"ffree=%" PRIu64 "\n"
|
||||
"bsize=%" PRIu32 "\n"
|
||||
"namelen=%" PRIu32 "\n"
|
||||
"frsize=%" PRIu32,
|
||||
ks->blocks,
|
||||
ks->bfree,
|
||||
ks->bavail,
|
||||
ks->files,
|
||||
ks->ffree,
|
||||
ks->bsize,
|
||||
ks->namelen,
|
||||
ks->frsize
|
||||
);
|
||||
}
|
||||
168
subsys/fs/fuse_client/fuse_client.h
Normal file
168
subsys/fs/fuse_client/fuse_client.h
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Antmicro <www.antmicro.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* This header provides helper functions to pack FUSE client requests. Note the client is the
|
||||
* side which initiates these requests, and that in a typical FUSE usage the client would be
|
||||
* the Linux kernel. While in Zephyr's case this is to enable functionality like the embedded
|
||||
* virtiofs client connecting to a virtiofsd daemon running in the host.
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_SUBSYS_FS_FUSE_CLIENT_H_
|
||||
#define ZEPHYR_SUBSYS_FS_FUSE_CLIENT_H_
|
||||
#include <stdint.h>
|
||||
#include "fuse_abi.h"
|
||||
|
||||
/*
|
||||
* requests are put into structs to leverage the fact that they are contiguous in memory and can
|
||||
* be passed to virtqueue as smaller amount of buffers, e.g. in_header + init_in can be sent as
|
||||
* a single buffer containing both of them instead of two separate buffers
|
||||
*/
|
||||
|
||||
struct fuse_init_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_init_in init_in;
|
||||
struct fuse_out_header out_header;
|
||||
struct fuse_init_out init_out;
|
||||
};
|
||||
|
||||
struct fuse_open_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_open_in open_in;
|
||||
struct fuse_out_header out_header;
|
||||
struct fuse_open_out open_out;
|
||||
};
|
||||
|
||||
struct fuse_create_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_create_in create_in;
|
||||
struct fuse_out_header out_header;
|
||||
struct fuse_create_out create_out;
|
||||
};
|
||||
|
||||
struct fuse_write_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_write_in write_in;
|
||||
struct fuse_out_header out_header;
|
||||
struct fuse_write_out write_out;
|
||||
};
|
||||
|
||||
struct fuse_lseek_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_lseek_in lseek_in;
|
||||
struct fuse_out_header out_header;
|
||||
struct fuse_lseek_out lseek_out;
|
||||
};
|
||||
|
||||
struct fuse_mkdir_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_mkdir_in mkdir_in;
|
||||
struct fuse_out_header out_header;
|
||||
struct fuse_entry_out entry_out;
|
||||
};
|
||||
|
||||
struct fuse_lookup_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_out_header out_header;
|
||||
struct fuse_entry_out entry_out;
|
||||
};
|
||||
|
||||
struct fuse_read_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_read_in read_in;
|
||||
struct fuse_out_header out_header;
|
||||
};
|
||||
|
||||
struct fuse_release_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_release_in release_in;
|
||||
struct fuse_out_header out_header;
|
||||
};
|
||||
|
||||
struct fuse_destroy_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_out_header out_header;
|
||||
};
|
||||
|
||||
struct fuse_setattr_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_out_header out_header;
|
||||
};
|
||||
|
||||
struct fuse_fsync_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_fsync_in fsync_in;
|
||||
struct fuse_out_header out_header;
|
||||
};
|
||||
|
||||
struct fuse_unlink_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_out_header out_header;
|
||||
};
|
||||
|
||||
struct fuse_rename_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_rename_in rename_in;
|
||||
struct fuse_out_header out_header;
|
||||
};
|
||||
|
||||
struct fuse_kstatfs_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_out_header out_header;
|
||||
struct fuse_kstatfs kstatfs_out;
|
||||
};
|
||||
|
||||
struct fuse_forget_req {
|
||||
struct fuse_in_header in_header;
|
||||
struct fuse_forget_in forget_in;
|
||||
};
|
||||
|
||||
enum fuse_object_type {
|
||||
FUSE_FILE,
|
||||
FUSE_DIR
|
||||
};
|
||||
|
||||
void fuse_fill_header(struct fuse_in_header *hdr, uint32_t len, uint32_t opcode, uint64_t nodeid);
|
||||
|
||||
void fuse_create_init_req(struct fuse_init_req *req);
|
||||
void fuse_create_open_req(struct fuse_open_req *req, uint64_t inode, uint32_t flags,
|
||||
enum fuse_object_type type);
|
||||
void fuse_create_lookup_req(struct fuse_lookup_req *req, uint64_t inode, uint32_t fname_len);
|
||||
void fuse_create_read_req(
|
||||
struct fuse_read_req *req, uint64_t inode, uint64_t fh, uint64_t offset, uint32_t size,
|
||||
enum fuse_object_type type);
|
||||
void fuse_create_release_req(struct fuse_release_req *req, uint64_t inode, uint64_t fh,
|
||||
enum fuse_object_type type);
|
||||
void fuse_create_destroy_req(struct fuse_destroy_req *req);
|
||||
void fuse_create_create_req(
|
||||
struct fuse_create_req *req, uint64_t inode, uint32_t fname_len, uint32_t flags,
|
||||
uint32_t mode);
|
||||
void fuse_create_write_req(
|
||||
struct fuse_write_req *req, uint64_t inode, uint64_t fh, uint64_t offset, uint32_t size);
|
||||
void fuse_create_lseek_req(
|
||||
struct fuse_lseek_req *req, uint64_t inode, uint64_t fh, uint64_t offset, uint32_t whence);
|
||||
void fuse_create_setattr_req(struct fuse_setattr_req *req, uint64_t inode);
|
||||
void fuse_create_fsync_req(struct fuse_fsync_req *req, uint64_t inode, uint64_t fh);
|
||||
void fuse_create_mkdir_req(
|
||||
struct fuse_mkdir_req *req, uint64_t inode, uint32_t dirname_len, uint32_t mode);
|
||||
void fuse_create_unlink_req(
|
||||
struct fuse_unlink_req *req, uint32_t fname_len, enum fuse_object_type type);
|
||||
void fuse_create_rename_req(
|
||||
struct fuse_rename_req *req, uint64_t old_dir_nodeid, uint32_t old_len,
|
||||
uint64_t new_dir_nodeid, uint32_t new_len);
|
||||
|
||||
const char *fuse_opcode_to_string(uint32_t opcode);
|
||||
|
||||
void fuse_dump_init_req_out(struct fuse_init_req *req);
|
||||
void fuse_dump_entry_out(struct fuse_entry_out *eo);
|
||||
void fuse_dump_open_req_out(struct fuse_open_req *req);
|
||||
void fuse_dump_create_req_out(struct fuse_create_out *req);
|
||||
void fuse_dump_write_out(struct fuse_write_out *wo);
|
||||
void fuse_dump_lseek_out(struct fuse_lseek_out *lo);
|
||||
void fuse_dump_attr_out(struct fuse_attr_out *ao);
|
||||
void fuse_dump_kstafs(struct fuse_kstatfs *ks);
|
||||
|
||||
#endif /* ZEPHYR_SUBSYS_FS_FUSE_CLIENT_H_ */
|
||||
Reference in New Issue
Block a user