From 168acb1a1fd9310aca6bb326a36237ebffa65ab2 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 26 Dec 2016 22:45:48 -0800 Subject: [PATCH] sys: statistics: implement FSCTL_FILESYSTEM_GET_STATISTICS --- build/VStudio/winfsp_sys.vcxproj | 1 + build/VStudio/winfsp_sys.vcxproj.filters | 3 + src/sys/device.c | 10 +++ src/sys/driver.c | 3 + src/sys/driver.h | 21 +++++- src/sys/fsctl.c | 23 +++++++ src/sys/iop.c | 22 +++++++ src/sys/read.c | 14 ++++ src/sys/statistics.c | 84 ++++++++++++++++++++++++ src/sys/write.c | 14 ++++ tools/run-tests.bat | 4 +- 11 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 src/sys/statistics.c diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj index f581e221..21747b51 100644 --- a/build/VStudio/winfsp_sys.vcxproj +++ b/build/VStudio/winfsp_sys.vcxproj @@ -177,6 +177,7 @@ + diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters index f13f62ca..cbe042c7 100644 --- a/build/VStudio/winfsp_sys.vcxproj.filters +++ b/build/VStudio/winfsp_sys.vcxproj.filters @@ -95,6 +95,9 @@ Source + + Source + diff --git a/src/sys/device.c b/src/sys/device.c index f71c9678..4dfef85a 100644 --- a/src/sys/device.c +++ b/src/sys/device.c @@ -364,6 +364,12 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject) InitializeListHead(&FsvolDeviceExtension->NotifyList); FsvolDeviceExtension->InitDoneNotify = 1; + /* create file system statistics */ + Result = FspStatisticsCreate(&FsvolDeviceExtension->Statistics); + if (!NT_SUCCESS(Result)) + return Result; + FsvolDeviceExtension->InitDoneStat = 1; + /* initialize our context table */ ExInitializeResourceLite(&FsvolDeviceExtension->FileRenameResource); ExInitializeResourceLite(&FsvolDeviceExtension->ContextTableResource); @@ -408,6 +414,10 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject) if (FsvolDeviceExtension->InitDoneTimer) IoStopTimer(DeviceObject); + /* delete the file system statistics */ + if (FsvolDeviceExtension->InitDoneStat) + FspStatisticsDelete(FsvolDeviceExtension->Statistics); + /* uninitialize the FSRTL Notify mechanism */ if (FsvolDeviceExtension->InitDoneNotify) { diff --git a/src/sys/driver.c b/src/sys/driver.c index 12fffa15..41ee0b6a 100644 --- a/src/sys/driver.c +++ b/src/sys/driver.c @@ -176,6 +176,8 @@ NTSTATUS DriverEntry( static VOID FspDriverMultiVersionInitialize(VOID) { + FspProcessorCount = KeQueryActiveProcessorCount(0); + ExInitializeDriverRuntime(DrvRtPoolNxOptIn); if (RtlIsNtDdiVersionAvailable(NTDDI_WIN7)) @@ -216,5 +218,6 @@ PDEVICE_OBJECT FspFsctlNetDeviceObject; FAST_IO_DISPATCH FspFastIoDispatch; CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks; +ULONG FspProcessorCount; FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache; ULONG FspMvMdlMappingNoWrite = 0; diff --git a/src/sys/driver.h b/src/sys/driver.h index 062c3e6d..c1d49319 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -949,6 +949,21 @@ VOID FspWqPostIrpWorkItem(PIRP Irp); #define FspWqRepostIrpWorkItem(I, RW, RF)\ FspWqCreateAndPostIrpWorkItem(I, RW, RF, TRUE) +/* file system statistics */ +typedef struct +{ + FILESYSTEM_STATISTICS Base; + FAT_STATISTICS Specific; /* pretend that we are FAT when it comes to stats */ + /* align to 64 bytes */ + __declspec(align(64)) UINT8 EndOfStruct[]; +} FSP_STATISTICS; +NTSTATUS FspStatisticsCreate(FSP_STATISTICS **PStatistics); +VOID FspStatisticsDelete(FSP_STATISTICS *Statistics); +NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLength); +#define FspStatistics(S) (&(S)[KeGetCurrentProcessorNumber() % FspProcessorCount]) +#define FspStatisticsInc(S,F) ((S)->F++) +#define FspStatisticsAdd(S,F,V) ((S)->F += (V)) + /* device management */ enum { @@ -990,7 +1005,7 @@ typedef struct { FSP_DEVICE_EXTENSION Base; UINT32 InitDoneFsvrt:1, InitDoneIoq:1, InitDoneSec:1, InitDoneDir:1, InitDoneStrm:1, - InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1; + InitDoneCtxTab:1, InitDoneTimer:1, InitDoneInfo:1, InitDoneNotify:1, InitDoneStat:1; PDEVICE_OBJECT FsctlDeviceObject; PDEVICE_OBJECT FsvrtDeviceObject; HANDLE MupHandle; @@ -1016,6 +1031,7 @@ typedef struct FSP_FSCTL_VOLUME_INFO VolumeInfo; PNOTIFY_SYNC NotifySync; LIST_ENTRY NotifyList; + FSP_STATISTICS *Statistics; } FSP_FSVOL_DEVICE_EXTENSION; static inline FSP_DEVICE_EXTENSION *FspDeviceExtension(PDEVICE_OBJECT DeviceObject) @@ -1083,6 +1099,8 @@ VOID FspDeviceGlobalUnlock(VOID) extern ERESOURCE FspDeviceGlobalResource; ExReleaseResourceLite(&FspDeviceGlobalResource); } +#define FspFsvolDeviceStatistics(DeviceObject)\ + FspStatistics(FspFsvolDeviceExtension(DeviceObject)->Statistics) #define FspFsvolDeviceStoppedStatus(DeviceObject)\ STATUS_VOLUME_DISMOUNTED //(FILE_DEVICE_DISK_FILE_SYSTEM == (DeviceObject)->DeviceType ?\ @@ -1486,6 +1504,7 @@ extern FSP_IOCMPL_DISPATCH *FspIopCompleteFunction[]; extern ERESOURCE FspDeviceGlobalResource; extern WCHAR FspFileDescDirectoryPatternMatchAll[]; extern const GUID FspMainFileOpenEcpGuid; +extern ULONG FspProcessorCount; extern FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache; extern ULONG FspMvMdlMappingNoWrite; diff --git a/src/sys/fsctl.c b/src/sys/fsctl.c index 6aaf6df3..701156b7 100644 --- a/src/sys/fsctl.c +++ b/src/sys/fsctl.c @@ -31,6 +31,8 @@ static IO_COMPLETION_ROUTINE FspFsvolFileSystemControlOplockCompletion; static WORKER_THREAD_ROUTINE FspFsvolFileSystemControlOplockCompletionWork; static NTSTATUS FspFsvolFileSystemControlQueryPersistentVolumeState( PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); +static NTSTATUS FspFsvolFileSystemControlGetStatistics( + PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); static NTSTATUS FspFsvolFileSystemControl( PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); FSP_IOCMPL_DISPATCH FspFsvolFileSystemControlComplete; @@ -45,6 +47,7 @@ FSP_DRIVER_DISPATCH FspFileSystemControl; // !#pragma alloc_text(PAGE, FspFsvolFileSystemControlOplockCompletion) #pragma alloc_text(PAGE, FspFsvolFileSystemControlOplockCompletionWork) #pragma alloc_text(PAGE, FspFsvolFileSystemControlQueryPersistentVolumeState) +#pragma alloc_text(PAGE, FspFsvolFileSystemControlGetStatistics) #pragma alloc_text(PAGE, FspFsvolFileSystemControl) #pragma alloc_text(PAGE, FspFsvolFileSystemControlComplete) #pragma alloc_text(PAGE, FspFsvolFileSystemControlRequestFini) @@ -513,6 +516,23 @@ static NTSTATUS FspFsvolFileSystemControlQueryPersistentVolumeState( return STATUS_SUCCESS; } +static NTSTATUS FspFsvolFileSystemControlGetStatistics( + PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) +{ + PAGED_CODE(); + + NTSTATUS Result; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject); + PVOID Buffer = Irp->AssociatedIrp.SystemBuffer; + ULONG Length = IrpSp->Parameters.FileSystemControl.OutputBufferLength; + + Result = FspStatisticsCopy(FsvolDeviceExtension->Statistics, Buffer, &Length); + + Irp->IoStatus.Information = Length; + + return Result; +} + static NTSTATUS FspFsvolFileSystemControl( PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) { @@ -549,6 +569,9 @@ static NTSTATUS FspFsvolFileSystemControl( case FSCTL_QUERY_PERSISTENT_VOLUME_STATE: Result = FspFsvolFileSystemControlQueryPersistentVolumeState(FsvolDeviceObject, Irp, IrpSp); break; + case FSCTL_FILESYSTEM_GET_STATISTICS: + Result = FspFsvolFileSystemControlGetStatistics(FsvolDeviceObject, Irp, IrpSp); + break; } break; } diff --git a/src/sys/iop.c b/src/sys/iop.c index 3dec1fe5..d0d837a1 100644 --- a/src/sys/iop.c +++ b/src/sys/iop.c @@ -281,6 +281,28 @@ VOID FspIopCompleteIrpEx(PIRP Irp, NTSTATUS Result, BOOLEAN DeviceDereference) PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PDEVICE_OBJECT DeviceObject = IrpSp->DeviceObject; + /* + * HACK: + * + * We update the Create statistics here to avoid doing it in multiple places. + */ + if (IRP_MJ_CREATE == IrpSp->MajorFunction) + { + FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObject); + + if (FspFsvolDeviceExtensionKind == FspDeviceExtension(DeviceObject)->Kind) + { + FSP_STATISTICS *Statistics = FspStatistics( + ((FSP_FSVOL_DEVICE_EXTENSION *)DeviceExtension)->Statistics); + + FspStatisticsInc(Statistics, Specific.CreateHits); + if (STATUS_SUCCESS == Result) + FspStatisticsInc(Statistics, Specific.SuccessfulCreates); + else + FspStatisticsInc(Statistics, Specific.FailedCreates); + } + } + else /* * HACK: * diff --git a/src/sys/read.c b/src/sys/read.c index d20227a8..176967d8 100644 --- a/src/sys/read.c +++ b/src/sys/read.c @@ -324,6 +324,20 @@ static NTSTATUS FspFsvolReadNonCached( FspFileNodeSetOwner(FileNode, Full, Request); FspIopRequestContext(Request, RequestIrp) = Irp; + FSP_STATISTICS *Statistics = FspFsvolDeviceStatistics(FsvolDeviceObject); + if (PagingIo) + { + FspStatisticsInc(Statistics, Base.UserFileReads); + FspStatisticsAdd(Statistics, Base.UserFileReadBytes, ReadLength); + FspStatisticsInc(Statistics, Base.UserDiskReads); + } + else + { + FspStatisticsInc(Statistics, Specific.NonCachedReads); + FspStatisticsAdd(Statistics, Specific.NonCachedReadBytes, ReadLength); + FspStatisticsInc(Statistics, Specific.NonCachedDiskReads); + } + return FSP_STATUS_IOQ_POST; } diff --git a/src/sys/statistics.c b/src/sys/statistics.c new file mode 100644 index 00000000..94194b08 --- /dev/null +++ b/src/sys/statistics.c @@ -0,0 +1,84 @@ +/** + * @file sys/statistics.c + * + * @copyright 2015-2016 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#include + +NTSTATUS FspStatisticsCreate(FSP_STATISTICS **PStatistics); +VOID FspStatisticsDelete(FSP_STATISTICS *Statistics); +NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLength); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FspStatisticsCreate) +#pragma alloc_text(PAGE, FspStatisticsDelete) +#pragma alloc_text(PAGE, FspStatisticsCopy) +#endif + +NTSTATUS FspStatisticsCreate(FSP_STATISTICS **PStatistics) +{ + *PStatistics = FspAllocNonPaged(sizeof(FSP_STATISTICS) * FspProcessorCount); + if (0 == *PStatistics) + return STATUS_INSUFFICIENT_RESOURCES; + + RtlZeroMemory(*PStatistics, sizeof(FSP_STATISTICS) * FspProcessorCount); + for (ULONG Index = 0; FspProcessorCount > Index; Index++) + { + FSP_STATISTICS *Statistics = PStatistics[Index]; + + /* pretend that we are FAT when it comes to stats */ + Statistics->Base.FileSystemType = FILESYSTEM_STATISTICS_TYPE_FAT; + Statistics->Base.Version = 1; + Statistics->Base.SizeOfCompleteStructure = sizeof(FSP_STATISTICS); + } + + return STATUS_SUCCESS; +} + +VOID FspStatisticsDelete(FSP_STATISTICS *Statistics) +{ + FspFree(Statistics); +} + +NTSTATUS FspStatisticsCopy(FSP_STATISTICS *Statistics, PVOID Buffer, PULONG PLength) +{ + NTSTATUS Result; + ULONG StatLength; + + if (0 == Buffer) + { + *PLength = 0; + return STATUS_INVALID_PARAMETER; + } + + if (sizeof(FILESYSTEM_STATISTICS) > *PLength) + { + *PLength = 0; + return STATUS_BUFFER_TOO_SMALL; + } + + StatLength = sizeof(FSP_STATISTICS) * FspProcessorCount; + if (*PLength >= StatLength) + { + *PLength = StatLength; + Result = STATUS_SUCCESS; + } + else + Result = STATUS_BUFFER_OVERFLOW; + + RtlCopyMemory(Buffer, Statistics, *PLength); + + return Result; +} diff --git a/src/sys/write.c b/src/sys/write.c index ef4d192e..fa79fc28 100644 --- a/src/sys/write.c +++ b/src/sys/write.c @@ -394,6 +394,20 @@ static NTSTATUS FspFsvolWriteNonCached( FspFileNodeSetOwner(FileNode, Full, Request); FspIopRequestContext(Request, RequestIrp) = Irp; + FSP_STATISTICS *Statistics = FspFsvolDeviceStatistics(FsvolDeviceObject); + if (PagingIo) + { + FspStatisticsInc(Statistics, Base.UserFileWrites); + FspStatisticsAdd(Statistics, Base.UserFileWriteBytes, WriteLength); + FspStatisticsInc(Statistics, Base.UserDiskWrites); + } + else + { + FspStatisticsInc(Statistics, Specific.NonCachedWrites); + FspStatisticsAdd(Statistics, Specific.NonCachedWriteBytes, WriteLength); + FspStatisticsInc(Statistics, Specific.NonCachedDiskWrites); + } + return FSP_STATUS_IOQ_POST; } diff --git a/tools/run-tests.bat b/tools/run-tests.bat index bdc0d0fb..29f0ec70 100755 --- a/tools/run-tests.bat +++ b/tools/run-tests.bat @@ -379,8 +379,8 @@ rem call :__ifstest %1 /d %2 /g ChangeNotification /z /v rem if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1 call :__ifstest %1 /d %2 /g ReadWrite /z /v if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1 -rem call :__ifstest %1 /d %2 /g SectionsCaching /z /v -rem if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1 +call :__ifstest %1 /d %2 /g SectionsCaching /z /v +if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1 rem call :__ifstest %1 /d %2 /g ReparsePoints /z /v rem if !ERRORLEVEL! neq 0 set IfsTestMemfsExit=1 rem call :__ifstest %1 /d %2 /g StreamEnhancements /z /v