unjustified read request limitation (regression from the C-language virtiofsd)
(1) Build OVMF at edk2-stable202302:
git clone https://github.com/tianocore/edk2.git
cd edk2
git checkout edk2-stable202302
git submodule update --init
unset WORKSPACE
source edksetup.sh
make -C "$EDK_TOOLS_PATH" -j $(getconf _NPROCESSORS_ONLN)
build -a X64 -b NOOPT -p OvmfPkg/OvmfPkgX64.dsc -t GCC5
(2) Populate the shared directory with the UEFI grub2 binary from your host system (as root):
mkdir /tmp/virtiofs-share
cp /boot/efi/EFI/redhat/grubx64.efi /tmp/virtiofs-share/
(3) Start the Rust-language virtiofsd (as root):
/usr/libexec/virtiofsd \
--socket-path=/tmp/vfsd.sock \
--shared-dir /tmp/virtiofs-share \
--log-level trace
(4) As root, make sure your normal user has rw access to /tmp/vfsd.sock created above (or use the --socket-group option perhaps, in step (3)).
(5) Launch OVMF in a QEMU/KVM guest, as your normal user, in the same working directory as (1). Use QEMU version 7.2.1!
qemu-system-x86_64 \
-accel kvm -m 512M \
-drive if=pflash,format=raw,file=Build/OvmfX64/NOOPT_GCC5/FV/OVMF_CODE.fd,readonly=on \
-drive if=pflash,format=raw,file=Build/OvmfX64/NOOPT_GCC5/FV/OVMF_VARS.fd,snapshot=on \
-debugcon file:debug.log -global isa-debugcon.iobase=0x402 \
-net none \
-chardev socket,id=char0,path=/tmp/vfsd.sock \
-device vhost-user-fs-pci,chardev=char0,tag=myfs,bootindex=1 \
-object memory-backend-file,id=mem,size=512M,mem-path=/dev/shm,share=on \
-numa node,memdev=mem
(6) In the guest window / UEFI shell, type:
fs0:
grubx64.efi
(7) Results:
In the UEFI shell window:
Command Error Status: Not Found
In the firmware log (debug.log, from step (5)); note Errno=-12:
VirtioFsFuseReadFileOrDir: Label="myfs" NodeId=7 FuseHandle=25 IsDir=0 Offset=0x0 Size=0x268A10 Data@1E0F9018 Errno=-12
In the virtiofsd trace (from step (3)):
Received request: opcode=Read (15), inode=7, unique=81, pid=1
Replying ERROR, header: OutHeader { error: -12 (Cannot allocate memory), unique: 81, len: 16 }
(8) Now force off the guest (which will terminate virtiofsd too), and start the C-language virtiofsd program from QEMU v7.2.1 (as root):
virtiofsd \
--socket-path=/tmp/vfsd.sock \
-o source=/tmp/virtiofs-share \
-d
(9) Repeat steps (4) through (6).
(10) Results:
In the UEFI shell window: the grub shell prompt appears.
In the C-language virtiofsd debug output:
unique: 48, opcode: READ (15), nodeid: 2, insize: 80, pid: 1
lo_read(ino=2, size=2525712, off=0)
virtio_send_data_iov: count=1 len=2525712 iov_len=16
virtio_send_data_iov: elem 0: with 2 in desc of length 2525728
virtio_send_data_iov: in_sg_cpy_count=1 len remaining=2525712
virtio_send_data_iov: preadv ret=2525712 len=2525712
fv_queue_thread: Waiting for Queue 1 event
fv_queue_thread: Got queue event on Queue 1
fv_queue_thread: Queue 1 gave evalue: 1 available: in: 16 out: 64
fv_queue_worker: elem 0: with 2 out desc of length 64
The Rust-language virtiofsd version used in step (3) is virtiofsd-1.4.0-1.el9.x86_64. I didn't test current upstream (ca1d808a), but as far as I can tell, the issue was introduced in commit 90062e4f, and it appears to remain the case that any FUSE_READ request that wants more than 1MB of data is rejected with ENOMEM. The C-language virtiofsd program does not have this limitation, as shown above -- it serves 2,525,712 bytes in a single FUSE_READ.