Skip to content

Commit bc0a5ad

Browse files
committed
Fix file deletion thread safety
1 parent 2efdf22 commit bc0a5ad

1 file changed

Lines changed: 20 additions & 12 deletions

File tree

WinFsp-MemFs-Extended/memfs.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,8 @@ typedef struct _MEMFS
494494
// memefs: Counter to track allocated memory
495495
volatile UINT64 AllocatedSectors;
496496
volatile UINT64 AllocatedSizesToBeDeleted;
497-
std::map<MEMFS_FILE_NODE*, UINT64>* ToBeDeletedFileNodeSizes;
497+
std::unordered_map<MEMFS_FILE_NODE*, UINT64>* ToBeDeletedFileNodeSizes;
498+
std::mutex* ToBeDeletedFileNodeSizesMutex;
498499
// memefs: MaxFsSize instead of max. file nodes and individual limits
499500
UINT64 MaxFsSize;
500501
UINT64 CachedMaxFsSize;
@@ -516,7 +517,7 @@ static MEMFS* GlobalMemfs = 0;
516517
// memefs: Get the all file sizes and the node map size
517518
static inline
518519
UINT64 MemefsGetUsedTotalSize(MEMFS* Memfs) {
519-
const ULONG nodeMapSize = (ULONG)Memfs->FileNodeMap->size() * (sizeof(PWSTR) * MEMFS_MAX_PATH + sizeof(MEMFS_FILE_NODE) + sizeof(std::mutex));
520+
const ULONG nodeMapSize = (ULONG)Memfs->FileNodeMap->size() * (sizeof(PWSTR) * MEMFS_MAX_PATH + sizeof(MEMFS_FILE_NODE) + sizeof(std::mutex) + sizeof(std::mutex*));
520521
// EA node map is ignored, because it is insignificant
521522

522523
const SIZE_T sectorSizes = Memfs->AllocatedSectors * (sizeof(MEMEFS_SECTOR) + sizeof(MEMEFS_SECTOR*));
@@ -583,7 +584,7 @@ BOOL MemefsIsFullyEmpty(MEMFS* Memfs)
583584
}
584585
*/
585586

586-
return InterlockedExchangeAdd(&Memfs->AllocatedSectors, 0ULL) == 0;
587+
return InterlockedExchangeAdd(&Memfs->AllocatedSectors, 0ULL) == 0;
587588
}
588589

589590
static inline
@@ -641,14 +642,16 @@ VOID MemfsFileNodeDelete(MEMFS_FILE_NODE* FileNode)
641642
#endif
642643

643644
// memefs: SectorFree
644-
SectorFree(&FileNode->FileDataSectors, FileNode->FileDataSectorsMutex, &GlobalMemfs->AllocatedSectors);
645-
646645
const auto mapIterator = GlobalMemfs->ToBeDeletedFileNodeSizes->find(FileNode);
647646
if (mapIterator != GlobalMemfs->ToBeDeletedFileNodeSizes->end()) {
648-
GlobalMemfs->AllocatedSizesToBeDeleted -= mapIterator->second;
649-
GlobalMemfs->ToBeDeletedFileNodeSizes->erase(mapIterator->first);
647+
InterlockedExchangeSubtract(&GlobalMemfs->AllocatedSizesToBeDeleted, mapIterator->second);
648+
649+
std::unique_lock writeLock(*GlobalMemfs->ToBeDeletedFileNodeSizesMutex);
650+
GlobalMemfs->ToBeDeletedFileNodeSizes->erase(mapIterator->first); // TODO: Thread safe map
650651
}
651652

653+
SectorFree(&FileNode->FileDataSectors, FileNode->FileDataSectorsMutex, &GlobalMemfs->AllocatedSectors);
654+
652655
FileNode->FileDataSectors.~vector();
653656
delete FileNode->FileDataSectorsMutex;
654657

@@ -966,7 +969,10 @@ VOID MemfsFileNodeMapRemove(MEMFS_FILE_NODE_MAP* FileNodeMap, MEMFS_FILE_NODE* F
966969
if (ReportDeletedSize)
967970
{
968971
const UINT64 toBeDeletedSizes = FileNode->FileDataSectors.size() * (sizeof(MEMEFS_SECTOR) + sizeof(MEMEFS_SECTOR*));
969-
GlobalMemfs->AllocatedSizesToBeDeleted += toBeDeletedSizes;
972+
973+
InterlockedExchangeAdd(&GlobalMemfs->AllocatedSizesToBeDeleted, toBeDeletedSizes);
974+
975+
std::unique_lock writeLock(*GlobalMemfs->ToBeDeletedFileNodeSizesMutex);
970976
GlobalMemfs->ToBeDeletedFileNodeSizes->insert_or_assign(FileNode, toBeDeletedSizes);
971977
}
972978

@@ -1267,12 +1273,11 @@ static NTSTATUS GetVolumeInfo(FSP_FILE_SYSTEM* FileSystem,
12671273
{
12681274
MEMFS* Memfs = (MEMFS*)FileSystem->UserContext;
12691275

1270-
const UINT64 toBeDeletedSize = Memfs->AllocatedSizesToBeDeleted;
1276+
const UINT64 toBeDeletedSize = InterlockedExchangeAdd(&Memfs->AllocatedSizesToBeDeleted, 0ULL);
12711277
const UINT64 maxSize = MemefsGetMaxTotalSize(Memfs);
1272-
const UINT64 usedSize = MemefsGetUsedTotalSize(Memfs) - toBeDeletedSize;
12731278
const UINT64 availableSize = MemefsGetAvailableTotalSize(Memfs) + toBeDeletedSize;
12741279

1275-
VolumeInfo->TotalSize = max(maxSize, usedSize);
1280+
VolumeInfo->TotalSize = maxSize;
12761281
VolumeInfo->FreeSize = availableSize;
12771282
VolumeInfo->VolumeLabelLength = Memfs->VolumeLabelLength;
12781283
memcpy(VolumeInfo->VolumeLabel, Memfs->VolumeLabel, Memfs->VolumeLabelLength);
@@ -2670,7 +2675,8 @@ NTSTATUS MemfsCreateFunnel(
26702675
}
26712676

26722677
// memefs: New ToBeDeletedFileNodeSizes
2673-
Memfs->ToBeDeletedFileNodeSizes = new std::map<MEMFS_FILE_NODE*, UINT64>();
2678+
Memfs->ToBeDeletedFileNodeSizes = new std::unordered_map<MEMFS_FILE_NODE*, UINT64>();
2679+
Memfs->ToBeDeletedFileNodeSizesMutex = new std::mutex();
26742680

26752681
memset(&VolumeParams, 0, sizeof VolumeParams);
26762682
VolumeParams.Version = sizeof FSP_FSCTL_VOLUME_PARAMS;
@@ -2717,6 +2723,7 @@ NTSTATUS MemfsCreateFunnel(
27172723
{
27182724
MemfsFileNodeMapDelete(Memfs->FileNodeMap);
27192725
delete Memfs->ToBeDeletedFileNodeSizes;
2726+
delete Memfs->ToBeDeletedFileNodeSizesMutex;
27202727
free(Memfs);
27212728
LocalFree(RootSecurity);
27222729
return Result;
@@ -2786,6 +2793,7 @@ VOID MemfsDelete(MEMFS* Memfs)
27862793

27872794
MemfsFileNodeMapDelete(Memfs->FileNodeMap);
27882795
delete Memfs->ToBeDeletedFileNodeSizes;
2796+
delete Memfs->ToBeDeletedFileNodeSizesMutex;
27892797

27902798
free(Memfs);
27912799
}

0 commit comments

Comments
 (0)