tst: memfs: slowio

This commit is contained in:
Bill Zissimopoulos 2017-11-01 17:12:29 -07:00
commit 9be2b7a2b9
4 changed files with 247 additions and 2 deletions

View File

@ -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
|===

View File

@ -44,6 +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 = 0; // From -R : adjust the rarity of long delays
PWSTR FileSystemName = 0;
PWSTR MountPoint = 0;
PWSTR VolumePrefix = 0;
@ -75,9 +78,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 +142,9 @@ NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
FileInfoTimeout,
MaxFileNodes,
MaxFileSize,
SlowioMaxDelay,
SlowioPercentDelay,
SlowioRarefyDelay,
FileSystemName,
VolumePrefix,
RootSddl,
@ -189,6 +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"

View File

@ -22,6 +22,7 @@
#include <cassert>
#include <map>
#include <unordered_map>
#include <thread>
#define MEMFS_MAX_PATH 512
FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
@ -47,6 +48,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
*/
#define MEMFS_DIRINFO_BY_NAME
/*
* 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.
@ -281,6 +287,12 @@ typedef struct _MEMFS
MEMFS_FILE_NODE_MAP *FileNodeMap;
ULONG MaxFileNodes;
ULONG MaxFileSize;
#ifdef MEMFS_SLOWIO
ULONG SlowioMaxDelay;
ULONG SlowioPercentDelay;
ULONG SlowioRarefyDelay;
volatile LONG SlowioThreadsRunning;
#endif
UINT16 VolumeLabelLength;
WCHAR VolumeLabel[32];
} MEMFS;
@ -646,6 +658,132 @@ VOID MemfsFileNodeMapEnumerateFree(MEMFS_FILE_NODE_MAP_ENUM_CONTEXT *Context)
free(Context->FileNodes);
}
#ifdef MEMFS_SLOWIO
/*
* 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 Hash(UINT64 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 spin = 0;
InterlockedIncrement(&spin);
return Hash(spin) % to;
}
int SlowioReturnPending(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;
int milliseconds = PseudoRandom(Memfs->SlowioMaxDelay+1) >> PseudoRandom(Memfs->SlowioRarefyDelay+1);
return milliseconds;
}
void SlowioReadThread(
FSP_FILE_SYSTEM *FileSystem,
MEMFS_FILE_NODE *FileNode,
PVOID Buffer,
UINT64 Offset,
UINT64 EndOffset,
UINT64 RequestHint)
{
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
int ms = SlowioMillisecondsOfDelay(FileSystem);
if (ms) Sleep(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(&Memfs->SlowioThreadsRunning);
}
void SlowioWriteThread(
FSP_FILE_SYSTEM *FileSystem,
MEMFS_FILE_NODE *FileNode,
PVOID Buffer,
UINT64 Offset,
UINT64 EndOffset,
UINT64 RequestHint,
FSP_FSCTL_FILE_INFO *FileInfo)
{
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
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
FspFileSystemSendResponse(FileSystem, &ResponseBuf);
InterlockedDecrement(&Memfs->SlowioThreadsRunning);
}
void SlowioReadDirectoryThread(
FSP_FILE_SYSTEM *FileSystem,
ULONG BytesTransferred,
UINT64 RequestHint)
{
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
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
FspFileSystemSendResponse(FileSystem, &ResponseBuf);
InterlockedDecrement(&Memfs->SlowioThreadsRunning);
}
#endif
/*
* FSP_FILE_SYSTEM_INTERFACE
*/
@ -1029,6 +1167,29 @@ static NTSTATUS Read(FSP_FILE_SYSTEM *FileSystem,
if (EndOffset > FileNode->FileInfo.FileSize)
EndOffset = FileNode->FileInfo.FileSize;
#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));
*PBytesTransferred = (ULONG)(EndOffset - Offset);
@ -1082,6 +1243,29 @@ static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem,
}
}
#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));
*PBytesTransferred = (ULONG)(EndOffset - Offset);
@ -1451,6 +1635,28 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
ReadDirectoryEnumFn, &Context))
FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);
#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;
}
@ -1752,6 +1958,9 @@ NTSTATUS MemfsCreateFunnel(
ULONG FileInfoTimeout,
ULONG MaxFileNodes,
ULONG MaxFileSize,
ULONG SlowioMaxDelay,
ULONG SlowioPercentDelay,
ULONG SlowioRarefyDelay,
PWSTR FileSystemName,
PWSTR VolumePrefix,
PWSTR RootSddl,
@ -1793,6 +2002,12 @@ NTSTATUS MemfsCreateFunnel(
AllocationUnit = MEMFS_SECTOR_SIZE * MEMFS_SECTORS_PER_ALLOCATION_UNIT;
Memfs->MaxFileSize = (ULONG)((MaxFileSize + AllocationUnit - 1) / AllocationUnit * AllocationUnit);
#ifdef MEMFS_SLOWIO
Memfs->SlowioMaxDelay = SlowioMaxDelay;
Memfs->SlowioPercentDelay = SlowioPercentDelay;
Memfs->SlowioRarefyDelay = SlowioRarefyDelay;
#endif
Result = MemfsFileNodeMapCreate(CaseInsensitive, &Memfs->FileNodeMap);
if (!NT_SUCCESS(Result))
{
@ -1895,12 +2110,20 @@ VOID MemfsDelete(MEMFS *Memfs)
NTSTATUS MemfsStart(MEMFS *Memfs)
{
#ifdef MEMFS_SLOWIO
Memfs->SlowioThreadsRunning = 0;
#endif
return FspFileSystemStartDispatcher(Memfs->FileSystem, 0);
}
VOID MemfsStop(MEMFS *Memfs)
{
FspFileSystemStopDispatcher(Memfs->FileSystem);
#ifdef MEMFS_SLOWIO
while (Memfs->SlowioThreadsRunning) Sleep(1);
#endif
}
FSP_FILE_SYSTEM *MemfsFileSystem(MEMFS *Memfs)

View File

@ -33,13 +33,16 @@ 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, 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 SlowioPercentDelay,
ULONG SlowioRarefyDelay,
PWSTR FileSystemName,
PWSTR VolumePrefix,
PWSTR RootSddl,