From fa97e3728210fbb5963ac91fafdadd6f83dc1226 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Wed, 16 Dec 2020 22:10:45 +0100 Subject: [PATCH] OvmfPkg/VirtioFsDxe: submit the FUSE_INIT request to the device MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Submit the FUSE_INIT request to the Virtio Filesystem device, for starting the FUSE session. The FUSE_INIT request is logged by the virtio-fs daemon, with this patch applied, when (for example) using the "CONNECT" UEFI shell command. Cc: Ard Biesheuvel Cc: Jordan Justen Cc: Philippe Mathieu-Daudé Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3097 Signed-off-by: Laszlo Ersek Message-Id: <20201216211125.19496-9-lersek@redhat.com> Acked-by: Ard Biesheuvel --- OvmfPkg/Include/IndustryStandard/VirtioFs.h | 31 +++++ OvmfPkg/VirtioFsDxe/DriverBinding.c | 8 +- OvmfPkg/VirtioFsDxe/FuseInit.c | 132 ++++++++++++++++++++ OvmfPkg/VirtioFsDxe/Helpers.c | 5 +- OvmfPkg/VirtioFsDxe/VirtioFsDxe.h | 13 +- OvmfPkg/VirtioFsDxe/VirtioFsDxe.inf | 1 + 6 files changed, 182 insertions(+), 8 deletions(-) create mode 100644 OvmfPkg/VirtioFsDxe/FuseInit.c diff --git a/OvmfPkg/Include/IndustryStandard/VirtioFs.h b/OvmfPkg/Include/IndustryStandard/VirtioFs.h index 521288b03f..006e0f5deb 100644 --- a/OvmfPkg/Include/IndustryStandard/VirtioFs.h +++ b/OvmfPkg/Include/IndustryStandard/VirtioFs.h @@ -76,6 +76,13 @@ typedef struct { #define VIRTIO_FS_FUSE_MAJOR 7 #define VIRTIO_FS_FUSE_MINOR 31 +// +// FUSE operation codes. +// +typedef enum { + VirtioFsFuseOpInit = 26, +} VIRTIO_FS_FUSE_OPCODE; + #pragma pack (1) // // Request-response headers common to all request types. @@ -96,6 +103,30 @@ typedef struct { INT32 Error; UINT64 Unique; } VIRTIO_FS_FUSE_RESPONSE; + +// +// Headers for VirtioFsFuseOpInit. +// +typedef struct { + UINT32 Major; + UINT32 Minor; + UINT32 MaxReadahead; + UINT32 Flags; +} VIRTIO_FS_FUSE_INIT_REQUEST; + +typedef struct { + UINT32 Major; + UINT32 Minor; + UINT32 MaxReadahead; + UINT32 Flags; + UINT16 MaxBackground; + UINT16 CongestionThreshold; + UINT32 MaxWrite; + UINT32 TimeGran; + UINT16 MaxPages; + UINT16 MapAlignment; + UINT32 Unused[8]; +} VIRTIO_FS_FUSE_INIT_RESPONSE; #pragma pack () #endif // VIRTIO_FS_H_ diff --git a/OvmfPkg/VirtioFsDxe/DriverBinding.c b/OvmfPkg/VirtioFsDxe/DriverBinding.c index 4a2787a50a..4f77ffaa99 100644 --- a/OvmfPkg/VirtioFsDxe/DriverBinding.c +++ b/OvmfPkg/VirtioFsDxe/DriverBinding.c @@ -84,10 +84,10 @@ VirtioFsBindingStart ( goto CloseVirtio; } - // - // Initialize the FUSE request counter. - // - VirtioFs->RequestId = 1; + Status = VirtioFsFuseInitSession (VirtioFs); + if (EFI_ERROR (Status)) { + goto UninitVirtioFs; + } Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, VirtioFsExitBoot, VirtioFs, &VirtioFs->ExitBoot); diff --git a/OvmfPkg/VirtioFsDxe/FuseInit.c b/OvmfPkg/VirtioFsDxe/FuseInit.c new file mode 100644 index 0000000000..aa19dbdc05 --- /dev/null +++ b/OvmfPkg/VirtioFsDxe/FuseInit.c @@ -0,0 +1,132 @@ +/** @file + FUSE_INIT wrapper for the Virtio Filesystem device. + + Copyright (C) 2020, Red Hat, Inc. + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "VirtioFsDxe.h" + +/** + Send a FUSE_INIT request to the Virtio Filesystem device, for starting the + FUSE session. + + From virtio-v1.1-cs01-87fa6b5d8155, 5.11.5 Device Initialization: "On + initialization the driver first discovers the device's virtqueues. The FUSE + session is started by sending a FUSE_INIT request as defined by the FUSE + protocol on one request virtqueue." + + The function may only be called after VirtioFsInit() returns successfully and + before VirtioFsUninit() is called. + + @param[in,out] VirtioFs The Virtio Filesystem device to send the FUSE_INIT + request to. The FUSE request counter + "VirtioFs->RequestId" is set to 1 on output. + + @retval EFI_SUCCESS The FUSE session has been started. + + @retval EFI_UNSUPPORTED FUSE interface version negotiation failed. + + @return The "errno" value mapped to an EFI_STATUS code, if + the Virtio Filesystem device explicitly reported an + error. + + @return Error codes propagated from + VirtioFsSgListsValidate(), VirtioFsFuseNewRequest(), + VirtioFsSgListsSubmit(), + VirtioFsFuseCheckResponse(). +**/ +EFI_STATUS +VirtioFsFuseInitSession ( + IN OUT VIRTIO_FS *VirtioFs + ) +{ + VIRTIO_FS_FUSE_REQUEST CommonReq; + VIRTIO_FS_FUSE_INIT_REQUEST InitReq; + VIRTIO_FS_IO_VECTOR ReqIoVec[2]; + VIRTIO_FS_SCATTER_GATHER_LIST ReqSgList; + VIRTIO_FS_FUSE_RESPONSE CommonResp; + VIRTIO_FS_FUSE_INIT_RESPONSE InitResp; + VIRTIO_FS_IO_VECTOR RespIoVec[2]; + VIRTIO_FS_SCATTER_GATHER_LIST RespSgList; + EFI_STATUS Status; + + // + // Initialize the FUSE request counter. + // + VirtioFs->RequestId = 1; + + // + // Set up the scatter-gather lists. + // + ReqIoVec[0].Buffer = &CommonReq; + ReqIoVec[0].Size = sizeof CommonReq; + ReqIoVec[1].Buffer = &InitReq; + ReqIoVec[1].Size = sizeof InitReq; + ReqSgList.IoVec = ReqIoVec; + ReqSgList.NumVec = ARRAY_SIZE (ReqIoVec); + + RespIoVec[0].Buffer = &CommonResp; + RespIoVec[0].Size = sizeof CommonResp; + RespIoVec[1].Buffer = &InitResp; + RespIoVec[1].Size = sizeof InitResp; + RespSgList.IoVec = RespIoVec; + RespSgList.NumVec = ARRAY_SIZE (RespIoVec); + + // + // Validate the scatter-gather lists; calculate the total transfer sizes. + // + Status = VirtioFsSgListsValidate (VirtioFs, &ReqSgList, &RespSgList); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Populate the common request header. + // + Status = VirtioFsFuseNewRequest (VirtioFs, &CommonReq, ReqSgList.TotalSize, + VirtioFsFuseOpInit, 0); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Populate the FUSE_INIT-specific fields. + // + InitReq.Major = VIRTIO_FS_FUSE_MAJOR; + InitReq.Minor = VIRTIO_FS_FUSE_MINOR; + InitReq.MaxReadahead = 0; + InitReq.Flags = 0; + + // + // Submit the request. + // + Status = VirtioFsSgListsSubmit (VirtioFs, &ReqSgList, &RespSgList); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Verify the response (all response buffers are fixed size). + // + Status = VirtioFsFuseCheckResponse (&RespSgList, CommonReq.Unique, NULL); + if (EFI_ERROR (Status)) { + if (Status == EFI_DEVICE_ERROR) { + DEBUG ((DEBUG_ERROR, "%a: Label=\"%s\" Errno=%d\n", __FUNCTION__, + VirtioFs->Label, CommonResp.Error)); + Status = VirtioFsErrnoToEfiStatus (CommonResp.Error); + } + return Status; + } + + // + // Check FUSE interface version compatibility. + // + if (InitResp.Major < InitReq.Major || + (InitResp.Major == InitReq.Major && InitResp.Minor < InitReq.Minor)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} diff --git a/OvmfPkg/VirtioFsDxe/Helpers.c b/OvmfPkg/VirtioFsDxe/Helpers.c index b408913186..739b0c63cf 100644 --- a/OvmfPkg/VirtioFsDxe/Helpers.c +++ b/OvmfPkg/VirtioFsDxe/Helpers.c @@ -721,7 +721,8 @@ Unmap: to send. @param[in] NodeId The inode number of the file that the request refers - to. + to. When Opcode is VirtioFsFuseOpInit, NodeId is + ignored by the Virtio Filesystem device. @retval EFI_INVALID_PARAMETER RequestSize is smaller than sizeof(VIRTIO_FS_FUSE_REQUEST). @@ -737,7 +738,7 @@ VirtioFsFuseNewRequest ( IN OUT VIRTIO_FS *VirtioFs, OUT VIRTIO_FS_FUSE_REQUEST *Request, IN UINT32 RequestSize, - IN UINT32 Opcode, + IN VIRTIO_FS_FUSE_OPCODE Opcode, IN UINT64 NodeId ) { diff --git a/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h b/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h index 772ab743cc..b8d4640118 100644 --- a/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h +++ b/OvmfPkg/VirtioFsDxe/VirtioFsDxe.h @@ -44,7 +44,7 @@ typedef struct { UINT16 QueueSize; // VirtioFsInit 1 VRING Ring; // VirtioRingInit 2 VOID *RingMap; // VirtioRingMap 2 - UINT64 RequestId; // DriverBindingStart 0 + UINT64 RequestId; // FuseInitSession 1 EFI_EVENT ExitBoot; // DriverBindingStart 0 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFs; // DriverBindingStart 0 } VIRTIO_FS; @@ -138,7 +138,7 @@ VirtioFsFuseNewRequest ( IN OUT VIRTIO_FS *VirtioFs, OUT VIRTIO_FS_FUSE_REQUEST *Request, IN UINT32 RequestSize, - IN UINT32 Opcode, + IN VIRTIO_FS_FUSE_OPCODE Opcode, IN UINT64 NodeId ); @@ -154,6 +154,15 @@ VirtioFsErrnoToEfiStatus ( IN INT32 Errno ); +// +// Wrapper functions for FUSE commands (primitives). +// + +EFI_STATUS +VirtioFsFuseInitSession ( + IN OUT VIRTIO_FS *VirtioFs + ); + // // EFI_SIMPLE_FILE_SYSTEM_PROTOCOL member functions for the Virtio Filesystem // driver. diff --git a/OvmfPkg/VirtioFsDxe/VirtioFsDxe.inf b/OvmfPkg/VirtioFsDxe/VirtioFsDxe.inf index f6eebdb6bc..8fddc50318 100644 --- a/OvmfPkg/VirtioFsDxe/VirtioFsDxe.inf +++ b/OvmfPkg/VirtioFsDxe/VirtioFsDxe.inf @@ -82,6 +82,7 @@ [Sources] DriverBinding.c + FuseInit.c Helpers.c SimpleFsOpenVolume.c VirtioFsDxe.h -- 2.39.2