diff options
| author | karlf <[email protected]> | 2016-08-11 13:28:13 -0700 |
|---|---|---|
| committer | karlf <[email protected]> | 2016-08-11 13:28:13 -0700 |
| commit | 96eb96dfb613e4c745db6bd1f53a92fe7e2290fc (patch) | |
| tree | ad5f3ede5cbcd6b598677ce41bcf8318471bdd92 /storage/class | |
| parent | 687b274aa38fd05c8c26e3068932121876d7f745 (diff) | |
Updated for "Windows 10 Anniversary Update" (Version 1607)
Diffstat (limited to 'storage/class')
23 files changed, 542 insertions, 270 deletions
diff --git a/storage/class/cdrom/cdrom.sln b/storage/class/cdrom/cdrom.sln index 813369c9..4516f3dc 100644 --- a/storage/class/cdrom/cdrom.sln +++ b/storage/class/cdrom/cdrom.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdrom", "src\cdrom.vcxproj", "{5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdrom", "src\cdrom.vcxproj", "{9DB6E759-C294-4E18-9013-82FD8F3DD5E6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Debug|Win32.ActiveCfg = Debug|Win32 - {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Debug|Win32.Build.0 = Debug|Win32 - {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Release|Win32.ActiveCfg = Release|Win32 - {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Release|Win32.Build.0 = Release|Win32 - {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Debug|x64.ActiveCfg = Debug|x64 - {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Debug|x64.Build.0 = Debug|x64 - {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Release|x64.ActiveCfg = Release|x64 - {5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}.Release|x64.Build.0 = Release|x64 + {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Debug|Win32.ActiveCfg = Debug|Win32 + {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Debug|Win32.Build.0 = Debug|Win32 + {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Release|Win32.ActiveCfg = Release|Win32 + {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Release|Win32.Build.0 = Release|Win32 + {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Debug|x64.ActiveCfg = Debug|x64 + {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Debug|x64.Build.0 = Debug|x64 + {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Release|x64.ActiveCfg = Release|x64 + {9DB6E759-C294-4E18-9013-82FD8F3DD5E6}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/storage/class/cdrom/src/cdrom.inf b/storage/class/cdrom/src/cdrom.inf Binary files differindex a1ba9f7f..d74fe65b 100644 --- a/storage/class/cdrom/src/cdrom.inf +++ b/storage/class/cdrom/src/cdrom.inf diff --git a/storage/class/cdrom/src/cdrom.vcxproj b/storage/class/cdrom/src/cdrom.vcxproj index 1b8b4bda..689c9716 100644 --- a/storage/class/cdrom/src/cdrom.vcxproj +++ b/storage/class/cdrom/src/cdrom.vcxproj @@ -19,13 +19,13 @@ </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> - <ProjectGuid>{5CAAC17A-F6C8-4F60-8599-BF5B710B9E75}</ProjectGuid> + <ProjectGuid>{9DB6E759-C294-4E18-9013-82FD8F3DD5E6}</ProjectGuid> <RootNamespace>$(MSBuildProjectName)</RootNamespace> <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> <SupportsPackaging>false</SupportsPackaging> <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> <Platform Condition="'$(Platform)' == ''">Win32</Platform> - <SampleGuid>{1D0354B6-7638-4B49-A326-3F635DF4792D}</SampleGuid> + <SampleGuid>{E2CAD978-F695-4642-9CD1-65CB518B0B80}</SampleGuid> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> diff --git a/storage/class/cdrom/src/cdrom.vcxproj.Filters b/storage/class/cdrom/src/cdrom.vcxproj.Filters index 984e47ff..57895acd 100644 --- a/storage/class/cdrom/src/cdrom.vcxproj.Filters +++ b/storage/class/cdrom/src/cdrom.vcxproj.Filters @@ -3,19 +3,19 @@ <ItemGroup> <Filter Include="Source Files"> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> - <UniqueIdentifier>{F4624455-84A0-4D68-9FDA-5A45BDDF16E9}</UniqueIdentifier> + <UniqueIdentifier>{1BE21169-AD4D-4A1B-AACD-6310066933B0}</UniqueIdentifier> </Filter> <Filter Include="Header Files"> <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - <UniqueIdentifier>{59782596-7387-4C2F-8B3F-14DD7DBBE39E}</UniqueIdentifier> + <UniqueIdentifier>{9B550B9E-2283-4A6B-BAC8-52E0EAB6DD60}</UniqueIdentifier> </Filter> <Filter Include="Resource Files"> <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> - <UniqueIdentifier>{F55549B9-4C00-441C-8960-79D8E04B2640}</UniqueIdentifier> + <UniqueIdentifier>{B3F87DD6-6AE2-4B7C-9C6F-6BC20F347A17}</UniqueIdentifier> </Filter> <Filter Include="Driver Files"> <Extensions>inf;inv;inx;mof;mc;</Extensions> - <UniqueIdentifier>{BE2B60C1-58DD-4635-A2B4-E75CEC446355}</UniqueIdentifier> + <UniqueIdentifier>{4F903A62-C105-4A95-AB1A-2EB0F3AE253F}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> diff --git a/storage/class/cdrom/src/ioctl.c b/storage/class/cdrom/src/ioctl.c index 49eeba49..590f1419 100644 --- a/storage/class/cdrom/src/ioctl.c +++ b/storage/class/cdrom/src/ioctl.c @@ -4150,9 +4150,10 @@ Return Value: driveLetterName.MaximumLength = sizeof(driveLetterNameBuffer); driveLetterName.Length = 0; - queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT; + queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = valueName; queryTable[0].EntryContext = &driveLetterName; + queryTable[0].DefaultType = (REG_SZ << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, L"\\Registry\\Machine\\System\\DISK", // why hard coded? diff --git a/storage/class/classpnp/classpnp.sln b/storage/class/classpnp/classpnp.sln index b11f5768..8078e6e1 100644 --- a/storage/class/classpnp/classpnp.sln +++ b/storage/class/classpnp/classpnp.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "classpnp", "src\classpnp.vcxproj", "{427E597B-35E8-4D6C-8AA5-35A4519B33D5}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "classpnp", "src\classpnp.vcxproj", "{CAE2DAC6-A407-41A6-A943-11156A103D14}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Debug|Win32.ActiveCfg = Debug|Win32 - {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Debug|Win32.Build.0 = Debug|Win32 - {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Release|Win32.ActiveCfg = Release|Win32 - {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Release|Win32.Build.0 = Release|Win32 - {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Debug|x64.ActiveCfg = Debug|x64 - {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Debug|x64.Build.0 = Debug|x64 - {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Release|x64.ActiveCfg = Release|x64 - {427E597B-35E8-4D6C-8AA5-35A4519B33D5}.Release|x64.Build.0 = Release|x64 + {CAE2DAC6-A407-41A6-A943-11156A103D14}.Debug|Win32.ActiveCfg = Debug|Win32 + {CAE2DAC6-A407-41A6-A943-11156A103D14}.Debug|Win32.Build.0 = Debug|Win32 + {CAE2DAC6-A407-41A6-A943-11156A103D14}.Release|Win32.ActiveCfg = Release|Win32 + {CAE2DAC6-A407-41A6-A943-11156A103D14}.Release|Win32.Build.0 = Release|Win32 + {CAE2DAC6-A407-41A6-A943-11156A103D14}.Debug|x64.ActiveCfg = Debug|x64 + {CAE2DAC6-A407-41A6-A943-11156A103D14}.Debug|x64.Build.0 = Debug|x64 + {CAE2DAC6-A407-41A6-A943-11156A103D14}.Release|x64.ActiveCfg = Release|x64 + {CAE2DAC6-A407-41A6-A943-11156A103D14}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/storage/class/classpnp/src/autorun.c b/storage/class/classpnp/src/autorun.c index 4dba537b..f0a88414 100644 --- a/storage/class/classpnp/src/autorun.c +++ b/storage/class/classpnp/src/autorun.c @@ -804,6 +804,7 @@ ClasspInternalSetMediaChangeState( MEDIA_CHANGE_DETECTION_STATE oldMediaState; PMEDIA_CHANGE_DETECTION_INFO info = FdoExtension->MediaChangeDetectionInfo; CLASS_MEDIA_CHANGE_CONTEXT mcnContext; + PIO_WORKITEM workItem; if (!((NewState >= MediaUnknown) && (NewState <= MediaUnavailable))) { return; @@ -837,6 +838,25 @@ ClasspInternalSetMediaChangeState( return; } + + // + // Inform PartMgr that the media changed. It will need to propagate + // DO_VERIFY_VOLUME to each partition. Ensure that only one work item + // updates the disk's properties at any given time. + // + if (InterlockedCompareExchange((volatile LONG *)&FdoExtension->PrivateFdoData->UpdateDiskPropertiesWorkItemActive, 1, 0) == 0) { + + workItem = IoAllocateWorkItem(FdoExtension->DeviceObject); + + if (workItem) { + + IoQueueWorkItem(workItem, ClasspUpdateDiskProperties, DelayedWorkQueue, workItem); + + } else { + + InterlockedExchange((volatile LONG *)&FdoExtension->PrivateFdoData->UpdateDiskPropertiesWorkItemActive, 0); + } + } if(info->MediaChangeDetectionDisableCount != 0) { #if DBG @@ -2595,8 +2615,8 @@ ClasspMediaChangeDeviceInstanceOverride( RtlZeroMemory(&queryTable[0], sizeof(queryTable)); - queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; - queryTable[0].DefaultType = REG_DWORD; + queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK; + queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; queryTable[0].DefaultLength = 0; if (i==0) { @@ -3001,7 +3021,7 @@ ClasspIsMediaChangeDisabledForClass( parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; parameters[0].Name = L"Autorun"; parameters[0].EntryContext = &mcnRegistryValue; - parameters[0].DefaultType = REG_DWORD; + parameters[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD; parameters[0].DefaultData = &mcnRegistryValue; parameters[0].DefaultLength = sizeof(ULONG); diff --git a/storage/class/classpnp/src/class.c b/storage/class/classpnp/src/class.c index 6113cd7e..5e7f00f1 100644 --- a/storage/class/classpnp/src/class.c +++ b/storage/class/classpnp/src/class.c @@ -1955,13 +1955,6 @@ NTSTATUS ClassPnpStartDevice(IN PDEVICE_OBJECT DeviceObject) } - // Initialize performance counter frequency - KeQueryPerformanceCounter(&(fdoExtension->PrivateFdoData->PerfCounterFrequency)); - - if (fdoExtension->PrivateFdoData->PerfCounterFrequency.QuadPart == 0) { - fdoExtension->PrivateFdoData->PerfCounterFrequency.QuadPart = 1; - } - /* * Anchor the FDO in our static list. * Pnp is synchronized, so we shouldn't need any synchronization here. @@ -2244,6 +2237,16 @@ NTSTATUS ClassPnpStartDevice(IN PDEVICE_OBJECT DeviceObject) UNREFERENCED_PARAMETER(legacyErrorHandling); #endif + + // + // Get the copy offload max target duration value. + // This function will set the default value if one hasn't been + // specified in the registry. + // + ClasspGetCopyOffloadMaxDuration(DeviceObject, + REG_DISK_CLASS_CONTROL, + &(fdoExtension->PrivateFdoData->CopyOffloadMaxTargetDuration)); + } } @@ -2409,6 +2412,7 @@ NTSTATUS ClassReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); if (isRemoved) { Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; + Irp->IoStatus.Information = 0; ClassReleaseRemoveLock(DeviceObject, Irp); ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); status = STATUS_DEVICE_DOES_NOT_EXIST; @@ -2451,6 +2455,7 @@ NTSTATUS ClassReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) _Analysis_assume_(status != STATUS_PENDING); if (!NT_SUCCESS(status)){ NT_ASSERT(Irp->IoStatus.Status == status); + Irp->IoStatus.Information = 0; ClassReleaseRemoveLock(DeviceObject, Irp); ClassCompleteRequest (DeviceObject, Irp, IO_NO_INCREMENT); } @@ -2575,8 +2580,7 @@ NTSTATUS ClassReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) ClasspMarkIrpAsIdle(Irp, FALSE); status = ServiceTransferRequest(DeviceObject, Irp, FALSE); if (fdoData->IdlePrioritySupported == TRUE) { - fdoData->LastIoTime = ClasspGetCurrentTime(NULL); - fdoData->IdleTicks = 0; + fdoData->LastNonIdleIoTime = ClasspGetCurrentTime(); } ClassReleaseRemoveLock(DeviceObject, (PVOID)&uniqueAddr); @@ -7274,6 +7278,7 @@ ClassDeviceControl( NTSTATUS status; ULONG modifiedIoControlCode = 0; + GUID activityId = {0}; // @@ -7457,9 +7462,11 @@ ClassDeviceControl( driveLetterName.Length = 0; queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | - RTL_QUERY_REGISTRY_DIRECT; + RTL_QUERY_REGISTRY_DIRECT | + RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = valueName; queryTable[0].EntryContext = &driveLetterName; + queryTable->DefaultType = (REG_SZ << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, L"\\Registry\\Machine\\System\\DISK", @@ -8550,7 +8557,7 @@ ClassDeviceControl( // only process Trim action in class layer if possible. case DeviceDsmAction_Trim: { - status = ClasspDeviceTrimProcess(DeviceObject, Irp, srb); + status = ClasspDeviceTrimProcess(DeviceObject, Irp, &activityId, srb); break; } @@ -9451,10 +9458,10 @@ ClassQueryTimeOutRegistryValue( RtlZeroMemory(parameters, (sizeof(RTL_QUERY_REGISTRY_TABLE)*2)); - parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK; parameters[0].Name = L"TimeOutValue"; parameters[0].EntryContext = &timeOut; - parameters[0].DefaultType = REG_DWORD; + parameters[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD; parameters[0].DefaultData = &zero; parameters[0].DefaultLength = sizeof(ULONG); @@ -12589,10 +12596,10 @@ ClasspScanForSpecialInRegistry( // Setup the structure to read // - queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = CLASSP_REG_HACK_VALUE_NAME; queryTable[0].EntryContext = &deviceHacks; - queryTable[0].DefaultType = REG_DWORD; + queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD; queryTable[0].DefaultData = &deviceHacks; queryTable[0].DefaultLength = 0; @@ -13369,7 +13376,7 @@ Arguments: DeviceObject - Supplies the device object associated with this request Irp - The IRP to be processed - Srb - An SRB that can be optinally used to process this request + Srb - An SRB that can be optimally used to process this request Return Value: @@ -15608,12 +15615,18 @@ Return Value: --*/ { - NT_ASSERT( - OffloadWriteContext->TotalSectorsProcessedSuccessfully <= - OffloadWriteContext->TotalRequestSizeSectors); + PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = OffloadWriteContext->Fdo->DeviceExtension; + PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; - // Time taken in 100 ns units + // + // Time taken in 100ns units. + // ULONGLONG durationIn100ns = (KeQueryInterruptTime() - OffloadWriteContext->OperationStartTime); + ULONGLONG maxTargetDuration = fdoData->CopyOffloadMaxTargetDuration * 10ULL * 1000 * 1000; + + NT_ASSERT( + OffloadWriteContext->TotalSectorsProcessedSuccessfully <= + OffloadWriteContext->TotalRequestSizeSectors); if (OffloadWriteContext->TotalSectorsProcessedSuccessfully == OffloadWriteContext->TotalRequestSizeSectors) { @@ -15627,7 +15640,7 @@ Return Value: // Since we don't want a layered timeout mechanism (e.g. guest and parent OS in Hyper-V scenarios) // to cause a SCSI timeout for the higher layer token operations. // - if (MAX_TARGET_DURATION <= durationIn100ns) { + if (maxTargetDuration <= durationIn100ns) { TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, diff --git a/storage/class/classpnp/src/classlog.mof b/storage/class/classpnp/src/classlog.mof index b82d2e81..2443193f 100644 --- a/storage/class/classpnp/src/classlog.mof +++ b/storage/class/classpnp/src/classlog.mof @@ -1,3 +1,6 @@ +#pragma autorecover +#pragma namespace("\\\\.\\Root\\WMI") + [WMI, guid("F903D6EC-8647-438f-9E42-891F4733EDAF")] class MSStorageDriver_ScsiRequestBlock { diff --git a/storage/class/classpnp/src/classp.h b/storage/class/classpnp/src/classp.h index e0046be8..d7d57e9d 100644 --- a/storage/class/classpnp/src/classp.h +++ b/storage/class/classpnp/src/classp.h @@ -74,7 +74,6 @@ Revision History: #define WPP_CONTROL_GUIDS WPP_CONTROL_GUIDS_NORMAL_FLAGS(WPP_GUID_CLASSPNP) #endif - /* * IA64 requires 8-byte alignment for pointers, but the IA64 NT kernel expects 16-byte alignment */ @@ -113,6 +112,7 @@ extern ULONG ClassMaxInterleavePerCriticalIo; #define CLASSP_REG_DISABLE_D3COLD (L"DisableD3Cold") #define CLASSP_REG_QERR_OVERRIDE_MODE (L"QERROverrideMode") #define CLASSP_REG_LEGACY_ERROR_HANDLING (L"LegacyErrorHandling") +#define CLASSP_REG_COPY_OFFLOAD_MAX_TARGET_DURATION (L"CopyOffloadMaxTargetDuration") #define CLASS_PERF_RESTORE_MINIMUM (0x10) #define CLASS_ERROR_LEVEL_1 (0x4) @@ -146,6 +146,7 @@ extern ULONG ClassMaxInterleavePerCriticalIo; #define NUM_MODESENSE_RETRIES 1 #define NUM_MODESELECT_RETRIES 1 #define NUM_DRIVECAPACITY_RETRIES 1 +#define NUM_THIN_PROVISIONING_RETRIES 32 #if (NTDDI_VERSION >= NTDDI_WINBLUE) @@ -194,7 +195,7 @@ extern ULONG ClassMaxInterleavePerCriticalIo; #define MAX_RECEIVE_TOKEN_INFORMATION_PARAMETER_DATA_LENGTH MAXULONG #define MAX_TOKEN_TRANSFER_SIZE MAXULONGLONG #define MAX_NUMBER_BLOCKS_PER_BLOCK_DEVICE_RANGE_DESCRIPTOR MAXULONG -#define MAX_TARGET_DURATION (4ULL * 10 * 1000 * 1000) // 4sec in 100ns units +#define DEFAULT_MAX_TARGET_DURATION 4 // 4sec #define DEFAULT_MAX_NUMBER_BYTES_PER_SYNC_WRITE_USING_TOKEN (64ULL * 1024 * 1024) // 64MB #define MAX_NUMBER_BYTES_PER_SYNC_WRITE_USING_TOKEN (256ULL * 1024 * 1024) // 256MB #define MIN_TOKEN_LIST_IDENTIFIERS 256 @@ -231,6 +232,11 @@ extern ULONG DiskIdleTimeoutInMS; extern CONST LARGE_INTEGER Magic10000; #define SHIFT10000 13 +// +// Constant to help wih various time conversions +// +#define CONST_MSECS_PER_SEC 1000 + #define Convert100nsToMilliseconds(LARGE_INTEGER) \ ( \ RtlExtendedMagicDivide((LARGE_INTEGER), Magic10000, SHIFT10000) \ @@ -494,7 +500,8 @@ typedef struct _TRANSFER_PACKET { * Stuff for retrying the transfer. */ #if (NTDDI_VERSION >= NTDDI_WINBLUE) - USHORT NumRetries; // Total number of retries remaining. + UCHAR NumRetries; // Total number of retries remaining. + UCHAR NumThinProvisioningRetries; //Number of retries carried out so far for a request failed with THIN_PROVISIONING_SOFT_THRESHOLD_ERROR UCHAR NumIoTimeoutRetries; // Number of retries remaining for a timed-out request. UCHAR TimedOut; // Indicates if this packet has timed-out. #else @@ -637,6 +644,13 @@ typedef struct _PNL_SLIST_HEADER { // struct _CLASS_PRIVATE_FDO_DATA { + // + // The amount of time allowed for a target to complete a copy offload + // operation, in seconds. Default is 4s, but it can be modified via + // registry key. + // + ULONG CopyOffloadMaxTargetDuration; + #if (NTDDI_VERSION >= NTDDI_WIN8) @@ -882,40 +896,35 @@ struct _CLASS_PRIVATE_FDO_DATA { #endif // - // Timer interval for sending low priority I/O - // - USHORT IdleTimerInterval; - - // - // Idle counts required to process idle request + // Idle duration required to process idle request // to avoid starvation // - USHORT StarvationCount; + USHORT StarvationDuration; // - // Idle timer tick count + // Idle I/O count // - ULONG IdleTimerTicks; + ULONG IdleIoCount; // - // Idle timer tick count + // Flag to indicate timer status // - ULONG IdleTicks; + LONG IdleTimerStarted; // - // Idle I/O count + // Time when the Idle timer was started // - ULONG IdleIoCount; + LARGE_INTEGER AntiStarvationStartTime; // - // Flag to indicate timer status + // Normal priority I/O time // - LONG IdleTimerStarted; + LARGE_INTEGER LastNonIdleIoTime; // - // Normal priority I/O time + // Time when the last IO of any priority completed. // - LARGE_INTEGER LastIoTime; + LARGE_INTEGER LastIoCompletionTime; // // Count of active normal priority I/O @@ -941,9 +950,6 @@ struct _CLASS_PRIVATE_FDO_DATA { ULONG MaxPowerOperationRetryCount; PIRP PowerProcessIrp; - // Counter frequency : Currently used for KeQueryPerferformanceCounter - LARGE_INTEGER PerfCounterFrequency; - // // Indicates legacy error handling should be used. // This means: @@ -1176,15 +1182,16 @@ typedef struct _IO_RETRIED_LOG_MESSAGE_CONTEXT { #define MINIMUM_RETRY_UNITS ((LONGLONG)32) #define MODE_PAGE_DATA_SIZE 192 -#define CLASS_IDLE_INTERVAL 50 // 50 milliseconds +#define CLASS_IDLE_INTERVAL_MIN 12 // 12 milliseconds +#define CLASS_IDLE_INTERVAL 12 // 12 milliseconds #define CLASS_STARVATION_INTERVAL 500 // 500 milliseconds -#define CLASS_IDLE_TIMER_TICKS 4 // // Value of 50 milliseconds in 100 nanoseconds units // #define FIFTY_MS_IN_100NS_UNITS 50 * 100 + /* * Simple singly-linked-list queuing macros, with no synchronization. */ @@ -1245,21 +1252,15 @@ ClasspIsIdleRequest( return ((BOOLEAN)Irp->Tail.Overlay.DriverContext[1]); } -extern BOOLEAN UseQPCTime; - __inline LARGE_INTEGER ClasspGetCurrentTime( - PLARGE_INTEGER Frequency + VOID ) { LARGE_INTEGER currentTime; - if (UseQPCTime) { - currentTime = KeQueryPerformanceCounter(Frequency); - } else { - currentTime.QuadPart = (LONGLONG)KeQueryUnbiasedInterruptTime(); - } + currentTime.QuadPart = KeQueryUnbiasedInterruptTimePrecise((ULONG64*)¤tTime.QuadPart); return currentTime; } @@ -1267,16 +1268,10 @@ ClasspGetCurrentTime( __inline ULONGLONG ClasspTimeDiffToMs( - PCLASS_PRIVATE_FDO_DATA FdoData, ULONGLONG TimeDiff ) { - if (UseQPCTime) { - TimeDiff *= 1000; - TimeDiff /= FdoData->PerfCounterFrequency.QuadPart; - } else { - TimeDiff /= (10 * 1000); - } + TimeDiff /= (10 * 1000); return TimeDiff; } @@ -1839,6 +1834,7 @@ NTSTATUS ClasspDeviceLBProvisioningProperty( NTSTATUS ClasspDeviceTrimProcess( _In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, + _In_ PGUID ActivityId, _Inout_ PSCSI_REQUEST_BLOCK Srb ); @@ -1906,6 +1902,14 @@ ClasspGetMaximumTokenListIdentifier( _Out_ PULONG MaximumListIdentifier ); +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +ClasspGetCopyOffloadMaxDuration( + _In_ PDEVICE_OBJECT DeviceObject, + _In_z_ PWSTR RegistryPath, + _Out_ PULONG MaxDuration + ); + _IRQL_requires_max_(APC_LEVEL) _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_same_ @@ -2595,6 +2599,11 @@ Return Value: } +BOOLEAN +ClasspIsThinProvisioningError ( + _In_ PSCSI_REQUEST_BLOCK _Srb + ); + __inline BOOLEAN ClasspLowerLayerNotSupport ( diff --git a/storage/class/classpnp/src/classpnp.vcxproj b/storage/class/classpnp/src/classpnp.vcxproj index 20ea07c2..c2802197 100644 --- a/storage/class/classpnp/src/classpnp.vcxproj +++ b/storage/class/classpnp/src/classpnp.vcxproj @@ -19,12 +19,12 @@ </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> - <ProjectGuid>{427E597B-35E8-4D6C-8AA5-35A4519B33D5}</ProjectGuid> + <ProjectGuid>{CAE2DAC6-A407-41A6-A943-11156A103D14}</ProjectGuid> <RootNamespace>$(MSBuildProjectName)</RootNamespace> <SupportsPackaging>false</SupportsPackaging> <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> <Platform Condition="'$(Platform)' == ''">Win32</Platform> - <SampleGuid>{F2A79FAF-7AB2-460E-A8F9-E0CB6AE58519}</SampleGuid> + <SampleGuid>{58F97C0C-9D73-4882-B4FA-BBEAE3EA4E10}</SampleGuid> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> diff --git a/storage/class/classpnp/src/classpnp.vcxproj.Filters b/storage/class/classpnp/src/classpnp.vcxproj.Filters index de33c904..93c2a79b 100644 --- a/storage/class/classpnp/src/classpnp.vcxproj.Filters +++ b/storage/class/classpnp/src/classpnp.vcxproj.Filters @@ -3,19 +3,19 @@ <ItemGroup> <Filter Include="Source Files"> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> - <UniqueIdentifier>{E57AA4D3-2361-468E-BADF-7E50D1657C78}</UniqueIdentifier> + <UniqueIdentifier>{EC5C82CA-040D-44DB-91A3-D25A1FF34443}</UniqueIdentifier> </Filter> <Filter Include="Header Files"> <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - <UniqueIdentifier>{73F07EE3-6460-42CC-9827-F4EB5CBD6FFA}</UniqueIdentifier> + <UniqueIdentifier>{88553D70-9C9C-49F9-B2D5-19552AB34B09}</UniqueIdentifier> </Filter> <Filter Include="Resource Files"> <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> - <UniqueIdentifier>{01AD74A8-90EE-49F4-B392-6C515177B2CB}</UniqueIdentifier> + <UniqueIdentifier>{92330849-35A6-4C9A-9499-F2492A79CD86}</UniqueIdentifier> </Filter> <Filter Include="Driver Files"> <Extensions>inf;inv;inx;mof;mc;</Extensions> - <UniqueIdentifier>{F1A14E0E-14F3-4FBA-B152-C150E51DFCB6}</UniqueIdentifier> + <UniqueIdentifier>{128D6F0C-829B-4E8A-A01D-4859DCC86D60}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> diff --git a/storage/class/classpnp/src/classwmi.c b/storage/class/classpnp/src/classwmi.c index 1df85512..1b1eeeee 100644 --- a/storage/class/classpnp/src/classwmi.c +++ b/storage/class/classpnp/src/classwmi.c @@ -40,10 +40,6 @@ Revision History: #include "classwmi.tmh" #endif -const UCHAR wmiInternalMOF[] = { -#include "classlog.x" -}; - #define TIME_STRING_LENGTH 25 BOOLEAN @@ -95,15 +91,11 @@ ClassFindInternalGuid( GUIDREGINFO wmiClassGuids[] = { { - MSWmi_MofDataGuid, 1, 0 - }, - { MSStorageDriver_ClassErrorLogGuid, 1, 0 } }; -#define MSWmi_MofData_GUID_Index 0 -#define MSStorageDriver_ClassErrorLogGuid_Index 1 +#define MSStorageDriver_ClassErrorLogGuid_Index 0 #define NUM_CLASS_WMI_GUIDS (sizeof(wmiClassGuids) / sizeof(GUIDREGINFO)) @@ -820,15 +812,7 @@ Return Value: ULONG sizeNeeded = 0, i; PFUNCTIONAL_DEVICE_EXTENSION fdoExt = DeviceObject->DeviceExtension; - if (GuidIndex == MSWmi_MofData_GUID_Index) { - sizeNeeded = sizeof(wmiInternalMOF); - if (BufferAvail >= sizeNeeded) { - RtlMoveMemory(Buffer, wmiInternalMOF, sizeof(wmiInternalMOF)); - status = STATUS_SUCCESS; - } else { - status = STATUS_BUFFER_TOO_SMALL; - } - } else if (GuidIndex == MSStorageDriver_ClassErrorLogGuid_Index) { + if (GuidIndex == MSStorageDriver_ClassErrorLogGuid_Index) { // // NOTE - ClassErrorLog is still using SCSI_REQUEST_BLOCK and will not be diff --git a/storage/class/classpnp/src/clntirp.c b/storage/class/classpnp/src/clntirp.c index d615dce1..c0fbcb1a 100644 --- a/storage/class/classpnp/src/clntirp.c +++ b/storage/class/classpnp/src/clntirp.c @@ -31,8 +31,7 @@ Revision History: VOID ClasspStartIdleTimer( - IN PCLASS_PRIVATE_FDO_DATA FdoData, - IN ULONGLONG IdleInterval + IN PCLASS_PRIVATE_FDO_DATA FdoData ); VOID @@ -48,6 +47,7 @@ ClasspServiceIdleRequest( BOOLEAN PostToDpc ); + PIRP ClasspDequeueIdleRequest( PFUNCTIONAL_DEVICE_EXTENSION FdoExtension @@ -165,7 +165,6 @@ Routine Description: Arguments: FdoExtension - Pointer to the device extension - IdleInterval - Timer interval Return Value: @@ -207,7 +206,7 @@ ClasspInitializeIdleTimer( CLASSP_REG_IDLE_INTERVAL_NAME, &idleInterval); - if ((idleInterval < CLASS_IDLE_TIMER_TICKS) || (idleInterval > USHORT_MAX)) { + if ((idleInterval < CLASS_IDLE_INTERVAL_MIN) || (idleInterval > USHORT_MAX)) { // // If the interval is too low or too high, reset it to the default value. // @@ -220,18 +219,8 @@ ClasspInitializeIdleTimer( KeInitializeDpc(&fdoData->IdleDpc, ClasspIdleTimerDpc, FdoExtension); InitializeListHead(&fdoData->IdleIrpList); fdoData->IdleTimerStarted = FALSE; - fdoData->IdleTimerInterval = (USHORT) (idleInterval / CLASS_IDLE_TIMER_TICKS); - fdoData->StarvationCount = CLASS_STARVATION_INTERVAL / fdoData->IdleTimerInterval; - - // - // Due to the coarseness of the idle timer frequency, some variability in - // the idle interval will be tolerated such that it is the desired idle - // interval on average. - fdoData->IdleInterval = - (USHORT)(idleInterval - (fdoData->IdleTimerInterval / 2)); - - fdoData->IdleTimerTicks = 0; - fdoData->IdleTicks = 0; + fdoData->StarvationDuration = CLASS_STARVATION_INTERVAL; + fdoData->IdleInterval = (USHORT)(idleInterval); fdoData->IdleIoCount = 0; fdoData->ActiveIoCount = 0; fdoData->ActiveIdleIoCount = 0; @@ -263,8 +252,6 @@ Arguments: FdoData - Pointer to the private fdo data - IdleInterval - Amount of time since the completion of the last non-idle request - Return Value: None @@ -272,8 +259,7 @@ Return Value: --*/ VOID ClasspStartIdleTimer( - IN PCLASS_PRIVATE_FDO_DATA FdoData, - IN ULONGLONG IdleInterval + IN PCLASS_PRIVATE_FDO_DATA FdoData ) { LARGE_INTEGER dueTime; @@ -287,15 +273,9 @@ ClasspStartIdleTimer( if (!timerStarted) { // - // Reset the anti-starvation timer tick counter and set the idle tick - // counter according to the actual amount of idle time. The latter is - // important to do to ensure that if the idle queue drains and the timer - // has to be stopped and started on the arrival of the next idle request, - // those requests don't get delayed unnecessarily due to IdleTicks not - // reflecting actual idle time. + // Reset the anti-starvation start time. // - FdoData->IdleTimerTicks = 0; - FdoData->IdleTicks = (ULONG)(IdleInterval / FdoData->IdleTimerInterval); + FdoData->AntiStarvationStartTime = ClasspGetCurrentTime(); // // convert milliseconds to a relative 100ns @@ -305,11 +285,11 @@ ClasspStartIdleTimer( // // multiply the period // - dueTime.QuadPart = Int32x32To64(FdoData->IdleTimerInterval, mstotimer); + dueTime.QuadPart = Int32x32To64(FdoData->IdleInterval, mstotimer); KeSetTimerEx(&FdoData->IdleTimer, dueTime, - FdoData->IdleTimerInterval, + FdoData->IdleInterval, &FdoData->IdleDpc); } return; @@ -369,36 +349,27 @@ Return Value: --*/ ULONGLONG ClasspGetIdleTime ( - IN PCLASS_PRIVATE_FDO_DATA FdoData + IN PCLASS_PRIVATE_FDO_DATA FdoData, + IN LARGE_INTEGER CurrentTime ) { ULONGLONG idleTime; - LARGE_INTEGER currentTime; NTSTATUS status; // - // If there are any outstanding non-idle requests, then there has been no - // idle time. - // - if (FdoData->ActiveIoCount > 0) { - return 0; - } - - // // Get the time difference between current time and last I/O // complete time. // - currentTime = ClasspGetCurrentTime(NULL); - status = RtlULongLongSub((ULONGLONG)currentTime.QuadPart, - (ULONGLONG)FdoData->LastIoTime.QuadPart, + status = RtlULongLongSub((ULONGLONG)CurrentTime.QuadPart, + (ULONGLONG)FdoData->LastNonIdleIoTime.QuadPart, &idleTime); if (NT_SUCCESS(status)) { // // Convert the time to milliseconds. // - idleTime = ClasspTimeDiffToMs(FdoData, idleTime); + idleTime = ClasspTimeDiffToMs(idleTime); } else { // // Failed to get time difference, assume enough time passed. @@ -411,58 +382,57 @@ ClasspGetIdleTime ( /*++ -ClasspIdleTicksSufficient +ClasspIdleDurationSufficient Routine Description: - This routine whether enough idle ticks have occurred since the completion of - the last non-idle request. + This routine computes whether enough idle duration has elapsed since the + completion of the last non-idle request. Arguments: FdoData - Pointer to the private fdo data + CurrentTimeIn - If CurrentTimeIn is non-NULL + - contents are set to NULL if the time is not updated. + - time is updated otherwise + Return Value: - TRUE if sufficient idle ticks have expired to issue the next idle request. + TRUE if sufficient idle duration has elapsed to issue the next idle request. --*/ LOGICAL -ClasspIdleTicksSufficient ( - IN PCLASS_PRIVATE_FDO_DATA FdoData +ClasspIdleDurationSufficient ( + IN PCLASS_PRIVATE_FDO_DATA FdoData, + OUT LARGE_INTEGER** CurrentTimeIn ) { ULONGLONG idleInterval; + LARGE_INTEGER CurrentTime; // - // If it has been more than enough idle timer ticks since the completion of - // the last non-idle request, enough idle time has passed. - // - - if (FdoData->IdleTicks > CLASS_IDLE_TIMER_TICKS) { - return TRUE; - } - - // - // If there have not been enough timer ticks, then there has not been - // enough idle time. + // If there are any outstanding non-idle requests, then there has been no + // idle time. // - if (FdoData->IdleTicks < CLASS_IDLE_TIMER_TICKS) { + if (FdoData->ActiveIoCount > 0) { + if (CurrentTimeIn != NULL) { + *CurrentTimeIn = NULL; + } return FALSE; } // - // IdleTicks can reach CLASS_IDLE_TIMER_TICKS before FdoData->IdleInterval - // worth of time elapses from the completion of the last non-idle request. - // This can happen because when the idle timer is running, the last non-idle - // request can complete at any time in the middle of the timer period (half - // on average) so on the next timer expiration, IdleTicks will transition - // 0->1 without its full time having passed since the completion of the last - // non-idle request. So when IdleTicks is exactly CLASS_IDLE_TIMER_TICKS, - // explicitly check whether an idle request should be issued now or on the - // next timer expiration. + // Check whether an idle request should be issued now or on the next timer + // expiration. // - idleInterval = ClasspGetIdleTime(FdoData); + + CurrentTime = ClasspGetCurrentTime(); + idleInterval = ClasspGetIdleTime(FdoData, CurrentTime); + + if (CurrentTimeIn != NULL) { + **CurrentTimeIn = CurrentTime; + } if (idleInterval >= FdoData->IdleInterval) { return TRUE; @@ -478,14 +448,8 @@ ClasspIdleTimerDpc Routine Description: Timer dpc function. This function will be called once every - IdleInterval. This will increment the IdleTicks and - if it goes above 1 (i.e., disk is in idle state) then - it will service an idle request. - - This function will increment IdleTimerTicks if the IdleTicks - does not go above 1 (i.e., disk is not in idle state). When it - reaches the starvation idle count (1 second) it will process - one idle request. + IdleInterval. An idle request will be queued if sufficient idle time + has elapsed since the last non-idle request. Arguments: @@ -509,6 +473,10 @@ ClasspIdleTimerDpc( { PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Context; PCLASS_PRIVATE_FDO_DATA fdoData; + ULONGLONG idleTime; + NTSTATUS status; + LARGE_INTEGER currentTime; + LARGE_INTEGER* pCurrentTime; UNREFERENCED_PARAMETER(Dpc); UNREFERENCED_PARAMETER(SystemArgument1); @@ -521,11 +489,10 @@ ClasspIdleTimerDpc( fdoData = fdoExtension->PrivateFdoData; - if ((fdoData->ActiveIoCount <= 0) && - (++fdoData->IdleTicks >= CLASS_IDLE_TIMER_TICKS)) { + if (fdoData->ActiveIoCount <= 0) { // - // If there are max active idle request, do not issue another one here. + // If there are max active idle requests, do not issue another one here. // if (fdoData->ActiveIdleIoCount >= fdoData->IdleActiveIoMax) { return; @@ -536,22 +503,48 @@ ClasspIdleTimerDpc( // request has completed. // - if (ClasspIdleTicksSufficient(fdoData)) { + pCurrentTime = ¤tTime; + if (ClasspIdleDurationSufficient(fdoData, &pCurrentTime)) { // // We are going to issue an idle request so reset the anti-starvation // timer counter. + // If we are here (Idle duration is sufficient), pCurrentTime is + // expected to be set. // - fdoData->IdleTimerTicks = 0; + NT_ASSERT(pCurrentTime != NULL); + fdoData->AntiStarvationStartTime = *pCurrentTime; ClasspServiceIdleRequest(fdoExtension, FALSE); } return; } // + // Get the time difference between current time and last I/O + // complete time. + // + + currentTime = ClasspGetCurrentTime(); + status = RtlULongLongSub((ULONGLONG)currentTime.QuadPart, + (ULONGLONG)fdoData->AntiStarvationStartTime.QuadPart, + &idleTime); + + if (NT_SUCCESS(status)) { + // + // Convert the time to milliseconds. + // + idleTime = ClasspTimeDiffToMs(idleTime); + } else { + // + // Failed to get time difference, assume enough time passed. + // + idleTime = fdoData->StarvationDuration; + } + + // // If the timer is running then there must be at least one idle priority I/O pending // - if (++fdoData->IdleTimerTicks >= fdoData->StarvationCount) { - fdoData->IdleTimerTicks = 0; + if (idleTime >= fdoData->StarvationDuration) { + fdoData->AntiStarvationStartTime = currentTime; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_TIMER, "ClasspIdleTimerDpc: Starvation timer. Send one idle request\n")); ClasspServiceIdleRequest(fdoExtension, FALSE); } @@ -588,24 +581,18 @@ ClasspEnqueueIdleRequest( PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; KIRQL oldIrql; BOOLEAN issueRequest = TRUE; - ULONGLONG idleInterval; + LARGE_INTEGER currentTime; + LARGE_INTEGER* pCurrentTime; TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_TIMER, "ClasspEnqueueIdleRequest: Queue idle request %p\n", Irp)); IoMarkIrpPending(Irp); // - // Get the time difference between current time and last non-idle request - // complete time. If the there has been enough idle time, then issue the - // request (unless other factors prevent us from doing so below) and set the - // idle time such that we starting the timer below, it would start off with - // enough idle ticks. + // Reset issueRequest if the idle duration is not sufficient. // - idleInterval = ClasspGetIdleTime(fdoData); - - if (idleInterval >= fdoData->IdleInterval) { - idleInterval = fdoData->IdleTimerInterval * CLASS_IDLE_TIMER_TICKS; - } else { + pCurrentTime = ¤tTime; + if (ClasspIdleDurationSufficient(fdoData, &pCurrentTime) == FALSE) { issueRequest = FALSE; } @@ -617,7 +604,6 @@ ClasspEnqueueIdleRequest( issueRequest = FALSE; } - TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_TIMER, "ClasspEnqueueIdleRequest: Diff time %I64d\n", idleInterval)); KeAcquireSpinLock(&fdoData->IdleListLock, &oldIrql); if (IsListEmpty(&fdoData->IdleIrpList)) { @@ -628,7 +614,7 @@ ClasspEnqueueIdleRequest( fdoData->IdleIoCount++; if (!fdoData->IdleTimerStarted) { - ClasspStartIdleTimer(fdoData, idleInterval); + ClasspStartIdleTimer(fdoData); } if (fdoData->IdleIoCount != 1) { @@ -699,6 +685,8 @@ ClasspDequeueIdleRequest( } KeReleaseSpinLock(&fdoData->IdleListLock, oldIrql); + + return irp; } @@ -736,7 +724,7 @@ ClasspCompleteIdleRequest( if ((fdoData->IdleIoCount > 0) && (fdoData->ActiveIdleIoCount < fdoData->IdleActiveIoMax) && (fdoData->ActiveIoCount <= 0) && - (ClasspIdleTicksSufficient(fdoData))) { + (ClasspIdleDurationSufficient(fdoData, NULL))) { TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_TIMER, "ClasspCompleteIdleRequest: Service next idle reqeusts\n")); ClasspServiceIdleRequest(FdoExtension, TRUE); } @@ -779,5 +767,3 @@ ClasspServiceIdleRequest( return; } - - diff --git a/storage/class/classpnp/src/retry.c b/storage/class/classpnp/src/retry.c index 1a74c0b2..9b732bec 100644 --- a/storage/class/classpnp/src/retry.c +++ b/storage/class/classpnp/src/retry.c @@ -458,28 +458,40 @@ BOOLEAN RetryTransferPacket(PTRANSFER_PACKET Pkt) PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; PCDB pCdb = SrbGetCdb(Pkt->Srb); - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "retrying failed transfer (pkt=%ph, op=%s)", Pkt, DBGGETSCSIOPSTR(Pkt->Srb))); + if(ClasspIsThinProvisioningError((PSCSI_REQUEST_BLOCK)Pkt->Srb) && + (pCdb != NULL) && IS_SCSIOP_READWRITE(pCdb->CDB10.OperationCode)) { - NT_ASSERT(Pkt->NumRetries > 0 || Pkt->RetryHistory); - Pkt->NumRetries--; + if(Pkt->NumThinProvisioningRetries >= NUM_THIN_PROVISIONING_RETRIES) { + //We've already retried this the maximum times. Bail out. + return TRUE; + } + Pkt->NumThinProvisioningRetries++; + } + else { + NT_ASSERT(Pkt->NumRetries > 0 || Pkt->RetryHistory); + Pkt->NumRetries--; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, "retrying failed transfer (pkt=%ph, op=%s)", Pkt, DBGGETSCSIOPSTR(Pkt->Srb))); if (!fdoData->DisableThrottling) { // // If this is the last retry, then turn off disconnect, sync transfer, // and tagged queuing. On all other retries, leave the original settings. + // Do not apply this for thin provisioning soft threshold errors, since + // they should succeed as soon as they're retried on the right IT nexus. // - if (Pkt->NumRetries == 0) { + if ((Pkt->NumRetries == 0) && !ClasspIsThinProvisioningError((PSCSI_REQUEST_BLOCK)Pkt->Srb)) { scaleDown = TRUE; } #if (NTDDI_VERSION >= NTDDI_WINBLUE) // // If this request previously timed-out and there are no more retries left - // for timed-out requests then we should also apply the scale down. + // for timed-out requests, then we should also apply the scale down. // - if (Pkt->TimedOut && - Pkt->NumIoTimeoutRetries == 0) { + if (Pkt->TimedOut && Pkt->NumIoTimeoutRetries == 0) { scaleDown = TRUE; } #endif diff --git a/storage/class/classpnp/src/utils.c b/storage/class/classpnp/src/utils.c index 20917d83..323d7449 100644 --- a/storage/class/classpnp/src/utils.c +++ b/storage/class/classpnp/src/utils.c @@ -118,10 +118,10 @@ VOID ClassGetDeviceParameter( defaultParameterValue = *ParameterValue; - queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; + queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK; queryTable->Name = ParameterName; queryTable->EntryContext = ParameterValue; - queryTable->DefaultType = REG_DWORD; + queryTable->DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; queryTable->DefaultData = NULL; queryTable->DefaultLength = 0; @@ -181,10 +181,10 @@ VOID ClassGetDeviceParameter( defaultParameterValue = *ParameterValue; - queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; + queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_TYPECHECK; queryTable->Name = ParameterName; queryTable->EntryContext = ParameterValue; - queryTable->DefaultType = REG_DWORD; + queryTable->DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; queryTable->DefaultData = NULL; queryTable->DefaultLength = 0; @@ -1569,7 +1569,7 @@ ClassReadCapacity16 ( FdoExtension->LowerLayerSupport->AccessAlignment.LowerLayerSupported = Supported; to indicate that info has been cached. - NOTE: some future processes may use this funciton to send the command anyway, it will be caller's decision + NOTE: some future processes may use this function to send the command anyway, it will be caller's decision on checking 'AccessAlignment.LowerLayerSupported' in case the cached info is good enough. */ { @@ -1638,7 +1638,7 @@ ClassReadCapacity16 ( //prepare the Srb if (NT_SUCCESS(status)) { - + SrbSetTimeOutValue(Srb, FdoExtension->TimeOutValue); SrbSetRequestTag(Srb, SP_UNTAGGED); SrbSetRequestAttribute(Srb, SRB_SIMPLE_TAG_REQUEST); @@ -1745,7 +1745,7 @@ NTSTATUS ClasspAccessAlignmentProperty( // // Request validation. - // Note that InputBufferLength and IsFdo have been validated beforing entering this routine. + // Note that InputBufferLength and IsFdo have been validated before entering this routine. // if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { @@ -1814,7 +1814,7 @@ NTSTATUS ClasspAccessAlignmentProperty( } else { information = 0; } - goto Exit; + } else { // case 2: the request is supported and it completes successfully // case 3: the request is supported by lower stack but other failure status is returned. @@ -1823,8 +1823,11 @@ NTSTATUS ClasspAccessAlignmentProperty( information = (ULONG)Irp->IoStatus.Information; - goto Exit; } + + + goto Exit; + break; } @@ -1851,7 +1854,7 @@ NTSTATUS ClasspAccessAlignmentProperty( } case Supported: { - NT_ASSERT(FALSE); // this case is handled at the begining of the function. + NT_ASSERT(FALSE); // this case is handled at the beginning of the function. status = STATUS_INTERNAL_ERROR; break; } @@ -3154,6 +3157,8 @@ DeviceProcessDsmTrimRequest( _In_ ULONG DataSetRangesCount, _In_ ULONG UnmapGranularity, _In_ ULONG SrbFlags, + _In_ PIRP Irp, + _In_ PGUID ActivityId, _Inout_ PSCSI_REQUEST_BLOCK Srb ) /*++ @@ -3199,8 +3204,11 @@ Return Value: ULONGLONG maxLbaCount; ULONGLONG maxParameterListLength; - UNREFERENCED_PARAMETER(UnmapGranularity); + UNREFERENCED_PARAMETER(UnmapGranularity); + UNREFERENCED_PARAMETER(ActivityId); + UNREFERENCED_PARAMETER(Irp); + // // The given LBA ranges are in DEVICE_DATA_SET_RANGE format and need to be converted into UNMAP Block Descriptors. // The UNMAP command is able to carry 0xFFFF bytes (0xFFF8 in reality as there are 8 bytes of header plus n*16 bytes of Block Descriptors) of data. @@ -3320,6 +3328,7 @@ Return Value: blockDescrIndex = 0; lbaCount = 0; + while (!allDataSetRangeFullyConverted) { // @@ -3348,8 +3357,8 @@ Return Value: // // Send the UNMAP command when the buffer is full or when all input entries are converted. // - if ( (blockDescrIndex == maxBlockDescrCount) || // Buffer full or block descriptor count reached - (lbaCount == maxLbaCount) || // Block LBA count reached + if ((blockDescrIndex == maxBlockDescrCount) || // Buffer full or block descriptor count reached + (lbaCount == maxLbaCount) || // Block LBA count reached allDataSetRangeFullyConverted) { // All DataSetRanges have been converted USHORT transferSize; @@ -3457,6 +3466,7 @@ Exit: NTSTATUS ClasspDeviceTrimProcess( _In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, + _In_ PGUID ActivityId, _Inout_ PSCSI_REQUEST_BLOCK Srb ) /* @@ -3483,6 +3493,7 @@ NTSTATUS ClasspDeviceTrimProcess( CLASS_VPD_B0_DATA blockLimitsData; ULONG generationCount; + if ( (DeviceObject->DeviceType != FILE_DEVICE_DISK) || (TEST_FLAG(DeviceObject->Characteristics, FILE_FLOPPY_DISKETTE)) || (fdoExtension->FunctionSupportInfo->LowerLayerSupport.TrimProcess == Supported) ) { @@ -3511,6 +3522,7 @@ NTSTATUS ClasspDeviceTrimProcess( goto Exit; } + // // If the caller has not set the "entire dataset range" flag then at least // one dataset range should be specified. However, if the caller *has* set @@ -3703,6 +3715,8 @@ NTSTATUS ClasspDeviceTrimProcess( dataSetRangesCount, granularityInBlocks, srbFlags, + Irp, + ActivityId, Srb); } else { // DSM IOCTL should be completed as not supported @@ -3736,6 +3750,8 @@ Exit: Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; + + ClassReleaseRemoveLock(DeviceObject, Irp); ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); @@ -6725,7 +6741,7 @@ Return Value: // // Indicate that there is NO call-back routine. // - queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK; // // The value to query. @@ -6736,7 +6752,7 @@ Return Value: // Where to put the value, the type of the value, default value and length. // queryTable[0].EntryContext = &value; - queryTable[0].DefaultType = REG_DWORD; + queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD; queryTable[0].DefaultData = &value; queryTable[0].DefaultLength = sizeof(value); @@ -6765,6 +6781,99 @@ Return Value: return status; } +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +ClasspGetCopyOffloadMaxDuration( + _In_ PDEVICE_OBJECT DeviceObject, + _In_z_ PWSTR RegistryPath, + _Out_ PULONG MaxDuration + ) + + /*++ + + Routine Description: + + This routine returns the maximum time (in seconds) that a Copy Offload + operation should take to complete by a target. + + Arguments: + + DeviceObject - The device handling the request. + RegistryPath - The absolute registry path under which MaxDuration resides. + MaxDuration - Returns the value being queried, in seconds. + + Return Value: + + STATUS_SUCCESS or appropriate error status returned by Registry API. + + --*/ + +{ + RTL_QUERY_REGISTRY_TABLE queryTable[2]; + ULONG value = 0; + NTSTATUS status; + + TracePrint((TRACE_LEVEL_VERBOSE, + TRACE_FLAG_PNP, + "ClasspGetCopyOffloadMaxDuration (%p): Entering function.\n", + DeviceObject)); + + // + // Zero the table entries. + // + RtlZeroMemory(queryTable, sizeof(queryTable)); + + // + // The query table has two entries. One for CopyOffloadMaxDuration and + // the second which is the 'NULL' terminator. + // + // Indicate that there is NO call-back routine. + // + queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK; + + // + // The value to query. + // + queryTable[0].Name = CLASSP_REG_COPY_OFFLOAD_MAX_TARGET_DURATION; + + // + // Where to put the value, the type of the value, default value and length. + // + queryTable[0].EntryContext = &value; + queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; + queryTable[0].DefaultData = &value; + queryTable[0].DefaultLength = sizeof(value); + + // + // Try to get the max target duration. + // + status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, + RegistryPath, + queryTable, + NULL, + NULL); + + // + // Don't allow the user to set the value to lower than the default (4s) so + // they don't break ODX functionality if they accidentally set it too low. + // + if (NT_SUCCESS(status) && + value > DEFAULT_MAX_TARGET_DURATION) { + *MaxDuration = value; + } else { + *MaxDuration = DEFAULT_MAX_TARGET_DURATION; + } + + TracePrint((TRACE_LEVEL_VERBOSE, + TRACE_FLAG_PNP, + "ClasspGetCopyOffloadMaxDuration (%p): Exiting function with status %x (Max Duration %u seconds).\n", + DeviceObject, + status, + *MaxDuration)); + + return status; +} + _IRQL_requires_max_(APC_LEVEL) _IRQL_requires_min_(PASSIVE_LEVEL) @@ -8205,7 +8314,7 @@ ClassDeviceHwFirmwareIsPortDriverSupported( /* Routine Description: - This function informs the caller whether the port driver supports hardware firmware requests. + This function informs the caller whether the port driver supports hardware firmware requests. Arguments: DeviceObject: The target object. @@ -8343,10 +8452,15 @@ Exit_Firmware_Get_Info: // // Firmware information is already cached in classpnp. Return a copy. // + KLOCK_QUEUE_HANDLE lockHandle; + KeAcquireInStackQueuedSpinLock(&fdoExtension->FunctionSupportInfo->SyncLock, &lockHandle); + ULONG dataLength = min(irpStack->Parameters.DeviceIoControl.OutputBufferLength, fdoExtension->FunctionSupportInfo->HwFirmwareInfo->Size); memcpy(Irp->AssociatedIrp.SystemBuffer, fdoExtension->FunctionSupportInfo->HwFirmwareInfo, dataLength); + KeReleaseInStackQueuedSpinLock(&lockHandle); + Irp->IoStatus.Information = dataLength; } @@ -8426,6 +8540,8 @@ ClassDeviceHwFirmwareDownloadProcess( PIRP irp2 = NULL; PIO_STACK_LOCATION newStack = NULL; PCDB cdb = NULL; + BOOLEAN lockHeld = FALSE; + KLOCK_QUEUE_HANDLE lockHandle; // @@ -8521,6 +8637,13 @@ ClassDeviceHwFirmwareDownloadProcess( } // + // Acquire the SyncLock to ensure the HwFirmwareInfo pointer doesn't change + // while we're dereferencing it. + // + lockHeld = TRUE; + KeAcquireInStackQueuedSpinLock(&fdoExtension->FunctionSupportInfo->SyncLock, &lockHandle); + + // // Validate the device support // if ((fdoExtension->FunctionSupportInfo->HwFirmwareInfo->SupportUpgrade == FALSE) || @@ -8573,6 +8696,14 @@ ClassDeviceHwFirmwareDownloadProcess( // bufferSize = ALIGN_UP_BY(firmwareDownload->BufferSize, fdoExtension->FunctionSupportInfo->HwFirmwareInfo->ImagePayloadAlignment); + // + // We're done accessing HwFirmwareInfo at this point so we can release + // the SyncLock. + // + NT_ASSERT(lockHeld); + KeReleaseInStackQueuedSpinLock(&lockHandle); + lockHeld = FALSE; + #pragma prefast(suppress:6014, "The allocated memory that firmwareImageBuffer points to will be freed in ClassHwFirmwareDownloadComplete().") firmwareImageBuffer = ExAllocatePoolWithTag(NonPagedPoolNx, bufferSize, CLASSPNP_POOL_TAG_FIRMWARE); @@ -8586,6 +8717,10 @@ ClassDeviceHwFirmwareDownloadProcess( RtlCopyMemory(firmwareImageBuffer, firmwareDownload->ImageBuffer, (ULONG)firmwareDownload->BufferSize); } else { + NT_ASSERT(lockHeld); + KeReleaseInStackQueuedSpinLock(&lockHandle); + lockHeld = FALSE; + firmwareImageBuffer = firmwareDownload->ImageBuffer; bufferSize = (ULONG)firmwareDownload->BufferSize; } @@ -8654,7 +8789,7 @@ ClassDeviceHwFirmwareDownloadProcess( SrbSetCdbLength(Srb, CDB10GENERIC_LENGTH); cdb = SrbGetCdb(Srb); cdb->WRITE_BUFFER.OperationCode = SCSIOP_WRITE_DATA_BUFF; - cdb->WRITE_BUFFER.Mode = 0x0E; + cdb->WRITE_BUFFER.Mode = SCSI_WRITE_BUFFER_MODE_DOWNLOAD_MICROCODE_WITH_OFFSETS_SAVE_DEFER_ACTIVATE; cdb->WRITE_BUFFER.ModeSpecific = 0; //Reserved for Mode 0x0E cdb->WRITE_BUFFER.BufferID = firmwareDownload->Slot; @@ -8713,6 +8848,15 @@ ClassDeviceHwFirmwareDownloadProcess( Exit_Firmware_Download: // + // Release the SyncLock if it's still held. + // This should only happen in the failure path. + // + if (lockHeld) { + KeReleaseInStackQueuedSpinLock(&lockHandle); + lockHeld = FALSE; + } + + // // Firmware Download request will be failed. // NT_ASSERT(!NT_SUCCESS(status)); @@ -8751,6 +8895,8 @@ ClassDeviceHwFirmwareActivateProcess( BOOLEAN passDown = FALSE; PCDB cdb = NULL; ULONG i; + BOOLEAN lockHeld = FALSE; + KLOCK_QUEUE_HANDLE lockHandle; // @@ -8845,6 +8991,13 @@ ClassDeviceHwFirmwareActivateProcess( } // + // Acquire the SyncLock to ensure the HwFirmwareInfo pointer doesn't change + // while we're dereferencing it. + // + lockHeld = TRUE; + KeAcquireInStackQueuedSpinLock(&fdoExtension->FunctionSupportInfo->SyncLock, &lockHandle); + + // // Validate the device support // if (fdoExtension->FunctionSupportInfo->HwFirmwareInfo->SupportUpgrade == FALSE) { @@ -8870,6 +9023,14 @@ ClassDeviceHwFirmwareActivateProcess( } // + // We're done accessing HwFirmwareInfo at this point so we can release + // the SyncLock. + // + NT_ASSERT(lockHeld); + KeReleaseInStackQueuedSpinLock(&lockHandle); + lockHeld = FALSE; + + // // Process the request by translating it into WRITE BUFFER command. // // @@ -8878,7 +9039,7 @@ ClassDeviceHwFirmwareActivateProcess( SrbSetCdbLength(Srb, CDB10GENERIC_LENGTH); cdb = SrbGetCdb(Srb); cdb->WRITE_BUFFER.OperationCode = SCSIOP_WRITE_DATA_BUFF; - cdb->WRITE_BUFFER.Mode = 0x0F; + cdb->WRITE_BUFFER.Mode = SCSI_WRITE_BUFFER_MODE_ACTIVATE_DEFERRED_MICROCODE; cdb->WRITE_BUFFER.ModeSpecific = 0; //Reserved for Mode 0x0F cdb->WRITE_BUFFER.BufferID = firmwareActivate->Slot; //NOTE: this field will be ignored by SCSI device. @@ -8912,6 +9073,15 @@ ClassDeviceHwFirmwareActivateProcess( Exit_Firmware_Activate: // + // Release the SyncLock if it's still held. + // This should only happen in the failure path. + // + if (lockHeld) { + KeReleaseInStackQueuedSpinLock(&lockHandle); + lockHeld = FALSE; + } + + // // Firmware Activate request will be failed. // NT_ASSERT(!NT_SUCCESS(status)); @@ -8930,3 +9100,46 @@ Exit_Firmware_Activate: return status; } + +BOOLEAN +ClasspIsThinProvisioningError ( + _In_ PSCSI_REQUEST_BLOCK Srb + ) +/*++ + +Routine Description: + + This routine checks whether the completed SRB Srb was completed with a thin provisioning + soft threshold error. + +Arguments: + + Srb - the SRB to be checked. + +Return Value: + + BOOLEAN + +--*/ +{ + if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) { + PVOID senseBuffer = SrbGetSenseInfoBuffer(Srb); + if (senseBuffer) { + UCHAR senseKey = 0; + UCHAR addlSenseCode = 0; + UCHAR addlSenseCodeQual = 0; + BOOLEAN validSense = ScsiGetSenseKeyAndCodes(senseBuffer, + SrbGetSenseInfoBufferLength(Srb), + SCSI_SENSE_OPTIONS_NONE, + &senseKey, + &addlSenseCode, + &addlSenseCodeQual); + + return (validSense + && (senseKey == SCSI_SENSE_UNIT_ATTENTION) + && (addlSenseCode == SCSI_ADSENSE_LB_PROVISIONING) + && (addlSenseCodeQual == SCSI_SENSEQ_SOFT_THRESHOLD_REACHED)); + } + } + return FALSE; +} diff --git a/storage/class/classpnp/src/xferpkt.c b/storage/class/classpnp/src/xferpkt.c index db728770..e66918b0 100644 --- a/storage/class/classpnp/src/xferpkt.c +++ b/storage/class/classpnp/src/xferpkt.c @@ -700,6 +700,7 @@ PTRANSFER_PACKET DequeueFreeTransferPacketEx( } + /* * SetupReadWriteTransferPacket * @@ -824,6 +825,7 @@ VOID SetupReadWriteTransferPacket( PTRANSFER_PACKET Pkt, Pkt->SyncEventPtr = NULL; Pkt->CompleteOriginalIrpWhenLastPacketCompletes = TRUE; Pkt->NumIoTimeoutRetries = fdoData->MaxNumberOfIoRetries; + Pkt->NumThinProvisioningRetries = 0; if (pCdb) { @@ -927,6 +929,8 @@ NTSTATUS TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Co BOOLEAN packetDone = FALSE; BOOLEAN idleRequest = FALSE; ULONG transferLength; + LARGE_INTEGER completionTime; + ULONGLONG lastIoCompletionTime; UNREFERENCED_PARAMETER(NullFdo); @@ -938,14 +942,31 @@ NTSTATUS TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Co HISTORYLOGRETURNEDPACKET(pkt); + completionTime = ClasspGetCurrentTime(); + + // + // Record the time at which the last IO completed while snapping the old + // value to be used later. This can occur on multiple threads and hence + // could be overwritten with an older value. This is OK because this value + // is maintained as a heuristic. + // + +#ifdef _WIN64 + lastIoCompletionTime = ReadULong64NoFence((volatile ULONG64*)&fdoData->LastIoCompletionTime.QuadPart); + WriteULong64NoFence((volatile ULONG64*)&fdoData->LastIoCompletionTime.QuadPart, + completionTime.QuadPart); +#else + lastIoCompletionTime = InterlockedExchangeNoFence64((volatile LONG64*)&fdoData->LastIoCompletionTime.QuadPart, + completionTime.QuadPart); +#endif + if (fdoData->IdlePrioritySupported == TRUE) { idleRequest = ClasspIsIdleRequest(pkt->OriginalIrp); if (idleRequest) { InterlockedDecrement(&fdoData->ActiveIdleIoCount); NT_ASSERT(fdoData->ActiveIdleIoCount >= 0); } else { - fdoData->LastIoTime = ClasspGetCurrentTime(NULL); - fdoData->IdleTicks = 0; + fdoData->LastNonIdleIoTime = completionTime; InterlockedDecrement(&fdoData->ActiveIoCount); NT_ASSERT(fdoData->ActiveIoCount >= 0); } @@ -979,6 +1000,7 @@ NTSTATUS TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Co InterlockedExchangeAdd((PLONG)&pkt->OriginalIrp->IoStatus.Information, (LONG)transferLength); + if ((pkt->InLowMemRetry) || (pkt->DriverUsesStartIO && pkt->LowMemRetry_remainingBufLen > 0)) { packetDone = StepLowMemRetry(pkt); @@ -1028,6 +1050,7 @@ NTSTATUS TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Co ClassReleaseQueue(pkt->Fdo); } + if (NT_SUCCESS(Irp->IoStatus.Status)){ /* * The error was recovered above in the InterpretTransferPacketError() call. @@ -1741,7 +1764,6 @@ Return Value: Pkt->ContinuationRoutine = ClasspPopulateTokenTransferPacketDone; Pkt->ContinuationContext = OffloadReadContext; - TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "ClasspSetupPopulateTokenTransferPacket (%p): Exiting function with Irp %p\n", @@ -1839,7 +1861,6 @@ Return Value: Pkt->ContinuationRoutine = ClasspReceivePopulateTokenInformationTransferPacketDone; Pkt->ContinuationContext = OffloadReadContext; - TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "ClasspSetupReceivePopulateTokenInformationTransferPacket (%p): Exiting function with Irp %p\n", @@ -1941,7 +1962,6 @@ Return Value: Pkt->ContinuationRoutine = ClasspWriteUsingTokenTransferPacketDone; Pkt->ContinuationContext = OffloadWriteContext; - TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "ClasspSetupWriteUsingTokenTransferPacket (%p): Exiting function with Irp %p\n", @@ -2040,7 +2060,6 @@ Return Value: Pkt->ContinuationRoutine = ClasspReceiveWriteUsingTokenInformationTransferPacketDone; Pkt->ContinuationContext = OffloadWriteContext; - TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, "ClasspSetupReceiveWriteUsingTokenInformationTransferPacket (%p): Exiting function with Irp %p\n", diff --git a/storage/class/disk/disk.sln b/storage/class/disk/disk.sln index 3632e931..26ff24dd 100644 --- a/storage/class/disk/disk.sln +++ b/storage/class/disk/disk.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0 MinimumVisualStudioVersion = 12.0 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "disk", "src\disk.vcxproj", "{0900F953-9DAF-4C58-9137-45A2DEC9C62C}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "disk", "src\disk.vcxproj", "{C4E8B1CC-0131-442C-8EB8-8E84F938878A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Debug|Win32.ActiveCfg = Debug|Win32 - {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Debug|Win32.Build.0 = Debug|Win32 - {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Release|Win32.ActiveCfg = Release|Win32 - {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Release|Win32.Build.0 = Release|Win32 - {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Debug|x64.ActiveCfg = Debug|x64 - {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Debug|x64.Build.0 = Debug|x64 - {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Release|x64.ActiveCfg = Release|x64 - {0900F953-9DAF-4C58-9137-45A2DEC9C62C}.Release|x64.Build.0 = Release|x64 + {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Debug|Win32.Build.0 = Debug|Win32 + {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Release|Win32.ActiveCfg = Release|Win32 + {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Release|Win32.Build.0 = Release|Win32 + {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Debug|x64.ActiveCfg = Debug|x64 + {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Debug|x64.Build.0 = Debug|x64 + {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Release|x64.ActiveCfg = Release|x64 + {C4E8B1CC-0131-442C-8EB8-8E84F938878A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/storage/class/disk/src/disk.c b/storage/class/disk/src/disk.c index 3d4d19b4..05f0d6d3 100644 --- a/storage/class/disk/src/disk.c +++ b/storage/class/disk/src/disk.c @@ -1550,6 +1550,7 @@ Return Value: PIO_STACK_LOCATION irpSp = NULL; PSTOR_ADDR_BTL8 storAddrBtl8; PSRBEX_DATA_SCSI_CDB16 srbExDataCdb16; + NTSTATUS SyncCacheStatus = STATUS_SUCCESS; // // Fill in the srb fields appropriately @@ -1623,7 +1624,7 @@ Return Value: TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending sync cache\n")); - ClassSendSrbSynchronous(Fdo, srb, NULL, 0, TRUE); + SyncCacheStatus = ClassSendSrbSynchronous(Fdo, srb, NULL, 0, TRUE); } // @@ -1669,7 +1670,7 @@ Return Value: irpSp->MajorFunction = IRP_MJ_SCSI; irpSp->Parameters.Scsi.Srb = srb; - IoSetCompletionRoutine(FlushContext->CurrIrp, DiskFlushComplete, NULL, TRUE, TRUE, TRUE); + IoSetCompletionRoutine(FlushContext->CurrIrp, DiskFlushComplete, (PVOID)SyncCacheStatus, TRUE, TRUE, TRUE); TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_SCSI, "DiskFlushDispatch: sending srb flush on irp %p\n", FlushContext->CurrIrp)); @@ -1700,7 +1701,9 @@ Arguments: Fdo - The device object which requested the completion routine Irp - The irp that is being completed - Context - The flush group context + Context - If disk had write cache enabled and SYNC CACHE command was sent as 1st part of FLUSH processing + then context must carry the completion status of SYNC CACHE request, + else context must be set to STATUS_SUCCESS. Return Value: @@ -1713,8 +1716,7 @@ Return Value: NTSTATUS status; PFUNCTIONAL_DEVICE_EXTENSION fdoExt; PDISK_DATA diskData; - - UNREFERENCED_PARAMETER(Context); + NTSTATUS SyncCacheStatus = (NTSTATUS) Context; TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, "DiskFlushComplete: %p %p\n", Fdo, Irp)); @@ -1742,6 +1744,15 @@ Return Value: NT_ASSERT(status != STATUS_MORE_PROCESSING_REQUIRED); // + // If sync cache failed earlier, final status of the flush request needs to be failure + // even if SRB_FUNCTION_FLUSH srb request succeeded + // + if (NT_SUCCESS(status) && + (!NT_SUCCESS(SyncCacheStatus))) { + Irp->IoStatus.Status = status = SyncCacheStatus; + } + + // // Complete the flush requests tagged to this one // diff --git a/storage/class/disk/src/disk.vcxproj b/storage/class/disk/src/disk.vcxproj index 1f52e370..bc5efddb 100644 --- a/storage/class/disk/src/disk.vcxproj +++ b/storage/class/disk/src/disk.vcxproj @@ -19,12 +19,12 @@ </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> - <ProjectGuid>{0900F953-9DAF-4C58-9137-45A2DEC9C62C}</ProjectGuid> + <ProjectGuid>{C4E8B1CC-0131-442C-8EB8-8E84F938878A}</ProjectGuid> <RootNamespace>$(MSBuildProjectName)</RootNamespace> <SupportsPackaging>false</SupportsPackaging> <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> <Platform Condition="'$(Platform)' == ''">Win32</Platform> - <SampleGuid>{6222553B-2B65-4267-9522-973010FB316D}</SampleGuid> + <SampleGuid>{1257A10C-96B8-46FB-9FFD-6726981343C7}</SampleGuid> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> diff --git a/storage/class/disk/src/disk.vcxproj.Filters b/storage/class/disk/src/disk.vcxproj.Filters index 1a2af052..5c982e78 100644 --- a/storage/class/disk/src/disk.vcxproj.Filters +++ b/storage/class/disk/src/disk.vcxproj.Filters @@ -3,19 +3,19 @@ <ItemGroup> <Filter Include="Source Files"> <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> - <UniqueIdentifier>{9D58AF57-E3D3-492B-A93C-CD4BD860C101}</UniqueIdentifier> + <UniqueIdentifier>{5312DB94-F2AD-4908-9DC6-C3525D0469E6}</UniqueIdentifier> </Filter> <Filter Include="Header Files"> <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - <UniqueIdentifier>{5021C225-A54E-4A00-A24F-A0AEC3B6B92A}</UniqueIdentifier> + <UniqueIdentifier>{1EA3AD8C-6E4B-4964-A3D1-62178CDEC868}</UniqueIdentifier> </Filter> <Filter Include="Resource Files"> <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> - <UniqueIdentifier>{2092A6B9-C332-464C-B263-00060DE1B3E0}</UniqueIdentifier> + <UniqueIdentifier>{2A5B4A49-7B7B-4C84-9F4D-4B3B50FFA526}</UniqueIdentifier> </Filter> <Filter Include="Driver Files"> <Extensions>inf;inv;inx;mof;mc;</Extensions> - <UniqueIdentifier>{2F3C9ECA-BD6F-472C-915B-51096E28B70C}</UniqueIdentifier> + <UniqueIdentifier>{48E85F2C-8024-453C-8D4D-AFA7E6BB0AB7}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> diff --git a/storage/class/disk/src/geometry.c b/storage/class/disk/src/geometry.c index 911a33a4..a852c092 100644 --- a/storage/class/disk/src/geometry.c +++ b/storage/class/disk/src/geometry.c @@ -1358,8 +1358,8 @@ Return Value: // ISSUE-2000/5/24-henrygab - figure out if there's a way to keep // removals from happening while doing this. // - - for(deviceObject = DriverObject->DeviceObject, unmatchedDiskCount = 0; + unmatchedDiskCount = 0; + for(deviceObject = DriverObject->DeviceObject; deviceObject != NULL; #pragma prefast(suppress:28175, "Need to access the opaque field to scan through the list of disks") deviceObject = deviceObject->NextDevice) { diff --git a/storage/class/disk/src/pnp.c b/storage/class/disk/src/pnp.c index bb3a33c5..5eb333e7 100644 --- a/storage/class/disk/src/pnp.c +++ b/storage/class/disk/src/pnp.c @@ -122,9 +122,10 @@ Return Value: LEAVE; } - queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK; queryTable[0].Name = L"RootPartitionMountable"; queryTable[0].EntryContext = &(rootPartitionMountable); + queryTable[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; #pragma prefast(suppress:6309, "We don't have QueryRoutine so Context doesn't make any sense") status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, |
