VirtioFs = VirtioFsFile->OwnerFs;\r
\r
//\r
- // At this point, the implementation is only suitable for closing the\r
- // VIRTIO_FS_FILE that was created by VirtioFsOpenVolume().\r
+ // All actions in this function are "best effort"; the UEFI spec requires\r
+ // EFI_FILE_PROTOCOL.Close() to sync all data to the device, but it also\r
+ // requires EFI_FILE_PROTOCOL.Close() to release resources unconditionally,\r
+ // and to return EFI_SUCCESS unconditionally.\r
//\r
- ASSERT (VirtioFsFile->IsDirectory);\r
- ASSERT (VirtioFsFile->NodeId == VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID);\r
- //\r
- // Close the root directory.\r
- //\r
- // Ignore any errors, because EFI_FILE_PROTOCOL.Close() is required to\r
- // release the EFI_FILE_PROTOCOL object unconditionally.\r
+ // Flush, sync, release, and (if needed) forget. If any action fails, we\r
+ // still try the others.\r
//\r
+ if (VirtioFsFile->IsOpenForWriting) {\r
+ if (!VirtioFsFile->IsDirectory) {\r
+ VirtioFsFuseFlush (VirtioFs, VirtioFsFile->NodeId,\r
+ VirtioFsFile->FuseHandle);\r
+ }\r
+\r
+ VirtioFsFuseFsyncFileOrDir (VirtioFs, VirtioFsFile->NodeId,\r
+ VirtioFsFile->FuseHandle, VirtioFsFile->IsDirectory);\r
+ }\r
+\r
VirtioFsFuseReleaseFileOrDir (VirtioFs, VirtioFsFile->NodeId,\r
VirtioFsFile->FuseHandle, VirtioFsFile->IsDirectory);\r
\r
+ //\r
+ // VirtioFsFile->FuseHandle is gone at this point, but VirtioFsFile->NodeId\r
+ // is still valid. If we've known VirtioFsFile->NodeId from a lookup, then\r
+ // now we should ask the server to forget it *once*.\r
+ //\r
+ if (VirtioFsFile->NodeId != VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID) {\r
+ VirtioFsFuseForget (VirtioFs, VirtioFsFile->NodeId);\r
+ }\r
+\r
//\r
// One fewer file left open for the owner filesystem.\r
//\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
**/\r
\r
+#include <Library/BaseLib.h> // RemoveEntryList()\r
+#include <Library/MemoryAllocationLib.h> // FreePool()\r
+\r
#include "VirtioFsDxe.h"\r
\r
EFI_STATUS\r
IN EFI_FILE_PROTOCOL *This\r
)\r
{\r
+ VIRTIO_FS_FILE *VirtioFsFile;\r
+ VIRTIO_FS *VirtioFs;\r
+ EFI_STATUS Status;\r
+\r
+ VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This);\r
+ VirtioFs = VirtioFsFile->OwnerFs;\r
+\r
+ //\r
+ // All actions in this function are "best effort"; the UEFI spec requires\r
+ // EFI_FILE_PROTOCOL.Delete() to release resources unconditionally. If a step\r
+ // related to removing the file fails, it's only reflected in the return\r
+ // status (EFI_WARN_DELETE_FAILURE rather than EFI_SUCCESS).\r
+ //\r
+ // Release, remove, and (if needed) forget. We don't waste time flushing and\r
+ // syncing; if the EFI_FILE_PROTOCOL user cares enough, they should keep the\r
+ // parent directory open until after this function call returns, and then\r
+ // force a sync on *that* EFI_FILE_PROTOCOL instance, using either the\r
+ // Flush() member function, or the Close() member function.\r
+ //\r
+ // If any action fails below, we still try the others.\r
+ //\r
+ VirtioFsFuseReleaseFileOrDir (VirtioFs, VirtioFsFile->NodeId,\r
+ VirtioFsFile->FuseHandle, VirtioFsFile->IsDirectory);\r
+\r
+ //\r
+ // VirtioFsFile->FuseHandle is gone at this point, but VirtioFsFile->NodeId\r
+ // is still valid. Continue with removing the file or directory. The result\r
+ // of this operation determines the return status of the function.\r
//\r
- // At this point, the implementation is only suitable for closing the\r
- // VIRTIO_FS_FILE that was created by VirtioFsOpenVolume().\r
+ // TODO\r
//\r
- // Actually deleting the root directory is not possible, so we're only going\r
- // to release resources, and return EFI_WARN_DELETE_FAILURE.\r
+ Status = EFI_WARN_DELETE_FAILURE;\r
+\r
//\r
- // In order to release resources, VirtioFsSimpleFileClose() is just right\r
- // here.\r
+ // Finally, if we've known VirtioFsFile->NodeId from a lookup, then we should\r
+ // also ask the server to forget it *once*.\r
//\r
- VirtioFsSimpleFileClose (This);\r
- return EFI_WARN_DELETE_FAILURE;\r
+ if (VirtioFsFile->NodeId != VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID) {\r
+ VirtioFsFuseForget (VirtioFs, VirtioFsFile->NodeId);\r
+ }\r
+\r
+ //\r
+ // One fewer file left open for the owner filesystem.\r
+ //\r
+ RemoveEntryList (&VirtioFsFile->OpenFilesEntry);\r
+\r
+ FreePool (VirtioFsFile);\r
+ return Status;\r
}\r