Skip to content

Support virtio-fs #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Conversation

MikazukiHikari
Copy link

@MikazukiHikari MikazukiHikari commented Jul 2, 2025

Overview

This commit introduces the VirtIO file system device (virtio-fs) to enable efficient and secure sharing of host directories with semu.

Implementation Details

  • Virtio-fs is implemented as a VIRTIO device in the emulator, following the FUSE protocol for all file system requests.
  • The guest acts as a FUSE client, while semu acts as the FUSE server, handling requests such as :
    • INIT
    • GETATTR
    • OPENDIR
    • READDIRPLUS
    • LOOKUP
    • FORGET
    • RELEASEDIR
    • OPEN
    • READ
    • RELEASE
    • FLUSH
    • DESTROY
  • Each request from the guest is placed into a virtqueue and processed by semu, which performs the actual filesystem operations and returns the results.
  • In this implementation, a hash table (inode_map, using uthash.h) is used to efficiently map guest inode numbers to host file paths, ensuring fast lookups and consistent file operations. If we don't utilize it, which may results lacking an efficient and unique mapping structure increases the risk of losing, duplicating, or corrupting inode-path associations, leading to abnormal file operations, data loss, or security issues.
  • The device supports mounting with a tag, e.g.:
semu# mount -t virtiofs myfs /mnt

Test Procedures

  1. Build and launch the emulator with virtio-fs enabled.
  2. On the guest, mount the shared directory:
mount -t virtiofs myfs /mnt
  1. Verify file operations:
  • Read files in the shared directory in host.
  • Support commands like ls, cat, and cd to ensure correct operation.
  1. Unmount and remount to confirm stability.
umount /mnt

This project is implemented on 6.11.0-26-generic 24.04.1-Ubuntu GNU/Linux.

