2 FUSE_READ / FUSE_READDIRPLUS wrapper for the Virtio Filesystem device.
4 Copyright (C) 2020, Red Hat, Inc.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "VirtioFsDxe.h"
12 Read a chunk from a regular file or a directory stream, by sending the
13 FUSE_READ / FUSE_READDIRPLUS request to the Virtio Filesystem device.
15 The function may only be called after VirtioFsFuseInitSession() returns
16 successfully and before VirtioFsUninit() is called.
18 @param[in,out] VirtioFs The Virtio Filesystem device to send the FUSE_READ
19 or FUSE_READDIRPLUS request to. On output, the FUSE
20 request counter "VirtioFs->RequestId" will have been
23 @param[in] NodeId The inode number of the regular file or directory
26 @param[in] FuseHandle The open handle to the regular file or directory
29 @param[in] IsDir TRUE if NodeId and FuseHandle refer to a directory,
30 FALSE if NodeId and FuseHandle refer to a regular
33 @param[in] Offset If IsDir is FALSE: the absolute file position at
34 which to start reading.
36 If IsDir is TRUE: the directory stream cookie at
37 which to start or continue reading. The zero-valued
38 cookie identifies the start of the directory stream.
39 Further positions in the directory stream can be
40 passed in from the CookieForNextEntry field of
41 VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE.
43 @param[in,out] Size On input, the number of bytes to read. On successful
44 return, the number of bytes actually read, which may
45 be smaller than the value on input.
47 When reading a regular file (i.e., when IsDir is
48 FALSE), EOF can be detected by passing in a nonzero
49 Size, and finding a zero Size on output.
51 When reading a directory stream (i.e., when IsDir is
52 TRUE), Data consists of a sequence of variably-sized
53 records (directory entries). A read operation
54 returns the maximal sequence of records that fits in
55 Size, without having to truncate a record. In order
56 to guarantee progress, call
58 VirtioFsFuseStatFs (VirtioFs, NodeId,
61 first, to learn the maximum Namelen for the
62 directory stream. Then assign Size at least
64 VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE_SIZE (
67 on input. (Remember that
68 VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE_SIZE() may return
69 0 if its Namelen argument is invalid.) EOF can be
70 detected if Size is set on input like described
71 above, and Size is zero on output.
73 @param[out] Data Buffer to read the bytes from the regular file or
74 the directory stream into. The caller is responsible
75 for providing room for (at least) as many bytes in
76 Data as Size is on input.
78 @retval EFI_SUCCESS Read successful. The caller is responsible for checking
79 Size to learn the actual byte count transferred.
81 @return The "errno" value mapped to an EFI_STATUS code, if the
82 Virtio Filesystem device explicitly reported an error.
84 @return Error codes propagated from VirtioFsSgListsValidate(),
85 VirtioFsFuseNewRequest(), VirtioFsSgListsSubmit(),
86 VirtioFsFuseCheckResponse().
89 VirtioFsFuseReadFileOrDir (
90 IN OUT VIRTIO_FS
*VirtioFs
,
99 VIRTIO_FS_FUSE_REQUEST CommonReq
;
100 VIRTIO_FS_FUSE_READ_REQUEST ReadReq
;
101 VIRTIO_FS_IO_VECTOR ReqIoVec
[2];
102 VIRTIO_FS_SCATTER_GATHER_LIST ReqSgList
;
103 VIRTIO_FS_FUSE_RESPONSE CommonResp
;
104 VIRTIO_FS_IO_VECTOR RespIoVec
[2];
105 VIRTIO_FS_SCATTER_GATHER_LIST RespSgList
;
107 UINTN TailBufferFill
;
110 // Set up the scatter-gather lists.
112 ReqIoVec
[0].Buffer
= &CommonReq
;
113 ReqIoVec
[0].Size
= sizeof CommonReq
;
114 ReqIoVec
[1].Buffer
= &ReadReq
;
115 ReqIoVec
[1].Size
= sizeof ReadReq
;
116 ReqSgList
.IoVec
= ReqIoVec
;
117 ReqSgList
.NumVec
= ARRAY_SIZE (ReqIoVec
);
119 RespIoVec
[0].Buffer
= &CommonResp
;
120 RespIoVec
[0].Size
= sizeof CommonResp
;
121 RespIoVec
[1].Buffer
= Data
;
122 RespIoVec
[1].Size
= *Size
;
123 RespSgList
.IoVec
= RespIoVec
;
124 RespSgList
.NumVec
= ARRAY_SIZE (RespIoVec
);
127 // Validate the scatter-gather lists; calculate the total transfer sizes.
129 Status
= VirtioFsSgListsValidate (VirtioFs
, &ReqSgList
, &RespSgList
);
130 if (EFI_ERROR (Status
)) {
135 // Populate the common request header.
137 Status
= VirtioFsFuseNewRequest (
141 IsDir
? VirtioFsFuseOpReadDirPlus
: VirtioFsFuseOpRead
,
144 if (EFI_ERROR (Status
)) {
149 // Populate the FUSE_READ- / FUSE_READDIRPLUS-specific fields.
151 ReadReq
.FileHandle
= FuseHandle
;
152 ReadReq
.Offset
= Offset
;
153 ReadReq
.Size
= *Size
;
154 ReadReq
.ReadFlags
= 0;
155 ReadReq
.LockOwner
= 0;
160 // Submit the request.
162 Status
= VirtioFsSgListsSubmit (VirtioFs
, &ReqSgList
, &RespSgList
);
163 if (EFI_ERROR (Status
)) {
168 // Verify the response. Note that TailBufferFill is variable.
170 Status
= VirtioFsFuseCheckResponse (
175 if (EFI_ERROR (Status
)) {
176 if (Status
== EFI_DEVICE_ERROR
) {
179 "%a: Label=\"%s\" NodeId=%Lu FuseHandle=%Lu "
180 "IsDir=%d Offset=0x%Lx Size=0x%x Data@%p Errno=%d\n",
191 Status
= VirtioFsErrnoToEfiStatus (CommonResp
.Error
);
198 // Report the actual transfer size.
200 // Integer overflow in the (UINT32) cast below is not possible; the
201 // VIRTIO_FS_SCATTER_GATHER_LIST functions would have caught that.
203 *Size
= (UINT32
)TailBufferFill
;