FuseInit.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /** @file
  2. FUSE_INIT 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. Send a FUSE_INIT request to the Virtio Filesystem device, for starting the
  9. FUSE session.
  10. From virtio-v1.1-cs01-87fa6b5d8155, 5.11.5 Device Initialization: "On
  11. initialization the driver first discovers the device's virtqueues. The FUSE
  12. session is started by sending a FUSE_INIT request as defined by the FUSE
  13. protocol on one request virtqueue."
  14. The function may only be called after VirtioFsInit() returns successfully and
  15. before VirtioFsUninit() is called.
  16. @param[in,out] VirtioFs The Virtio Filesystem device to send the FUSE_INIT
  17. request to. The FUSE request counter
  18. "VirtioFs->RequestId" is set to 1 on output. The
  19. maximum write buffer size exposed in the FUSE_INIT
  20. response is saved in "VirtioFs->MaxWrite", on
  21. output.
  22. @retval EFI_SUCCESS The FUSE session has been started.
  23. @retval EFI_UNSUPPORTED FUSE interface version or feature negotiation
  24. failed.
  25. @return The "errno" value mapped to an EFI_STATUS code, if
  26. the Virtio Filesystem device explicitly reported an
  27. error.
  28. @return Error codes propagated from
  29. VirtioFsSgListsValidate(), VirtioFsFuseNewRequest(),
  30. VirtioFsSgListsSubmit(),
  31. VirtioFsFuseCheckResponse().
  32. **/
  33. EFI_STATUS
  34. VirtioFsFuseInitSession (
  35. IN OUT VIRTIO_FS *VirtioFs
  36. )
  37. {
  38. VIRTIO_FS_FUSE_REQUEST CommonReq;
  39. VIRTIO_FS_FUSE_INIT_REQUEST InitReq;
  40. VIRTIO_FS_IO_VECTOR ReqIoVec[2];
  41. VIRTIO_FS_SCATTER_GATHER_LIST ReqSgList;
  42. VIRTIO_FS_FUSE_RESPONSE CommonResp;
  43. VIRTIO_FS_FUSE_INIT_RESPONSE InitResp;
  44. VIRTIO_FS_IO_VECTOR RespIoVec[2];
  45. VIRTIO_FS_SCATTER_GATHER_LIST RespSgList;
  46. EFI_STATUS Status;
  47. //
  48. // Initialize the FUSE request counter.
  49. //
  50. VirtioFs->RequestId = 1;
  51. //
  52. // Set up the scatter-gather lists.
  53. //
  54. ReqIoVec[0].Buffer = &CommonReq;
  55. ReqIoVec[0].Size = sizeof CommonReq;
  56. ReqIoVec[1].Buffer = &InitReq;
  57. ReqIoVec[1].Size = sizeof InitReq;
  58. ReqSgList.IoVec = ReqIoVec;
  59. ReqSgList.NumVec = ARRAY_SIZE (ReqIoVec);
  60. RespIoVec[0].Buffer = &CommonResp;
  61. RespIoVec[0].Size = sizeof CommonResp;
  62. RespIoVec[1].Buffer = &InitResp;
  63. RespIoVec[1].Size = sizeof InitResp;
  64. RespSgList.IoVec = RespIoVec;
  65. RespSgList.NumVec = ARRAY_SIZE (RespIoVec);
  66. //
  67. // Validate the scatter-gather lists; calculate the total transfer sizes.
  68. //
  69. Status = VirtioFsSgListsValidate (VirtioFs, &ReqSgList, &RespSgList);
  70. if (EFI_ERROR (Status)) {
  71. return Status;
  72. }
  73. //
  74. // Populate the common request header.
  75. //
  76. Status = VirtioFsFuseNewRequest (
  77. VirtioFs,
  78. &CommonReq,
  79. ReqSgList.TotalSize,
  80. VirtioFsFuseOpInit,
  81. 0
  82. );
  83. if (EFI_ERROR (Status)) {
  84. return Status;
  85. }
  86. //
  87. // Populate the FUSE_INIT-specific fields.
  88. //
  89. InitReq.Major = VIRTIO_FS_FUSE_MAJOR;
  90. InitReq.Minor = VIRTIO_FS_FUSE_MINOR;
  91. InitReq.MaxReadahead = 0;
  92. InitReq.Flags = VIRTIO_FS_FUSE_INIT_REQ_F_DO_READDIRPLUS;
  93. //
  94. // Submit the request.
  95. //
  96. Status = VirtioFsSgListsSubmit (VirtioFs, &ReqSgList, &RespSgList);
  97. if (EFI_ERROR (Status)) {
  98. return Status;
  99. }
  100. //
  101. // Verify the response (all response buffers are fixed size).
  102. //
  103. Status = VirtioFsFuseCheckResponse (&RespSgList, CommonReq.Unique, NULL);
  104. if (EFI_ERROR (Status)) {
  105. if (Status == EFI_DEVICE_ERROR) {
  106. DEBUG ((
  107. DEBUG_ERROR,
  108. "%a: Label=\"%s\" Errno=%d\n",
  109. __FUNCTION__,
  110. VirtioFs->Label,
  111. CommonResp.Error
  112. ));
  113. Status = VirtioFsErrnoToEfiStatus (CommonResp.Error);
  114. }
  115. return Status;
  116. }
  117. //
  118. // Check FUSE interface version / feature compatibility.
  119. //
  120. if ((InitResp.Major < InitReq.Major) ||
  121. ((InitResp.Major == InitReq.Major) && (InitResp.Minor < InitReq.Minor)) ||
  122. ((InitResp.Flags & VIRTIO_FS_FUSE_INIT_REQ_F_DO_READDIRPLUS) == 0) ||
  123. (InitResp.MaxWrite < SIZE_4KB))
  124. {
  125. return EFI_UNSUPPORTED;
  126. }
  127. //
  128. // Save the maximum write buffer size for FUSE_WRITE requests.
  129. //
  130. VirtioFs->MaxWrite = InitResp.MaxWrite;
  131. return EFI_SUCCESS;
  132. }