@jserv jserv changed the title Implement virtio filesystem in semu Support virtio-fs Jul 3, 2025
@jserv jserv requested a review from shengwen-tw July 3, 2025 00:29
README.md Outdated
@@ -77,13 +77,33 @@ You can exit the emulator using: \<Ctrl-a x\>. (press Ctrl+A, leave it, afterwar
## Usage

```shell
./semu -k linux-image [-b dtb-file] [-i initrd-image] [-d disk-image]
./semu -k linux-image [-b dtb-file] [-i initrd-image] [-d disk-image] [-s mount-folder]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never use "folder." Instead, use "directory."

@@ -102,7 +102,8 @@ CONFIG_SRCU=y
CONFIG_TINY_SRCU=y
# end of RCU Subsystem

# CONFIG_IKCONFIG is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minimize the necessary changes.

@@ -1257,7 +1262,7 @@ CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_AUTOFS4_FS=y
CONFIG_AUTOFS_FS=y
# CONFIG_FUSE_FS is not set

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't do this.

Copy link
Collaborator

@jserv jserv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix build breakage.

int32_t error;
uint64_t unique;
};

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove redundant line.

fuse.h Outdated

struct fuse_lookup_in {
uint64_t parent; // inode of parent dir
// char name[]; // followed by name (not null-terminated!)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't leave dead code. Add TODO if this requires further development.

main.c Outdated

#if SEMU_HAS(VIRTIOFS)
case 0x48: /* virtio-fs */
// printf("width:%d\n",width);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove debugging code.

minimal.dts Outdated
compatible = "virtio,mmio";
reg = <0x4800000 0x1000>;
interrupts = <6>;
tag = "myfs";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is tag necessary?

#define FUSE_RELEASE 18
#define FUSE_FLUSH 25
#define FUSE_DESTROY 38

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove redundant line.

fuse.h Outdated
};

struct fuse_init_in {
uint32_t major; // FUSE major version supported by the guest (typically 7)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow the coding style guide from CONTRIBUTING.md, i.e., using /* ... */ instead of // ... for single-line comment.

fuse.h Outdated
uint32_t major; // FUSE major version supported by the device
uint32_t minor; // FUSE minor version supported by the device
uint32_t max_readahead; // Maximum readahead size accepted by the device
uint32_t
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewrite like

/* Flags supported by the device (negotiated with the guest) */
uint32_t flags;

to avoid line breaking.

uint64_t lock_owner;
};

struct fuse_flush_in {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrap with PACKED() for all structures that require proper memory alignment.

Check the following code as example:

semu/common.h

Line 31 in 5cb78df

#define PACKED(name) name __attribute__((packed))

semu/virtio.h

Line 60 in 5cb78df

PACKED(struct virtq_desc {

#include <sys/uio.h>
#include <time.h>
#include <unistd.h>

Copy link
Collaborator

@shengwen-tw shengwen-tw Jul 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove all redundant lines in the file.

case FUSE_DESTROY:
virtio_fs_destroy_handler(vfs, vq_desc, plen);
break;
default:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add TODO for the OP codes to implement in the future.

Copy link
Collaborator

@jserv jserv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always write comments in C-style and American English.

@shengwen-tw
Copy link
Collaborator

Clean up the commit history by squashing related commits using

$ git rebase -i GIT_HASH

@jserv
Copy link
Collaborator

jserv commented Jul 3, 2025

Why uhash.h is used? Clarify its necessity.

@shengwen-tw
Copy link
Collaborator

Please improve the pull request description to make the content clearer and easier to understand. See:
Check: #70

@shengwen-tw
Copy link
Collaborator

Please move configs/linux.config to a separated commit for better history tracking.

@MikazukiHikari
Copy link
Author

Many thanks to @shengwen-tw .

I rebased the branch, and split the changes into two commits: one for configs/linux.config, and the other for the rest.
Besides, I improved the pull request description to make the content clearer and easier to understand, which includes the necessity of uthash.h.
Please examine the changes at your convenience.

device.h Outdated

typedef struct {
uint64_t ino;
char path[4096];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of hard-coding the value, consider using PATH_MAX from the standard library (limits.h) for better portability and readability.

#include <stdio.h>
#include <limits.h>

int main(void) {
    printf("PATH_MAX is defined: %d\n", PATH_MAX);
    return 0;
}

main.c Outdated

#if SEMU_HAS(VIRTIOFS)
case 0x48: /* virtio-fs */
// printf("width:%d\n",width);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove debugging code.

main.c Outdated
execpath);
fprintf(stderr,
"Usage: %s -k linux-image [-b dtb] [-i initrd-image] [-d "
"disk-image] [-s mount-folder]\n",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use directory (UNIX terminology) instead of folder (Windows terminology).

@@ -24,6 +24,45 @@
#define VIRTIO_BLK_S_IOERR 1
#define VIRTIO_BLK_S_UNSUPP 2

#define FUSE_INIT 26
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you point out the source for the FUSE OP codes and what are missing in the current implementation?

device.h Outdated
/* guest memory base */
uint32_t *ram;

char *mount_tag; // guest sees this tag
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use /* ... */ instead.

virtio-fs.c Outdated
PACKED(struct virtio_fs_config {
char tag[36];
uint32_t num_request_queues;
uint32_t notify_buf_size; // ignored
Copy link
Collaborator

@shengwen-tw shengwen-tw Jul 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rewrite all // ... with /* ... */ in this file.

virtio-fs.c Outdated

typedef struct {
DIR *dir;
char path[4096];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to use malloc() instead of a fixing path size?

virtio-fs.c Outdated
uint32_t *ram = vfs->ram;
void *priv = vfs->priv;
char *mount_tag = vfs->mount_tag;
char shared_dir[4096];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to use malloc() instead of a fixing path size?

virtio-fs.c Outdated
*plen = header_resp->out.len;
}


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove redundant lines.

virtio-fs.c Outdated
fprintf(stderr, "unsupported virtio-fs operation!\n");
return -1;
}
/* TO DO: FUSE_WRITE, FUSE_MKDIR, FUSE_RMDIR , FUSE_CREATE */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

README.md Outdated
@@ -77,13 +77,33 @@ You can exit the emulator using: \<Ctrl-a x\>. (press Ctrl+A, leave it, afterwar
## Usage

```shell
./semu -k linux-image [-b dtb-file] [-i initrd-image] [-d disk-image]
./semu -k linux-image [-b dtb-file] [-i initrd-image] [-d disk-image] [-s mount-directory]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mount-directory might be ambiguous, especially in contexts involving virtio-blk devices. Consider renaming it to something more descriptive, such as shared-directory.

@shengwen-tw
Copy link
Collaborator

Drop Finally, use clang-format-18 to fit the code style. in the commit message.

@MikazukiHikari MikazukiHikari force-pushed the master branch 2 times, most recently from 9168250 to 9210af1 Compare July 4, 2025 18:52
@ChinYikMing
Copy link
Collaborator

@MikazukiHikari Hi, could you provide a Linux image with virtio-fs enabled for quick testing? Thank you!

@ChinYikMing
Copy link
Collaborator

Please rebase to the latest remote master branch. Otherwise, the build on macOS will fail.

@MikazukiHikari
Copy link
Author

MikazukiHikari commented Jul 5, 2025

@MikazukiHikari您好,能否提供一個啟用了 virtio-fs 的 Linux 鏡像,方便我們快速測試一下?謝謝!

No problem! How should I send it to you? via Gmail? Or just commit the Linux image?

@ChinYikMing
Copy link
Collaborator

ChinYikMing commented Jul 5, 2025

@MikazukiHikari您好,能否提供一個啟用了 virtio-fs 的 Linux 鏡像,方便我們快速測試一下?謝謝!

No problem! How should I send it to you? via Gmail? Or just commit the Linux image?

You can simply upload to this code review thread.

@MikazukiHikari
Copy link
Author

Image.zip

@MikazukiHikari
Copy link
Author

@MikazukiHikari您好,能否提供一個啟用了 virtio-fs 的 Linux 鏡像,方便我們快速測試一下?謝謝!

No problem! How should I send it to you? via Gmail? Or just commit the Linux image?

You can simply upload to this code review thread.

THX for the reminder.

@ChinYikMing
Copy link
Collaborator

Verify file operations:
Create, read, write, and delete files in the shared directory in host.

@MikazukiHikari After a quick test, it seems that the create operation is not yet implemented. However, you mentioned file creation in your earlier comment.

I encountered the following error when trying to create a file using the touch command in the guest:

Welcome to Buildroot
buildroot login: root
# mount -t virtiofs myfs /mnt
# touch /mnt/apple
unsupported virtio-fs operation!

My testing environment:
OS: macOS/arm64 Version 15.3.1 (Darwin 24.3.0 Darwin Kernel Version 24.3.0)
Compiler: Apple clang version 16.0.0 (clang-1600.0.26.6)

@MikazukiHikari
Copy link
Author

MikazukiHikari commented Jul 5, 2025

Verify file operations:
Create, read, write, and delete files in the shared directory in host.

@MikazukiHikari After a quick test, it seems that the create operation is not yet implemented. However, you mentioned file creation in your earlier comment.

I encountered the following error when trying to create a file using the touch command in the guest:

Welcome to Buildroot
buildroot login: root
# mount -t virtiofs myfs /mnt
# touch /mnt/apple
unsupported virtio-fs operation!

My testing environment: OS: macOS/arm64 Version 15.3.1 (Darwin 24.3.0 Darwin Kernel Version 24.3.0) Compiler: Apple clang version 16.0.0 (clang-1600.0.26.6)

You're right! I wrote the previous comment incorrectly — it's been corrected. Sorry for the confusion.
BTW, touch command is about FUSE_CREATE, and it is not yet implemented.

Map MMIO region at 0xF48____ for virtio-fs device in semu.
Introduce special-case logic for char tag in virtio_fs config handling in semu.
Add inode_map hash table for mapping inodes to file paths.
Implement FUSE core operations:
- INIT
- GETATTR
- OPENDIR
- READDIRPLUS
- LOOKUP
- FORGET
- RELEASEDIR
- OPEN
- READ
- RELEASE
- FLUSH
- DESTROY
to make semu supports commands:`cd`, `cat`, `ls`.
Introduced uthash.h to implement a hash table for mapping inode numbers to file paths.
This improves lookup performance and simplifies path management in the virtio-fs implementation.
Set default mount tag to "myfs" and mount directory to "./shared".
When `make check`, if MOUNT_DIRECTORY is not exist, then create a new one.
If -s parameter is empty, virtio-fs is unused.
Add the explanation about virtio-fs in `Usage` of README.md.
Add the introduction of how to mount and unmount in semu.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants