FuseWrite.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /** @file
  2. FUSE_WRITE wrapper for the Virtio Filesystem device.
  3. Copyright (C) 2020, Red Hat, Inc.
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "VirtioFsDxe.h"
  7. /**
  8. Write a chunk to a regular file, by sending the FUSE_WRITE request to the
  9. Virtio Filesystem device.
  10. The function may only be called after VirtioFsFuseInitSession() returns
  11. successfully and before VirtioFsUninit() is called.
  12. @param[in,out] VirtioFs The Virtio Filesystem device to send the FUSE_WRITE
  13. request to. On output, the FUSE request counter
  14. "VirtioFs->RequestId" will have been incremented.
  15. @param[in] NodeId The inode number of the regular file to write to.
  16. @param[in] FuseHandle The open handle to the regular file to write to.
  17. @param[in] Offset The absolute file position at which to start
  18. writing.
  19. @param[in,out] Size On input, the number of bytes to write. On
  20. successful return, the number of bytes actually
  21. written, which may be smaller than the value on
  22. input.
  23. @param[in] Data The buffer to write to the regular file.
  24. @retval EFI_SUCCESS Write successful. The caller is responsible for
  25. checking Size to learn the actual byte count
  26. transferred.
  27. @retval EFI_BAD_BUFFER_SIZE On input, Size is larger than
  28. "VirtioFs->MaxWrite".
  29. @return The "errno" value mapped to an EFI_STATUS code,
  30. if the Virtio Filesystem device explicitly
  31. reported an error.
  32. @return Error codes propagated from
  33. VirtioFsSgListsValidate(),
  34. VirtioFsFuseNewRequest(),
  35. VirtioFsSgListsSubmit(),
  36. VirtioFsFuseCheckResponse().
  37. **/
  38. EFI_STATUS
  39. VirtioFsFuseWrite (
  40. IN OUT VIRTIO_FS *VirtioFs,
  41. IN UINT64 NodeId,
  42. IN UINT64 FuseHandle,
  43. IN UINT64 Offset,
  44. IN OUT UINT32 *Size,
  45. IN VOID *Data
  46. )
  47. {
  48. VIRTIO_FS_FUSE_REQUEST CommonReq;
  49. VIRTIO_FS_FUSE_WRITE_REQUEST WriteReq;
  50. VIRTIO_FS_IO_VECTOR ReqIoVec[3];
  51. VIRTIO_FS_SCATTER_GATHER_LIST ReqSgList;
  52. VIRTIO_FS_FUSE_RESPONSE CommonResp;
  53. VIRTIO_FS_FUSE_WRITE_RESPONSE WriteResp;
  54. VIRTIO_FS_IO_VECTOR RespIoVec[2];
  55. VIRTIO_FS_SCATTER_GATHER_LIST RespSgList;
  56. EFI_STATUS Status;
  57. //
  58. // Honor the write buffer size limit of the Virtio Filesystem device.
  59. //
  60. if (*Size > VirtioFs->MaxWrite) {
  61. return EFI_BAD_BUFFER_SIZE;
  62. }
  63. //
  64. // Set up the scatter-gather lists.
  65. //
  66. ReqIoVec[0].Buffer = &CommonReq;
  67. ReqIoVec[0].Size = sizeof CommonReq;
  68. ReqIoVec[1].Buffer = &WriteReq;
  69. ReqIoVec[1].Size = sizeof WriteReq;
  70. ReqIoVec[2].Buffer = Data;
  71. ReqIoVec[2].Size = *Size;
  72. ReqSgList.IoVec = ReqIoVec;
  73. ReqSgList.NumVec = ARRAY_SIZE (ReqIoVec);
  74. RespIoVec[0].Buffer = &CommonResp;
  75. RespIoVec[0].Size = sizeof CommonResp;
  76. RespIoVec[1].Buffer = &WriteResp;
  77. RespIoVec[1].Size = sizeof WriteResp;
  78. RespSgList.IoVec = RespIoVec;
  79. RespSgList.NumVec = ARRAY_SIZE (RespIoVec);
  80. //
  81. // Validate the scatter-gather lists; calculate the total transfer sizes.
  82. //
  83. Status = VirtioFsSgListsValidate (VirtioFs, &ReqSgList, &RespSgList);
  84. if (EFI_ERROR (Status)) {
  85. return Status;
  86. }
  87. //
  88. // Populate the common request header.
  89. //
  90. Status = VirtioFsFuseNewRequest (
  91. VirtioFs,
  92. &CommonReq,
  93. ReqSgList.TotalSize,
  94. VirtioFsFuseOpWrite,
  95. NodeId
  96. );
  97. if (EFI_ERROR (Status)) {
  98. return Status;
  99. }
  100. //
  101. // Populate the FUSE_WRITE-specific fields.
  102. //
  103. WriteReq.FileHandle = FuseHandle;
  104. WriteReq.Offset = Offset;
  105. WriteReq.Size = *Size;
  106. WriteReq.WriteFlags = 0;
  107. WriteReq.LockOwner = 0;
  108. WriteReq.Flags = 0;
  109. WriteReq.Padding = 0;
  110. //
  111. // Submit the request.
  112. //
  113. Status = VirtioFsSgListsSubmit (VirtioFs, &ReqSgList, &RespSgList);
  114. if (EFI_ERROR (Status)) {
  115. return Status;
  116. }
  117. //
  118. // Verify the response (all response buffers are fixed size).
  119. //
  120. Status = VirtioFsFuseCheckResponse (&RespSgList, CommonReq.Unique, NULL);
  121. if (EFI_ERROR (Status)) {
  122. if (Status == EFI_DEVICE_ERROR) {
  123. DEBUG ((
  124. DEBUG_ERROR,
  125. "%a: Label=\"%s\" NodeId=%Lu FuseHandle=%Lu "
  126. "Offset=0x%Lx Size=0x%x Data@%p Errno=%d\n",
  127. __FUNCTION__,
  128. VirtioFs->Label,
  129. NodeId,
  130. FuseHandle,
  131. Offset,
  132. *Size,
  133. Data,
  134. CommonResp.Error
  135. ));
  136. Status = VirtioFsErrnoToEfiStatus (CommonResp.Error);
  137. }
  138. return Status;
  139. }
  140. //
  141. // Report the actual transfer size.
  142. //
  143. *Size = WriteResp.Size;
  144. return EFI_SUCCESS;
  145. }