winfsp/src/sys/driver.c
2022-08-18 11:05:45 +01:00

544 lines
20 KiB
C

/**
* @file sys/driver.c
*
* @copyright 2015-2022 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 software
* in accordance with the commercial license agreement provided in
* conjunction with the software. The terms and conditions of any such
* commercial license agreement shall govern, supersede, and render
* ineffective any application of the GPLv3 license to this software,
* notwithstanding of any reference thereto in the software or
* associated repository.
*/
#include <sys/driver.h>
DRIVER_INITIALIZE DriverEntry;
static DRIVER_UNLOAD DriverUnload;
static VOID FspDriverMultiVersionInitialize(VOID);
static NTSTATUS FspDriverInitializeDevices(VOID);
static VOID FspDriverFinalizeDevices(VOID);
static VOID FspDriverFinalizeDevicesEx(BOOLEAN DeleteDevices);
NTSTATUS FspDriverUnload(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, DriverUnload)
#pragma alloc_text(INIT, FspDriverMultiVersionInitialize)
#pragma alloc_text(PAGE, FspDriverInitializeDevices)
#pragma alloc_text(PAGE, FspDriverFinalizeDevices)
#pragma alloc_text(PAGE, FspDriverFinalizeDevicesEx)
#pragma alloc_text(PAGE, FspDriverUnload)
#endif
NTSTATUS DriverEntry(
PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
FSP_ENTER_DRV();
FSP_TRACE_INIT();
FspSxsIdentInitialize(&DriverObject->DriverName);
/* setup the driver object */
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE] = FspCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = FspClose;
DriverObject->MajorFunction[IRP_MJ_READ] = FspRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = FspWrite;
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = FspQueryInformation;
DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = FspSetInformation;
DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = FspQueryEa;
DriverObject->MajorFunction[IRP_MJ_SET_EA] = FspSetEa;
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = FspFlushBuffers;
DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = FspQueryVolumeInformation;
DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = FspSetVolumeInformation;
DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = FspDirectoryControl;
DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FspFileSystemControl;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FspDeviceControl;
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = FspShutdown;
DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = FspLockControl;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FspCleanup;
DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = FspQuerySecurity;
DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = FspSetSecurity;
/* setup the I/O prepare/complete functions */
FspIopPrepareFunction[IRP_MJ_CREATE] = FspFsvolCreatePrepare;
FspIopCompleteFunction[IRP_MJ_CREATE] = FspFsvolCreateComplete;
FspIopCompleteFunction[IRP_MJ_CLOSE] = FspFsvolCloseComplete;
FspIopPrepareFunction[IRP_MJ_READ] = FspFsvolReadPrepare;
FspIopCompleteFunction[IRP_MJ_READ] = FspFsvolReadComplete;
FspIopPrepareFunction[IRP_MJ_WRITE] = FspFsvolWritePrepare;
FspIopCompleteFunction[IRP_MJ_WRITE] = FspFsvolWriteComplete;
FspIopCompleteFunction[IRP_MJ_QUERY_INFORMATION] = FspFsvolQueryInformationComplete;
FspIopPrepareFunction[IRP_MJ_SET_INFORMATION] = FspFsvolSetInformationPrepare;
FspIopCompleteFunction[IRP_MJ_SET_INFORMATION] = FspFsvolSetInformationComplete;
FspIopCompleteFunction[IRP_MJ_QUERY_EA] = FspFsvolQueryEaComplete;
FspIopCompleteFunction[IRP_MJ_SET_EA] = FspFsvolSetEaComplete;
FspIopCompleteFunction[IRP_MJ_FLUSH_BUFFERS] = FspFsvolFlushBuffersComplete;
FspIopCompleteFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = FspFsvolQueryVolumeInformationComplete;
FspIopCompleteFunction[IRP_MJ_SET_VOLUME_INFORMATION] = FspFsvolSetVolumeInformationComplete;
FspIopPrepareFunction[IRP_MJ_DIRECTORY_CONTROL] = FspFsvolDirectoryControlPrepare;
FspIopCompleteFunction[IRP_MJ_DIRECTORY_CONTROL] = FspFsvolDirectoryControlComplete;
FspIopCompleteFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FspFsvolFileSystemControlComplete;
FspIopCompleteFunction[IRP_MJ_DEVICE_CONTROL] = FspFsvolDeviceControlComplete;
FspIopCompleteFunction[IRP_MJ_LOCK_CONTROL] = FspFsvolLockControlComplete;
FspIopCompleteFunction[IRP_MJ_CLEANUP] = FspFsvolCleanupComplete;
FspIopCompleteFunction[IRP_MJ_QUERY_SECURITY] = FspFsvolQuerySecurityComplete;
FspIopCompleteFunction[IRP_MJ_SET_SECURITY] = FspFsvolSetSecurityComplete;
/* setup fast I/O and resource acquisition */
FspFastIoDispatch.SizeOfFastIoDispatch = sizeof FspFastIoDispatch;
FspFastIoDispatch.FastIoCheckIfPossible = FspFastIoCheckIfPossible;
FspFastIoDispatch.FastIoRead = FspFastIoRead;
FspFastIoDispatch.FastIoWrite = FspFastIoWrite;
FspFastIoDispatch.FastIoQueryBasicInfo = FspFastIoQueryBasicInfo;
FspFastIoDispatch.FastIoQueryStandardInfo = FspFastIoQueryStandardInfo;
//FspFastIoDispatch.FastIoLock = 0;
//FspFastIoDispatch.FastIoUnlockSingle = 0;
//FspFastIoDispatch.FastIoUnlockAll = 0;
//FspFastIoDispatch.FastIoUnlockAllByKey = 0;
FspFastIoDispatch.FastIoDeviceControl = FspFastIoDeviceControl;
FspFastIoDispatch.AcquireFileForNtCreateSection = FspAcquireFileForNtCreateSection;
FspFastIoDispatch.ReleaseFileForNtCreateSection = FspReleaseFileForNtCreateSection;
//FspFastIoDispatch.FastIoDetachDevice = 0;
FspFastIoDispatch.FastIoQueryNetworkOpenInfo = FspFastIoQueryNetworkOpenInfo;
FspFastIoDispatch.AcquireForModWrite = FspAcquireForModWrite;
//FspFastIoDispatch.MdlRead = 0;
//FspFastIoDispatch.MdlReadComplete = 0;
//FspFastIoDispatch.PrepareMdlWrite = 0;
//FspFastIoDispatch.MdlWriteComplete = 0;
//FspFastIoDispatch.FastIoReadCompressed = 0;
//FspFastIoDispatch.FastIoWriteCompressed = 0;
//FspFastIoDispatch.MdlReadCompleteCompressed = 0;
//FspFastIoDispatch.MdlWriteCompleteCompressed = 0;
FspFastIoDispatch.FastIoQueryOpen = FspFastIoQueryOpen;
FspFastIoDispatch.ReleaseForModWrite = FspReleaseForModWrite;
FspFastIoDispatch.AcquireForCcFlush = FspAcquireForCcFlush;
FspFastIoDispatch.ReleaseForCcFlush = FspReleaseForCcFlush;
FspCacheManagerCallbacks.AcquireForLazyWrite = FspAcquireForLazyWrite;
FspCacheManagerCallbacks.ReleaseFromLazyWrite = FspReleaseFromLazyWrite;
FspCacheManagerCallbacks.AcquireForReadAhead = FspAcquireForReadAhead;
FspCacheManagerCallbacks.ReleaseFromReadAhead = FspReleaseFromReadAhead;
#pragma prefast(suppress:28175, "We are a filesystem: ok to access FastIoDispatch")
DriverObject->FastIoDispatch = &FspFastIoDispatch;
BOOLEAN InitDoneSilo = FALSE, InitDonePsBuf = FALSE,
InitDoneTimers = FALSE, InitDoneDevices = FALSE;
FspDriverObject = DriverObject;
FspDriverMultiVersionInitialize();
ExInitializeFastMutex(&FspDriverUnloadMutex);
ExInitializeFastMutex(&FspDeviceGlobalMutex);
Result = FspSiloInitialize(FspDriverInitializeDevices, FspDriverFinalizeDevices);
if (!NT_SUCCESS(Result))
goto exit;
InitDoneSilo = TRUE;
Result = FspProcessBufferInitialize();
if (!NT_SUCCESS(Result))
goto exit;
InitDonePsBuf = TRUE;
Result = FspDeviceInitializeAllTimers();
if (!NT_SUCCESS(Result))
goto exit;
InitDoneTimers = TRUE;
Result = FspDriverInitializeDevices();
if (!NT_SUCCESS(Result))
goto exit;
InitDoneDevices = TRUE;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
{
if (InitDoneDevices)
FspDriverFinalizeDevices();
if (InitDoneTimers)
FspDeviceFinalizeAllTimers();
if (InitDonePsBuf)
FspProcessBufferFinalize();
if (InitDoneSilo)
FspSiloFinalize();
FSP_TRACE_FINI();
}
#pragma prefast(suppress:28175, "We are in DriverEntry: ok to access DriverName")
FSP_LEAVE_DRV("DriverName=\"%wZ\", RegistryPath=\"%wZ\"",
&DriverObject->DriverName, RegistryPath);
}
VOID DriverUnload(
PDRIVER_OBJECT DriverObject)
{
FSP_ENTER_VOID(PAGED_CODE());
FspDriverFinalizeDevices();
FspDeviceFinalizeAllTimers();
FspProcessBufferFinalize();
FspSiloFinalize();
FSP_TRACE_FINI();
#pragma prefast(suppress:28175, "We are in DriverUnload: ok to access DriverName")
FSP_LEAVE_VOID("DriverName=\"%wZ\"",
&DriverObject->DriverName);
}
static VOID FspDriverMultiVersionInitialize(VOID)
{
FspProcessorCount = KeQueryActiveProcessorCount(0);
#pragma prefast(suppress:30035, "FspDriverMultiVersionInitialize is called from DriverEntry")
ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
if (FspIsNtDdiVersionAvailable(NTDDI_WIN7))
{
UNICODE_STRING Name;
RtlInitUnicodeString(&Name, L"CcCoherencyFlushAndPurgeCache");
FspMvCcCoherencyFlushAndPurgeCache =
(FSP_MV_CcCoherencyFlushAndPurgeCache *)(UINT_PTR)MmGetSystemRoutineAddress(&Name);
}
if (FspIsNtDdiVersionAvailable(NTDDI_WIN8))
FspMvMdlMappingNoWrite = MdlMappingNoWrite;
if (FspIsNtDdiVersionAvailable(NTDDI_WIN10_RS4))
FspHasReparsePointCaseSensitivityFix = TRUE;
}
static NTSTATUS FspDriverInitializeDevices(VOID)
{
PAGED_CODE();
FSP_SILO_GLOBALS *Globals;
UNICODE_STRING DeviceSddl;
UNICODE_STRING DeviceName;
WCHAR DeviceNameBuf[128];
UNICODE_STRING SymlinkName;
GUID Guid;
NTSTATUS Result;
FspSiloGetGlobals(&Globals);
ASSERT(0 != Globals);
/* create the file system control device objects */
RtlInitUnicodeString(&DeviceSddl, L"" FSP_FSCTL_DEVICE_SDDL);
RtlInitEmptyUnicodeString(&DeviceName, DeviceNameBuf, sizeof DeviceNameBuf);
Result = RtlUnicodeStringPrintf(&DeviceName,
L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME "%wZ",
FspSxsSuffix());
ASSERT(NT_SUCCESS(Result));
Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
&DeviceName, FILE_DEVICE_DISK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
&DeviceSddl, &FspFsctlDeviceClassGuid,
&Globals->FsctlDiskDeviceObject);
if (!NT_SUCCESS(Result))
goto exit;
if (0 != FspSxsIdent()->Length)
{
/* \Device\WinFsp.Disk SxS symlink */
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME);
Result = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
if (!NT_SUCCESS(Result))
goto exit;
Globals->InitDoneSymlinkDisk = 1;
}
RtlInitEmptyUnicodeString(&DeviceName, DeviceNameBuf, sizeof DeviceNameBuf);
Result = RtlUnicodeStringPrintf(&DeviceName,
L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME "%wZ",
FspSxsSuffix());
ASSERT(NT_SUCCESS(Result));
Result = FspDeviceCreateSecure(FspFsctlDeviceExtensionKind, 0,
&DeviceName, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_DEVICE_SECURE_OPEN,
&DeviceSddl, &FspFsctlDeviceClassGuid,
&Globals->FsctlNetDeviceObject);
if (!NT_SUCCESS(Result))
goto exit;
if (0 != FspSxsIdent()->Length)
{
/* \Device\WinFsp.Net SxS symlink */
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
Result = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
if (!NT_SUCCESS(Result))
goto exit;
Globals->InitDoneSymlinkNet = 1;
}
Result = FspDeviceCreate(FspFsmupDeviceExtensionKind, 0,
FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_REMOTE_DEVICE,
&Globals->FsmupDeviceObject);
if (!NT_SUCCESS(Result))
goto exit;
#if DBG
/*
* Fix GitHub issue #177. All credit for the investigation of this issue
* and the suggested steps to reproduce and work around the problem goes
* to GitHub user @thinkport.
*
* On debug builds set DO_LOW_PRIORITY_FILESYSTEM to place the file system
* at the end of the file system list during IoRegisterFileSystem below.
* This allows us to test the behavior of our Fsvrt devices when foreign
* file systems attempt to use them for mounting.
*/
SetFlag(Globals->FsctlDiskDeviceObject->Flags, DO_LOW_PRIORITY_FILESYSTEM);
#endif
Result = FspDeviceInitialize(Globals->FsctlDiskDeviceObject);
ASSERT(STATUS_SUCCESS == Result);
Result = FspDeviceInitialize(Globals->FsctlNetDeviceObject);
ASSERT(STATUS_SUCCESS == Result);
Result = FspDeviceInitialize(Globals->FsmupDeviceObject);
ASSERT(STATUS_SUCCESS == Result);
FspSiloGetContainerId(&Guid);
RtlInitEmptyUnicodeString(&DeviceName,
Globals->FsmupDeviceNameBuf, sizeof Globals->FsmupDeviceNameBuf);
Result = RtlUnicodeStringPrintf(&DeviceName,
0 == ((PULONG)&Guid)[0] && 0 == ((PULONG)&Guid)[1] &&
0 == ((PULONG)&Guid)[2] && 0 == ((PULONG)&Guid)[3] ?
L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME "%wZ":
L"\\Device\\" FSP_FSCTL_MUP_DEVICE_NAME "%wZ{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
FspSxsSuffix(),
Guid.Data1, Guid.Data2, Guid.Data3,
Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3],
Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]);
ASSERT(NT_SUCCESS(Result));
DeviceName.MaximumLength = DeviceName.Length;
Result = FsRtlRegisterUncProviderEx(&Globals->MupHandle,
&DeviceName, Globals->FsmupDeviceObject, 0);
if (!NT_SUCCESS(Result))
{
Globals->MupHandle = 0;
goto exit;
}
/*
* Register our "disk" device as a file system. We do not register our "net" device
* as a file system; we register with the MUP instead.
*/
IoRegisterFileSystem(Globals->FsctlDiskDeviceObject);
Globals->InitDoneRegisterDisk = 1;
/*
* Reference primary device objects to allow for IoDeleteDevice during FspDriverUnload.
*/
ObReferenceObject(Globals->FsctlDiskDeviceObject);
ObReferenceObject(Globals->FsctlNetDeviceObject);
ObReferenceObject(Globals->FsmupDeviceObject);
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result))
{
if (Globals->InitDoneRegisterDisk)
{
IoUnregisterFileSystem(Globals->FsctlDiskDeviceObject);
Globals->InitDoneRegisterDisk = 0;
}
if (0 != Globals->MupHandle)
{
FsRtlDeregisterUncProvider(Globals->MupHandle);
Globals->MupHandle = 0;
}
if (0 != Globals->FsmupDeviceObject)
{
FspDeviceDelete(Globals->FsmupDeviceObject);
Globals->FsmupDeviceObject = 0;
}
if (Globals->InitDoneSymlinkNet)
{
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
IoDeleteSymbolicLink(&SymlinkName);
Globals->InitDoneSymlinkNet = 0;
}
if (0 != Globals->FsctlNetDeviceObject)
{
FspDeviceDelete(Globals->FsctlNetDeviceObject);
Globals->FsctlNetDeviceObject = 0;
}
if (Globals->InitDoneSymlinkDisk)
{
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME);
IoDeleteSymbolicLink(&SymlinkName);
Globals->InitDoneSymlinkDisk = 0;
}
if (0 != Globals->FsctlDiskDeviceObject)
{
FspDeviceDelete(Globals->FsctlDiskDeviceObject);
Globals->FsctlDiskDeviceObject = 0;
}
}
FspSiloDereferenceGlobals(Globals);
return Result;
}
static VOID FspDriverFinalizeDevices(VOID)
{
PAGED_CODE();
FspDriverFinalizeDevicesEx(TRUE);
}
static VOID FspDriverFinalizeDevicesEx(BOOLEAN DeleteDevices)
{
PAGED_CODE();
FSP_SILO_GLOBALS *Globals;
UNICODE_STRING SymlinkName;
FspSiloGetGlobals(&Globals);
ASSERT(0 != Globals);
if (Globals->InitDoneRegisterDisk)
{
IoUnregisterFileSystem(Globals->FsctlDiskDeviceObject);
Globals->InitDoneRegisterDisk = 0;
}
if (0 != Globals->MupHandle)
{
FsRtlDeregisterUncProvider(Globals->MupHandle);
Globals->MupHandle = 0;
}
if (0 != Globals->FsmupDeviceObject)
{
if (DeleteDevices)
{
FspDeviceDelete(Globals->FsmupDeviceObject);
ObDereferenceObject(Globals->FsmupDeviceObject);
Globals->FsmupDeviceObject = 0;
}
else
FspDeviceDoIoDeleteDevice(Globals->FsmupDeviceObject);
}
if (Globals->InitDoneSymlinkNet)
{
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_NET_DEVICE_NAME);
IoDeleteSymbolicLink(&SymlinkName);
Globals->InitDoneSymlinkNet = 0;
}
if (0 != Globals->FsctlNetDeviceObject)
{
if (DeleteDevices)
{
FspDeviceDelete(Globals->FsctlNetDeviceObject);
ObDereferenceObject(Globals->FsctlNetDeviceObject);
Globals->FsctlNetDeviceObject = 0;
}
else
FspDeviceDoIoDeleteDevice(Globals->FsctlNetDeviceObject);
}
if (Globals->InitDoneSymlinkDisk)
{
RtlInitUnicodeString(&SymlinkName, L"\\Device\\" FSP_FSCTL_DISK_DEVICE_NAME);
IoDeleteSymbolicLink(&SymlinkName);
Globals->InitDoneSymlinkDisk = 0;
}
if (0 != Globals->FsctlDiskDeviceObject)
{
if (DeleteDevices)
{
FspDeviceDelete(Globals->FsctlDiskDeviceObject);
ObDereferenceObject(Globals->FsctlDiskDeviceObject);
Globals->FsctlDiskDeviceObject = 0;
}
else
FspDeviceDoIoDeleteDevice(Globals->FsctlDiskDeviceObject);
}
FspSiloDereferenceGlobals(Globals);
}
NTSTATUS FspDriverUnload(
PDEVICE_OBJECT FsctlDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PAGED_CODE();
ASSERT(IRP_MJ_FILE_SYSTEM_CONTROL == IrpSp->MajorFunction);
ASSERT(IRP_MN_USER_FS_REQUEST == IrpSp->MinorFunction);
ASSERT(FSP_FSCTL_UNLOAD == IrpSp->Parameters.FileSystemControl.FsControlCode);
NTSTATUS Result;
UNICODE_STRING DriverServiceName, DriverName, Remain;
WCHAR DriverServiceNameBuf[64 + 256];
PDEVICE_OBJECT *DeviceObjects = 0;
ULONG DeviceObjectCount = 0;
if (!FspSiloIsHost())
return STATUS_INVALID_DEVICE_REQUEST;
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_LOAD_DRIVER_PRIVILEGE), UserMode))
return STATUS_PRIVILEGE_NOT_HELD;
ExAcquireFastMutexUnsafe(&FspDriverUnloadMutex);
if (!FspDriverUnloadDone)
{
FspFileNameSuffix(&FspDriverObject->DriverName, &Remain, &DriverName);
RtlInitEmptyUnicodeString(&DriverServiceName, DriverServiceNameBuf, sizeof DriverServiceNameBuf);
Result = RtlUnicodeStringPrintf(&DriverServiceName,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\%wZ", &DriverName);
if (!NT_SUCCESS(Result))
goto exit;
Result = ZwUnloadDriver(&DriverServiceName);
if (!NT_SUCCESS(Result))
goto exit;
FspDriverFinalizeDevicesEx(FALSE);
Result = FspDeviceCopyList(&DeviceObjects, &DeviceObjectCount);
if (NT_SUCCESS(Result))
{
for (ULONG I = 0; DeviceObjectCount > I; I++)
{
FSP_DEVICE_EXTENSION *DeviceExtension = FspDeviceExtension(DeviceObjects[I]);
if (FspFsvolDeviceExtensionKind == DeviceExtension->Kind)
FspIoqStop(((FSP_FSVOL_DEVICE_EXTENSION *)DeviceExtension)->Ioq, FALSE);
}
FspDeviceDeleteList(DeviceObjects, DeviceObjectCount);
}
FspDriverUnloadDone = TRUE;
}
Result = STATUS_SUCCESS;
exit:
ExReleaseFastMutexUnsafe(&FspDriverUnloadMutex);
return Result;
}
PDRIVER_OBJECT FspDriverObject;
FAST_IO_DISPATCH FspFastIoDispatch;
CACHE_MANAGER_CALLBACKS FspCacheManagerCallbacks;
FAST_MUTEX FspDriverUnloadMutex;
BOOLEAN FspDriverUnloadDone;
ULONG FspProcessorCount;
FSP_MV_CcCoherencyFlushAndPurgeCache *FspMvCcCoherencyFlushAndPurgeCache;
ULONG FspMvMdlMappingNoWrite = 0;
BOOLEAN FspHasReparsePointCaseSensitivityFix = FALSE;