Update memfs.cpp

This commit is contained in:
John Oberschelp 2017-10-31 15:44:24 -07:00 committed by GitHub
parent 76ff8232bc
commit 111955db84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -43,6 +43,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
*/ */
#define MEMFS_NAMED_STREAMS #define MEMFS_NAMED_STREAMS
/*
* Define the MEMFS_SLOWIO macro to include delayed I/O response support.
*/
//#define MEMFS_SLOWIO
/* /*
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes * Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
* a check for the Write buffer to ensure that it is read-only. * a check for the Write buffer to ensure that it is read-only.
@ -271,11 +276,12 @@ typedef struct _MEMFS
MEMFS_FILE_NODE_MAP *FileNodeMap; MEMFS_FILE_NODE_MAP *FileNodeMap;
ULONG MaxFileNodes; ULONG MaxFileNodes;
ULONG MaxFileSize; ULONG MaxFileSize;
#ifdef MEMFS_SLOWIO
ULONG SlowioMaxDelay; ULONG SlowioMaxDelay;
ULONG SlowioPercentDelay; ULONG SlowioPercentDelay;
ULONG SlowioRarefyDelay; ULONG SlowioRarefyDelay;
volatile LONG SlowioThreadsRunning;
#endif
UINT16 VolumeLabelLength; UINT16 VolumeLabelLength;
WCHAR VolumeLabel[32]; WCHAR VolumeLabel[32];
} MEMFS; } MEMFS;
@ -641,23 +647,21 @@ VOID MemfsFileNodeMapEnumerateFree(MEMFS_FILE_NODE_MAP_ENUM_CONTEXT *Context)
free(Context->FileNodes); free(Context->FileNodes);
} }
////////////////////////////////////////////////////////////////////// #ifdef MEMFS_SLOWIO
//////////////////////////////////////////////////////////////////////
/* /*
* * SLOWIO
* Slowio is included for two uses: *
* * This is included for two uses:
* 1) For testing winfsp, by allowing memfs to act more like a non-ram file system, *
* with some slow IO taking many milliseconds, and some IO completion delayed. * 1) For testing winfsp, by allowing memfs to act more like a non-ram file system,
* * with some IO taking many milliseconds, and some IO completion delayed.
* 2) As sample code for how to use winfsp's STATUS_PENDING capabilities. *
* * 2) As sample code for how to use winfsp's STATUS_PENDING capabilities.
* If you aren't testing winfsp, leave SlowioMaxDelay at 0. *
* */
*/
inline uint64_t hash(uint64_t x) inline UINT64 Hash(UINT64 x)
{ {
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ull; x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ull;
x = (x ^ (x >> 27)) * 0x94d049bb133111ebull; x = (x ^ (x >> 27)) * 0x94d049bb133111ebull;
@ -665,122 +669,109 @@ inline uint64_t hash(uint64_t x)
return x; return x;
} }
unsigned int pseudoRandom(unsigned int to) unsigned int PseudoRandom(unsigned int to)
{ {
static uint64_t spin = 1; static UINT64 spin = 0;
return hash(spin++) % to; InterlockedIncrement(&spin);
return Hash(spin) % to;
} }
int SlowioShouldPostpone(FSP_FILE_SYSTEM *FileSystem) int SlowioReturnPending(FSP_FILE_SYSTEM *FileSystem)
{ {
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
return pseudoRandom(100) < Memfs->SlowioPercentDelay; return PseudoRandom(100) < Memfs->SlowioPercentDelay;
} }
int SlowioMillisecondsOfDelay(FSP_FILE_SYSTEM *FileSystem) int SlowioMillisecondsOfDelay(FSP_FILE_SYSTEM *FileSystem)
{ {
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
if ( ! Memfs->SlowioMaxDelay ) return 0; int milliseconds = PseudoRandom(Memfs->SlowioMaxDelay+1) >> PseudoRandom(Memfs->SlowioRarefyDelay+1);
int milliseconds = pseudoRandom(Memfs->SlowioMaxDelay) >> pseudoRandom(Memfs->SlowioRarefyDelay); return milliseconds;
return milliseconds;
} }
volatile LONG ioThreadsRunning; void SlowioReadThread(
FSP_FILE_SYSTEM *FileSystem,
//////////////////////////////////////////////////////////////////////
void readThread(
FSP_FILE_SYSTEM *FileSystem,
MEMFS_FILE_NODE *FileNode, MEMFS_FILE_NODE *FileNode,
PVOID Buffer, PVOID Buffer,
UINT64 Offset, UINT64 Offset,
UINT64 EndOffset, UINT64 EndOffset,
UINT64 RequestHint) UINT64 RequestHint)
{ {
InterlockedIncrement(&ioThreadsRunning); MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
int ms = SlowioMillisecondsOfDelay(FileSystem); int ms = SlowioMillisecondsOfDelay(FileSystem);
if (ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms)); if (ms) Sleep(ms);
memcpy(Buffer, (PUINT8)FileNode->FileData + Offset, (size_t)(EndOffset - Offset)); memcpy(Buffer, (PUINT8)FileNode->FileData + Offset, (size_t)(EndOffset - Offset));
UINT32 BytesTransferred = (ULONG)(EndOffset - Offset); UINT32 BytesTransferred = (ULONG)(EndOffset - Offset);
FSP_FSCTL_TRANSACT_RSP ResponseBuf; FSP_FSCTL_TRANSACT_RSP ResponseBuf;
memset(&ResponseBuf, 0, sizeof ResponseBuf); memset(&ResponseBuf, 0, sizeof ResponseBuf);
ResponseBuf.Size = sizeof ResponseBuf; ResponseBuf.Size = sizeof ResponseBuf;
ResponseBuf.Kind = FspFsctlTransactReadKind; ResponseBuf.Kind = FspFsctlTransactReadKind;
ResponseBuf.Hint = RequestHint; // IRP that is being completed ResponseBuf.Hint = RequestHint; // IRP that is being completed
ResponseBuf.IoStatus.Status = STATUS_SUCCESS; ResponseBuf.IoStatus.Status = STATUS_SUCCESS;
ResponseBuf.IoStatus.Information = BytesTransferred; // bytes read ResponseBuf.IoStatus.Information = BytesTransferred; // bytes read
FspFileSystemSendResponse(FileSystem, &ResponseBuf); FspFileSystemSendResponse(FileSystem, &ResponseBuf);
InterlockedDecrement(&ioThreadsRunning); InterlockedDecrement(&Memfs->SlowioThreadsRunning);
} }
////////////////////////////////////////////////////////////////////// void SlowioWriteThread(
FSP_FILE_SYSTEM *FileSystem,
void writeThread(
FSP_FILE_SYSTEM *FileSystem,
MEMFS_FILE_NODE *FileNode, MEMFS_FILE_NODE *FileNode,
PVOID Buffer, PVOID Buffer,
UINT64 Offset, UINT64 Offset,
UINT64 EndOffset, UINT64 EndOffset,
UINT64 RequestHint, UINT64 RequestHint,
FSP_FSCTL_FILE_INFO *FileInfo) FSP_FSCTL_FILE_INFO *FileInfo)
{ {
InterlockedIncrement(&ioThreadsRunning); MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
int ms = SlowioMillisecondsOfDelay(FileSystem); int ms = SlowioMillisecondsOfDelay(FileSystem);
if (ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms)); if (ms) Sleep(ms);
memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset)); memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset));
UINT32 BytesTransferred = (ULONG)(EndOffset - Offset); UINT32 BytesTransferred = (ULONG)(EndOffset - Offset);
FSP_FSCTL_TRANSACT_RSP ResponseBuf; FSP_FSCTL_TRANSACT_RSP ResponseBuf;
memset(&ResponseBuf, 0, sizeof ResponseBuf); memset(&ResponseBuf, 0, sizeof ResponseBuf);
ResponseBuf.Size = sizeof ResponseBuf; ResponseBuf.Size = sizeof ResponseBuf;
ResponseBuf.Kind = FspFsctlTransactWriteKind; ResponseBuf.Kind = FspFsctlTransactWriteKind;
ResponseBuf.Hint = RequestHint; // IRP that is being completed ResponseBuf.Hint = RequestHint; // IRP that is being completed
ResponseBuf.IoStatus.Status = STATUS_SUCCESS; ResponseBuf.IoStatus.Status = STATUS_SUCCESS;
ResponseBuf.IoStatus.Information = BytesTransferred; // bytes written ResponseBuf.IoStatus.Information = BytesTransferred; // bytes written
ResponseBuf.Rsp.Write.FileInfo = *FileInfo; // FileInfo of file after Write ResponseBuf.Rsp.Write.FileInfo = *FileInfo; // FileInfo of file after Write
FspFileSystemSendResponse(FileSystem, &ResponseBuf); FspFileSystemSendResponse(FileSystem, &ResponseBuf);
InterlockedDecrement(&ioThreadsRunning); InterlockedDecrement(&Memfs->SlowioThreadsRunning);
} }
////////////////////////////////////////////////////////////////////// void SlowioReadDirectoryThread(
FSP_FILE_SYSTEM *FileSystem,
void readDirectoryThread( ULONG BytesTransferred,
FSP_FILE_SYSTEM *FileSystem, UINT64 RequestHint)
PVOID Buffer,
MEMFS *Memfs,
PWSTR Marker,
ULONG BytesTransferred,
UINT64 RequestHint)
{ {
InterlockedIncrement(&ioThreadsRunning); MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
int ms = SlowioMillisecondsOfDelay(FileSystem); int ms = SlowioMillisecondsOfDelay(FileSystem);
if (ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms)); if (ms) Sleep(ms);
FSP_FSCTL_TRANSACT_RSP ResponseBuf; FSP_FSCTL_TRANSACT_RSP ResponseBuf;
memset(&ResponseBuf, 0, sizeof ResponseBuf); memset(&ResponseBuf, 0, sizeof ResponseBuf);
ResponseBuf.Size = sizeof ResponseBuf; ResponseBuf.Size = sizeof ResponseBuf;
ResponseBuf.Kind = FspFsctlTransactQueryDirectoryKind; ResponseBuf.Kind = FspFsctlTransactQueryDirectoryKind;
ResponseBuf.Hint = RequestHint; // IRP that is being completed ResponseBuf.Hint = RequestHint; // IRP that is being completed
ResponseBuf.IoStatus.Status = STATUS_SUCCESS; ResponseBuf.IoStatus.Status = STATUS_SUCCESS;
ResponseBuf.IoStatus.Information = BytesTransferred; // bytes of directory info read ResponseBuf.IoStatus.Information = BytesTransferred; // bytes of directory info read
FspFileSystemSendResponse(FileSystem, &ResponseBuf); FspFileSystemSendResponse(FileSystem, &ResponseBuf);
InterlockedDecrement(&ioThreadsRunning); InterlockedDecrement(&Memfs->SlowioThreadsRunning);
} }
#endif
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
/* /*
* FSP_FILE_SYSTEM_INTERFACE * FSP_FILE_SYSTEM_INTERFACE
@ -1165,20 +1156,28 @@ static NTSTATUS Read(FSP_FILE_SYSTEM *FileSystem,
if (EndOffset > FileNode->FileInfo.FileSize) if (EndOffset > FileNode->FileInfo.FileSize)
EndOffset = FileNode->FileInfo.FileSize; EndOffset = FileNode->FileInfo.FileSize;
#ifdef MEMFS_SLOWIO
if (SlowioShouldPostpone(FileSystem)) int ms = SlowioMillisecondsOfDelay(FileSystem);
{ if (ms) Sleep(ms);
FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request; if (SlowioReturnPending(FileSystem))
UINT64 RequestHint = Request->Hint; {
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
std::thread rt = std::thread(readThread, FileSystem, FileNode, Buffer, Offset, EndOffset, RequestHint); FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request;
rt.detach(); UINT64 RequestHint = Request->Hint;
InterlockedIncrement(&Memfs->SlowioThreadsRunning);
return STATUS_PENDING; try {
} auto Thread = std::thread(SlowioReadThread, FileSystem, FileNode, Buffer, Offset, EndOffset, RequestHint);
int ms = SlowioMillisecondsOfDelay(FileSystem); Thread.detach();
if (ms) Sleep(ms); }
catch (...)
{
InterlockedDecrement(&Memfs->SlowioThreadsRunning);
goto regular;
}
return STATUS_PENDING;
}
regular:
#endif
memcpy(Buffer, (PUINT8)FileNode->FileData + Offset, (size_t)(EndOffset - Offset)); memcpy(Buffer, (PUINT8)FileNode->FileData + Offset, (size_t)(EndOffset - Offset));
@ -1233,20 +1232,28 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
} }
} }
#ifdef MEMFS_SLOWIO
if (SlowioShouldPostpone(FileSystem)) int ms = SlowioMillisecondsOfDelay(FileSystem);
{ if (ms) Sleep(ms);
FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request; if (SlowioReturnPending(FileSystem))
UINT64 RequestHint = Request->Hint; {
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
std::thread wt = std::thread(writeThread, FileSystem, FileNode, Buffer, Offset, EndOffset, RequestHint, FileInfo); FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request;
wt.detach(); UINT64 RequestHint = Request->Hint;
InterlockedIncrement(&Memfs->SlowioThreadsRunning);
return STATUS_PENDING; try {
} auto Thread = std::thread(SlowioWriteThread, FileSystem, FileNode, Buffer, Offset, EndOffset, RequestHint, FileInfo);
int ms = SlowioMillisecondsOfDelay(FileSystem); Thread.detach();
if (ms) Sleep(ms); }
catch (...)
{
InterlockedDecrement(&Memfs->SlowioThreadsRunning);
goto regular;
}
return STATUS_PENDING;
}
regular:
#endif
memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset)); memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset));
@ -1615,20 +1622,27 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
ReadDirectoryEnumFn, &Context)) ReadDirectoryEnumFn, &Context))
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred); FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
#ifdef MEMFS_SLOWIO
if (SlowioShouldPostpone(FileSystem)) int ms = SlowioMillisecondsOfDelay(FileSystem);
{ if (ms) Sleep(ms);
FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request; if (SlowioReturnPending(FileSystem))
UINT64 RequestHint = Request->Hint; {
FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request;
std::thread rdt = std::thread(readDirectoryThread, FileSystem, Buffer, Memfs, Marker, *PBytesTransferred, RequestHint); UINT64 RequestHint = Request->Hint;
rdt.detach(); InterlockedIncrement(&Memfs->SlowioThreadsRunning);
try {
return STATUS_PENDING; auto Thread = std::thread(SlowioReadDirectoryThread, FileSystem, *PBytesTransferred, RequestHint);
} Thread.detach();
int ms = SlowioMillisecondsOfDelay(FileSystem); }
if (ms) Sleep(ms); catch (...)
{
InterlockedDecrement(&Memfs->SlowioThreadsRunning);
goto regular;
}
return STATUS_PENDING;
}
regular:
#endif
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -1884,11 +1898,9 @@ NTSTATUS MemfsCreateFunnel(
ULONG FileInfoTimeout, ULONG FileInfoTimeout,
ULONG MaxFileNodes, ULONG MaxFileNodes,
ULONG MaxFileSize, ULONG MaxFileSize,
ULONG SlowioMaxDelay,
ULONG SlowioMaxDelay,
ULONG SlowioPercentDelay, ULONG SlowioPercentDelay,
ULONG SlowioRarefyDelay, ULONG SlowioRarefyDelay,
PWSTR FileSystemName, PWSTR FileSystemName,
PWSTR VolumePrefix, PWSTR VolumePrefix,
PWSTR RootSddl, PWSTR RootSddl,
@ -1930,9 +1942,11 @@ NTSTATUS MemfsCreateFunnel(
AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT; AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT;
Memfs->MaxFileSize = (ULONG)((MaxFileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit); Memfs->MaxFileSize = (ULONG)((MaxFileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit);
Memfs->SlowioMaxDelay = SlowioMaxDelay; #ifdef MEMFS_SLOWIO
Memfs->SlowioMaxDelay = SlowioMaxDelay;
Memfs->SlowioPercentDelay = SlowioPercentDelay; Memfs->SlowioPercentDelay = SlowioPercentDelay;
Memfs->SlowioRarefyDelay = SlowioRarefyDelay; Memfs->SlowioRarefyDelay = SlowioRarefyDelay;
#endif
Result = MemfsFileNodeMapCreate(CaseInsensitive, &Memfs->FileNodeMap); Result = MemfsFileNodeMapCreate(CaseInsensitive, &Memfs->FileNodeMap);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
@ -2033,16 +2047,20 @@ VOID MemfsDelete(MEMFS *Memfs)
NTSTATUS MemfsStart(MEMFS *Memfs) NTSTATUS MemfsStart(MEMFS *Memfs)
{ {
ioThreadsRunning = 0; #ifdef MEMFS_SLOWIO
Memfs->SlowioThreadsRunning = 0;
#endif
return FspFileSystemStartDispatcher(Memfs->FileSystem, 0); return FspFileSystemStartDispatcher(Memfs->FileSystem, 0);
} }
VOID MemfsStop(MEMFS *Memfs) VOID MemfsStop(MEMFS *Memfs)
{ {
while (ioThreadsRunning) Sleep(1);
FspFileSystemStopDispatcher(Memfs->FileSystem); FspFileSystemStopDispatcher(Memfs->FileSystem);
#ifdef MEMFS_SLOWIO
while (Memfs->SlowioThreadsRunning) Sleep(1);
#endif
} }
FSP_FILE_SYSTEM *MemfsFileSystem(MEMFS *Memfs) FSP_FILE_SYSTEM *MemfsFileSystem(MEMFS *Memfs)