Skip to content

Commit eab840b

Browse files
fs: virtiofs: add virtiofs sample
This commit adds virtiofs sample that presents use of this filesystem Signed-off-by: Jakub Michalski <[email protected]> Signed-off-by: Filip Kokosinski <[email protected]>
1 parent a9bd880 commit eab840b

File tree

7 files changed

+254
-0
lines changed

7 files changed

+254
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
5+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
6+
project(virtiofs)
7+
8+
target_sources(app PRIVATE src/main.c)

samples/subsys/fs/virtiofs/README.rst

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
.. zephyr:code-sample:: virtiofs
2+
:name: virtiofs filesystem
3+
:relevant-api: file_system_api
4+
5+
Use file system API over virtiofs.
6+
7+
Overview
8+
********
9+
10+
This sample app demonstrates use of Zephyr's :ref:`file system API
11+
<file_system_api>` over `virtiofs <https://virtio-fs.gitlab.io/>`_ by reading, creating and listing files and directories.
12+
In the case of virtiofs the mounted filesystem is a directory on the host.
13+
14+
Requirements
15+
************
16+
This sample requires `virtiofsd <https://gitlab.com/virtio-fs/virtiofsd>`_ to run.
17+
18+
Building
19+
********
20+
.. zephyr-app-commands::
21+
:zephyr-app: samples/subsys/fs/virtiofs
22+
:board: qemu_x86_64
23+
:goals: build
24+
:compact:
25+
26+
27+
Running
28+
*******
29+
Before launching QEMU the virtiofsd has to be running. The QEMU arguments are embedded using :code:`CONFIG_QEMU_EXTRA_FLAGS` and socket path is set to :code:`/tmp/vhostqemu`, so virtiofsd has to be launched using
30+
31+
.. code-block::
32+
33+
virtiofsd --socket-path=/tmp/vhostqemu -o source=shared_dir_path
34+
35+
where :code:`shared_dir_path` is a directory that will be mounted on Zephyr side.
36+
Then you can launch the QEMU using:
37+
38+
.. code-block::
39+
40+
west build -t run
41+
42+
This sample will list files and directories in the mounted filesystem and print contents of file :code:`file` in the mounted directory.
43+
This sample will also create some files and directories.
44+
You can create sample directory using :code:`prepare_sample_directory.sh`.
45+
46+
Example output:
47+
48+
.. code-block::
49+
50+
*** Booting Zephyr OS build v4.1.0-rc1-28-gc6816316fc50 ***
51+
/virtiofs directory tree:
52+
- dir2 (type=dir)
53+
- b (type=file, size=3)
54+
- a (type=file, size=2)
55+
- c (type=file, size=4)
56+
- dir (type=dir)
57+
- some_file (type=file, size=0)
58+
- nested_dir (type=dir)
59+
- some_other_file (type=file, size=0)
60+
- file (type=file, size=27)
61+
62+
/virtiofs/file content:
63+
this is a file on the host
64+
65+
66+
After running the sample you can check the created files:
67+
68+
.. code-block:: console
69+
70+
shared_dir_path$ cat file_created_by_zephyr
71+
hello world
72+
shared_dir_path$ cat second_file_created_by_zephyr
73+
lorem ipsum
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
&pcie0 {
2+
virtio_pci: virtio_pci {
3+
compatible = "virtio,pci";
4+
5+
vendor-id = <0x1af4>;
6+
device-id = <0x105a>;
7+
8+
interrupts = <0xb 0x0 0x0>;
9+
interrupt-parent = <&intc>;
10+
11+
status = "okay";
12+
};
13+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) 2025 Antmicro <www.antmicro.com>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
mkdir -p dir/nested_dir
5+
touch dir/some_file
6+
touch dir/nested_dir/some_other_file
7+
mkdir dir2
8+
echo "a" > dir2/a
9+
echo "bb" > dir2/b
10+
echo "ccc" > dir2/c
11+
echo "this is a file on the host" > file

samples/subsys/fs/virtiofs/prj.conf

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CONFIG_VIRTIO=y
2+
CONFIG_PCIE=y
3+
CONFIG_FILE_SYSTEM=y
4+
CONFIG_FILE_SYSTEM_VIRTIOFS=y
5+
CONFIG_HEAP_MEM_POOL_SIZE=100000
6+
CONFIG_QEMU_EXTRA_FLAGS="-chardev socket,id=char0,path=/tmp/vhostqemu -device vhost-user-fs-pci,queue-size=1024,chardev=char0,tag=myfs -m 32M -object memory-backend-memfd,id=mem,size=32M,share=on -numa node,memdev=mem"
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
sample:
2+
name: virtio filesystem sample
3+
common:
4+
tags:
5+
- filesystem
6+
- virtio
7+
tests:
8+
sample.filesystem.virtiofs:
9+
build_only: true
10+
filter: CONFIG_DT_HAS_VIRTIO_PCI_ENABLED

