Skip to content
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

Enable VirtIO block to access hostOS /dev/ block devices #572

Merged
merged 4 commits into from
Mar 20, 2025

Conversation

ChinYikMing
Copy link
Collaborator

@ChinYikMing ChinYikMing commented Feb 20, 2025

The user may not always have a disk image but might have a /dev/x block device, such as a USB drive that they want to share with the guest OS. So, allowing this type of virtio-blk source is intuitive. To support this, ioctl is used to retrieve the actual size of the /dev/x block device. This implementation supports both Apple and Linux platforms.

Testing

  1. Clone the repo:
$ git clone https://github.com/ChinYikMing/rv32emu.git -b virtio-blk-ioctl --depth 1 && cd rv32emu
  1. Get the prebuilt images and build:
$ make ENABLE_SYSTEM=1 INITRD_SIZE=32 -j100 && make ENABLE_SYSTEM=1 artifact
  1. Prepare /dev/x device:

macOS:

# Might need to install file system utility
$ brew install e2fsprogs

# Create a disk image
$ dd if=/dev/zero of=disk.img bs=4M count=32
$ $(brew --prefix e2fsprogs)/sbin/mkfs.ext4 disk.img

# Setup a block device with the disk image
$ hdiutil attach -nomount disk.img              # this would output the <block-device>
$ sudo build/rv32emu -k build/linux-image/Image -i build/linux-image/rootfs.cpio -x vblk:<block-device>

Linux

# Create a disk image
$ dd if=/dev/zero of=disk.img bs=4M count=32
$ mkfs.ext4 disk.img

# Setup a loop back device with the disk image
$ sudo losetup -f              # this would output the <first-unused-loop-device>
$ sudo losetup <first-unused-loop-device> disk.img 
$ sudo build/rv32emu -k build/linux-image/Image -i build/linux-image/rootfs.cpio -x vblk:<first-unused-loop-device>
  1. Check the kernel boot log which should have something as the following:
...
...
[    0.583109] virtio_blk virtio0: 1/0/0 default/read/poll queues
[    0.584873] virtio_blk virtio0: [vda] 262144 512-byte logical blocks (134 MB/128 MiB)
...
...
  1. Mount the virtio block device and manipulate the device:
# mkdir mnt
# mount /dev/vda mnt
# echo "rv32emu" > mnt/emu.txt
# ls mnt

Might see:

emu.txt     lost+found
  1. Detach newly created block device:

macOS

$ hdiutil detach <block-device>

Linux

$ losetup -d <first-unused-loop-device>

Known Issue:

On macOS/arm64, OS v15.3.1, the /dev/ block device cannot be mmap with error log: ERROR src/devices/virtio-blk.c:475: Could not map disk <block-device>.

After some debugging, the errno is set to EINVAL. Then, reading the man page of mmap in the system:

[EINVAL]           MAP_FIXED was specified and the addr argument was not page aligned, or part of the desired address space resides out of the valid address space
                        for a user process.

[EINVAL]           flags does not include either MAP_PRIVATE or MAP_SHARED.

[EINVAL]           flags includes bits that are not part of any valid flags value.

[EINVAL]           The len argument was negative or zero. Historically, the system call would not return an error if the argument was zero.  See other potential
                        additional restrictions in the COMPATIBILITY section below.

[EINVAL]           The offset argument was not page-aligned based on the page size as returned by getpagesize(3).

The page size in my system is 16KiB, which the block device size aligned of (128MiB % 16KiB == 0). The rest of the requirements appear to be met, so this seems a bit strange to me. If anyone has a macOS/arm64 machine, maybe can give it a try.

Summary by Bito

This pull request significantly enhances the virtio-blk driver, enabling guest OS access to hostOS /dev/ block devices like USB drives. It implements ioctl calls for accurate device size retrieval, improves compatibility for Apple and Linux, and includes better error handling, logging, and updated documentation. Unit tests have been added to ensure reliability.

Unit tests added: True

Estimated effort to review (1-5, lower is better): 2

@ChinYikMing ChinYikMing marked this pull request as draft February 21, 2025 02:32
@ChinYikMing ChinYikMing force-pushed the virtio-blk-ioctl branch 2 times, most recently from da0053e to 567e8d9 Compare March 17, 2025 19:24
Copy link
Contributor

@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.

Benchmarks

Benchmark suite Current: e2e87ee Previous: d1743ff Ratio
Dhrystone 1318 Average DMIPS over 10 runs 1315 Average DMIPS over 10 runs 1.00
Coremark 916.239 Average iterations/sec over 10 runs 913.984 Average iterations/sec over 10 runs 1.00

This comment was automatically generated by workflow using github-action-benchmark.

@ChinYikMing ChinYikMing force-pushed the virtio-blk-ioctl branch 2 times, most recently from b74d233 to 7a4a903 Compare March 17, 2025 19:49
@ChinYikMing ChinYikMing changed the title Enable virtio-blk to access hostOS /dev/ block devices Enable VirtIO block to access hostOS /dev/ block devices Mar 17, 2025
@ChinYikMing ChinYikMing force-pushed the virtio-blk-ioctl branch 2 times, most recently from 9409aa1 to 5163318 Compare March 17, 2025 20:09
@ChinYikMing ChinYikMing marked this pull request as ready for review March 17, 2025 20:10
@ChinYikMing
Copy link
Collaborator Author

