summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/VirtioFsDxe/FuseRelease.c
blob: c8363158f5e7163bb1f62e5debe105318bce296c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/** @file
  FUSE_RELEASE / FUSE_RELEASEDIR wrapper for the Virtio Filesystem device.

  Copyright (C) 2020, Red Hat, Inc.

  SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#include "VirtioFsDxe.h"

/**
  Close a regular file or a directory that is open, by sending the FUSE_RELEASE
  or FUSE_RELEASEDIR request to the Virtio Filesystem device.

  The function may only be called after VirtioFsFuseInitSession() returns
  successfully and before VirtioFsUninit() is called.

  @param[in,out] VirtioFs  The Virtio Filesystem device to send the
                           FUSE_RELEASE / FUSE_RELEASEDIR request to. On
                           output, the FUSE request counter
                           "VirtioFs->RequestId" will have been incremented.

  @param[in] NodeId        The inode number of the file or directory to close.

  @param[in] FuseHandle    The open handle to the file or directory to close.

  @param[in] IsDir         TRUE if NodeId and FuseHandle refer to a directory,
                           FALSE if NodeId and FuseHandle refer to a regular
                           file.

  @retval EFI_SUCCESS  The file or directory has been closed.

  @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
VirtioFsFuseReleaseFileOrDir (
  IN OUT VIRTIO_FS  *VirtioFs,
  IN     UINT64     NodeId,
  IN     UINT64     FuseHandle,
  IN     BOOLEAN    IsDir
  )
{
  VIRTIO_FS_FUSE_REQUEST          CommonReq;
  VIRTIO_FS_FUSE_RELEASE_REQUEST  ReleaseReq;
  VIRTIO_FS_IO_VECTOR             ReqIoVec[2];
  VIRTIO_FS_SCATTER_GATHER_LIST   ReqSgList;
  VIRTIO_FS_FUSE_RESPONSE         CommonResp;
  VIRTIO_FS_IO_VECTOR             RespIoVec[1];
  VIRTIO_FS_SCATTER_GATHER_LIST   RespSgList;
  EFI_STATUS                      Status;

  //
  // Set up the scatter-gather lists.
  //
  ReqIoVec[0].Buffer = &CommonReq;
  ReqIoVec[0].Size   = sizeof CommonReq;
  ReqIoVec[1].Buffer = &ReleaseReq;
  ReqIoVec[1].Size   = sizeof ReleaseReq;
  ReqSgList.IoVec    = ReqIoVec;
  ReqSgList.NumVec   = ARRAY_SIZE (ReqIoVec);

  RespIoVec[0].Buffer = &CommonResp;
  RespIoVec[0].Size   = sizeof CommonResp;
  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,
             IsDir ? VirtioFsFuseOpReleaseDir : VirtioFsFuseOpRelease,
             NodeId
             );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // Populate the FUSE_RELEASE- / FUSE_RELEASEDIR-specific fields.
  //
  ReleaseReq.FileHandle   = FuseHandle;
  ReleaseReq.Flags        = 0;
  ReleaseReq.ReleaseFlags = 0;
  ReleaseReq.LockOwner    = 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 (Status == EFI_DEVICE_ERROR) {
    DEBUG ((
      DEBUG_ERROR,
      "%a: Label=\"%s\" NodeId=%Lu FuseHandle=%Lu "
      "IsDir=%d Errno=%d\n",
      __FUNCTION__,
      VirtioFs->Label,
      NodeId,
      FuseHandle,
      IsDir,
      CommonResp.Error
      ));
    Status = VirtioFsErrnoToEfiStatus (CommonResp.Error);
  }

  return Status;
}