samples/subsys/fs/virtiofs/src/main.c

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright (c) 2025 Antmicro <www.antmicro.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <stdio.h>
8+
#include <string.h>
9+
#include <zephyr/device.h>
10+
#include <zephyr/fs/fs.h>
11+
#include <zephyr/fs/virtiofs.h>
12+
#include <zephyr/kernel.h>
13+
14+
#define VIRTIO_DEV DEVICE_DT_GET(DT_NODELABEL(virtio_pci))
15+
16+
#define MOUNT_POINT "/virtiofs"
17+
18+
struct virtiofs_fs_data fs_data;
19+
20+
static struct fs_mount_t mp = {
21+
.type = FS_VIRTIOFS,
22+
.fs_data = &fs_data,
23+
.flags = 0,
24+
.storage_dev = (void *)VIRTIO_DEV,
25+
.mnt_point = MOUNT_POINT,
26+
};
27+
28+
void dirtree(const char *path, int indent)
29+
{
30+
struct fs_dir_t dir;
31+
32+
fs_dir_t_init(&dir);
33+
if (fs_opendir(&dir, path) == 0) {
34+
while (1) {
35+
struct fs_dirent entry;
36+
37+
if (fs_readdir(&dir, &entry) == 0) {
38+
if (entry.name[0] == '\0') {
39+
break;
40+
}
41+
if (entry.type == FS_DIR_ENTRY_DIR) {
42+
printf("%*s- %s (type=dir)\n", indent * 2, "", entry.name);
43+
char *subdir_path = k_malloc(
44+
strlen(path) + strlen(entry.name) + 2
45+
);
46+
47+
if (subdir_path == NULL) {
48+
printf("failed to allocate subdir path\n");
49+
continue;
50+
}
51+
strcpy(subdir_path, path);
52+
strcat(subdir_path, "/");
53+
strcat(subdir_path, entry.name);
54+
dirtree(subdir_path, indent + 1);
55+
k_free(subdir_path);
56+
} else {
57+
printf(
58+
"%*s- %s (type=file, size=%lu)\n",
59+
indent * 2, "", entry.name, entry.size
60+
);
61+
}
62+
} else {
63+
printf("failed to readdir %s\n", path);
64+
break;
65+
}
66+
};
67+
68+
fs_closedir(&dir);
69+
} else {
70+
printf("failed to opendir %s\n", path);
71+
}
72+
}
73+
74+
void create_file(const char *path, const char *content)
75+
{
76+
struct fs_file_t file;
77+
78+
fs_file_t_init(&file);
79+
if (fs_open(&file, path, FS_O_CREATE | FS_O_WRITE) == 0) {
80+
fs_write(&file, content, strlen(content) + 1);
81+
} else {
82+
printf("failed to create %s\n", path);
83+
}
84+
fs_close(&file);
85+
}
86+
87+
void print_file(const char *path)
88+
{
89+
struct fs_file_t file;
90+
91+
fs_file_t_init(&file);
92+
if (fs_open(&file, path, FS_O_READ) == 0) {
93+
char buf[256] = "\0";
94+
int read_c = fs_read(&file, buf, sizeof(buf));
95+
96+
if (read_c >= 0) {
97+
buf[read_c] = 0;
98+
99+
printf(
100+
"%s content:\n"
101+
"%s\n",
102+
path, buf
103+
);
104+
} else {
105+
printf("failed to read from %s\n", path);
106+
}
107+
108+
fs_close(&file);
109+
} else {
110+
printf("failed to open %s\n", path);
111+
}
112+
}
113+
114+
int main(void)
115+
{
116+
if (fs_mount(&mp) == 0) {
117+
printf("%s directory tree:\n", MOUNT_POINT);
118+
dirtree(MOUNT_POINT, 0);
119+
printf("\n");
120+
121+
print_file(MOUNT_POINT"/file");
122+
123+
create_file("/virtiofs/file_created_by_zephyr", "hello world\n");
124+
125+
create_file("/virtiofs/second_file_created_by_zephyr", "lorem ipsum\n");
126+
127+
fs_mkdir("/virtiofs/dir_created_by_zephyr");
128+
} else {
129+
printf("failed to mount %s\n", MOUNT_POINT);
130+
}
131+
132+
return 0;
133+
}

0 commit comments

Comments
 (0)