OvmfPkg/VirtioFsDxe: submit the FUSE_INIT request to the device

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 <ard.biesheuvel@arm.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3097
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Message-Id: <20201216211125.19496-9-lersek@redhat.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>
This commit is contained in:
Laszlo Ersek 2020-12-16 22:10:45 +01:00 committed by mergify[bot]
parent e8a74c9a07
commit fa97e37282
6 changed files with 182 additions and 8 deletions

View File

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

View File

@ -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);

View File

@ -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;
}

View File

@ -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
)
{

View File

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

View File

@ -82,6 +82,7 @@
[Sources]
DriverBinding.c
FuseInit.c
Helpers.c
SimpleFsOpenVolume.c
VirtioFsDxe.h