From 0da43fe2d49f893f70a77d1f692951d2352bff6e Mon Sep 17 00:00:00 2001 From: John Oberschelp Date: Mon, 9 Oct 2017 14:46:24 -0700 Subject: [PATCH 01/12] Update memfs.cpp --- tst/memfs/memfs.cpp | 205 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/tst/memfs/memfs.cpp b/tst/memfs/memfs.cpp index 7ccf637c..7a2c1fce 100644 --- a/tst/memfs/memfs.cpp +++ b/tst/memfs/memfs.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #define MEMFS_MAX_PATH 512 FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH, @@ -270,6 +271,11 @@ typedef struct _MEMFS MEMFS_FILE_NODE_MAP *FileNodeMap; ULONG MaxFileNodes; ULONG MaxFileSize; + + ULONG SlowioMaxDelay; + ULONG SlowioPercentDelay; + ULONG SlowioRarefyDelay; + UINT16 VolumeLabelLength; WCHAR VolumeLabel[32]; } MEMFS; @@ -635,6 +641,147 @@ VOID MemfsFileNodeMapEnumerateFree(MEMFS_FILE_NODE_MAP_ENUM_CONTEXT *Context) free(Context->FileNodes); } +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// + + /* + * + * Slowio 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. + * + * 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) +{ + x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ull; + x = (x ^ (x >> 27)) * 0x94d049bb133111ebull; + x = x ^ (x >> 31); + return x; +} + +unsigned int pseudoRandom(unsigned int to) +{ + static uint64_t spin = 1; + return hash(spin++) % to; +} + +int SlowioShouldPostpone(FSP_FILE_SYSTEM *FileSystem) +{ + MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; + return pseudoRandom(100) < Memfs->SlowioPercentDelay; +} + +int SlowioMillisecondsOfDelay(FSP_FILE_SYSTEM *FileSystem) +{ + MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; + if ( ! Memfs->SlowioMaxDelay ) return 0; + int milliseconds = pseudoRandom(Memfs->SlowioMaxDelay) >> pseudoRandom(Memfs->SlowioRarefyDelay); + return milliseconds; +} + +volatile LONG ioThreadsRunning; + +////////////////////////////////////////////////////////////////////// + +void readThread( + FSP_FILE_SYSTEM *FileSystem, + MEMFS_FILE_NODE *FileNode, + PVOID Buffer, + UINT64 Offset, + UINT64 EndOffset, + UINT64 RequestHint) +{ + InterlockedIncrement(&ioThreadsRunning); + + int ms = SlowioMillisecondsOfDelay(FileSystem); + if (ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + + memcpy(Buffer, (PUINT8)FileNode->FileData + Offset, (size_t)(EndOffset - Offset)); + UINT32 BytesTransferred = (ULONG)(EndOffset - Offset); + + FSP_FSCTL_TRANSACT_RSP ResponseBuf; + memset(&ResponseBuf, 0, sizeof ResponseBuf); + ResponseBuf.Size = sizeof ResponseBuf; + ResponseBuf.Kind = FspFsctlTransactReadKind; + ResponseBuf.Hint = RequestHint; // IRP that is being completed + ResponseBuf.IoStatus.Status = STATUS_SUCCESS; + ResponseBuf.IoStatus.Information = BytesTransferred; // bytes read + + FspFileSystemSendResponse(FileSystem, &ResponseBuf); + + InterlockedDecrement(&ioThreadsRunning); +} + +////////////////////////////////////////////////////////////////////// + +void writeThread( + FSP_FILE_SYSTEM *FileSystem, + MEMFS_FILE_NODE *FileNode, + PVOID Buffer, + UINT64 Offset, + UINT64 EndOffset, + UINT64 RequestHint, + FSP_FSCTL_FILE_INFO *FileInfo) +{ + InterlockedIncrement(&ioThreadsRunning); + + int ms = SlowioMillisecondsOfDelay(FileSystem); + if (ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + + memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset)); + UINT32 BytesTransferred = (ULONG)(EndOffset - Offset); + + FSP_FSCTL_TRANSACT_RSP ResponseBuf; + memset(&ResponseBuf, 0, sizeof ResponseBuf); + ResponseBuf.Size = sizeof ResponseBuf; + ResponseBuf.Kind = FspFsctlTransactWriteKind; + ResponseBuf.Hint = RequestHint; // IRP that is being completed + ResponseBuf.IoStatus.Status = STATUS_SUCCESS; + ResponseBuf.IoStatus.Information = BytesTransferred; // bytes written + ResponseBuf.Rsp.Write.FileInfo = *FileInfo; // FileInfo of file after Write + + FspFileSystemSendResponse(FileSystem, &ResponseBuf); + + InterlockedDecrement(&ioThreadsRunning); +} + +////////////////////////////////////////////////////////////////////// + +void readDirectoryThread( + FSP_FILE_SYSTEM *FileSystem, + PVOID Buffer, + MEMFS *Memfs, + PWSTR Marker, + ULONG BytesTransferred, + UINT64 RequestHint) +{ + InterlockedIncrement(&ioThreadsRunning); + + int ms = SlowioMillisecondsOfDelay(FileSystem); + if (ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + + FSP_FSCTL_TRANSACT_RSP ResponseBuf; + memset(&ResponseBuf, 0, sizeof ResponseBuf); + ResponseBuf.Size = sizeof ResponseBuf; + ResponseBuf.Kind = FspFsctlTransactQueryDirectoryKind; + ResponseBuf.Hint = RequestHint; // IRP that is being completed + ResponseBuf.IoStatus.Status = STATUS_SUCCESS; + ResponseBuf.IoStatus.Information = BytesTransferred; // bytes of directory info read + + FspFileSystemSendResponse(FileSystem, &ResponseBuf); + + InterlockedDecrement(&ioThreadsRunning); +} + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// + /* * FSP_FILE_SYSTEM_INTERFACE */ @@ -1018,6 +1165,21 @@ static NTSTATUS Read(FSP_FILE_SYSTEM *FileSystem, if (EndOffset > FileNode->FileInfo.FileSize) EndOffset = FileNode->FileInfo.FileSize; + + if (SlowioShouldPostpone(FileSystem)) + { + FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request; + UINT64 RequestHint = Request->Hint; + + std::thread rt = std::thread(readThread, FileSystem, FileNode, Buffer, Offset, EndOffset, RequestHint); + rt.detach(); + + return STATUS_PENDING; + } + int ms = SlowioMillisecondsOfDelay(FileSystem); + if (ms) Sleep(ms); + + memcpy(Buffer, (PUINT8)FileNode->FileData + Offset, (size_t)(EndOffset - Offset)); *PBytesTransferred = (ULONG)(EndOffset - Offset); @@ -1071,6 +1233,21 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem, } } + + if (SlowioShouldPostpone(FileSystem)) + { + FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request; + UINT64 RequestHint = Request->Hint; + + std::thread wt = std::thread(writeThread, FileSystem, FileNode, Buffer, Offset, EndOffset, RequestHint, FileInfo); + wt.detach(); + + return STATUS_PENDING; + } + int ms = SlowioMillisecondsOfDelay(FileSystem); + if (ms) Sleep(ms); + + memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset)); *PBytesTransferred = (ULONG)(EndOffset - Offset); @@ -1438,6 +1615,21 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem, ReadDirectoryEnumFn, &Context)) FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred); + + if (SlowioShouldPostpone(FileSystem)) + { + FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request; + UINT64 RequestHint = Request->Hint; + + std::thread rdt = std::thread(readDirectoryThread, FileSystem, Buffer, Memfs, Marker, *PBytesTransferred, RequestHint); + rdt.detach(); + + return STATUS_PENDING; + } + int ms = SlowioMillisecondsOfDelay(FileSystem); + if (ms) Sleep(ms); + + return STATUS_SUCCESS; } @@ -1692,6 +1884,11 @@ NTSTATUS MemfsCreateFunnel( ULONG FileInfoTimeout, ULONG MaxFileNodes, ULONG MaxFileSize, + + ULONG SlowioMaxDelay, + ULONG SlowioPercentDelay, + ULONG SlowioRarefyDelay, + PWSTR FileSystemName, PWSTR VolumePrefix, PWSTR RootSddl, @@ -1733,6 +1930,10 @@ NTSTATUS MemfsCreateFunnel( AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT; Memfs->MaxFileSize = (ULONG)((MaxFileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit); + Memfs->SlowioMaxDelay = SlowioMaxDelay; + Memfs->SlowioPercentDelay = SlowioPercentDelay; + Memfs->SlowioRarefyDelay = SlowioRarefyDelay; + Result = MemfsFileNodeMapCreate(CaseInsensitive, &Memfs->FileNodeMap); if (!NT_SUCCESS(Result)) { @@ -1832,11 +2033,15 @@ VOID MemfsDelete(MEMFS *Memfs) NTSTATUS MemfsStart(MEMFS *Memfs) { + ioThreadsRunning = 0; + return FspFileSystemStartDispatcher(Memfs->FileSystem, 0); } VOID MemfsStop(MEMFS *Memfs) { + while (ioThreadsRunning) Sleep(1); + FspFileSystemStopDispatcher(Memfs->FileSystem); } From 0fb6299f1704eefd889b5f5520dc0350c0687a1b Mon Sep 17 00:00:00 2001 From: John Oberschelp Date: Mon, 9 Oct 2017 14:47:28 -0700 Subject: [PATCH 02/12] Update memfs-main.c --- tst/memfs/memfs-main.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tst/memfs/memfs-main.c b/tst/memfs/memfs-main.c index edebbfea..b2b0aaab 100644 --- a/tst/memfs/memfs-main.c +++ b/tst/memfs/memfs-main.c @@ -44,6 +44,11 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) ULONG FileInfoTimeout = INFINITE; ULONG MaxFileNodes = 1024; ULONG MaxFileSize = 16 * 1024 * 1024; + + ULONG SlowioMaxDelay = 0; // From -M : maximum delay in milliseconds + ULONG SlowioPercentDelay = 0; // From -D : percent of IO to slow down + ULONG SlowioRarefyDelay = 12; // From -R : adjust the rarity of long delays + PWSTR FileSystemName = 0; PWSTR MountPoint = 0; PWSTR VolumePrefix = 0; @@ -75,9 +80,18 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) case L'm': argtos(MountPoint); break; + case L'M': + argtol(SlowioMaxDelay); + break; case L'n': argtol(MaxFileNodes); break; + case L'P': + argtol(SlowioPercentDelay); + break; + case L'R': + argtol(SlowioRarefyDelay); + break; case L'S': argtos(RootSddl); break; @@ -130,6 +144,11 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) FileInfoTimeout, MaxFileNodes, MaxFileSize, + + SlowioMaxDelay, + SlowioPercentDelay, + SlowioRarefyDelay, + FileSystemName, VolumePrefix, RootSddl, @@ -189,6 +208,11 @@ usage: " -t FileInfoTimeout [millis]\n" " -n MaxFileNodes\n" " -s MaxFileSize [bytes]\n" + + " -M MaxDelay [maximum slow IO delay in millis]\n" + " -P PercentDelay [percent of IO to make slow IO\n" + " -R RarefyDelay [adjust the rarity of slow IO\n" + " -F FileSystemName\n" " -S RootSddl [file rights: FA, etc; NO generic rights: GA, etc.]\n" " -u \\Server\\Share [UNC prefix (single backslash)]\n" From 1468df78a2a3c4870a385ca4666447491823594d Mon Sep 17 00:00:00 2001 From: John Oberschelp Date: Mon, 9 Oct 2017 14:48:33 -0700 Subject: [PATCH 03/12] Update memfs.h --- tst/memfs/memfs.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tst/memfs/memfs.h b/tst/memfs/memfs.h index a88ac9bd..d3509915 100644 --- a/tst/memfs/memfs.h +++ b/tst/memfs/memfs.h @@ -33,13 +33,18 @@ enum MemfsCaseInsensitive = 0x80, }; -#define MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl, PMemfs)\ - MemfsCreateFunnel(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, 0, VolumePrefix, RootSddl, PMemfs) +#define MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, SlowioMaxDelay, SlowioPercentDelay, SlowioRarefyDelay, VolumePrefix, RootSddl, PMemfs)\ + MemfsCreateFunnel(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, SlowioMaxDelay, SlowioPercentDelay, SlowioRarefyDelay, 0, VolumePrefix, RootSddl, PMemfs) NTSTATUS MemfsCreateFunnel( ULONG Flags, ULONG FileInfoTimeout, ULONG MaxFileNodes, ULONG MaxFileSize, + + ULONG SlowioMaxDelay, + ULONG SlowioPercentDelay, + ULONG SlowioRarefyDelay, + PWSTR FileSystemName, PWSTR VolumePrefix, PWSTR RootSddl, From c9b2c0460b3bd998eef5df877fb1df7643fb088f Mon Sep 17 00:00:00 2001 From: John Oberschelp Date: Mon, 9 Oct 2017 14:49:50 -0700 Subject: [PATCH 04/12] Update fscrash-main.c --- tst/fscrash/fscrash-main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tst/fscrash/fscrash-main.c b/tst/fscrash/fscrash-main.c index defb785e..4eb84d5a 100644 --- a/tst/fscrash/fscrash-main.c +++ b/tst/fscrash/fscrash-main.c @@ -278,6 +278,9 @@ int wmain(int argc, wchar_t **argv) OptFileInfoTimeout, 1024, 1024 * 1024, + + 0,0,0, // Slowio + (MemfsNet & OptMemfsFlags) ? L"\\memfs\\share" : 0, 0, &Memfs); From 045a1fa19ce92c4af35c3f8b67a5919063063e7b Mon Sep 17 00:00:00 2001 From: John Oberschelp Date: Mon, 9 Oct 2017 14:51:18 -0700 Subject: [PATCH 05/12] Update memfs-test.c --- tst/winfsp-tests/memfs-test.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tst/winfsp-tests/memfs-test.c b/tst/winfsp-tests/memfs-test.c index 5f6d8834..2bfa6cf9 100644 --- a/tst/winfsp-tests/memfs-test.c +++ b/tst/winfsp-tests/memfs-test.c @@ -40,7 +40,10 @@ void *memfs_start_ex(ULONG Flags, ULONG FileInfoTimeout) FileInfoTimeout, 1024, 1024 * 1024, - MemfsNet == Flags ? L"\\memfs\\share" : 0, + + 0,0,0, // Slowio + + MemfsNet == Flags ? L"\\memfs\\share" : 0, 0, &Memfs); ASSERT(NT_SUCCESS(Result)); From 91c714dd5384844d58f296ccbdd6c7d2ee41ff0c Mon Sep 17 00:00:00 2001 From: John Oberschelp Date: Tue, 31 Oct 2017 15:32:12 -0700 Subject: [PATCH 06/12] Update fscrash-main.c --- tst/fscrash/fscrash-main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tst/fscrash/fscrash-main.c b/tst/fscrash/fscrash-main.c index 4eb84d5a..defb785e 100644 --- a/tst/fscrash/fscrash-main.c +++ b/tst/fscrash/fscrash-main.c @@ -278,9 +278,6 @@ int wmain(int argc, wchar_t **argv) OptFileInfoTimeout, 1024, 1024 * 1024, - - 0,0,0, // Slowio - (MemfsNet & OptMemfsFlags) ? L"\\memfs\\share" : 0, 0, &Memfs); From 4adc0d4700e64e5f13151ea2293bf4674adf5cb1 Mon Sep 17 00:00:00 2001 From: John Oberschelp Date: Tue, 31 Oct 2017 15:36:09 -0700 Subject: [PATCH 07/12] Update memfs-test.c --- tst/winfsp-tests/memfs-test.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tst/winfsp-tests/memfs-test.c b/tst/winfsp-tests/memfs-test.c index 2bfa6cf9..5f6d8834 100644 --- a/tst/winfsp-tests/memfs-test.c +++ b/tst/winfsp-tests/memfs-test.c @@ -40,10 +40,7 @@ void *memfs_start_ex(ULONG Flags, ULONG FileInfoTimeout) FileInfoTimeout, 1024, 1024 * 1024, - - 0,0,0, // Slowio - - MemfsNet == Flags ? L"\\memfs\\share" : 0, + MemfsNet == Flags ? L"\\memfs\\share" : 0, 0, &Memfs); ASSERT(NT_SUCCESS(Result)); From 9a3ac3c7a1183eacf8d66ff05f703f1f134d8c9d Mon Sep 17 00:00:00 2001 From: John Oberschelp Date: Tue, 31 Oct 2017 15:39:19 -0700 Subject: [PATCH 08/12] Update memfs.h --- tst/memfs/memfs.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tst/memfs/memfs.h b/tst/memfs/memfs.h index d3509915..22970b4e 100644 --- a/tst/memfs/memfs.h +++ b/tst/memfs/memfs.h @@ -33,18 +33,16 @@ enum MemfsCaseInsensitive = 0x80, }; -#define MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, SlowioMaxDelay, SlowioPercentDelay, SlowioRarefyDelay, VolumePrefix, RootSddl, PMemfs)\ - MemfsCreateFunnel(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, SlowioMaxDelay, SlowioPercentDelay, SlowioRarefyDelay, 0, VolumePrefix, RootSddl, PMemfs) +#define MemfsCreate(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, VolumePrefix, RootSddl, PMemfs)\ + MemfsCreateFunnel(Flags, FileInfoTimeout, MaxFileNodes, MaxFileSize, 0, 0, 0, 0, VolumePrefix, RootSddl, PMemfs) NTSTATUS MemfsCreateFunnel( ULONG Flags, ULONG FileInfoTimeout, ULONG MaxFileNodes, ULONG MaxFileSize, - - ULONG SlowioMaxDelay, + ULONG SlowioMaxDelay, ULONG SlowioPercentDelay, ULONG SlowioRarefyDelay, - PWSTR FileSystemName, PWSTR VolumePrefix, PWSTR RootSddl, From 76ff8232bc79b0c3b45daac9e67c53c3b6318d19 Mon Sep 17 00:00:00 2001 From: John Oberschelp Date: Tue, 31 Oct 2017 15:42:26 -0700 Subject: [PATCH 09/12] Update memfs-main.c --- tst/memfs/memfs-main.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/tst/memfs/memfs-main.c b/tst/memfs/memfs-main.c index b2b0aaab..8f19988f 100644 --- a/tst/memfs/memfs-main.c +++ b/tst/memfs/memfs-main.c @@ -44,11 +44,9 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) ULONG FileInfoTimeout = INFINITE; ULONG MaxFileNodes = 1024; ULONG MaxFileSize = 16 * 1024 * 1024; - - ULONG SlowioMaxDelay = 0; // From -M : maximum delay in milliseconds - ULONG SlowioPercentDelay = 0; // From -D : percent of IO to slow down - ULONG SlowioRarefyDelay = 12; // From -R : adjust the rarity of long delays - + ULONG SlowioMaxDelay = 0; // From -M : maximum delay in milliseconds + ULONG SlowioPercentDelay = 0; // From -D : percent of IO to slow down + ULONG SlowioRarefyDelay = 0; // From -R : adjust the rarity of long delays PWSTR FileSystemName = 0; PWSTR MountPoint = 0; PWSTR VolumePrefix = 0; @@ -144,11 +142,9 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) FileInfoTimeout, MaxFileNodes, MaxFileSize, - - SlowioMaxDelay, - SlowioPercentDelay, - SlowioRarefyDelay, - + SlowioMaxDelay, + SlowioPercentDelay, + SlowioRarefyDelay, FileSystemName, VolumePrefix, RootSddl, @@ -209,7 +205,7 @@ usage: " -n MaxFileNodes\n" " -s MaxFileSize [bytes]\n" - " -M MaxDelay [maximum slow IO delay in millis]\n" + " -M MaxDelay [maximum slow IO delay in millis]\n" " -P PercentDelay [percent of IO to make slow IO\n" " -R RarefyDelay [adjust the rarity of slow IO\n" From 111955db843f89ddc83cff63f39d7854a77a3878 Mon Sep 17 00:00:00 2001 From: John Oberschelp Date: Tue, 31 Oct 2017 15:44:24 -0700 Subject: [PATCH 10/12] Update memfs.cpp --- tst/memfs/memfs.cpp | 308 +++++++++++++++++++++++--------------------- 1 file changed, 163 insertions(+), 145 deletions(-) diff --git a/tst/memfs/memfs.cpp b/tst/memfs/memfs.cpp index 7a2c1fce..110cdbe3 100644 --- a/tst/memfs/memfs.cpp +++ b/tst/memfs/memfs.cpp @@ -43,6 +43,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH, */ #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 * 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; ULONG MaxFileNodes; ULONG MaxFileSize; - - ULONG SlowioMaxDelay; +#ifdef MEMFS_SLOWIO + ULONG SlowioMaxDelay; ULONG SlowioPercentDelay; ULONG SlowioRarefyDelay; - + volatile LONG SlowioThreadsRunning; +#endif UINT16 VolumeLabelLength; WCHAR VolumeLabel[32]; } MEMFS; @@ -641,23 +647,21 @@ VOID MemfsFileNodeMapEnumerateFree(MEMFS_FILE_NODE_MAP_ENUM_CONTEXT *Context) free(Context->FileNodes); } -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// +#ifdef MEMFS_SLOWIO - /* - * - * Slowio 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. - * - * 2) As sample code for how to use winfsp's STATUS_PENDING capabilities. - * - * If you aren't testing winfsp, leave SlowioMaxDelay at 0. - * - */ +/* + * SLOWIO + * + * This is included for two uses: + * + * 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. + * + */ -inline uint64_t hash(uint64_t x) +inline UINT64 Hash(UINT64 x) { x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ull; x = (x ^ (x >> 27)) * 0x94d049bb133111ebull; @@ -665,122 +669,109 @@ inline uint64_t hash(uint64_t x) return x; } -unsigned int pseudoRandom(unsigned int to) +unsigned int PseudoRandom(unsigned int to) { - static uint64_t spin = 1; - return hash(spin++) % to; + static UINT64 spin = 0; + InterlockedIncrement(&spin); + return Hash(spin) % to; } -int SlowioShouldPostpone(FSP_FILE_SYSTEM *FileSystem) +int SlowioReturnPending(FSP_FILE_SYSTEM *FileSystem) { MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; - return pseudoRandom(100) < Memfs->SlowioPercentDelay; + return PseudoRandom(100) < Memfs->SlowioPercentDelay; } int SlowioMillisecondsOfDelay(FSP_FILE_SYSTEM *FileSystem) { MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; - if ( ! Memfs->SlowioMaxDelay ) return 0; - int milliseconds = pseudoRandom(Memfs->SlowioMaxDelay) >> pseudoRandom(Memfs->SlowioRarefyDelay); - return milliseconds; + int milliseconds = PseudoRandom(Memfs->SlowioMaxDelay+1) >> PseudoRandom(Memfs->SlowioRarefyDelay+1); + return milliseconds; } -volatile LONG ioThreadsRunning; - -////////////////////////////////////////////////////////////////////// - -void readThread( - FSP_FILE_SYSTEM *FileSystem, +void SlowioReadThread( + FSP_FILE_SYSTEM *FileSystem, MEMFS_FILE_NODE *FileNode, - PVOID Buffer, - UINT64 Offset, - UINT64 EndOffset, - UINT64 RequestHint) + PVOID Buffer, + UINT64 Offset, + UINT64 EndOffset, + UINT64 RequestHint) { - InterlockedIncrement(&ioThreadsRunning); + MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; - int ms = SlowioMillisecondsOfDelay(FileSystem); - if (ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + int ms = SlowioMillisecondsOfDelay(FileSystem); + 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); - FSP_FSCTL_TRANSACT_RSP ResponseBuf; - memset(&ResponseBuf, 0, sizeof ResponseBuf); - ResponseBuf.Size = sizeof ResponseBuf; - ResponseBuf.Kind = FspFsctlTransactReadKind; - ResponseBuf.Hint = RequestHint; // IRP that is being completed - ResponseBuf.IoStatus.Status = STATUS_SUCCESS; - ResponseBuf.IoStatus.Information = BytesTransferred; // bytes read + FSP_FSCTL_TRANSACT_RSP ResponseBuf; + memset(&ResponseBuf, 0, sizeof ResponseBuf); + ResponseBuf.Size = sizeof ResponseBuf; + ResponseBuf.Kind = FspFsctlTransactReadKind; + ResponseBuf.Hint = RequestHint; // IRP that is being completed + ResponseBuf.IoStatus.Status = STATUS_SUCCESS; + ResponseBuf.IoStatus.Information = BytesTransferred; // bytes read - FspFileSystemSendResponse(FileSystem, &ResponseBuf); + FspFileSystemSendResponse(FileSystem, &ResponseBuf); - InterlockedDecrement(&ioThreadsRunning); + InterlockedDecrement(&Memfs->SlowioThreadsRunning); } -////////////////////////////////////////////////////////////////////// - -void writeThread( - FSP_FILE_SYSTEM *FileSystem, +void SlowioWriteThread( + FSP_FILE_SYSTEM *FileSystem, MEMFS_FILE_NODE *FileNode, - PVOID Buffer, - UINT64 Offset, - UINT64 EndOffset, - UINT64 RequestHint, - FSP_FSCTL_FILE_INFO *FileInfo) + PVOID Buffer, + UINT64 Offset, + UINT64 EndOffset, + UINT64 RequestHint, + FSP_FSCTL_FILE_INFO *FileInfo) { - InterlockedIncrement(&ioThreadsRunning); + MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; - int ms = SlowioMillisecondsOfDelay(FileSystem); - if (ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms)); - + int ms = SlowioMillisecondsOfDelay(FileSystem); + if (ms) Sleep(ms); + memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset)); UINT32 BytesTransferred = (ULONG)(EndOffset - Offset); - FSP_FSCTL_TRANSACT_RSP ResponseBuf; - memset(&ResponseBuf, 0, sizeof ResponseBuf); - ResponseBuf.Size = sizeof ResponseBuf; - ResponseBuf.Kind = FspFsctlTransactWriteKind; - ResponseBuf.Hint = RequestHint; // IRP that is being completed - ResponseBuf.IoStatus.Status = STATUS_SUCCESS; - ResponseBuf.IoStatus.Information = BytesTransferred; // bytes written - ResponseBuf.Rsp.Write.FileInfo = *FileInfo; // FileInfo of file after Write + FSP_FSCTL_TRANSACT_RSP ResponseBuf; + memset(&ResponseBuf, 0, sizeof ResponseBuf); + ResponseBuf.Size = sizeof ResponseBuf; + ResponseBuf.Kind = FspFsctlTransactWriteKind; + ResponseBuf.Hint = RequestHint; // IRP that is being completed + ResponseBuf.IoStatus.Status = STATUS_SUCCESS; + ResponseBuf.IoStatus.Information = BytesTransferred; // bytes written + ResponseBuf.Rsp.Write.FileInfo = *FileInfo; // FileInfo of file after Write - FspFileSystemSendResponse(FileSystem, &ResponseBuf); + FspFileSystemSendResponse(FileSystem, &ResponseBuf); - InterlockedDecrement(&ioThreadsRunning); + InterlockedDecrement(&Memfs->SlowioThreadsRunning); } -////////////////////////////////////////////////////////////////////// - -void readDirectoryThread( - FSP_FILE_SYSTEM *FileSystem, - PVOID Buffer, - MEMFS *Memfs, - PWSTR Marker, - ULONG BytesTransferred, - UINT64 RequestHint) +void SlowioReadDirectoryThread( + FSP_FILE_SYSTEM *FileSystem, + ULONG BytesTransferred, + UINT64 RequestHint) { - InterlockedIncrement(&ioThreadsRunning); + MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; - int ms = SlowioMillisecondsOfDelay(FileSystem); - if (ms) std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + int ms = SlowioMillisecondsOfDelay(FileSystem); + if (ms) Sleep(ms); - FSP_FSCTL_TRANSACT_RSP ResponseBuf; - memset(&ResponseBuf, 0, sizeof ResponseBuf); - ResponseBuf.Size = sizeof ResponseBuf; - ResponseBuf.Kind = FspFsctlTransactQueryDirectoryKind; - ResponseBuf.Hint = RequestHint; // IRP that is being completed - ResponseBuf.IoStatus.Status = STATUS_SUCCESS; - ResponseBuf.IoStatus.Information = BytesTransferred; // bytes of directory info read + FSP_FSCTL_TRANSACT_RSP ResponseBuf; + memset(&ResponseBuf, 0, sizeof ResponseBuf); + ResponseBuf.Size = sizeof ResponseBuf; + ResponseBuf.Kind = FspFsctlTransactQueryDirectoryKind; + ResponseBuf.Hint = RequestHint; // IRP that is being completed + ResponseBuf.IoStatus.Status = STATUS_SUCCESS; + 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 @@ -1165,20 +1156,28 @@ static NTSTATUS Read(FSP_FILE_SYSTEM *FileSystem, if (EndOffset > FileNode->FileInfo.FileSize) EndOffset = FileNode->FileInfo.FileSize; - - if (SlowioShouldPostpone(FileSystem)) - { - FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request; - UINT64 RequestHint = Request->Hint; - - std::thread rt = std::thread(readThread, FileSystem, FileNode, Buffer, Offset, EndOffset, RequestHint); - rt.detach(); - - return STATUS_PENDING; - } - int ms = SlowioMillisecondsOfDelay(FileSystem); - if (ms) Sleep(ms); - +#ifdef MEMFS_SLOWIO + int ms = SlowioMillisecondsOfDelay(FileSystem); + if (ms) Sleep(ms); + if (SlowioReturnPending(FileSystem)) + { + MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; + FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request; + UINT64 RequestHint = Request->Hint; + InterlockedIncrement(&Memfs->SlowioThreadsRunning); + try { + auto Thread = std::thread(SlowioReadThread, FileSystem, FileNode, Buffer, Offset, EndOffset, RequestHint); + Thread.detach(); + } + catch (...) + { + InterlockedDecrement(&Memfs->SlowioThreadsRunning); + goto regular; + } + return STATUS_PENDING; + } +regular: +#endif memcpy(Buffer, (PUINT8)FileNode->FileData + Offset, (size_t)(EndOffset - Offset)); @@ -1233,20 +1232,28 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem, } } - - if (SlowioShouldPostpone(FileSystem)) - { - FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request; - UINT64 RequestHint = Request->Hint; - - std::thread wt = std::thread(writeThread, FileSystem, FileNode, Buffer, Offset, EndOffset, RequestHint, FileInfo); - wt.detach(); - - return STATUS_PENDING; - } - int ms = SlowioMillisecondsOfDelay(FileSystem); - if (ms) Sleep(ms); - +#ifdef MEMFS_SLOWIO + int ms = SlowioMillisecondsOfDelay(FileSystem); + if (ms) Sleep(ms); + if (SlowioReturnPending(FileSystem)) + { + MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; + FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request; + UINT64 RequestHint = Request->Hint; + InterlockedIncrement(&Memfs->SlowioThreadsRunning); + try { + auto Thread = std::thread(SlowioWriteThread, FileSystem, FileNode, Buffer, Offset, EndOffset, RequestHint, FileInfo); + Thread.detach(); + } + catch (...) + { + InterlockedDecrement(&Memfs->SlowioThreadsRunning); + goto regular; + } + return STATUS_PENDING; + } +regular: +#endif memcpy((PUINT8)FileNode->FileData + Offset, Buffer, (size_t)(EndOffset - Offset)); @@ -1615,20 +1622,27 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem, ReadDirectoryEnumFn, &Context)) FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred); - - if (SlowioShouldPostpone(FileSystem)) - { - FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request; - UINT64 RequestHint = Request->Hint; - - std::thread rdt = std::thread(readDirectoryThread, FileSystem, Buffer, Memfs, Marker, *PBytesTransferred, RequestHint); - rdt.detach(); - - return STATUS_PENDING; - } - int ms = SlowioMillisecondsOfDelay(FileSystem); - if (ms) Sleep(ms); - +#ifdef MEMFS_SLOWIO + int ms = SlowioMillisecondsOfDelay(FileSystem); + if (ms) Sleep(ms); + if (SlowioReturnPending(FileSystem)) + { + FSP_FSCTL_TRANSACT_REQ *Request = FspFileSystemGetOperationContext()->Request; + UINT64 RequestHint = Request->Hint; + InterlockedIncrement(&Memfs->SlowioThreadsRunning); + try { + auto Thread = std::thread(SlowioReadDirectoryThread, FileSystem, *PBytesTransferred, RequestHint); + Thread.detach(); + } + catch (...) + { + InterlockedDecrement(&Memfs->SlowioThreadsRunning); + goto regular; + } + return STATUS_PENDING; + } +regular: +#endif return STATUS_SUCCESS; } @@ -1884,11 +1898,9 @@ NTSTATUS MemfsCreateFunnel( ULONG FileInfoTimeout, ULONG MaxFileNodes, ULONG MaxFileSize, - - ULONG SlowioMaxDelay, + ULONG SlowioMaxDelay, ULONG SlowioPercentDelay, ULONG SlowioRarefyDelay, - PWSTR FileSystemName, PWSTR VolumePrefix, PWSTR RootSddl, @@ -1930,9 +1942,11 @@ NTSTATUS MemfsCreateFunnel( AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT; Memfs->MaxFileSize = (ULONG)((MaxFileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit); - Memfs->SlowioMaxDelay = SlowioMaxDelay; +#ifdef MEMFS_SLOWIO + Memfs->SlowioMaxDelay = SlowioMaxDelay; Memfs->SlowioPercentDelay = SlowioPercentDelay; Memfs->SlowioRarefyDelay = SlowioRarefyDelay; +#endif Result = MemfsFileNodeMapCreate(CaseInsensitive, &Memfs->FileNodeMap); if (!NT_SUCCESS(Result)) @@ -2033,16 +2047,20 @@ VOID MemfsDelete(MEMFS *Memfs) NTSTATUS MemfsStart(MEMFS *Memfs) { - ioThreadsRunning = 0; +#ifdef MEMFS_SLOWIO + Memfs->SlowioThreadsRunning = 0; +#endif return FspFileSystemStartDispatcher(Memfs->FileSystem, 0); } VOID MemfsStop(MEMFS *Memfs) { - while (ioThreadsRunning) Sleep(1); - FspFileSystemStopDispatcher(Memfs->FileSystem); + +#ifdef MEMFS_SLOWIO + while (Memfs->SlowioThreadsRunning) Sleep(1); +#endif } FSP_FILE_SYSTEM *MemfsFileSystem(MEMFS *Memfs) From 244afc8a3c76aa9726f9b440829ee08e3778da38 Mon Sep 17 00:00:00 2001 From: John Oberschelp Date: Tue, 31 Oct 2017 15:50:50 -0700 Subject: [PATCH 11/12] Update memfs-main.c --- tst/memfs/memfs-main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tst/memfs/memfs-main.c b/tst/memfs/memfs-main.c index 8f19988f..3b719ab9 100644 --- a/tst/memfs/memfs-main.c +++ b/tst/memfs/memfs-main.c @@ -204,11 +204,9 @@ usage: " -t FileInfoTimeout [millis]\n" " -n MaxFileNodes\n" " -s MaxFileSize [bytes]\n" - " -M MaxDelay [maximum slow IO delay in millis]\n" " -P PercentDelay [percent of IO to make slow IO\n" " -R RarefyDelay [adjust the rarity of slow IO\n" - " -F FileSystemName\n" " -S RootSddl [file rights: FA, etc; NO generic rights: GA, etc.]\n" " -u \\Server\\Share [UNC prefix (single backslash)]\n" From 39dd7662bd48e4c601b1752e17801114ad5c8eb5 Mon Sep 17 00:00:00 2001 From: John Oberschelp Date: Wed, 1 Nov 2017 09:58:11 -0700 Subject: [PATCH 12/12] Update Contributors.asciidoc --- Contributors.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/Contributors.asciidoc b/Contributors.asciidoc index 8666e01f..927d761d 100644 --- a/Contributors.asciidoc +++ b/Contributors.asciidoc @@ -55,6 +55,7 @@ CONTRIBUTOR LIST ---------------- |=== |Bill Zissimopoulos |billziss at navimatics.com +|John Oberschelp |john at oberschelp.net |Sam Kelly (DuroSoft Technologies LLC, https://durosoft.com) |sam at durosoft.com |Tobias Urlaub |saibotu at outlook.de |===