On Apple platform, if mmap() /dev/ block devices fails, fallback to malloc(). In this way, both Apple and Linux platform are supported to access hostOS /dev/ block devices.

@ChinYikMing ChinYikMing requested a review from jserv March 17, 2025 20:16
@jserv jserv requested a review from vacantron March 17, 2025 22:43
@jserv jserv added this to the release-2025.1 milestone Mar 17, 2025
@ChinYikMing ChinYikMing force-pushed the virtio-blk-ioctl branch 2 times, most recently from d67e6e0 to 5db091a Compare March 18, 2025 06:13
@ChinYikMing ChinYikMing marked this pull request as draft March 18, 2025 15:21
@ChinYikMing ChinYikMing force-pushed the virtio-blk-ioctl branch 3 times, most recently from e3aab19 to 119d07a Compare March 19, 2025 15:38
@ChinYikMing
Copy link
Collaborator Author

ChinYikMing commented Mar 19, 2025

37cf3f3 refines the Linux boot script to validate all new system emulation features, excluding SDL.

@ChinYikMing ChinYikMing force-pushed the virtio-blk-ioctl branch 5 times, most recently from 68fb6cd to 37cf3f3 Compare March 19, 2025 19:17
@ChinYikMing ChinYikMing marked this pull request as ready for review March 19, 2025 19:21
@sysprog21 sysprog21 deleted a comment from bito-code-review bot Mar 20, 2025
@sysprog21 sysprog21 deleted a comment from bito-code-review bot Mar 20, 2025
@sysprog21 sysprog21 deleted a comment from bito-code-review bot Mar 20, 2025
@sysprog21 sysprog21 deleted a comment from bito-code-review bot Mar 20, 2025
@sysprog21 sysprog21 deleted a comment from bito-code-review bot Mar 20, 2025
@sysprog21 sysprog21 deleted a comment from bito-code-review bot Mar 20, 2025
@sysprog21 sysprog21 deleted a comment from bito-code-review bot Mar 20, 2025
@sysprog21 sysprog21 deleted a comment from bito-code-review bot Mar 20, 2025
@sysprog21 sysprog21 deleted a comment from bito-code-review bot Mar 20, 2025
@sysprog21 sysprog21 deleted a comment from bito-code-review bot Mar 20, 2025
@@ -265,15 +265,15 @@ jobs:
CC: ${{ steps.install_cc.outputs.cc }}
run: |
make distclean && make INITRD_SIZE=32 ENABLE_SYSTEM=1 $PARALLEL && make ENABLE_SYSTEM=1 artifact $PARALLEL
.ci/boot-linux.sh
sudo .ci/boot-linux.sh
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of running with superuser, can you relax the access permission of loop device and then run the emulator in non-root user?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Instead of running with superuser, can you relax the access permission of loop device and then run the emulator in non-root user?

The system validation flow in CI is abstracted into a variable called BOOT_LINUX_TEST which uses sudo only for data preparation and does not use sudo to run .ci/boot-linux.sh, enhancing security when launching the system VM.

@ChinYikMing ChinYikMing force-pushed the virtio-blk-ioctl branch 4 times, most recently from 1b8c300 to d1743ff Compare March 20, 2025 14:45
The user may not always have a disk image but might have a /dev/x block
device, such as a USB drive that they want to share with the guest OS.
So, allowing this type of virtio-blk source is intuitive. To support
this, ioctl is used to retrieve the actual size of the /dev/x block
device. This implementation supports both Apple and Linux platforms.

On Apple platforms, mmap() on block devices appears to be unsupported
with various flag combinations. To address this, a fallback mechanism is
added and used when mmap() fails, using malloc() along with pread(),
pwrite() and fsync() on the block device fd to emulate the behavior of
mmap().

Additionally, the initial fallback was incomplete, as it only allocated
heap memory without loading the block device's content into memory. This
commit resolves the issue by properly reading the device contents into
the allocated buffer.

Since there may be asynchronous exits, a new rv_fsync_device() function
is introduced to ensure the block device is properly synchronized during
such exits.

To fully support this fallback, disk_fd and disk_size are now stored in
the vblk state during its initialization.

Close sysprog21#544
The Linux boot script previously tested both booting and VirtIO block
access simultaneously. This commit refines the boot script to test each
guest Linux feature independently. In addition, a new color (yellow) is
introduced to clearly indicate which test is currently running in the
CI, improving debugging capabilities. For future VirtIO device tests or
other new features, TEST_OPTIONS and EXPECT_CMDS can be easily updated
to extend the tests, enhancing the overall flexibility of the script.

The VirtIO block device image or loop device is prepared by the
.ci/boot-linux-prepare.sh script which decouples data and control for
system emulation validation in .ci/boot-linux.sh. This script can be
extended in the future to support additional VirtIO devices by preparing
their associated data prior to Linux boot validation.

The system validation flow is abstracted into a variable called
BOOT_LINUX_TEST which uses sudo only for data preparation and does not
use sudo to run .ci/boot-linux.sh, enhancing security when launching
the system VM.
@jserv jserv merged commit 92fd789 into sysprog21:master Mar 20, 2025
26 of 28 checks passed
@jserv
Copy link
Contributor

jserv commented Mar 20, 2025

Thank @ChinYikMing for contributing!

@ChinYikMing ChinYikMing deleted the virtio-blk-ioctl branch March 21, 2025 01:17
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.

2 participants