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.