Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

15892 lines
471 KiB

  1. /*++
  2. Copyright (c) 1996-1998 Microsoft Corporation
  3. Module Name:
  4. clusdisk.c
  5. Abstract:
  6. This driver controls access to disks in an NT cluster environment.
  7. Initially this driver will support SCSI, but other controller types
  8. should be supported in the future.
  9. Authors:
  10. Rod Gamache 13-Feb-1996
  11. Environment:
  12. kernel mode only
  13. Notes:
  14. Revision History:
  15. --*/
  16. #define _NTDDK_
  17. #include "initguid.h"
  18. #include "clusdskp.h"
  19. #include "ntddk.h"
  20. #include "diskarbp.h"
  21. #include "ntddft.h"
  22. #include "clusdisk.h"
  23. #include "scsi.h"
  24. #include "ntddcnet.h"
  25. #include "mountdev.h"
  26. #include "ntddvol.h" // IOCTL_VOLUME_ONLINE
  27. #include "wdmguid.h"
  28. #include "clusverp.h"
  29. #include <partmgrp.h> // PartMgr IOCTLs
  30. #if !defined(WMI_TRACING)
  31. #define CDLOG0(Dummy)
  32. #define CDLOG(Dummy1,Dummy2)
  33. #define CDLOGFLG(Dummy0,Dummy1,Dummy2)
  34. #define LOGENABLED(Dummy) FALSE
  35. #else
  36. #include "clusdisk.tmh"
  37. #endif // !defined(WMI_TRACING)
  38. extern POBJECT_TYPE *IoFileObjectType;
  39. //
  40. // format string for old style partition names. 10 extra chars are added
  41. // for enough space for the disk and partition numbers
  42. //
  43. #define DEVICE_PARTITION_NAME L"\\Device\\Harddisk%d\\Partition%d"
  44. #define MAX_PARTITION_NAME_LENGTH (( sizeof(DEVICE_PARTITION_NAME) / sizeof(WCHAR)) + 10 )
  45. //
  46. // format string for a clusdisk non-zero partition device
  47. //
  48. #define CLUSDISK_DEVICE_NAME L"\\Device\\ClusDisk%uPart%u"
  49. #define MAX_CLUSDISK_DEVICE_NAME_LENGTH (( sizeof(CLUSDISK_DEVICE_NAME) / sizeof(WCHAR)) + 10 )
  50. #define RESET_SLEEP 1 // Sleep for 1 second after bus resets.
  51. // max # of partition entries we can handle that are returned
  52. // by IOCTL_DISK_GET_DRIVE_LAYOUT
  53. #define MAX_PARTITIONS 128
  54. #ifndef max
  55. #define max( a, b ) ((a) >= (b) ? (a) : (b))
  56. #endif
  57. #define UNHANDLED_ERROR( status ) \
  58. if ( !NT_SUCCESS(status) ) { \
  59. KeBugCheck(status); \
  60. }
  61. #define CLUSDISK_ALLOC_TAG 'kdSC'
  62. #ifndef ASSERT_RESERVES_STARTED
  63. #define ASSERT_RESERVES_STARTED( _de ) \
  64. ASSERT( _de->PerformReserves == TRUE && _de->ReserveTimer != 0 );
  65. #endif
  66. #ifndef ASSERT_RESERVES_STOPPED
  67. #define ASSERT_RESERVES_STOPPED( _de ) \
  68. ASSERT( _de->PerformReserves == FALSE || _de->ReserveTimer == 0 );
  69. #endif
  70. #define OFFLINE_DISK( _physDisk ) \
  71. _physDisk->DiskState = DiskOffline; \
  72. SetVolumeState( _physDisk, DiskOffline );
  73. #define ONLINE_DISK( _physDisk ) \
  74. _physDisk->DiskState = DiskOnline; \
  75. SetVolumeState( _physDisk, DiskOnline );
  76. #define DEREFERENCE_OBJECT( _obj ) \
  77. if ( _obj ) { \
  78. ObDereferenceObject( _obj ); \
  79. _obj = NULL; \
  80. }
  81. #define ACCESS_FROM_CTL_CODE(ctrlCode) (((ULONG)(ctrlCode & 0xc000)) >> 14)
  82. //
  83. // Global Data
  84. //
  85. UNICODE_STRING ClusDiskRegistryPath;
  86. #if DBG
  87. ULONG ClusDiskPrintLevel = 0;
  88. #endif
  89. #define CLUSDISK_DEBUG 1
  90. #if CLUSDISK_DEBUG
  91. ULONG ClusDiskGood = TRUE;
  92. #endif
  93. //
  94. // Spinlock for protecting global data.
  95. //
  96. KSPIN_LOCK ClusDiskSpinLock;
  97. //
  98. // Resource to protect the list of the device objects
  99. // associated with the DriverObject
  100. //
  101. // We also use this resource to synchronize
  102. // HoldIo and users of the OpenFileHandles function,
  103. //
  104. // Lock order is
  105. // ClusDiskDeviceListLock
  106. // CancelSpinLock
  107. // ClusDiskSpinLock
  108. //
  109. ERESOURCE ClusDiskDeviceListLock;
  110. //
  111. // KeEnterCriticalRegion is required if resource
  112. // acquisition is done at a PASSIVE level in the context
  113. // of non-kernel thread.
  114. //
  115. // KeEnterCriticalRegion() == KeGetCurrentThread()->KernelApcDisable -= 1;
  116. //
  117. // guarantees that the thread in which we execute cannot get
  118. // suspeneded in APC while we own the global resource.
  119. //
  120. #define ACQUIRE_EXCLUSIVE( _lock ) \
  121. do { KeEnterCriticalRegion();ExAcquireResourceExclusiveLite(_lock, TRUE); } while(0)
  122. #define ACQUIRE_SHARED( _lock ) \
  123. do { KeEnterCriticalRegion();ExAcquireResourceSharedLite(_lock, TRUE); } while(0)
  124. #define RELEASE_EXCLUSIVE( _lock ) \
  125. do { ExReleaseResourceLite( _lock );KeLeaveCriticalRegion(); } while(0)
  126. #define RELEASE_SHARED( _lock ) \
  127. do { ExReleaseResourceLite( _lock );KeLeaveCriticalRegion(); } while(0)
  128. //
  129. // System disk signature and (SCSI?) port number
  130. //
  131. ULONG SystemDiskSignature = 0;
  132. UCHAR SystemDiskPort = 0xff; // Hopefully -1 for both fields is unused
  133. UCHAR SystemDiskPath = 0xff;
  134. //
  135. // The Root Device Object (clusdisk0)
  136. //
  137. PDEVICE_OBJECT RootDeviceObject = NULL;
  138. //
  139. // List of devices (signatures) that clusdisk should control.
  140. //
  141. PDEVICE_LIST_ENTRY ClusDiskDeviceList = NULL;
  142. //
  143. // List of SCSI busses.
  144. //
  145. PSCSI_BUS_ENTRY ClusDiskScsiBusList = NULL;
  146. //
  147. // Clusdisk is started at boot time vs run time (ie loaded).
  148. //
  149. BOOLEAN ClusDiskBootTime = TRUE;
  150. //
  151. // Clusdisk should rescan and previous disk count
  152. //
  153. BOOLEAN ClusDiskRescan = FALSE;
  154. BOOLEAN ClusDiskRescanBusy = FALSE;
  155. ULONG ClusDiskRescanRetry = 0;
  156. PVOID ClusDiskNextDisk = 0;
  157. WORK_QUEUE_ITEM ClusDiskRescanWorkItem;
  158. #define MAX_RESCAN_RETRIES 30
  159. PKPROCESS ClusDiskSystemProcess = NULL;
  160. //
  161. // Handle to ClusNet device driver.
  162. //
  163. HANDLE ClusNetHandle = NULL;
  164. //
  165. // Count of references to ClusNet.
  166. //
  167. ULONG ClusNetRefCount = 0;
  168. //
  169. // Work queue item context for halt processing.
  170. //
  171. WORK_QUEUE_ITEM HaltWorkItem = {0};
  172. BOOLEAN HaltBusy = FALSE; // TRUE if halt work item is busy
  173. //
  174. // Change notification work item queue
  175. //
  176. BOOLEAN ChangeWorkerBusy = FALSE;
  177. LIST_ENTRY ChangeWorkList;
  178. //
  179. // RemoveLock tracing
  180. //
  181. #if DBG
  182. ULONG TrackRemoveLocks = 0;
  183. ULONG TrackRemoveLocksEnableChecks = 1;
  184. PIO_REMOVE_LOCK TrackRemoveLockSpecific = 0;
  185. #endif
  186. extern PARBITRATION_ID gArbitrationBuffer;
  187. //
  188. // Forward routines
  189. //
  190. #ifdef ALLOC_PRAGMA
  191. #pragma alloc_text(INIT, DriverEntry)
  192. #pragma alloc_text(INIT, ClusDiskInitialize)
  193. #pragma alloc_text(INIT, GetSystemRootPort)
  194. #pragma alloc_text(INIT, GetBootTimeSystemRoot)
  195. #pragma alloc_text(INIT, GetRunTimeSystemRoot)
  196. #pragma alloc_text(INIT, RegistryQueryValue)
  197. //#pragma alloc_text(INIT, ResetScsiBusses)
  198. // 2000/02/05: stevedz - Pageable code cannot acquire spinlocks (or call routines that do).
  199. // ClusDiskScsiInitialize calls ClusDiskDeleteDevice which acquires a spinlock.
  200. // #pragma alloc_text(PAGE, ClusDiskScsiInitialize)
  201. #pragma alloc_text(PAGE, ClusDiskUnload)
  202. #endif // ALLOC_PRAGMA
  203. //
  204. // INIT routines
  205. //
  206. NTSTATUS
  207. RegistryQueryValue(
  208. PVOID hKey,
  209. LPWSTR pValueName,
  210. PULONG pulType,
  211. PVOID pData,
  212. PULONG pulDataSize
  213. )
  214. /*++
  215. Routine Description:
  216. Queries a value from the registry
  217. Arguments:
  218. hKey - Key with value to query
  219. pValueName - Name of value to query
  220. pulType - Returned type of data
  221. pData - Pointer to the data buffer to store result
  222. pulDataSize - Number of bytes placed into buffer
  223. Return Value:
  224. NTSTATUS
  225. - STATUS_BUFFER_OVERFLOW if buffer can't be allocated
  226. --*/
  227. {
  228. KEY_VALUE_PARTIAL_INFORMATION *pValInfo;
  229. UNICODE_STRING valName;
  230. NTSTATUS ntStatus;
  231. ULONG ulSize;
  232. // Size of query buffer
  233. ulSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + *pulDataSize;
  234. pValInfo = ExAllocatePool(NonPagedPool, ulSize );
  235. if (pValInfo == NULL)
  236. return(STATUS_BUFFER_OVERFLOW);
  237. RtlInitUnicodeString(&valName, pValueName);
  238. pValInfo->DataLength = *pulDataSize;
  239. ntStatus = ZwQueryValueKey(hKey,
  240. &valName,
  241. KeyValuePartialInformation,
  242. pValInfo,
  243. ulSize,
  244. &ulSize);
  245. if ( NT_SUCCESS(ntStatus) ) {
  246. // Copy the data queried into buffer
  247. RtlCopyMemory(pData, pValInfo->Data, pValInfo->DataLength);
  248. *pulType = pValInfo->Type;
  249. *pulDataSize = pValInfo->DataLength;
  250. } else {
  251. #if 0
  252. ClusDiskPrint((
  253. 1,
  254. "[ClusDisk] Failed to read key %ws\n",
  255. pValueName ));
  256. #endif
  257. }
  258. ExFreePool(pValInfo);
  259. return ntStatus;
  260. } // RegistryQueryValue
  261. NTSTATUS
  262. GetBootTimeSystemRoot(
  263. IN OUT PWCHAR Path
  264. )
  265. /*++
  266. Routine Description:
  267. Find "Partition" string in the partition name, then truncate the
  268. string just after the "Partition" string.
  269. Arguments:
  270. Path - the path for the system disk.
  271. Return Value:
  272. NTSTATUS
  273. --*/
  274. {
  275. PWCHAR ptrPartition;
  276. //
  277. // At boot time, systemroot is init'ed using the Arcname of the
  278. // system device. In this form, "partition" is in lower case.
  279. //
  280. ptrPartition = wcsstr( Path, L"partition" );
  281. if ( ptrPartition == NULL ) {
  282. return(STATUS_INVALID_PARAMETER);
  283. }
  284. ptrPartition = wcsstr( ptrPartition, L")" );
  285. if ( ptrPartition == NULL ) {
  286. return(STATUS_INVALID_PARAMETER);
  287. }
  288. ptrPartition++;
  289. *ptrPartition = UNICODE_NULL;
  290. return(STATUS_SUCCESS);
  291. } // GetBootTimeSystemRoot
  292. NTSTATUS
  293. GetRunTimeSystemRoot(
  294. IN OUT PWCHAR Path
  295. )
  296. /*++
  297. Routine Description:
  298. Find "Partition" string in the partition name, then truncate the
  299. string just after the "Partition" string.
  300. Arguments:
  301. Path - the path for the system disk.
  302. Return Value:
  303. NTSTATUS
  304. --*/
  305. {
  306. PWCHAR ptrPartition;
  307. //
  308. // Once the system has booted, systemroot is changed to point to
  309. // a string of the form \Device\HarddiskX\PartitionY\<win dir>. Note
  310. // that "partition" is now capitalized.
  311. //
  312. ptrPartition = wcsstr( Path, L"Partition" );
  313. if ( ptrPartition == NULL ) {
  314. return(STATUS_INVALID_PARAMETER);
  315. }
  316. ptrPartition = wcsstr( ptrPartition, L"\\" );
  317. if ( ptrPartition == NULL ) {
  318. return(STATUS_INVALID_PARAMETER);
  319. }
  320. --ptrPartition;
  321. *ptrPartition++ = L'0';
  322. *ptrPartition = UNICODE_NULL;
  323. return(STATUS_SUCCESS);
  324. } // GetRunTimeSystemRoot
  325. NTSTATUS
  326. GetSystemRootPort(
  327. VOID
  328. )
  329. /*++
  330. Routine Description:
  331. Get the port number and signature for the system disk.
  332. Arguments:
  333. None.
  334. Return Value:
  335. NTSTATUS
  336. --*/
  337. {
  338. WCHAR path[MAXIMUM_FILENAME_LENGTH] = L"SystemRoot";
  339. WCHAR keyNameBuffer[MAXIMUM_FILENAME_LENGTH];
  340. WCHAR clussvcKey[] = L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\SERVICES\\ClusSvc\\Parameters";
  341. UNICODE_STRING ntUnicodeString;
  342. NTSTATUS status;
  343. HANDLE ntFileHandle;
  344. IO_STATUS_BLOCK ioStatus;
  345. OBJECT_ATTRIBUTES objectAttributes;
  346. PDRIVE_LAYOUT_INFORMATION driveLayout;
  347. ULONG driveLayoutSize;
  348. ULONG singleBus;
  349. SCSI_ADDRESS scsiAddress;
  350. HANDLE eventHandle;
  351. //
  352. // Find the bus on which the system disk is loaded.
  353. //
  354. GetSymbolicLink( L"\\", path );
  355. if ( wcslen(path) == 0 ) {
  356. ClusDiskPrint((1, "[ClusDisk] GetSystemRootPort: couldn't find symbolic link for SystemRoot.\n"));
  357. return(STATUS_FILE_INVALID);
  358. }
  359. status = GetBootTimeSystemRoot( path );
  360. if ( !NT_SUCCESS(status) ) {
  361. status = GetRunTimeSystemRoot( path );
  362. ClusDiskBootTime = FALSE;
  363. } // else - default is TRUE
  364. if ( !NT_SUCCESS(status) ) {
  365. ClusDiskPrint((1,
  366. "[ClusDisk] GetSystemRootPort: unable to get system disk name ->%ws<-\n",
  367. path));
  368. //continue
  369. //return(status);
  370. }
  371. //
  372. // Open the device.
  373. //
  374. RtlInitUnicodeString( &ntUnicodeString, path );
  375. InitializeObjectAttributes( &objectAttributes,
  376. &ntUnicodeString,
  377. OBJ_CASE_INSENSITIVE,
  378. NULL,
  379. NULL );
  380. status = ZwCreateFile( &ntFileHandle,
  381. FILE_READ_DATA,
  382. &objectAttributes,
  383. &ioStatus,
  384. NULL,
  385. FILE_ATTRIBUTE_NORMAL,
  386. FILE_SHARE_READ | FILE_SHARE_WRITE,
  387. FILE_OPEN,
  388. FILE_SYNCHRONOUS_IO_NONALERT,
  389. NULL,
  390. 0 );
  391. if ( !NT_SUCCESS(status) ) {
  392. ClusDiskPrint((
  393. 1,
  394. "[ClusDisk] Failed to open device for [%ws]. Error %08X.\n",
  395. path,
  396. status));
  397. return(status);
  398. }
  399. //
  400. // Allocate a drive layout buffer.
  401. //
  402. driveLayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
  403. (MAX_PARTITIONS * sizeof(PARTITION_INFORMATION));
  404. driveLayout = ExAllocatePool( NonPagedPoolCacheAligned,
  405. driveLayoutSize );
  406. if ( driveLayout == NULL ) {
  407. ClusDiskPrint((
  408. 1,
  409. "[ClusDisk] Failed to allocate root drive layout structure.\n"
  410. ));
  411. ZwClose( ntFileHandle );
  412. return(STATUS_INSUFFICIENT_RESOURCES);
  413. }
  414. //
  415. // Create event for notification.
  416. //
  417. status = ZwCreateEvent( &eventHandle,
  418. EVENT_ALL_ACCESS,
  419. NULL,
  420. SynchronizationEvent,
  421. FALSE );
  422. if ( !NT_SUCCESS(status) ) {
  423. ClusDiskPrint((
  424. 1,
  425. "[ClusDisk] Failed to create event. %08X\n",
  426. status));
  427. ExFreePool( driveLayout );
  428. ZwClose( ntFileHandle );
  429. return(status);
  430. }
  431. //
  432. // Get the port number for the SystemRoot disk device.
  433. //
  434. status = ZwDeviceIoControlFile( ntFileHandle,
  435. NULL,
  436. NULL,
  437. NULL,
  438. &ioStatus,
  439. IOCTL_SCSI_GET_ADDRESS,
  440. NULL,
  441. 0,
  442. &scsiAddress,
  443. sizeof(SCSI_ADDRESS) );
  444. ASSERT( status != STATUS_PENDING);
  445. if ( NT_SUCCESS(status) ) {
  446. status = ZwDeviceIoControlFile( ntFileHandle,
  447. eventHandle,
  448. NULL,
  449. NULL,
  450. &ioStatus,
  451. IOCTL_DISK_GET_DRIVE_LAYOUT,
  452. NULL,
  453. 0,
  454. driveLayout,
  455. driveLayoutSize );
  456. }
  457. if ( status == STATUS_PENDING ) {
  458. status = ZwWaitForSingleObject(eventHandle,
  459. FALSE,
  460. NULL);
  461. ASSERT( NT_SUCCESS(status) );
  462. status = ioStatus.Status;
  463. }
  464. ZwClose( ntFileHandle );
  465. ZwClose( eventHandle );
  466. if ( NT_SUCCESS(status) ) {
  467. SystemDiskSignature = driveLayout->Signature;
  468. SystemDiskPort = scsiAddress.PortNumber;
  469. SystemDiskPath = scsiAddress.PathId;
  470. //
  471. // Check if we are allowed to have a single bus on the system.
  472. // If disks on system bus are allowed, reset the Port and Path
  473. // to uninitialized values. Leave the signature set so we don't
  474. // pick the system disk.
  475. //
  476. singleBus = 0;
  477. status = GetRegistryValue( &ClusDiskRegistryPath,
  478. CLUSDISK_SINGLE_BUS_KEYNAME,
  479. &singleBus );
  480. if ( NT_SUCCESS(status) && singleBus ) {
  481. ClusDiskPrint(( 1,
  482. "[ClusDisk] ClusDiskInitialize: %ws parm found, allow use of system bus\n",
  483. CLUSDISK_SINGLE_BUS_KEYNAME ));
  484. SystemDiskPort = 0xff;
  485. SystemDiskPath = 0xff;
  486. }
  487. status = STATUS_SUCCESS;
  488. singleBus = 0;
  489. RtlInitUnicodeString( &ntUnicodeString, clussvcKey );
  490. status = GetRegistryValue( &ntUnicodeString,
  491. CLUSSVC_VALUENAME_MANAGEDISKSONSYSTEMBUSES,
  492. &singleBus );
  493. if ( NT_SUCCESS(status) && singleBus ) {
  494. ClusDiskPrint(( 1,
  495. "[ClusDisk] ClusDiskInitialize: %ws parm found, allow use of system bus\n",
  496. CLUSSVC_VALUENAME_MANAGEDISKSONSYSTEMBUSES ));
  497. SystemDiskPort = 0xff;
  498. SystemDiskPath = 0xff;
  499. }
  500. status = STATUS_SUCCESS;
  501. } else {
  502. ClusDiskPrint((
  503. 1,
  504. "[ClusDisk] Failed to get boot device drive layout info. Error %08X.\n",
  505. status
  506. ));
  507. status = STATUS_SUCCESS; // Use default Port/Path of -1
  508. }
  509. ExFreePool( driveLayout );
  510. return(status);
  511. } // GetSystemRootPort
  512. NTSTATUS
  513. GetRegistryValue(
  514. PUNICODE_STRING KeyName,
  515. PWSTR ValueName,
  516. PULONG ReturnValue
  517. )
  518. {
  519. HANDLE parametersKey;
  520. NTSTATUS status = STATUS_UNSUCCESSFUL;
  521. ULONG length;
  522. ULONG type;
  523. OBJECT_ATTRIBUTES objectAttributes;
  524. UNICODE_STRING keyName;
  525. *ReturnValue = 0;
  526. //
  527. // Setup the object attributes for the Parameters\SingleBus key.
  528. //
  529. InitializeObjectAttributes(
  530. &objectAttributes,
  531. KeyName,
  532. OBJ_CASE_INSENSITIVE,
  533. NULL,
  534. NULL
  535. );
  536. //
  537. // Open Parameters key.
  538. //
  539. status = ZwOpenKey(
  540. &parametersKey,
  541. KEY_READ,
  542. &objectAttributes
  543. );
  544. if ( !NT_SUCCESS(status) ) {
  545. ClusDiskPrint(( 1,
  546. "[ClusDisk] GetRegistryValue: Failed to open registry key: %ws. Status: %lx\n",
  547. KeyName->Buffer,
  548. status
  549. ));
  550. goto FnExit;
  551. }
  552. RtlInitUnicodeString( &keyName, ValueName );
  553. type = REG_DWORD;
  554. length = sizeof(ULONG);
  555. status = RegistryQueryValue( parametersKey,
  556. ValueName,
  557. &type,
  558. ReturnValue,
  559. &length );
  560. ZwClose( parametersKey );
  561. if ( !NT_SUCCESS(status) ||
  562. (length != 4) ) {
  563. *ReturnValue = 0;
  564. ClusDiskPrint(( 3,
  565. "[ClusDisk] GetRegistryValue: Failed to read registry value, status %08LX, length %u\n",
  566. status,
  567. length ));
  568. goto FnExit;
  569. }
  570. if ( *ReturnValue ) {
  571. ClusDiskPrint(( 1,
  572. "[ClusDisk] GetRegistryValue: Allow use of system bus\n" ));
  573. }
  574. FnExit:
  575. return status;
  576. } // GetRegistryValue
  577. VOID
  578. ResetScsiBusses(
  579. VOID
  580. )
  581. /*++
  582. Routine Description:
  583. Reset all SCSI busses at once on the system.
  584. Arguments:
  585. None.
  586. Return Value:
  587. None.
  588. --*/
  589. {
  590. PCONFIGURATION_INFORMATION configurationInformation;
  591. ULONG i;
  592. NTSTATUS status;
  593. SCSI_ADDRESS scsiAddress;
  594. HANDLE fileHandle;
  595. IO_STATUS_BLOCK ioStatusBlock;
  596. WCHAR portDeviceBuffer[64];
  597. UNICODE_STRING portDevice;
  598. PDEVICE_OBJECT deviceObject;
  599. PFILE_OBJECT fileObject;
  600. OBJECT_ATTRIBUTES objectAttributes;
  601. LARGE_INTEGER waitTime;
  602. scsiAddress.PathId = 0;
  603. CDLOG( "ResetScsiBusses: Entry" );
  604. //
  605. // Get the system configuration information.
  606. //
  607. configurationInformation = IoGetConfigurationInformation();
  608. //
  609. // Reset each scsi bus
  610. //
  611. for ( i = 0; i < configurationInformation->ScsiPortCount; i++ ) {
  612. if ( SystemDiskPort == i ) {
  613. continue;
  614. }
  615. //
  616. // Create device name for the physical disk.
  617. //
  618. swprintf(portDeviceBuffer, L"\\Device\\ScsiPort%d", i);
  619. WCSLEN_ASSERT( portDeviceBuffer );
  620. RtlInitUnicodeString( &portDevice, portDeviceBuffer );
  621. //
  622. // Try to open this device to get its scsi info
  623. //
  624. InitializeObjectAttributes( &objectAttributes,
  625. &portDevice,
  626. OBJ_CASE_INSENSITIVE,
  627. NULL,
  628. NULL );
  629. status = ZwOpenFile( &fileHandle,
  630. FILE_ALL_ACCESS,
  631. &objectAttributes,
  632. &ioStatusBlock,
  633. 0,
  634. FILE_NON_DIRECTORY_FILE );
  635. if ( !NT_SUCCESS(status) ) {
  636. ClusDiskPrint((1,
  637. "[ClusDisk] ResetScsiBusses, failed to open file %wZ. Error %08X.\n",
  638. &portDevice, status ));
  639. continue;
  640. }
  641. status = ObReferenceObjectByHandle( fileHandle,
  642. 0,
  643. NULL,
  644. KernelMode,
  645. (PVOID *) &fileObject,
  646. NULL );
  647. if ( !NT_SUCCESS(status) ) {
  648. ClusDiskPrint((1,
  649. "[ClusDisk] Failed to reference object for file %wZ. Error %08X.\n",
  650. &portDevice,
  651. status ));
  652. ZwClose( fileHandle );
  653. continue;
  654. }
  655. //
  656. // Get the address of the target device object. If this file represents
  657. // a device that was opened directly, then simply use the device or its
  658. // attached device(s) directly. Also get the address of the Fast Io
  659. // dispatch structure.
  660. //
  661. if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
  662. deviceObject = IoGetRelatedDeviceObject( fileObject );
  663. // Add a reference to the object so we can dereference it later.
  664. ObReferenceObject( deviceObject );
  665. } else {
  666. deviceObject = IoGetAttachedDeviceReference( fileObject->DeviceObject );
  667. }
  668. //
  669. // If we get a file system device object... go back and get the
  670. // device object.
  671. //
  672. if ( deviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM ) {
  673. ObDereferenceObject( deviceObject );
  674. deviceObject = IoGetAttachedDeviceReference( fileObject->DeviceObject );
  675. }
  676. ASSERT( deviceObject->DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM );
  677. ZwClose( fileHandle );
  678. ObDereferenceObject( fileObject );
  679. ResetScsiDevice( deviceObject, &scsiAddress );
  680. DEREFERENCE_OBJECT( deviceObject );
  681. }
  682. //
  683. // Now sleep for a few seconds
  684. //
  685. waitTime.QuadPart = (ULONGLONG)(RESET_SLEEP * -(10000*1000));
  686. KeDelayExecutionThread( KernelMode, FALSE, &waitTime );
  687. CDLOG( "ResetScsiBusses: Exit" );
  688. return;
  689. } // ResetScsiBusses
  690. NTSTATUS
  691. ClusDiskGetDeviceObject(
  692. IN PWCHAR DeviceName,
  693. OUT PDEVICE_OBJECT *DeviceObject
  694. )
  695. /*++
  696. Routine Description:
  697. Get the device object pointer given a symbolic device name.
  698. The device object will have reference count incremented and the
  699. caller must decrement the count when done with the object.
  700. Arguments:
  701. Return Value:
  702. NTSTATUS.
  703. --*/
  704. {
  705. NTSTATUS status;
  706. HANDLE handle;
  707. PDEVICE_OBJECT deviceObject;
  708. PDEVICE_OBJECT targetDevice;
  709. PFILE_OBJECT fileObject;
  710. UNICODE_STRING deviceName;
  711. WCHAR path[MAXIMUM_FILENAME_LENGTH] = L"";
  712. OBJECT_ATTRIBUTES objectAttributes;
  713. ULONG len;
  714. len = wcslen(DeviceName);
  715. WCSLEN_ASSERT( DeviceName );
  716. ASSERT( len < MAXIMUM_FILENAME_LENGTH );
  717. //DbgBreakPoint();
  718. if ( (len + 1) > MAXIMUM_FILENAME_LENGTH ) {
  719. return STATUS_UNSUCCESSFUL;
  720. }
  721. wcsncpy( path, DeviceName, len );
  722. GetSymbolicLink( L"", path );
  723. if ( wcslen(path) == 0 ) {
  724. ClusDiskPrint((
  725. 1,
  726. "[ClusDisk] GetDeviceObject: Failed find symbolic link for %ws\n",
  727. DeviceName ));
  728. return(STATUS_FILE_INVALID);
  729. }
  730. RtlInitUnicodeString( &deviceName, path );
  731. //DbgBreakPoint();
  732. status = IoGetDeviceObjectPointer( &deviceName,
  733. FILE_READ_ATTRIBUTES,
  734. &fileObject,
  735. &targetDevice );
  736. if ( !NT_SUCCESS(status) ) {
  737. ClusDiskPrint((
  738. 1,
  739. "[ClusDisk] GetDeviceObject: Failed to get target devobj, %LX\n",
  740. status ));
  741. CDLOG( "ClusDiskGetDeviceObject: GetDevObj failed, status %!status!",
  742. status );
  743. } else {
  744. if ( !(fileObject->Flags & FO_DIRECT_DEVICE_OPEN) ) {
  745. deviceObject = IoGetRelatedDeviceObject( fileObject );
  746. // Add a reference to the object so we can dereference it later.
  747. ObReferenceObject( deviceObject );
  748. //
  749. // If we get a file system device object... go back and get the
  750. // device object.
  751. //
  752. if ( deviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM ) {
  753. ObDereferenceObject( deviceObject );
  754. deviceObject = IoGetAttachedDeviceReference( fileObject->DeviceObject );
  755. }
  756. ClusDiskPrint((
  757. 3,
  758. "[ClusDisk] GetDevObj: (DIRECT_OPEN) fileObj = %p, devObj= %p \n",
  759. fileObject, deviceObject ));
  760. } else {
  761. deviceObject = IoGetAttachedDeviceReference( fileObject->DeviceObject );
  762. ClusDiskPrint((
  763. 3,
  764. "[ClusDisk] GetDevObj: fileObj = %p, devObj= %p \n",
  765. fileObject, deviceObject ));
  766. }
  767. *DeviceObject = deviceObject;
  768. ObDereferenceObject( fileObject );
  769. }
  770. ClusDiskPrint((
  771. 3,
  772. "[ClusDisk] GetDeviceObject: target devobj = %p, status = %LX\n",
  773. targetDevice,
  774. status ));
  775. return(status);
  776. } // ClusDiskGetDeviceObject
  777. NTSTATUS
  778. ClusDiskDeviceChangeNotification(
  779. IN PDEVICE_INTERFACE_CHANGE_NOTIFICATION DeviceChangeNotification,
  780. IN PCLUS_DEVICE_EXTENSION DeviceExtension
  781. )
  782. {
  783. /*++
  784. Routine Description:
  785. Handle the arrival of new disk spindles. We only want to add the signature
  786. to the available list if it is not already a known signature.
  787. If the signature matches one we should be controlling, we also need to
  788. try to attach to the disk.
  789. Arguments:
  790. DeviceChangeNotification - the device change notification structure
  791. DeviceExtension - the device extension for the root device
  792. Return Value:
  793. NTSTATUS for this request.
  794. --*/
  795. PIO_WORKITEM workItem = NULL;
  796. PDEVICE_CHANGE_CONTEXT workContext = NULL;
  797. PWSTR symLinkBuffer = NULL;
  798. BOOLEAN cleanupRequired = TRUE;
  799. CDLOG( "DeviceChangeNotification: Entry DO %p", DeviceExtension->DeviceObject );
  800. //
  801. // Process device arrivals only.
  802. //
  803. if ( IsEqualGUID( &DeviceChangeNotification->Event,
  804. &GUID_DEVICE_INTERFACE_ARRIVAL ) ) {
  805. workItem = IoAllocateWorkItem( DeviceExtension->DeviceObject );
  806. if ( NULL == workItem ) {
  807. ClusDiskPrint(( 1,
  808. "[ClusDisk] DeviceChangeNotification: Failed to allocate WorkItem \n" ));
  809. goto FnExit;
  810. }
  811. workContext = ExAllocatePool( NonPagedPool, sizeof( DEVICE_CHANGE_CONTEXT ) );
  812. if ( !workContext ) {
  813. ClusDiskPrint(( 1,
  814. "[ClusDisk] DeviceChangeNotification: Failed to allocate context \n" ));
  815. goto FnExit;
  816. }
  817. RtlZeroMemory( workContext, sizeof( DEVICE_CHANGE_CONTEXT ) );
  818. workContext->WorkItem = workItem;
  819. workContext->DeviceExtension = DeviceExtension;
  820. //
  821. // We have to copy the symbolic link info as pnp thread may free the
  822. // structures on return.
  823. //
  824. workContext->SymbolicLinkName.Length = 0;
  825. workContext->SymbolicLinkName.MaximumLength = DeviceChangeNotification->SymbolicLinkName->MaximumLength;
  826. symLinkBuffer = ExAllocatePool( PagedPool,
  827. DeviceChangeNotification->SymbolicLinkName->MaximumLength + 1 );
  828. if ( !symLinkBuffer ) {
  829. ClusDiskPrint(( 1,
  830. "[ClusDisk] DeviceChangeNotification: Failed to allocate symlink buffer \n" ));
  831. goto FnExit;
  832. }
  833. workContext->SymbolicLinkName.Buffer = symLinkBuffer;
  834. RtlCopyUnicodeString( &workContext->SymbolicLinkName, DeviceChangeNotification->SymbolicLinkName );
  835. //
  836. // Queue the workitem. IoQueueWorkItem will insure that the device object is
  837. // referenced while the work-item progresses.
  838. //
  839. cleanupRequired = FALSE;
  840. ClusDiskPrint(( 3,
  841. "[ClusDisk] DeviceChangeNotification: Queuing work item \n" ));
  842. IoQueueWorkItem( workItem,
  843. ClusDiskDeviceChangeNotificationWorker,
  844. DelayedWorkQueue,
  845. workContext );
  846. }
  847. FnExit:
  848. if ( cleanupRequired ) {
  849. if ( workItem ) {
  850. IoFreeWorkItem( workItem );
  851. }
  852. if ( workContext ) {
  853. ExFreePool( workContext );
  854. }
  855. if ( symLinkBuffer ) {
  856. ExFreePool( symLinkBuffer );
  857. }
  858. }
  859. CDLOG( "DeviceChangeNotification: Exit, DO %p", DeviceExtension->DeviceObject );
  860. return STATUS_SUCCESS;
  861. } // ClusDiskDeviceChangeNotification
  862. NTSTATUS
  863. ClusDiskDeviceChangeNotificationWorker(
  864. IN PDEVICE_OBJECT DeviceObject,
  865. IN PVOID Context
  866. )
  867. /*++
  868. Routine Description:
  869. Handle the arrival of new disk spindles. We only want to add the signature
  870. to the available list if it is not already a known signature.
  871. If the signature matches one we should be controlling, we also need to
  872. try to attach to the disk.
  873. This routine must free the workitem structure.
  874. Arguments:
  875. DeviceObject - the root device object
  876. Context - information relevant to processing this device change.
  877. Return Value:
  878. NTSTATUS for this request.
  879. --*/
  880. {
  881. PDEVICE_CHANGE_CONTEXT deviceChange = Context;
  882. PCLUS_DEVICE_EXTENSION deviceExtension;
  883. PIO_WORKITEM workItem;
  884. PUNICODE_STRING symbolicLinkName;
  885. NTSTATUS status;
  886. OBJECT_ATTRIBUTES objectAttributes;
  887. HANDLE fileHandle = NULL;
  888. HANDLE eventHandle= NULL;
  889. IO_STATUS_BLOCK ioStatusBlock;
  890. ULONG signature;
  891. ULONG driveLayoutSize;
  892. PDRIVE_LAYOUT_INFORMATION driveLayoutInfo = NULL;
  893. UNICODE_STRING availableName;
  894. SCSI_ADDRESS scsiAddress;
  895. CDLOG( "DeviceChangeNotificationWorker: Entry DO %p", DeviceObject );
  896. deviceExtension = deviceChange->DeviceExtension;
  897. workItem = deviceChange->WorkItem;
  898. symbolicLinkName = &deviceChange->SymbolicLinkName;
  899. //
  900. // Create event for notification.
  901. //
  902. status = ZwCreateEvent( &eventHandle,
  903. EVENT_ALL_ACCESS,
  904. NULL,
  905. SynchronizationEvent,
  906. FALSE );
  907. if ( !NT_SUCCESS(status) ) {
  908. ClusDiskPrint((
  909. 1,
  910. "[ClusDisk] DeviceChangeNotificationWorker: Failed to create event, status %08X\n",
  911. status ));
  912. goto FnExit;
  913. }
  914. ClusDiskPrint((3,
  915. "[ClusDisk] DeviceChangeNotificationWorker, A new disk device arrived\n %ws\n",
  916. symbolicLinkName->Buffer));
  917. //
  918. // Setup object attributes for the file to open.
  919. //
  920. InitializeObjectAttributes(&objectAttributes,
  921. symbolicLinkName,
  922. OBJ_CASE_INSENSITIVE,
  923. NULL,
  924. NULL);
  925. status = ZwCreateFile(&fileHandle,
  926. //FILE_READ_DATA,
  927. // SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  928. SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  929. &objectAttributes,
  930. &ioStatusBlock,
  931. NULL,
  932. FILE_ATTRIBUTE_NORMAL,
  933. FILE_SHARE_READ | FILE_SHARE_WRITE,
  934. FILE_OPEN,
  935. FILE_SYNCHRONOUS_IO_NONALERT,
  936. NULL,
  937. 0 );
  938. ASSERT( status != STATUS_PENDING );
  939. if ( !NT_SUCCESS(status) ) {
  940. ClusDiskPrint((1,
  941. "[ClusDisk] DeviceChangeNotificationWorker, failed to open file %ws. Error %08X.\n",
  942. symbolicLinkName->Buffer,
  943. status ));
  944. goto FnExit;
  945. }
  946. driveLayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
  947. (MAX_PARTITIONS * sizeof(PARTITION_INFORMATION));
  948. driveLayoutInfo = ExAllocatePool(NonPagedPoolCacheAligned,
  949. driveLayoutSize);
  950. if ( driveLayoutInfo == NULL ) {
  951. status = STATUS_INSUFFICIENT_RESOURCES;
  952. goto FnExit;
  953. }
  954. //
  955. // Get the Signature
  956. //
  957. status = ZwDeviceIoControlFile( fileHandle,
  958. eventHandle,
  959. NULL,
  960. NULL,
  961. &ioStatusBlock,
  962. IOCTL_DISK_GET_DRIVE_LAYOUT,
  963. NULL,
  964. 0,
  965. driveLayoutInfo,
  966. driveLayoutSize );
  967. if ( status == STATUS_PENDING ) {
  968. status = ZwWaitForSingleObject(eventHandle,
  969. FALSE,
  970. NULL);
  971. ASSERT( NT_SUCCESS(status) );
  972. status = ioStatusBlock.Status;
  973. }
  974. //
  975. // If success, next get the SCSI address
  976. //
  977. if ( NT_SUCCESS(status) ) {
  978. status = ZwDeviceIoControlFile( fileHandle,
  979. eventHandle,
  980. NULL,
  981. NULL,
  982. &ioStatusBlock,
  983. IOCTL_SCSI_GET_ADDRESS,
  984. NULL,
  985. 0,
  986. &scsiAddress,
  987. sizeof(SCSI_ADDRESS) );
  988. if ( status == STATUS_PENDING ) {
  989. status = ZwWaitForSingleObject(eventHandle,
  990. FALSE,
  991. NULL);
  992. ASSERT( NT_SUCCESS(status) );
  993. status = ioStatusBlock.Status;
  994. }
  995. }
  996. if ( !NT_SUCCESS(status) ) {
  997. goto FnExit;
  998. }
  999. signature = driveLayoutInfo->Signature;
  1000. if ( driveLayoutInfo ) {
  1001. ExFreePool( driveLayoutInfo );
  1002. driveLayoutInfo = NULL;
  1003. }
  1004. //
  1005. // No signature or system disk signature, don't add it.
  1006. //
  1007. if ( ( 0 == signature ) || SystemDiskSignature == signature ) {
  1008. status = STATUS_SUCCESS;
  1009. goto FnExit;
  1010. }
  1011. //
  1012. // Disk is already in signature list, try to attach again. If we
  1013. // are already attached, nothing will happen. If we are not attached,
  1014. // we will attach and make sure the disk is offline.
  1015. //
  1016. if ( ClusDiskIsSignatureDisk( signature ) ) {
  1017. ClusDiskTryAttachDevice( signature,
  1018. 0,
  1019. deviceExtension->DriverObject );
  1020. status = STATUS_SUCCESS;
  1021. goto FnExit;
  1022. }
  1023. if ( (SystemDiskPort != scsiAddress.PortNumber) ||
  1024. (SystemDiskPath != scsiAddress.PathId) ) {
  1025. //
  1026. // Allocate buffer for Signatures registry key. So we can add
  1027. // the signature to the available list.
  1028. //
  1029. status = ClusDiskInitRegistryString(
  1030. &availableName,
  1031. CLUSDISK_AVAILABLE_DISKS_KEYNAME,
  1032. sizeof(CLUSDISK_AVAILABLE_DISKS_KEYNAME)
  1033. );
  1034. if ( NT_SUCCESS(status) ) {
  1035. //
  1036. // Create the signature key under \Parameters\AvailableDisks
  1037. //
  1038. status = ClusDiskAddSignature(
  1039. &availableName,
  1040. signature,
  1041. TRUE
  1042. );
  1043. ExFreePool( availableName.Buffer );
  1044. }
  1045. if ( NT_SUCCESS(status) ) {
  1046. ClusDiskPrint((3,
  1047. "[ClusDisk] DeviceChangeNotificationWorker, added signature %08LX for %ws to available list.\n",
  1048. signature,
  1049. symbolicLinkName->Buffer));
  1050. } else {
  1051. ClusDiskPrint((1,
  1052. "[ClusDisk] DeviceChangeNotificationWorker, failed to add signature %08LX for %ws. Error %08X.\n",
  1053. signature,
  1054. symbolicLinkName->Buffer,
  1055. status ));
  1056. }
  1057. }
  1058. FnExit:
  1059. if ( eventHandle ) {
  1060. ZwClose( eventHandle );
  1061. }
  1062. if ( fileHandle ) {
  1063. ZwClose( fileHandle );
  1064. }
  1065. if ( driveLayoutInfo ) {
  1066. ExFreePool( driveLayoutInfo );
  1067. }
  1068. //
  1069. // Free the work item.
  1070. //
  1071. IoFreeWorkItem( workItem );
  1072. ExFreePool( symbolicLinkName->Buffer );
  1073. CDLOG( "DeviceChangeNotificationWorker: Exit, DO %p", deviceExtension->DeviceObject );
  1074. return(STATUS_SUCCESS);
  1075. } // ClusDiskDeviceChangeNotificationWorker
  1076. NTSTATUS
  1077. ClusDiskInitialize(
  1078. IN PDRIVER_OBJECT DriverObject
  1079. )
  1080. /*++
  1081. Routine Description:
  1082. Common intialization for ClusDisk
  1083. Arguments:
  1084. DriverObject - The Cluster Disk driver object.
  1085. Return Value:
  1086. NTSTATUS for this request.
  1087. --*/
  1088. {
  1089. ULONG status;
  1090. PDEVICE_OBJECT rootDevice;
  1091. PCLUS_DEVICE_EXTENSION deviceExtension;
  1092. UNICODE_STRING uniNameString;
  1093. KIRQL irql;
  1094. //
  1095. // Find the bus on which the system disk is loaded.
  1096. //
  1097. status = GetSystemRootPort();
  1098. if ( !NT_SUCCESS( status )) {
  1099. return status;
  1100. }
  1101. //
  1102. // Initialize the global locks.
  1103. //
  1104. KeInitializeSpinLock(&ClusDiskSpinLock);
  1105. ExInitializeResourceLite(&ClusDiskDeviceListLock);
  1106. //
  1107. // Init halt processing work item
  1108. //
  1109. ExInitializeWorkItem( &HaltWorkItem,
  1110. (PWORKER_THREAD_ROUTINE)ClusDiskHaltProcessingWorker,
  1111. NULL );
  1112. //
  1113. // Init rescan processing work item
  1114. //
  1115. ExInitializeWorkItem( &ClusDiskRescanWorkItem,
  1116. (PWORKER_THREAD_ROUTINE)ClusDiskRescanWorker,
  1117. NULL );
  1118. //
  1119. // Init change notification list head.
  1120. //
  1121. InitializeListHead( &ChangeWorkList );
  1122. //
  1123. // Reset all SCSI busses.
  1124. //
  1125. //ResetScsiBusses();
  1126. //
  1127. // Create device object for \Device\ClusDisk0
  1128. //
  1129. RtlInitUnicodeString( &uniNameString, CLUSDISK_ROOT_DEVICE );
  1130. status = IoCreateDevice(DriverObject,
  1131. sizeof(CLUS_DEVICE_EXTENSION),
  1132. &uniNameString,
  1133. FILE_DEVICE_NETWORK,
  1134. 0,
  1135. FALSE,
  1136. &rootDevice);
  1137. if ( !NT_SUCCESS(status) ) {
  1138. return(status);
  1139. }
  1140. rootDevice->Flags |= DO_DIRECT_IO;
  1141. deviceExtension = rootDevice->DeviceExtension;
  1142. deviceExtension->DeviceObject = rootDevice;
  1143. deviceExtension->DiskNumber = UNINITIALIZED_DISK_NUMBER;
  1144. deviceExtension->LastPartitionNumber = 0;
  1145. deviceExtension->DriverObject = DriverObject;
  1146. deviceExtension->BusType = RootBus;
  1147. deviceExtension->DiskState = DiskOffline;
  1148. deviceExtension->AttachValid = FALSE;
  1149. deviceExtension->PerformReserves = FALSE;
  1150. deviceExtension->ReserveFailure = 0;
  1151. deviceExtension->Signature = 0xffffffff;
  1152. deviceExtension->Detached = TRUE;
  1153. deviceExtension->OfflinePending = FALSE;
  1154. InitializeListHead( &deviceExtension->WaitingIoctls );
  1155. InitializeListHead( &deviceExtension->HoldIO );
  1156. deviceExtension->SectorSize = 0;
  1157. deviceExtension->ArbitrationSector = 12;
  1158. IoInitializeRemoveLock( &deviceExtension->RemoveLock, CLUSDISK_ALLOC_TAG, 0, 0 );
  1159. //
  1160. // Signal the worker thread running event.
  1161. //
  1162. KeInitializeEvent( &deviceExtension->Event, NotificationEvent, TRUE );
  1163. KeInitializeEvent( &deviceExtension->PagingPathCountEvent,
  1164. NotificationEvent, TRUE );
  1165. deviceExtension->PagingPathCount = 0;
  1166. deviceExtension->HibernationPathCount = 0;
  1167. deviceExtension->DumpPathCount = 0;
  1168. ExInitializeResourceLite( &deviceExtension->DriveLayoutLock );
  1169. //
  1170. // Init the tick handler timer
  1171. //
  1172. IoInitializeTimer( rootDevice, ClusDiskTickHandler, NULL );
  1173. //
  1174. // This is the physical device object for \Device\ClusDisk0.
  1175. //
  1176. ObReferenceObject( rootDevice );
  1177. deviceExtension->PhysicalDevice = rootDevice;
  1178. RootDeviceObject = rootDevice;
  1179. //
  1180. // Call the initialize routine (for each bus type) for the first time.
  1181. //
  1182. // With the new PNP stuff, we should be able to remove the following call.
  1183. // It's been tried and it seems to work correctly. rodga.
  1184. //
  1185. ClusDiskScsiInitialize(DriverObject, 0, 0);
  1186. //
  1187. // Register for disk device notifications
  1188. // If we called ClusDiskScsiInitialize just above, we don't have to register for notification
  1189. // with PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES flag set (second parameter).
  1190. //
  1191. status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
  1192. 0,
  1193. (PVOID)&DiskClassGuid,
  1194. DriverObject,
  1195. ClusDiskDeviceChangeNotification,
  1196. deviceExtension,
  1197. &deviceExtension->DiskNotificationEntry);
  1198. if (!NT_SUCCESS(status)) {
  1199. RootDeviceObject = NULL;
  1200. IoDeleteDevice( rootDevice );
  1201. return status;
  1202. }
  1203. //
  1204. // Start the tick handler.
  1205. //
  1206. IoStartTimer( rootDevice );
  1207. #if defined(WMI_TRACING)
  1208. status = IoWMIRegistrationControl (rootDevice, WMIREG_ACTION_REGISTER);
  1209. if (!NT_SUCCESS(status)) {
  1210. ClusDiskPrint((1, "[ClusDisk] Failed to register with WMI %x.\n",status));
  1211. }
  1212. #endif // WMI_TRACING
  1213. return( STATUS_SUCCESS );
  1214. } // ClusDiskInitialize
  1215. NTSTATUS
  1216. ClusDiskPassThrough(
  1217. IN PDEVICE_OBJECT DeviceObject,
  1218. IN PIRP Irp
  1219. )
  1220. /*++
  1221. Routine Description:
  1222. This routine is a generic dispatch for all unsupported
  1223. major IRP types
  1224. Note that we don't have to worry about the RemoveLock as
  1225. we are simply passing I/O's to the next driver.
  1226. Arguments:
  1227. DeviceObject - Supplies the device object.
  1228. Irp - Supplies the IO request packet.
  1229. Return Value:
  1230. NTSTATUS
  1231. --*/
  1232. {
  1233. PCLUS_DEVICE_EXTENSION deviceExtension =
  1234. (PCLUS_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1235. if ( deviceExtension->BusType == RootBus ) {
  1236. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  1237. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1238. return(STATUS_INVALID_DEVICE_REQUEST);
  1239. }
  1240. IoSkipCurrentIrpStackLocation(Irp);
  1241. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  1242. }
  1243. NTSTATUS
  1244. ClusDiskPowerDispatch(
  1245. IN PDEVICE_OBJECT DeviceObject,
  1246. IN PIRP Irp
  1247. )
  1248. /*++
  1249. Routine Description:
  1250. This routine is the dispatch for the IRP_MJ_PNP_POWER.
  1251. Arguments:
  1252. DeviceObject - Supplies the device object.
  1253. Irp - Supplies the IO request packet.
  1254. Return Value:
  1255. NTSTATUS
  1256. --*/
  1257. {
  1258. PCLUS_DEVICE_EXTENSION deviceExtension =
  1259. (PCLUS_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1260. PCLUS_DEVICE_EXTENSION physicalDisk =
  1261. deviceExtension->PhysicalDevice->DeviceExtension;
  1262. NTSTATUS status;
  1263. ClusDiskPrint(( 3,
  1264. "[ClusDisk] Processing Power IRP %p for device %p \n",
  1265. Irp,
  1266. DeviceObject ));
  1267. //
  1268. // Always call PoStartnextPowerIrp, even if we couldn't get the RemoveLock.
  1269. //
  1270. PoStartNextPowerIrp( Irp );
  1271. status = AcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  1272. if ( !NT_SUCCESS(status) ) {
  1273. ClusDiskPrint((
  1274. 1,
  1275. "[ClusDisk] ClusDiskPowerDispatch: AcquireRemoveLock for %p failed %08X \n",
  1276. deviceExtension,
  1277. status ));
  1278. Irp->IoStatus.Status = status;
  1279. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1280. return status;
  1281. }
  1282. status = AcquireRemoveLock(&physicalDisk->RemoveLock, Irp);
  1283. if ( !NT_SUCCESS(status) ) {
  1284. ClusDiskPrint((
  1285. 1,
  1286. "[ClusDisk] ClusDiskPowerDispatch: AcquireRemoveLock for %p (PD) failed %08X \n",
  1287. physicalDisk,
  1288. status ));
  1289. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  1290. Irp->IoStatus.Status = status;
  1291. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1292. return status;
  1293. }
  1294. //
  1295. // Always send IRP_MJ_POWER request down the stack.
  1296. //
  1297. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  1298. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  1299. IoSkipCurrentIrpStackLocation(Irp);
  1300. return PoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  1301. } // ClusDiskPowerDispatch
  1302. NTSTATUS
  1303. ClusDiskIrpCompletion(
  1304. IN PDEVICE_OBJECT DeviceObject,
  1305. IN PIRP Irp,
  1306. IN PVOID Context
  1307. )
  1308. /*++
  1309. Routine Description:
  1310. Forwarded IRP completion routine. Set an event and return
  1311. STATUS_MORE_PROCESSING_REQUIRED. Irp forwarder will wait on this
  1312. event and then re-complete the irp after cleaning up.
  1313. Arguments:
  1314. DeviceObject is the device object of the WMI driver
  1315. Irp is the WMI irp that was just completed
  1316. Context is a PKEVENT that forwarder will wait on
  1317. Return Value:
  1318. STATUS_MORE_PORCESSING_REQUIRED
  1319. --*/
  1320. {
  1321. PKEVENT event = (PKEVENT) Context;
  1322. UNREFERENCED_PARAMETER(DeviceObject);
  1323. UNREFERENCED_PARAMETER(Irp);
  1324. //
  1325. // Don't need to release the RemoveLock as it is still held by the routine
  1326. // that set this completion routine and will be released after we set the
  1327. // event.
  1328. //
  1329. KeSetEvent( event, IO_NO_INCREMENT, FALSE );
  1330. return(STATUS_MORE_PROCESSING_REQUIRED);
  1331. } // ClusDiskIrpCompletion
  1332. NTSTATUS
  1333. ClusDiskPnpDispatch(
  1334. IN PDEVICE_OBJECT DeviceObject,
  1335. IN PIRP Irp
  1336. )
  1337. /*++
  1338. Routine Description:
  1339. This routine is the dispatch for the IRP_MJ_PNP.
  1340. Arguments:
  1341. DeviceObject - Supplies the device object.
  1342. Irp - Supplies the IO request packet.
  1343. Return Value:
  1344. NTSTATUS
  1345. --*/
  1346. {
  1347. PCLUS_DEVICE_EXTENSION deviceExtension =
  1348. (PCLUS_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
  1349. NTSTATUS status;
  1350. PIO_STACK_LOCATION irpSp;
  1351. PDEVICE_OBJECT targetObject;
  1352. PDEVICE_LIST_ENTRY deviceEntry;
  1353. KIRQL irql;
  1354. // PAGED_CODE();
  1355. status = AcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  1356. if ( !NT_SUCCESS(status) ) {
  1357. ClusDiskPrint((
  1358. 1,
  1359. "[ClusDisk] ClusDiskPnpDispatch: AcquireRemoveLock for %p failed %08X \n",
  1360. deviceExtension,
  1361. status ));
  1362. Irp->IoStatus.Status = status;
  1363. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1364. return status;
  1365. }
  1366. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1367. CDLOG( "ClusDiskPnpDispatch_Entry(%p): IrpMn %!pnpmn!", DeviceObject, irpSp->MinorFunction );
  1368. ClusDiskPrint(( 3,
  1369. "[ClusDisk] PNP IRP for devobj %p MinorFunction: %s (%lx) \n",
  1370. DeviceObject,
  1371. PnPMinorFunctionString( irpSp->MinorFunction ),
  1372. irpSp->MinorFunction ));
  1373. if ( deviceExtension->BusType == RootBus ) {
  1374. ClusDiskPrint(( 1, "[ClusDisk] PNP IRP for root bus - failing \n" ));
  1375. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  1376. Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  1377. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1378. return(STATUS_DEVICE_BUSY);
  1379. }
  1380. //
  1381. // We should the following order on a remove request.
  1382. //
  1383. // 1. IRP_MN_QUERY_REMOVE_DEVICE
  1384. // Don't accept any new operations
  1385. // 2. IRP_MN_REMOVE_DEVICE if success on all drivers in stack
  1386. // Remove the device
  1387. // 3. IRP_MN_CANCEL_REMOVE_DEVICE if remove fails
  1388. // Resume activity
  1389. //
  1390. switch ( irpSp->MinorFunction ) {
  1391. case IRP_MN_QUERY_REMOVE_DEVICE:
  1392. ClusDiskPrint((1,
  1393. "[ClusDisk] QueryRemoveDevice PNP IRP on devobj %p \n",
  1394. DeviceObject));
  1395. break; // just pass it on
  1396. case IRP_MN_REMOVE_DEVICE: {
  1397. REPLACE_CONTEXT context;
  1398. ClusDiskPrint((1,
  1399. "[ClusDisk] RemoveDevice PNP IRP on devobj %p \n",
  1400. DeviceObject));
  1401. //
  1402. // Flush all queued I/O.
  1403. //
  1404. ClusDiskCompletePendedIrps(deviceExtension,
  1405. NULL, // Will complete all IRPs
  1406. FALSE // Don't set the device state
  1407. );
  1408. //
  1409. // Wait for I/O to complete before removing the device.
  1410. //
  1411. ReleaseRemoveLockAndWait(&deviceExtension->RemoveLock, Irp);
  1412. // 2000/02/05: stevedz - Moved this code from the legacy unload routine.
  1413. if ( DeviceObject == RootDeviceObject ) {
  1414. IoStopTimer( DeviceObject );
  1415. status = IoUnregisterPlugPlayNotification(
  1416. deviceExtension->DiskNotificationEntry);
  1417. RootDeviceObject = NULL;
  1418. }
  1419. ACQUIRE_SHARED( &ClusDiskDeviceListLock );
  1420. // Release the device list entry for this device object
  1421. deviceEntry = ClusDiskDeviceList;
  1422. while ( deviceEntry ) {
  1423. if ( deviceEntry->DeviceObject == DeviceObject ) {
  1424. deviceEntry->FreePool = TRUE;
  1425. CleanupDeviceList( DeviceObject );
  1426. break;
  1427. }
  1428. deviceEntry = deviceEntry->Next;
  1429. }
  1430. targetObject = deviceExtension->TargetDeviceObject;
  1431. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  1432. deviceExtension->Detached = TRUE;
  1433. deviceExtension->TargetDeviceObject = NULL;
  1434. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  1435. RELEASE_SHARED( &ClusDiskDeviceListLock );
  1436. context.DeviceExtension = deviceExtension;
  1437. context.NewValue = NULL; // clear the field
  1438. context.Flags = 0; // don't dismount
  1439. ProcessDelayedWorkSynchronous( DeviceObject, ClusDiskpReplaceHandleArray, &context );
  1440. //
  1441. // [GorN] 10/05/1999
  1442. //
  1443. // The following lock acquisition is causing a deadlock as follows:
  1444. //
  1445. // Disk is being removed. Clustering detects that and starts dismounting of
  1446. // cluster disks, while it is doing that it acquires ClusDiskDeviceListLock in
  1447. // the shared mode. Processing a dismount request, FS reports Dismount PnP event,
  1448. // this gets blocked on PnP lock.
  1449. //
  1450. // At the same time, PnP is trying to deliver RemoveDevice, which gets blocked
  1451. // in clusdisk, when clusdisk is trying to acquire ClusDiskDeviceListLock in
  1452. // exclusive mode.
  1453. //
  1454. // [HACKHACK] It is better to defer the detaching / deletion to the worker thread
  1455. // which will be properly protected by exclusive lock
  1456. // ACQUIRE_EXCLUSIVE( &ClusDiskDeviceListLock );
  1457. IoDetachDevice( targetObject );
  1458. IoDeleteDevice( DeviceObject );
  1459. // RELEASE_EXCLUSIVE( &ClusDiskDeviceListLock );
  1460. CDLOG( "ClusDiskPnpDispatch: IoDeleteDevice DO %p", DeviceObject );
  1461. // Don't release the RemoveLock as it was done just above.
  1462. IoSkipCurrentIrpStackLocation( Irp );
  1463. return( IoCallDriver( targetObject, Irp ) );
  1464. }
  1465. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1466. ClusDiskPrint((1,
  1467. "[ClusDisk] CancelRemoveDevice PNP IRP on devobj %p \n",
  1468. DeviceObject));
  1469. break;
  1470. case IRP_MN_DEVICE_USAGE_NOTIFICATION: {
  1471. UNICODE_STRING availableName;
  1472. ClusDiskPrint((1,
  1473. "[ClusDisk] DeviceUsageNotification DevObj %p Type %08x InPath %08x \n",
  1474. DeviceObject,
  1475. irpSp->Parameters.UsageNotification.Type,
  1476. irpSp->Parameters.UsageNotification.InPath
  1477. ));
  1478. //
  1479. // If we are adding one of the special files and the disk is clustered,
  1480. // then fail the request. We can't have these files on clustered disks.
  1481. // We will allow removal of the special files at any time (online or offline).
  1482. //
  1483. if ( irpSp->Parameters.UsageNotification.InPath &&
  1484. !deviceExtension->Detached ) {
  1485. ClusDiskPrint((1,
  1486. "[ClusDisk] DeviceUsageNotification - specified device is in cluster - failing request \n"
  1487. ));
  1488. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  1489. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  1490. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1491. return (STATUS_INVALID_DEVICE_REQUEST);
  1492. }
  1493. switch ( irpSp->Parameters.UsageNotification.Type ) {
  1494. case DeviceUsageTypePaging: {
  1495. BOOLEAN setPagable;
  1496. //
  1497. // We need this event to synchonize access to the paging count.
  1498. //
  1499. status = KeWaitForSingleObject( &deviceExtension->PagingPathCountEvent,
  1500. Executive, KernelMode,
  1501. FALSE, NULL );
  1502. //
  1503. // If we are removing the last paging device, we need to set DO_POWER_PAGABLE
  1504. // bit here, and possible re-set it below on failure.
  1505. //
  1506. setPagable = FALSE;
  1507. if ( !irpSp->Parameters.UsageNotification.InPath &&
  1508. deviceExtension->PagingPathCount == 1 ) {
  1509. //
  1510. // We are removing the last paging file. We must have DO_POWER_PAGABLE bit
  1511. // set, but only if no one set the DO_POWER_INRUSH bit
  1512. //
  1513. if ( DeviceObject->Flags & DO_POWER_INRUSH ) {
  1514. ClusDiskPrint(( 2,
  1515. "[ClusDisk] Last paging file removed, but DO_POWER_INRUSH was already set, devobj %p \n",
  1516. DeviceObject ));
  1517. } else {
  1518. ClusDiskPrint(( 2,
  1519. "[ClusDisk] Last paging file removed, setting DO_POWER_INRUSH, devobj %p \n",
  1520. DeviceObject ));
  1521. DeviceObject->Flags |= DO_POWER_PAGABLE;
  1522. setPagable = TRUE;
  1523. }
  1524. }
  1525. //
  1526. // Forward the IRP to the drivers below before finishing handling the
  1527. // special cases.
  1528. //
  1529. status = ClusDiskForwardIrpSynchronous( DeviceObject, Irp );
  1530. //
  1531. // Now deal with the failure and success cases. Note that we are not allowed
  1532. // to fail the IRP once it is sent to the lower drivers.
  1533. //
  1534. if ( NT_SUCCESS(status) ) {
  1535. IoAdjustPagingPathCount(
  1536. &deviceExtension->PagingPathCount,
  1537. irpSp->Parameters.UsageNotification.InPath);
  1538. if ( irpSp->Parameters.UsageNotification.InPath ) {
  1539. if ( deviceExtension->PagingPathCount == 1 ) {
  1540. ClusDiskPrint(( 2,
  1541. "[ClusDisk] Clearing DO_POWER_PAGABLE, devobj %p \n",
  1542. DeviceObject ));
  1543. DeviceObject->Flags &= ~DO_POWER_PAGABLE;
  1544. }
  1545. }
  1546. } else {
  1547. //
  1548. // Clean up the changes done above.
  1549. //
  1550. if ( TRUE == setPagable ) {
  1551. ClusDiskPrint(( 2,
  1552. "[ClusDisk] Clearing DO_POWER_PAGABLE due to IRP failure, devobj %p status %08x \n",
  1553. DeviceObject,
  1554. status ));
  1555. DeviceObject->Flags &= ~DO_POWER_PAGABLE;
  1556. setPagable = FALSE;
  1557. }
  1558. }
  1559. //
  1560. // Set the event so the next paging request can occur.
  1561. //
  1562. KeSetEvent( &deviceExtension->PagingPathCountEvent,
  1563. IO_NO_INCREMENT, FALSE );
  1564. break;
  1565. }
  1566. case DeviceUsageTypeHibernation: {
  1567. IoAdjustPagingPathCount( &deviceExtension->HibernationPathCount,
  1568. irpSp->Parameters.UsageNotification.InPath );
  1569. status = ClusDiskForwardIrpSynchronous( DeviceObject, Irp );
  1570. if ( !NT_SUCCESS(status) ) {
  1571. IoAdjustPagingPathCount( &deviceExtension->HibernationPathCount,
  1572. !irpSp->Parameters.UsageNotification.InPath );
  1573. }
  1574. break;
  1575. }
  1576. case DeviceUsageTypeDumpFile: {
  1577. IoAdjustPagingPathCount( &deviceExtension->DumpPathCount,
  1578. irpSp->Parameters.UsageNotification.InPath );
  1579. status = ClusDiskForwardIrpSynchronous( DeviceObject, Irp );
  1580. if ( !NT_SUCCESS(status) ) {
  1581. IoAdjustPagingPathCount( &deviceExtension->DumpPathCount,
  1582. !irpSp->Parameters.UsageNotification.InPath );
  1583. }
  1584. break;
  1585. }
  1586. default: {
  1587. ClusDiskPrint(( 2,
  1588. "[ClusDisk] Unrecognized notification type, devobj %p notification %08x \n",
  1589. DeviceObject,
  1590. irpSp->Parameters.UsageNotification.Type ));
  1591. status = STATUS_INVALID_PARAMETER;
  1592. break;
  1593. }
  1594. }
  1595. //
  1596. // This debug print is outside of the synchonization, but that's OK.
  1597. //
  1598. ClusDiskPrint(( 3,
  1599. "[ClusDisk] PagingCount %08lx HibernationCount %08x DumpCount %08x\n",
  1600. deviceExtension->PagingPathCount,
  1601. deviceExtension->HibernationPathCount,
  1602. deviceExtension->DumpPathCount ));
  1603. //
  1604. // We need this event to synchonize access to the paging count.
  1605. //
  1606. status = KeWaitForSingleObject( &deviceExtension->PagingPathCountEvent,
  1607. Executive, KernelMode,
  1608. FALSE, NULL );
  1609. //
  1610. // If the device is not currently clustered and the paging count is zero,
  1611. // add the disk to Parameters\AvailableDisks list. Otherwise, remove this
  1612. // disk from the list. We can only get to this code if we already know
  1613. // the disk is not clustered (i.e. Detached is TRUE).
  1614. //
  1615. ASSERT( deviceExtension->Detached );
  1616. //
  1617. // Allocate buffer for AvailableDisks registry key.
  1618. //
  1619. status = ClusDiskInitRegistryString( &availableName,
  1620. CLUSDISK_AVAILABLE_DISKS_KEYNAME,
  1621. sizeof(CLUSDISK_AVAILABLE_DISKS_KEYNAME) );
  1622. if ( NT_SUCCESS(status) ) {
  1623. if ( 0 == deviceExtension->PagingPathCount &&
  1624. 0 == deviceExtension->HibernationPathCount &&
  1625. 0 == deviceExtension->DumpPathCount ) {
  1626. //
  1627. // Create the signature key under Parameters\AvailableDisks
  1628. //
  1629. ClusDiskAddSignature( &availableName,
  1630. deviceExtension->Signature,
  1631. TRUE );
  1632. } else {
  1633. //
  1634. // Delete the signature key under Parameters\AvailableDisks.
  1635. //
  1636. ClusDiskDeleteSignature( &availableName,
  1637. deviceExtension->Signature );
  1638. }
  1639. ExFreePool( availableName.Buffer );
  1640. status = STATUS_SUCCESS;
  1641. }
  1642. //
  1643. // Set the event so the next paging request can occur.
  1644. //
  1645. KeSetEvent( &deviceExtension->PagingPathCountEvent,
  1646. IO_NO_INCREMENT, FALSE );
  1647. //
  1648. // Complete the IRP. This IRP was already sent to the lower drivers.
  1649. //
  1650. Irp->IoStatus.Status = status;
  1651. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  1652. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1653. return status;
  1654. break;
  1655. } // IRP_MN_DEVICE_USAGE_NOTIFICATION
  1656. default:
  1657. break;
  1658. }
  1659. CDLOG( "ClusDiskPnpDispatch: Exit, DO %p", DeviceObject );
  1660. //
  1661. // We don't recognize this IRP - simply pass it on to next guy.
  1662. //
  1663. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  1664. IoSkipCurrentIrpStackLocation(Irp);
  1665. return (IoCallDriver( deviceExtension->TargetDeviceObject,
  1666. Irp ) );
  1667. } // ClusDiskPnpDispatch
  1668. NTSTATUS
  1669. DriverEntry(
  1670. IN PDRIVER_OBJECT DriverObject,
  1671. IN PUNICODE_STRING RegistryPath
  1672. )
  1673. /*++
  1674. Routine Description:
  1675. This is the routine called by the system to initialize the disk
  1676. performance driver. The driver object is set up and then the
  1677. driver calls ClusDiskxxxInitialize to attach to the boot devices.
  1678. Arguments:
  1679. DriverObject - The Cluster Disk driver object.
  1680. Return Value:
  1681. NTSTATUS
  1682. --*/
  1683. {
  1684. NTSTATUS status;
  1685. ULONG i;
  1686. ClusDiskRegistryPath.Buffer = NULL;
  1687. #if CLUSDISK_DEBUG
  1688. if ( !ClusDiskGood ) {
  1689. status = STATUS_INSUFFICIENT_RESOURCES;
  1690. goto FnExit;
  1691. }
  1692. #endif
  1693. WPP_INIT_TRACING(DriverObject, RegistryPath);
  1694. ClusDiskSystemProcess = (PKPROCESS) IoGetCurrentProcess();
  1695. //
  1696. // Set up the device driver entry points.
  1697. //
  1698. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  1699. DriverObject->MajorFunction[i] = ClusDiskPassThrough;
  1700. }
  1701. DriverObject->MajorFunction[IRP_MJ_CREATE] = ClusDiskCreate;
  1702. DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClusDiskClose;
  1703. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = ClusDiskCleanup;
  1704. DriverObject->MajorFunction[IRP_MJ_READ] = ClusDiskRead;
  1705. DriverObject->MajorFunction[IRP_MJ_WRITE] = ClusDiskWrite;
  1706. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClusDiskDeviceControl;
  1707. DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ClusDiskShutdownFlush;
  1708. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ClusDiskShutdownFlush;
  1709. DriverObject->MajorFunction[IRP_MJ_POWER] = ClusDiskPowerDispatch;
  1710. DriverObject->MajorFunction[IRP_MJ_PNP] = ClusDiskPnpDispatch;
  1711. //
  1712. // Driver is unloadable. (Not for now... the problem is that the driver
  1713. // can be called at the unload entrypoint even with open file handles.
  1714. // Until this is fixed, disable the unload.)
  1715. //
  1716. // NTRAID#72826-2000/02/05-stevedz ClusDisk.sys Unload routine not supported.
  1717. //
  1718. // This was the closest bug to this problem I could find. Until this driver
  1719. // is fully PnP or until the reference count bug is fixed, this driver cannot
  1720. // support unload.
  1721. //
  1722. // DriverObject->DriverUnload = ClusDiskUnload;
  1723. //
  1724. // make a copy of RegistryPath, appending the Parameters subkey
  1725. //
  1726. ClusDiskRegistryPath.Buffer = ExAllocatePool(NonPagedPool,
  1727. RegistryPath->MaximumLength +
  1728. sizeof( CLUSDISK_PARAMETERS_KEYNAME ) +
  1729. sizeof( WCHAR ));
  1730. if ( ClusDiskRegistryPath.Buffer == NULL ) {
  1731. status = STATUS_INSUFFICIENT_RESOURCES;
  1732. goto FnExit;
  1733. }
  1734. ClusDiskRegistryPath.MaximumLength = RegistryPath->MaximumLength +
  1735. sizeof( CLUSDISK_PARAMETERS_KEYNAME ) +
  1736. sizeof( WCHAR );
  1737. RtlCopyUnicodeString( &ClusDiskRegistryPath, RegistryPath );
  1738. RtlAppendUnicodeToString( &ClusDiskRegistryPath, CLUSDISK_PARAMETERS_KEYNAME );
  1739. ClusDiskRegistryPath.Buffer[ ClusDiskRegistryPath.Length / sizeof( WCHAR )] = UNICODE_NULL;
  1740. status = ArbitrationInitialize();
  1741. if( !NT_SUCCESS(status) ) {
  1742. ClusDiskPrint((1,
  1743. "[ClusDisk] ArbitrationInitialize failed, error: %08X\n",
  1744. status));
  1745. goto FnExit;
  1746. }
  1747. //
  1748. // Find the bus on which the system disk is loaded.
  1749. //
  1750. status = ClusDiskInitialize( DriverObject );
  1751. if ( !NT_SUCCESS(status) ) {
  1752. ClusDiskPrint((1,
  1753. "[ClusDisk] Failed to initialize! %08X\n",
  1754. status));
  1755. }
  1756. FnExit:
  1757. if ( !NT_SUCCESS(status) ) {
  1758. if ( ClusDiskRegistryPath.Buffer ) {
  1759. ExFreePool( ClusDiskRegistryPath.Buffer );
  1760. ClusDiskRegistryPath.Buffer = NULL;
  1761. }
  1762. if ( gArbitrationBuffer ) {
  1763. ExFreePool( gArbitrationBuffer );
  1764. gArbitrationBuffer = NULL;
  1765. }
  1766. }
  1767. return(status);
  1768. } // DriverEntry
  1769. VOID
  1770. ClusDiskTickHandler(
  1771. IN PDEVICE_OBJECT DeviceObject,
  1772. IN PVOID Context
  1773. )
  1774. /*++
  1775. Routine Description:
  1776. Timer routine that handles reservations. Walk all device objects, looking
  1777. for active timers.
  1778. Arguments:
  1779. DeviceObject - Supplies a pointer to the root device object.
  1780. Context - Not used.
  1781. Return Value:
  1782. None.
  1783. Notes:
  1784. We can't process the reservations at DPC level because reservation
  1785. IOCTL's invoke paged code in the SCSI subsystem.
  1786. --*/
  1787. {
  1788. PCLUS_DEVICE_EXTENSION deviceExtension;
  1789. KIRQL irql;
  1790. PDEVICE_OBJECT deviceObject = DeviceObject->DriverObject->DeviceObject;
  1791. LARGE_INTEGER currentTime;
  1792. LARGE_INTEGER deltaTime;
  1793. BOOLEAN arbitrationTickIsCalled = FALSE;
  1794. NTSTATUS status;
  1795. CDLOGF(TICK,"ClusDiskTickHandler: Entry DO %p", DeviceObject );
  1796. //
  1797. // Globally Synchronize
  1798. //
  1799. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  1800. if ( ClusDiskRescan && !ClusDiskRescanBusy && ClusDiskRescanRetry ) {
  1801. --ClusDiskRescanRetry;
  1802. ClusDiskRescanBusy = TRUE;
  1803. ExQueueWorkItem(&ClusDiskRescanWorkItem,
  1804. CriticalWorkQueue );
  1805. }
  1806. CDLOGF(TICK,"ClusDiskTickHandler: SpinLockAcquired DO %p", DeviceObject );
  1807. //
  1808. // Loop through all device objects looking for timeouts...
  1809. //
  1810. while ( deviceObject ) {
  1811. deviceExtension = deviceObject->DeviceExtension;
  1812. //
  1813. // If we have an attached partition0 device object (with a
  1814. // reserve irp) that is is online and has a timer going.
  1815. //
  1816. if ( !deviceExtension->Detached &&
  1817. deviceExtension->PerformReserves &&
  1818. (deviceExtension->ReserveTimer != 0) ) {
  1819. //
  1820. // Countdown to next reservation.
  1821. //
  1822. KeQuerySystemTime( &currentTime );
  1823. deltaTime.QuadPart = ( currentTime.QuadPart - deviceExtension->LastReserve.QuadPart ) / 10000;
  1824. #if 0
  1825. ClusDiskPrint((
  1826. 1,
  1827. "[ClusDisk] Signature %08X, msec since last reserve = %u\n",
  1828. deviceExtension->Signature,
  1829. deltaTime.LowPart ));
  1830. #endif
  1831. if ( deltaTime.LowPart >= ((RESERVE_TIMER * 1000) - 500) ) {
  1832. #if 0 // we no longer rely strictly on the timer.
  1833. if ( --deviceExtension->ReserveTimer == 0 )
  1834. //
  1835. // Reset next timeout
  1836. //
  1837. deviceExtension->ReserveTimer = RESERVE_TIMER;
  1838. #endif
  1839. if (!arbitrationTickIsCalled) {
  1840. ArbitrationTick();
  1841. arbitrationTickIsCalled = TRUE;
  1842. }
  1843. CDLOGF(TICK,"ClusDiskTickHandler: DeltaTime DO %p %!delta!",
  1844. deviceObject, // LOGPTR
  1845. deltaTime.QuadPart ); // LOGULONG
  1846. //
  1847. // Check if worker thread still busy from last timeout.
  1848. //
  1849. if ( !deviceExtension->TimerBusy ) {
  1850. //
  1851. // Acquire the RemoveLock here and free it when the reserve code completes.
  1852. //
  1853. status = AcquireRemoveLock(&deviceExtension->RemoveLock, ClusDiskReservationWorker);
  1854. if ( !NT_SUCCESS(status) ) {
  1855. ClusDiskPrint(( 1,
  1856. "[ClusDisk] ClusDiskTickHandler: AcquireRemoveLock for %p failed %08X \n",
  1857. deviceExtension,
  1858. status ));
  1859. //
  1860. // Failed to get the RemoveLock for this device, go on to the next one.
  1861. //
  1862. deviceObject = deviceObject->NextDevice;
  1863. continue;
  1864. }
  1865. //
  1866. // Reset time since last reserve.
  1867. //
  1868. deviceExtension->LastReserve.QuadPart = currentTime.QuadPart;
  1869. deviceExtension->TimerBusy = TRUE;
  1870. CDLOGF(TICK,"ClusDiskTickHandler: QueueWorkItem DO %p",
  1871. deviceObject );
  1872. ExQueueWorkItem(&deviceExtension->WorkItem,
  1873. CriticalWorkQueue );
  1874. }
  1875. }
  1876. }
  1877. //
  1878. // Walk all device objects.
  1879. //
  1880. deviceObject = deviceObject->NextDevice;
  1881. }
  1882. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  1883. } // ClusDiskTickHandler
  1884. VOID
  1885. ClusDiskReservationWorker(
  1886. IN PCLUS_DEVICE_EXTENSION DeviceExtension
  1887. )
  1888. /*++
  1889. Routine Description:
  1890. Reservation timeout worker routine. This worker queue routine
  1891. attempts a reservation on a cluster device.
  1892. The RemoveLock for this device (the one owning the device extension)
  1893. must be acquired before this routine runs.
  1894. Arguments:
  1895. DeviceExtension - The device extension for the device to reserve.
  1896. Return Value:
  1897. None
  1898. Notes:
  1899. The reservations must be handled here, because we can't handle them
  1900. at DPC level.
  1901. --*/
  1902. {
  1903. NTSTATUS status;
  1904. KIRQL irql;
  1905. PLIST_ENTRY listEntry;
  1906. PIRP irp;
  1907. LARGE_INTEGER currentTime;
  1908. LARGE_INTEGER timeDelta;
  1909. LARGE_INTEGER startReserveTime;
  1910. if ( RootDeviceObject == NULL ) {
  1911. return;
  1912. }
  1913. CDLOGF(TICK,"ClusDiskReservationWorker: Entry DO %p", DeviceExtension->DeviceObject );
  1914. //
  1915. // If ReserveTimer is cleared, we should not do reservation on the device.
  1916. //
  1917. if ( DeviceExtension->ReserveTimer == 0 ) {
  1918. goto FnExit;
  1919. }
  1920. #if 0 // Very noisy...
  1921. // Use only for really intense debugging....
  1922. ClusDiskPrint(( 3,
  1923. "[ClusDisk] Reserving: Sig %08X DevObj %p \n",
  1924. DeviceExtension->Signature,
  1925. DeviceExtension->DeviceObject ));
  1926. #endif
  1927. KeQuerySystemTime( &startReserveTime );
  1928. status = ReserveScsiDevice( DeviceExtension );
  1929. KeQuerySystemTime( &currentTime );
  1930. timeDelta.QuadPart = ( currentTime.QuadPart - startReserveTime.QuadPart );
  1931. if (timeDelta.QuadPart > 500 * 10000) {
  1932. timeDelta.QuadPart /= 10000;
  1933. ClusDiskPrint((
  1934. 1,
  1935. "[ClusDisk] Signature %08X, %u ms spent in ReserveScsiDevice\n",
  1936. DeviceExtension->Signature, timeDelta.LowPart));
  1937. CDLOGF(RESERVE, "ClusDiskReservationWorker: LongTimeInThisReserve DevObj %p timeDelta %d",
  1938. DeviceExtension->DeviceObject,
  1939. timeDelta.LowPart );
  1940. }
  1941. timeDelta.QuadPart = ( currentTime.QuadPart - DeviceExtension->LastReserve.QuadPart );
  1942. if (timeDelta.QuadPart > 3500 * 10000) {
  1943. timeDelta.QuadPart /= 10000;
  1944. ClusDiskPrint((
  1945. 1,
  1946. "[ClusDisk] Signature %08X, %u ms since last reserve\n",
  1947. DeviceExtension->Signature, timeDelta.LowPart));
  1948. CDLOGF(RESERVE, "ClusDiskReservationWorker: LongTimeBetweenReserves DevObj %p timeDelta %d",
  1949. DeviceExtension->DeviceObject,
  1950. timeDelta.LowPart );
  1951. }
  1952. if ( !NT_SUCCESS(status) ) {
  1953. ClusDiskPrint((
  1954. 1,
  1955. "[ClusDisk] We lost our reservation for Signature %08X\n",
  1956. DeviceExtension->Signature));
  1957. timeDelta.QuadPart = ( currentTime.QuadPart - DeviceExtension->LastReserve.QuadPart ) / 10000;
  1958. CDLOGF(RESERVE,"ClusDiskReservationWorker: LostReserve DO %p delta %!u! ms status %!status!",
  1959. DeviceExtension->DeviceObject,
  1960. timeDelta.LowPart,
  1961. status);
  1962. ClusDiskPrint((
  1963. 1,
  1964. "[ClusDisk] Milliseconds since last reserve = %u, on Signature %08X\n",
  1965. timeDelta.LowPart,
  1966. DeviceExtension->Signature ));
  1967. IoAcquireCancelSpinLock( &irql );
  1968. KeAcquireSpinLockAtDpcLevel(&ClusDiskSpinLock);
  1969. DeviceExtension->ReserveTimer = 0;
  1970. DeviceExtension->ReserveFailure = status;
  1971. OFFLINE_DISK( DeviceExtension );
  1972. //
  1973. // Signal all waiting Irp's
  1974. //
  1975. while ( !IsListEmpty(&DeviceExtension->WaitingIoctls) ) {
  1976. listEntry = RemoveHeadList(&DeviceExtension->WaitingIoctls);
  1977. irp = CONTAINING_RECORD( listEntry,
  1978. IRP,
  1979. Tail.Overlay.ListEntry );
  1980. //irp->IoStatus.Status = status;
  1981. //IoCompleteRequest(irp, IO_NO_INCREMENT);
  1982. ClusDiskCompletePendingRequest(irp, status, DeviceExtension);
  1983. }
  1984. KeReleaseSpinLockFromDpcLevel(&ClusDiskSpinLock);
  1985. IoReleaseCancelSpinLock( irql );
  1986. } else {
  1987. //
  1988. // Arbitration write is now done after successful reservation. The reserve won't be
  1989. // stalled by a write (and a request sense).
  1990. //
  1991. ArbitrationReserve( DeviceExtension );
  1992. }
  1993. FnExit:
  1994. ReleaseRemoveLock(&DeviceExtension->RemoveLock, ClusDiskReservationWorker);
  1995. CDLOGF(TICK,"ClusDiskReservationWorker: Exit DO %p", DeviceExtension->DeviceObject );
  1996. return;
  1997. } // ClusDiskReservationWorker
  1998. NTSTATUS
  1999. ClusDiskRescanWorker(
  2000. IN PVOID Context
  2001. )
  2002. /*++
  2003. Routine Description:
  2004. Arguments:
  2005. Context - input context - not used.
  2006. Return Value:
  2007. None
  2008. --*/
  2009. {
  2010. if ( !RootDeviceObject ) {
  2011. return(STATUS_SUCCESS);
  2012. }
  2013. ClusDiskRescanBusy = FALSE;
  2014. ClusDiskScsiInitialize(RootDeviceObject->DriverObject, ClusDiskNextDisk, 1);
  2015. return(STATUS_SUCCESS);
  2016. } // ClusDiskRescanWorker
  2017. NTSTATUS
  2018. ClusDiskHaltProcessingWorker(
  2019. IN PVOID Context
  2020. )
  2021. /*++
  2022. Routine Description:
  2023. This worker thread processes halt notifications from the Cluster Network
  2024. driver.
  2025. Arguments:
  2026. Context - input context - not used.
  2027. Return Value:
  2028. NTSTATUS for this request.
  2029. Notes:
  2030. Halt processing must be done via a worker thread because it cannot
  2031. be done at DPC since the disks are dismounted.
  2032. --*/
  2033. {
  2034. NTSTATUS status;
  2035. PDEVICE_OBJECT deviceObject;
  2036. PCLUS_DEVICE_EXTENSION deviceExtension;
  2037. KIRQL irql;
  2038. CDLOG("HaltProcessingWorker: Entry(%p)", Context );
  2039. if ( RootDeviceObject == NULL ) {
  2040. return(STATUS_DEVICE_OFF_LINE);
  2041. }
  2042. ACQUIRE_SHARED( &ClusDiskDeviceListLock );
  2043. //
  2044. // First, capture file handles for all P0 devices
  2045. //
  2046. deviceObject = RootDeviceObject->DriverObject->DeviceObject;
  2047. while ( deviceObject ) {
  2048. deviceExtension = deviceObject->DeviceExtension;
  2049. // Remove this online check? OpenFile should work with FILE_WRITE_ATTRIBUTES.
  2050. if ( !deviceExtension->Detached &&
  2051. deviceExtension->PhysicalDevice == deviceObject &&
  2052. deviceExtension->DiskState == DiskOnline)
  2053. {
  2054. //
  2055. // Disk has to be online,
  2056. // If it is offline, OpenFile will fail - not if FILE_WRITE_ATTRIBUTES used...
  2057. // It it is stalled OpenFile may stall
  2058. //
  2059. ProcessDelayedWorkSynchronous( deviceObject, ClusDiskpOpenFileHandles, NULL );
  2060. }
  2061. deviceObject = deviceObject->NextDevice;
  2062. }
  2063. deviceObject = RootDeviceObject->DriverObject->DeviceObject;
  2064. //
  2065. // Then, release all pended irps on all devices
  2066. // (Otherwise FSCTL_DISMOUNT will stall and cause a deadlock)
  2067. //
  2068. deviceObject = RootDeviceObject->DriverObject->DeviceObject;
  2069. while ( deviceObject ) {
  2070. deviceExtension = deviceObject->DeviceExtension;
  2071. if ( !deviceExtension->Detached )
  2072. {
  2073. ClusDiskCompletePendedIrps(
  2074. deviceExtension,
  2075. /* FileObject => */ NULL, // Will complete all irps //
  2076. /* Offline => */ TRUE);// will set device state to offline //
  2077. }
  2078. deviceObject = deviceObject->NextDevice;
  2079. }
  2080. //
  2081. // For each ClusDisk device, if we have a persistent reservation, then
  2082. // stop it.
  2083. //
  2084. deviceObject = RootDeviceObject->DriverObject->DeviceObject;
  2085. while ( deviceObject ) {
  2086. deviceExtension = deviceObject->DeviceExtension;
  2087. if ( !deviceExtension->Detached &&
  2088. deviceExtension->PhysicalDevice == deviceObject)
  2089. {
  2090. status = AcquireRemoveLock( &deviceExtension->RemoveLock, deviceExtension );
  2091. if ( !NT_SUCCESS(status) ) {
  2092. ClusDiskPrint(( 1,
  2093. "[ClusDisk] ClusDiskHaltProcessingWorker: AcquireRemoveLock for %p failed %08X \n",
  2094. deviceExtension,
  2095. status ));
  2096. // If we can't get the RemoveLock, skip this device.
  2097. deviceObject = deviceObject->NextDevice;
  2098. continue;
  2099. }
  2100. // Keep the device object around
  2101. ObReferenceObject( deviceObject);
  2102. ClusDiskDismountVolumes( deviceObject );
  2103. }
  2104. deviceObject = deviceObject->NextDevice;
  2105. }
  2106. RELEASE_SHARED( &ClusDiskDeviceListLock );
  2107. HaltBusy = FALSE;
  2108. CDLOG( "HaltProcessingWorker: Exit(%p)", Context );
  2109. return(STATUS_SUCCESS);
  2110. } // ClusDiskHaltProcessingWorker
  2111. VOID
  2112. ClusDiskCleanupDevice(
  2113. IN HANDLE FileHandle,
  2114. IN BOOLEAN Reset
  2115. )
  2116. /*++
  2117. Routine Description:
  2118. Cleanup the device by resetting the bus, and forcing a read of the
  2119. disk geometry.
  2120. Arguments:
  2121. FileHandle - the file handle to perform the operations.
  2122. Reset - TRUE if we should attempt resets to fix problems. FALSE otherwise.
  2123. Return Value:
  2124. None.
  2125. --*/
  2126. {
  2127. NTSTATUS status;
  2128. HANDLE eventHandle;
  2129. IO_STATUS_BLOCK ioStatusBlock;
  2130. STORAGE_BUS_RESET_REQUEST storageReset;
  2131. DISK_GEOMETRY diskGeometry;
  2132. SCSI_ADDRESS scsiAddress;
  2133. BOOLEAN busReset = FALSE;
  2134. CDLOG( "CleanupDevice: Entry fh %p, reset=%!bool!", FileHandle, Reset );
  2135. ClusDiskPrint(( 3,
  2136. "[ClusDisk] CleanupDevice: FileHandle %p, Reset %s \n",
  2137. FileHandle,
  2138. BoolToString( Reset ) ));
  2139. //
  2140. // Create event for notification.
  2141. //
  2142. status = ZwCreateEvent( &eventHandle,
  2143. EVENT_ALL_ACCESS,
  2144. NULL,
  2145. SynchronizationEvent,
  2146. FALSE );
  2147. if ( !NT_SUCCESS(status) ) {
  2148. ClusDiskPrint((
  2149. 1,
  2150. "[ClusDisk] CleanupDevice: Failed to create event, status %08X\n",
  2151. status ));
  2152. return;
  2153. }
  2154. if ( Reset ) {
  2155. //
  2156. // Start off by getting the SCSI address.
  2157. //
  2158. status = ZwDeviceIoControlFile( FileHandle,
  2159. eventHandle,
  2160. NULL,
  2161. NULL,
  2162. &ioStatusBlock,
  2163. IOCTL_SCSI_GET_ADDRESS,
  2164. NULL,
  2165. 0,
  2166. &scsiAddress,
  2167. sizeof(SCSI_ADDRESS) );
  2168. if ( NT_SUCCESS(status) ) {
  2169. CDLOG( "CleanupDevice: BusReset fh %p", FileHandle );
  2170. ClusDiskPrint(( 3,
  2171. "[ClusDisk] CleanupDevice: Bus Reset \n"
  2172. ));
  2173. //
  2174. // Now reset the bus!
  2175. //
  2176. busReset = TRUE;
  2177. storageReset.PathId = scsiAddress.PathId;
  2178. status = ZwDeviceIoControlFile( FileHandle,
  2179. eventHandle,
  2180. NULL,
  2181. NULL,
  2182. &ioStatusBlock,
  2183. IOCTL_STORAGE_BREAK_RESERVATION,
  2184. &storageReset,
  2185. sizeof(STORAGE_BUS_RESET_REQUEST),
  2186. NULL,
  2187. 0 );
  2188. if ( !NT_SUCCESS(status) ) {
  2189. ClusDiskPrint((
  2190. 1,
  2191. "[ClusDisk] CleanupDevice: Failed to reset device, error %08X.\n",
  2192. status));
  2193. }
  2194. }
  2195. }
  2196. //
  2197. // Next try to read the disk geometry.
  2198. //
  2199. status = ZwDeviceIoControlFile( FileHandle,
  2200. eventHandle,
  2201. NULL,
  2202. NULL,
  2203. &ioStatusBlock,
  2204. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  2205. NULL,
  2206. 0,
  2207. &diskGeometry,
  2208. sizeof(DISK_GEOMETRY) );
  2209. ZwClose( eventHandle );
  2210. //
  2211. // If we had to reset the bus, then wait for a few seconds.
  2212. //
  2213. if ( busReset ) {
  2214. LARGE_INTEGER waitTime;
  2215. waitTime.QuadPart = (ULONGLONG)(RESET_SLEEP * -(10000*1000));
  2216. KeDelayExecutionThread( KernelMode, FALSE, &waitTime );
  2217. }
  2218. CDLOG( "CleanupDevice: Exit fh %p", FileHandle );
  2219. return;
  2220. } // ClusDiskCleanupDevice
  2221. VOID
  2222. ClusDiskCleanupDeviceObject(
  2223. IN PDEVICE_OBJECT DeviceObject,
  2224. IN BOOLEAN Reset
  2225. )
  2226. /*++
  2227. Routine Description:
  2228. Cleanup the device object by resetting the bus, and forcing a read of the
  2229. disk geometry.
  2230. Arguments:
  2231. DeviceObject - the device to perform the operations.
  2232. Reset - TRUE if we should attempt resets to fix problems. FALSE otherwise.
  2233. Return Value:
  2234. None.
  2235. --*/
  2236. {
  2237. NTSTATUS status;
  2238. IO_STATUS_BLOCK ioStatusBlock;
  2239. STORAGE_BUS_RESET_REQUEST storageReset;
  2240. DISK_GEOMETRY diskGeometry;
  2241. SCSI_ADDRESS scsiAddress;
  2242. BOOLEAN busReset = FALSE;
  2243. PKEVENT event;
  2244. PIRP irp;
  2245. CDLOG( "CleanupDeviceObject: Entry DO %p reset=%!bool!", DeviceObject, Reset );
  2246. event = ExAllocatePool( NonPagedPool,
  2247. sizeof(KEVENT) );
  2248. if ( event == NULL ) {
  2249. ClusDiskPrint((
  2250. 1,
  2251. "[ClusDisk] CleanupDeviceObject: Failed to allocate event\n" ));
  2252. return;
  2253. }
  2254. if ( Reset ) {
  2255. //
  2256. // Start off by getting the SCSI address.
  2257. //
  2258. //
  2259. // Find out if this is on a SCSI bus. Note, that if this device
  2260. // is not a SCSI device, it is expected that the following
  2261. // IOCTL will fail!
  2262. //
  2263. irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_ADDRESS,
  2264. DeviceObject,
  2265. NULL,
  2266. 0,
  2267. &scsiAddress,
  2268. sizeof(SCSI_ADDRESS),
  2269. FALSE,
  2270. event,
  2271. &ioStatusBlock);
  2272. if ( !irp ) {
  2273. ExFreePool( event );
  2274. ClusDiskPrint((
  2275. 1,
  2276. "[ClusDisk] Failed to build IRP to read SCSI ADDRESS.\n"
  2277. ));
  2278. return;
  2279. }
  2280. //
  2281. // Set the event object to the unsignaled state.
  2282. // It will be used to signal request completion.
  2283. //
  2284. KeInitializeEvent(event,
  2285. NotificationEvent,
  2286. FALSE);
  2287. status = IoCallDriver(DeviceObject,
  2288. irp);
  2289. if (status == STATUS_PENDING) {
  2290. KeWaitForSingleObject(event,
  2291. Suspended,
  2292. KernelMode,
  2293. FALSE,
  2294. NULL);
  2295. status = ioStatusBlock.Status;
  2296. }
  2297. if ( !NT_SUCCESS(status) ) {
  2298. ClusDiskPrint((
  2299. 1,
  2300. "[ClusDisk] Failed to read SCSI ADDRESS. %08X\n",
  2301. status
  2302. ));
  2303. } else {
  2304. CDLOG( "CleanupDeviceObject: BusReset DO %p", DeviceObject );
  2305. busReset = TRUE;
  2306. storageReset.PathId = scsiAddress.PathId;
  2307. irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_BREAK_RESERVATION,
  2308. DeviceObject,
  2309. NULL,
  2310. 0,
  2311. &storageReset,
  2312. sizeof(STORAGE_BUS_RESET_REQUEST),
  2313. FALSE,
  2314. event,
  2315. &ioStatusBlock);
  2316. if ( !irp ) {
  2317. ExFreePool( event );
  2318. ClusDiskPrint((
  2319. 1,
  2320. "[ClusDisk] Failed to build IRP to read DRIVE GEOMETRY.\n"
  2321. ));
  2322. return;
  2323. }
  2324. //
  2325. // Set the event object to the unsignaled state.
  2326. // It will be used to signal request completion.
  2327. //
  2328. KeInitializeEvent(event,
  2329. NotificationEvent,
  2330. FALSE);
  2331. status = IoCallDriver(DeviceObject,
  2332. irp);
  2333. if (status == STATUS_PENDING) {
  2334. KeWaitForSingleObject(event,
  2335. Suspended,
  2336. KernelMode,
  2337. FALSE,
  2338. NULL);
  2339. status = ioStatusBlock.Status;
  2340. }
  2341. if ( !NT_SUCCESS(status) ) {
  2342. ClusDiskPrint((
  2343. 1,
  2344. "[ClusDisk] Failed to read disk geometry for DRIVE LAYOUT. %08X\n",
  2345. status
  2346. ));
  2347. }
  2348. }
  2349. }
  2350. //
  2351. // Next try to read the disk geometry.
  2352. //
  2353. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
  2354. DeviceObject,
  2355. NULL,
  2356. 0,
  2357. &diskGeometry,
  2358. sizeof(DISK_GEOMETRY),
  2359. FALSE,
  2360. event,
  2361. &ioStatusBlock);
  2362. if ( !irp ) {
  2363. ClusDiskPrint((
  2364. 1,
  2365. "[ClusDisk] Failed to build IRP to read DISK GEOMETRY.\n"
  2366. ));
  2367. } else {
  2368. //
  2369. // Set the event object to the unsignaled state.
  2370. // It will be used to signal request completion.
  2371. //
  2372. KeInitializeEvent(event,
  2373. NotificationEvent,
  2374. FALSE);
  2375. status = IoCallDriver(DeviceObject,
  2376. irp);
  2377. if (status == STATUS_PENDING) {
  2378. KeWaitForSingleObject(event,
  2379. Suspended,
  2380. KernelMode,
  2381. FALSE,
  2382. NULL);
  2383. status = ioStatusBlock.Status;
  2384. }
  2385. if ( !NT_SUCCESS(status) ) {
  2386. busReset = FALSE;
  2387. ClusDiskPrint((
  2388. 1,
  2389. "[ClusDisk] Failed to read DISK GEOMETRY. %08X\n",
  2390. status
  2391. ));
  2392. }
  2393. //
  2394. // If we had to reset the bus, then wait for a few seconds.
  2395. //
  2396. if ( busReset ) {
  2397. LARGE_INTEGER waitTime;
  2398. waitTime.QuadPart = (ULONGLONG)(RESET_SLEEP * -(10000*1000));
  2399. KeDelayExecutionThread( KernelMode, FALSE, &waitTime );
  2400. }
  2401. }
  2402. ExFreePool( event );
  2403. CDLOG( "CleanupDeviceObject: Exit DO %p", DeviceObject );
  2404. return;
  2405. } // ClusDiskCleanupDeviceObject
  2406. NTSTATUS
  2407. ClusDiskGetP0TargetDevice(
  2408. OUT PDEVICE_OBJECT * DeviceObject OPTIONAL,
  2409. IN PUNICODE_STRING DeviceName,
  2410. OUT PDRIVE_LAYOUT_INFORMATION * DriveLayoutInfo OPTIONAL,
  2411. OUT PSCSI_ADDRESS ScsiAddress OPTIONAL,
  2412. IN BOOLEAN Reset
  2413. )
  2414. /*++
  2415. Routine Description:
  2416. Find the target device object given the disk/partition numbers.
  2417. The device object will have reference count incremented and the
  2418. caller must decrement the count when done with the object.
  2419. Arguments:
  2420. DeviceObject - returns the device object if successful.
  2421. DeviceName - the unicode name for the device requested.
  2422. DriveLayoutInfo - returns the partition info if needed.
  2423. ScsiAddress - returns the scsi address info if needed.
  2424. Reset - TRUE if we should attempt resets to fix problems. FALSE otherwise.
  2425. Return Value:
  2426. NTSTATUS for this request.
  2427. --*/
  2428. {
  2429. NTSTATUS status;
  2430. OBJECT_ATTRIBUTES objectAttributes;
  2431. HANDLE fileHandle;
  2432. PFILE_OBJECT fileObject;
  2433. IO_STATUS_BLOCK ioStatusBlock;
  2434. ULONG driveLayoutSize;
  2435. PDRIVE_LAYOUT_INFORMATION driveLayoutInfo = NULL;
  2436. HANDLE eventHandle;
  2437. ULONG retry;
  2438. if ( DriveLayoutInfo != NULL ) {
  2439. *DriveLayoutInfo = NULL;
  2440. driveLayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
  2441. (MAX_PARTITIONS * sizeof(PARTITION_INFORMATION));
  2442. driveLayoutInfo = ExAllocatePool(NonPagedPoolCacheAligned,
  2443. driveLayoutSize);
  2444. if ( driveLayoutInfo == NULL ) {
  2445. return(STATUS_INSUFFICIENT_RESOURCES);
  2446. }
  2447. }
  2448. //
  2449. // Setup object attributes for the file to open.
  2450. //
  2451. InitializeObjectAttributes(&objectAttributes,
  2452. DeviceName,
  2453. OBJ_CASE_INSENSITIVE,
  2454. NULL,
  2455. NULL);
  2456. status = ZwCreateFile(&fileHandle,
  2457. FILE_READ_ATTRIBUTES,
  2458. &objectAttributes,
  2459. &ioStatusBlock,
  2460. NULL,
  2461. FILE_ATTRIBUTE_NORMAL,
  2462. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2463. FILE_OPEN,
  2464. FILE_SYNCHRONOUS_IO_NONALERT,
  2465. NULL,
  2466. 0 );
  2467. ASSERT( status != STATUS_PENDING );
  2468. if ( !NT_SUCCESS(status) ) {
  2469. ClusDiskPrint((1,
  2470. "[ClusDisk] GetP0TargetDevice, failed to open file %ws. Error %08X.\n",
  2471. DeviceName->Buffer,
  2472. status ));
  2473. CDLOG( "ClusDiskGetP0TargetDevice: Open %wZ failed %!status!",
  2474. DeviceName,
  2475. status );
  2476. if ( driveLayoutInfo ) {
  2477. ExFreePool( driveLayoutInfo );
  2478. }
  2479. return(status);
  2480. }
  2481. //
  2482. // get device object if requested
  2483. //
  2484. if ( DeviceObject ) {
  2485. status = ObReferenceObjectByHandle(fileHandle,
  2486. 0,
  2487. NULL,
  2488. KernelMode,
  2489. (PVOID *) &fileObject,
  2490. NULL );
  2491. if ( !NT_SUCCESS(status) ) {
  2492. ClusDiskPrint((1,
  2493. "[ClusDisk] GetP0TargetDevice Failed to reference object for file <%ws>. Error %08X.\n",
  2494. DeviceName->Buffer,
  2495. status ));
  2496. CDLOG( "ClusDiskGetP0TargetDevice: ObRef(%wZ) failed %!status!",
  2497. DeviceName,
  2498. status );
  2499. ZwClose( fileHandle );
  2500. if ( driveLayoutInfo ) {
  2501. ExFreePool( driveLayoutInfo );
  2502. }
  2503. return(status);
  2504. }
  2505. //
  2506. // Get the address of the target device object. If this file represents
  2507. // a device that was opened directly, then simply use the device or its
  2508. // attached device(s) directly. Also get the address of the Fast Io
  2509. // dispatch structure.
  2510. //
  2511. if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
  2512. *DeviceObject = IoGetRelatedDeviceObject( fileObject );
  2513. // Add a reference to the object so we can dereference it later.
  2514. ObReferenceObject( *DeviceObject );
  2515. } else {
  2516. *DeviceObject = IoGetAttachedDeviceReference( fileObject->DeviceObject );
  2517. }
  2518. //
  2519. // If we get a file system device object... go back and get the
  2520. // device object.
  2521. //
  2522. if ( (*DeviceObject)->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM ) {
  2523. ObDereferenceObject( *DeviceObject );
  2524. *DeviceObject = IoGetAttachedDeviceReference( fileObject->DeviceObject );
  2525. }
  2526. ASSERT( (*DeviceObject)->DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM );
  2527. ObDereferenceObject( fileObject );
  2528. }
  2529. //
  2530. // If we need to return scsi address information, do that now.
  2531. //
  2532. retry = 2;
  2533. while ( ScsiAddress &&
  2534. retry-- ) {
  2535. //
  2536. // Create event for notification.
  2537. //
  2538. status = ZwCreateEvent( &eventHandle,
  2539. EVENT_ALL_ACCESS,
  2540. NULL,
  2541. SynchronizationEvent,
  2542. FALSE );
  2543. if ( !NT_SUCCESS(status) ) {
  2544. ClusDiskPrint((1,
  2545. "[ClusDisk] GetP0TargetDevice: Failed to create event, status %lx\n",
  2546. status ));
  2547. } else {
  2548. // Should this routine be called GetScsiTargetDevice?
  2549. status = ZwDeviceIoControlFile( fileHandle,
  2550. eventHandle,
  2551. NULL,
  2552. NULL,
  2553. &ioStatusBlock,
  2554. IOCTL_SCSI_GET_ADDRESS,
  2555. NULL,
  2556. 0,
  2557. ScsiAddress,
  2558. sizeof(SCSI_ADDRESS) );
  2559. ZwClose( eventHandle );
  2560. if ( NT_SUCCESS(status) ) {
  2561. break;
  2562. } else {
  2563. ClusDiskPrint((3,
  2564. "[ClusDisk] GetP0TargetDevice failed to read scsi address info for <%ws>, error %lx.\n",
  2565. DeviceName->Buffer,
  2566. status ));
  2567. CDLOG( "ClusDiskGetP0TargetDevice: GetScsiAddr(%wZ), failed %!status!",
  2568. DeviceName,
  2569. status );
  2570. ClusDiskCleanupDevice( fileHandle, Reset );
  2571. }
  2572. }
  2573. }
  2574. //
  2575. // If we need to return partition information, do that now.
  2576. //
  2577. status = STATUS_SUCCESS;
  2578. retry = 2;
  2579. while ( driveLayoutInfo &&
  2580. retry-- ) {
  2581. //
  2582. // Create event for notification.
  2583. //
  2584. status = ZwCreateEvent( &eventHandle,
  2585. EVENT_ALL_ACCESS,
  2586. NULL,
  2587. SynchronizationEvent,
  2588. FALSE );
  2589. if ( !NT_SUCCESS(status) ) {
  2590. ClusDiskPrint((
  2591. 1,
  2592. "[ClusDisk] GetP0TargetDevice: Failed to create event, status %08X\n",
  2593. status ));
  2594. } else {
  2595. status = ZwDeviceIoControlFile( fileHandle,
  2596. eventHandle,
  2597. NULL,
  2598. NULL,
  2599. &ioStatusBlock,
  2600. IOCTL_DISK_GET_DRIVE_LAYOUT,
  2601. NULL,
  2602. 0,
  2603. driveLayoutInfo,
  2604. driveLayoutSize );
  2605. ZwClose( eventHandle );
  2606. if ( NT_SUCCESS(status) ) {
  2607. *DriveLayoutInfo = driveLayoutInfo;
  2608. break;
  2609. } else {
  2610. ClusDiskPrint((( status == STATUS_DEVICE_BUSY ? 3 : 1 ),
  2611. "[ClusDisk] GetP0TargetDevice failed to read partition info for <%ws>, error %lx.\n",
  2612. DeviceName->Buffer,
  2613. status ));
  2614. CDLOG( "ClusDiskGetP0TargetDevice: GetDriveLayout(%wZ) failed %!status!",
  2615. DeviceName,
  2616. status);
  2617. ClusDiskCleanupDevice( fileHandle, Reset );
  2618. }
  2619. }
  2620. }
  2621. if ( !NT_SUCCESS(status) ) {
  2622. ZwClose( fileHandle );
  2623. if ( driveLayoutInfo ) {
  2624. ExFreePool( driveLayoutInfo );
  2625. }
  2626. return(status);
  2627. }
  2628. ZwClose( fileHandle );
  2629. return(status);
  2630. } // ClusDiskGetP0TargetDevice
  2631. NTSTATUS
  2632. ClusDiskGetTargetDevice(
  2633. IN ULONG DiskNumber,
  2634. IN ULONG PartitionNumber,
  2635. OUT PDEVICE_OBJECT * DeviceObject OPTIONAL,
  2636. OUT PUNICODE_STRING DeviceName,
  2637. OUT PDRIVE_LAYOUT_INFORMATION * DriveLayoutInfo OPTIONAL,
  2638. OUT PSCSI_ADDRESS ScsiAddress OPTIONAL,
  2639. IN BOOLEAN Reset
  2640. )
  2641. /*++
  2642. Routine Description:
  2643. Find the target device object given the disk/partition numbers.
  2644. Arguments:
  2645. DiskNumber - the disk number for the requested device.
  2646. PartitionNumber - the partition number for the requested device.
  2647. DeviceObject - returns a pointer to the device object if needed.
  2648. DeviceName - returns the unicode string for the device if successful.
  2649. DriveLayoutInfo - returns the partition info if needed.
  2650. ScsiAddress - returns the scsi address info if needed.
  2651. Reset - TRUE if we should attempt resets to fix problems. FALSE otherwise.
  2652. Return Value:
  2653. NTSTATUS for this request.
  2654. --*/
  2655. {
  2656. NTSTATUS status;
  2657. NTSTATUS retStatus = STATUS_SUCCESS;
  2658. PWCHAR deviceNameBuffer;
  2659. OBJECT_ATTRIBUTES objectAttributes;
  2660. ULONG driveLayoutSize;
  2661. PDEVICE_OBJECT deviceObject;
  2662. PDRIVE_LAYOUT_INFORMATION driveLayoutInfo = NULL;
  2663. ULONG retry;
  2664. DeviceName->Buffer = NULL;
  2665. //
  2666. // allocate enough space for a harddiskX partitionY string
  2667. //
  2668. deviceNameBuffer = ExAllocatePool(NonPagedPool,
  2669. MAX_PARTITION_NAME_LENGTH*sizeof(WCHAR));
  2670. if ( deviceNameBuffer == NULL ) {
  2671. DeviceName->Buffer = NULL;
  2672. return(STATUS_INSUFFICIENT_RESOURCES);
  2673. }
  2674. //
  2675. // Create device name for the physical disk.
  2676. //
  2677. swprintf( deviceNameBuffer, DEVICE_PARTITION_NAME, DiskNumber, PartitionNumber );
  2678. WCSLEN_ASSERT( deviceNameBuffer );
  2679. RtlInitUnicodeString( DeviceName, deviceNameBuffer );
  2680. if ( !PartitionNumber ) {
  2681. status = ClusDiskGetP0TargetDevice(
  2682. DeviceObject,
  2683. DeviceName,
  2684. DriveLayoutInfo,
  2685. ScsiAddress,
  2686. Reset );
  2687. if ( NT_SUCCESS(status) ) {
  2688. return(status);
  2689. }
  2690. ClusDiskPrint((
  2691. 1,
  2692. "[ClusDisk] GetTargetDevice: try for just the device object.\n"
  2693. ));
  2694. retStatus = status;
  2695. }
  2696. //
  2697. // Get the device object.
  2698. //
  2699. deviceObject = NULL;
  2700. status = ClusDiskGetDeviceObject( deviceNameBuffer,
  2701. &deviceObject );
  2702. if ( !NT_SUCCESS(status) ) {
  2703. ClusDiskPrint((
  2704. 1,
  2705. "[ClusDisk] GetDeviceObject failed for %ws, status %08LX\n",
  2706. deviceNameBuffer,
  2707. status ));
  2708. DeviceName->Buffer = NULL;
  2709. ExFreePool( deviceNameBuffer );
  2710. return(status);
  2711. }
  2712. if ( DeviceObject ) {
  2713. *DeviceObject = deviceObject;
  2714. }
  2715. ClusDiskPrint((
  2716. 3,
  2717. "[ClusDisk] GetTargetDevice, Found Device Object = %p \n",
  2718. deviceObject
  2719. ));
  2720. //
  2721. // If we failed to get the P0 information, then return now with just
  2722. // the DeviceObject;
  2723. //
  2724. if ( !NT_SUCCESS(retStatus) ) {
  2725. ClusDiskPrint(( 3,
  2726. "[ClusDisk] GetTargetDevice, returning status %08LX (before ScsiAddress and DriveLayout) \n",
  2727. retStatus
  2728. ));
  2729. return(retStatus);
  2730. }
  2731. //
  2732. // Try twice to get the SCSI ADDRESS or Drive Layout if requested.
  2733. //
  2734. retry = 2;
  2735. while ( (ScsiAddress || DriveLayoutInfo) &&
  2736. retry-- ) {
  2737. status = STATUS_SUCCESS;
  2738. if ( ScsiAddress ) {
  2739. status = GetScsiAddress( deviceObject,
  2740. ScsiAddress );
  2741. }
  2742. if ( NT_SUCCESS(status) &&
  2743. DriveLayoutInfo &&
  2744. !driveLayoutInfo ) {
  2745. ClusDiskPrint(( 3,
  2746. "[ClusDisk] GetTargetDevice, GetScsiAddress was successful \n"
  2747. ));
  2748. status = GetDriveLayout( deviceObject,
  2749. &driveLayoutInfo,
  2750. FALSE );
  2751. if ( NT_SUCCESS(status) ) {
  2752. ClusDiskPrint(( 3,
  2753. "[ClusDisk] GetTargetDevice, GetDriveLayout was successful \n"
  2754. ));
  2755. }
  2756. }
  2757. //
  2758. // If we have what we need, then break out now.
  2759. //
  2760. if ( NT_SUCCESS(status) ) {
  2761. break;
  2762. }
  2763. ClusDiskCleanupDeviceObject( deviceObject, Reset );
  2764. }
  2765. if ( !NT_SUCCESS(status) ) {
  2766. ExFreePool( deviceNameBuffer );
  2767. DeviceName->Buffer = NULL;
  2768. if ( driveLayoutInfo ) {
  2769. ExFreePool( driveLayoutInfo );
  2770. }
  2771. } else {
  2772. if ( DriveLayoutInfo ) {
  2773. *DriveLayoutInfo = driveLayoutInfo;
  2774. }
  2775. }
  2776. ClusDiskPrint(( 3,
  2777. "[ClusDisk] GetTargetDevice, returning status %08LX \n",
  2778. status
  2779. ));
  2780. return(status);
  2781. } // ClusDiskGetTargetDevice
  2782. NTSTATUS
  2783. ClusDiskInitRegistryString(
  2784. OUT PUNICODE_STRING UnicodeString,
  2785. IN LPWSTR KeyName,
  2786. IN ULONG KeyNameSize
  2787. )
  2788. /*++
  2789. Routine Description:
  2790. Initialize a Unicode registry key string.
  2791. Arguments:
  2792. UnicodeString - pointer to the registry string to initialize.
  2793. KeyName - the key name.
  2794. KeyNameSize - the size of KeyName.
  2795. Return Value:
  2796. NTSTATUS for this request.
  2797. Notes:
  2798. The UnicodeString buffer is allocated from paged pool.
  2799. --*/
  2800. {
  2801. //
  2802. // Allocate buffer for signatures registry keys.
  2803. //
  2804. UnicodeString->Length = 0;
  2805. UnicodeString->MaximumLength = (USHORT)(ClusDiskRegistryPath.MaximumLength +
  2806. KeyNameSize +
  2807. sizeof(CLUSDISK_SIGNATURE_FIELD) +
  2808. sizeof(UNICODE_NULL));
  2809. UnicodeString->Buffer = ExAllocatePool(
  2810. PagedPool,
  2811. UnicodeString->MaximumLength
  2812. );
  2813. if ( !UnicodeString->Buffer ) {
  2814. ClusDiskPrint((
  2815. 1,
  2816. "[ClusDisk] InitRegistryString, failed to allocate a KeyName buffer\n"
  2817. ));
  2818. return(STATUS_INSUFFICIENT_RESOURCES);
  2819. }
  2820. //
  2821. // Zero the key name buffer.
  2822. //
  2823. RtlZeroMemory(
  2824. UnicodeString->Buffer,
  2825. UnicodeString->MaximumLength
  2826. );
  2827. //
  2828. // Initialize the string to the registry name for clusdisk.
  2829. //
  2830. RtlAppendUnicodeToString(
  2831. UnicodeString,
  2832. ClusDiskRegistryPath.Buffer
  2833. );
  2834. //
  2835. // Append the keyname.
  2836. //
  2837. RtlAppendUnicodeToString(
  2838. UnicodeString,
  2839. KeyName
  2840. );
  2841. return(STATUS_SUCCESS);
  2842. } // ClusDiskInitRegistryString
  2843. ULONG
  2844. ClusDiskIsSignatureDisk(
  2845. IN ULONG Signature
  2846. )
  2847. /*++
  2848. Routine Description:
  2849. Determine if the specified signature is in the signature list.
  2850. Arguments:
  2851. Signature - the signature for the disk of interest.
  2852. Return Value:
  2853. NTSTATUS for this request.
  2854. --*/
  2855. {
  2856. WCHAR buffer[128];
  2857. HANDLE regHandle;
  2858. OBJECT_ATTRIBUTES objectAttributes;
  2859. NTSTATUS status;
  2860. UNICODE_STRING regString;
  2861. swprintf(buffer,
  2862. L"%ws\\%08lX\0",
  2863. CLUSDISK_SIGNATURE_KEYNAME,
  2864. Signature);
  2865. status = ClusDiskInitRegistryString(
  2866. &regString,
  2867. buffer,
  2868. wcslen(buffer)
  2869. );
  2870. if ( !NT_SUCCESS(status) ) {
  2871. return(FALSE);
  2872. }
  2873. InitializeObjectAttributes(
  2874. &objectAttributes,
  2875. &regString,
  2876. OBJ_CASE_INSENSITIVE,
  2877. NULL,
  2878. NULL
  2879. );
  2880. status = ZwOpenKey(
  2881. &regHandle,
  2882. KEY_ALL_ACCESS,
  2883. &objectAttributes
  2884. );
  2885. if ( !NT_SUCCESS(status) ) {
  2886. #if 0
  2887. ClusDiskPrint((
  2888. 1,
  2889. "[ClusDisk] IsSignatureDisk: Error opening registry key <%wZ> for delete. Status %lx.\n",
  2890. &regString,
  2891. status));
  2892. #endif
  2893. ExFreePool( regString.Buffer );
  2894. return(FALSE);
  2895. } else {
  2896. ExFreePool( regString.Buffer );
  2897. ZwClose( regHandle );
  2898. return(TRUE);
  2899. }
  2900. return(STATUS_SUCCESS);
  2901. } // ClusDiskIsSignatureDisk
  2902. NTSTATUS
  2903. ClusDiskDeleteSignatureKey(
  2904. IN PUNICODE_STRING UnicodeString,
  2905. IN LPWSTR Name
  2906. )
  2907. /*++
  2908. Routine Description:
  2909. Delete the signature from the specified list.
  2910. Arguments:
  2911. UnicodeString - pointer to the Unicode base keyname for deleting.
  2912. Name - the keyname to delete.
  2913. Return Value:
  2914. NTSTATUS for this request.
  2915. --*/
  2916. {
  2917. WCHAR buffer[128];
  2918. UNICODE_STRING nameString;
  2919. HANDLE deleteHandle;
  2920. OBJECT_ATTRIBUTES objectAttributes;
  2921. NTSTATUS status;
  2922. nameString.Length = 0;
  2923. nameString.MaximumLength = sizeof(buffer);
  2924. nameString.Buffer = buffer;
  2925. RtlCopyUnicodeString( &nameString, UnicodeString );
  2926. RtlAppendUnicodeToString(
  2927. &nameString,
  2928. L"\\"
  2929. );
  2930. RtlAppendUnicodeToString(
  2931. &nameString,
  2932. Name
  2933. );
  2934. InitializeObjectAttributes(
  2935. &objectAttributes,
  2936. &nameString,
  2937. OBJ_CASE_INSENSITIVE,
  2938. NULL,
  2939. NULL
  2940. );
  2941. status = ZwOpenKey(
  2942. &deleteHandle,
  2943. KEY_ALL_ACCESS,
  2944. &objectAttributes
  2945. );
  2946. if ( !NT_SUCCESS(status) ) {
  2947. ClusDiskPrint((
  2948. 1,
  2949. "[ClusDisk] DeleteSignatureKey: Error opening registry key <%wZ> for delete. Status %lx.\n",
  2950. &nameString,
  2951. status));
  2952. return(status);
  2953. }
  2954. status = ZwDeleteKey( deleteHandle );
  2955. if ( !NT_SUCCESS(status) &&
  2956. (status != STATUS_OBJECT_NAME_NOT_FOUND) ) {
  2957. ClusDiskPrint((
  2958. 1,
  2959. "[ClusDisk] DeleteSignatureKey Error deleting <%ws> registry key from <%wZ>. Status: %lx\n",
  2960. Name,
  2961. &nameString,
  2962. status));
  2963. }
  2964. ZwClose( deleteHandle );
  2965. return(STATUS_SUCCESS);
  2966. } // ClusDiskDeleteSignatureKey
  2967. NTSTATUS
  2968. ClusDiskAddSignature(
  2969. IN PUNICODE_STRING UnicodeString,
  2970. IN ULONG Signature,
  2971. IN BOOLEAN Volatile
  2972. )
  2973. /*++
  2974. Routine Description:
  2975. Add the signature to the specified list.
  2976. Arguments:
  2977. UnicodeString - pointer to the Unicode base keyname for adding.
  2978. Signature - signature to add.
  2979. Volatile - TRUE if volatile key should be created.
  2980. Return Value:
  2981. NTSTATUS for this request.
  2982. --*/
  2983. {
  2984. NTSTATUS status;
  2985. WCHAR buffer[MAXIMUM_FILENAME_LENGTH];
  2986. UNICODE_STRING keyString;
  2987. UNICODE_STRING nameString;
  2988. HANDLE addHandle;
  2989. OBJECT_ATTRIBUTES objectAttributes;
  2990. OBJECT_ATTRIBUTES keyObjectAttributes;
  2991. ULONG options = 0;
  2992. UCHAR ntNameBuffer[64];
  2993. STRING ntNameString;
  2994. UNICODE_STRING ntUnicodeString;
  2995. ClusDiskPrint(( 3,
  2996. "[ClusDisk] ClusDiskAddSignature: adding signature %08X to %ws \n",
  2997. Signature,
  2998. UnicodeString->Buffer
  2999. ));
  3000. if ( SystemDiskSignature == Signature ) {
  3001. ClusDiskPrint(( 3,
  3002. "[ClusDisk] ClusDiskAddSignature: skipping system disk signature %08X \n",
  3003. Signature
  3004. ));
  3005. return STATUS_INVALID_PARAMETER;
  3006. }
  3007. if ( Volatile ) {
  3008. options = REG_OPTION_VOLATILE;
  3009. }
  3010. nameString.Length = 0;
  3011. nameString.MaximumLength = sizeof( buffer );
  3012. nameString.Buffer = buffer;
  3013. //
  3014. // Create the name of the key to add.
  3015. //
  3016. RtlCopyUnicodeString( &nameString, UnicodeString );
  3017. //
  3018. // Create device name for the physical disk.
  3019. //
  3020. sprintf(ntNameBuffer,
  3021. "\\%08lX",
  3022. Signature);
  3023. ASSERT( strlen(ntNameBuffer) < 64 );
  3024. RtlInitAnsiString(&ntNameString,
  3025. ntNameBuffer);
  3026. status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
  3027. &ntNameString,
  3028. TRUE);
  3029. UNHANDLED_ERROR( status );
  3030. RtlAppendUnicodeToString(
  3031. &nameString,
  3032. ntUnicodeString.Buffer
  3033. );
  3034. RtlFreeUnicodeString( &ntUnicodeString );
  3035. //
  3036. // For opening the passed in registry key name.
  3037. //
  3038. InitializeObjectAttributes(
  3039. &keyObjectAttributes,
  3040. UnicodeString,
  3041. OBJ_CASE_INSENSITIVE,
  3042. NULL,
  3043. NULL
  3044. );
  3045. //
  3046. // Attempt to open the passed in key.
  3047. //
  3048. status = ZwOpenKey(
  3049. &addHandle,
  3050. KEY_ALL_ACCESS,
  3051. &keyObjectAttributes
  3052. );
  3053. if ( !NT_SUCCESS(status) ) {
  3054. //
  3055. // Assume the key doesn't exist.
  3056. //
  3057. status = ZwCreateKey(
  3058. &addHandle,
  3059. KEY_ALL_ACCESS,
  3060. &keyObjectAttributes,
  3061. 0,
  3062. NULL,
  3063. options,
  3064. NULL
  3065. );
  3066. if ( !NT_SUCCESS(status) ) {
  3067. ClusDiskPrint((
  3068. 1,
  3069. "[ClusDisk] AddSignature: Error creating registry key <%wZ>. Status: %lx\n",
  3070. UnicodeString,
  3071. status
  3072. ));
  3073. return(status);
  3074. }
  3075. }
  3076. ZwClose( addHandle );
  3077. //
  3078. // For opening the new registry key name.
  3079. //
  3080. InitializeObjectAttributes(
  3081. &objectAttributes,
  3082. &nameString,
  3083. OBJ_CASE_INSENSITIVE,
  3084. NULL,
  3085. NULL
  3086. );
  3087. status = ZwCreateKey(
  3088. &addHandle,
  3089. KEY_ALL_ACCESS,
  3090. &objectAttributes,
  3091. 0,
  3092. NULL,
  3093. options,
  3094. NULL
  3095. );
  3096. if ( !NT_SUCCESS(status) ) {
  3097. ClusDiskPrint((
  3098. 1,
  3099. "[ClusDisk] AddSignature: Error creating registry key <%wZ> under <%wZ>. Status: %lx\n",
  3100. &nameString,
  3101. UnicodeString,
  3102. status
  3103. ));
  3104. return(status);
  3105. }
  3106. ZwClose( addHandle );
  3107. return(STATUS_SUCCESS);
  3108. } // ClusDiskAddSignature
  3109. NTSTATUS
  3110. ClusDiskDeleteSignature(
  3111. IN PUNICODE_STRING UnicodeString,
  3112. IN ULONG Signature
  3113. )
  3114. /*++
  3115. Routine Description:
  3116. Delete the signature from the specified list.
  3117. Arguments:
  3118. UnicodeString - pointer to the Unicode base keyname for deleting.
  3119. Signature - signature to delete.
  3120. Return Value:
  3121. NTSTATUS for this request.
  3122. --*/
  3123. {
  3124. NTSTATUS status;
  3125. WCHAR buffer[128];
  3126. UNICODE_STRING keyString;
  3127. UNICODE_STRING nameString;
  3128. HANDLE deleteHandle;
  3129. OBJECT_ATTRIBUTES objectAttributes;
  3130. OBJECT_ATTRIBUTES keyObjectAttributes;
  3131. UCHAR ntNameBuffer[64];
  3132. STRING ntNameString;
  3133. UNICODE_STRING ntUnicodeString;
  3134. ClusDiskPrint(( 3,
  3135. "[ClusDisk] ClusDiskDeleteSignature: removing signature %08X \n",
  3136. Signature
  3137. ));
  3138. nameString.Length = 0;
  3139. nameString.MaximumLength = sizeof(buffer);
  3140. nameString.Buffer = buffer;
  3141. //
  3142. // Create the name of the key to delete.
  3143. //
  3144. RtlCopyUnicodeString( &nameString, UnicodeString );
  3145. //
  3146. // Create device name for the physical disk.
  3147. //
  3148. sprintf(ntNameBuffer,
  3149. "\\%08lX",
  3150. Signature);
  3151. RtlInitAnsiString(&ntNameString,
  3152. ntNameBuffer);
  3153. status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
  3154. &ntNameString,
  3155. TRUE);
  3156. UNHANDLED_ERROR( status );
  3157. RtlAppendUnicodeToString(
  3158. &nameString,
  3159. ntUnicodeString.Buffer
  3160. );
  3161. RtlFreeUnicodeString( &ntUnicodeString );
  3162. //
  3163. // Use generated name for opening.
  3164. //
  3165. InitializeObjectAttributes(
  3166. &objectAttributes,
  3167. &nameString,
  3168. OBJ_CASE_INSENSITIVE,
  3169. NULL,
  3170. NULL
  3171. );
  3172. //
  3173. // Open the key for deleting.
  3174. //
  3175. status = ZwOpenKey(
  3176. &deleteHandle,
  3177. KEY_ALL_ACCESS,
  3178. &objectAttributes
  3179. );
  3180. if ( !NT_SUCCESS(status) ) {
  3181. ClusDiskPrint((
  3182. 1,
  3183. "[ClusDisk] DeleteSignature: Error opening registry key <%wZ> for delete. Status %lx.\n",
  3184. &nameString,
  3185. status
  3186. ));
  3187. return(status);
  3188. }
  3189. status = ZwDeleteKey( deleteHandle );
  3190. if ( !NT_SUCCESS(status) &&
  3191. (status != STATUS_OBJECT_NAME_NOT_FOUND) ) {
  3192. ClusDiskPrint((
  3193. 1,
  3194. "[ClusDisk] DeleteSignature: Error deleting <%s> registry key from <%wZ>. Status: %lx\n",
  3195. ntNameBuffer,
  3196. &nameString,
  3197. status
  3198. ));
  3199. }
  3200. ZwClose( deleteHandle );
  3201. return(STATUS_SUCCESS);
  3202. } // ClusDiskDeleteSignature
  3203. NTSTATUS
  3204. ClusDiskAddDiskName(
  3205. IN HANDLE SignatureHandle,
  3206. IN ULONG DiskNumber
  3207. )
  3208. /*++
  3209. Routine Description:
  3210. Set the DiskName for a given signature handle.
  3211. Arguments:
  3212. SignatureHandle - the handle for the signature to write.
  3213. DiskNumber - the disk number for this signature.
  3214. Return Value:
  3215. NTSTATUS for this request.
  3216. --*/
  3217. {
  3218. NTSTATUS status;
  3219. UNICODE_STRING name;
  3220. UCHAR ntNameBuffer[64];
  3221. STRING ntNameString;
  3222. UNICODE_STRING ntUnicodeString;
  3223. //
  3224. // Write the disk name.
  3225. //
  3226. RtlInitUnicodeString( &name, CLUSDISK_SIGNATURE_DISK_NAME );
  3227. sprintf(ntNameBuffer,
  3228. "\\Device\\Harddisk%d",
  3229. DiskNumber);
  3230. RtlInitAnsiString(&ntNameString,
  3231. ntNameBuffer);
  3232. status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
  3233. &ntNameString,
  3234. TRUE);
  3235. UNHANDLED_ERROR( status );
  3236. status = ZwSetValueKey(
  3237. SignatureHandle,
  3238. &name,
  3239. 0,
  3240. REG_SZ,
  3241. ntUnicodeString.Buffer,
  3242. ntUnicodeString.Length + sizeof(UNICODE_NULL) ); // Length for this call must include the trailing NULL.
  3243. if ( !NT_SUCCESS(status) ) {
  3244. ClusDiskPrint((1,
  3245. "[ClusDisk] AddDiskName: Failed to set diskname for signature %wZ status: %08X\n",
  3246. &ntUnicodeString,
  3247. status));
  3248. }
  3249. RtlFreeUnicodeString( &ntUnicodeString );
  3250. return(status);
  3251. } // ClusDiskAddDiskName
  3252. NTSTATUS
  3253. ClusDiskDeleteDiskName(
  3254. IN PUNICODE_STRING KeyName,
  3255. IN LPWSTR Name
  3256. )
  3257. /*++
  3258. Routine Description:
  3259. Delete the DiskName for the given key.
  3260. Arguments:
  3261. KeyName - pointer to the Unicode base keyname for deleting.
  3262. Name - the signature key to delete the diskname.
  3263. Return Value:
  3264. NTSTATUS for this request.
  3265. --*/
  3266. {
  3267. NTSTATUS status;
  3268. WCHAR buffer[128];
  3269. UNICODE_STRING nameString;
  3270. HANDLE deleteHandle;
  3271. OBJECT_ATTRIBUTES objectAttributes;
  3272. UNICODE_STRING name;
  3273. nameString.Length = 0;
  3274. nameString.MaximumLength = sizeof(buffer);
  3275. nameString.Buffer = buffer;
  3276. RtlCopyUnicodeString( &nameString, KeyName );
  3277. RtlAppendUnicodeToString(
  3278. &nameString,
  3279. L"\\"
  3280. );
  3281. RtlAppendUnicodeToString(
  3282. &nameString,
  3283. Name
  3284. );
  3285. InitializeObjectAttributes(
  3286. &objectAttributes,
  3287. &nameString,
  3288. OBJ_CASE_INSENSITIVE,
  3289. NULL,
  3290. NULL
  3291. );
  3292. status = ZwOpenKey(
  3293. &deleteHandle,
  3294. KEY_ALL_ACCESS,
  3295. &objectAttributes
  3296. );
  3297. if ( status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  3298. return(STATUS_SUCCESS);
  3299. }
  3300. if ( !NT_SUCCESS(status) ) {
  3301. ClusDiskPrint((
  3302. 1,
  3303. "[ClusDisk] DeleteDiskName: Error opening registry key <%wZ> to delete DiskName. Status %lx.\n",
  3304. &nameString,
  3305. status
  3306. ));
  3307. return(status);
  3308. }
  3309. RtlInitUnicodeString( &nameString, CLUSDISK_SIGNATURE_DISK_NAME );
  3310. status = ZwDeleteValueKey(
  3311. deleteHandle,
  3312. &nameString
  3313. );
  3314. if ( !NT_SUCCESS(status) &&
  3315. (status != STATUS_OBJECT_NAME_NOT_FOUND) ) {
  3316. ClusDiskPrint((
  3317. 1,
  3318. "[ClusDisk] DeleteDiskName: Error deleting DiskName value key from <%ws\\%wZ>. Status: %lx\n",
  3319. Name,
  3320. &nameString,
  3321. status
  3322. ));
  3323. }
  3324. ZwClose( deleteHandle );
  3325. return(STATUS_SUCCESS);
  3326. } // ClusDiskDeleteDiskName
  3327. VOID
  3328. ClusDiskDeleteDevice(
  3329. IN PDEVICE_OBJECT DeviceObject
  3330. )
  3331. {
  3332. KIRQL irql;
  3333. PCLUS_DEVICE_EXTENSION deviceExtension;
  3334. deviceExtension = DeviceObject->DeviceExtension;
  3335. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  3336. deviceExtension->Detached = TRUE;
  3337. if ( deviceExtension->PhysicalDevice ) {
  3338. ObDereferenceObject( deviceExtension->PhysicalDevice );
  3339. }
  3340. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  3341. IoDeleteDevice( DeviceObject );
  3342. return;
  3343. }
  3344. VOID
  3345. ClusDiskScsiInitialize(
  3346. IN PDRIVER_OBJECT DriverObject,
  3347. IN PVOID NextDisk,
  3348. IN ULONG Count
  3349. )
  3350. /*++
  3351. Routine Description:
  3352. Attach to new disk devices and partitions for busses defined in registry.
  3353. If this is the first time this routine is called,
  3354. then register with the IO system to be called
  3355. after all other disk device drivers have initiated.
  3356. Arguments:
  3357. DriverObject - Disk performance driver object.
  3358. NextDisk - Starting disk for this part of the initialization.
  3359. Count - Not used. Number of times this routine has been called.
  3360. Return Value:
  3361. NTSTATUS
  3362. --*/
  3363. {
  3364. PCONFIGURATION_INFORMATION configurationInformation;
  3365. UNICODE_STRING targetDeviceName;
  3366. UNICODE_STRING clusdiskDeviceName;
  3367. WCHAR clusdiskDeviceBuffer[MAX_CLUSDISK_DEVICE_NAME_LENGTH];
  3368. PDEVICE_OBJECT deviceObject;
  3369. PDEVICE_OBJECT physicalDevice;
  3370. PDEVICE_OBJECT targetDevice = NULL;
  3371. PDEVICE_OBJECT attachedTargetDevice;
  3372. PCLUS_DEVICE_EXTENSION deviceExtension;
  3373. PCLUS_DEVICE_EXTENSION zeroExtension;
  3374. PDRIVE_LAYOUT_INFORMATION driveLayoutInfo;
  3375. PPARTITION_INFORMATION partitionInfo;
  3376. NTSTATUS status;
  3377. ULONG diskNumber;
  3378. ULONG partIndex;
  3379. ULONG enumIndex;
  3380. ULONG returnedLength;
  3381. ULONG signature;
  3382. HANDLE signatureHandle;
  3383. HANDLE availableHandle;
  3384. WCHAR signatureBuffer[64];
  3385. UNICODE_STRING signatureKeyName;
  3386. UNICODE_STRING keyName;
  3387. UNICODE_STRING availableName;
  3388. UNICODE_STRING numberString;
  3389. OBJECT_ATTRIBUTES objectAttributes;
  3390. OBJECT_ATTRIBUTES availableObjectAttributes;
  3391. UCHAR basicBuffer[MAX_BUFFER_SIZE];
  3392. PKEY_BASIC_INFORMATION keyBasicInformation;
  3393. WCHAR signatureKeyBuffer[128];
  3394. SCSI_ADDRESS scsiAddress;
  3395. BOOLEAN attachVolume;
  3396. UCHAR driveLetter;
  3397. // PAGED_CODE(); // 2000/02/05: stevedz - Paged code cannot grab spinlocks.
  3398. ClusDiskRescan = FALSE;
  3399. keyBasicInformation = (PKEY_BASIC_INFORMATION)basicBuffer;
  3400. RtlZeroMemory(
  3401. basicBuffer,
  3402. MAX_BUFFER_SIZE
  3403. );
  3404. //
  3405. // Get registry parameters for our device.
  3406. //
  3407. //
  3408. // Allocate buffer for signatures registry key.
  3409. //
  3410. status = ClusDiskInitRegistryString(
  3411. &keyName,
  3412. CLUSDISK_SIGNATURE_KEYNAME,
  3413. sizeof(CLUSDISK_SIGNATURE_KEYNAME)
  3414. );
  3415. if ( !NT_SUCCESS(status) ) {
  3416. return;
  3417. }
  3418. //
  3419. // Allocate buffer for our list of available signatures,
  3420. // and form the subkey string name.
  3421. //
  3422. status = ClusDiskInitRegistryString(
  3423. &availableName,
  3424. CLUSDISK_AVAILABLE_DISKS_KEYNAME,
  3425. sizeof(CLUSDISK_AVAILABLE_DISKS_KEYNAME)
  3426. );
  3427. if ( !NT_SUCCESS(status) ) {
  3428. ExFreePool( keyName.Buffer );
  3429. return;
  3430. }
  3431. //
  3432. // Setup the object attributes for the Parameters\Signatures key.
  3433. //
  3434. InitializeObjectAttributes(
  3435. &objectAttributes,
  3436. &keyName,
  3437. OBJ_CASE_INSENSITIVE,
  3438. NULL,
  3439. NULL
  3440. );
  3441. //
  3442. // Open Parameters\Signatures Key.
  3443. //
  3444. status = ZwOpenKey(
  3445. &signatureHandle,
  3446. KEY_READ,
  3447. &objectAttributes
  3448. );
  3449. if ( status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  3450. status = ZwCreateKey(
  3451. &signatureHandle,
  3452. KEY_ALL_ACCESS,
  3453. &objectAttributes,
  3454. 0,
  3455. NULL,
  3456. 0,
  3457. NULL
  3458. );
  3459. }
  3460. if ( !NT_SUCCESS(status) ) {
  3461. ExFreePool( keyName.Buffer );
  3462. ExFreePool( availableName.Buffer );
  3463. ClusDiskPrint((
  3464. 1,
  3465. "[ClusDisk] ScsiInit: Failed to open Signatures registry key. Status: %lx\n",
  3466. status
  3467. ));
  3468. return;
  3469. }
  3470. //
  3471. // Setup the object attributes for the Parameters\AvailableDisks key.
  3472. //
  3473. InitializeObjectAttributes(
  3474. &availableObjectAttributes,
  3475. &availableName,
  3476. OBJ_CASE_INSENSITIVE,
  3477. NULL,
  3478. NULL
  3479. );
  3480. //
  3481. // Open Parameters\AvailableDisks Key.
  3482. //
  3483. status = ZwOpenKey(
  3484. &availableHandle,
  3485. KEY_ALL_ACCESS,
  3486. &availableObjectAttributes
  3487. );
  3488. if ( !NT_SUCCESS(status) ) {
  3489. if ( status != STATUS_OBJECT_NAME_NOT_FOUND ) {
  3490. ClusDiskPrint((
  3491. 1,
  3492. "[ClusDisk] ScsiInit: Failed to open AvailableDisks registry key. Status: %lx. Continuing.\n",
  3493. status
  3494. ));
  3495. }
  3496. } else {
  3497. //
  3498. // Delete the previous list of available devices.
  3499. //
  3500. enumIndex = 0;
  3501. while ( TRUE ) {
  3502. status = ZwEnumerateKey(
  3503. availableHandle,
  3504. enumIndex,
  3505. KeyBasicInformation,
  3506. keyBasicInformation,
  3507. MAX_BUFFER_SIZE,
  3508. &returnedLength
  3509. );
  3510. enumIndex++;
  3511. if ( !NT_SUCCESS(status) ) {
  3512. if ( status == STATUS_NO_MORE_ENTRIES ) {
  3513. break;
  3514. } else {
  3515. continue;
  3516. }
  3517. }
  3518. status = ClusDiskDeleteSignatureKey(
  3519. &availableName,
  3520. keyBasicInformation->Name
  3521. );
  3522. if ( !NT_SUCCESS(status) ) {
  3523. continue;
  3524. }
  3525. }
  3526. status = ZwDeleteKey( availableHandle );
  3527. if ( !NT_SUCCESS(status) &&
  3528. (status != STATUS_OBJECT_NAME_NOT_FOUND) &&
  3529. (status != STATUS_CANNOT_DELETE) ) {
  3530. ClusDiskPrint((
  3531. 1,
  3532. "[ClusDisk] ScsiInit: Failed to delete AvailableDisks registry key. Status: %lx\n",
  3533. status
  3534. ));
  3535. }
  3536. ZwClose( availableHandle );
  3537. }
  3538. //
  3539. // Find out which Scsi Devices to control by enumerating all of the
  3540. // Signature keys. If we find a device that we cannot read the signature
  3541. // for, we will attach to it anyway.
  3542. //
  3543. enumIndex = 0;
  3544. while ( TRUE ) {
  3545. status = ZwEnumerateKey(
  3546. signatureHandle,
  3547. enumIndex,
  3548. KeyBasicInformation,
  3549. keyBasicInformation,
  3550. MAX_BUFFER_SIZE,
  3551. &returnedLength
  3552. );
  3553. enumIndex++;
  3554. if ( !NT_SUCCESS(status) ) {
  3555. if ( status == STATUS_NO_MORE_ENTRIES ) {
  3556. break;
  3557. } else {
  3558. continue;
  3559. }
  3560. }
  3561. //
  3562. // Check that the value is reasonable. We're only looking for
  3563. // signatures (ie keys that are hex numbers).
  3564. //
  3565. //
  3566. // Check the signature. Make sure it's a number.
  3567. //
  3568. numberString.Buffer = keyBasicInformation->Name;
  3569. numberString.MaximumLength = (USHORT)keyBasicInformation->NameLength +
  3570. sizeof(UNICODE_NULL);
  3571. numberString.Length = (USHORT)keyBasicInformation->NameLength;
  3572. status = RtlUnicodeStringToInteger(
  3573. &numberString,
  3574. 16,
  3575. &signature
  3576. );
  3577. if ( !NT_SUCCESS(status) ) {
  3578. ClusDiskPrint((1,
  3579. "[ClusDisk] ScsiInit: Failed to get a good signature for %.*ws status: %08X\n",
  3580. keyBasicInformation->NameLength/sizeof(WCHAR),
  3581. keyBasicInformation->Name,
  3582. status));
  3583. continue;
  3584. }
  3585. //
  3586. // If this device is not in our list of attached devices, then add it!
  3587. //
  3588. if ( !MatchDevice( signature, NULL ) ) {
  3589. if ( !AddAttachedDevice( signature, NULL ) ) {
  3590. continue;
  3591. }
  3592. }
  3593. //
  3594. // Delete the DiskName for this signature key. We do this here in
  3595. // case any of the rest of this fails.
  3596. //
  3597. // Don't delete entries for disks that we've already processed.
  3598. if ( (ULONG_PTR)NextDisk != 0 ) {
  3599. continue;
  3600. }
  3601. //
  3602. // Delete the DiskName for the signature.
  3603. //
  3604. status = ClusDiskDeleteDiskName(
  3605. &keyName,
  3606. keyBasicInformation->Name
  3607. );
  3608. }
  3609. ZwClose( signatureHandle );
  3610. //
  3611. // Get the system configuration information.
  3612. //
  3613. configurationInformation = IoGetConfigurationInformation();
  3614. //
  3615. // Find ALL disk devices.
  3616. //
  3617. for (diskNumber = (ULONG)((ULONG_PTR)NextDisk);
  3618. diskNumber < configurationInformation->DiskCount;
  3619. diskNumber++) {
  3620. //
  3621. // Create device name for the physical disk.
  3622. //
  3623. DEREFERENCE_OBJECT( targetDevice );
  3624. status = ClusDiskGetTargetDevice( diskNumber,
  3625. 0,
  3626. &targetDevice,
  3627. &targetDeviceName,
  3628. &driveLayoutInfo,
  3629. &scsiAddress,
  3630. FALSE );
  3631. if ( !NT_SUCCESS(status) ) {
  3632. //
  3633. // If we didn't get a target device or we're already attached
  3634. // then skip this device.
  3635. //
  3636. if ( !targetDevice || ( targetDevice &&
  3637. ClusDiskAttached( targetDevice, diskNumber ) ) ) {
  3638. if ( targetDeviceName.Buffer ) {
  3639. RtlFreeUnicodeString( &targetDeviceName );
  3640. }
  3641. if ( driveLayoutInfo ) {
  3642. ExFreePool( driveLayoutInfo );
  3643. }
  3644. continue;
  3645. }
  3646. //
  3647. // If this device is on the system bus... then skip it.
  3648. // Also... if the media type is not FixedMedia, skip it.
  3649. //
  3650. if ( ((SystemDiskPort == scsiAddress.PortNumber) &&
  3651. (SystemDiskPath == scsiAddress.PathId)) ||
  3652. (GetMediaType( targetDevice ) != FixedMedia) ) {
  3653. if ( targetDeviceName.Buffer ) {
  3654. RtlFreeUnicodeString( &targetDeviceName );
  3655. }
  3656. if ( driveLayoutInfo ) {
  3657. ExFreePool( driveLayoutInfo );
  3658. }
  3659. continue;
  3660. }
  3661. // Check if disk is non-MBR (i.e. GPT). If so, skip it.
  3662. // The call to get the drive layout above will fail for GPT disk, because
  3663. // we are using IOCTL_DISK_GET_DRIVE_LAYOUT, and GPT disks only respond
  3664. // to IOCTL_DISK_GET_DRIVE_LAYOUT_EX. So make the call here to find out
  3665. // if the disk is MBR or not.
  3666. if ( !IsDiskMbr( targetDevice ) ) {
  3667. ClusDiskPrint(( 3,
  3668. "[ClusDisk] Skipping non-MBR disk device %ws \n",
  3669. targetDeviceName.Buffer ));
  3670. CDLOG( "ClusDiskScsiInitialize: Skipping non-MBR disk device %ws ",
  3671. targetDeviceName.Buffer );
  3672. continue;
  3673. }
  3674. if ( Count &&
  3675. (status == STATUS_DEVICE_NOT_READY) ) {
  3676. ClusDiskRescan = TRUE;
  3677. ClusDiskRescanRetry = MAX_RESCAN_RETRIES;
  3678. }
  3679. //
  3680. // On failures, where we got a target device, always attach.
  3681. // Use a signature of zero.
  3682. //
  3683. signature = 0;
  3684. ClusDiskPrint((
  3685. 1,
  3686. "[ClusDisk] Attach to device %ws anyway.\n",
  3687. targetDeviceName.Buffer ));
  3688. CDLOG( "ClusDiskScsiInitialize: Attach to device %ws using signature = 0 ",
  3689. targetDeviceName.Buffer );
  3690. goto Attach_Anyway;
  3691. }
  3692. if ( driveLayoutInfo == NULL ) {
  3693. RtlFreeUnicodeString(&targetDeviceName);
  3694. continue;
  3695. }
  3696. //
  3697. // Don't control disks that have no signature.
  3698. //
  3699. if ( 0 == driveLayoutInfo->Signature ) {
  3700. RtlFreeUnicodeString(&targetDeviceName);
  3701. ExFreePool(driveLayoutInfo);
  3702. continue;
  3703. }
  3704. //
  3705. // If this device is on the system bus... then skip it.
  3706. // Also... skip any device we're already attached to.
  3707. //
  3708. if ( ((SystemDiskPort == scsiAddress.PortNumber) &&
  3709. (SystemDiskPath == scsiAddress.PathId)) ||
  3710. (GetMediaType( targetDevice ) != FixedMedia) ||
  3711. ClusDiskAttached( targetDevice, diskNumber) ) {
  3712. ExFreePool(driveLayoutInfo);
  3713. RtlFreeUnicodeString(&targetDeviceName);
  3714. continue;
  3715. }
  3716. //
  3717. // Skip system disk.
  3718. //
  3719. if ( SystemDiskSignature == driveLayoutInfo->Signature ) {
  3720. ExFreePool(driveLayoutInfo);
  3721. RtlFreeUnicodeString(&targetDeviceName);
  3722. continue;
  3723. }
  3724. #if 0
  3725. // Don't check for NTFS partitions.
  3726. //
  3727. // Look through the partition table and determine if all
  3728. // the partitions are NTFS. If not all NTFS, then we won't
  3729. // attach to this volume.
  3730. //
  3731. attachVolume = TRUE;
  3732. for (partIndex = 0;
  3733. partIndex < driveLayoutInfo->PartitionCount;
  3734. partIndex++)
  3735. {
  3736. partitionInfo = &driveLayoutInfo->PartitionEntry[partIndex];
  3737. if (!partitionInfo->RecognizedPartition ||
  3738. partitionInfo->PartitionNumber == 0)
  3739. {
  3740. continue;
  3741. }
  3742. if ( (partitionInfo->PartitionType & ~PARTITION_NTFT) != PARTITION_IFS ) {
  3743. attachVolume = FALSE;
  3744. break;
  3745. }
  3746. }
  3747. if ( !attachVolume ) {
  3748. ExFreePool(driveLayoutInfo);
  3749. RtlFreeUnicodeString(&targetDeviceName);
  3750. continue;
  3751. }
  3752. #endif
  3753. signature = driveLayoutInfo->Signature;
  3754. Attach_Anyway:
  3755. //
  3756. // Create device object for partition 0.
  3757. //
  3758. swprintf(clusdiskDeviceBuffer,
  3759. CLUSDISK_DEVICE_NAME,
  3760. diskNumber,
  3761. 0);
  3762. RtlInitUnicodeString( &clusdiskDeviceName, clusdiskDeviceBuffer );
  3763. status = IoCreateDevice(DriverObject,
  3764. sizeof(CLUS_DEVICE_EXTENSION),
  3765. &clusdiskDeviceName,
  3766. FILE_DEVICE_DISK,
  3767. 0,
  3768. FALSE,
  3769. &physicalDevice);
  3770. if ( !NT_SUCCESS(status) ) {
  3771. ClusDiskPrint((1, "[ClusDisk] ScsiInit: Failed to create device for Drive%u %08X\n",
  3772. diskNumber, status));
  3773. if ( targetDeviceName.Buffer ) RtlFreeUnicodeString(&targetDeviceName);
  3774. if ( driveLayoutInfo ) ExFreePool(driveLayoutInfo);
  3775. continue;
  3776. }
  3777. CDLOG( "ClusDiskScsiInitialize: Created new device %p for disk %d partition 0 signature %08X ",
  3778. physicalDevice,
  3779. diskNumber,
  3780. signature );
  3781. physicalDevice->Flags |= DO_DIRECT_IO;
  3782. physicalDevice->Flags &= ~DO_DEVICE_INITIALIZING;
  3783. //
  3784. // Point device extension back at device object and remember
  3785. // the disk number.
  3786. //
  3787. deviceExtension = physicalDevice->DeviceExtension;
  3788. zeroExtension = deviceExtension;
  3789. deviceExtension->DeviceObject = physicalDevice;
  3790. deviceExtension->DiskNumber = diskNumber;
  3791. deviceExtension->LastPartitionNumber = 0;
  3792. deviceExtension->DriverObject = DriverObject;
  3793. deviceExtension->AttachValid = TRUE;
  3794. deviceExtension->ReserveTimer = 0;
  3795. deviceExtension->PerformReserves = TRUE;
  3796. deviceExtension->ReserveFailure = 0;
  3797. deviceExtension->Signature = signature;
  3798. deviceExtension->Detached = TRUE;
  3799. deviceExtension->OfflinePending = FALSE;
  3800. deviceExtension->ScsiAddress = scsiAddress;
  3801. deviceExtension->BusType = ScsiBus;
  3802. InitializeListHead( &deviceExtension->WaitingIoctls );
  3803. InitializeListHead( &deviceExtension->HoldIO );
  3804. IoInitializeRemoveLock( &deviceExtension->RemoveLock, CLUSDISK_ALLOC_TAG, 0, 0 );
  3805. //
  3806. // Signal the worker thread running event.
  3807. //
  3808. KeInitializeEvent( &deviceExtension->Event, NotificationEvent, TRUE );
  3809. ExInitializeWorkItem(&deviceExtension->WorkItem,
  3810. (PWORKER_THREAD_ROUTINE)ClusDiskReservationWorker,
  3811. (PVOID)deviceExtension );
  3812. // Always mark disk offline. If disk is one we shouldn't control, then
  3813. // we will mark it online before exiting.
  3814. //
  3815. // We offline all the volumes later. For now, just mark the disk offline.
  3816. //
  3817. deviceExtension->DiskState = DiskOffline;
  3818. KeInitializeEvent( &deviceExtension->PagingPathCountEvent,
  3819. NotificationEvent, TRUE );
  3820. deviceExtension->PagingPathCount = 0;
  3821. deviceExtension->HibernationPathCount = 0;
  3822. deviceExtension->DumpPathCount = 0;
  3823. ExInitializeResourceLite( &deviceExtension->DriveLayoutLock );
  3824. //
  3825. // This is the physical device object.
  3826. //
  3827. ObReferenceObject( physicalDevice );
  3828. deviceExtension->PhysicalDevice = physicalDevice;
  3829. #if 0 // Can't have a FS on partition 0
  3830. //
  3831. // Dismount any file system that might be hanging around
  3832. //
  3833. if ( targetDevice->Vpb &&
  3834. (targetDevice->Vpb->Flags & VPB_MOUNTED) ) {
  3835. status = DismountPartition( targetDevice, diskNumber, 0 );
  3836. if ( !NT_SUCCESS( status )) {
  3837. ClusDiskPrint((1,
  3838. "[ClusDisk] ScsiInit: dismount of %u/0 failed, %08X\n",
  3839. diskNumber, status));
  3840. }
  3841. }
  3842. #endif
  3843. //
  3844. // Attach to partition0. This call links the newly created
  3845. // device to the target device, returning the target device object.
  3846. // We may not want to stay attached for long... depending on
  3847. // whether this is a device we're interested in.
  3848. //
  3849. attachedTargetDevice = IoAttachDeviceToDeviceStack(physicalDevice,
  3850. targetDevice);
  3851. if ( targetDeviceName.Buffer ) RtlFreeUnicodeString(&targetDeviceName);
  3852. deviceExtension->TargetDeviceObject = attachedTargetDevice;
  3853. deviceExtension->Detached = FALSE;
  3854. //
  3855. // Once attached, we always need to set this information.
  3856. //
  3857. if ( attachedTargetDevice ) {
  3858. //
  3859. // Propagate driver's alignment requirements and power flags
  3860. //
  3861. physicalDevice->AlignmentRequirement =
  3862. deviceExtension->TargetDeviceObject->AlignmentRequirement;
  3863. physicalDevice->SectorSize =
  3864. deviceExtension->TargetDeviceObject->SectorSize;
  3865. //
  3866. // The storage stack explicitly requires DO_POWER_PAGABLE to be
  3867. // set in all filter drivers *unless* DO_POWER_INRUSH is set.
  3868. // this is true even if the attached device doesn't set DO_POWER_PAGABLE.
  3869. //
  3870. if ( deviceExtension->TargetDeviceObject->Flags & DO_POWER_INRUSH) {
  3871. physicalDevice->Flags |= DO_POWER_INRUSH;
  3872. } else {
  3873. physicalDevice->Flags |= DO_POWER_PAGABLE;
  3874. }
  3875. }
  3876. if ( signature == 0 ) {
  3877. if ( driveLayoutInfo ) {
  3878. ExFreePool( driveLayoutInfo );
  3879. driveLayoutInfo = NULL;
  3880. }
  3881. ClusDiskDismountDevice( diskNumber, FALSE );
  3882. continue;
  3883. }
  3884. if ( attachedTargetDevice == NULL ) {
  3885. ClusDiskPrint((1,
  3886. "[ClusDisk] ScsiInit: Failed to attach to device Drive%u\n",
  3887. diskNumber));
  3888. ClusDiskDeleteDevice(physicalDevice);
  3889. ExFreePool(driveLayoutInfo);
  3890. continue;
  3891. }
  3892. ASSERT( attachedTargetDevice == targetDevice );
  3893. //
  3894. // If we're attaching to a file system device, then return
  3895. // now. We must do this check after the dismount!
  3896. //
  3897. if (deviceExtension->TargetDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) {
  3898. goto skip_this_physical_device_with_info;
  3899. }
  3900. //
  3901. // Add the bus to our list of busses.
  3902. //
  3903. ClusDiskAddScsiBusList( deviceExtension );
  3904. //
  3905. // Add this this device and bus to our list of devices/busses.
  3906. //
  3907. // This still isn't the correct place to do this. The
  3908. // available disk list is built at the end of this function by
  3909. // looking at the signatures and noting which ones are NOT in
  3910. // the device list. If so, then that signature is added to the
  3911. // available device registry key. By call AddAttachedDevice at
  3912. // this point, the signature is always present on the list. If
  3913. // we add the call after the following if clause, then the code
  3914. // at the end of the function will still fail. This should probably
  3915. // be changed to add the device to the available device list when
  3916. // the following if fails.
  3917. //
  3918. // AddAttachedDevice( deviceExtension->Signature, physicalDevice );
  3919. //
  3920. // If the signature does not match one that we should really attach
  3921. // to, then just mark it as not attached.
  3922. //
  3923. if ( !MatchDevice( deviceExtension->Signature, NULL ) ) {
  3924. ClusDiskPrint((3,
  3925. "[ClusDisk] ScsiInit: adding disk %u (%08X) to available disks list\n",
  3926. diskNumber, driveLayoutInfo->Signature));
  3927. //
  3928. // Create the signature key using the available name.
  3929. //
  3930. status = ClusDiskAddSignature(&availableName,
  3931. driveLayoutInfo->Signature,
  3932. TRUE);
  3933. //
  3934. // Detach from the target device. This only requires marking
  3935. // the device object as detached!
  3936. //
  3937. deviceExtension->Detached = TRUE;
  3938. //
  3939. // Make this device available again.
  3940. // Don't need to stop reserves because reserves not yet started.
  3941. //
  3942. // deviceExtension->DiskState = DiskOnline;
  3943. ONLINE_DISK( deviceExtension );
  3944. continue;
  3945. //goto skip_this_physical_device_with_info;
  3946. }
  3947. //
  3948. // add this disk to devices we're controlling
  3949. //
  3950. AddAttachedDevice( deviceExtension->Signature, physicalDevice );
  3951. //
  3952. // Now open the actual signature key. Using original key name.
  3953. //
  3954. signatureKeyName.Length = 0;
  3955. signatureKeyName.MaximumLength = sizeof(signatureKeyBuffer);
  3956. signatureKeyName.Buffer = signatureKeyBuffer;
  3957. RtlCopyUnicodeString( &signatureKeyName, &keyName );
  3958. //
  3959. // Create device name for the physical disk we just attached.
  3960. //
  3961. swprintf(signatureBuffer, L"\\%08lX", deviceExtension->Signature);
  3962. WCSLEN_ASSERT( signatureBuffer );
  3963. RtlAppendUnicodeToString( &signatureKeyName, signatureBuffer );
  3964. //
  3965. // Setup the object attributes for the Parameters\Signatures\xyz key.
  3966. //
  3967. InitializeObjectAttributes(
  3968. &objectAttributes,
  3969. &signatureKeyName,
  3970. OBJ_CASE_INSENSITIVE,
  3971. NULL,
  3972. NULL
  3973. );
  3974. //
  3975. // Open Parameters\Signatures\xyz Key.
  3976. //
  3977. status = ZwOpenKey(
  3978. &signatureHandle,
  3979. KEY_READ | KEY_WRITE,
  3980. &objectAttributes
  3981. );
  3982. if ( !NT_SUCCESS(status) ) {
  3983. ClusDiskPrint((
  3984. 1,
  3985. "[ClusDisk] ScsiInit: Failed to open %wZ registry key. Status: %lx\n",
  3986. &signatureKeyName,
  3987. status
  3988. ));
  3989. continue;
  3990. }
  3991. //
  3992. // Write the disk name.
  3993. //
  3994. status = ClusDiskAddDiskName( signatureHandle, diskNumber );
  3995. ZwClose( signatureHandle );
  3996. //
  3997. // Offline all volumes for this disk.
  3998. //
  3999. OFFLINE_DISK( deviceExtension );
  4000. //
  4001. // Dismount all volumes on this disk.
  4002. //
  4003. ClusDiskDismountDevice( diskNumber, TRUE );
  4004. #if 0 // Removed 2/27/2001
  4005. //
  4006. // Called only for physical devices (partition0).
  4007. //
  4008. EjectVolumes( deviceExtension->DeviceObject );
  4009. ReclaimVolumes( deviceExtension->DeviceObject );
  4010. #endif
  4011. //
  4012. // Now enumerate the partitions on this device in order to
  4013. // attach a ClusDisk device object to each partition device object.
  4014. //
  4015. for (partIndex = 0;
  4016. partIndex < driveLayoutInfo->PartitionCount;
  4017. partIndex++)
  4018. {
  4019. partitionInfo = &driveLayoutInfo->PartitionEntry[partIndex];
  4020. //
  4021. // Make sure that there really is a partition here.
  4022. //
  4023. if (!partitionInfo->RecognizedPartition ||
  4024. partitionInfo->PartitionNumber == 0)
  4025. {
  4026. continue;
  4027. }
  4028. //
  4029. // Create device name for partition.
  4030. //
  4031. DEREFERENCE_OBJECT( targetDevice );
  4032. status = ClusDiskGetTargetDevice(diskNumber,
  4033. partitionInfo->PartitionNumber,
  4034. &targetDevice,
  4035. &targetDeviceName,
  4036. NULL,
  4037. NULL,
  4038. FALSE );
  4039. if ( !NT_SUCCESS(status) ) {
  4040. ClusDiskPrint((1,
  4041. "[ClusDisk] ScsiInit: couldn't attach to disk %u, partition %u %08X\n",
  4042. diskNumber,
  4043. partitionInfo->PartitionNumber,
  4044. status));
  4045. CDLOG( "ClusDiskScsiInitialize: Couldn't attach to disk %d partition %d, status %08X",
  4046. diskNumber,
  4047. partitionInfo->PartitionNumber,
  4048. status );
  4049. continue;
  4050. }
  4051. //
  4052. // Make sure we're not attached here!
  4053. //
  4054. if ( ClusDiskAttached( targetDevice, diskNumber ) ) {
  4055. // really hosed!
  4056. ClusDiskPrint((
  4057. 1,
  4058. "[ClusDisk] ScsiInit: Previously attached to %wZ.\n",
  4059. &targetDeviceName ));
  4060. CDLOG( "ClusDiskScsiInitialize: Previously attached to %wZ ",
  4061. &targetDeviceName );
  4062. RtlFreeUnicodeString( &targetDeviceName );
  4063. continue;
  4064. }
  4065. //
  4066. // Check if this device is a file system device.
  4067. //
  4068. if ( targetDevice->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM ) {
  4069. //
  4070. // Can't attach to a device that is already mounted.
  4071. //
  4072. ClusDiskPrint((
  4073. 1,
  4074. "[ClusDisk] ScsiInit: Attempted to attach to FS device %wZ.\n",
  4075. &targetDeviceName ));
  4076. CDLOG( "ClusDiskScsiInitialize: Attempted to attach to FS device %wZ ",
  4077. &targetDeviceName );
  4078. RtlFreeUnicodeString(&targetDeviceName);
  4079. continue;
  4080. }
  4081. //
  4082. // Create device object for this partition.
  4083. //
  4084. swprintf(clusdiskDeviceBuffer,
  4085. CLUSDISK_DEVICE_NAME,
  4086. diskNumber,
  4087. partitionInfo->PartitionNumber);
  4088. WCSLEN_ASSERT( clusdiskDeviceBuffer );
  4089. RtlInitUnicodeString( &clusdiskDeviceName, clusdiskDeviceBuffer );
  4090. status = IoCreateDevice(DriverObject,
  4091. sizeof(CLUS_DEVICE_EXTENSION),
  4092. &clusdiskDeviceName,
  4093. FILE_DEVICE_DISK,
  4094. 0,
  4095. FALSE,
  4096. &deviceObject);
  4097. if ( !NT_SUCCESS(status) ) {
  4098. RtlFreeUnicodeString(&targetDeviceName);
  4099. continue;
  4100. }
  4101. CDLOG( "ClusDiskScsiInitialize: Created new device %p for disk %d partition %d signature %08X ",
  4102. physicalDevice,
  4103. diskNumber,
  4104. partitionInfo->PartitionNumber,
  4105. signature );
  4106. deviceObject->Flags |= DO_DIRECT_IO;
  4107. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  4108. //
  4109. // Point device extension back at device object and
  4110. // remember the disk number.
  4111. //
  4112. deviceExtension = deviceObject->DeviceExtension;
  4113. deviceExtension->DeviceObject = deviceObject;
  4114. deviceExtension->DiskNumber = diskNumber;
  4115. deviceExtension->DriverObject = DriverObject;
  4116. deviceExtension->AttachValid = TRUE;
  4117. deviceExtension->BusType = ScsiBus;
  4118. deviceExtension->PerformReserves = FALSE;
  4119. deviceExtension->ReserveFailure = 0;
  4120. deviceExtension->Signature = zeroExtension->Signature;
  4121. deviceExtension->ScsiAddress = scsiAddress;
  4122. deviceExtension->Detached = TRUE;
  4123. deviceExtension->OfflinePending = FALSE;
  4124. deviceExtension->DiskState = zeroExtension->DiskState;
  4125. InitializeListHead( &deviceExtension->WaitingIoctls );
  4126. InitializeListHead( &deviceExtension->HoldIO );
  4127. IoInitializeRemoveLock( &deviceExtension->RemoveLock, CLUSDISK_ALLOC_TAG, 0, 0 );
  4128. //
  4129. // Signal the worker thread running event.
  4130. //
  4131. KeInitializeEvent( &deviceExtension->Event, NotificationEvent, TRUE );
  4132. //
  4133. // Maintain the last partition number created. Put it in
  4134. // each extension just to initialize the field.
  4135. //
  4136. deviceExtension->LastPartitionNumber = max(deviceExtension->LastPartitionNumber,
  4137. partitionInfo->PartitionNumber);
  4138. zeroExtension->LastPartitionNumber = deviceExtension->LastPartitionNumber;
  4139. KeInitializeEvent( &deviceExtension->PagingPathCountEvent,
  4140. NotificationEvent, TRUE );
  4141. deviceExtension->PagingPathCount = 0;
  4142. deviceExtension->HibernationPathCount = 0;
  4143. deviceExtension->DumpPathCount = 0;
  4144. ExInitializeResourceLite( &deviceExtension->DriveLayoutLock );
  4145. //
  4146. // Store pointer to physical device.
  4147. //
  4148. ObReferenceObject( physicalDevice );
  4149. deviceExtension->PhysicalDevice = physicalDevice;
  4150. //
  4151. // Attach to the partition. This call links the newly created
  4152. // device to the target device, returning the target device object.
  4153. //
  4154. ClusDiskPrint((3,
  4155. "[ClusDisk] ScsiInit: attaching to device %wZ\n",
  4156. &targetDeviceName ));
  4157. //
  4158. // First dismount any mounted file systems.
  4159. //
  4160. if ( targetDevice->Vpb &&
  4161. (targetDevice->Vpb->Flags & VPB_MOUNTED) ) {
  4162. status = DismountPartition( targetDevice,
  4163. diskNumber,
  4164. partitionInfo->PartitionNumber);
  4165. if ( !NT_SUCCESS( status )) {
  4166. ClusDiskPrint((1,
  4167. "[ClusDisk] ScsiInit: dismount of disk %u/%u failed %08X\n",
  4168. diskNumber, partitionInfo->PartitionNumber, status));
  4169. }
  4170. }
  4171. attachedTargetDevice = IoAttachDeviceToDeviceStack(deviceObject,
  4172. targetDevice );
  4173. deviceExtension->Detached = zeroExtension->Detached;
  4174. ASSERT( attachedTargetDevice == targetDevice );
  4175. if ( attachedTargetDevice == NULL ) {
  4176. ClusDiskPrint((1,
  4177. "[ClusDisk] ScsiInit: Failed to attach to device %wZ\n",
  4178. &targetDeviceName));
  4179. ClusDiskDeleteDevice(deviceObject);
  4180. RtlFreeUnicodeString(&targetDeviceName);
  4181. continue;
  4182. }
  4183. deviceExtension->TargetDeviceObject = attachedTargetDevice;
  4184. RtlFreeUnicodeString(&targetDeviceName);
  4185. //
  4186. // Call ourself back to make sure ft acts appropriately.
  4187. //
  4188. // [GN] No need to do it now. We are setting only P0 state
  4189. //
  4190. // CluCallBackDiskState( deviceObject, deviceExtension->DiskState );
  4191. //
  4192. // Propagate driver's alignment requirements and power flags.
  4193. //
  4194. deviceObject->AlignmentRequirement =
  4195. deviceExtension->TargetDeviceObject->AlignmentRequirement;
  4196. deviceObject->SectorSize =
  4197. deviceExtension->TargetDeviceObject->SectorSize;
  4198. //
  4199. // The storage stack explicitly requires DO_POWER_PAGABLE to be
  4200. // set in all filter drivers *unless* DO_POWER_INRUSH is set.
  4201. // this is true even if the attached device doesn't set DO_POWER_PAGABLE.
  4202. //
  4203. if ( deviceExtension->TargetDeviceObject->Flags & DO_POWER_INRUSH) {
  4204. deviceObject->Flags |= DO_POWER_INRUSH;
  4205. } else {
  4206. deviceObject->Flags |= DO_POWER_PAGABLE;
  4207. }
  4208. //
  4209. // Safe to dismount now that we're attached. This should cause
  4210. // the next IO to attach the FS to our device.
  4211. //
  4212. if ( targetDevice->Vpb ) {
  4213. if ( targetDevice->Vpb->Flags & VPB_MOUNTED ) {
  4214. ClusDiskPrint((1,
  4215. "[ClusDisk] ScsiInit: Disk %u/%u is Mounted!\n",
  4216. diskNumber, partitionInfo->PartitionNumber));
  4217. status = DismountPartition( targetDevice,
  4218. diskNumber,
  4219. partitionInfo->PartitionNumber);
  4220. if ( !NT_SUCCESS( status )) {
  4221. ClusDiskPrint((1,
  4222. "[ClusDisk] ScsiInit: dismount of %u/%u failed %08X\n",
  4223. diskNumber, partitionInfo->PartitionNumber, status));
  4224. }
  4225. }
  4226. }
  4227. }
  4228. ExFreePool( driveLayoutInfo );
  4229. continue;
  4230. skip_this_physical_device_with_info:
  4231. ExFreePool( driveLayoutInfo );
  4232. //skip_this_physical_device:
  4233. deviceExtension->Detached = TRUE;
  4234. IoDetachDevice( deviceExtension->TargetDeviceObject );
  4235. ClusDiskDeleteDevice( physicalDevice );
  4236. }
  4237. ExFreePool( keyName.Buffer );
  4238. //
  4239. // Find all available disk devices. These are devices that do not reside
  4240. // on the system bus and the signature is not part of the Signatures list.
  4241. //
  4242. for (diskNumber = 0;
  4243. diskNumber < configurationInformation->DiskCount;
  4244. diskNumber++) {
  4245. //
  4246. // Create device name for the physical disk.
  4247. //
  4248. DEREFERENCE_OBJECT( targetDevice );
  4249. status = ClusDiskGetTargetDevice( diskNumber,
  4250. 0,
  4251. NULL,
  4252. &targetDeviceName,
  4253. &driveLayoutInfo,
  4254. &scsiAddress,
  4255. FALSE );
  4256. if ( !NT_SUCCESS(status) ) {
  4257. continue;
  4258. }
  4259. if ( driveLayoutInfo == NULL ) {
  4260. RtlFreeUnicodeString(&targetDeviceName);
  4261. continue;
  4262. }
  4263. //
  4264. // Don't control disks that have no signature or system disk.
  4265. //
  4266. if ( ( 0 == driveLayoutInfo->Signature ) ||
  4267. ( SystemDiskSignature == driveLayoutInfo->Signature ) ) {
  4268. RtlFreeUnicodeString(&targetDeviceName);
  4269. ExFreePool(driveLayoutInfo);
  4270. continue;
  4271. }
  4272. //
  4273. // Now write the signature to the list of available disks,
  4274. // if the signature does not match one we already have and
  4275. // the device is not on the system bus.
  4276. //
  4277. if ( !MatchDevice(driveLayoutInfo->Signature, &deviceObject) &&
  4278. ((SystemDiskPort != scsiAddress.PortNumber) ||
  4279. (SystemDiskPath != scsiAddress.PathId)) ) {
  4280. ClusDiskPrint((3,
  4281. "[ClusDisk] ScsiInit: adding disk %u (%08X) to available disks list\n",
  4282. diskNumber, driveLayoutInfo->Signature));
  4283. //
  4284. // Create the signature key. Using the available name.
  4285. //
  4286. status = ClusDiskAddSignature(&availableName,
  4287. driveLayoutInfo->Signature,
  4288. TRUE);
  4289. //
  4290. // Make sure this device comes online.
  4291. //
  4292. if ( deviceObject ) {
  4293. deviceExtension = deviceObject->DeviceExtension;
  4294. deviceExtension->Detached = TRUE;
  4295. // deviceExtension->DiskState = DiskOnline;
  4296. ONLINE_DISK( deviceExtension );
  4297. }
  4298. }
  4299. RtlFreeUnicodeString(&targetDeviceName);
  4300. ExFreePool( driveLayoutInfo );
  4301. }
  4302. ExFreePool( availableName.Buffer );
  4303. DEREFERENCE_OBJECT( targetDevice );
  4304. } // ClusDiskScsiInitialize
  4305. #if 0 // This code cannot be used!
  4306. VOID
  4307. ClusDiskUnload(
  4308. IN PDRIVER_OBJECT DriverObject
  4309. )
  4310. /*++
  4311. Routine Description:
  4312. This routine cleans up all memmory allocations and detaches from each
  4313. target device.
  4314. Arguments:
  4315. DriverObject - a pointer to the driver object to unload.
  4316. Return Value:
  4317. None.
  4318. Note - we should acquire the ClusDiskSpinLock, but then this code is NOT
  4319. pageable!
  4320. --*/
  4321. {
  4322. PCONFIGURATION_INFORMATION configurationInformation;
  4323. PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
  4324. PCLUS_DEVICE_EXTENSION deviceExtension;
  4325. PDEVICE_LIST_ENTRY deviceEntry;
  4326. PSCSI_BUS_ENTRY scsiBusEntry;
  4327. PVOID freeBlock;
  4328. PLIST_ENTRY listEntry;
  4329. PIRP irp;
  4330. ULONG diskNumber;
  4331. NTSTATUS status;
  4332. PAGED_CODE();
  4333. #if 0 // Moved to IRP_PNP_MN_REMOVE handler
  4334. if ( RootDeviceObject ) {
  4335. deviceExtension = RootDeviceObject->DeviceExtension;
  4336. status = IoUnregisterPlugPlayNotification(
  4337. deviceExtension->DiskNotificationEntry);
  4338. RootDeviceObject = NULL;
  4339. }
  4340. //
  4341. // Free all device entries..
  4342. //
  4343. deviceEntry = ClusDiskDeviceList;
  4344. while ( deviceEntry ) {
  4345. freeBlock = deviceEntry;
  4346. deviceEntry = deviceEntry->Next;
  4347. ExFreePool( freeBlock );
  4348. }
  4349. ClusDiskDeviceList = NULL;
  4350. #endif
  4351. //
  4352. // Free all SCSI bus entries..
  4353. //
  4354. scsiBusEntry = ClusDiskScsiBusList;
  4355. while ( scsiBusEntry ) {
  4356. freeBlock = scsiBusEntry;
  4357. scsiBusEntry = scsiBusEntry->Next;
  4358. ExFreePool( freeBlock );
  4359. }
  4360. ClusDiskScsiBusList = NULL;
  4361. //
  4362. // Free all drive letters
  4363. //
  4364. ClusDiskReleaseDriveLetters();
  4365. //
  4366. // 2000/02/04: stevedz - With PnP, the following loop is not required.
  4367. // When we get unload working, it will be removed.
  4368. //
  4369. #if 0
  4370. //
  4371. // Loop through all device objects detaching...
  4372. //
  4373. // On NT4 - Need SpinLocks! The DriverObject->DeviceObject list is not synchronized!
  4374. // On Win2000, PnP will already have cleaned this up
  4375. //
  4376. while ( deviceObject ) {
  4377. deviceExtension = deviceObject->DeviceExtension;
  4378. //
  4379. // Signal all waiting Irp's on the physical device extension.
  4380. //
  4381. while ( !IsListEmpty(&deviceExtension->WaitingIoctls) ) {
  4382. listEntry = RemoveHeadList(&deviceExtension->WaitingIoctls);
  4383. irp = CONTAINING_RECORD( listEntry,
  4384. IRP,
  4385. Tail.Overlay.ListEntry );
  4386. ClusDiskCompletePendingRequest(irp, STATUS_SUCCESS, deviceExtension);
  4387. }
  4388. while ( !IsListEmpty(&deviceExtension->HoldIO ) ) {
  4389. listEntry = RemoveHeadList(&deviceExtension->HoldIO );
  4390. irp = CONTAINING_RECORD( listEntry,
  4391. IRP,
  4392. Tail.Overlay.ListEntry );
  4393. ClusDiskCompletePendingRequest(irp, STATUS_REQUEST_ABORTED, deviceExtension);
  4394. }
  4395. if ( deviceExtension->BusType != RootBus ) {
  4396. IoDetachDevice( deviceExtension->TargetDeviceObject );
  4397. }
  4398. if ( deviceExtension->BusType == RootBus ) {
  4399. IoStopTimer( deviceObject );
  4400. }
  4401. IoDeleteDevice( deviceObject );
  4402. deviceObject = DriverObject->DeviceObject;
  4403. }
  4404. #endif
  4405. #if 0
  4406. //
  4407. // dismount all FS so we can free up references to our dev objs
  4408. //
  4409. configurationInformation = IoGetConfigurationInformation();
  4410. for (diskNumber = 0;
  4411. diskNumber < configurationInformation->DiskCount;
  4412. diskNumber++)
  4413. {
  4414. ClusDiskDismountDevice( diskNumber, TRUE );
  4415. }
  4416. #endif
  4417. ExFreePool( ClusDiskRegistryPath.Buffer )
  4418. ArbitrationDone();
  4419. ExDeleteResourceLite(&ClusDiskDeviceListLock);
  4420. WPP_CLEANUP(DriverObject);
  4421. } // ClusDiskUnload
  4422. #endif
  4423. NTSTATUS
  4424. ClusDiskCreate(
  4425. IN PDEVICE_OBJECT DeviceObject,
  4426. IN PIRP Irp
  4427. )
  4428. /*++
  4429. Routine Description:
  4430. This routine services open requests. It establishes
  4431. the driver's existance by returning status success.
  4432. Arguments:
  4433. DeviceObject - Context for the activity.
  4434. Irp - The device control argument block.
  4435. Return Value:
  4436. NT Status
  4437. --*/
  4438. {
  4439. PCLUS_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  4440. PCLUS_DEVICE_EXTENSION physicalExtension =
  4441. deviceExtension->PhysicalDevice->DeviceExtension;
  4442. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  4443. LARGE_INTEGER waitTime;
  4444. NTSTATUS status;
  4445. CDLOGF(CREATE,"ClusDiskCreate: Entry DO %p", DeviceObject);
  4446. status = AcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  4447. if ( !NT_SUCCESS(status) ) {
  4448. ClusDiskPrint((
  4449. 1,
  4450. "[ClusDisk] ClusDiskCreate: AcquireRemoveLock for %p failed %08X \n",
  4451. deviceExtension,
  4452. status ));
  4453. Irp->IoStatus.Status = status;
  4454. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4455. return status;
  4456. }
  4457. status = AcquireRemoveLock(&physicalExtension->RemoveLock, Irp);
  4458. if ( !NT_SUCCESS(status) ) {
  4459. ClusDiskPrint((
  4460. 1,
  4461. "[ClusDisk] ClusDiskCreate: AcquireRemoveLock for %p (PD) failed %08X \n",
  4462. physicalExtension,
  4463. status ));
  4464. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  4465. Irp->IoStatus.Status = status;
  4466. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4467. return status;
  4468. }
  4469. //
  4470. // Make sure that the user is not attempting to sneak around the
  4471. // security checks. Make sure that FileObject->RelatedFileObject is
  4472. // NULL and that the FileName length is zero!
  4473. //
  4474. if ( irpStack->FileObject->RelatedFileObject ||
  4475. irpStack->FileObject->FileName.Length ) {
  4476. ReleaseRemoveLock(&physicalExtension->RemoveLock, Irp);
  4477. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  4478. Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
  4479. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4480. return STATUS_ACCESS_DENIED;
  4481. }
  4482. //
  4483. // if our dev object for partition 0 is offline, clear the
  4484. // FS context. If we've been asked to create a directory file,
  4485. // fail the request.
  4486. //
  4487. if ( physicalExtension->DiskState == DiskOffline ) {
  4488. //
  4489. // [GORN] Why do we do this here?
  4490. // ClusDiskCreate is called when FileObject is created,
  4491. // so nobody has been able to put anything into FsContext field yet.
  4492. //
  4493. CDLOGF(CREATE,"ClusDiskCreate: RefTrack(%p)", irpStack->FileObject->FsContext );
  4494. irpStack->FileObject->FsContext = NULL;
  4495. if ( irpStack->Parameters.Create.Options & FILE_DIRECTORY_FILE ) {
  4496. ReleaseRemoveLock(&physicalExtension->RemoveLock, Irp);
  4497. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  4498. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  4499. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4500. return(STATUS_INVALID_DEVICE_REQUEST);
  4501. }
  4502. }
  4503. CDLOGF(CREATE,"ClusDiskCreate: Exit DO %p", DeviceObject );
  4504. ReleaseRemoveLock(&physicalExtension->RemoveLock, Irp);
  4505. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  4506. Irp->IoStatus.Status = STATUS_SUCCESS;
  4507. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4508. return STATUS_SUCCESS;
  4509. } // ClusDiskCreate
  4510. NTSTATUS
  4511. ClusDiskClose(
  4512. IN PDEVICE_OBJECT DeviceObject,
  4513. IN PIRP Irp
  4514. )
  4515. /*++
  4516. Routine Description:
  4517. This routine services close commands. It destroys the file object
  4518. context.
  4519. Arguments:
  4520. DeviceObject - Pointer to the device object on which the irp was received.
  4521. Irp - The IRP.
  4522. Return Value:
  4523. NT Status
  4524. --*/
  4525. {
  4526. PCLUS_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  4527. PCLUS_DEVICE_EXTENSION physicalExtension =
  4528. deviceExtension->PhysicalDevice->DeviceExtension;
  4529. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  4530. NTSTATUS status;
  4531. status = AcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  4532. if ( !NT_SUCCESS(status) ) {
  4533. ClusDiskPrint((
  4534. 1,
  4535. "[ClusDisk] ClusDiskClose: AcquireRemoveLock for %p failed %08X \n",
  4536. deviceExtension,
  4537. status ));
  4538. Irp->IoStatus.Status = status;
  4539. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4540. return status;
  4541. }
  4542. status = AcquireRemoveLock(&physicalExtension->RemoveLock, Irp);
  4543. if ( !NT_SUCCESS(status) ) {
  4544. ClusDiskPrint((
  4545. 1,
  4546. "[ClusDisk] ClusDiskClose: AcquireRemoveLock for %p (PD) failed %08X \n",
  4547. physicalExtension,
  4548. status ));
  4549. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  4550. Irp->IoStatus.Status = status;
  4551. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4552. return status;
  4553. }
  4554. if ( physicalExtension->DiskState == DiskOffline ) {
  4555. //
  4556. // [GORN] Cleanup cleans the FsContext, by the time
  4557. // we will get here, FsContext should be already NULL
  4558. //
  4559. CDLOGF(CLOSE,"ClusDiskClose: RefTrack %p", irpStack->FileObject->FsContext );
  4560. irpStack->FileObject->FsContext = NULL;
  4561. }
  4562. CDLOGF(CLOSE,"ClusDiskClose DO %p", DeviceObject );
  4563. //
  4564. // Release the RemoveLocks with the FileObject tag, not the IRP.
  4565. //
  4566. ReleaseRemoveLock(&physicalExtension->RemoveLock, Irp);
  4567. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  4568. Irp->IoStatus.Status = STATUS_SUCCESS;
  4569. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4570. return STATUS_SUCCESS;
  4571. } // ClusDiskClose
  4572. VOID
  4573. ClusDiskCompletePendedIrps(
  4574. IN PCLUS_DEVICE_EXTENSION DeviceExtension,
  4575. IN PFILE_OBJECT FileObject OPTIONAL,
  4576. IN ULONG Offline
  4577. )
  4578. /*++
  4579. Routine Description:
  4580. This routine completes all pended irps belonging
  4581. to a FileObject specified. If FileObject is 0, all
  4582. irps pended on the DeviceExtension are completed.
  4583. Arguments:
  4584. DeviceExtension -
  4585. FileObject -
  4586. Offline - if TRUE, set DiskState to Offline
  4587. --*/
  4588. {
  4589. KIRQL irql;
  4590. PIRP irp;
  4591. PLIST_ENTRY listEntry;
  4592. PLIST_ENTRY nextEntry, head;
  4593. CDLOGF(UNPEND, "CompletePendedIrps: Entry DevExt %p FileObject %p",
  4594. DeviceExtension, FileObject );
  4595. if (Offline) {
  4596. PCLUS_DEVICE_EXTENSION physicalDisk = DeviceExtension->PhysicalDevice->DeviceExtension;
  4597. CDLOG( "CompletePendedIrps: StateOffline PhysDevObj %p",
  4598. physicalDisk->DeviceObject);
  4599. ClusDiskPrint(( 3,
  4600. "[ClusDisk] Pending IRPS: Offline device %p \n",
  4601. physicalDisk->DeviceObject ));
  4602. DeviceExtension->DiskState = DiskOffline;
  4603. DeviceExtension->ReserveTimer = 0;
  4604. // physicalDisk->DiskState = DiskOffline;
  4605. OFFLINE_DISK( physicalDisk );
  4606. physicalDisk->ReserveTimer = 0;
  4607. }
  4608. IoAcquireCancelSpinLock( &irql );
  4609. KeAcquireSpinLockAtDpcLevel(&ClusDiskSpinLock);
  4610. head = &DeviceExtension->WaitingIoctls;
  4611. for (listEntry = head->Flink; listEntry != head; listEntry = nextEntry) {
  4612. nextEntry = listEntry->Flink;
  4613. irp = CONTAINING_RECORD( listEntry,
  4614. IRP,
  4615. Tail.Overlay.ListEntry );
  4616. if ( FileObject == NULL ||
  4617. IoGetCurrentIrpStackLocation(irp)->FileObject == FileObject )
  4618. {
  4619. CDLOG( "CompletePendedIrps: CompleteIrp %p", irp );
  4620. RemoveEntryList( listEntry );
  4621. ClusDiskCompletePendingRequest(irp, STATUS_SUCCESS, DeviceExtension);
  4622. }
  4623. }
  4624. head = &DeviceExtension->HoldIO;
  4625. for (listEntry = head->Flink; listEntry != head; listEntry = nextEntry) {
  4626. nextEntry = listEntry->Flink;
  4627. irp = CONTAINING_RECORD( listEntry,
  4628. IRP,
  4629. Tail.Overlay.ListEntry );
  4630. if ( FileObject == NULL ||
  4631. IoGetCurrentIrpStackLocation(irp)->FileObject == FileObject )
  4632. {
  4633. CDLOG( "CompletePendedIrps: AbortIrp %p", irp );
  4634. RemoveEntryList( listEntry );
  4635. ClusDiskCompletePendingRequest(irp, STATUS_REQUEST_ABORTED, DeviceExtension);
  4636. }
  4637. }
  4638. KeReleaseSpinLockFromDpcLevel(&ClusDiskSpinLock);
  4639. IoReleaseCancelSpinLock( irql );
  4640. CDLOGF(UNPEND, "CompletePendedIrps: Exit DevExt %p FileObj %p",
  4641. DeviceExtension, FileObject );
  4642. }
  4643. #if 0
  4644. // 2000/02/05: stevedz - RemoveLocks should resolve this problem.
  4645. //
  4646. // This is a temporary workaround for bug 387113.
  4647. // If we dismount the volume close to the time
  4648. // when resmon is killed. PnP system will deadlock
  4649. // trying to deliver a notification to resmon, though it
  4650. // is already dead.
  4651. //
  4652. // As a workaround we will postpone dismount for a few seconds,
  4653. // hoping that PnP will clean up its listener list by the time
  4654. // we will try to dismount
  4655. //
  4656. NTSTATUS
  4657. ClusDiskDelayedDismountVolumes(
  4658. IN PDEVICE_OBJECT Part0DeviceObject
  4659. )
  4660. {
  4661. LARGE_INTEGER waitTime;
  4662. // Sleep three seconds before attempting a dismount //
  4663. CDLOG( "DelayedDismount: Sleep DevObj %p", Part0DeviceObject );
  4664. waitTime.QuadPart = (ULONGLONG)(3 * -(10000*1000));
  4665. KeDelayExecutionThread( KernelMode, FALSE, &waitTime );
  4666. return ClusDiskDismountVolumes(Part0DeviceObject) ;
  4667. }
  4668. #endif
  4669. NTSTATUS
  4670. ClusDiskCleanup(
  4671. IN PDEVICE_OBJECT DeviceObject,
  4672. IN PIRP Irp
  4673. )
  4674. /*++
  4675. Routine Description:
  4676. This routine services cleanup commands. It deactivates the reservation
  4677. threads on the device object, and takes the device offline.
  4678. Arguments:
  4679. DeviceObject - Pointer to the device object on which the irp was received.
  4680. Irp - The IRP.
  4681. Return Value:
  4682. NT Status
  4683. Notes:
  4684. We don't release the reservations here, since the process may have
  4685. failed and might be restarted. Make the remote system go through full
  4686. arbitration if needed.
  4687. --*/
  4688. {
  4689. NTSTATUS status;
  4690. PCLUS_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  4691. PCLUS_DEVICE_EXTENSION physicalDisk;
  4692. PDEVICE_OBJECT targetDeviceObject;
  4693. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  4694. PWORK_QUEUE_ITEM workItem;
  4695. KIRQL irql;
  4696. BOOLEAN phyDiskRemLockAvail = FALSE;
  4697. CDLOGF(CLEANUP,"ClusDiskCleanup: Entry DO %p", DeviceObject );
  4698. status = AcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  4699. if ( !NT_SUCCESS(status) ) {
  4700. ClusDiskPrint((
  4701. 1,
  4702. "[ClusDisk] ClusDiskCleanup: AcquireRemoveLock for %p failed %08X \n",
  4703. deviceExtension,
  4704. status ));
  4705. Irp->IoStatus.Status = status;
  4706. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4707. return status;
  4708. }
  4709. //
  4710. // Signal all waiting Irp's on the physical device extension.
  4711. //
  4712. ClusDiskCompletePendedIrps(
  4713. deviceExtension,
  4714. irpStack->FileObject,
  4715. /* offline => */ FALSE);
  4716. if ( (deviceExtension->BusType == RootBus) &&
  4717. (irpStack->FileObject->FsContext) ) {
  4718. CDLOG("ClusDiskCleanup: StopReserve DO %p", DeviceObject );
  4719. targetDeviceObject = (PDEVICE_OBJECT)irpStack->FileObject->FsContext;
  4720. irpStack->FileObject->FsContext = NULL;
  4721. physicalDisk = targetDeviceObject->DeviceExtension;
  4722. status = AcquireRemoveLock(&physicalDisk->RemoveLock, Irp);
  4723. if ( !NT_SUCCESS(status) ) {
  4724. ClusDiskPrint((
  4725. 1,
  4726. "[ClusDisk] ClusDiskCleanup: AcquireRemoveLock for %p failed %08X \n",
  4727. physicalDisk,
  4728. status ));
  4729. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  4730. Irp->IoStatus.Status = status;
  4731. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4732. return status;
  4733. }
  4734. phyDiskRemLockAvail = TRUE;
  4735. //
  4736. // 2000/02/05: stevedz - RemoveLocks should resolve this problem.
  4737. //
  4738. // The following "if" only reduces the chances of AV to occur, not
  4739. // eliminates it completely. TargetDeviceObject is zeroed out by our PnP
  4740. // handler when the device is removed
  4741. //
  4742. if (physicalDisk->TargetDeviceObject == NULL) {
  4743. ClusDiskPrint((
  4744. 1,
  4745. "[ClusDisk] Part0 object %p got deleted. Skip the dismount\n", targetDeviceObject));
  4746. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  4747. DisableHaltProcessing( &irql );
  4748. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  4749. goto skip_it;
  4750. }
  4751. ACQUIRE_SHARED( &ClusDiskDeviceListLock );
  4752. #if 0 // Always get volume handles...
  4753. //
  4754. // Capture handles for the volumes before offlining the device
  4755. //
  4756. if ( physicalDisk->DiskState == DiskOnline ) {
  4757. #endif
  4758. ProcessDelayedWorkSynchronous( targetDeviceObject, ClusDiskpOpenFileHandles, NULL );
  4759. #if 0 // Always get volume handles...
  4760. }
  4761. #endif
  4762. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  4763. physicalDisk->ReserveTimer = 0;
  4764. DisableHaltProcessing( &irql );
  4765. ASSERT_RESERVES_STOPPED( physicalDisk );
  4766. // physicalDisk->DiskState = DiskOffline;
  4767. OFFLINE_DISK( physicalDisk );
  4768. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  4769. RELEASE_SHARED( &ClusDiskDeviceListLock );
  4770. ClusDiskPrint(( 3,
  4771. "[ClusDisk] Cleanup: Signature %08X (device %p) now marked offline \n",
  4772. physicalDisk->Signature,
  4773. physicalDisk->DeviceObject ));
  4774. CDLOG( "ClusDiskCleanup: LastWrite %!datetime!",
  4775. physicalDisk->LastWriteTime.QuadPart );
  4776. physicalDisk->ReserveTimer = 0;
  4777. ReleaseScsiDevice( physicalDisk );
  4778. ClusDiskPrint((3,
  4779. "[ClusDisk] Cleanup, stop reservations on signature %lx, disk state %s \n",
  4780. physicalDisk->Signature,
  4781. DiskStateToString(physicalDisk->DiskState) ));
  4782. //
  4783. // We need to release all pended irps immediately,
  4784. // w/o relying on worker thread to do it for us.
  4785. //
  4786. ClusDiskOfflineEntireDisk( targetDeviceObject );
  4787. //
  4788. // We must use a worker item to do this work.
  4789. //
  4790. //status = ClusDiskOfflineDevice( targetDeviceObject );
  4791. if ( !KeReadStateEvent( &physicalDisk->Event ) ) {
  4792. CDLOG("ClusDiskCleanup: WorkerIsStillRunning DO %p", DeviceObject );
  4793. } else {
  4794. workItem = (PWORK_QUEUE_ITEM)ExAllocatePool(NonPagedPool,
  4795. sizeof(WORK_QUEUE_ITEM));
  4796. if ( workItem == NULL ) {
  4797. ClusDiskPrint((1,
  4798. "[ClusDisk] Failed to allocate WorkItem for Disk Cleanup. No cleanup will be performed.\n"));
  4799. } else {
  4800. //
  4801. // Acquire the RemoveLock for the target device object one more time. Since
  4802. // we are queuing a work item, we don't know when the ClusDiskDismountVolumes will
  4803. // run. When it does run, the RemoveLock will be released.
  4804. //
  4805. status = AcquireRemoveLock( &physicalDisk->RemoveLock, physicalDisk);
  4806. if ( !NT_SUCCESS(status) ) {
  4807. ClusDiskPrint((
  4808. 1,
  4809. "[ClusDisk] ClusDiskCleanup: (ClusDiskDismountVolumes) AcquireRemoveLock for %p failed %08X \n",
  4810. deviceExtension,
  4811. status));
  4812. // Skip this device.
  4813. goto skip_it;
  4814. }
  4815. //
  4816. // init this work item
  4817. //
  4818. ExInitializeWorkItem( workItem,
  4819. (PWORKER_THREAD_ROUTINE)ClusDiskDismountVolumes,
  4820. targetDeviceObject );
  4821. KeClearEvent( &physicalDisk->Event );
  4822. ClusDiskPrint((
  4823. 3,
  4824. "[ClusDisk] Cleanup: ClearEvent (%p)\n", &physicalDisk->Event));
  4825. //
  4826. // Queue work item and start worker thread
  4827. //
  4828. // Keep the device object around
  4829. ObReferenceObject( targetDeviceObject );
  4830. //
  4831. // 2000/02/05: stevedz - RemoveLocks should resolve this problem.
  4832. //
  4833. // bug 387113 causes a deadlock when we are trying to dismount.
  4834. // Until it is fixed, we need to make dismount occur a few seconds
  4835. // later after resmon is killed.
  4836. // When it is fixed, please replace DelayedWorkQueue with
  4837. // CriticalWorkQueue and ClusDiskDelayedDismountVolumes
  4838. // with ClusDiskDismountVolumes
  4839. ExQueueWorkItem(workItem,
  4840. DelayedWorkQueue );
  4841. }
  4842. }
  4843. skip_it:
  4844. CDLOG( "RootCtl: DecRef DO %p", targetDeviceObject );
  4845. ObDereferenceObject( targetDeviceObject );
  4846. }
  4847. CDLOGF(CLEANUP,"ClusDiskCleanup: Exit DO %p", DeviceObject );
  4848. if (phyDiskRemLockAvail) {
  4849. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  4850. }
  4851. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  4852. Irp->IoStatus.Status = STATUS_SUCCESS;
  4853. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4854. return(STATUS_SUCCESS);
  4855. } // ClusDiskCleanup
  4856. NTSTATUS
  4857. ClusDiskOfflineEntireDisk(
  4858. IN PDEVICE_OBJECT Part0DeviceObject
  4859. )
  4860. /*++
  4861. Routine Description:
  4862. Complete all pended irps on the disk and all its volumes and
  4863. sets the state to offline.
  4864. Arguments:
  4865. Part0DeviceObject - the device to take offline.
  4866. Return Value:
  4867. NTSTATUS for the request.
  4868. --*/
  4869. {
  4870. PCLUS_DEVICE_EXTENSION Part0Extension = Part0DeviceObject->DeviceExtension;
  4871. PCLUS_DEVICE_EXTENSION deviceExtension;
  4872. PDEVICE_OBJECT deviceObject;
  4873. CDLOG( "OfflineEntireDisk: Entry DO %p", Part0DeviceObject );
  4874. ASSERT(Part0DeviceObject == Part0Extension->PhysicalDevice);
  4875. //
  4876. // Signal all waiting Irp's on the physical device extension.
  4877. //
  4878. ClusDiskCompletePendedIrps(
  4879. Part0Extension,
  4880. /* FileObject => */ NULL,
  4881. /* offline => */ TRUE);
  4882. //
  4883. // We also need to complete all the irps on all the volumes belonging to this disk
  4884. //
  4885. ACQUIRE_SHARED( &ClusDiskDeviceListLock );
  4886. //
  4887. // Get the first DeviceObject in the driver list
  4888. //
  4889. deviceObject = Part0DeviceObject->DriverObject->DeviceObject;
  4890. // First release all pended irps and set the volume state to offline
  4891. while ( deviceObject ) {
  4892. deviceExtension = deviceObject->DeviceExtension;
  4893. if ( deviceExtension->PhysicalDevice == Part0DeviceObject &&
  4894. deviceObject != Part0DeviceObject) // not P0
  4895. {
  4896. ClusDiskCompletePendedIrps(
  4897. deviceExtension,
  4898. /* FileObject => */ NULL,
  4899. /* Offline => */ TRUE);
  4900. }
  4901. deviceObject = deviceObject->NextDevice;
  4902. }
  4903. RELEASE_SHARED( &ClusDiskDeviceListLock );
  4904. CDLOG( "OfflineEntireDisk: Exit DO %p", Part0DeviceObject );
  4905. return STATUS_SUCCESS;
  4906. } // ClusDiskOfflineEntireDisk //
  4907. NTSTATUS
  4908. ClusDiskDismountVolumes(
  4909. IN PDEVICE_OBJECT Part0DeviceObject
  4910. )
  4911. /*++
  4912. Routine Description:
  4913. Dismount the file systems on a all volumes belonging to Part0DO.
  4914. The RemoveLock for Part0DeviceObject must be acquired before this
  4915. routine runs.
  4916. Arguments:
  4917. Part0DeviceObject - the device to take offline.
  4918. Return Value:
  4919. NTSTATUS for the request.
  4920. --*/
  4921. {
  4922. PCLUS_DEVICE_EXTENSION Part0Extension = Part0DeviceObject->DeviceExtension;
  4923. REPLACE_CONTEXT context;
  4924. NTSTATUS status;
  4925. CDLOG( "ClusDiskDismountVolumes: Entry %p", Part0DeviceObject );
  4926. //
  4927. // We assume that DeviceObject is P0
  4928. //
  4929. ASSERT(Part0DeviceObject == Part0Extension->PhysicalDevice);
  4930. context.DeviceExtension = Part0Extension;
  4931. context.NewValue = NULL; // clear the field
  4932. context.Flags = DO_DISMOUNT | RELEASE_REMOVE_LOCK;
  4933. ProcessDelayedWorkSynchronous( Part0DeviceObject, ClusDiskpReplaceHandleArray, &context );
  4934. KeSetEvent( &Part0Extension->Event, 0, FALSE );
  4935. ClusDiskPrint((
  4936. 3,
  4937. "[ClusDisk] DismountVolumes: SetEvent (%p)\n", &Part0Extension->Event));
  4938. //
  4939. // Now the device object/device extension can go away
  4940. //
  4941. ObDereferenceObject( Part0DeviceObject );
  4942. // We released the RemoveLock in ClusDiskpReplaceHandleArray.
  4943. //
  4944. // ReleaseRemoveLock(&Part0Extension->RemoveLock, Part0Extension);
  4945. CDLOG( "ClusDiskDismountVolumes: Exit DO %p", Part0DeviceObject );
  4946. return STATUS_SUCCESS;
  4947. } // ClusDiskDismountVolumes
  4948. NTSTATUS
  4949. ClusDiskDismountDevice(
  4950. IN ULONG DiskNumber,
  4951. IN BOOLEAN ForceDismount
  4952. )
  4953. /*++
  4954. Routine Description:
  4955. Dismount the file systems on the specified disk
  4956. Arguments:
  4957. DiskNumber - number of the disk on which to dismount all FSs.
  4958. ForceDismount - TRUE if dismount should always take place (ignore VPB)
  4959. Return Value:
  4960. NTSTATUS for the request.
  4961. --*/
  4962. {
  4963. NTSTATUS status;
  4964. ULONG partIndex;
  4965. UCHAR letter;
  4966. WCHAR partitionNameBuffer[MAX_PARTITION_NAME_LENGTH];
  4967. PDRIVE_LAYOUT_INFORMATION driveLayoutInfo;
  4968. PPARTITION_INFORMATION partitionInfo;
  4969. UNICODE_STRING targetDeviceName;
  4970. PDEVICE_OBJECT targetDevice = NULL;
  4971. KIRQL irql;
  4972. CDLOG( "ClusDiskDismountDevice: Entry DiskNumber %d", DiskNumber );
  4973. ClusDiskPrint(( 3,
  4974. "[ClusDisk] DismountDevice: disknum %08X \n",
  4975. DiskNumber ));
  4976. irql = KeGetCurrentIrql();
  4977. if ( PASSIVE_LEVEL != irql ) {
  4978. ClusDiskPrint(( 1,
  4979. "[ClusDisk] ClusDiskDismountDevice: Invalid IRQL %d \n", irql ));
  4980. CDLOG( "DismountDevice: Invalid IRQL %d ", irql );
  4981. ASSERT( FALSE );
  4982. status = STATUS_UNSUCCESSFUL;
  4983. goto FnExit;
  4984. }
  4985. //
  4986. // Dismount the file system on each partition.
  4987. //
  4988. status = ClusDiskGetTargetDevice(DiskNumber,
  4989. 0,
  4990. &targetDevice,
  4991. &targetDeviceName,
  4992. &driveLayoutInfo,
  4993. NULL,
  4994. FALSE );
  4995. if ( targetDeviceName.Buffer ) {
  4996. RtlFreeUnicodeString(&targetDeviceName);
  4997. }
  4998. if ( !NT_SUCCESS(status) ) {
  4999. goto FnExit;
  5000. }
  5001. //
  5002. // Dismount the partition zero device object.
  5003. //
  5004. //status = DismountPartition( DiskNumber, 0 );
  5005. if ( driveLayoutInfo != NULL ) {
  5006. for ( partIndex = 0;
  5007. partIndex < driveLayoutInfo->PartitionCount;
  5008. partIndex++ )
  5009. {
  5010. partitionInfo = &driveLayoutInfo->PartitionEntry[partIndex];
  5011. //
  5012. // Make sure this is a valid partition.
  5013. //
  5014. if ( !partitionInfo->RecognizedPartition ||
  5015. partitionInfo->PartitionNumber == 0 )
  5016. {
  5017. continue;
  5018. }
  5019. //
  5020. // Create device name for the physical disk.
  5021. //
  5022. swprintf(partitionNameBuffer,
  5023. DEVICE_PARTITION_NAME,
  5024. DiskNumber,
  5025. partitionInfo->PartitionNumber);
  5026. WCSLEN_ASSERT( partitionNameBuffer );
  5027. DEREFERENCE_OBJECT( targetDevice );
  5028. status = ClusDiskGetTargetDevice( DiskNumber,
  5029. partitionInfo->PartitionNumber,
  5030. &targetDevice,
  5031. &targetDeviceName,
  5032. NULL,
  5033. NULL,
  5034. FALSE );
  5035. if ( targetDeviceName.Buffer ) {
  5036. RtlFreeUnicodeString(&targetDeviceName);
  5037. }
  5038. if ( ForceDismount || ( targetDevice && targetDevice->Vpb &&
  5039. (targetDevice->Vpb->Flags & VPB_MOUNTED) ) ) {
  5040. status = DismountPartition( targetDevice,
  5041. DiskNumber,
  5042. partitionInfo->PartitionNumber);
  5043. }
  5044. }
  5045. ExFreePool(driveLayoutInfo);
  5046. status = STATUS_SUCCESS;
  5047. } else {
  5048. //
  5049. // This should not have failed!
  5050. //
  5051. ClusDiskPrint((1,
  5052. "[ClusDisk] DismountDevice: Failed to read partition info for \\Device\\Harddisk%u.\n",
  5053. DiskNumber));
  5054. status = STATUS_DEVICE_OFF_LINE;
  5055. }
  5056. FnExit:
  5057. DEREFERENCE_OBJECT( targetDevice );
  5058. CDLOG( "ClusDiskDismountDevice: Exit DiskNumber %d status %!status!",
  5059. DiskNumber,
  5060. status );
  5061. //
  5062. // The target device should not have any reservations.
  5063. //
  5064. return(status);
  5065. } // ClusDiskDismountDevice
  5066. NTSTATUS
  5067. ClusDiskReAttachDevice(
  5068. PDEVICE_OBJECT DeviceObject
  5069. )
  5070. /*++
  5071. Routine Description:
  5072. Re-attach to a disk device with the signature specified if it is detached.
  5073. Arguments:
  5074. DeviceObject - the device object for Partition0.
  5075. Return Value:
  5076. NT Status
  5077. Notes:
  5078. Dismount the file system if we do perform an attach.
  5079. --*/
  5080. {
  5081. NTSTATUS status;
  5082. PCLUS_DEVICE_EXTENSION physicalExtension;
  5083. PCLUS_DEVICE_EXTENSION deviceExtension;
  5084. UNICODE_STRING signatureName;
  5085. PDRIVE_LAYOUT_INFORMATION driveLayoutInfo;
  5086. PPARTITION_INFORMATION partitionInfo;
  5087. PDEVICE_OBJECT deviceObject;
  5088. ULONG partIndex;
  5089. WCHAR deviceNameBuffer[MAX_PARTITION_NAME_LENGTH];
  5090. UCHAR letter;
  5091. KIRQL irql;
  5092. CDLOG( "ClusDiskReAttachDevice: Entry DO %p", DeviceObject );
  5093. physicalExtension = DeviceObject->DeviceExtension;
  5094. ClusDiskPrint((3,
  5095. "[ClusDisk] ReAttach entry: signature %08X, disk state %s \n",
  5096. physicalExtension->Signature,
  5097. DiskStateToString( physicalExtension->DiskState ) ));
  5098. if ( !physicalExtension->Detached ) {
  5099. CDLOG( "ClusDiskReAttachDevice_Exit2 Detached == FALSE" );
  5100. ClusDiskPrint((3,
  5101. "[ClusDisk] ReAttach: signature %08X, PerformReserves = %s, ReserveTimer = %u \n",
  5102. physicalExtension->Signature,
  5103. BoolToString( physicalExtension->PerformReserves ),
  5104. physicalExtension->ReserveTimer ));
  5105. return(STATUS_SUCCESS);
  5106. }
  5107. //
  5108. // Dismount the file systems!
  5109. //
  5110. status = ClusDiskDismountDevice( physicalExtension->DiskNumber, TRUE );
  5111. //
  5112. // Now add the signature to the signatures list!
  5113. //
  5114. //
  5115. // Allocate buffer for Signatures registry key. So we can add
  5116. // the signature.
  5117. //
  5118. status = ClusDiskInitRegistryString(
  5119. &signatureName,
  5120. CLUSDISK_SIGNATURE_KEYNAME,
  5121. sizeof(CLUSDISK_SIGNATURE_KEYNAME)
  5122. );
  5123. if ( NT_SUCCESS(status) ) {
  5124. //
  5125. // Create the signature key under \Parameters\Signatures.
  5126. //
  5127. status = ClusDiskAddSignature(
  5128. &signatureName,
  5129. physicalExtension->Signature,
  5130. FALSE
  5131. );
  5132. //
  5133. // Now write the disk name.
  5134. //
  5135. ClusDiskWriteDiskInfo( physicalExtension->Signature,
  5136. physicalExtension->DiskNumber,
  5137. CLUSDISK_SIGNATURE_KEYNAME
  5138. );
  5139. ExFreePool( signatureName.Buffer );
  5140. }
  5141. //
  5142. // Now remove the signature from the available list!
  5143. //
  5144. //
  5145. // Allocate buffer for AvailableDisks registry key. So we can
  5146. // delete the disk signature.
  5147. //
  5148. status = ClusDiskInitRegistryString(
  5149. &signatureName,
  5150. CLUSDISK_AVAILABLE_DISKS_KEYNAME,
  5151. sizeof(CLUSDISK_AVAILABLE_DISKS_KEYNAME)
  5152. );
  5153. if ( NT_SUCCESS(status) ) {
  5154. //
  5155. // Delete the signature key under \Parameters\AvailableDisks.
  5156. //
  5157. status = ClusDiskDeleteSignature(
  5158. &signatureName,
  5159. physicalExtension->Signature
  5160. );
  5161. ExFreePool( signatureName.Buffer );
  5162. }
  5163. //
  5164. // Find all related device objects and mark them as being attached now,
  5165. // and offline.
  5166. //
  5167. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  5168. deviceObject = DeviceObject->DriverObject->DeviceObject;
  5169. while ( deviceObject ) {
  5170. deviceExtension = deviceObject->DeviceExtension;
  5171. if ( deviceExtension->Signature == physicalExtension->Signature ) {
  5172. ClusDiskPrint((3,
  5173. "[ClusDisk] ReAttach, marking signature %08X offline, old state %s \n",
  5174. deviceExtension->Signature,
  5175. DiskStateToString( deviceExtension->DiskState ) ));
  5176. deviceExtension->Detached = FALSE;
  5177. deviceExtension->ReserveTimer = 0;
  5178. deviceExtension->ReserveFailure = 0;
  5179. // [stevedz 11/06/2000] Fix NTFS corruption.
  5180. // Change to mark disk offline, rather than online (as the comments above
  5181. // originally indicated). Marking the disk offline was commented out and
  5182. // the code marked the disk online here. Don't understand why we would
  5183. // want to mark it online with no reserves running.
  5184. // deviceExtension->DiskState = DiskOffline;
  5185. OFFLINE_DISK( deviceExtension );
  5186. }
  5187. CDLOG( "ClusDiskReAttachDevice: RelatedObject %p diskstate %!diskstate!",
  5188. deviceObject,
  5189. deviceExtension->DiskState );
  5190. deviceObject = deviceObject->NextDevice;
  5191. }
  5192. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  5193. #if 0
  5194. //
  5195. // set each drive letter to point to the appropriate
  5196. // ClusDisk<X>Part<Y> device
  5197. //
  5198. //
  5199. driveLayoutInfo = ClusDiskGetPartitionInfo( physicalExtension );
  5200. if ( driveLayoutInfo != NULL ) {
  5201. ASSERT( driveLayoutInfo->Signature == physicalExtension->Signature );
  5202. for ( partIndex = 0;
  5203. partIndex < driveLayoutInfo->PartitionCount;
  5204. partIndex++ )
  5205. {
  5206. partitionInfo = &driveLayoutInfo->PartitionEntry[partIndex];
  5207. //
  5208. // First make sure this is a valid partition.
  5209. //
  5210. if ( !partitionInfo->RecognizedPartition ||
  5211. partitionInfo->PartitionNumber == 0 )
  5212. {
  5213. continue;
  5214. }
  5215. //
  5216. // Create the device name for the device.
  5217. //
  5218. swprintf(deviceNameBuffer,
  5219. DEVICE_PARTITION_NAME,
  5220. physicalExtension->DiskNumber,
  5221. partitionInfo->PartitionNumber);
  5222. WCSLEN_ASSERT( deviceNameBuffer );
  5223. }
  5224. ExFreePool( driveLayoutInfo );
  5225. } else {
  5226. CDLOG( "ClusDiskReAttachDevice: FailedToReadPartitionInfo" );
  5227. }
  5228. #endif
  5229. CDLOG( "ClusDiskReAttachDevice: Exit status %!status!", status );
  5230. return(status);
  5231. } // ClusDiskReAttachDevice
  5232. NTSTATUS
  5233. ClusDiskTryAttachDevice(
  5234. ULONG Signature,
  5235. ULONG NextDisk,
  5236. PDRIVER_OBJECT DriverObject
  5237. )
  5238. /*++
  5239. Routine Description:
  5240. Attach to a disk device with the signature specified.
  5241. Arguments:
  5242. Signature - the signature for the device to attach to.
  5243. NextDisk - the start disk number.
  5244. DriverObject - the driver object for our driver.
  5245. Return Value:
  5246. NT Status
  5247. Notes:
  5248. Dismount the file system for the given device - if it is mounted.
  5249. --*/
  5250. {
  5251. NTSTATUS ntStatus;
  5252. BOOLEAN stopProcessing = FALSE;
  5253. CDLOG( "TryAttachDevice: Entry Sig %08x DO %p NextDisk %d",
  5254. Signature,
  5255. DriverObject,
  5256. NextDisk );
  5257. //
  5258. // First just try to attach to the device with no bus resets.
  5259. //
  5260. ntStatus = ClusDiskAttachDevice(
  5261. Signature,
  5262. NextDisk,
  5263. DriverObject,
  5264. FALSE,
  5265. &stopProcessing );
  5266. if ( NT_SUCCESS(ntStatus) || stopProcessing ) {
  5267. CDLOG( "TryAttachDevice: FirstTrySuccess" );
  5268. goto exit_gracefully;
  5269. }
  5270. //
  5271. // Second, try to attach after reset all busses at once.
  5272. //
  5273. ResetScsiBusses();
  5274. ntStatus = ClusDiskAttachDevice(
  5275. Signature,
  5276. NextDisk,
  5277. DriverObject,
  5278. FALSE,
  5279. &stopProcessing );
  5280. if ( NT_SUCCESS(ntStatus) || stopProcessing ) {
  5281. CDLOG( "TryAttachDevice: SecondTrySuccess" );
  5282. goto exit_gracefully;
  5283. }
  5284. //
  5285. // Lastly, try to attach with a bus reset after each failure.
  5286. //
  5287. ntStatus = ClusDiskAttachDevice(
  5288. Signature,
  5289. NextDisk,
  5290. DriverObject,
  5291. TRUE,
  5292. &stopProcessing );
  5293. exit_gracefully:
  5294. CDLOG( "TryAttachDevice: Exit sig %08x => %!status!",
  5295. Signature,
  5296. ntStatus );
  5297. return ntStatus;
  5298. } // ClusDiskTryAttachDevice
  5299. NTSTATUS
  5300. ClusDiskAttachDevice(
  5301. ULONG Signature,
  5302. ULONG NextDisk,
  5303. PDRIVER_OBJECT DriverObject,
  5304. BOOLEAN Reset,
  5305. BOOLEAN *StopProcessing
  5306. )
  5307. /*++
  5308. Routine Description:
  5309. Attach to a disk device with the signature specified.
  5310. Arguments:
  5311. Signature - the signature for the device to attach to.
  5312. NextDisk - the start disk number.
  5313. DriverObject - the driver object for our driver.
  5314. Reset - Indicates whether bus reset should be performed on each I/O
  5315. StopProcessing - Indicates whether to stop trying to attach. If FALSE,
  5316. we will try a bus reset between attach attempts.
  5317. Return Value:
  5318. NT Status
  5319. Notes:
  5320. Dismount the file system for the given device - if it is mounted.
  5321. --*/
  5322. {
  5323. NTSTATUS status;
  5324. NTSTATUS finalStatus = STATUS_NO_SUCH_DEVICE;
  5325. UNICODE_STRING targetDeviceName;
  5326. ULONG diskNumber;
  5327. ULONG partIndex;
  5328. PCONFIGURATION_INFORMATION configurationInformation;
  5329. PDEVICE_OBJECT attachedTargetDevice;
  5330. PDEVICE_OBJECT physicalDevice;
  5331. PDEVICE_OBJECT deviceObject;
  5332. PCLUS_DEVICE_EXTENSION deviceExtension;
  5333. PCLUS_DEVICE_EXTENSION zeroExtension;
  5334. PDRIVE_LAYOUT_INFORMATION driveLayoutInfo;
  5335. PPARTITION_INFORMATION partitionInfo;
  5336. UNICODE_STRING signatureName;
  5337. SCSI_ADDRESS scsiAddress;
  5338. ULONG busType;
  5339. PDEVICE_OBJECT targetDevice = NULL;
  5340. UNICODE_STRING clusdiskDeviceName;
  5341. WCHAR clusdiskDeviceBuffer[MAX_CLUSDISK_DEVICE_NAME_LENGTH];
  5342. UCHAR driveLetter;
  5343. KIRQL irql;
  5344. CDLOG( "ClusDiskAttachDevice: Entry sig %08x nextdisk %d reset %!bool!",
  5345. Signature,
  5346. NextDisk,
  5347. Reset );
  5348. ClusDiskPrint(( 3,
  5349. "[ClusDisk] AttachDevice: Trying to attach to signature %08X reset = %u \n",
  5350. Signature,
  5351. Reset
  5352. ));
  5353. *StopProcessing = FALSE;
  5354. //
  5355. // If we're already attached, then return success.
  5356. //
  5357. if ( AttachedDevice( Signature, &physicalDevice ) ) {
  5358. CDLOG( "ClusDiskAttachDevice: AlreadyAttached DO %p", physicalDevice );
  5359. deviceExtension = physicalDevice->DeviceExtension;
  5360. if ( !deviceExtension ) {
  5361. return STATUS_DEVICE_REMOVED;
  5362. }
  5363. status = AcquireRemoveLock( &deviceExtension->RemoveLock, deviceExtension );
  5364. if ( !NT_SUCCESS(status) ) {
  5365. ClusDiskPrint((
  5366. 1,
  5367. "[ClusDisk] ClusDiskAttachDevice: AcquireRemoveLock for %p failed %08X \n",
  5368. deviceExtension,
  5369. status));
  5370. CDLOG( "ClusDiskAttachDevice: AcquireRemoveLock for %p failed %08X", deviceExtension, status );
  5371. return status;
  5372. }
  5373. //
  5374. // If any of the special file counts are nonzero, don't allow the attach.
  5375. //
  5376. if ( deviceExtension->PagingPathCount ||
  5377. deviceExtension->HibernationPathCount ||
  5378. deviceExtension->DumpPathCount ) {
  5379. CDLOG( "ClusDiskAttachDevice: Exit, special file count nonzero %08X %08X %08X",
  5380. deviceExtension->PagingPathCount,
  5381. deviceExtension->HibernationPathCount,
  5382. deviceExtension->DumpPathCount );
  5383. ClusDiskPrint(( 1,
  5384. "[ClusDisk] AttachDevice: Exit, special file count nonzero %08X %08X %08X \n",
  5385. deviceExtension->PagingPathCount,
  5386. deviceExtension->HibernationPathCount,
  5387. deviceExtension->DumpPathCount ));
  5388. *StopProcessing = TRUE;
  5389. ReleaseRemoveLock( &deviceExtension->RemoveLock, deviceExtension );
  5390. return STATUS_INVALID_PARAMETER;
  5391. }
  5392. status = ClusDiskReAttachDevice( physicalDevice );
  5393. CDLOG( "ClusDiskAttachDevice: Exit1 %!status!", status );
  5394. ReleaseRemoveLock( &deviceExtension->RemoveLock, deviceExtension );
  5395. return status;
  5396. }
  5397. //
  5398. // Make sure the signature is NOT for the system device!
  5399. //
  5400. if ( SystemDiskSignature == Signature ) {
  5401. CDLOG( "ClusDiskAttachDevice: Exit2 SystemDiskSig %08x",
  5402. SystemDiskSignature );
  5403. *StopProcessing = TRUE;
  5404. return(STATUS_INVALID_PARAMETER);
  5405. }
  5406. //
  5407. //
  5408. // Get the configuration information.
  5409. //
  5410. configurationInformation = IoGetConfigurationInformation();
  5411. //
  5412. // Find ALL disk devices. We will attempt to read the partition info
  5413. // without attaching. We might already be attached and not know it.
  5414. // So once we've performed a successful read, if the device is attached
  5415. // we will know it by checking again.
  5416. //
  5417. for (diskNumber = NextDisk;
  5418. diskNumber < configurationInformation->DiskCount;
  5419. diskNumber++) {
  5420. DEREFERENCE_OBJECT( targetDevice );
  5421. //
  5422. // Create device name for the physical disk.
  5423. //
  5424. status = ClusDiskGetTargetDevice( diskNumber,
  5425. 0,
  5426. &targetDevice,
  5427. &targetDeviceName,
  5428. &driveLayoutInfo,
  5429. &scsiAddress,
  5430. Reset );
  5431. if ( !NT_SUCCESS(status) ) {
  5432. continue;
  5433. }
  5434. RtlFreeUnicodeString(&targetDeviceName);
  5435. if ( driveLayoutInfo == NULL ) {
  5436. continue;
  5437. }
  5438. if ( Signature != driveLayoutInfo->Signature ) {
  5439. ExFreePool( driveLayoutInfo );
  5440. continue;
  5441. }
  5442. busType = ScsiBus; // because of GetTargetDevice above!
  5443. //
  5444. // Create ClusDisk device object for partition 0, if we are not
  5445. // already attached!
  5446. //
  5447. if ( ClusDiskAttached( targetDevice, diskNumber ) ) {
  5448. ClusDiskPrint((3,
  5449. "[ClusDisk] AttachDevice: We were already attached to device %p (disk %u), simply mark as attached.\n",
  5450. physicalDevice,
  5451. diskNumber));
  5452. CDLOG( "ClusDiskAttachDevice: Previously attached to device %p (disk %u) signature %08X ",
  5453. physicalDevice,
  5454. diskNumber,
  5455. Signature );
  5456. physicalDevice = targetDevice;
  5457. deviceExtension = physicalDevice->DeviceExtension;
  5458. zeroExtension = deviceExtension;
  5459. deviceExtension->Detached = FALSE;
  5460. //
  5461. // We offline all the volumes later. For now, just mark the disk offline.
  5462. //
  5463. deviceExtension->DiskState = DiskOffline;
  5464. //
  5465. // Seen instances where the device extension signature is zero, but the entry
  5466. // in the ClusDiskDeviceList contains a valid signature. This causes a problem
  5467. // if there is a detach and then we try to attach to the same device later.
  5468. //
  5469. // The issue is that the devExt->Sig can be zero if the drive layout couldn't
  5470. // be read. When we attach and the device object was previously created,
  5471. // we don't update the devExt->Sig. When we detach, ClusDiskDetachDevice
  5472. // tries to find all the devices with devExt->Sig matching the detached
  5473. // device. When a matching signature is found, devExt->Detached is set
  5474. // to TRUE. Since some devExt->Sigs are zero (if drive layout couldn't be read
  5475. // at the time the device object was created), they don't match the detaching
  5476. // signature, and the devExt->Detached flag is still set to FALSE.
  5477. //
  5478. // Then when trying to attach to the same device later, ClusDiskAttachDevice
  5479. // can see that we still have an entry in ClusDiskDeviceList, and then
  5480. // ClusDiskReAttachDevice is called. However, since the devExt->Detached flag
  5481. // is still FALSE, ClusDiskReAttachDevice assumes we are still attached and
  5482. // doesn't do anything except return success.
  5483. //
  5484. //
  5485. // If Signature we are attaching to does not equal the devExt->Sig, write an
  5486. // error to the WMI log, and update the devExt->Sig with the attaching Signature.
  5487. //
  5488. if ( Signature != deviceExtension->Signature ) {
  5489. CDLOG( "ClusDiskAttachDevice: PreviouslyAttachedSignatureMismatch sig %08x devExtSig %08x",
  5490. Signature,
  5491. deviceExtension->Signature );
  5492. ASSERT( deviceExtension->Signature == 0 );
  5493. deviceExtension->Signature = Signature;
  5494. }
  5495. } else {
  5496. //
  5497. // Now create a Partition zero device object to attach to
  5498. //
  5499. swprintf(clusdiskDeviceBuffer,
  5500. CLUSDISK_DEVICE_NAME,
  5501. diskNumber,
  5502. 0);
  5503. RtlInitUnicodeString( &clusdiskDeviceName, clusdiskDeviceBuffer );
  5504. status = IoCreateDevice(DriverObject,
  5505. sizeof(CLUS_DEVICE_EXTENSION),
  5506. &clusdiskDeviceName,
  5507. FILE_DEVICE_DISK,
  5508. 0,
  5509. FALSE,
  5510. &physicalDevice);
  5511. if ( !NT_SUCCESS(status) ) {
  5512. ExFreePool( driveLayoutInfo );
  5513. ClusDiskPrint((
  5514. 1,
  5515. "[ClusDisk] AttachDevice: Failed to create device for Drive%u. %08X\n",
  5516. diskNumber,
  5517. status));
  5518. continue;
  5519. }
  5520. CDLOG( "ClusDiskAttachDevice: IoCreateDeviceP0 DO %p DiskNumber %d",
  5521. physicalDevice, diskNumber );
  5522. physicalDevice->Flags |= DO_DIRECT_IO;
  5523. physicalDevice->Flags &= ~DO_DEVICE_INITIALIZING;
  5524. //
  5525. // Point device extension back at device object and remember
  5526. // the disk number.
  5527. //
  5528. deviceExtension = physicalDevice->DeviceExtension;
  5529. zeroExtension = deviceExtension;
  5530. deviceExtension->DeviceObject = physicalDevice;
  5531. deviceExtension->DiskNumber = diskNumber;
  5532. deviceExtension->LastPartitionNumber = 0;
  5533. deviceExtension->DriverObject = DriverObject;
  5534. deviceExtension->Signature = Signature;
  5535. deviceExtension->AttachValid = TRUE;
  5536. deviceExtension->ReserveTimer = 0;
  5537. deviceExtension->PerformReserves = TRUE;
  5538. deviceExtension->ReserveFailure = 0;
  5539. deviceExtension->Detached = TRUE;
  5540. deviceExtension->OfflinePending = FALSE;
  5541. deviceExtension->ScsiAddress = scsiAddress;
  5542. deviceExtension->BusType = busType;
  5543. InitializeListHead( &deviceExtension->WaitingIoctls );
  5544. InitializeListHead( &deviceExtension->HoldIO );
  5545. IoInitializeRemoveLock( &deviceExtension->RemoveLock, CLUSDISK_ALLOC_TAG, 0, 0 );
  5546. //
  5547. // Signal the worker thread running event.
  5548. //
  5549. KeInitializeEvent( &deviceExtension->Event, NotificationEvent, TRUE );
  5550. ExInitializeWorkItem(&deviceExtension->WorkItem,
  5551. (PWORKER_THREAD_ROUTINE)ClusDiskReservationWorker,
  5552. (PVOID)deviceExtension );
  5553. // Always set state to offline.
  5554. //
  5555. // We offline all the volumes later. For now, just mark the disk offline.
  5556. //
  5557. deviceExtension->DiskState = DiskOffline;
  5558. KeInitializeEvent( &deviceExtension->PagingPathCountEvent,
  5559. NotificationEvent, TRUE );
  5560. deviceExtension->PagingPathCount = 0;
  5561. deviceExtension->HibernationPathCount = 0;
  5562. deviceExtension->DumpPathCount = 0;
  5563. ExInitializeResourceLite( &deviceExtension->DriveLayoutLock );
  5564. //
  5565. // This is the physical device object.
  5566. //
  5567. ObReferenceObject( physicalDevice );
  5568. deviceExtension->PhysicalDevice = physicalDevice;
  5569. //
  5570. // Attach to partition0. This call links the newly created
  5571. // device to the target device, returning the target device object.
  5572. // We may not want to stay attached for long... depending on
  5573. // whether this is a device we're interested in.
  5574. //
  5575. //
  5576. // 2000/02/05: stevedz - Bug in FTDISK [note that we currently don't support FTDISK].
  5577. // There seems to be a bug in FTDISK, where the DO_DEVICE_INITIALIZING gets
  5578. // stuck when a new device is found during a RESCAN. We will unconditionally
  5579. // clear this bit for any device we are about to attach to. We could check
  5580. // if the device is an FTDISK device... but that might be work.
  5581. //
  5582. targetDevice->Flags &= ~DO_DEVICE_INITIALIZING;
  5583. attachedTargetDevice = IoAttachDeviceToDeviceStack(physicalDevice,
  5584. targetDevice);
  5585. ASSERT( attachedTargetDevice == targetDevice );
  5586. if ( attachedTargetDevice == NULL ) {
  5587. ClusDiskPrint((1,
  5588. "[ClusDisk] AttachDevice: Failed to attach to device Drive%u.\n",
  5589. diskNumber));
  5590. ExFreePool( driveLayoutInfo );
  5591. IoDeleteDevice(physicalDevice);
  5592. continue;
  5593. }
  5594. deviceExtension->TargetDeviceObject = attachedTargetDevice;
  5595. deviceExtension->Detached = FALSE;
  5596. #if 0 // Can't have a FS on partition 0
  5597. if ( targetDevice->Vpb ) {
  5598. if ( targetDevice->Vpb->Flags & VPB_MOUNTED ) {
  5599. status = DismountPartition( targetDevice, diskNumber, 0 );
  5600. if ( !NT_SUCCESS( status )) {
  5601. ClusDiskPrint((1,
  5602. "[ClusDisk] AttachDevice: dismount of %u/0 failed %08X\n",
  5603. diskNumber, status));
  5604. }
  5605. }
  5606. }
  5607. #endif
  5608. }
  5609. CDLOG( "ClusDiskInfo *** PDO %p DevExt %p DiskNum %d Signature %X ***",
  5610. physicalDevice,
  5611. deviceExtension,
  5612. deviceExtension->DiskNumber,
  5613. deviceExtension->Signature );
  5614. //
  5615. // make sure we haven't attached to a file system. if so, something
  5616. // whacky has occurred and consequently, we back what we just did
  5617. //
  5618. if (deviceExtension->TargetDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) {
  5619. ClusDiskPrint((3,
  5620. "[ClusDisk] AttachDevice: We incorrectly attached our device %p to file system device %p \n",
  5621. physicalDevice,
  5622. deviceExtension->TargetDeviceObject));
  5623. status = STATUS_INSUFFICIENT_RESOURCES;
  5624. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  5625. deviceExtension->Detached = TRUE;
  5626. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  5627. IoDetachDevice( deviceExtension->TargetDeviceObject );
  5628. IoDeleteDevice( physicalDevice );
  5629. continue;
  5630. }
  5631. //
  5632. // Propagate driver's alignment requirements and power flags.
  5633. //
  5634. physicalDevice->AlignmentRequirement =
  5635. deviceExtension->TargetDeviceObject->AlignmentRequirement;
  5636. physicalDevice->SectorSize =
  5637. deviceExtension->TargetDeviceObject->SectorSize;
  5638. //
  5639. // The storage stack explicitly requires DO_POWER_PAGABLE to be
  5640. // set in all filter drivers *unless* DO_POWER_INRUSH is set.
  5641. // this is true even if the attached device doesn't set DO_POWER_PAGABLE.
  5642. //
  5643. if ( deviceExtension->TargetDeviceObject->Flags & DO_POWER_INRUSH) {
  5644. physicalDevice->Flags |= DO_POWER_INRUSH;
  5645. } else {
  5646. physicalDevice->Flags |= DO_POWER_PAGABLE;
  5647. }
  5648. //
  5649. // Add this device to our list of attached devices.
  5650. //
  5651. AddAttachedDevice( Signature, physicalDevice );
  5652. //
  5653. // Add this bus to our bus list.
  5654. //
  5655. switch ( deviceExtension->BusType ) {
  5656. case ScsiBus:
  5657. ClusDiskAddScsiBusList( deviceExtension );
  5658. break;
  5659. default:
  5660. break;
  5661. }
  5662. //
  5663. // Add the signature to the signatures list!
  5664. //
  5665. //
  5666. // Allocate buffer for Signatures registry key. So we can add
  5667. // the signature.
  5668. //
  5669. status = ClusDiskInitRegistryString(
  5670. &signatureName,
  5671. CLUSDISK_SIGNATURE_KEYNAME,
  5672. sizeof(CLUSDISK_SIGNATURE_KEYNAME)
  5673. );
  5674. if ( NT_SUCCESS(status) ) {
  5675. //
  5676. // Create the signature key under \Parameters\Signatures.
  5677. //
  5678. status = ClusDiskAddSignature(
  5679. &signatureName,
  5680. Signature,
  5681. FALSE
  5682. );
  5683. //
  5684. // Now write the disk name.
  5685. //
  5686. ClusDiskWriteDiskInfo( Signature,
  5687. deviceExtension->DiskNumber,
  5688. CLUSDISK_SIGNATURE_KEYNAME
  5689. );
  5690. ExFreePool( signatureName.Buffer );
  5691. }
  5692. //
  5693. // Remove the signature from the available list!
  5694. //
  5695. //
  5696. // Allocate buffer for AvailableDisks registry key. So we can
  5697. // delete the disk signature.
  5698. //
  5699. status = ClusDiskInitRegistryString(
  5700. &signatureName,
  5701. CLUSDISK_AVAILABLE_DISKS_KEYNAME,
  5702. sizeof(CLUSDISK_AVAILABLE_DISKS_KEYNAME)
  5703. );
  5704. if ( NT_SUCCESS(status) ) {
  5705. //
  5706. // Delete the signature key under \Parameters\AvailableDisks.
  5707. //
  5708. status = ClusDiskDeleteSignature(
  5709. &signatureName,
  5710. Signature
  5711. );
  5712. ExFreePool( signatureName.Buffer );
  5713. }
  5714. //
  5715. // Offline all volumes on this disk.
  5716. //
  5717. OFFLINE_DISK( zeroExtension );
  5718. //
  5719. // Dismount all volumes on this disk.
  5720. //
  5721. ClusDiskDismountDevice( diskNumber, TRUE );
  5722. //
  5723. // Now enumerate the partitions on this device.
  5724. //
  5725. for (partIndex = 0;
  5726. partIndex < driveLayoutInfo->PartitionCount;
  5727. partIndex++)
  5728. {
  5729. partitionInfo = &driveLayoutInfo->PartitionEntry[partIndex];
  5730. //
  5731. // Make sure that there really is a partition here.
  5732. //
  5733. if ( !partitionInfo->RecognizedPartition ||
  5734. partitionInfo->PartitionNumber == 0 )
  5735. {
  5736. continue;
  5737. }
  5738. DEREFERENCE_OBJECT( targetDevice );
  5739. status = ClusDiskGetTargetDevice(diskNumber,
  5740. partitionInfo->PartitionNumber,
  5741. &targetDevice,
  5742. &targetDeviceName,
  5743. NULL,
  5744. NULL,
  5745. FALSE );
  5746. if ( !NT_SUCCESS(status) ) {
  5747. ClusDiskPrint((1,
  5748. "[ClusDisk] AttachDevice: couldn't attach to disk %u/%u %08X\n",
  5749. diskNumber,
  5750. partitionInfo->PartitionNumber,
  5751. status));
  5752. continue;
  5753. }
  5754. //
  5755. // Make sure we are not attaching to a file system device
  5756. //
  5757. if (deviceExtension->TargetDeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) {
  5758. ClusDiskPrint((3,
  5759. "[ClusDisk] AttachDevice: We incorrectly attached our partition device %p to file system device %p \n",
  5760. physicalDevice,
  5761. deviceExtension->TargetDeviceObject));
  5762. RtlFreeUnicodeString( &targetDeviceName );
  5763. continue;
  5764. }
  5765. ClusDiskPrint((3,
  5766. "[ClusDisk] AttachDevice: Attach to partition %u/%u\n",
  5767. diskNumber,
  5768. partitionInfo->PartitionNumber));
  5769. //
  5770. // Create device object for this partition.
  5771. //
  5772. swprintf(clusdiskDeviceBuffer,
  5773. CLUSDISK_DEVICE_NAME,
  5774. diskNumber,
  5775. partitionInfo->PartitionNumber);
  5776. WCSLEN_ASSERT( clusdiskDeviceBuffer );
  5777. RtlInitUnicodeString( &clusdiskDeviceName, clusdiskDeviceBuffer );
  5778. status = IoCreateDevice(DriverObject,
  5779. sizeof(CLUS_DEVICE_EXTENSION),
  5780. &clusdiskDeviceName,
  5781. FILE_DEVICE_DISK,
  5782. 0,
  5783. FALSE,
  5784. &deviceObject);
  5785. if ( !NT_SUCCESS(status) ) {
  5786. ClusDiskPrint((3,
  5787. "[ClusDisk] AttachDevice: Failed to create device %wZ, %08X\n",
  5788. &clusdiskDeviceName,
  5789. status));
  5790. RtlFreeUnicodeString(&targetDeviceName);
  5791. continue;
  5792. }
  5793. deviceObject->Flags |= DO_DIRECT_IO;
  5794. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  5795. //
  5796. // Point device extension back at device object and
  5797. // remember the disk number.
  5798. //
  5799. deviceExtension = deviceObject->DeviceExtension;
  5800. deviceExtension->DeviceObject = deviceObject;
  5801. deviceExtension->DiskNumber = diskNumber;
  5802. deviceExtension->DriverObject = DriverObject;
  5803. deviceExtension->BusType = zeroExtension->BusType;
  5804. //
  5805. // Always set disk state to offline. These are volume objects.
  5806. //
  5807. deviceExtension->DiskState = DiskOffline;
  5808. deviceExtension->PerformReserves = FALSE;
  5809. deviceExtension->ReserveFailure = 0;
  5810. deviceExtension->Signature = Signature;
  5811. deviceExtension->AttachValid = TRUE;
  5812. deviceExtension->Detached = TRUE;
  5813. deviceExtension->OfflinePending = FALSE;
  5814. deviceExtension->ScsiAddress = scsiAddress;
  5815. InitializeListHead( &deviceExtension->WaitingIoctls );
  5816. InitializeListHead( &deviceExtension->HoldIO );
  5817. IoInitializeRemoveLock( &deviceExtension->RemoveLock, CLUSDISK_ALLOC_TAG, 0, 0 );
  5818. CDLOG( "ClusDiskAttachDevice: IoCreateDevice D0 %p State %!diskstate! diskNo %d partNo %d",
  5819. deviceObject,
  5820. deviceExtension->DiskState,
  5821. diskNumber,
  5822. partitionInfo->PartitionNumber );
  5823. //
  5824. // Signal the worker thread running event.
  5825. //
  5826. KeInitializeEvent( &deviceExtension->Event, NotificationEvent, TRUE );
  5827. //
  5828. // Maintain the last partition number created. Put it in
  5829. // each extension just to initialize the field.
  5830. //
  5831. deviceExtension->LastPartitionNumber = max(deviceExtension->LastPartitionNumber,
  5832. partitionInfo->PartitionNumber);
  5833. zeroExtension->LastPartitionNumber = deviceExtension->LastPartitionNumber;
  5834. KeInitializeEvent( &deviceExtension->PagingPathCountEvent,
  5835. NotificationEvent, TRUE );
  5836. deviceExtension->PagingPathCount = 0;
  5837. deviceExtension->HibernationPathCount = 0;
  5838. deviceExtension->DumpPathCount = 0;
  5839. ExInitializeResourceLite( &deviceExtension->DriveLayoutLock );
  5840. //
  5841. // Store pointer to physical device.
  5842. //
  5843. ObReferenceObject( physicalDevice );
  5844. deviceExtension->PhysicalDevice = physicalDevice;
  5845. //
  5846. // First dismount any mounted file systems.
  5847. //
  5848. if ( targetDevice->Vpb &&
  5849. (targetDevice->Vpb->Flags & VPB_MOUNTED) ) {
  5850. status = DismountPartition( targetDevice,
  5851. diskNumber,
  5852. partitionInfo->PartitionNumber);
  5853. if ( !NT_SUCCESS( status )) {
  5854. ClusDiskPrint((1,
  5855. "[ClusDisk] AttachDevice: Dismount of %u/%u failed %08X\n",
  5856. diskNumber, partitionInfo->PartitionNumber, status));
  5857. }
  5858. }
  5859. //
  5860. // Attach to the partition. This call links the newly created
  5861. // device to the target device, returning the target device object.
  5862. //
  5863. ClusDiskPrint((3,
  5864. "[ClusDisk] AttachDevice: attaching to device %wZ\n",
  5865. &targetDeviceName ));
  5866. attachedTargetDevice = IoAttachDeviceToDeviceStack(deviceObject,
  5867. targetDevice);
  5868. ASSERT( attachedTargetDevice == targetDevice );
  5869. if ( attachedTargetDevice == NULL ) {
  5870. ClusDiskPrint((1,
  5871. "[ClusDisk] AttachDevice: Failed to attach to device %wZ\n",
  5872. &targetDeviceName));
  5873. RtlFreeUnicodeString(&targetDeviceName);
  5874. IoDeleteDevice(deviceObject);
  5875. continue;
  5876. }
  5877. deviceExtension->TargetDeviceObject = attachedTargetDevice;
  5878. deviceExtension->Detached = FALSE;
  5879. RtlFreeUnicodeString(&targetDeviceName);
  5880. //
  5881. // Call ourself back to make sure ft acts appropriately.
  5882. //
  5883. // [GN] No need to do it.
  5884. //
  5885. // CluCallBackDiskState( deviceObject, deviceExtension->DiskState );
  5886. //
  5887. // Propagate driver's alignment requirements and power flags.
  5888. //
  5889. deviceObject->AlignmentRequirement =
  5890. deviceExtension->TargetDeviceObject->AlignmentRequirement;
  5891. deviceObject->SectorSize =
  5892. deviceExtension->TargetDeviceObject->SectorSize;
  5893. //
  5894. // The storage stack explicitly requires DO_POWER_PAGABLE to be
  5895. // set in all filter drivers *unless* DO_POWER_INRUSH is set.
  5896. // this is true even if the attached device doesn't set DO_POWER_PAGABLE.
  5897. //
  5898. if ( deviceExtension->TargetDeviceObject->Flags & DO_POWER_INRUSH) {
  5899. deviceObject->Flags |= DO_POWER_INRUSH;
  5900. } else {
  5901. deviceObject->Flags |= DO_POWER_PAGABLE;
  5902. }
  5903. //
  5904. // Check if this device is already mounted or is a file system
  5905. // device. The file systems should have already been dismounted!
  5906. //
  5907. if ( targetDevice->Vpb ) {
  5908. if ( targetDevice->Vpb->Flags & VPB_MOUNTED ) {
  5909. ClusDiskPrint((3,
  5910. "[ClusDisk] AttachDevice: Dismounting disk %u partition %u (devobj %p)\n",
  5911. diskNumber, partitionInfo->PartitionNumber,
  5912. targetDevice));
  5913. status = DismountPartition( targetDevice,
  5914. diskNumber,
  5915. partitionInfo->PartitionNumber);
  5916. if ( !NT_SUCCESS( status )) {
  5917. ClusDiskPrint((1,
  5918. "[ClusDisk] AttachDevice: Dismount disk %u partition %u failed %08X\n",
  5919. diskNumber, partitionInfo->PartitionNumber, status));
  5920. }
  5921. }
  5922. }
  5923. }
  5924. ExFreePool( driveLayoutInfo );
  5925. finalStatus = STATUS_SUCCESS;
  5926. break;
  5927. }
  5928. DEREFERENCE_OBJECT( targetDevice );
  5929. CDLOG( "ClusDiskAttachDevice: Exit status %!status!", finalStatus );
  5930. return(finalStatus);
  5931. } // ClusDiskAttachDevice
  5932. NTSTATUS
  5933. ClusDiskDetachDevice(
  5934. ULONG Signature,
  5935. PDRIVER_OBJECT DriverObject
  5936. )
  5937. /*++
  5938. Routine Description:
  5939. Detach from a disk device with the signature specified.
  5940. Arguments:
  5941. Signature - the signature for the device to detach from.
  5942. DriverObject - the driver object for our device.
  5943. Return Value:
  5944. NT Status
  5945. Notes:
  5946. We have to be careful with the partition0 devices. RAW doesn't support
  5947. dismount, so it is not clear that we can actually delete those device
  5948. objects, since they could be cached by FileSystems like RAW!
  5949. --*/
  5950. {
  5951. NTSTATUS status;
  5952. PDEVICE_LIST_ENTRY deviceEntry;
  5953. PCLUS_DEVICE_EXTENSION deviceExtension;
  5954. PCLUS_DEVICE_EXTENSION physicalDeviceExtension;
  5955. PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
  5956. BOOLEAN found = FALSE;
  5957. UNICODE_STRING signatureName;
  5958. UNICODE_STRING availableName;
  5959. KIRQL irql;
  5960. PCLUS_DEVICE_EXTENSION foundExtension = NULL;
  5961. PLIST_ENTRY listEntry;
  5962. PIRP irp;
  5963. //
  5964. // Find our device entry.
  5965. //
  5966. // 2000/02/05: stevedz - added synchronization.
  5967. ACQUIRE_SHARED( &ClusDiskDeviceListLock );
  5968. deviceEntry = ClusDiskDeviceList;
  5969. while ( deviceEntry ) {
  5970. if ( deviceEntry->Signature == Signature ) {
  5971. break;
  5972. }
  5973. deviceEntry = deviceEntry->Next;
  5974. }
  5975. if ( (deviceEntry == NULL) ||
  5976. !deviceEntry->Attached ) {
  5977. if ( deviceEntry ) {
  5978. ClusDiskPrint((
  5979. 1,
  5980. "[ClusDisk] DetachDevice: Failed to detach signature = %lx, attached = %lx\n",
  5981. Signature, deviceEntry->Attached ));
  5982. } else {
  5983. ClusDiskPrint((
  5984. 1,
  5985. "[ClusDisk] DetachDevice: Failed to detach signature = %lx\n",
  5986. Signature ));
  5987. }
  5988. RELEASE_SHARED( &ClusDiskDeviceListLock );
  5989. goto DeleteDiskSignature;
  5990. }
  5991. //
  5992. // Now find all devices that we are attached to with this signature.
  5993. //
  5994. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  5995. while ( deviceObject ) {
  5996. deviceExtension = deviceObject->DeviceExtension;
  5997. //
  5998. // Only disable devices with our signature, but
  5999. // Don't remove the root device...
  6000. //
  6001. if ( (deviceExtension->Signature == Signature) ) {
  6002. //
  6003. // Remember one found extension - it doesn't matter which one.
  6004. //
  6005. foundExtension = deviceExtension;
  6006. //
  6007. // Detach from the target device. This only requires marking
  6008. // the device object as detached!
  6009. //
  6010. deviceExtension->Detached = TRUE;
  6011. //
  6012. // We want to make sure reserves are stopped because the disk is
  6013. // not going to be controlled by the cluster any longer.
  6014. //
  6015. ASSERT_RESERVES_STOPPED( deviceExtension );
  6016. //
  6017. // Make this device available again.
  6018. //
  6019. // deviceExtension->DiskState = DiskOnline;
  6020. ONLINE_DISK( deviceExtension );
  6021. ClusDiskPrint(( 3,
  6022. "[ClusDisk] DetachDevice: Marking signature = %lx online \n",
  6023. Signature ));
  6024. found = TRUE;
  6025. }
  6026. deviceObject = deviceObject->NextDevice;
  6027. }
  6028. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  6029. RELEASE_SHARED( &ClusDiskDeviceListLock );
  6030. //
  6031. // Delete all drive letters for this disk signature, and assign letters
  6032. // to the correct device name.
  6033. //
  6034. if ( foundExtension ) {
  6035. physicalDeviceExtension = foundExtension->PhysicalDevice->DeviceExtension;
  6036. //
  6037. // Signal all waiting Irp's on the physical device extension.
  6038. //
  6039. IoAcquireCancelSpinLock( &irql );
  6040. KeAcquireSpinLockAtDpcLevel(&ClusDiskSpinLock);
  6041. while ( !IsListEmpty(&physicalDeviceExtension->WaitingIoctls) ) {
  6042. listEntry = RemoveHeadList(&physicalDeviceExtension->WaitingIoctls);
  6043. irp = CONTAINING_RECORD( listEntry,
  6044. IRP,
  6045. Tail.Overlay.ListEntry );
  6046. ClusDiskCompletePendingRequest(irp, STATUS_SUCCESS, physicalDeviceExtension);
  6047. }
  6048. while ( !IsListEmpty(&foundExtension->HoldIO) ) {
  6049. listEntry = RemoveHeadList(&foundExtension->HoldIO);
  6050. irp = CONTAINING_RECORD( listEntry,
  6051. IRP,
  6052. Tail.Overlay.ListEntry );
  6053. ClusDiskCompletePendingRequest(irp, STATUS_REQUEST_ABORTED, foundExtension);
  6054. }
  6055. KeReleaseSpinLockFromDpcLevel(&ClusDiskSpinLock);
  6056. IoReleaseCancelSpinLock( irql );
  6057. }
  6058. DeleteDiskSignature:
  6059. //
  6060. // Allocate buffer for signatures registry key.
  6061. //
  6062. status = ClusDiskInitRegistryString(
  6063. &signatureName,
  6064. CLUSDISK_SIGNATURE_KEYNAME,
  6065. sizeof(CLUSDISK_SIGNATURE_KEYNAME)
  6066. );
  6067. if ( !NT_SUCCESS(status) ) {
  6068. return(status);
  6069. }
  6070. //
  6071. // Allocate buffer for our list of available signatures,
  6072. // and form the subkey string name.
  6073. //
  6074. status = ClusDiskInitRegistryString(
  6075. &availableName,
  6076. CLUSDISK_AVAILABLE_DISKS_KEYNAME,
  6077. sizeof(CLUSDISK_AVAILABLE_DISKS_KEYNAME)
  6078. );
  6079. if ( !NT_SUCCESS(status) ) {
  6080. ExFreePool( signatureName.Buffer );
  6081. return(STATUS_INSUFFICIENT_RESOURCES);
  6082. }
  6083. //
  6084. // Always - remove signature from signature list.
  6085. //
  6086. status = ClusDiskDeleteSignature(
  6087. &signatureName,
  6088. Signature
  6089. );
  6090. //
  6091. // Conditionally add signature to available list.
  6092. //
  6093. // always add signature to available list. This will handle the case
  6094. // where the disk signature was not found by this system in a previous
  6095. // scan of the disks.
  6096. //
  6097. found = TRUE;
  6098. if ( found ) {
  6099. ClusDiskPrint((3,
  6100. "[ClusDisk] DetachDevice: adding disk %08X to available disks list\n",
  6101. Signature));
  6102. status = ClusDiskAddSignature(
  6103. &availableName,
  6104. Signature,
  6105. TRUE
  6106. );
  6107. } else {
  6108. ClusDiskPrint((
  6109. 3,
  6110. "[ClusDisk] DetachDevice: No devices were detached!\n" ));
  6111. }
  6112. ExFreePool( signatureName.Buffer );
  6113. ExFreePool( availableName.Buffer );
  6114. return(STATUS_SUCCESS);
  6115. } // ClusDiskDetachDevice
  6116. NTSTATUS
  6117. ClusDiskRead(
  6118. IN PDEVICE_OBJECT DeviceObject,
  6119. IN PIRP Irp
  6120. )
  6121. /*++
  6122. Routine Description:
  6123. This is the driver entry point for read and write requests
  6124. to disks to which the clusdisk driver has attached.
  6125. This driver collects statistics and then sets a completion
  6126. routine so that it can collect additional information when
  6127. the request completes. Then it calls the next driver below
  6128. it.
  6129. Arguments:
  6130. DeviceObject
  6131. Irp
  6132. Return Value:
  6133. NTSTATUS
  6134. --*/
  6135. {
  6136. PCLUS_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  6137. PCLUS_DEVICE_EXTENSION physicalDisk =
  6138. deviceExtension->PhysicalDevice->DeviceExtension;
  6139. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  6140. PDEVICE_OBJECT targetDeviceObject = deviceExtension->TargetDeviceObject;
  6141. KIRQL irql;
  6142. NTSTATUS status;
  6143. status = AcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  6144. if (!NT_SUCCESS(status)) {
  6145. ClusDiskPrint((
  6146. 1,
  6147. "[ClusDisk] ClusDiskRead: AcquireRemoveLock for %p failed %08X \n",
  6148. deviceExtension,
  6149. status));
  6150. Irp->IoStatus.Status = status;
  6151. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6152. return status;
  6153. }
  6154. status = AcquireRemoveLock(&physicalDisk->RemoveLock, Irp);
  6155. if (!NT_SUCCESS(status)) {
  6156. ClusDiskPrint((
  6157. 1,
  6158. "[ClusDisk] ClusDiskRead: AcquireRemoveLock for %p (PD) failed %08X \n",
  6159. physicalDisk,
  6160. status));
  6161. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  6162. Irp->IoStatus.Status = status;
  6163. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6164. return status;
  6165. }
  6166. //
  6167. // Return error if device is our root device.
  6168. //
  6169. if ( deviceExtension->BusType == RootBus ) {
  6170. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  6171. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  6172. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  6173. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6174. return(STATUS_INVALID_DEVICE_REQUEST);
  6175. }
  6176. //
  6177. // Return error if disk is not Online (or Stalled).
  6178. // ReclaimInProgress means we are trying to create the volume objects
  6179. // and reads should pass through (but not writes).
  6180. //
  6181. if ( (physicalDisk->DiskState != DiskOnline) &&
  6182. (physicalDisk->DiskState != DiskStalled) )
  6183. {
  6184. CDLOG( "ClusDiskRead(%p): Irp %p Reject len %d offset %I64x",
  6185. DeviceObject,
  6186. Irp,
  6187. currentIrpStack->Parameters.Read.Length,
  6188. currentIrpStack->Parameters.Read.ByteOffset.QuadPart
  6189. );
  6190. ClusDiskPrint((
  6191. 3,
  6192. "[ClusDisk] ClusDiskRead: ReadReject IRP %p for signature %p (%p) (PD) \n",
  6193. Irp,
  6194. physicalDisk->Signature,
  6195. physicalDisk));
  6196. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  6197. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  6198. Irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE;
  6199. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6200. return(STATUS_DEVICE_OFF_LINE);
  6201. }
  6202. CDLOGF(READ,"ClusDiskRead(%p): Irp %p Read len %d offset %I64x",
  6203. DeviceObject,
  6204. Irp,
  6205. currentIrpStack->Parameters.Read.Length,
  6206. currentIrpStack->Parameters.Read.ByteOffset.QuadPart );
  6207. //
  6208. // Until we start doing something in the completion routine, just
  6209. // skip this driver. In the future, we might want to report errors
  6210. // back to the cluster software... but that could get tricky, since some
  6211. // requests should fail, but that is expected.
  6212. //
  6213. #if 0
  6214. //
  6215. // Copy current stack to next stack.
  6216. //
  6217. IoCopyCurrentIrpStackLocationToNext( Irp );
  6218. //
  6219. // Set completion routine callback.
  6220. //
  6221. IoSetCompletionRoutine(Irp,
  6222. ClusDiskIoCompletion,
  6223. NULL, // Completion context
  6224. TRUE, // Invoke on success
  6225. TRUE, // Invoke on error
  6226. TRUE); // Invoke on cancel
  6227. #else
  6228. //
  6229. // Set current stack back one.
  6230. //
  6231. IoSkipCurrentIrpStackLocation( Irp );
  6232. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  6233. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  6234. #endif
  6235. //
  6236. // Return the results of the call to the disk driver.
  6237. //
  6238. return IoCallDriver(targetDeviceObject,
  6239. Irp);
  6240. } // ClusDiskRead
  6241. NTSTATUS
  6242. ClusDiskWrite(
  6243. IN PDEVICE_OBJECT DeviceObject,
  6244. IN PIRP Irp
  6245. )
  6246. /*++
  6247. Routine Description:
  6248. This is the driver entry point for read and write requests
  6249. to disks to which the clusdisk driver has attached.
  6250. This driver collects statistics and then sets a completion
  6251. routine so that it can collect additional information when
  6252. the request completes. Then it calls the next driver below
  6253. it.
  6254. Arguments:
  6255. DeviceObject
  6256. Irp
  6257. Return Value:
  6258. NTSTATUS
  6259. --*/
  6260. {
  6261. PCLUS_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  6262. PCLUS_DEVICE_EXTENSION physicalDisk =
  6263. deviceExtension->PhysicalDevice->DeviceExtension;
  6264. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  6265. PDEVICE_OBJECT targetDeviceObject = deviceExtension->TargetDeviceObject;
  6266. KIRQL irql;
  6267. NTSTATUS status;
  6268. status = AcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  6269. if ( !NT_SUCCESS(status) ) {
  6270. ClusDiskPrint((
  6271. 1,
  6272. "[ClusDisk] ClusDiskWrite: AcquireRemoveLock for %p failed %08X \n",
  6273. deviceExtension,
  6274. status));
  6275. Irp->IoStatus.Status = status;
  6276. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6277. return status;
  6278. }
  6279. status = AcquireRemoveLock(&physicalDisk->RemoveLock, Irp);
  6280. if ( !NT_SUCCESS(status) ) {
  6281. ClusDiskPrint((
  6282. 1,
  6283. "[ClusDisk] ClusDiskWrite: AcquireRemoveLock for %p (PD) failed %08X \n",
  6284. physicalDisk,
  6285. status));
  6286. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  6287. Irp->IoStatus.Status = status;
  6288. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6289. return status;
  6290. }
  6291. //
  6292. // Return error if device is our root device.
  6293. //
  6294. if ( deviceExtension->BusType == RootBus ) {
  6295. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  6296. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  6297. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  6298. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6299. return(STATUS_INVALID_DEVICE_REQUEST);
  6300. }
  6301. //
  6302. // Hold the I/O request if we are stalled.
  6303. // First check for hint - i.e. with no lock held.
  6304. //
  6305. if ( deviceExtension->DiskState == DiskStalled ) {
  6306. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  6307. //
  6308. // Check again, with lock held - this one is valid!
  6309. //
  6310. if ( deviceExtension->DiskState == DiskStalled ) {
  6311. CDLOG( "ClusDiskWrite(%p): HoldIo irp %p", DeviceObject, Irp );
  6312. ClusDiskPrint((1,"[ClusDisk] HoldIO - pending IRP %p, target %p, Q: %p \n",
  6313. Irp, targetDeviceObject, &deviceExtension->HoldIO ));
  6314. IoMarkIrpPending( Irp );
  6315. InsertTailList( &deviceExtension->HoldIO,
  6316. &Irp->Tail.Overlay.ListEntry );
  6317. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  6318. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  6319. IoAcquireCancelSpinLock( &irql );
  6320. if (Irp->Cancel) {
  6321. IoReleaseCancelSpinLock( irql );
  6322. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  6323. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  6324. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  6325. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  6326. Irp->IoStatus.Status = STATUS_CANCELLED;
  6327. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6328. return STATUS_CANCELLED;
  6329. } else {
  6330. IoSetCancelRoutine(Irp, ClusDiskIrpCancel);
  6331. }
  6332. IoReleaseCancelSpinLock( irql );
  6333. //
  6334. // We don't release the RemoveLock here as it will be
  6335. // done when the IRP is removed from the queue.
  6336. //
  6337. return(STATUS_PENDING);
  6338. }
  6339. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  6340. }
  6341. //
  6342. // Return error if disk is not Online.
  6343. //
  6344. if ( physicalDisk->DiskState != DiskOnline ) {
  6345. CDLOG( "ClusDiskWrite(%p) Reject irp %p", DeviceObject, Irp );
  6346. ClusDiskPrint((
  6347. 3,
  6348. "[ClusDisk] ClusDiskWrite: WriteReject IRP %p for signature %p (%p) (PD) \n",
  6349. Irp,
  6350. physicalDisk->Signature,
  6351. physicalDisk));
  6352. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  6353. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  6354. Irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE;
  6355. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6356. return(STATUS_DEVICE_OFF_LINE);
  6357. }
  6358. //
  6359. // Trace writes to the first few sectors
  6360. //
  6361. CDLOGF(WRITE, "ClusDiskWrite(%p) Irp %p Write len %d offset %I64x",
  6362. DeviceObject,
  6363. Irp,
  6364. currentIrpStack->Parameters.Write.Length,
  6365. currentIrpStack->Parameters.Write.ByteOffset.QuadPart );
  6366. KeQuerySystemTime( &physicalDisk->LastWriteTime );
  6367. //
  6368. // Until we start doing something in the completion routine, just
  6369. // skip this driver. In the future, we might want to report errors
  6370. // back to the cluster software... but that could get tricky, since some
  6371. // requests should fail, but that is expected.
  6372. //
  6373. #if 0
  6374. //
  6375. // Copy current stack to next stack.
  6376. //
  6377. IoCopyCurrentIrpStackLocationToNext( Irp );
  6378. //
  6379. // Set completion routine callback.
  6380. //
  6381. IoSetCompletionRoutine(Irp,
  6382. ClusDiskIoCompletion,
  6383. NULL, // Completion context
  6384. TRUE, // Invoke on success
  6385. TRUE, // Invoke on error
  6386. TRUE); // Invoke on cancel
  6387. #else
  6388. //
  6389. // Set current stack back one.
  6390. //
  6391. IoSkipCurrentIrpStackLocation( Irp );
  6392. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  6393. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  6394. #endif
  6395. //
  6396. // Return the results of the call to the disk driver.
  6397. //
  6398. return IoCallDriver(targetDeviceObject,
  6399. Irp);
  6400. } // ClusDiskWrite
  6401. NTSTATUS
  6402. ClusDiskIoCompletion(
  6403. IN PDEVICE_OBJECT DeviceObject,
  6404. IN PIRP Irp,
  6405. IN PVOID Context
  6406. )
  6407. /*++
  6408. Routine Description:
  6409. This routine will get control from the system at the completion of an IRP.
  6410. It will calculate the difference between the time the IRP was started
  6411. and the current time, and decrement the queue depth.
  6412. Arguments:
  6413. DeviceObject - for the IRP.
  6414. Irp - The I/O request that just completed.
  6415. Context - Not used.
  6416. Return Value:
  6417. The IRP status.
  6418. --*/
  6419. {
  6420. PCLUS_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  6421. PCLUS_DEVICE_EXTENSION physicalDisk = deviceExtension->PhysicalDevice->DeviceExtension;
  6422. UNREFERENCED_PARAMETER(Context);
  6423. CDLOGF(WRITE, "ClusDiskIoCompletion: CompletedIrp DevObj %p Irp %p",
  6424. DeviceObject,
  6425. Irp );
  6426. if ( physicalDisk->DiskState != DiskOnline ) {
  6427. CDLOGF(WRITE,"ClusDiskIoCompletion: CompletedIrpNotOnline DevObj %p Irp %p %!diskstate!",
  6428. DeviceObject,
  6429. Irp,
  6430. physicalDisk->DiskState );
  6431. CDLOG( "ClusDiskIoCompletion: CompletedIrpNotOnline2 DevObj %p Irp %p %!diskstate!",
  6432. DeviceObject,
  6433. Irp,
  6434. physicalDisk->DiskState );
  6435. }
  6436. ReleaseRemoveLock( &deviceExtension->RemoveLock, Irp );
  6437. ReleaseRemoveLock( &physicalDisk->RemoveLock, Irp );
  6438. if (Irp->PendingReturned) {
  6439. IoMarkIrpPending(Irp);
  6440. }
  6441. return STATUS_SUCCESS;
  6442. } // ClusDiskIoCompletion
  6443. NTSTATUS
  6444. ClusDiskUpdateDriveLayout(
  6445. IN PDEVICE_OBJECT PhysicalDeviceObject,
  6446. IN PIRP Irp
  6447. )
  6448. /*++
  6449. Routine Description:
  6450. This routine is called after an IOCTL to set drive layout completes.
  6451. It attempts to attach to each partition in the system. If it fails
  6452. then it is assumed that clusdisk has already attached. After
  6453. the attach the new device extension is set up to point to the
  6454. device extension representing the physical disk. There are no
  6455. data items or other pointers that need to be cleaned up on a
  6456. per partition basis.
  6457. Arguments:
  6458. PhysicalDeviceObject - Pointer to device object for the disk just changed.
  6459. Irp - IRP involved.
  6460. Return Value:
  6461. NT Status
  6462. --*/
  6463. {
  6464. PCLUS_DEVICE_EXTENSION physicalExtension = PhysicalDeviceObject->DeviceExtension;
  6465. ULONG partitionNumber = physicalExtension->LastPartitionNumber;
  6466. PDEVICE_OBJECT targetObject;
  6467. PDEVICE_OBJECT deviceObject;
  6468. PCLUS_DEVICE_EXTENSION deviceExtension;
  6469. WCHAR ntDeviceName[MAX_PARTITION_NAME_LENGTH];
  6470. STRING ntString;
  6471. UNICODE_STRING ntUnicodeString;
  6472. PFILE_OBJECT fileObject;
  6473. NTSTATUS status;
  6474. KIRQL irql;
  6475. //
  6476. // Attach to any new partitions created by the set layout call.
  6477. //
  6478. do {
  6479. //
  6480. // Get first/next partition. Already attached to the disk,
  6481. // otherwise control would not have been passed to this driver
  6482. // on the device I/O control.
  6483. //
  6484. partitionNumber++;
  6485. //
  6486. // Create unicode NT device name.
  6487. //
  6488. swprintf(ntDeviceName,
  6489. DEVICE_PARTITION_NAME,
  6490. physicalExtension->DiskNumber,
  6491. partitionNumber);
  6492. WCSLEN_ASSERT( ntDeviceName );
  6493. RtlInitUnicodeString(&ntUnicodeString, ntDeviceName);
  6494. //
  6495. // Get target device object.
  6496. //
  6497. status = IoGetDeviceObjectPointer(&ntUnicodeString,
  6498. FILE_READ_ATTRIBUTES,
  6499. &fileObject,
  6500. &targetObject);
  6501. //
  6502. // If this fails then it is because there is no such device
  6503. // which signals completion.
  6504. //
  6505. if ( !NT_SUCCESS(status) ) {
  6506. break;
  6507. }
  6508. //
  6509. // Dereference file object as these are the rules.
  6510. //
  6511. ObDereferenceObject(fileObject);
  6512. //
  6513. // Check if this device is already mounted.
  6514. //
  6515. if ( (targetObject->Vpb &&
  6516. (targetObject->Vpb->Flags & VPB_MOUNTED)) ) {
  6517. //
  6518. // Assume this device has already been attached.
  6519. //
  6520. continue;
  6521. }
  6522. //
  6523. // Create device object for this partition.
  6524. //
  6525. status = IoCreateDevice(physicalExtension->DriverObject,
  6526. sizeof(CLUS_DEVICE_EXTENSION),
  6527. NULL, // XXXX
  6528. FILE_DEVICE_DISK,
  6529. 0,
  6530. FALSE,
  6531. &deviceObject);
  6532. if ( !NT_SUCCESS(status) ) {
  6533. continue;
  6534. }
  6535. deviceObject->Flags |= DO_DIRECT_IO;
  6536. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  6537. //
  6538. // Point device extension back at device object.
  6539. //
  6540. deviceExtension = deviceObject->DeviceExtension;
  6541. deviceExtension->DeviceObject = deviceObject;
  6542. //
  6543. // Store pointer to physical device and disk/driver information.
  6544. //
  6545. ObReferenceObject( PhysicalDeviceObject );
  6546. deviceExtension->PhysicalDevice = PhysicalDeviceObject;
  6547. deviceExtension->DiskNumber = physicalExtension->DiskNumber;
  6548. deviceExtension->DriverObject = physicalExtension->DriverObject;
  6549. deviceExtension->BusType = physicalExtension->BusType;
  6550. deviceExtension->ReserveTimer = 0;
  6551. deviceExtension->PerformReserves = FALSE;
  6552. deviceExtension->ReserveFailure = 0;
  6553. deviceExtension->Signature = physicalExtension->Signature;
  6554. deviceExtension->Detached = TRUE;
  6555. deviceExtension->OfflinePending = FALSE;
  6556. InitializeListHead( &deviceExtension->WaitingIoctls );
  6557. InitializeListHead( &deviceExtension->HoldIO );
  6558. IoInitializeRemoveLock( &deviceExtension->RemoveLock, CLUSDISK_ALLOC_TAG, 0, 0 );
  6559. //
  6560. // Signal the worker thread running event.
  6561. //
  6562. KeInitializeEvent( &deviceExtension->Event, NotificationEvent, TRUE );
  6563. KeInitializeEvent( &deviceExtension->PagingPathCountEvent,
  6564. NotificationEvent, TRUE );
  6565. deviceExtension->PagingPathCount = 0;
  6566. deviceExtension->HibernationPathCount = 0;
  6567. deviceExtension->DumpPathCount = 0;
  6568. ExInitializeResourceLite( &deviceExtension->DriveLayoutLock );
  6569. //
  6570. // Update the highest partition number in partition zero
  6571. // and store the same value in this new extension just to initialize
  6572. // the field.
  6573. //
  6574. physicalExtension->LastPartitionNumber =
  6575. deviceExtension->LastPartitionNumber = partitionNumber;
  6576. //
  6577. // Attach to the partition. This call links the newly created
  6578. // device to the target device, returning the target device object.
  6579. //
  6580. status = IoAttachDevice(deviceObject,
  6581. &ntUnicodeString,
  6582. &deviceExtension->TargetDeviceObject);
  6583. if ( (!NT_SUCCESS(status)) || (status == STATUS_OBJECT_NAME_EXISTS) ) {
  6584. //
  6585. // Assume this device is already attached.
  6586. //
  6587. IoDeleteDevice(deviceObject);
  6588. } else {
  6589. //
  6590. // Propagate driver's alignment requirements and power flags.
  6591. //
  6592. deviceExtension->Detached = FALSE;
  6593. deviceObject->AlignmentRequirement =
  6594. deviceExtension->TargetDeviceObject->AlignmentRequirement;
  6595. deviceObject->SectorSize =
  6596. deviceExtension->TargetDeviceObject->SectorSize;
  6597. //
  6598. // The storage stack explicitly requires DO_POWER_PAGABLE to be
  6599. // set in all filter drivers *unless* DO_POWER_INRUSH is set.
  6600. // this is true even if the attached device doesn't set DO_POWER_PAGABLE.
  6601. //
  6602. if ( deviceExtension->TargetDeviceObject->Flags & DO_POWER_INRUSH) {
  6603. deviceObject->Flags |= DO_POWER_INRUSH;
  6604. } else {
  6605. deviceObject->Flags |= DO_POWER_PAGABLE;
  6606. }
  6607. }
  6608. } while (TRUE);
  6609. return Irp->IoStatus.Status;
  6610. } // ClusDiskUpdateDriveLayout
  6611. NTSTATUS
  6612. ClusDiskGetRunningDevices(
  6613. IN PVOID Buffer,
  6614. IN ULONG BufferSize
  6615. )
  6616. /*++
  6617. Routine Description:
  6618. Find out the list of signatures for devices with active reservations.
  6619. Arguments:
  6620. Return Value:
  6621. --*/
  6622. {
  6623. ULONG bufferSize = BufferSize;
  6624. PULONG itemCount = (PULONG)Buffer;
  6625. PULONG nextSignature;
  6626. PDEVICE_OBJECT deviceObject;
  6627. PCLUS_DEVICE_EXTENSION deviceExtension;
  6628. KIRQL irql;
  6629. if ( bufferSize < sizeof(ULONG) ) {
  6630. return(STATUS_BUFFER_TOO_SMALL);
  6631. }
  6632. bufferSize -= sizeof(ULONG);
  6633. *itemCount = 0;
  6634. nextSignature = itemCount+1;
  6635. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  6636. deviceObject = RootDeviceObject->DriverObject->DeviceObject;
  6637. //
  6638. // For each ClusDisk device, if we have a persistent reservation, then
  6639. // add it.
  6640. //
  6641. while ( deviceObject ) {
  6642. deviceExtension = deviceObject->DeviceExtension;
  6643. if ( (deviceExtension->BusType != RootBus) &&
  6644. deviceExtension->ReserveTimer &&
  6645. (deviceExtension->PhysicalDevice == deviceObject) ) {
  6646. if ( bufferSize < sizeof(ULONG) ) {
  6647. break;
  6648. }
  6649. bufferSize -= sizeof(ULONG);
  6650. *itemCount = *itemCount + 1;
  6651. *nextSignature++ = deviceExtension->Signature;
  6652. }
  6653. deviceObject = deviceObject->NextDevice;
  6654. }
  6655. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  6656. return(STATUS_SUCCESS);
  6657. } // ClusDiskGetRunningDevices
  6658. NTSTATUS
  6659. GetScsiPortNumber(
  6660. IN ULONG DiskSignature,
  6661. IN PUCHAR DiskPortNumber
  6662. )
  6663. /*--
  6664. Routine Description:
  6665. Find the Scsi Port Number for the given device signature.
  6666. Arguments:
  6667. DiskSignature - supplies the disk signature for the requested device.
  6668. DiskPortNumber - returns the corresponding Scsi Port Number if found.
  6669. Return Value:
  6670. NTSTATUS
  6671. --*/
  6672. {
  6673. ULONG driveLayoutSize;
  6674. PDRIVE_LAYOUT_INFORMATION driveLayout = NULL;
  6675. ULONG diskCount;
  6676. ULONG diskNumber;
  6677. WCHAR deviceNameBuffer[MAX_PARTITION_NAME_LENGTH];
  6678. UNICODE_STRING unicodeString;
  6679. NTSTATUS status = STATUS_UNSUCCESSFUL;
  6680. OBJECT_ATTRIBUTES objectAttributes;
  6681. IO_STATUS_BLOCK ioStatus;
  6682. HANDLE ntFileHandle = NULL;
  6683. SCSI_ADDRESS scsiAddress;
  6684. HANDLE eventHandle;
  6685. PCONFIGURATION_INFORMATION configurationInformation;
  6686. //
  6687. // Get the system configuration information to get number of disks.
  6688. //
  6689. configurationInformation = IoGetConfigurationInformation();
  6690. // Allocate a drive layout buffer.
  6691. driveLayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
  6692. (MAX_PARTITIONS * sizeof(PARTITION_INFORMATION));
  6693. driveLayout = ExAllocatePool( NonPagedPoolCacheAligned,
  6694. driveLayoutSize );
  6695. if ( driveLayout == NULL ) {
  6696. ClusDiskPrint((
  6697. 1,
  6698. "[ClusDisk] GetScsiPortNumber: Failed to allocate root drive layout structure.\n"
  6699. ));
  6700. return(STATUS_INSUFFICIENT_RESOURCES);
  6701. }
  6702. *DiskPortNumber = 0xff;
  6703. // Find the disk with the right signature
  6704. for ( diskNumber = 0;
  6705. diskNumber < configurationInformation->DiskCount;
  6706. diskNumber++ ) {
  6707. if ( ntFileHandle ) {
  6708. ZwClose( ntFileHandle );
  6709. ntFileHandle = NULL;
  6710. }
  6711. swprintf(deviceNameBuffer, DEVICE_PARTITION_NAME, diskNumber, 0);
  6712. WCSLEN_ASSERT( deviceNameBuffer );
  6713. // Create device name for the physical disk.
  6714. RtlInitUnicodeString(&unicodeString, deviceNameBuffer);
  6715. // Setup object attributes for the file to open.
  6716. InitializeObjectAttributes(&objectAttributes,
  6717. &unicodeString,
  6718. OBJ_CASE_INSENSITIVE,
  6719. NULL,
  6720. NULL);
  6721. // Open the device.
  6722. status = ZwCreateFile( &ntFileHandle,
  6723. FILE_READ_DATA,
  6724. &objectAttributes,
  6725. &ioStatus,
  6726. NULL,
  6727. FILE_ATTRIBUTE_NORMAL,
  6728. FILE_SHARE_READ | FILE_SHARE_WRITE,
  6729. FILE_OPEN,
  6730. FILE_SYNCHRONOUS_IO_NONALERT,
  6731. NULL,
  6732. 0 );
  6733. if ( !NT_SUCCESS(status) ) {
  6734. ClusDiskPrint((
  6735. 1,
  6736. "[ClusDisk] GetScsiPortNumber: Failed to open device [%ws]. Error %lx.\n",
  6737. deviceNameBuffer,
  6738. status ));
  6739. ExFreePool( driveLayout );
  6740. return(status);
  6741. }
  6742. // Create event for notification.
  6743. status = ZwCreateEvent( &eventHandle,
  6744. EVENT_ALL_ACCESS,
  6745. NULL,
  6746. SynchronizationEvent,
  6747. FALSE );
  6748. if ( !NT_SUCCESS(status) ) {
  6749. ClusDiskPrint((
  6750. 1,
  6751. "[ClusDisk] GetScsiPortNumber: Failed to create event. %08X\n",
  6752. status));
  6753. ExFreePool( driveLayout );
  6754. ZwClose( ntFileHandle );
  6755. return(status);
  6756. }
  6757. status = ZwDeviceIoControlFile( ntFileHandle,
  6758. eventHandle,
  6759. NULL,
  6760. NULL,
  6761. &ioStatus,
  6762. IOCTL_DISK_GET_DRIVE_LAYOUT,
  6763. NULL,
  6764. 0,
  6765. driveLayout,
  6766. driveLayoutSize );
  6767. ZwClose( eventHandle );
  6768. if ( NT_SUCCESS(status) ) {
  6769. if ( DiskSignature == driveLayout->Signature ) {
  6770. // Create event for notification.
  6771. status = ZwCreateEvent( &eventHandle,
  6772. EVENT_ALL_ACCESS,
  6773. NULL,
  6774. SynchronizationEvent,
  6775. FALSE );
  6776. if ( !NT_SUCCESS(status) ) {
  6777. ClusDiskPrint((
  6778. 1,
  6779. "[ClusDisk] GetScsiPortNumber: Failed to create event. %08X\n",
  6780. status));
  6781. ExFreePool( driveLayout );
  6782. ZwClose( ntFileHandle );
  6783. return(status);
  6784. }
  6785. // Get the port number for the SystemRoot disk device.
  6786. status = ZwDeviceIoControlFile( ntFileHandle,
  6787. NULL,
  6788. NULL,
  6789. NULL,
  6790. &ioStatus,
  6791. IOCTL_SCSI_GET_ADDRESS,
  6792. NULL,
  6793. 0,
  6794. &scsiAddress,
  6795. sizeof(SCSI_ADDRESS) );
  6796. if ( NT_SUCCESS(status) ) {
  6797. *DiskPortNumber = scsiAddress.PortNumber;
  6798. break;
  6799. } else {
  6800. ClusDiskPrint((
  6801. 1,
  6802. "[ClusDisk] GetScsiAddress FAILED. Error %lx\n",
  6803. status));
  6804. }
  6805. } else {
  6806. continue;
  6807. }
  6808. } else {
  6809. ClusDiskPrint((
  6810. 1,
  6811. "[ClusDisk] GetScsiAddress, GetDriveLayout FAILED. Error %lx.\n",
  6812. status));
  6813. }
  6814. }
  6815. if ( ntFileHandle ) {
  6816. ZwClose( ntFileHandle );
  6817. }
  6818. ExFreePool( driveLayout );
  6819. return(status);
  6820. } // GetScsiPortNumber
  6821. NTSTATUS
  6822. IsDiskClusterCapable(
  6823. IN UCHAR PortNumber,
  6824. OUT PBOOLEAN IsCapable
  6825. )
  6826. /*++
  6827. Routine Description:
  6828. Check if a given SCSI port device supports cluster manageable SCSI devices.
  6829. Arguments:
  6830. PortNumber - the port number for the SCSI device.
  6831. IsCapable - returns whether the SCSI device is cluster capable. That is,
  6832. supports, RESERVE/RELEASE/BUS RESET, etc.
  6833. Return Value:
  6834. --*/
  6835. {
  6836. WCHAR deviceNameBuffer[64];
  6837. UNICODE_STRING deviceNameString;
  6838. NTSTATUS status;
  6839. OBJECT_ATTRIBUTES objectAttributes;
  6840. IO_STATUS_BLOCK ioStatus;
  6841. HANDLE ntFileHandle;
  6842. HANDLE eventHandle;
  6843. SRB_IO_CONTROL srbControl;
  6844. *IsCapable = TRUE; // Err on the side of being usable.
  6845. swprintf(deviceNameBuffer, L"\\Device\\Scsiport%d", PortNumber);
  6846. WCSLEN_ASSERT( deviceNameBuffer );
  6847. // Create device name for the scsiport driver
  6848. RtlInitUnicodeString(&deviceNameString, deviceNameBuffer);
  6849. // Setup object attributes for the file to open.
  6850. InitializeObjectAttributes(&objectAttributes,
  6851. &deviceNameString,
  6852. OBJ_CASE_INSENSITIVE,
  6853. NULL,
  6854. NULL);
  6855. // Open the device.
  6856. status = ZwCreateFile( &ntFileHandle,
  6857. FILE_READ_DATA,
  6858. &objectAttributes,
  6859. &ioStatus,
  6860. NULL,
  6861. FILE_ATTRIBUTE_NORMAL,
  6862. FILE_SHARE_READ | FILE_SHARE_WRITE,
  6863. FILE_OPEN,
  6864. FILE_SYNCHRONOUS_IO_NONALERT,
  6865. NULL,
  6866. 0 );
  6867. if ( !NT_SUCCESS(status) ) {
  6868. ClusDiskPrint((1,
  6869. "[ClusDisk] IsDiskClusterCapable: Failed to open device [%ws]. Error %08X.\n",
  6870. deviceNameString, status ));
  6871. return(status);
  6872. }
  6873. // Create event for notification.
  6874. status = ZwCreateEvent( &eventHandle,
  6875. EVENT_ALL_ACCESS,
  6876. NULL,
  6877. SynchronizationEvent,
  6878. FALSE );
  6879. if ( !NT_SUCCESS(status) ) {
  6880. ClusDiskPrint((1, "[ClusDisk] IsDiskClusterCapable: Failed to create event. %08X\n",
  6881. status));
  6882. ZwClose( ntFileHandle );
  6883. return(status);
  6884. }
  6885. srbControl.HeaderLength = sizeof(SRB_IO_CONTROL);
  6886. RtlMoveMemory( srbControl.Signature, "CLUSDISK", 8 );
  6887. srbControl.Timeout = 3;
  6888. srbControl.Length = 0;
  6889. srbControl.ControlCode = IOCTL_SCSI_MINIPORT_NOT_QUORUM_CAPABLE;
  6890. status = ZwDeviceIoControlFile(ntFileHandle,
  6891. eventHandle,
  6892. NULL,
  6893. NULL,
  6894. &ioStatus,
  6895. IOCTL_SCSI_MINIPORT,
  6896. &srbControl,
  6897. sizeof(SRB_IO_CONTROL),
  6898. NULL,
  6899. 0 );
  6900. if ( NT_SUCCESS(status) ) {
  6901. *IsCapable = TRUE;
  6902. } else {
  6903. ClusDiskPrint((3,
  6904. "[ClusDisk] IsDiskClusterCapable: NOT_QUORUM_CAPABLE IOCTL FAILED. Error %08X.\n",
  6905. status));
  6906. }
  6907. ZwClose( eventHandle );
  6908. ZwClose( ntFileHandle );
  6909. return(status);
  6910. } // IsDiskClusterCapable
  6911. VOID
  6912. ClusDiskResumeIO(
  6913. PDEVICE_OBJECT DeviceObject
  6914. )
  6915. /*++
  6916. --*/
  6917. {
  6918. PLIST_ENTRY listEntry;
  6919. PIRP irp;
  6920. KIRQL irql;
  6921. PDEVICE_OBJECT clusterDeviceObject;
  6922. PCLUS_DEVICE_EXTENSION deviceExtension;
  6923. PCLUS_DEVICE_EXTENSION physicalDisk;
  6924. PDEVICE_OBJECT targetDeviceObject;
  6925. REPLACE_CONTEXT context;
  6926. CDLOG( "ClusDiskResumeIO(%p): Entry", DeviceObject );
  6927. IoAcquireCancelSpinLock( &irql );
  6928. KeAcquireSpinLockAtDpcLevel(&ClusDiskSpinLock);
  6929. clusterDeviceObject = DeviceObject->DriverObject->DeviceObject;
  6930. while ( clusterDeviceObject ) {
  6931. deviceExtension = clusterDeviceObject->DeviceExtension;
  6932. //physicalDisk = deviceExtension->PhysicalDevice->DeviceExtension;
  6933. if ( deviceExtension->DiskState == DiskStalled ) {
  6934. targetDeviceObject = deviceExtension->TargetDeviceObject;
  6935. while ( !IsListEmpty(&deviceExtension->HoldIO ) ) {
  6936. listEntry = RemoveHeadList(&deviceExtension->HoldIO);
  6937. irp = CONTAINING_RECORD( listEntry,
  6938. IRP,
  6939. Tail.Overlay.ListEntry );
  6940. IoSetCancelRoutine(irp, NULL);
  6941. KeReleaseSpinLockFromDpcLevel(&ClusDiskSpinLock);
  6942. IoReleaseCancelSpinLock( irql );
  6943. ReleaseRemoveLock(&deviceExtension->RemoveLock, irp);
  6944. if (irp->Cancel) {
  6945. CDLOG( "ResumeIo: CompleteCanceled irp %p", irp );
  6946. irp->IoStatus.Status = STATUS_CANCELLED;
  6947. IoCompleteRequest(irp, IO_NO_INCREMENT);
  6948. } else {
  6949. ClusDiskPrint((1, "[ClusDisk] ResumeIO: Resume IRP %p, target %p Q: %p \n",
  6950. irp, targetDeviceObject, &deviceExtension->HoldIO ));
  6951. //
  6952. // We must bump the stack location here, in case we cancel
  6953. // the I/O.
  6954. //
  6955. IoSkipCurrentIrpStackLocation( irp );
  6956. IoCallDriver(targetDeviceObject,
  6957. irp);
  6958. }
  6959. IoAcquireCancelSpinLock( &irql );
  6960. KeAcquireSpinLockAtDpcLevel(&ClusDiskSpinLock);
  6961. // KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  6962. }
  6963. ASSERT_RESERVES_STARTED( deviceExtension );
  6964. // deviceExtension->DiskState = DiskOnline;
  6965. ONLINE_DISK( deviceExtension );
  6966. ClusDiskPrint(( 3,
  6967. "[ClusDisk] ResumeIO: Marking signature %08X online \n",
  6968. deviceExtension->Signature ));
  6969. }
  6970. // Advance to next device
  6971. clusterDeviceObject = clusterDeviceObject->NextDevice;
  6972. }
  6973. // KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  6974. KeReleaseSpinLockFromDpcLevel(&ClusDiskSpinLock);
  6975. IoReleaseCancelSpinLock( irql );
  6976. //
  6977. // Before we did HoldIo, we opened a handles to all volumes
  6978. // to be able to dismount if we decide to offline the disks while HoldIo
  6979. // is in progress. Clean them up now.
  6980. //
  6981. clusterDeviceObject = DeviceObject->DriverObject->DeviceObject;
  6982. while ( clusterDeviceObject ) {
  6983. deviceExtension = clusterDeviceObject->DeviceExtension;
  6984. if (deviceExtension->PhysicalDevice == clusterDeviceObject) {
  6985. context.DeviceExtension = deviceExtension;
  6986. context.NewValue = NULL; // clean up
  6987. context.Flags = 0; // don't dismount
  6988. ProcessDelayedWorkSynchronous( clusterDeviceObject, ClusDiskpReplaceHandleArray, &context );
  6989. }
  6990. clusterDeviceObject = clusterDeviceObject->NextDevice;
  6991. }
  6992. CDLOG( "ClusDiskResumeIO(%p): Exit", DeviceObject );
  6993. return;
  6994. } // ClusDiskResumeIO
  6995. NTSTATUS
  6996. ClusDiskCreateHandle(
  6997. OUT PHANDLE pHandle,
  6998. IN ULONG DiskNumber,
  6999. IN ULONG PartitionNumber,
  7000. IN ACCESS_MASK DesiredAccess
  7001. )
  7002. /*++
  7003. Routine Description:
  7004. Open a file handle to self
  7005. Arguments:
  7006. DeviceObject -
  7007. DesiredAccess - acces mask to be passed to create file
  7008. Return Value:
  7009. Status is returned.
  7010. --*/
  7011. {
  7012. WCHAR deviceNameBuffer[ MAX_PARTITION_NAME_LENGTH ];
  7013. UNICODE_STRING deviceName;
  7014. IO_STATUS_BLOCK ioStatus;
  7015. OBJECT_ATTRIBUTES objectAttributes;
  7016. NTSTATUS status;
  7017. swprintf( deviceNameBuffer, DEVICE_PARTITION_NAME,
  7018. DiskNumber,
  7019. PartitionNumber );
  7020. RtlInitUnicodeString( &deviceName, deviceNameBuffer );
  7021. CDLOG( "CreateHandle(%wZ): Entry", &deviceName );
  7022. InitializeObjectAttributes( &objectAttributes,
  7023. &deviceName,
  7024. OBJ_CASE_INSENSITIVE,
  7025. NULL,
  7026. NULL );
  7027. *pHandle = 0;
  7028. status = ZwCreateFile( pHandle,
  7029. DesiredAccess,
  7030. &objectAttributes,
  7031. &ioStatus,
  7032. NULL,
  7033. FILE_ATTRIBUTE_NORMAL,
  7034. FILE_SHARE_READ | FILE_SHARE_WRITE,
  7035. FILE_OPEN,
  7036. FILE_SYNCHRONOUS_IO_NONALERT,
  7037. NULL,
  7038. 0 );
  7039. CDLOG( "CreateHandle: Exit status %!status! handle %p", status, *pHandle );
  7040. return status;
  7041. }
  7042. VOID
  7043. ClusDiskpReplaceHandleArray(
  7044. PDEVICE_OBJECT DeviceObject,
  7045. PWORK_CONTEXT WorkContext
  7046. )
  7047. /*++
  7048. Routine Description:
  7049. Replaces handle array stored in the device extension with a new one.
  7050. Use NULL as a NewValue to clean up the field.
  7051. It will close all the handles stored in the array and free up the memory block.
  7052. If DO_DISMOUNT is specified, it will call FSCTL_DISMOUNT for every handle
  7053. Arguments:
  7054. DeviceObject - Partition0 Device Object
  7055. WorkContext - General context info and routine specific context info.
  7056. Return Value:
  7057. Status is returned.
  7058. --*/
  7059. {
  7060. PREPLACE_CONTEXT Context = WorkContext->Context;
  7061. PCLUS_DEVICE_EXTENSION deviceExtension = Context->DeviceExtension;
  7062. HANDLE* OldArray;
  7063. CDLOG( "ClusDiskpReplaceHandleArray: Entry NewValue %p Flags %x",
  7064. Context->NewValue,
  7065. Context->Flags );
  7066. OldArray =
  7067. InterlockedExchangePointer(
  7068. (VOID*)&deviceExtension->VolumeHandles, Context->NewValue);
  7069. //
  7070. // We can release the remove lock now (in some instances). This prevents a deadlock
  7071. // between the DismountDevice routine and the Remove PnP IRP. During dismount, we
  7072. // have saved a copy of the handle array, and we no longer refer to the device object
  7073. // or extension.
  7074. //
  7075. if ( Context->Flags & RELEASE_REMOVE_LOCK ) {
  7076. ReleaseRemoveLock(&deviceExtension->RemoveLock, deviceExtension);
  7077. }
  7078. if (OldArray) {
  7079. ULONG i;
  7080. ULONG Count = PtrToUlong( OldArray[0] );
  7081. //
  7082. // We should already be running in the system process. If not, then there
  7083. // is an error and we need to exit.
  7084. //
  7085. if ( ClusDiskSystemProcess != (PKPROCESS) IoGetCurrentProcess() ) {
  7086. CDLOG( "ClusDiskpReplaceHandleArray: Not running in system process" );
  7087. ExFreePool( OldArray );
  7088. goto FnExit;
  7089. }
  7090. for(i = 1; i <= Count; ++i) {
  7091. if (OldArray[i]) {
  7092. ClusDiskPrint(( 3,
  7093. "[ClusDisk] ClusDiskpReplaceHandleArray: Handle %x \n",
  7094. OldArray[i] ));
  7095. if (Context->Flags & DO_DISMOUNT) {
  7096. DismountDevice(OldArray[i]);
  7097. }
  7098. ZwClose(OldArray[i]);
  7099. }
  7100. }
  7101. CDLOG("ClusDiskpReplaceHandleArray: Freed oldArray %p", OldArray );
  7102. ExFreePool( OldArray );
  7103. }
  7104. FnExit:
  7105. CDLOG( "ClusDiskpReplaceHandleArray: Exit" );
  7106. ClusDiskPrint(( 3,
  7107. "[ClusDisk] ClusDiskpReplaceHandleArray: Returns \n" ));
  7108. KeSetEvent( &WorkContext->CompletionEvent, IO_NO_INCREMENT, FALSE );
  7109. } // ClusDiskpReplaceHandleArray
  7110. NTSTATUS
  7111. ProcessDelayedWorkSynchronous(
  7112. PDEVICE_OBJECT DeviceObject,
  7113. PVOID WorkerRoutine,
  7114. PVOID Context
  7115. )
  7116. /*++
  7117. Routine Description:
  7118. Call the WorkerRoutine directly if we are running in the system process. If
  7119. we are not running in the system process, check the IRQL. If the IRQL is
  7120. PASSIVE_LEVEL, queue the WorkerRoutine as a work item and wait for it to complete.
  7121. When the work item completes, it will set an event.
  7122. If the IRQL is not PASSIVE_LEVEL, then this routine will return an error.
  7123. Arguments:
  7124. DeviceObject
  7125. WorkerRoutine - Routine to run.
  7126. Context - Context information for the WorkerRoutine.
  7127. Return Value:
  7128. Status is returned.
  7129. --*/
  7130. {
  7131. PIO_WORKITEM workItem = NULL;
  7132. PWORK_CONTEXT workContext = NULL;
  7133. NTSTATUS status = STATUS_UNSUCCESSFUL;
  7134. __try {
  7135. ClusDiskPrint(( 3,
  7136. "[ClusDisk] DelayedWorkSync: Entry \n" ));
  7137. //
  7138. // Prepare a context structure.
  7139. //
  7140. workContext = ExAllocatePool( NonPagedPool, sizeof(WORK_CONTEXT) );
  7141. if ( !workContext ) {
  7142. ClusDiskPrint(( 1,
  7143. "[ClusDisk] DelayedWorkSync: Failed to allocate WorkContext \n" ));
  7144. __leave;
  7145. }
  7146. KeInitializeEvent( &workContext->CompletionEvent, SynchronizationEvent, FALSE );
  7147. workContext->DeviceObject = DeviceObject;
  7148. workContext->FinalStatus = STATUS_SUCCESS;
  7149. workContext->Context = Context;
  7150. //
  7151. // If we are in the system process, we can call the worker routine directly.
  7152. //
  7153. if ( (PKPROCESS)IoGetCurrentProcess() == ClusDiskSystemProcess ) {
  7154. ClusDiskPrint(( 3,
  7155. "[ClusDisk] DelayedWorkSync: Calling WorkerRoutine directly \n" ));
  7156. ((PIO_WORKITEM_ROUTINE)WorkerRoutine)( DeviceObject, workContext );
  7157. __leave;
  7158. }
  7159. //
  7160. // If we are not running at passive level, we cannot continue.
  7161. //
  7162. if ( PASSIVE_LEVEL != KeGetCurrentIrql() ) {
  7163. ClusDiskPrint(( 1,
  7164. "[ClusDisk] DelayedWorkSync: IRQL not PASSIVE_LEVEL \n" ));
  7165. __leave;
  7166. }
  7167. workItem = IoAllocateWorkItem( DeviceObject );
  7168. if ( NULL == workItem ) {
  7169. ClusDiskPrint(( 1,
  7170. "[ClusDisk] DelayedWorkSync: Failed to allocate WorkItem \n" ));
  7171. __leave;
  7172. }
  7173. //
  7174. // Queue the workitem. IoQueueWorkItem will insure that the device object is
  7175. // referenced while the work-item progresses.
  7176. //
  7177. ClusDiskPrint(( 3,
  7178. "[ClusDisk] DelayedWorkSync: Queuing work item \n" ));
  7179. IoQueueWorkItem( workItem,
  7180. WorkerRoutine,
  7181. DelayedWorkQueue,
  7182. workContext );
  7183. KeWaitForSingleObject( &workContext->CompletionEvent,
  7184. Executive,
  7185. KernelMode,
  7186. FALSE,
  7187. NULL );
  7188. ClusDiskPrint(( 3,
  7189. "[ClusDisk] DelayedWorkSync: Work item completed \n" ));
  7190. } __finally {
  7191. if ( workItem) {
  7192. IoFreeWorkItem( workItem );
  7193. }
  7194. if ( workContext ) {
  7195. status = workContext->FinalStatus;
  7196. ExFreePool( workContext );
  7197. }
  7198. }
  7199. ClusDiskPrint(( 3,
  7200. "[ClusDisk] DelayedWorkSync: Returning status %08X \n", status ));
  7201. return status;
  7202. } // ProcessDelayedWorkSynchronous
  7203. VOID
  7204. ClusDiskpOpenFileHandles(
  7205. PDEVICE_OBJECT Part0DeviceObject,
  7206. PWORK_CONTEXT WorkContext
  7207. )
  7208. /*++
  7209. Routine Description:
  7210. Creates file handles for all partitions on the disk.
  7211. Arguments:
  7212. DeviceObject - Partition0 Device Object
  7213. WorkContext - General context info and routine specific context info.
  7214. Return Value:
  7215. Status is returned.
  7216. --*/
  7217. {
  7218. NTSTATUS status;
  7219. NTSTATUS returnStatus = STATUS_SUCCESS;
  7220. PCLUS_DEVICE_EXTENSION deviceExtension =
  7221. Part0DeviceObject->DeviceExtension;
  7222. PDEVICE_OBJECT deviceObject;
  7223. PDRIVE_LAYOUT_INFORMATION pDriveLayout;
  7224. ULONG partitionCount;
  7225. ULONG i;
  7226. HANDLE* HandleArray = NULL;
  7227. ULONG ArraySize;
  7228. REPLACE_CONTEXT context;
  7229. CDLOG( "OpenFileHandles(%p): Entry", Part0DeviceObject );
  7230. ASSERT( (deviceExtension->PhysicalDevice == Part0DeviceObject)
  7231. && (Part0DeviceObject != RootDeviceObject) );
  7232. pDriveLayout = ClusDiskGetPartitionInfo( deviceExtension );
  7233. if (NULL == pDriveLayout) {
  7234. returnStatus = STATUS_INSUFFICIENT_RESOURCES;
  7235. goto exit_gracefully;
  7236. }
  7237. partitionCount = pDriveLayout->PartitionCount;
  7238. ExFreePool(pDriveLayout);
  7239. ArraySize = (partitionCount + 1) * sizeof(HANDLE);
  7240. //
  7241. // If we are not running in the system process, we can't continue.
  7242. //
  7243. if ( ClusDiskSystemProcess != (PKPROCESS) IoGetCurrentProcess() ) {
  7244. CDLOG("OpenFileHandles: Not running in system process" );
  7245. returnStatus = STATUS_UNSUCCESSFUL;
  7246. goto exit_gracefully;
  7247. }
  7248. HandleArray =
  7249. ExAllocatePool(PagedPool, ArraySize );
  7250. if (!HandleArray) {
  7251. CDLOG("OpenFileHandles: AllocFailed ArraySize %d", ArraySize );
  7252. returnStatus = STATUS_INSUFFICIENT_RESOURCES;
  7253. goto exit_gracefully;
  7254. }
  7255. //
  7256. // Store the size of the array in the first element
  7257. //
  7258. HandleArray[0] = (HANDLE)( UlongToPtr(partitionCount) );
  7259. for(i = 1; i <= partitionCount; ++i) {
  7260. HANDLE FileHandle;
  7261. status = ClusDiskCreateHandle(
  7262. &FileHandle,
  7263. deviceExtension->DiskNumber,
  7264. i,
  7265. FILE_WRITE_ATTRIBUTES); // Use FILE_WRITE_ATTRIBUTES for dismount
  7266. if (NT_SUCCESS(status)) {
  7267. HandleArray[i] = FileHandle;
  7268. } else {
  7269. HandleArray[i] = 0;
  7270. returnStatus = status;
  7271. }
  7272. }
  7273. context.DeviceExtension = deviceExtension;
  7274. context.NewValue = HandleArray;
  7275. context.Flags = 0; // don't dismount
  7276. ProcessDelayedWorkSynchronous( Part0DeviceObject, ClusDiskpReplaceHandleArray, &context );
  7277. exit_gracefully:
  7278. CDLOG( "OpenFileHandles: Exit => %!status!", returnStatus );
  7279. ClusDiskPrint(( 3,
  7280. "[ClusDisk] ClusDiskpOpenFileHandles: Returning status %08X \n", returnStatus ));
  7281. WorkContext->FinalStatus = returnStatus;
  7282. KeSetEvent( &WorkContext->CompletionEvent, IO_NO_INCREMENT, FALSE );
  7283. } // ClusDiskpOpenFileHandles
  7284. NTSTATUS
  7285. ClusDiskDeviceControl(
  7286. PDEVICE_OBJECT DeviceObject,
  7287. PIRP Irp
  7288. )
  7289. /*++
  7290. Routine Description:
  7291. This device control dispatcher handles only the cluster disk
  7292. device control. All others are passed down to the disk drivers.
  7293. Arguments:
  7294. DeviceObject - Context for the activity.
  7295. Irp - The device control argument block.
  7296. Return Value:
  7297. Status is returned.
  7298. --*/
  7299. {
  7300. PCLUS_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  7301. PCLUS_DEVICE_EXTENSION physicalDisk =
  7302. deviceExtension->PhysicalDevice->DeviceExtension;
  7303. PDEVICE_OBJECT targetDeviceObject;
  7304. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  7305. PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
  7306. PUCHAR ioDiskState = Irp->AssociatedIrp.SystemBuffer;
  7307. UCHAR newDiskState;
  7308. UCHAR oldDiskState;
  7309. ULONG returnLength = 0;
  7310. ULONG access;
  7311. NTSTATUS status = STATUS_SUCCESS;
  7312. PSTORAGE_BUS_RESET_REQUEST storageReset;
  7313. BOOLEAN settingNewState = FALSE;
  7314. KIRQL irql;
  7315. PULONG reserveSignature;
  7316. ULONG signature;
  7317. PSRB_IO_CONTROL srbControl;
  7318. BOOLEAN isCapable;
  7319. LARGE_INTEGER waitTime;
  7320. //
  7321. // Note that we are going to acquire two RemoveLocks here: one for the original DO and one
  7322. // for the physical device (pointed to this DO's device extension). Whenever an IRP is
  7323. // queued, we release one RemoveLock in this routine - release the RemoveLock in the device
  7324. // extension NOT containing the queued IRP. The routine that processes the queued IRP will
  7325. // release the RemoveLock as it has the proper device extension.
  7326. //
  7327. // This should work correctly even if the DO and the physical device point to the same DO, since
  7328. // the RemoveLock is really just a counter, we will increment the counter for the DO twice and
  7329. // decrement it once here, and once when the IRP is completed.
  7330. status = AcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  7331. if ( !NT_SUCCESS(status) ) {
  7332. ClusDiskPrint((
  7333. 1,
  7334. "[ClusDisk] ClusDiskDeviceControl: AcquireRemoveLock for %p failed %08X \n",
  7335. deviceExtension,
  7336. status));
  7337. Irp->IoStatus.Status = status;
  7338. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7339. return status;
  7340. }
  7341. status = AcquireRemoveLock(&physicalDisk->RemoveLock, Irp);
  7342. if ( !NT_SUCCESS(status) ) {
  7343. ClusDiskPrint((
  7344. 1,
  7345. "[ClusDisk] ClusDiskDeviceControl: AcquireRemoveLock for %p (PD) failed %08X \n",
  7346. physicalDisk,
  7347. status));
  7348. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7349. Irp->IoStatus.Status = status;
  7350. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7351. return status;
  7352. }
  7353. //
  7354. // Find out if this is directed at the root device. If so, we only
  7355. // support ATTACH and DETACH.
  7356. //
  7357. if ( deviceExtension->BusType == RootBus ) {
  7358. return(ClusDiskRootDeviceControl( DeviceObject, Irp ));
  7359. }
  7360. switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
  7361. #if 0
  7362. // Since we cannot get to the device object from the user mode when we
  7363. // are holding IOs, we will use only ClusDisk0 to perform arbitration
  7364. // escape operations.
  7365. // Remove, when Hold IO stuff is fully tested.
  7366. // Arbitration support routine. Currently provides ability to read/write
  7367. // physical sectors on the disk while the device is offline
  7368. case IOCTL_DISK_CLUSTER_ARBITRATION_ESCAPE:
  7369. if ( ARGUMENT_PRESENT( Irp->AssociatedIrp.SystemBuffer ) &&
  7370. currentIrpStack->Parameters.DeviceIoControl.InputBufferLength >=
  7371. sizeof(ULONG) ) {
  7372. CDLOG("IoctlClusterArbitrationEscape: DO %p", DeviceObject );
  7373. status = ProcessArbitrationEscape( physicalDisk,
  7374. Irp->AssociatedIrp.SystemBuffer,
  7375. currentIrpStack->Parameters.DeviceIoControl.InputBufferLength,
  7376. 0);
  7377. } else {
  7378. status = STATUS_INVALID_PARAMETER;
  7379. }
  7380. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7381. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7382. Irp->IoStatus.Status = status;
  7383. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7384. return(status);
  7385. #endif
  7386. // Optionally set new state, and optionally get old state.
  7387. case IOCTL_DISK_CLUSTER_SET_STATE:
  7388. //
  7389. // Save the old disk state.
  7390. //
  7391. oldDiskState = (UCHAR)physicalDisk->DiskState;
  7392. ClusDiskPrint((3, "[ClusDisk] DeviceControl: PD DiskState %s, devObj DiskState %s \n",
  7393. DiskStateToString( physicalDisk->DiskState ),
  7394. DiskStateToString( deviceExtension->DiskState ) ));
  7395. // stevedz - remove this assert for now. Why is part0 state different from partX state?
  7396. // ASSERT( physicalDisk->DiskState == deviceExtension->DiskState );
  7397. //
  7398. // Check if input buffer supplied. If present, then this is the
  7399. // new disk state.
  7400. //
  7401. if ( ARGUMENT_PRESENT( ioDiskState) &&
  7402. currentIrpStack->Parameters.DeviceIoControl.InputBufferLength >=
  7403. sizeof(UCHAR) ) {
  7404. newDiskState = ioDiskState[0];
  7405. ClusDiskPrint((3, "[ClusDisk] DeviceControl: Setting state on disk %u (%p), state %s \n",
  7406. physicalDisk->DiskNumber,
  7407. DeviceObject,
  7408. DiskStateToString( newDiskState ) ));
  7409. if ( newDiskState > DiskStateMaximum ) {
  7410. status = STATUS_INVALID_PARAMETER;
  7411. } else if ( DiskOfflinePending == newDiskState ) {
  7412. //
  7413. // We are not changing the current disk state, but the disk resource DLL is
  7414. // telling us that we are in offline/terminate processing. When NTFS is done
  7415. // flushing the drive, it sends an IOCTL to unlock the media. When we see
  7416. // the unlock IOCTL and the offline pending flag is set, we know we can
  7417. // immediately mark the disk as offline.
  7418. //
  7419. ClusDiskPrint(( 1,
  7420. "[ClusDisk] Set offline pending flag, Signature = %08lX \n",
  7421. physicalDisk->Signature ));
  7422. physicalDisk->OfflinePending = TRUE;
  7423. settingNewState = FALSE;
  7424. status = STATUS_SUCCESS;
  7425. } else {
  7426. if ( DiskOnline == newDiskState ) {
  7427. ASSERT_RESERVES_STARTED( physicalDisk );
  7428. physicalDisk->OfflinePending = FALSE;
  7429. //
  7430. // If current state is offline, then before bringing the disk
  7431. // online, we want to dismount the file systems if they are mounted.
  7432. //
  7433. if ( DiskOffline == physicalDisk->DiskState ) {
  7434. ClusDiskDismountDevice( physicalDisk->DiskNumber, TRUE );
  7435. }
  7436. ONLINE_DISK( physicalDisk );
  7437. } else if ( DiskOffline == newDiskState ) {
  7438. OFFLINE_DISK( physicalDisk );
  7439. } else {
  7440. physicalDisk->DiskState = newDiskState;
  7441. }
  7442. CDLOG( "IoctlClusterSetState(%p): old %!diskstate! => new %!diskstate!",
  7443. DeviceObject,
  7444. oldDiskState,
  7445. newDiskState );
  7446. settingNewState = TRUE;
  7447. #if 0
  7448. if ( oldDiskState != newDiskState ) {
  7449. // going from Online to Offline or Offline to Online
  7450. physicalDisk->ReserveTimer = RESERVE_TIMER;
  7451. }
  7452. #endif
  7453. }
  7454. } else {
  7455. ClusDiskPrint((3, "[ClusDisk] DeviceControl: Getting state from disk %u (%p), state %s \n",
  7456. physicalDisk->DiskNumber,
  7457. DeviceObject,
  7458. DiskStateToString( oldDiskState ) ));
  7459. }
  7460. if ( NT_SUCCESS(status) &&
  7461. ARGUMENT_PRESENT( ioDiskState ) &&
  7462. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength >=
  7463. sizeof(UCHAR) ) {
  7464. ioDiskState[0] = oldDiskState;
  7465. returnLength = 1;
  7466. }
  7467. Irp->IoStatus.Status = status;
  7468. Irp->IoStatus.Information = returnLength;
  7469. if ((status == STATUS_SUCCESS) &&
  7470. settingNewState) {
  7471. //
  7472. // Call down to what's below. If it's FT it will know what to do.
  7473. // Any other driver will reject the ioctl. However none of this
  7474. // matters since we absolutely want to return to our caller the
  7475. // results we just set up. SO, we will use our current stack location
  7476. // to save off the status, information, and pointer to the system buffer.
  7477. // We will use the fourth stack location to hold the state we wish
  7478. // to set the member to.
  7479. //
  7480. #if 0 // We can't ignore the status from IoCallDriver!
  7481. currentIrpStack->Parameters.Others.Argument1 = ioDiskState;
  7482. (ULONG_PTR)currentIrpStack->Parameters.Others.Argument2 = Irp->IoStatus.Information;
  7483. (BOOLEAN)currentIrpStack->Parameters.Others.Argument3 = newDiskState == DiskOnline;
  7484. Irp->AssociatedIrp.SystemBuffer = &currentIrpStack->Parameters.Others.Argument3;
  7485. nextIrpStack->Flags = currentIrpStack->Flags;
  7486. nextIrpStack->MajorFunction = currentIrpStack->MajorFunction;
  7487. nextIrpStack->MinorFunction = currentIrpStack->MinorFunction;
  7488. nextIrpStack->Parameters.DeviceIoControl.OutputBufferLength = 0;
  7489. nextIrpStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(BOOLEAN);
  7490. nextIrpStack->Parameters.DeviceIoControl.IoControlCode = FT_CLUSTER_SET_MEMBER_STATE;
  7491. nextIrpStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  7492. IoSetCompletionRoutine(
  7493. Irp,
  7494. CluSetFtMemberComplete,
  7495. NULL,
  7496. TRUE,
  7497. TRUE,
  7498. TRUE
  7499. );
  7500. return (IoCallDriver(deviceExtension->TargetDeviceObject, Irp));
  7501. #endif
  7502. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7503. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7504. IoCompleteRequest(Irp,IO_NO_INCREMENT);
  7505. return(STATUS_SUCCESS);
  7506. } else {
  7507. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7508. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7509. IoCompleteRequest(Irp,IO_NO_INCREMENT);
  7510. return(status);
  7511. }
  7512. // Check the reservation timer
  7513. case IOCTL_DISK_CLUSTER_ALIVE_CHECK:
  7514. if ( RootDeviceObject == NULL ) {
  7515. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7516. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7517. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  7518. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  7519. return(STATUS_INVALID_DEVICE_REQUEST);
  7520. }
  7521. IoAcquireCancelSpinLock( &irql );
  7522. KeAcquireSpinLockAtDpcLevel(&ClusDiskSpinLock);
  7523. if ( (physicalDisk->DiskState == DiskOnline) &&
  7524. (physicalDisk->ReserveTimer == 0) &&
  7525. (!NT_SUCCESS(physicalDisk->ReserveFailure)) ) {
  7526. status = physicalDisk->ReserveFailure;
  7527. } else {
  7528. if ( (physicalDisk->DiskState != DiskOnline) ||
  7529. (physicalDisk->ReserveTimer == 0) ) {
  7530. #if 0
  7531. ClusDiskPrint((
  7532. 1,
  7533. "[ClusDisk] DeviceControl, AliveCheck failed, signature %lx.\n",
  7534. physicalDisk->Signature ));
  7535. #endif
  7536. status = STATUS_CANCELLED;
  7537. } else {
  7538. status = STATUS_SUCCESS;
  7539. }
  7540. }
  7541. if ( status == STATUS_SUCCESS ) {
  7542. NTSTATUS newStatus;
  7543. newStatus = ClusDiskMarkIrpPending( Irp, ClusDiskIrpCancel );
  7544. if ( NT_SUCCESS( newStatus ) ) {
  7545. InsertTailList( &physicalDisk->WaitingIoctls,
  7546. &Irp->Tail.Overlay.ListEntry );
  7547. status = STATUS_PENDING;
  7548. // Release only this DO RemoveLock. The physical device RemoveLock
  7549. // will be released when the IRP is removed from the queue.
  7550. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7551. } else {
  7552. status = newStatus;
  7553. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7554. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7555. Irp->IoStatus.Status = status;
  7556. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7557. }
  7558. KeReleaseSpinLockFromDpcLevel(&ClusDiskSpinLock);
  7559. IoReleaseCancelSpinLock( irql );
  7560. } else {
  7561. KeReleaseSpinLockFromDpcLevel(&ClusDiskSpinLock);
  7562. IoReleaseCancelSpinLock( irql );
  7563. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7564. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7565. Irp->IoStatus.Status = status;
  7566. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7567. }
  7568. return(status);
  7569. // Perform a bus reset
  7570. case IOCTL_DISK_CLUSTER_RESET_BUS:
  7571. CDLOG( "IoctlBusReset(%p): Sig %08x PathId %d",
  7572. DeviceObject,
  7573. deviceExtension->Signature,
  7574. deviceExtension->ScsiAddress.PathId );
  7575. if ( currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  7576. sizeof(STORAGE_BUS_RESET_REQUEST) ) {
  7577. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7578. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7579. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  7580. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7581. return(STATUS_INSUFFICIENT_RESOURCES);
  7582. }
  7583. *nextIrpStack = *currentIrpStack;
  7584. storageReset = Irp->AssociatedIrp.SystemBuffer;
  7585. storageReset->PathId = deviceExtension->ScsiAddress.PathId;
  7586. nextIrpStack->Parameters.DeviceIoControl.OutputBufferLength = 0;
  7587. nextIrpStack->Parameters.DeviceIoControl.InputBufferLength =
  7588. sizeof(STORAGE_BUS_RESET_REQUEST);
  7589. nextIrpStack->Parameters.DeviceIoControl.IoControlCode =
  7590. IOCTL_STORAGE_BREAK_RESERVATION;
  7591. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7592. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7593. return(IoCallDriver(deviceExtension->TargetDeviceObject, Irp));
  7594. case IOCTL_SCSI_GET_ADDRESS:
  7595. IoSkipCurrentIrpStackLocation( Irp );
  7596. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7597. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7598. //
  7599. // Pass this device control down to next driver layer.
  7600. //
  7601. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  7602. // Perform unrestricted reserve
  7603. case IOCTL_DISK_CLUSTER_RESERVE:
  7604. CDLOG( "IoctlClusterReserve(%p): sig %08x", DeviceObject, deviceExtension->Signature );
  7605. *nextIrpStack = *currentIrpStack;
  7606. nextIrpStack->Parameters.DeviceIoControl.IoControlCode =
  7607. IOCTL_DISK_RESERVE;
  7608. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7609. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7610. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  7611. // Perform unrestricted get drive layout
  7612. case IOCTL_DISK_CLUSTER_GET_DRIVE_LAYOUT:
  7613. // This IOCTL can result in a read of the disk - so honor HoldIO
  7614. //
  7615. // Hold the I/O request if we are stalled.
  7616. // First check for hint - i.e. with no lock held.
  7617. //
  7618. if ( deviceExtension->DiskState == DiskStalled ) {
  7619. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  7620. //
  7621. // Check again, with lock held - this one is valid!
  7622. //
  7623. if ( deviceExtension->DiskState == DiskStalled ) {
  7624. ClusDiskPrint((1,"[ClusDisk] HoldCTL - pending IRP %p, target %p \n",
  7625. Irp, DeviceObject ));
  7626. CDLOG("IoctlGetDriveLayout: Stall DO %p", DeviceObject );
  7627. InsertTailList( &deviceExtension->HoldIO,
  7628. &Irp->Tail.Overlay.ListEntry );
  7629. // Release the physical device RemoveLock. The original DO RemoveLock will
  7630. // be released when the IRP is removed from the queue.
  7631. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7632. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  7633. return(STATUS_PENDING);
  7634. }
  7635. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  7636. }
  7637. *nextIrpStack = *currentIrpStack;
  7638. nextIrpStack->Parameters.DeviceIoControl.IoControlCode =
  7639. IOCTL_DISK_GET_DRIVE_LAYOUT;
  7640. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7641. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7642. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  7643. // Perform unrestricted release
  7644. case IOCTL_DISK_CLUSTER_RELEASE:
  7645. CDLOG( "IoctlClusterRelease(%p): sig %08x", DeviceObject, deviceExtension->Signature );
  7646. ClusDiskPrint((3,
  7647. "[ClusDisk] Release on signature %lx.\n",
  7648. deviceExtension->Signature ));
  7649. physicalDisk->ReserveTimer = 0;
  7650. *nextIrpStack = *currentIrpStack;
  7651. nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_DISK_RELEASE;
  7652. Irp->IoStatus.Status = STATUS_SUCCESS;
  7653. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7654. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7655. status = IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  7656. ASSERT( status != STATUS_PENDING );
  7657. return(STATUS_SUCCESS);
  7658. // Check if this is the root device
  7659. case IOCTL_DISK_CLUSTER_ROOT:
  7660. if ( deviceExtension->BusType == RootBus ) {
  7661. status = STATUS_SUCCESS;
  7662. } else {
  7663. status = STATUS_INVALID_DEVICE_REQUEST;
  7664. }
  7665. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7666. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7667. Irp->IoStatus.Status = status;
  7668. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7669. return(status);
  7670. // Check if low-level miniport driver support cluster devices.
  7671. case IOCTL_DISK_CLUSTER_NOT_CLUSTER_CAPABLE:
  7672. //
  7673. // Make sure there is no input/output data buffer.
  7674. //
  7675. if ( Irp->AssociatedIrp.SystemBuffer != NULL ) {
  7676. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7677. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7678. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  7679. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7680. return(STATUS_INVALID_PARAMETER);
  7681. }
  7682. //
  7683. // Verifier found a problem with the original code. The status returned
  7684. // wasn't the same as Irp->IoStatus.Status. The IRP status was always
  7685. // success, but the dispatch routine sometimes returned an error. This
  7686. // seems to work but verifier says this is invalid. When I changed the code
  7687. // to update the IRP status with the same returned status, new drives
  7688. // couldn't be seen. This is because the user mode component uses this
  7689. // IOCTL to indicate the disk is NOT cluster capable, so the user mode
  7690. // code looked for a failure to incidate a cluster disk.
  7691. //
  7692. //
  7693. // IsDiskClusterCapable always returns TRUE ???
  7694. //
  7695. status = IsDiskClusterCapable ( deviceExtension->ScsiAddress.PortNumber,
  7696. &isCapable);
  7697. //
  7698. // Fix for IBM. The Win2000 2195 code returned from this IOCTL the status
  7699. // of the SCSI miniport IOCTL. This was returned to DeviceIoControl rather
  7700. // than the status in the IRP. Changed to make the behavior the same as
  7701. // Win20000 2195.
  7702. //
  7703. //
  7704. // If the SCSI miniport IOCTL succeeds, we return success -- meaning we should
  7705. // *not* use this disk. If any of the routines failed while trying to issue
  7706. // the SCSI miniport IOCTL (including issuing the SCSI miniport IOCTL itself),
  7707. // then we return failure -- meaning we *should* use this disk.
  7708. //
  7709. Irp->IoStatus.Status = status;
  7710. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7711. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7712. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  7713. return(status);
  7714. // Test if the Cluster Disk Filter driver is part of driver stack.
  7715. case IOCTL_DISK_CLUSTER_NT4_CAPABLE:
  7716. //
  7717. // 2000/02/05: stevedz - start failing this IOCTL.
  7718. //
  7719. status = STATUS_INVALID_DEVICE_REQUEST;
  7720. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7721. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7722. Irp->IoStatus.Status = status;
  7723. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7724. return(status);
  7725. case IOCTL_DISK_CLUSTER_WAIT_FOR_CLEANUP:
  7726. {
  7727. ULONG waitTimeInSeconds;
  7728. if ( currentIrpStack->Parameters.DeviceIoControl.InputBufferLength <
  7729. sizeof(ULONG) || Irp->AssociatedIrp.SystemBuffer == NULL) {
  7730. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7731. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7732. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  7733. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7734. return(STATUS_INVALID_PARAMETER);
  7735. }
  7736. waitTimeInSeconds = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
  7737. CDLOG( "IoctlWaitForCleanup(%p): Entry waitTime %d second(s)",
  7738. DeviceObject,
  7739. waitTimeInSeconds );
  7740. waitTime.QuadPart = (LONGLONG)waitTimeInSeconds * -(10000*1000);
  7741. status = KeWaitForSingleObject(
  7742. &physicalDisk->Event,
  7743. Suspended,
  7744. KernelMode,
  7745. FALSE,
  7746. &waitTime);
  7747. //
  7748. // Reset the event in case of timeout.
  7749. // [HACKHACK] should we do this?
  7750. // No. If Offline worker is stuck somewhere, we better
  7751. // go and debug the problem, rather then return success
  7752. // and wait for the offline worker to do nasty things
  7753. // behind our backs
  7754. //
  7755. // KeSetEvent( &physicalExtension->Event, 0, FALSE );
  7756. if (status == STATUS_TIMEOUT) {
  7757. //
  7758. // NT_SUCCESS considers STATUS_TIMEOUT as a success code
  7759. // we need something stronger
  7760. //
  7761. status = STATUS_IO_TIMEOUT;
  7762. }
  7763. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7764. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7765. Irp->IoStatus.Status = status;
  7766. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7767. CDLOG( "IoctlWaitForCleanup(%p): Exit => %!status!",
  7768. DeviceObject,
  7769. status );
  7770. return(status);
  7771. }
  7772. case IOCTL_DISK_CLUSTER_TEST:
  7773. CDLOG( "IoctlDiskClusterTest(%p)", DeviceObject );
  7774. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7775. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7776. Irp->IoStatus.Status = STATUS_SUCCESS;
  7777. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7778. return(STATUS_SUCCESS);
  7779. case IOCTL_VOLUME_IS_CLUSTERED:
  7780. //
  7781. // Look at the reserve timer. If reserved, this is a clustered disk.
  7782. //
  7783. if ( physicalDisk->ReserveTimer != 0 ) {
  7784. status = STATUS_SUCCESS;
  7785. } else {
  7786. status = STATUS_UNSUCCESSFUL;
  7787. }
  7788. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7789. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7790. Irp->IoStatus.Status = status;
  7791. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7792. return(status);
  7793. case IOCTL_DISK_CLUSTER_VOLUME_TEST:
  7794. if ( deviceExtension->PhysicalDevice == DeviceObject ) {
  7795. status = STATUS_ILLEGAL_FUNCTION;
  7796. } else {
  7797. status = STATUS_SUCCESS;
  7798. }
  7799. CDLOG( "IoctlDiskClusterVolumeTest(%p) => %!status!", DeviceObject, status );
  7800. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7801. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7802. Irp->IoStatus.Status = status;
  7803. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7804. return(status);
  7805. case IOCTL_DISK_MEDIA_REMOVAL: {
  7806. PPREVENT_MEDIA_REMOVAL mediaRemoval = Irp->AssociatedIrp.SystemBuffer;
  7807. if ( currentIrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(PREVENT_MEDIA_REMOVAL) ||
  7808. NULL == mediaRemoval ) {
  7809. ClusDiskPrint(( 1,
  7810. "[ClusDisk] IOCTL_DISK_MEDIA_REMOVAL invalid parameter, Signature = %08lX \n",
  7811. physicalDisk->Signature ));
  7812. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7813. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7814. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  7815. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7816. return(STATUS_INVALID_PARAMETER);
  7817. }
  7818. ClusDiskPrint(( 3,
  7819. "[ClusDisk] IOCTL_DISK_MEDIA_REMOVAL: received, Signature = %08lX OfflinePending = %d PreventMedia = %d \n",
  7820. physicalDisk->Signature,
  7821. physicalDisk->OfflinePending,
  7822. mediaRemoval->PreventMediaRemoval ));
  7823. #if 0 // Remove for now. If we eject we cannot provent pagefile creation.
  7824. if ( physicalDisk->OfflinePending && !mediaRemoval->PreventMediaRemoval ) {
  7825. //
  7826. // When the disk resource gets an offline or terminate request, we set
  7827. // the OfflinePending flag. When the disk resource asks NTFS to dismount
  7828. // the volume (via FSCTL_DISMOUNT_VOLUME), the last thing NTFS does before
  7829. // returning from the dismount request is to send IOCTL_DISK_MEDIA_REMOVAL
  7830. // to unlock the media. When we get this IOCTL, mark the disk offline
  7831. // instead of waiting for the stop reserve request. This should close
  7832. // the window between the time the NTFS dismount occurs and the time
  7833. // we previously marked the disk offline in stop reserve handler.
  7834. //
  7835. // physicalDisk->DiskState = DiskOffline;
  7836. OFFLINE_DISK( physicalDisk );
  7837. ClusDiskPrint(( 1,
  7838. "[ClusDisk] IOCTL_DISK_MEDIA_REMOVAL: Disk state set to offline, Signature = %08lX \n",
  7839. physicalDisk->Signature ));
  7840. physicalDisk->OfflinePending = FALSE;
  7841. }
  7842. #endif
  7843. // FALL THROUGH
  7844. IoSkipCurrentIrpStackLocation( Irp );
  7845. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7846. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7847. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  7848. }
  7849. // **************************
  7850. // The following IOCTL's should not be blocked by stalled disks
  7851. // **************************
  7852. // Reset an individual disk on a shared bus. Not implemented.
  7853. //case IOCTL_DISK_CLUSTER_DISK_RESET:
  7854. case IOCTL_STORAGE_GET_HOTPLUG_INFO:
  7855. case IOCTL_STORAGE_RESET_BUS:
  7856. case IOCTL_STORAGE_BREAK_RESERVATION:
  7857. case IOCTL_STORAGE_QUERY_PROPERTY:
  7858. case IOCTL_STORAGE_GET_MEDIA_TYPES:
  7859. case IOCTL_STORAGE_GET_MEDIA_TYPES_EX:
  7860. case IOCTL_STORAGE_FIND_NEW_DEVICES:
  7861. case IOCTL_STORAGE_GET_DEVICE_NUMBER:
  7862. case IOCTL_STORAGE_MEDIA_REMOVAL:
  7863. case IOCTL_STORAGE_CHECK_VERIFY:
  7864. case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
  7865. case IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY:
  7866. case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
  7867. case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME:
  7868. case IOCTL_MOUNTDEV_LINK_CREATED:
  7869. case IOCTL_MOUNTDEV_LINK_DELETED:
  7870. case IOCTL_DISK_GET_DRIVE_LAYOUT:
  7871. case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
  7872. case IOCTL_DISK_CHECK_VERIFY:
  7873. case IOCTL_DISK_GET_DRIVE_GEOMETRY:
  7874. case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
  7875. case IOCTL_DISK_GET_PARTITION_INFO:
  7876. case IOCTL_DISK_GET_PARTITION_INFO_EX:
  7877. case IOCTL_DISK_IS_WRITABLE:
  7878. case IOCTL_VOLUME_ONLINE:
  7879. case IOCTL_VOLUME_OFFLINE:
  7880. case IOCTL_VOLUME_IS_OFFLINE:
  7881. case IOCTL_DISK_GET_LENGTH_INFO:
  7882. case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
  7883. case IOCTL_PARTMGR_QUERY_DISK_SIGNATURE:
  7884. if ( physicalDisk->DiskState == DiskStalled ) {
  7885. ClusDiskPrint((
  7886. 1,
  7887. "[ClusDisk] Passthru (when stalled) IOCTL = %08lX, Signature = %08lX .\n",
  7888. currentIrpStack->Parameters.DeviceIoControl.IoControlCode,
  7889. deviceExtension->Signature));
  7890. //
  7891. // Set current stack back one.
  7892. //
  7893. IoSkipCurrentIrpStackLocation( Irp );
  7894. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7895. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7896. //
  7897. // Pass unrecognized device control requests
  7898. // down to next driver layer.
  7899. //
  7900. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  7901. } // othwerwise fall through
  7902. // FALL THROUGH
  7903. //
  7904. // N.B. The following IOCTLs are used a lot in booting and by WINDISK.
  7905. // We treat them special in that they will passed through to the
  7906. // next level driver. I.E. We don't check if we should verify the attach!
  7907. //
  7908. //
  7909. // None yet found...
  7910. //case IOCTL_xxx
  7911. //
  7912. // Hold the I/O request if we are stalled.
  7913. // First check for hint - i.e. with no lock held.
  7914. //
  7915. if ( deviceExtension->DiskState == DiskStalled ) {
  7916. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  7917. //
  7918. // Check again, with lock held - this one is valid!
  7919. //
  7920. if ( deviceExtension->DiskState == DiskStalled ) {
  7921. ClusDiskPrint((1,"[ClusDisk] HoldCTL - pending IRP %p, target %p \n",
  7922. Irp, DeviceObject ));
  7923. InsertTailList( &deviceExtension->HoldIO,
  7924. &Irp->Tail.Overlay.ListEntry );
  7925. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  7926. // Release only the physical device RemoveLock. The original DO
  7927. // will be released when the IRP is removed from the queue.
  7928. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7929. return(STATUS_PENDING);
  7930. }
  7931. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  7932. }
  7933. IoSkipCurrentIrpStackLocation( Irp );
  7934. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7935. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7936. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  7937. default:
  7938. //
  7939. // For all other requests, we must be online to process the request.
  7940. //
  7941. //
  7942. // Before returning failure, first verify device attachment. This
  7943. // means that if the device is attached check if it should be detached.
  7944. // If the device does get detached, then allow IO to go through.
  7945. //
  7946. if ( !deviceExtension->AttachValid ) {
  7947. targetDeviceObject = deviceExtension->TargetDeviceObject;
  7948. ClusDiskPrint((
  7949. 1,
  7950. "[ClusDisk] Attach is not valid. IOCTL = %lx, check if we need to detach.\n",
  7951. currentIrpStack->Parameters.DeviceIoControl.IoControlCode));
  7952. if ( !ClusDiskVerifyAttach( DeviceObject ) ) {
  7953. ClusDiskPrint((
  7954. 1,
  7955. "[ClusDisk] We detached.\n"));
  7956. IoSkipCurrentIrpStackLocation( Irp );
  7957. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7958. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7959. return IoCallDriver(targetDeviceObject,
  7960. Irp);
  7961. }
  7962. if ( deviceExtension->AttachValid ) {
  7963. ClusDiskPrint((
  7964. 1,
  7965. "[ClusDisk] Attach is now valid, Signature = %08lX .\n",
  7966. deviceExtension->Signature));
  7967. }
  7968. }
  7969. if ( physicalDisk->DiskState != DiskOnline ) {
  7970. #if 0
  7971. // This seems like a good idea, but needs more testing. We might miss
  7972. // setting up irp completion routine.
  7973. //
  7974. // Try cracking the control code and letting any IOCTLs through that
  7975. // do not have write access set.
  7976. //
  7977. access = ACCESS_FROM_CTL_CODE(currentIrpStack->Parameters.DeviceIoControl.IoControlCode);
  7978. if ( !(access & FILE_WRITE_ACCESS) ) {
  7979. ClusDiskPrint((
  7980. 3,
  7981. "[ClusDisk] Sending IOCTL = %08lX based on access %02X, Signature = %08lX \n",
  7982. currentIrpStack->Parameters.DeviceIoControl.IoControlCode,
  7983. access,
  7984. deviceExtension->Signature));
  7985. IoSkipCurrentIrpStackLocation( Irp );
  7986. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7987. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7988. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  7989. }
  7990. #endif
  7991. // All other IOCTL's fall through and are failed because disk is offline.
  7992. ClusDiskPrint((
  7993. 1,
  7994. "[ClusDisk] Disk not online: Rejected IOCTL = %08lX, Signature = %08lX \n",
  7995. currentIrpStack->Parameters.DeviceIoControl.IoControlCode,
  7996. deviceExtension->Signature));
  7997. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  7998. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  7999. Irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE;
  8000. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8001. return(STATUS_DEVICE_OFF_LINE);
  8002. }
  8003. switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
  8004. case IOCTL_DISK_FIND_NEW_DEVICES:
  8005. //
  8006. // Copy current stack to next stack.
  8007. //
  8008. IoCopyCurrentIrpStackLocationToNext( Irp );
  8009. //
  8010. // Ask to be called back during request completion.
  8011. // Pass current disk count as context.
  8012. //
  8013. //
  8014. IoSetCompletionRoutine(Irp,
  8015. ClusDiskNewDiskCompletion,
  8016. (PVOID)( UlongToPtr( IoGetConfigurationInformation()->DiskCount ) ),
  8017. TRUE, // Invoke on success
  8018. TRUE, // Invoke on error
  8019. TRUE); // Invoke on cancel
  8020. //
  8021. // Call target driver.
  8022. //
  8023. // The completion routine will release the RemoveLocks.
  8024. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  8025. case IOCTL_DISK_SET_DRIVE_LAYOUT:
  8026. case IOCTL_DISK_SET_DRIVE_LAYOUT_EX:
  8027. CDLOG( "IoctlDiskSetDriveLayout(%p)", DeviceObject );
  8028. //
  8029. // Copy current stack to next stack.
  8030. //
  8031. IoCopyCurrentIrpStackLocationToNext( Irp );
  8032. //
  8033. // Ask to be called back during request completion.
  8034. //
  8035. IoSetCompletionRoutine(Irp,
  8036. ClusDiskSetLayoutCompletion,
  8037. DeviceObject,
  8038. TRUE, // Invoke on success
  8039. TRUE, // Invoke on error
  8040. TRUE); // Invoke on cancel
  8041. //
  8042. // Call target driver.
  8043. //
  8044. // The completion routine will release the RemoveLocks.
  8045. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  8046. default:
  8047. //
  8048. // Set current stack back one.
  8049. //
  8050. IoSkipCurrentIrpStackLocation( Irp );
  8051. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  8052. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  8053. //
  8054. // Pass unrecognized device control requests
  8055. // down to next driver layer.
  8056. //
  8057. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  8058. }
  8059. }
  8060. } // ClusDiskDeviceControl
  8061. NTSTATUS
  8062. ClusDiskRootDeviceControl(
  8063. PDEVICE_OBJECT DeviceObject,
  8064. PIRP Irp
  8065. )
  8066. /*++
  8067. Routine Description:
  8068. This device control dispatcher handles only the cluster disk IOCTLs
  8069. for the root device. This is ATTACH and DETACH.
  8070. Important: Two RemoveLocks will be held on entry to this function.
  8071. One RemoveLock for the original DO and one for the associated physical
  8072. device.
  8073. Arguments:
  8074. DeviceObject - Context for the activity.
  8075. Irp - The device control argument block.
  8076. Return Value:
  8077. Status is returned.
  8078. --*/
  8079. {
  8080. PCLUS_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  8081. PCLUS_DEVICE_EXTENSION physicalDisk =
  8082. deviceExtension->PhysicalDevice->DeviceExtension;
  8083. // Save pointers to the original RemoveLocks as the device extensions
  8084. // may change in this routine.
  8085. PCLUS_DEVICE_EXTENSION lockedDeviceExtension = deviceExtension;
  8086. PCLUS_DEVICE_EXTENSION lockedPhysicalDisk = physicalDisk;
  8087. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  8088. PDEVICE_OBJECT targetDeviceObject;
  8089. NTSTATUS status = STATUS_SUCCESS;
  8090. ULONG signature;
  8091. PULONG inputData = Irp->AssociatedIrp.SystemBuffer;
  8092. ULONG inputSize = currentIrpStack->Parameters.DeviceIoControl.InputBufferLength;
  8093. ULONG outputSize = currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
  8094. KIRQL irql;
  8095. BOOLEAN isCapable;
  8096. BOOLEAN newPhysLockAcquired;
  8097. UCHAR portNumber;
  8098. PLIST_ENTRY listEntry;
  8099. PIRP irp;
  8100. switch (currentIrpStack->Parameters.DeviceIoControl.IoControlCode) {
  8101. // Stall I/O's until further notice
  8102. case IOCTL_DISK_CLUSTER_HOLD_IO:
  8103. CDLOG( "RootCluserHoldIo(%p)", DeviceObject );
  8104. // First - let's flush the file buffers!
  8105. // - one of these device objects should be the physical device object
  8106. #if 0
  8107. // Flushing the file buffers can take a while... we'll skip it for
  8108. // now. Until we can come up with a good way of doing it.
  8109. targetDeviceObject = DeviceObject->DriverObject->DeviceObject;
  8110. while ( targetDeviceObject ) {
  8111. deviceExtension = targetDeviceObject->DeviceExtension;
  8112. if ( deviceExtension->DiskState == DiskOnline ) {
  8113. LockVolumes( deviceExtension );
  8114. }
  8115. targetDeviceObject = targetDeviceObject->NextDevice;
  8116. }
  8117. #endif
  8118. ACQUIRE_SHARED( &ClusDiskDeviceListLock );
  8119. // First - let's capture the file handles to
  8120. // volume objects. We will not be able to do it
  8121. // if the device is stalled or offline, so we will not be able
  8122. // to dismount
  8123. targetDeviceObject = DeviceObject->DriverObject->DeviceObject;
  8124. while ( targetDeviceObject ) {
  8125. deviceExtension = targetDeviceObject->DeviceExtension;
  8126. if ( (deviceExtension->PhysicalDevice == targetDeviceObject) &&
  8127. (!deviceExtension->Detached) &&
  8128. (deviceExtension->DiskState == DiskOnline) )
  8129. {
  8130. //
  8131. // Disk has to be online,
  8132. // If it is offline, OpenFile will fail - not if FILE_WRITE_ATTRIBUTES used...
  8133. // It it is stalled OpenFile may stall
  8134. //
  8135. ProcessDelayedWorkSynchronous( targetDeviceObject, ClusDiskpOpenFileHandles, NULL );
  8136. }
  8137. targetDeviceObject = targetDeviceObject->NextDevice;
  8138. }
  8139. //
  8140. // Now set their states to Stalled!
  8141. // - some of these device objects should be the physical device object
  8142. // - skip those...
  8143. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  8144. targetDeviceObject = DeviceObject->DriverObject->DeviceObject;
  8145. while ( targetDeviceObject ) {
  8146. deviceExtension = targetDeviceObject->DeviceExtension;
  8147. physicalDisk = deviceExtension->PhysicalDevice->DeviceExtension;
  8148. if ( (deviceExtension != physicalDisk) &&
  8149. (!deviceExtension->Detached) &&
  8150. (physicalDisk->DiskState == DiskOnline) ) {
  8151. deviceExtension->DiskState = DiskStalled;
  8152. }
  8153. targetDeviceObject = targetDeviceObject->NextDevice;
  8154. }
  8155. //
  8156. // Now set the state for the physical device objects!
  8157. targetDeviceObject = DeviceObject->DriverObject->DeviceObject;
  8158. while ( targetDeviceObject ) {
  8159. deviceExtension = targetDeviceObject->DeviceExtension;
  8160. physicalDisk = deviceExtension->PhysicalDevice->DeviceExtension;
  8161. if ( (deviceExtension == physicalDisk) &&
  8162. (!deviceExtension->Detached) &&
  8163. (physicalDisk->DiskState == DiskOnline) ) {
  8164. physicalDisk->DiskState = DiskStalled;
  8165. }
  8166. targetDeviceObject = targetDeviceObject->NextDevice;
  8167. }
  8168. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  8169. RELEASE_SHARED( &ClusDiskDeviceListLock );
  8170. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8171. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8172. Irp->IoStatus.Status = STATUS_SUCCESS;
  8173. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  8174. return(STATUS_SUCCESS);
  8175. // Resume stalled I/O's
  8176. case IOCTL_DISK_CLUSTER_RESUME_IO:
  8177. CDLOG( "RootCluserResumeIo(%p)", DeviceObject );
  8178. ClusDiskResumeIO( DeviceObject );
  8179. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8180. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8181. Irp->IoStatus.Status = STATUS_SUCCESS;
  8182. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  8183. return(STATUS_SUCCESS);
  8184. case IOCTL_DISK_CLUSTER_ARBITRATION_ESCAPE:
  8185. if ( ARGUMENT_PRESENT( inputData ) &&
  8186. inputSize >= sizeof(ARBITRATION_READ_WRITE_PARAMS) )
  8187. {
  8188. BOOLEAN success;
  8189. PDEVICE_OBJECT physicalDevice;
  8190. PARBITRATION_READ_WRITE_PARAMS params =
  8191. (PARBITRATION_READ_WRITE_PARAMS)inputData;
  8192. // Can't hold the spinlock and then try to acquire the resource lock or the system
  8193. // might deadlock.
  8194. // KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  8195. success = AttachedDevice( params->Signature, &physicalDevice );
  8196. // KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  8197. if( success ) {
  8198. PCLUS_DEVICE_EXTENSION tempDeviceExtension = physicalDevice->DeviceExtension;
  8199. // We have a new device here, acquire the RemoveLock if possible.
  8200. status = AcquireRemoveLock(&tempDeviceExtension->RemoveLock, Irp);
  8201. if ( !NT_SUCCESS(status) ) {
  8202. ClusDiskPrint((
  8203. 1,
  8204. "[ClusDisk] ClusDiskRootDeviceControl: AcquireRemoveLock for %p failed %08X \n",
  8205. tempDeviceExtension,
  8206. status));
  8207. } else {
  8208. status = ProcessArbitrationEscape(
  8209. physicalDevice->DeviceExtension,
  8210. inputData,
  8211. inputSize,
  8212. &outputSize);
  8213. if ( NT_SUCCESS(status) ) {
  8214. Irp->IoStatus.Information = outputSize;
  8215. }
  8216. ReleaseRemoveLock(&tempDeviceExtension->RemoveLock, Irp);
  8217. }
  8218. } else {
  8219. status = STATUS_NOT_FOUND;
  8220. }
  8221. } else {
  8222. status = STATUS_INVALID_PARAMETER;
  8223. }
  8224. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8225. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8226. Irp->IoStatus.Status = status;
  8227. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8228. return(status);
  8229. // Perform an attach to a device object, for a given signature
  8230. case IOCTL_DISK_CLUSTER_ATTACH:
  8231. if ( ARGUMENT_PRESENT( inputData ) &&
  8232. currentIrpStack->Parameters.DeviceIoControl.InputBufferLength >=
  8233. sizeof(ULONG) ) {
  8234. signature = inputData[0];
  8235. ClusDiskPrint((3,
  8236. "[ClusDisk] RootDeviceControl: attaching signature %08X\n",
  8237. signature));
  8238. CDLOG( "RootCluserAttach: sig %08x", signature );
  8239. status = ClusDiskTryAttachDevice( signature,
  8240. 0,
  8241. DeviceObject->DriverObject );
  8242. } else {
  8243. status = STATUS_INVALID_PARAMETER;
  8244. }
  8245. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8246. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8247. Irp->IoStatus.Status = status;
  8248. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8249. return(status);
  8250. // Perform a detach from a device object, for a given signature
  8251. case IOCTL_DISK_CLUSTER_DETACH:
  8252. if ( ARGUMENT_PRESENT( inputData ) &&
  8253. currentIrpStack->Parameters.DeviceIoControl.InputBufferLength >=
  8254. sizeof(ULONG) ) {
  8255. signature = inputData[0];
  8256. CDLOG( "RootCluserDetach: sig %08x", signature );
  8257. ClusDiskPrint((3,
  8258. "[ClusDisk] RootDeviceControl: detaching signature %08X\n",
  8259. signature));
  8260. status = ClusDiskDetachDevice( signature,
  8261. DeviceObject->DriverObject );
  8262. } else {
  8263. status = STATUS_INVALID_PARAMETER;
  8264. }
  8265. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8266. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8267. Irp->IoStatus.Status = status;
  8268. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8269. return(status);
  8270. case IOCTL_DISK_CLUSTER_ATTACH_LIST: {
  8271. //
  8272. // Attaches a signature list to the system. NO resets will occur. If we
  8273. // really need to make sure the device attaches, then use the normal
  8274. // attach IOCTL. This IOCTL is mainly used by cluster setup.
  8275. //
  8276. status = AttachSignatureList( DeviceObject,
  8277. inputData,
  8278. currentIrpStack->Parameters.DeviceIoControl.InputBufferLength
  8279. );
  8280. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8281. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8282. Irp->IoStatus.Status = status;
  8283. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8284. return(status);
  8285. }
  8286. // Detach from all the signatures in the list.
  8287. case IOCTL_DISK_CLUSTER_DETACH_LIST: {
  8288. status = DetachSignatureList( DeviceObject,
  8289. inputData,
  8290. currentIrpStack->Parameters.DeviceIoControl.InputBufferLength
  8291. );
  8292. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8293. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8294. Irp->IoStatus.Status = status;
  8295. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8296. return(status);
  8297. }
  8298. // Start the reservation timer
  8299. case IOCTL_DISK_CLUSTER_START_RESERVE:
  8300. CDLOG( "RootStartReserve(%p)", DeviceObject );
  8301. if ( RootDeviceObject == NULL ) {
  8302. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8303. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8304. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  8305. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  8306. return(STATUS_INVALID_DEVICE_REQUEST);
  8307. }
  8308. if ( currentIrpStack->FileObject->FsContext ) {
  8309. status = STATUS_DUPLICATE_OBJECTID;
  8310. } else if ( ARGUMENT_PRESENT(inputData) &&
  8311. currentIrpStack->Parameters.DeviceIoControl.InputBufferLength >=
  8312. sizeof(ULONG) ) {
  8313. status = VerifyArbitrationArgumentsIfAny(
  8314. inputData,
  8315. currentIrpStack->Parameters.DeviceIoControl.InputBufferLength);
  8316. if (!NT_SUCCESS(status) ) {
  8317. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8318. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8319. Irp->IoStatus.Status = status;
  8320. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8321. return(status);
  8322. }
  8323. signature = inputData[0];
  8324. // Acquire the device list lock first, then the spinlock. This will prevent deadlock.
  8325. ACQUIRE_SHARED( &ClusDiskDeviceListLock );
  8326. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  8327. if ( MatchDevice(signature, &targetDeviceObject) &&
  8328. targetDeviceObject ) {
  8329. status = EnableHaltProcessing( &irql );
  8330. if ( NT_SUCCESS(status) ) {
  8331. physicalDisk = targetDeviceObject->DeviceExtension;
  8332. status = AcquireRemoveLock(&physicalDisk->RemoveLock, Irp);
  8333. if ( !NT_SUCCESS(status) ) {
  8334. ClusDiskPrint((
  8335. 1,
  8336. "[ClusDisk] ClusDiskRootDeviceControl: AcquireRemoveLock for %p failed %08X \n",
  8337. physicalDisk,
  8338. status));
  8339. status = STATUS_NO_SUCH_FILE;
  8340. } else {
  8341. ProcessArbitrationArgumentsIfAny(
  8342. physicalDisk,
  8343. inputData,
  8344. currentIrpStack->Parameters.DeviceIoControl.InputBufferLength);
  8345. ClusDiskPrint((3,
  8346. "[ClusDisk] Start reservations on signature %lx.\n",
  8347. physicalDisk->Signature ));
  8348. currentIrpStack->FileObject->FsContext = targetDeviceObject;
  8349. CDLOG("RootCtl: IncRef(%p)", targetDeviceObject );
  8350. ObReferenceObject( targetDeviceObject );
  8351. physicalDisk->ReserveTimer = RESERVE_TIMER;
  8352. physicalDisk->ReserveFailure = 0;
  8353. physicalDisk->PerformReserves = TRUE;
  8354. status = STATUS_SUCCESS;
  8355. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  8356. }
  8357. }
  8358. } else {
  8359. status = STATUS_NO_SUCH_FILE;
  8360. }
  8361. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  8362. RELEASE_SHARED( &ClusDiskDeviceListLock );
  8363. } else {
  8364. status = STATUS_INVALID_PARAMETER;
  8365. }
  8366. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8367. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8368. Irp->IoStatus.Status = status;
  8369. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8370. return(status);
  8371. // Stop the reservation timer
  8372. case IOCTL_DISK_CLUSTER_STOP_RESERVE:
  8373. CDLOG( "RootStopReserve(%p)", DeviceObject );
  8374. if ( (RootDeviceObject == NULL) ||
  8375. (deviceExtension->BusType != RootBus) ) {
  8376. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8377. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8378. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  8379. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  8380. return(STATUS_INVALID_DEVICE_REQUEST);
  8381. }
  8382. newPhysLockAcquired = FALSE;
  8383. if ( currentIrpStack->FileObject->FsContext ) {
  8384. //
  8385. // GorN Oct/13/1999. PnP can come and rip out the device object
  8386. // we stored in the FsContext. It doesn't delete it, since we have a reference
  8387. // to it, but we will not be able to use it, since the objects underneath this one
  8388. // are destroyed.
  8389. //
  8390. // Our PnpRemoveDevice handler will zero out targetDevice field of the device
  8391. // extension, this will not eliminate the race completely, but will reduces the
  8392. // chance of this happening, since, usually, device removal comes first,
  8393. // we notify resmon and then it calls stop reserve.
  8394. //
  8395. // Chances that PnpRemoveDevice will come at exact moment resmon called ClusterStopReserve
  8396. // are smaller
  8397. //
  8398. targetDeviceObject = (PDEVICE_OBJECT)currentIrpStack->FileObject->FsContext;
  8399. physicalDisk = targetDeviceObject->DeviceExtension;
  8400. CDLOG( "RootStopReserve: FsContext targetDO %p RemoveLock.IoCount %d",
  8401. targetDeviceObject,
  8402. physicalDisk->RemoveLock.Common.IoCount );
  8403. // We have a new device here, acquire the RemoveLock if possible.
  8404. status = AcquireRemoveLock(&physicalDisk->RemoveLock, Irp);
  8405. if ( !NT_SUCCESS(status) ) {
  8406. ClusDiskPrint((
  8407. 1,
  8408. "[ClusDisk] ClusDiskRootDeviceControl: AcquireRemoveLock for %p failed %08X \n",
  8409. physicalDisk,
  8410. status));
  8411. status = STATUS_INVALID_HANDLE;
  8412. } else {
  8413. ClusDiskPrint((3,
  8414. "[ClusDisk] IOCTL, stop reservations on signature %lx, disk state %s \n",
  8415. physicalDisk->Signature,
  8416. DiskStateToString( physicalDisk->DiskState ) ));
  8417. newPhysLockAcquired = TRUE;
  8418. IoAcquireCancelSpinLock( &irql );
  8419. KeAcquireSpinLockAtDpcLevel(&ClusDiskSpinLock);
  8420. physicalDisk->ReserveTimer = 0;
  8421. //
  8422. // Signal all waiting Irp's on the physical device extension.
  8423. //
  8424. while ( !IsListEmpty(&physicalDisk->WaitingIoctls) ) {
  8425. listEntry = RemoveHeadList(&physicalDisk->WaitingIoctls);
  8426. irp = CONTAINING_RECORD( listEntry,
  8427. IRP,
  8428. Tail.Overlay.ListEntry );
  8429. ClusDiskCompletePendingRequest(irp, STATUS_SUCCESS, physicalDisk);
  8430. }
  8431. KeReleaseSpinLockFromDpcLevel(&ClusDiskSpinLock);
  8432. IoReleaseCancelSpinLock( irql );
  8433. //
  8434. // This should not be done here.
  8435. // Cleaning FsContext here, will prevent ClusDiskCleanup
  8436. // from doing its work
  8437. //
  8438. // ObDereferenceObject(targetDeviceObject);
  8439. // CDLOG("RootCtl_DecRef(%p)", targetDeviceObject );
  8440. // currentIrpStack->FileObject->FsContext = NULL;
  8441. //
  8442. // Release the scsi device.
  8443. //
  8444. // [GorN] 10/04/1999. Why this release was commented out?
  8445. // [GorN] 10/13/1999. It was commented out, because it was causing an AV,
  8446. // if the device was removed by PnP
  8447. //
  8448. // 2000/02/05: stevedz - RemoveLocks should resolve this problem.
  8449. //
  8450. // The following "if" only reduces the chances of AV to occur, not
  8451. // eliminates it completely. TargetDeviceObject is zeroed out by our PnP
  8452. // handler when the device is removed
  8453. //
  8454. if (physicalDisk->TargetDeviceObject) {
  8455. ReleaseScsiDevice( physicalDisk );
  8456. }
  8457. ClusDiskPrint((3,
  8458. "[ClusDisk] IOCTL, stop reservations on signature %lx.\n",
  8459. physicalDisk->Signature ));
  8460. status = STATUS_SUCCESS;
  8461. }
  8462. } else {
  8463. status = STATUS_INVALID_HANDLE;
  8464. }
  8465. if (newPhysLockAcquired) {
  8466. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  8467. }
  8468. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8469. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8470. Irp->IoStatus.Status = status;
  8471. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8472. return(status);
  8473. // Aliveness check
  8474. case IOCTL_DISK_CLUSTER_ALIVE_CHECK:
  8475. CDLOG( "RootAliveCheck(%p)", DeviceObject );
  8476. if ( (RootDeviceObject == NULL) ||
  8477. (deviceExtension->BusType != RootBus) ) {
  8478. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8479. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8480. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  8481. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  8482. return(STATUS_INVALID_DEVICE_REQUEST);
  8483. }
  8484. IoAcquireCancelSpinLock( &irql );
  8485. KeAcquireSpinLockAtDpcLevel( &ClusDiskSpinLock );
  8486. // Indicate that we didn't acquire a third RemoveLock for the new physical device.
  8487. newPhysLockAcquired = FALSE;
  8488. if ( currentIrpStack->FileObject->FsContext ) {
  8489. targetDeviceObject = (PDEVICE_OBJECT)currentIrpStack->FileObject->FsContext;
  8490. physicalDisk = targetDeviceObject->DeviceExtension;
  8491. // We have a new device here, acquire the RemoveLock if possible.
  8492. status = AcquireRemoveLock(&physicalDisk->RemoveLock, Irp);
  8493. if ( !NT_SUCCESS(status) ) {
  8494. ClusDiskPrint((
  8495. 1,
  8496. "[ClusDisk] ClusDiskRootDeviceControl: AcquireRemoveLock for %p failed %08X \n",
  8497. physicalDisk,
  8498. status));
  8499. status = STATUS_FILE_DELETED;
  8500. } else {
  8501. newPhysLockAcquired = TRUE;
  8502. if ( physicalDisk->TargetDeviceObject == NULL ) {
  8503. status = STATUS_FILE_DELETED;
  8504. } else
  8505. if ( physicalDisk->ReserveFailure &&
  8506. (!NT_SUCCESS(physicalDisk->ReserveFailure)) ) {
  8507. status = physicalDisk->ReserveFailure;
  8508. } else {
  8509. //
  8510. // The device does not have to be 'online' to have been
  8511. // successfully arbitrated and being defended. However,
  8512. // the quorum device really should be 'online'...
  8513. //
  8514. if ( physicalDisk->ReserveTimer == 0 ) {
  8515. #if 0
  8516. ClusDiskPrint((
  8517. 1,
  8518. "[ClusDisk] RootDeviceControl, AliveCheck failed, signature %lx, state = %s, ReserveTimer = %lx.\n",
  8519. physicalDisk->Signature,
  8520. DiskStateToString( physicalDisk->DiskState ),
  8521. physicalDisk->ReserveTimer ));
  8522. #endif
  8523. status = STATUS_CANCELLED;
  8524. } else {
  8525. status = STATUS_SUCCESS;
  8526. }
  8527. }
  8528. }
  8529. } else {
  8530. status = STATUS_INVALID_HANDLE;
  8531. }
  8532. if ( status == STATUS_SUCCESS ) {
  8533. NTSTATUS newStatus;
  8534. newStatus = ClusDiskMarkIrpPending( Irp, ClusDiskIrpCancel );
  8535. if ( NT_SUCCESS( newStatus ) ) {
  8536. InsertTailList( &physicalDisk->WaitingIoctls,
  8537. &Irp->Tail.Overlay.ListEntry );
  8538. status = STATUS_PENDING;
  8539. // Release all RemoveLocks except the one where we queued the I/O. When the IRP
  8540. // is processed, the RemoveLock will be processed.
  8541. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8542. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8543. } else {
  8544. status = newStatus;
  8545. if (newPhysLockAcquired) {
  8546. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  8547. }
  8548. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8549. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8550. Irp->IoStatus.Status = status;
  8551. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8552. }
  8553. KeReleaseSpinLockFromDpcLevel( &ClusDiskSpinLock );
  8554. IoReleaseCancelSpinLock( irql );
  8555. } else {
  8556. KeReleaseSpinLockFromDpcLevel( &ClusDiskSpinLock );
  8557. IoReleaseCancelSpinLock( irql );
  8558. if (newPhysLockAcquired) {
  8559. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  8560. }
  8561. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8562. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8563. Irp->IoStatus.Status = status;
  8564. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8565. }
  8566. return(status);
  8567. // Check out what's happening
  8568. case IOCTL_DISK_CLUSTER_ACTIVE:
  8569. if ( (RootDeviceObject == NULL) ||
  8570. (deviceExtension->BusType != RootBus) ) {
  8571. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8572. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8573. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  8574. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  8575. return(STATUS_INVALID_DEVICE_REQUEST);
  8576. }
  8577. status = ClusDiskGetRunningDevices(
  8578. inputData,
  8579. currentIrpStack->Parameters.DeviceIoControl.OutputBufferLength
  8580. );
  8581. Irp->IoStatus.Status = status;
  8582. if ( NT_SUCCESS(status) ) {
  8583. Irp->IoStatus.Information = (inputData[0] + 1) * sizeof(ULONG);
  8584. }
  8585. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8586. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8587. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  8588. return(status);
  8589. // Check if device is Cluster Capable (performs normal SCSI operations)
  8590. // NB: Non-SCSI device must return success on this call!
  8591. case IOCTL_DISK_CLUSTER_NOT_CLUSTER_CAPABLE:
  8592. //
  8593. // Get the passed in device signature.
  8594. //
  8595. isCapable = TRUE; // Err on the side of being usable.
  8596. if ( ARGUMENT_PRESENT( inputData ) &&
  8597. currentIrpStack->Parameters.DeviceIoControl.InputBufferLength >=
  8598. sizeof(ULONG) ) {
  8599. signature = inputData[0];
  8600. status = GetScsiPortNumber( signature, &portNumber );
  8601. if ( NT_SUCCESS(status) &&
  8602. (portNumber != 0xff) ) {
  8603. status = IsDiskClusterCapable( portNumber,
  8604. &isCapable);
  8605. }
  8606. } else {
  8607. //
  8608. // Default is to fail this IOCTL, which allows us to use the device.
  8609. //
  8610. status = STATUS_UNSUCCESSFUL;
  8611. }
  8612. //
  8613. // Verifier found a problem with the original code. The status returned
  8614. // wasn't the same as Irp->IoStatus.Status. The IRP status was always
  8615. // success, but the dispatch routine sometimes returned an error. This
  8616. // seems to work but verifier says this is invalid. When I changed the code
  8617. // to update the IRP status with the same returned status, new drives
  8618. // couldn't be seen. This is because the user mode component uses this
  8619. // IOCTL to indicate the disk is NOT cluster capable, so the user mode
  8620. // code looked for a failure to incidate a cluster disk.
  8621. //
  8622. //
  8623. // Fix for IBM. The Win2000 2195 code returned from this IOCTL the status
  8624. // of the SCSI miniport IOCTL. This was returned to DeviceIoControl rather
  8625. // than the status in the IRP. Changed to make the behavior the same as
  8626. // Win20000 2195.
  8627. //
  8628. //
  8629. // If the SCSI miniport IOCTL succeeds, we return success. If any of the
  8630. // routines failed while trying to issue the SCSI miniport IOCTL (including
  8631. // issuing the SCSI miniport IOCTL itself), then we return failure.
  8632. //
  8633. Irp->IoStatus.Status = status;
  8634. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8635. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8636. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  8637. return(status);
  8638. default:
  8639. ReleaseRemoveLock(&lockedPhysicalDisk->RemoveLock, Irp);
  8640. ReleaseRemoveLock(&lockedDeviceExtension->RemoveLock, Irp);
  8641. Irp->IoStatus.Status = STATUS_ILLEGAL_FUNCTION;
  8642. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8643. return(STATUS_ILLEGAL_FUNCTION);
  8644. }
  8645. } // ClusDiskRootDeviceControl
  8646. NTSTATUS
  8647. ClusDiskShutdownFlush(
  8648. IN PDEVICE_OBJECT DeviceObject,
  8649. IN PIRP Irp
  8650. )
  8651. /*++
  8652. Routine Description:
  8653. This routine is called for a shutdown and flush IRPs. These are sent by the
  8654. system before it actually shuts down or when the file system does a flush.
  8655. Arguments:
  8656. DriverObject - Pointer to device object to being shutdown by system.
  8657. Irp - IRP involved.
  8658. Return Value:
  8659. NT Status
  8660. --*/
  8661. {
  8662. PCLUS_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  8663. PCLUS_DEVICE_EXTENSION physicalDisk =
  8664. deviceExtension->PhysicalDevice->DeviceExtension;
  8665. NTSTATUS status;
  8666. status = AcquireRemoveLock( &deviceExtension->RemoveLock, Irp);
  8667. if ( !NT_SUCCESS(status) ) {
  8668. ClusDiskPrint((
  8669. 1,
  8670. "[ClusDisk] ClusDiskShutdownFlush: AcquireRemoveLock for %p failed %08X \n",
  8671. deviceExtension,
  8672. status));
  8673. Irp->IoStatus.Status = status;
  8674. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8675. return status;
  8676. }
  8677. //
  8678. // Return error if device is our root device.
  8679. //
  8680. if ( deviceExtension->BusType == RootBus ) {
  8681. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  8682. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  8683. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8684. return(STATUS_INVALID_DEVICE_REQUEST);
  8685. }
  8686. if ( physicalDisk->DiskState != DiskOnline ) {
  8687. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  8688. Irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE;
  8689. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8690. return(STATUS_DEVICE_OFF_LINE);
  8691. }
  8692. //
  8693. // Set current stack back one.
  8694. //
  8695. IoSkipCurrentIrpStackLocation( Irp );
  8696. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  8697. return IoCallDriver(deviceExtension->TargetDeviceObject, Irp);
  8698. } // ClusDiskShutdownFlush()
  8699. NTSTATUS
  8700. ClusDiskNewDiskCompletion(
  8701. IN PDEVICE_OBJECT DeviceObject,
  8702. IN PIRP Irp,
  8703. IN PVOID Context
  8704. )
  8705. /*++
  8706. Routine Description:
  8707. This is the completion routine for IOCTL_DISK_FIND_NEW_DEVICES.
  8708. Arguments:
  8709. DeviceObject - Pointer to device object to being shutdown by system.
  8710. Irp - IRP involved.
  8711. Context - Previous disk count.
  8712. Return Value:
  8713. NTSTATUS
  8714. --*/
  8715. {
  8716. PCLUS_DEVICE_EXTENSION deviceExtension =
  8717. (PCLUS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
  8718. PCLUS_DEVICE_EXTENSION physicalDisk =
  8719. deviceExtension->PhysicalDevice->DeviceExtension;
  8720. //
  8721. // Find new disk devices and attach to disk and all of its partitions.
  8722. //
  8723. ClusDiskNextDisk = Context;
  8724. ClusDiskScsiInitialize(DeviceObject->DriverObject, Context, 1);
  8725. // There are two RemoveLocks held. Release them both.
  8726. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  8727. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  8728. if (Irp->PendingReturned) {
  8729. IoMarkIrpPending(Irp);
  8730. }
  8731. return Irp->IoStatus.Status;
  8732. } // ClusDiskNewDiskCompletion
  8733. NTSTATUS
  8734. ClusDiskSetLayoutCompletion(
  8735. IN PDEVICE_OBJECT DeviceObject,
  8736. IN PIRP Irp,
  8737. IN PVOID Context
  8738. )
  8739. /*++
  8740. Routine Description:
  8741. This is the completion routine for IOCTL_SET_DRIVE_LAYOUT_EX and
  8742. IOCTL_DISK_SET_DRIVE_LAYOUT_EX. This will routine will make sure
  8743. the cached drive layout info structure is updated.
  8744. Arguments:
  8745. DeviceObject - Pointer to device object
  8746. Irp - IRP involved.
  8747. Context - Not used
  8748. Return Value:
  8749. NTSTATUS
  8750. --*/
  8751. {
  8752. PCLUS_DEVICE_EXTENSION deviceExtension =
  8753. (PCLUS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
  8754. PCLUS_DEVICE_EXTENSION physicalDisk =
  8755. deviceExtension->PhysicalDevice->DeviceExtension;
  8756. PDRIVE_LAYOUT_INFORMATION driveLayoutInfo = NULL;
  8757. //
  8758. // Update the cached drive layout.
  8759. //
  8760. GetDriveLayout( physicalDisk->DeviceObject, &driveLayoutInfo, TRUE );
  8761. if ( driveLayoutInfo ) {
  8762. ExFreePool( driveLayoutInfo );
  8763. }
  8764. // There are two RemoveLocks held. Release them both.
  8765. ReleaseRemoveLock(&physicalDisk->RemoveLock, Irp);
  8766. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  8767. if (Irp->PendingReturned) {
  8768. IoMarkIrpPending(Irp);
  8769. }
  8770. return Irp->IoStatus.Status;
  8771. } // ClusDiskSetLayoutCompletion
  8772. BOOLEAN
  8773. ClusDiskAttached(
  8774. IN PDEVICE_OBJECT DeviceObject,
  8775. IN ULONG DiskNumber
  8776. )
  8777. /*++
  8778. Routine Description:
  8779. This routine checks if clusdisk in in the path.
  8780. Arguments:
  8781. DeviceObject - pointer the device object to check if ClusDisk is present.
  8782. DiskNumber - the disk number for this device object.
  8783. Return Value:
  8784. TRUE - if ClusDisk is attached.
  8785. FALSE - if ClusDisk is not attached.
  8786. --*/
  8787. {
  8788. PIRP irp;
  8789. PKEVENT event;
  8790. IO_STATUS_BLOCK ioStatusBlock;
  8791. NTSTATUS status;
  8792. WCHAR deviceNameBuffer[MAX_PARTITION_NAME_LENGTH];
  8793. UNICODE_STRING deviceNameString;
  8794. OBJECT_ATTRIBUTES objectAttributes;
  8795. HANDLE fileHandle;
  8796. HANDLE eventHandle;
  8797. if ( DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM ) {
  8798. //
  8799. // Create event for notification.
  8800. //
  8801. status = ZwCreateEvent( &eventHandle,
  8802. EVENT_ALL_ACCESS,
  8803. NULL,
  8804. SynchronizationEvent,
  8805. FALSE );
  8806. if ( !NT_SUCCESS(status) ) {
  8807. ClusDiskPrint((
  8808. 1,
  8809. "[ClusDisk] Failed to create event, status %lx\n",
  8810. status ));
  8811. return(TRUE);
  8812. }
  8813. //
  8814. // Open a file handle and perform the request
  8815. //
  8816. swprintf(deviceNameBuffer, DEVICE_PARTITION_NAME, DiskNumber, 0);
  8817. WCSLEN_ASSERT( deviceNameBuffer );
  8818. RtlInitUnicodeString(&deviceNameString,
  8819. deviceNameBuffer);
  8820. //
  8821. // Setup object attributes for the file to open.
  8822. //
  8823. InitializeObjectAttributes(
  8824. &objectAttributes,
  8825. &deviceNameString,
  8826. OBJ_CASE_INSENSITIVE,
  8827. NULL,
  8828. NULL
  8829. );
  8830. status = ZwCreateFile( &fileHandle,
  8831. FILE_READ_DATA,
  8832. &objectAttributes,
  8833. &ioStatusBlock,
  8834. NULL,
  8835. FILE_ATTRIBUTE_NORMAL,
  8836. FILE_SHARE_READ | FILE_SHARE_WRITE,
  8837. FILE_OPEN,
  8838. FILE_SYNCHRONOUS_IO_NONALERT,
  8839. NULL,
  8840. 0 );
  8841. ASSERT( status != STATUS_PENDING );
  8842. if ( !NT_SUCCESS(status) ) {
  8843. ClusDiskPrint((
  8844. 1,
  8845. "[ClusDisk] DiskAttached, failed to open file %ws. Error %lx.\n",
  8846. deviceNameBuffer,
  8847. status ));
  8848. ZwClose(eventHandle);
  8849. return(TRUE);
  8850. }
  8851. status = ZwDeviceIoControlFile( fileHandle,
  8852. eventHandle,
  8853. NULL,
  8854. NULL,
  8855. &ioStatusBlock,
  8856. IOCTL_DISK_CLUSTER_TEST,
  8857. NULL,
  8858. 0,
  8859. NULL,
  8860. 0 );
  8861. ZwClose( fileHandle );
  8862. ZwClose( eventHandle );
  8863. return(status == STATUS_SUCCESS);
  8864. }
  8865. event = ExAllocatePool( NonPagedPool,
  8866. sizeof(KEVENT) );
  8867. if ( event == NULL ) {
  8868. return(FALSE);
  8869. }
  8870. //
  8871. // Find out if ClusDisk is already in device stack.
  8872. //
  8873. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_CLUSTER_TEST,
  8874. DeviceObject,
  8875. NULL,
  8876. 0,
  8877. NULL,
  8878. 0,
  8879. FALSE,
  8880. event,
  8881. &ioStatusBlock);
  8882. if (!irp) {
  8883. ExFreePool( event );
  8884. ClusDiskPrint((
  8885. 1,
  8886. "[ClusDisk] Failed to build IRP to test for ClusDisk.\n"
  8887. ));
  8888. return(FALSE);
  8889. }
  8890. //
  8891. // Set the event object to the unsignaled state.
  8892. // It will be used to signal request completion.
  8893. //
  8894. KeInitializeEvent(event,
  8895. NotificationEvent,
  8896. FALSE);
  8897. status = IoCallDriver(DeviceObject,
  8898. irp);
  8899. if (status == STATUS_PENDING) {
  8900. KeWaitForSingleObject(event,
  8901. Suspended,
  8902. KernelMode,
  8903. FALSE,
  8904. NULL);
  8905. status = ioStatusBlock.Status;
  8906. }
  8907. ExFreePool( event );
  8908. if ( NT_SUCCESS(status) ) {
  8909. return(TRUE);
  8910. }
  8911. return(FALSE);
  8912. } // ClusDiskAttached
  8913. BOOLEAN
  8914. ClusDiskVerifyAttach(
  8915. PDEVICE_OBJECT DeviceObject
  8916. )
  8917. /*++
  8918. Routine Description:
  8919. This routine verifies if ClusDisk is attached, and whether it should be
  8920. detached.
  8921. Arguments:
  8922. DeviceObject - pointer to a ClusDisk device object to verify if it is
  8923. and should remain attached.
  8924. Return Value:
  8925. TRUE - if device is still attached.
  8926. FALSE - if device was detached.
  8927. --*/
  8928. {
  8929. NTSTATUS status;
  8930. PDEVICE_OBJECT deviceObject;
  8931. PCLUS_DEVICE_EXTENSION deviceExtension;
  8932. PDRIVE_LAYOUT_INFORMATION driveLayoutInfo;
  8933. UNICODE_STRING signatureName;
  8934. deviceExtension = DeviceObject->DeviceExtension;
  8935. //
  8936. // The following call really can't fail!
  8937. //
  8938. if ( !ClusDiskAttached( DeviceObject, deviceExtension->DiskNumber ) ) {
  8939. return(FALSE);
  8940. }
  8941. //
  8942. // Check if this device is a valid attachment.
  8943. //
  8944. if ( deviceExtension->AttachValid ) {
  8945. return(TRUE);
  8946. }
  8947. //
  8948. // Get device object for the physical (partition0) device.
  8949. //
  8950. deviceObject = deviceExtension->PhysicalDevice;
  8951. //
  8952. // Otherwise, we're not sure... verify it.
  8953. //
  8954. //
  8955. // Read the partition info to get the signature. If this device is
  8956. // a valid attachment then update the ClusDisk DeviceObject. Otherwise,
  8957. // detach or leave attached but in the UNKNOWN state.
  8958. //
  8959. driveLayoutInfo = ClusDiskGetPartitionInfo( deviceExtension );
  8960. if ( driveLayoutInfo != NULL ) {
  8961. deviceExtension->Signature = driveLayoutInfo->Signature;
  8962. if ( MatchDevice( driveLayoutInfo->Signature, NULL ) ) {
  8963. //
  8964. // We assume that the device object we have is for the partition0
  8965. // device object.
  8966. //
  8967. #if 0
  8968. ClusDiskPrint((
  8969. 1,
  8970. "[ClusDisk] We are going to attach signature %08lx to DevObj %p \n",
  8971. driveLayoutInfo->Signature,
  8972. DeviceObject ));
  8973. #endif
  8974. AddAttachedDevice( driveLayoutInfo->Signature,
  8975. deviceObject );
  8976. //
  8977. // Need to write disk info into the signatures list.
  8978. //
  8979. status = ClusDiskInitRegistryString(
  8980. &signatureName,
  8981. CLUSDISK_SIGNATURE_KEYNAME,
  8982. sizeof(CLUSDISK_SIGNATURE_KEYNAME)
  8983. );
  8984. if ( NT_SUCCESS(status) ) {
  8985. ClusDiskWriteDiskInfo( driveLayoutInfo->Signature,
  8986. deviceExtension->DiskNumber,
  8987. CLUSDISK_SIGNATURE_KEYNAME
  8988. );
  8989. ExFreePool( signatureName.Buffer );
  8990. }
  8991. } else {
  8992. ClusDiskDetachDevice( driveLayoutInfo->Signature,
  8993. DeviceObject->DriverObject
  8994. );
  8995. }
  8996. ExFreePool( driveLayoutInfo );
  8997. }
  8998. return(TRUE);
  8999. } // ClusDiskVerifyAttach
  9000. VOID
  9001. ClusDiskWriteDiskInfo(
  9002. IN ULONG Signature,
  9003. IN ULONG DiskNumber,
  9004. IN LPWSTR SubKeyName
  9005. )
  9006. /*++
  9007. Routine Description:
  9008. Write the disk name for the given signature.
  9009. Arguments:
  9010. Signature - the signature key to store the disk name under.
  9011. DiskNumber - the disk number to assign to the given signature. It is
  9012. assumed that this is always describing partition0 on the disk.
  9013. SubKeyName - the clusdisk parameters subkey name in which to write
  9014. this information.
  9015. Return Value:
  9016. None.
  9017. --*/
  9018. {
  9019. UNICODE_STRING keyName;
  9020. WCHAR keyNameBuffer[MAXIMUM_FILENAME_LENGTH];
  9021. WCHAR signatureBuffer[64];
  9022. HANDLE signatureHandle;
  9023. OBJECT_ATTRIBUTES objectAttributes;
  9024. UNICODE_STRING name;
  9025. NTSTATUS status;
  9026. keyName.Length = 0;
  9027. keyName.MaximumLength = sizeof( keyNameBuffer );
  9028. keyName.Buffer = keyNameBuffer;
  9029. RtlAppendUnicodeToString( &keyName, ClusDiskRegistryPath.Buffer );
  9030. RtlAppendUnicodeToString( &keyName, SubKeyName );
  9031. swprintf( signatureBuffer, L"\\%08lX", Signature );
  9032. WCSLEN_ASSERT( signatureBuffer );
  9033. RtlAppendUnicodeToString( &keyName, signatureBuffer );
  9034. //
  9035. // Setup the object attributes for the Parameters\SubKeyName\xyz key.
  9036. //
  9037. InitializeObjectAttributes(
  9038. &objectAttributes,
  9039. &keyName,
  9040. OBJ_CASE_INSENSITIVE,
  9041. NULL,
  9042. NULL
  9043. );
  9044. //
  9045. // Open Parameters\SubKeyName\xyz Key.
  9046. //
  9047. status = ZwOpenKey(
  9048. &signatureHandle,
  9049. KEY_READ | KEY_WRITE,
  9050. &objectAttributes
  9051. );
  9052. if ( !NT_SUCCESS(status) ) {
  9053. ClusDiskPrint((
  9054. 1,
  9055. "[ClusDisk] WriteDiskInfo: Failed to open %wZ registry key. Status: %lx\n",
  9056. &keyName,
  9057. status
  9058. ));
  9059. return;
  9060. }
  9061. //
  9062. // Write the disk name.
  9063. //
  9064. status = ClusDiskAddDiskName( signatureHandle, DiskNumber );
  9065. ZwClose( signatureHandle );
  9066. return;
  9067. } // ClusDiskWriteDiskInfo
  9068. NTSTATUS
  9069. GetDriveLayout(
  9070. IN PDEVICE_OBJECT DeviceObject,
  9071. OUT PDRIVE_LAYOUT_INFORMATION *DriveLayout,
  9072. BOOLEAN UpdateCachedLayout
  9073. )
  9074. /*++
  9075. Routine Description:
  9076. Return the DRIVE_LAYOUT_INFORMATION for a given device object.
  9077. Arguments:
  9078. DeviceObject - The specific device object to return info about
  9079. BytesPerSector - The number of bytes per sector on this disk
  9080. DriveLayout - Pointer to a DRIVE_LAYOUT_INFORMATION structure to return the info
  9081. UpdateCachedLayout - Update the drive layout stored in the device extension (if any)
  9082. with a fresh copy.
  9083. Return Value:
  9084. NTSTATUS
  9085. --*/
  9086. {
  9087. PCLUS_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  9088. PCLUS_DEVICE_EXTENSION physicalDisk = deviceExtension->PhysicalDevice->DeviceExtension;
  9089. PDRIVE_LAYOUT_INFORMATION driveLayoutInfo = NULL;
  9090. PDRIVE_LAYOUT_INFORMATION cachedDriveLayoutInfo = NULL;
  9091. NTSTATUS status = STATUS_SUCCESS;
  9092. ULONG driveLayoutSize;
  9093. BOOLEAN cachedCopy = FALSE;
  9094. BOOLEAN freeLayouts = FALSE;
  9095. //
  9096. // Allocate a drive layout buffer.
  9097. //
  9098. driveLayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
  9099. (MAX_PARTITIONS * sizeof(PARTITION_INFORMATION));
  9100. driveLayoutInfo = ExAllocatePool(NonPagedPoolCacheAligned,
  9101. driveLayoutSize
  9102. );
  9103. if ( !driveLayoutInfo ) {
  9104. ClusDiskPrint(( 1,
  9105. "[ClusDisk] GetDriveLayout: Failed to allocate drive layout structure. \n"
  9106. ));
  9107. status = STATUS_INSUFFICIENT_RESOURCES;
  9108. goto FnExit;
  9109. }
  9110. if ( UpdateCachedLayout ) {
  9111. //
  9112. // If cached buffer needs to be updated, free the existing buffer.
  9113. //
  9114. ACQUIRE_EXCLUSIVE( &physicalDisk->DriveLayoutLock );
  9115. if ( physicalDisk->DriveLayout ) {
  9116. ExFreePool( physicalDisk->DriveLayout );
  9117. physicalDisk->DriveLayout = NULL;
  9118. }
  9119. physicalDisk->DriveLayoutSize = 0;
  9120. RELEASE_EXCLUSIVE( &physicalDisk->DriveLayoutLock );
  9121. } else {
  9122. //
  9123. // If cached copy exists, use that instead of getting a new version.
  9124. //
  9125. ACQUIRE_SHARED( &physicalDisk->DriveLayoutLock );
  9126. if ( physicalDisk->DriveLayout ) {
  9127. ClusDiskPrint(( 3,
  9128. "[ClusDisk] GetDriveLayout: using cached drive layout information for DE %p \n",
  9129. physicalDisk
  9130. ));
  9131. RtlCopyMemory( driveLayoutInfo,
  9132. physicalDisk->DriveLayout,
  9133. physicalDisk->DriveLayoutSize );
  9134. *DriveLayout = driveLayoutInfo;
  9135. cachedCopy = TRUE;
  9136. }
  9137. RELEASE_SHARED( &physicalDisk->DriveLayoutLock );
  9138. if ( cachedCopy ) {
  9139. goto FnExit;
  9140. }
  9141. }
  9142. freeLayouts = TRUE;
  9143. //
  9144. // Allocate a drive layout buffer for saving in device extension.
  9145. //
  9146. cachedDriveLayoutInfo = ExAllocatePool(NonPagedPoolCacheAligned,
  9147. driveLayoutSize
  9148. );
  9149. if ( !cachedDriveLayoutInfo ) {
  9150. ClusDiskPrint(( 1,
  9151. "[ClusDisk] GetDriveLayout: Failed to allocate cached drive layout structure. \n"
  9152. ));
  9153. status = STATUS_INSUFFICIENT_RESOURCES;
  9154. goto FnExit;
  9155. }
  9156. //
  9157. // Now get the drive layout information
  9158. //
  9159. status = SimpleDeviceIoControl(DeviceObject,
  9160. IOCTL_DISK_GET_DRIVE_LAYOUT,
  9161. NULL,
  9162. 0,
  9163. cachedDriveLayoutInfo,
  9164. driveLayoutSize
  9165. );
  9166. if ( !NT_SUCCESS(status) ) {
  9167. //
  9168. // Couldn't get the drive layout. Free the temporary buffer, set the caller's
  9169. // drive layout pointer to NULL, and return the error status to the caller.
  9170. //
  9171. ClusDiskPrint(( 1,
  9172. "[ClusDisk] GetDriveLayout: Failed to issue IoctlDiskGetDriveLayout. %08X\n",
  9173. status
  9174. ));
  9175. CDLOG( "GetDriveLayout(%p): failed %!status!",
  9176. DeviceObject,
  9177. status );
  9178. *DriveLayout = NULL;
  9179. freeLayouts = TRUE;
  9180. goto FnExit;
  9181. }
  9182. //
  9183. // Successfully retrieved drive layout. Save the new layout in the device
  9184. // extension. Copy the layout into the user's buffer.
  9185. //
  9186. ClusDiskPrint(( 3,
  9187. "[ClusDisk] GetDriveLayout: updating drive layout for DE %p \n",
  9188. physicalDisk
  9189. ));
  9190. CDLOG( "GetDriveLayout(%p): updating drive layout for DE %p ",
  9191. DeviceObject,
  9192. physicalDisk );
  9193. freeLayouts = FALSE;
  9194. ACQUIRE_EXCLUSIVE( &physicalDisk->DriveLayoutLock );
  9195. if ( physicalDisk->DriveLayout ) {
  9196. ExFreePool( physicalDisk->DriveLayout );
  9197. physicalDisk->DriveLayout = NULL;
  9198. }
  9199. physicalDisk->DriveLayout = cachedDriveLayoutInfo;
  9200. physicalDisk->DriveLayoutSize = driveLayoutSize;
  9201. RELEASE_EXCLUSIVE( &physicalDisk->DriveLayoutLock );
  9202. RtlCopyMemory( driveLayoutInfo,
  9203. cachedDriveLayoutInfo,
  9204. driveLayoutSize );
  9205. //
  9206. // Point the user to the drive layout buffer and return success. Caller is
  9207. // responsible for freeing the buffer when they are done with it.
  9208. //
  9209. *DriveLayout = driveLayoutInfo;
  9210. FnExit:
  9211. if ( freeLayouts ) {
  9212. if ( driveLayoutInfo ) {
  9213. ExFreePool( driveLayoutInfo );
  9214. }
  9215. if ( cachedDriveLayoutInfo ) {
  9216. ExFreePool( cachedDriveLayoutInfo );
  9217. }
  9218. }
  9219. return status;
  9220. } // GetDriveLayout
  9221. MEDIA_TYPE
  9222. GetMediaType(
  9223. IN PDEVICE_OBJECT DeviceObject
  9224. )
  9225. /*++
  9226. Routine Description:
  9227. Return the SCSI_ADDRESS for a given device object.
  9228. Arguments:
  9229. DeviceObject - The specific device object to return info about
  9230. ScsiAddress - Pointer to a SCSI_ADDRESS structure to return the info
  9231. Return Value:
  9232. Media Type or Unknown if not known.
  9233. --*/
  9234. {
  9235. PIRP irp;
  9236. PKEVENT event;
  9237. IO_STATUS_BLOCK ioStatusBlock;
  9238. NTSTATUS status;
  9239. DISK_GEOMETRY diskGeometry;
  9240. event = ExAllocatePool( NonPagedPool,
  9241. sizeof(KEVENT) );
  9242. if ( event == NULL ) {
  9243. return( Unknown );
  9244. }
  9245. //
  9246. // Find out if this is on a SCSI bus. Note, that if this device
  9247. // is not a SCSI device, it is expected that the following
  9248. // IOCTL will fail!
  9249. //
  9250. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
  9251. DeviceObject,
  9252. NULL,
  9253. 0,
  9254. &diskGeometry,
  9255. sizeof(DISK_GEOMETRY),
  9256. FALSE,
  9257. event,
  9258. &ioStatusBlock);
  9259. if (!irp) {
  9260. ExFreePool( event );
  9261. ClusDiskPrint((
  9262. 1,
  9263. "[ClusDisk] Failed to build IRP to read MediaType.\n"
  9264. ));
  9265. return(Unknown);
  9266. }
  9267. //
  9268. // Set the event object to the unsignaled state.
  9269. // It will be used to signal request completion.
  9270. //
  9271. KeInitializeEvent(event,
  9272. NotificationEvent,
  9273. FALSE);
  9274. status = IoCallDriver(DeviceObject,
  9275. irp);
  9276. if (status == STATUS_PENDING) {
  9277. KeWaitForSingleObject(event,
  9278. Suspended,
  9279. KernelMode,
  9280. FALSE,
  9281. NULL);
  9282. status = ioStatusBlock.Status;
  9283. }
  9284. ExFreePool( event );
  9285. if ( !NT_SUCCESS(status) ) {
  9286. ClusDiskPrint((
  9287. 1,
  9288. "[ClusDisk] Failed to read SCSI_ADDRESS. %08X\n",
  9289. status
  9290. ));
  9291. return(Unknown);
  9292. }
  9293. return(diskGeometry.MediaType);
  9294. } // GetMediaType
  9295. NTSTATUS
  9296. GetScsiAddress(
  9297. PDEVICE_OBJECT DeviceObject,
  9298. PSCSI_ADDRESS ScsiAddress
  9299. )
  9300. /*++
  9301. Routine Description:
  9302. Return the SCSI_ADDRESS for a given device object.
  9303. Arguments:
  9304. DeviceObject - The specific device object to return info about
  9305. ScsiAddress - Pointer to a SCSI_ADDRESS structure to return the info
  9306. Return Value:
  9307. NTSTATUS
  9308. --*/
  9309. {
  9310. PIRP irp;
  9311. PKEVENT event;
  9312. IO_STATUS_BLOCK ioStatusBlock;
  9313. NTSTATUS status;
  9314. event = ExAllocatePool( NonPagedPool,
  9315. sizeof(KEVENT) );
  9316. if ( event == NULL ) {
  9317. return( STATUS_INSUFFICIENT_RESOURCES );
  9318. }
  9319. //
  9320. // Find out if this is on a SCSI bus. Note, that if this device
  9321. // is not a SCSI device, it is expected that the following
  9322. // IOCTL will fail!
  9323. //
  9324. irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_ADDRESS,
  9325. DeviceObject,
  9326. NULL,
  9327. 0,
  9328. ScsiAddress,
  9329. sizeof(SCSI_ADDRESS),
  9330. FALSE,
  9331. event,
  9332. &ioStatusBlock);
  9333. if (!irp) {
  9334. ExFreePool( event );
  9335. ClusDiskPrint((
  9336. 1,
  9337. "[ClusDisk] Failed to build IRP to read SCSI ADDRESS.\n"
  9338. ));
  9339. return(STATUS_INSUFFICIENT_RESOURCES);
  9340. }
  9341. //
  9342. // Set the event object to the unsignaled state.
  9343. // It will be used to signal request completion.
  9344. //
  9345. KeInitializeEvent(event,
  9346. NotificationEvent,
  9347. FALSE);
  9348. status = IoCallDriver(DeviceObject,
  9349. irp);
  9350. if (status == STATUS_PENDING) {
  9351. KeWaitForSingleObject(event,
  9352. Suspended,
  9353. KernelMode,
  9354. FALSE,
  9355. NULL);
  9356. status = ioStatusBlock.Status;
  9357. }
  9358. ExFreePool( event );
  9359. if ( !NT_SUCCESS(status) ) {
  9360. ClusDiskPrint((
  9361. 1,
  9362. "[ClusDisk] Failed to read SCSI_ADDRESS. %08X\n",
  9363. status
  9364. ));
  9365. CDLOG( "GetScsiAddress(%p): failed %!status!",
  9366. DeviceObject,
  9367. status );
  9368. }
  9369. return(status);
  9370. } // GetScsiAddress
  9371. PDRIVE_LAYOUT_INFORMATION
  9372. ClusDiskGetPartitionInfo(
  9373. PCLUS_DEVICE_EXTENSION DeviceExtension
  9374. )
  9375. /*++
  9376. Routine Description:
  9377. Return the Partition Layout Information for particular device extension.
  9378. Arguments:
  9379. DeviceExtension - The specific device extension to return information.
  9380. Return Value:
  9381. Pointer to an allocated partition layout information structure.
  9382. NULL on failure.
  9383. Notes:
  9384. The caller is responsible for freeing the allocated buffer.
  9385. --*/
  9386. {
  9387. PIRP irp;
  9388. PKEVENT event;
  9389. IO_STATUS_BLOCK ioStatusBlock;
  9390. NTSTATUS status = STATUS_IO_TIMEOUT;
  9391. ULONG driveLayoutInfoSize;
  9392. PDRIVE_LAYOUT_INFORMATION driveLayoutInfo;
  9393. ULONG retryCount = MAX_RETRIES;
  9394. driveLayoutInfoSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
  9395. (MAX_PARTITIONS * sizeof(PARTITION_INFORMATION));
  9396. driveLayoutInfo = ExAllocatePool(NonPagedPoolCacheAligned,
  9397. driveLayoutInfoSize);
  9398. if ( !driveLayoutInfo ) {
  9399. ClusDiskPrint((
  9400. 1,
  9401. "[ClusDisk] Failed to allocate PartitionInfo structure to read drive layout.\n"
  9402. ));
  9403. return(NULL);
  9404. }
  9405. event = ExAllocatePool( NonPagedPool,
  9406. sizeof(KEVENT) );
  9407. if ( !event ) {
  9408. ExFreePool(driveLayoutInfo);
  9409. return(NULL);
  9410. }
  9411. while ( retryCount-- ) {
  9412. if ( (retryCount != (MAX_RETRIES-1)) &&
  9413. (status != STATUS_DEVICE_BUSY) ) {
  9414. ResetScsiDevice( DeviceExtension->TargetDeviceObject,
  9415. &DeviceExtension->ScsiAddress );
  9416. }
  9417. //
  9418. // Create IRP for the get drive layout device control.
  9419. //
  9420. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_LAYOUT,
  9421. DeviceExtension->TargetDeviceObject,
  9422. NULL,
  9423. 0,
  9424. driveLayoutInfo,
  9425. driveLayoutInfoSize,
  9426. FALSE,
  9427. event,
  9428. &ioStatusBlock);
  9429. if (!irp) {
  9430. ClusDiskPrint((
  9431. 1,
  9432. "[ClusDisk] Failed to Init IRP to read PartitionInfo. Skipping partitions!\n"
  9433. ));
  9434. status = STATUS_INSUFFICIENT_RESOURCES;
  9435. break;
  9436. }
  9437. //
  9438. // Set the event object to the unsignaled state.
  9439. // It will be used to signal request completion.
  9440. //
  9441. KeInitializeEvent(event,
  9442. NotificationEvent,
  9443. FALSE);
  9444. status = IoCallDriver(DeviceExtension->TargetDeviceObject,
  9445. irp);
  9446. if (status == STATUS_PENDING) {
  9447. KeWaitForSingleObject(event,
  9448. Suspended,
  9449. KernelMode,
  9450. FALSE,
  9451. NULL);
  9452. status = ioStatusBlock.Status;
  9453. }
  9454. if ( !NT_SUCCESS(status) ) {
  9455. if ( (status != STATUS_DEVICE_OFF_LINE) &&
  9456. (status != STATUS_DATA_OVERRUN) ) {
  9457. ClusDiskPrint((
  9458. 1,
  9459. "[ClusDisk] Failed to read PartitionInfo. Status %lx\n",
  9460. status
  9461. ));
  9462. }
  9463. ClusDiskGetDiskGeometry( DeviceExtension->TargetDeviceObject );
  9464. continue;
  9465. } else {
  9466. DeviceExtension->Signature = driveLayoutInfo->Signature;
  9467. break;
  9468. }
  9469. }
  9470. ExFreePool( event );
  9471. if ( NT_SUCCESS(status) ) {
  9472. return(driveLayoutInfo);
  9473. } else {
  9474. ExFreePool(driveLayoutInfo);
  9475. return(NULL);
  9476. }
  9477. } // ClusDiskGetPartitionInfo
  9478. BOOLEAN
  9479. AddAttachedDevice(
  9480. IN ULONG Signature,
  9481. IN PDEVICE_OBJECT DeviceObject
  9482. )
  9483. /*++
  9484. Routine Description:
  9485. Indicate that this device is now attached.
  9486. Arguments:
  9487. Signature - The signature for the device we just attached.
  9488. DeviceObject - The device object for the partition0 device object.
  9489. Return Value:
  9490. TRUE - Signature is already on the device list or has been added.
  9491. successfully.
  9492. FALSE - Signature was not on the device list and we failed to add it.
  9493. --*/
  9494. {
  9495. PDEVICE_LIST_ENTRY deviceEntry;
  9496. PCLUS_DEVICE_EXTENSION deviceExtension;
  9497. // 2000/02/05: stevedz - added synchronization.
  9498. ACQUIRE_EXCLUSIVE( &ClusDiskDeviceListLock );
  9499. deviceEntry = ClusDiskDeviceList;
  9500. while ( deviceEntry != NULL ) {
  9501. if ( Signature == deviceEntry->Signature ) {
  9502. if ( deviceEntry->Attached ) {
  9503. ClusDiskPrint((
  9504. 1,
  9505. "[ClusDisk] Attaching to %lx more than once!\n",
  9506. Signature ));
  9507. }
  9508. if ( DeviceObject ) {
  9509. deviceExtension = DeviceObject->DeviceExtension;
  9510. ASSERT(deviceExtension->PhysicalDevice == DeviceObject);
  9511. deviceEntry->Attached = TRUE;
  9512. deviceEntry->DeviceObject = DeviceObject;
  9513. deviceExtension->AttachValid = TRUE;
  9514. deviceExtension->Signature = Signature;
  9515. }
  9516. RELEASE_EXCLUSIVE( &ClusDiskDeviceListLock );
  9517. return(TRUE);
  9518. }
  9519. deviceEntry = deviceEntry->Next;
  9520. }
  9521. deviceEntry = ExAllocatePool(
  9522. NonPagedPool,
  9523. sizeof(DEVICE_LIST_ENTRY) );
  9524. if ( deviceEntry == NULL ) {
  9525. ClusDiskPrint((1,
  9526. "[ClusDisk] Failed to allocate device entry structure for signature %08lX\n",
  9527. Signature));
  9528. RELEASE_EXCLUSIVE( &ClusDiskDeviceListLock );
  9529. return(FALSE);
  9530. }
  9531. RtlZeroMemory( deviceEntry, sizeof(DEVICE_LIST_ENTRY) );
  9532. deviceEntry->Signature = Signature;
  9533. deviceEntry->LettersAssigned = FALSE;
  9534. deviceEntry->DeviceObject = DeviceObject;
  9535. if ( DeviceObject == NULL ) {
  9536. deviceEntry->Attached = FALSE;
  9537. } else {
  9538. deviceEntry->Attached = TRUE;
  9539. }
  9540. //
  9541. // Link new entry into list.
  9542. //
  9543. deviceEntry->Next = ClusDiskDeviceList;
  9544. ClusDiskDeviceList = deviceEntry;
  9545. RELEASE_EXCLUSIVE( &ClusDiskDeviceListLock );
  9546. return(TRUE);
  9547. } // AddAttachedDevice
  9548. BOOLEAN
  9549. MatchDevice(
  9550. IN ULONG Signature,
  9551. OUT PDEVICE_OBJECT *DeviceObject
  9552. )
  9553. /*++
  9554. Routine Description:
  9555. Check to see if the Signature of the specified device is one
  9556. that we should control.
  9557. Arguments:
  9558. Signature - The signature for the device we are checking.
  9559. DeviceObject - Pointer to a return value for the device object.
  9560. Return Value:
  9561. TRUE - if this Signature is for a device we should control.
  9562. FALSE - if this Signature is NOT for a device we should control.
  9563. --*/
  9564. {
  9565. PDEVICE_LIST_ENTRY deviceEntry;
  9566. if ( SystemDiskSignature == Signature ) {
  9567. if ( ARGUMENT_PRESENT(DeviceObject) ) {
  9568. *DeviceObject = NULL;
  9569. }
  9570. return(FALSE);
  9571. }
  9572. // 2000/02/05: stevedz - added synchronization.
  9573. ACQUIRE_SHARED( &ClusDiskDeviceListLock );
  9574. deviceEntry = ClusDiskDeviceList;
  9575. while ( deviceEntry != NULL ) {
  9576. if ( Signature == deviceEntry->Signature ) {
  9577. if ( ARGUMENT_PRESENT(DeviceObject) ) {
  9578. *DeviceObject = deviceEntry->DeviceObject;
  9579. }
  9580. RELEASE_SHARED( &ClusDiskDeviceListLock );
  9581. return(TRUE);
  9582. }
  9583. deviceEntry = deviceEntry->Next;
  9584. }
  9585. if ( ARGUMENT_PRESENT(DeviceObject) ) {
  9586. *DeviceObject = NULL;
  9587. }
  9588. RELEASE_SHARED( &ClusDiskDeviceListLock );
  9589. return(FALSE);
  9590. } // MatchDevice
  9591. BOOLEAN
  9592. MatchScsiBus(
  9593. PSCSI_ADDRESS ScsiAddress
  9594. )
  9595. /*++
  9596. Routine Description:
  9597. Check to see if the ScsiAddress of the specified device is one
  9598. that we could possibly control. That means that it resides on a
  9599. shared SCSI bus.
  9600. Arguments:
  9601. ScsiAddress - pointer to the SCSI_ADRESS for this device.
  9602. Return Value:
  9603. TRUE - if this SCSI_ADDRESS matchs.
  9604. FALSE - if this SCSI_ADDRESS does NOT match.
  9605. --*/
  9606. {
  9607. PSCSI_BUS_ENTRY busEntry;
  9608. busEntry = ClusDiskScsiBusList;
  9609. while ( busEntry ) {
  9610. if ( (busEntry->Port == ScsiAddress->PortNumber) &&
  9611. (busEntry->Path == ScsiAddress->PathId) ) {
  9612. return(TRUE);
  9613. }
  9614. busEntry = busEntry->Next;
  9615. }
  9616. return(FALSE);
  9617. } // MatchScsiBus
  9618. NTSTATUS
  9619. ClusDiskGetDiskGeometry(
  9620. PDEVICE_OBJECT DeviceObject
  9621. )
  9622. /*++
  9623. Routine Description:
  9624. Retry getting disk geometry.
  9625. Arguments:
  9626. DeviceObject - the target device object.
  9627. Return Value:
  9628. NTSTATUS
  9629. --*/
  9630. {
  9631. NTSTATUS status;
  9632. NTSTATUS tmpStatus;
  9633. ULONG retryCount = 2;
  9634. SCSI_ADDRESS scsiAddress;
  9635. if ( DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM ) {
  9636. return(STATUS_INVALID_DEVICE_REQUEST);
  9637. }
  9638. do {
  9639. status = GetDiskGeometry( DeviceObject );
  9640. if ( status == STATUS_DATA_OVERRUN ) {
  9641. tmpStatus = GetScsiAddress( DeviceObject, &scsiAddress );
  9642. if ( NT_SUCCESS(tmpStatus) &&
  9643. (status != STATUS_DEVICE_BUSY) &&
  9644. (retryCount > 1) ) {
  9645. ResetScsiDevice( DeviceObject, &scsiAddress );
  9646. }
  9647. }
  9648. } while ( --retryCount &&
  9649. (status == STATUS_DATA_OVERRUN) );
  9650. if ( !NT_SUCCESS(status) ) {
  9651. ClusDiskPrint(( 1,
  9652. "[ClusDisk] Failed to read disk geometry, error %lx.\n",
  9653. status ));
  9654. }
  9655. return(status);
  9656. } // ClusDiskGetDiskGeometry
  9657. NTSTATUS
  9658. GetDiskGeometry(
  9659. PDEVICE_OBJECT DeviceObject
  9660. )
  9661. /*++
  9662. Routine Description:
  9663. Get the disk geometry for a target device.
  9664. Arguments:
  9665. DeviceObject - the target device object.
  9666. Return Value:
  9667. NTSTATUS
  9668. --*/
  9669. {
  9670. PDISK_GEOMETRY diskGeometryBuffer;
  9671. NTSTATUS status;
  9672. PKEVENT event;
  9673. PIRP irp;
  9674. IO_STATUS_BLOCK ioStatusBlock;
  9675. //
  9676. // Allocate DISK_GEOMETRY buffer from nonpaged pool.
  9677. //
  9678. diskGeometryBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
  9679. sizeof(DISK_GEOMETRY));
  9680. if (!diskGeometryBuffer) {
  9681. return(STATUS_INSUFFICIENT_RESOURCES);
  9682. }
  9683. event = ExAllocatePool( NonPagedPool,
  9684. sizeof(KEVENT) );
  9685. if ( !event ) {
  9686. ExFreePool(diskGeometryBuffer);
  9687. return(STATUS_INSUFFICIENT_RESOURCES);
  9688. }
  9689. //
  9690. // Perform the get drive geometry synchronously.
  9691. //
  9692. KeInitializeEvent(event,
  9693. NotificationEvent,
  9694. FALSE);
  9695. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
  9696. DeviceObject,
  9697. NULL,
  9698. 0,
  9699. diskGeometryBuffer,
  9700. sizeof(DISK_GEOMETRY),
  9701. FALSE,
  9702. event,
  9703. &ioStatusBlock);
  9704. status = IoCallDriver(DeviceObject, irp);
  9705. if (status == STATUS_PENDING) {
  9706. KeWaitForSingleObject(event,
  9707. Suspended,
  9708. KernelMode,
  9709. FALSE,
  9710. NULL);
  9711. status = ioStatusBlock.Status;
  9712. }
  9713. ExFreePool(event);
  9714. //
  9715. // Deallocate read capacity buffer.
  9716. //
  9717. ExFreePool(diskGeometryBuffer);
  9718. return(status);
  9719. } // GetDiskGeometry
  9720. NTSTATUS
  9721. ReserveScsiDevice(
  9722. IN PCLUS_DEVICE_EXTENSION DeviceExtension
  9723. )
  9724. /*++
  9725. Routine Description:
  9726. Reserve a SCSI device.
  9727. Arguments:
  9728. DeviceExtension - The device extension for the device to reserve.
  9729. Return Value:
  9730. NTSTATUS
  9731. --*/
  9732. {
  9733. PIRP irp;
  9734. NTSTATUS status;
  9735. PIO_STACK_LOCATION irpStack;
  9736. PKEVENT event;
  9737. KIRQL irql;
  9738. PCLUS_DEVICE_EXTENSION rootDeviceExtension;
  9739. IO_STATUS_BLOCK ioStatusBlock;
  9740. PLIST_ENTRY listEntry;
  9741. ULONG retryCount = 1;
  9742. CDLOGF(RESERVE,"ReserveScsiDevice(%p): Entry DiskNo %d Sig %08x",
  9743. DeviceExtension->DeviceObject,
  9744. DeviceExtension->DiskNumber,
  9745. DeviceExtension->Signature );
  9746. event = ExAllocatePool( NonPagedPool,
  9747. sizeof(KEVENT) );
  9748. if ( !event ) {
  9749. return(STATUS_INSUFFICIENT_RESOURCES);
  9750. }
  9751. retry:
  9752. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_RESERVE,
  9753. DeviceExtension->TargetDeviceObject,
  9754. NULL,
  9755. 0,
  9756. NULL,
  9757. 0,
  9758. FALSE,
  9759. event,
  9760. &ioStatusBlock);
  9761. if ( irp == NULL ) {
  9762. ExFreePool(event);
  9763. return(STATUS_INSUFFICIENT_RESOURCES);
  9764. }
  9765. KeInitializeEvent(event,
  9766. NotificationEvent,
  9767. FALSE);
  9768. status = IoCallDriver(DeviceExtension->TargetDeviceObject,
  9769. irp);
  9770. if (status == STATUS_PENDING) {
  9771. KeWaitForSingleObject(event,
  9772. Suspended,
  9773. KernelMode,
  9774. FALSE,
  9775. NULL);
  9776. status = ioStatusBlock.Status;
  9777. }
  9778. rootDeviceExtension = RootDeviceObject->DeviceExtension;
  9779. if ( !NT_SUCCESS(status) ) {
  9780. if ( retryCount-- &&
  9781. (status == STATUS_IO_DEVICE_ERROR) ) {
  9782. goto retry;
  9783. }
  9784. ClusDiskPrint((
  9785. 1,
  9786. "[ClusDisk] Lost reservation for Signature %08lx, status %lx.\n",
  9787. DeviceExtension->Signature,
  9788. status
  9789. ));
  9790. IoAcquireCancelSpinLock( &irql );
  9791. KeAcquireSpinLockAtDpcLevel(&ClusDiskSpinLock);
  9792. DeviceExtension->ReserveTimer = 0;
  9793. DeviceExtension->ReserveFailure = status;
  9794. //
  9795. // Signal all waiting Irp's
  9796. //
  9797. while ( !IsListEmpty(&DeviceExtension->WaitingIoctls) ) {
  9798. listEntry = RemoveHeadList(&DeviceExtension->WaitingIoctls);
  9799. irp = CONTAINING_RECORD( listEntry,
  9800. IRP,
  9801. Tail.Overlay.ListEntry );
  9802. // ReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
  9803. //irp->IoStatus.Status = status;
  9804. //IoCompleteRequest(irp, IO_NO_INCREMENT);
  9805. ClusDiskCompletePendingRequest(irp, status, DeviceExtension);
  9806. }
  9807. KeReleaseSpinLockFromDpcLevel(&ClusDiskSpinLock);
  9808. IoReleaseCancelSpinLock( irql );
  9809. }
  9810. ExFreePool(event);
  9811. DeviceExtension->TimerBusy = FALSE;
  9812. CDLOGF(RESERVE,"ReserveScsiDevice(%p): Exit => %!status!",
  9813. DeviceExtension->DeviceObject,
  9814. status );
  9815. return(status);
  9816. } // ReserveScsiDevice
  9817. VOID
  9818. ReleaseScsiDevice(
  9819. IN PCLUS_DEVICE_EXTENSION DeviceExtension
  9820. )
  9821. /*++
  9822. Routine Description:
  9823. Release a SCSI device (release from reservation).
  9824. Arguments:
  9825. DeviceExtension - the device extension of the device to release.
  9826. This must be the physical device (partition0).
  9827. Return Value:
  9828. None.
  9829. --*/
  9830. {
  9831. PIRP irp;
  9832. SCSI_PASS_THROUGH spt;
  9833. SCSI_REQUEST_BLOCK srb;
  9834. PKEVENT event;
  9835. IO_STATUS_BLOCK ioStatusBlock;
  9836. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  9837. PIO_STACK_LOCATION irpStack;
  9838. CDLOG( "ReleaseScsiDevice(%p): Entry DiskNo %d Sig %08x",
  9839. DeviceExtension->DeviceObject,
  9840. DeviceExtension->DiskNumber,
  9841. DeviceExtension->Signature );
  9842. ClusDiskPrint((3,
  9843. "[ClusDisk] Release disk number %u (sig: %08X), disk state %s \n",
  9844. DeviceExtension->DiskNumber,
  9845. DeviceExtension->Signature,
  9846. DiskStateToString( DeviceExtension->DiskState ) ));
  9847. event = ExAllocatePool( NonPagedPool,
  9848. sizeof(KEVENT) );
  9849. if ( !event ) {
  9850. return;
  9851. }
  9852. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_RELEASE,
  9853. DeviceExtension->TargetDeviceObject,
  9854. &spt,
  9855. sizeof(SCSI_PASS_THROUGH),
  9856. &spt,
  9857. sizeof(SCSI_PASS_THROUGH),
  9858. FALSE,
  9859. event,
  9860. &ioStatusBlock);
  9861. if (!irp) {
  9862. ExFreePool(event);
  9863. ClusDiskPrint((
  9864. 1,
  9865. "[ClusDisk] Failed to Init IRP to perform a release.\n"
  9866. ));
  9867. return;
  9868. }
  9869. //
  9870. // Before release, mark disk as offline.
  9871. //
  9872. ASSERT( DeviceExtension == DeviceExtension->PhysicalDevice->DeviceExtension );
  9873. // stevedz - disable this assertion for now.
  9874. // ASSERT( DiskOffline == DeviceExtension->DiskState );
  9875. // DeviceExtension->DiskState = DiskOffline;
  9876. OFFLINE_DISK( DeviceExtension );
  9877. ClusDiskPrint(( 3,
  9878. "[ClusDisk] Release %p, marking disk offline \n",
  9879. DeviceExtension->PhysicalDevice
  9880. ));
  9881. //
  9882. // Set the event object to the unsignaled state.
  9883. // It will be used to signal request completion.
  9884. //
  9885. KeInitializeEvent(event,
  9886. NotificationEvent,
  9887. FALSE);
  9888. status = IoCallDriver(DeviceExtension->TargetDeviceObject,
  9889. irp);
  9890. if (status == STATUS_PENDING) {
  9891. KeWaitForSingleObject(event,
  9892. Suspended,
  9893. KernelMode,
  9894. FALSE,
  9895. NULL);
  9896. status = ioStatusBlock.Status;
  9897. }
  9898. ExFreePool(event);
  9899. if ( !NT_SUCCESS(status) ) {
  9900. ClusDiskPrint((
  9901. 1,
  9902. "[ClusDisk] Failed to perform release. Status %lx\n",
  9903. status
  9904. ));
  9905. }
  9906. CDLOG( "ReleaseScsiDevice(%p): Exit => %!status!",
  9907. DeviceExtension->DeviceObject,
  9908. status );
  9909. } // ReleaseScsiDevice
  9910. VOID
  9911. ResetScsiDevice(
  9912. PDEVICE_OBJECT DeviceObject,
  9913. PSCSI_ADDRESS ScsiAddress
  9914. )
  9915. /*++
  9916. Routine Description:
  9917. Reset a SCSI device.
  9918. Arguments:
  9919. DeviceObject - The device object to perform the bus reset.
  9920. ScsiAddress - The SCSI_ADDRESS for specific device. Needs PathId.
  9921. Return Value:
  9922. None.
  9923. --*/
  9924. {
  9925. PIRP irp;
  9926. STORAGE_BUS_RESET_REQUEST storageReset;
  9927. PKEVENT event;
  9928. IO_STATUS_BLOCK ioStatusBlock;
  9929. NTSTATUS status;
  9930. PIO_STACK_LOCATION irpStack;
  9931. CDLOG( "ResetScsiDevice(%p): Entry PathId %d",
  9932. DeviceObject,
  9933. ScsiAddress->PathId );
  9934. ClusDiskPrint(( 3,
  9935. "[ClusDisk] Bus Reset DevObj %p PathId %u \n",
  9936. DeviceObject,
  9937. ScsiAddress->PathId
  9938. ));
  9939. event = ExAllocatePool( NonPagedPool,
  9940. sizeof(KEVENT) );
  9941. if ( !event ) {
  9942. return;
  9943. }
  9944. storageReset.PathId = ScsiAddress->PathId;
  9945. irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_BREAK_RESERVATION,
  9946. DeviceObject,
  9947. &storageReset,
  9948. sizeof(STORAGE_BUS_RESET_REQUEST),
  9949. NULL,
  9950. 0,
  9951. FALSE,
  9952. event,
  9953. &ioStatusBlock);
  9954. if (!irp) {
  9955. ExFreePool( event );
  9956. ClusDiskPrint((
  9957. 1,
  9958. "[ClusDisk] Failed to Init IRP to perform a reset.\n"
  9959. ));
  9960. return;
  9961. }
  9962. //
  9963. // Set the event object to the unsignaled state.
  9964. // It will be used to signal request completion.
  9965. //
  9966. KeInitializeEvent(event,
  9967. NotificationEvent,
  9968. FALSE);
  9969. status = IoCallDriver(DeviceObject,
  9970. irp);
  9971. if (status == STATUS_PENDING) {
  9972. KeWaitForSingleObject(event,
  9973. Suspended,
  9974. KernelMode,
  9975. TRUE,
  9976. NULL);
  9977. status = ioStatusBlock.Status;
  9978. }
  9979. ExFreePool( event );
  9980. if ( !NT_SUCCESS(status) ) {
  9981. ClusDiskPrint((
  9982. 1,
  9983. "[ClusDisk] Failed to perform reset on %wZ. Status %lx\n",
  9984. &DeviceObject->DriverObject->DriverName,
  9985. status
  9986. ));
  9987. }
  9988. CDLOG( "ResetScsiDevice(%p): Exit => %!status!", DeviceObject, status );
  9989. } // ResetScsiDevice
  9990. NTSTATUS
  9991. ClusDiskOfflineFtSet(
  9992. IN PCLUS_DEVICE_EXTENSION DeviceExtension
  9993. )
  9994. /*++
  9995. Routine Description:
  9996. Tell FTDISK to offline the FT Set associated with this device.
  9997. Arguments:
  9998. DeviceExtension - pointer to the ClusDisk device extension for the device.
  9999. Return Value:
  10000. NTSTATUS for this request.
  10001. --*/
  10002. {
  10003. return STATUS_SUCCESS;
  10004. } // ClusDiskOfflineFtSet
  10005. VOID
  10006. ClusDiskAddScsiBusList(
  10007. IN PCLUS_DEVICE_EXTENSION DeviceExtension
  10008. )
  10009. /*++
  10010. Routine Description:
  10011. This routine adds a potentially new bus to our bus list.
  10012. Arguments:
  10013. DeviceExtension - The device extension that we just found.
  10014. Return Value:
  10015. None.
  10016. --*/
  10017. {
  10018. PSCSI_BUS_ENTRY busEntry;
  10019. busEntry = ClusDiskScsiBusList;
  10020. while ( busEntry ) {
  10021. if ( (busEntry->Port == DeviceExtension->ScsiAddress.PortNumber) &&
  10022. (busEntry->Path == DeviceExtension->ScsiAddress.PathId) ) {
  10023. break;
  10024. }
  10025. busEntry = busEntry->Next;
  10026. }
  10027. if ( !busEntry ) {
  10028. busEntry = ExAllocatePool(NonPagedPool,
  10029. sizeof(SCSI_BUS_ENTRY) );
  10030. if (busEntry != NULL ) {
  10031. busEntry->Port = DeviceExtension->ScsiAddress.PortNumber;
  10032. busEntry->Path = DeviceExtension->ScsiAddress.PathId;
  10033. busEntry->Next = ClusDiskScsiBusList;
  10034. ClusDiskScsiBusList = busEntry;
  10035. }
  10036. }
  10037. return;
  10038. } // ClusDiskAddScsiBusList
  10039. #if 0
  10040. NTSTATUS
  10041. LockVolumes(
  10042. IN PCLUS_DEVICE_EXTENSION DeviceExtension
  10043. )
  10044. /*++
  10045. Routine Description:
  10046. Lock all volumes for this Disk.
  10047. Arguments:
  10048. DiskNumber - the disk number for the disk to lock volumes.
  10049. Return Value:
  10050. NT Status for request.
  10051. --*/
  10052. {
  10053. NTSTATUS status;
  10054. OBJECT_ATTRIBUTES objectAttributes;
  10055. UNICODE_STRING ntUnicodeString;
  10056. HANDLE fileHandle;
  10057. WCHAR deviceNameBuffer[MAX_PARTITION_NAME_LENGTH];
  10058. IO_STATUS_BLOCK ioStatusBlock;
  10059. PDRIVE_LAYOUT_INFORMATION driveLayoutInfo;
  10060. PPARTITION_INFORMATION partitionInfo;
  10061. ULONG partIndex;
  10062. HANDLE eventHandle;
  10063. PFILE_OBJECT fileObject;
  10064. PDEVICE_OBJECT deviceObject;
  10065. PKEVENT event;
  10066. PIRP irp;
  10067. //
  10068. // Allocate an event structure
  10069. //
  10070. event = ExAllocatePool(
  10071. NonPagedPool,
  10072. sizeof(KEVENT)
  10073. );
  10074. status = STATUS_INSUFFICIENT_RESOURCES;
  10075. if (!event) {
  10076. return(status);
  10077. }
  10078. driveLayoutInfo = ClusDiskGetPartitionInfo( DeviceExtension );
  10079. if ( driveLayoutInfo != NULL ) {
  10080. //
  10081. // Create event for notification.
  10082. //
  10083. status = ZwCreateEvent( &eventHandle,
  10084. EVENT_ALL_ACCESS,
  10085. NULL,
  10086. SynchronizationEvent,
  10087. FALSE );
  10088. if ( !NT_SUCCESS(status) ) {
  10089. ExFreePool( driveLayoutInfo );
  10090. ExFreePool( event );
  10091. return(status);
  10092. }
  10093. for ( partIndex = 0;
  10094. partIndex < driveLayoutInfo->PartitionCount;
  10095. partIndex++ )
  10096. {
  10097. partitionInfo = &driveLayoutInfo->PartitionEntry[partIndex];
  10098. //
  10099. // First make sure this is a valid partition.
  10100. //
  10101. if ( !partitionInfo->RecognizedPartition ||
  10102. partitionInfo->PartitionNumber == 0 ) {
  10103. continue;
  10104. }
  10105. //
  10106. // Create the device name for the device.
  10107. //
  10108. swprintf(deviceNameBuffer,
  10109. DEVICE_PARTITION_NAME,
  10110. DeviceExtension->DiskNumber,
  10111. partitionInfo->PartitionNumber);
  10112. WCSLEN_ASSERT( deviceNameBuffer );
  10113. //
  10114. // Get Unicode name
  10115. //
  10116. RtlInitUnicodeString( &ntUnicodeString, deviceNameBuffer );
  10117. //
  10118. // Try to open this device to perform a dismount
  10119. //
  10120. InitializeObjectAttributes( &objectAttributes,
  10121. &ntUnicodeString,
  10122. OBJ_CASE_INSENSITIVE,
  10123. NULL,
  10124. NULL );
  10125. ClusDiskPrint((
  10126. 3,
  10127. "[ClusDisk] Locking Partition %ws.\n",
  10128. deviceNameBuffer ));
  10129. status = ZwCreateFile( &fileHandle,
  10130. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  10131. &objectAttributes,
  10132. &ioStatusBlock,
  10133. NULL,
  10134. FILE_ATTRIBUTE_NORMAL,
  10135. FILE_SHARE_READ | FILE_SHARE_WRITE,
  10136. FILE_OPEN,
  10137. FILE_SYNCHRONOUS_IO_NONALERT,
  10138. NULL,
  10139. 0 );
  10140. if ( !NT_SUCCESS(status) ) {
  10141. ClusDiskPrint((
  10142. 1,
  10143. "[ClusDisk] LockVolumes failed to open file %wZ. Error %lx.\n",
  10144. &ntUnicodeString,
  10145. status ));
  10146. continue;
  10147. }
  10148. status = ZwClearEvent( eventHandle );
  10149. #if 0
  10150. status = ObReferenceObjectByHandle(
  10151. fileHandle,
  10152. FILE_WRITE_DATA,
  10153. *IoFileObjectType,
  10154. KernelMode,
  10155. &fileObject,
  10156. NULL );
  10157. if ( !NT_SUCCESS(status) ) {
  10158. ClusDiskPrint((
  10159. 1,
  10160. "[ClusDisk] LockVolumes: failed to reference object %ws, status %lx\n",
  10161. deviceNameBuffer,
  10162. status ));
  10163. continue;
  10164. }
  10165. deviceObject = IoGetRelatedDeviceObject( fileObject );
  10166. ObDereferenceObject( fileObject );
  10167. ClusDiskPrint((
  10168. 1,
  10169. "[ClusDisk] LockVolumes - found file/device object %p \n",
  10170. deviceObject ));
  10171. if ( !deviceObject ) {
  10172. continue;
  10173. }
  10174. KeInitializeEvent(event,
  10175. NotificationEvent,
  10176. FALSE);
  10177. irp = IoBuildSynchronousFsdRequest(
  10178. IRP_MJ_FLUSH_BUFFERS,
  10179. deviceObject,
  10180. NULL,
  10181. 0,
  10182. NULL,
  10183. event,
  10184. &ioStatusBlock );
  10185. if (!irp) {
  10186. continue;
  10187. }
  10188. if (IoCallDriver( deviceObject,
  10189. irp ) == STATUS_PENDING) {
  10190. KeWaitForSingleObject(
  10191. event,
  10192. Suspended,
  10193. KernelMode,
  10194. FALSE,
  10195. NULL
  10196. );
  10197. }
  10198. #else
  10199. status = ZwFsControlFile(
  10200. fileHandle,
  10201. eventHandle, // Event Handle
  10202. NULL, // APC Routine
  10203. NULL, // APC Context
  10204. &ioStatusBlock,
  10205. FSCTL_LOCK_VOLUME,
  10206. NULL, // InputBuffer
  10207. 0, // InputBufferLength
  10208. NULL, // OutputBuffer
  10209. 0 // OutputBufferLength
  10210. );
  10211. if ( status == STATUS_PENDING ) {
  10212. status = ZwWaitForSingleObject(eventHandle,
  10213. FALSE,
  10214. NULL);
  10215. ASSERT( NT_SUCCESS(status) );
  10216. status = ioStatusBlock.Status;
  10217. }
  10218. #endif
  10219. if ( !NT_SUCCESS(status) ) {
  10220. ClusDiskPrint((
  10221. 1,
  10222. "[ClusDisk] Failed to flush buffers for %wZ. Error %lx.\n",
  10223. &ntUnicodeString,
  10224. status ));
  10225. } else {
  10226. ClusDiskPrint((
  10227. 3,
  10228. "[ClusDisk] Flushed buffers for %wZ.\n",
  10229. &ntUnicodeString ));
  10230. }
  10231. ZwClose( fileHandle );
  10232. } // for
  10233. ExFreePool( driveLayoutInfo );
  10234. ZwClose( eventHandle );
  10235. } // if
  10236. ExFreePool( event );
  10237. return(status);
  10238. } // LockVolumes
  10239. #endif
  10240. NTSTATUS
  10241. IsVolumeMounted(
  10242. IN ULONG DiskNumber,
  10243. IN ULONG PartNumber,
  10244. OUT BOOLEAN *IsMounted
  10245. )
  10246. {
  10247. HANDLE fileHandle = NULL;
  10248. NTSTATUS status;
  10249. FILE_FS_DEVICE_INFORMATION deviceInfo;
  10250. IO_STATUS_BLOCK ioStatusBlock;
  10251. if ( PASSIVE_LEVEL != KeGetCurrentIrql() ) {
  10252. status = STATUS_UNSUCCESSFUL;
  10253. goto FnExit;
  10254. }
  10255. //
  10256. // Open the device so we can query if a volume is mounted without
  10257. // causing it to be mounted. Note that we can only specify
  10258. // FILE_READ_ATTRIBUTES | SYNCHRONIZE or a mount will occur.
  10259. //
  10260. status = ClusDiskCreateHandle( &fileHandle,
  10261. DiskNumber,
  10262. PartNumber,
  10263. FILE_READ_ATTRIBUTES | SYNCHRONIZE );
  10264. if ( !NT_SUCCESS(status) ) {
  10265. goto FnExit;
  10266. }
  10267. //
  10268. // Make the device info query.
  10269. //
  10270. status = ZwQueryVolumeInformationFile( fileHandle,
  10271. &ioStatusBlock,
  10272. &deviceInfo,
  10273. sizeof(deviceInfo),
  10274. FileFsDeviceInformation );
  10275. if ( !NT_SUCCESS(status) ) {
  10276. goto FnExit;
  10277. }
  10278. *IsMounted = (deviceInfo.Characteristics & FILE_DEVICE_IS_MOUNTED) ? TRUE : FALSE;
  10279. FnExit:
  10280. if ( fileHandle ) {
  10281. ZwClose( fileHandle );
  10282. }
  10283. return status;
  10284. } // IsVolumeMounted
  10285. NTSTATUS
  10286. DismountPartition(
  10287. IN PDEVICE_OBJECT TargetDevice,
  10288. IN ULONG DiskNumber,
  10289. IN ULONG PartNumber
  10290. )
  10291. /*++
  10292. Routine Description:
  10293. Dismount the device, given the disk and partition numbers
  10294. Arguments:
  10295. TargetDevice - the target device to send volume IOCTLs to.
  10296. DiskNumber - the disk number for the disk to dismount
  10297. PartNumber - the parition number for the disk to dismount
  10298. Return Value:
  10299. NT Status for request.
  10300. --*/
  10301. {
  10302. NTSTATUS status;
  10303. NTSTATUS status2;
  10304. HANDLE fileHandle = NULL;
  10305. IO_STATUS_BLOCK ioStatusBlock;
  10306. KIRQL irql;
  10307. BOOLEAN isMounted;
  10308. CDLOG( "DismountPartition: Entry DiskNo %d PartNo %d", DiskNumber, PartNumber );
  10309. ClusDiskPrint(( 3,
  10310. "[ClusDisk] DismountPartition: Dismounting disk %d partition %d \n",
  10311. DiskNumber,
  10312. PartNumber ));
  10313. status = IsVolumeMounted( DiskNumber, PartNumber, &isMounted );
  10314. if ( NT_SUCCESS(status) ) {
  10315. ClusDiskPrint(( 1,
  10316. "[ClusDisk] DismountPartition: Volume is mounted returns: %s \n",
  10317. isMounted ? "TRUE" : "FALSE" ));
  10318. if ( FALSE == isMounted) {
  10319. // Volume not mounted, we are done. Return success.
  10320. status = STATUS_SUCCESS;
  10321. goto FnExit;
  10322. }
  10323. }
  10324. irql = KeGetCurrentIrql();
  10325. if ( PASSIVE_LEVEL != irql ) {
  10326. ClusDiskPrint(( 1,
  10327. "[ClusDisk] DismountPartition: Invalid IRQL %d \n", irql ));
  10328. CDLOG( "DismountPartition: Invalid IRQL %d ", irql );
  10329. ASSERT( FALSE );
  10330. status = STATUS_UNSUCCESSFUL;
  10331. goto FnExit;
  10332. }
  10333. #if DBG
  10334. //
  10335. // Find out if FTDISK thinks this disk is currently online or offline.
  10336. // If offline, success is returned.
  10337. // If online, c0000001 STATUS_UNSUCCESSFUL is returned.
  10338. //
  10339. status = SendFtdiskIoctlSync( TargetDevice,
  10340. DiskNumber,
  10341. PartNumber,
  10342. IOCTL_VOLUME_IS_OFFLINE );
  10343. if ( NT_SUCCESS(status) ) {
  10344. ClusDiskPrint(( 3,
  10345. "[ClusDisk] DismountPartition: IOCTL_VOLUME_IS_OFFLINE indicates volume is offline. \n" ));
  10346. CDLOG( "DismountPartition: IOCTL_VOLUME_OFFLINE indicates volume is offline" );
  10347. } else {
  10348. ClusDiskPrint(( 3,
  10349. "[ClusDisk] DismountPartition: IOCTL_VOLUME_IS_OFFLINE returns %08X \n",
  10350. status ));
  10351. CDLOG( "DismountPartition: IOCTL_VOLUME_OFFLINE returns %08X", status );
  10352. }
  10353. #endif
  10354. // If the disk is offline:
  10355. // if access is: FILE_READ_ATTRIBUTES | SYNCHRONIZE
  10356. //
  10357. // - DismountDevice fails with: c0000010 STATUS_INVALID_DEVICE_REQUEST
  10358. //
  10359. // if access is: FILE_READ_DATA | SYNCHRONIZE
  10360. //
  10361. // - ClusDiskCreateHandle fails with: C000000E STATUS_NO_SUCH_DEVICE
  10362. //
  10363. // if access is: FILE_WRITE_ATTRIBUTES | SYNCHRONIZE
  10364. //
  10365. // - DismountDevice works!
  10366. status = ClusDiskCreateHandle( &fileHandle,
  10367. DiskNumber,
  10368. PartNumber,
  10369. FILE_WRITE_ATTRIBUTES | SYNCHRONIZE );
  10370. //
  10371. // Check status of getting the device handle.
  10372. //
  10373. if ( !NT_SUCCESS(status) ) {
  10374. ClusDiskPrint(( 1,
  10375. "[ClusDisk] DismountPartition: Unable to get device handle \n" ));
  10376. CDLOG( "DismountPartition: Unable to get device handle" );
  10377. goto FnExit;
  10378. }
  10379. status = DismountDevice( fileHandle );
  10380. if ( !NT_SUCCESS(status) ) {
  10381. ClusDiskPrint(( 1,
  10382. "[ClusDisk] Failed to dismount disk %d partition %d. Error %08X.\n",
  10383. DiskNumber,
  10384. PartNumber,
  10385. status ));
  10386. } else {
  10387. ClusDiskPrint(( 3,
  10388. "[ClusDisk] Dismounted disk %d partition %d \n",
  10389. DiskNumber,
  10390. PartNumber ));
  10391. }
  10392. FnExit:
  10393. if ( fileHandle ) {
  10394. ZwClose( fileHandle );
  10395. }
  10396. CDLOG( "DismountPartition: Exit DiskNo %d PartNo %d => %!status!",
  10397. DiskNumber,
  10398. PartNumber,
  10399. status );
  10400. ClusDiskPrint(( 3,
  10401. "[ClusDisk] DismountPartition: Dismounting disk %d partition %d status %08X \n",
  10402. DiskNumber,
  10403. PartNumber,
  10404. status ));
  10405. return(status);
  10406. } // DismountPartition
  10407. NTSTATUS
  10408. DismountDevice(
  10409. IN HANDLE FileHandle
  10410. )
  10411. /*++
  10412. Routine Description:
  10413. Dismounts a device.
  10414. Arguments:
  10415. FileHandle - file handle to use for performing dismount.
  10416. Return Value:
  10417. NT Status for request.
  10418. --*/
  10419. {
  10420. IO_STATUS_BLOCK ioStatusBlock;
  10421. NTSTATUS status;
  10422. HANDLE eventHandle;
  10423. CDLOG( "DismountDevice: Entry handle %p", FileHandle );
  10424. ClusDiskPrint(( 3,
  10425. "[ClusDisk] DismountDevice: Entry handle %p \n",
  10426. FileHandle ));
  10427. //
  10428. // Create event for notification.
  10429. //
  10430. status = ZwCreateEvent( &eventHandle,
  10431. EVENT_ALL_ACCESS,
  10432. NULL,
  10433. SynchronizationEvent,
  10434. FALSE );
  10435. if ( !NT_SUCCESS(status) ) {
  10436. CDLOG( "DismountDevice: Failed to create event" );
  10437. goto FnExit;
  10438. }
  10439. //
  10440. // Lock first.
  10441. //
  10442. // If raw FS mounted, dismount will fail if lock was not done first.
  10443. // By doing the lock, we insure we don't see dismount failures on
  10444. // disks with raw mounted.
  10445. //
  10446. CDLOG( "DismountDevice: FSCTL_LOCK_VOLUME called" );
  10447. status = ZwFsControlFile(
  10448. FileHandle,
  10449. eventHandle, // Event Handle
  10450. NULL, // APC Routine
  10451. NULL, // APC Context
  10452. &ioStatusBlock,
  10453. FSCTL_LOCK_VOLUME,
  10454. NULL, // InputBuffer
  10455. 0, // InputBufferLength
  10456. NULL, // OutputBuffer
  10457. 0 // OutputBufferLength
  10458. );
  10459. if ( status == STATUS_PENDING ) {
  10460. status = ZwWaitForSingleObject(eventHandle,
  10461. FALSE,
  10462. NULL);
  10463. ASSERT( NT_SUCCESS(status) );
  10464. status = ioStatusBlock.Status;
  10465. }
  10466. //
  10467. // Now dismount. We don't care if the lock failed.
  10468. //
  10469. CDLOG( "DismountDevice: FSCTL_DISMOUNT_VOLUME called" );
  10470. status = ZwFsControlFile(
  10471. FileHandle,
  10472. eventHandle, // Event Handle
  10473. NULL, // APC Routine
  10474. NULL, // APC Context
  10475. &ioStatusBlock,
  10476. FSCTL_DISMOUNT_VOLUME,
  10477. NULL, // InputBuffer
  10478. 0, // InputBufferLength
  10479. NULL, // OutputBuffer
  10480. 0 // OutputBufferLength
  10481. );
  10482. if ( status == STATUS_PENDING ) {
  10483. status = ZwWaitForSingleObject(eventHandle,
  10484. FALSE,
  10485. NULL);
  10486. ASSERT( NT_SUCCESS(status) );
  10487. status = ioStatusBlock.Status;
  10488. }
  10489. ZwClose( eventHandle );
  10490. if ( !NT_SUCCESS(status) && status != STATUS_VOLUME_DISMOUNTED) {
  10491. ClusDiskPrint((
  10492. 1,
  10493. "[ClusDisk] DismountDevice: Failed to dismount the volume. Status %08X.\n",
  10494. status
  10495. ));
  10496. }
  10497. FnExit:
  10498. CDLOG( "DismountDevice: Handle %p Exit => %!status!", FileHandle, status );
  10499. ClusDiskPrint(( 3,
  10500. "[ClusDisk] DismountDevice: Exit handle %p, status %08X \n",
  10501. FileHandle,
  10502. status ));
  10503. return(status);
  10504. } // DismountDevice
  10505. BOOLEAN
  10506. AttachedDevice(
  10507. IN ULONG Signature,
  10508. OUT PDEVICE_OBJECT *DeviceObject
  10509. )
  10510. /*++
  10511. Routine Description:
  10512. Find out whether we're supposed to attach to a given disk signature.
  10513. Arguments:
  10514. Signature - The signature to decide whether to attach or not.
  10515. DeviceObject - The DeviceObject for Partition0 if it is attached.
  10516. Return Value:
  10517. TRUE - if we're supposed to attach to this signature.
  10518. FALSE - if not.
  10519. --*/
  10520. {
  10521. PDEVICE_LIST_ENTRY deviceEntry;
  10522. // 2000/02/05: stevedz - added synchronization.
  10523. ACQUIRE_SHARED( &ClusDiskDeviceListLock );
  10524. deviceEntry = ClusDiskDeviceList;
  10525. while ( deviceEntry ) {
  10526. if ( deviceEntry->Signature == Signature ) {
  10527. if ( deviceEntry->Attached ) {
  10528. *DeviceObject = deviceEntry->DeviceObject;
  10529. RELEASE_SHARED( &ClusDiskDeviceListLock );
  10530. return(TRUE);
  10531. } else {
  10532. RELEASE_SHARED( &ClusDiskDeviceListLock );
  10533. return(FALSE);
  10534. }
  10535. }
  10536. deviceEntry = deviceEntry->Next;
  10537. }
  10538. RELEASE_SHARED( &ClusDiskDeviceListLock );
  10539. return(FALSE);
  10540. } // AttachedDevice
  10541. NTSTATUS
  10542. EnableHaltProcessing(
  10543. IN KIRQL *Irql
  10544. )
  10545. /*++
  10546. Routine Description:
  10547. Enable halt processing. This routine is called every time we create
  10548. an open reference to the ClusDisk control channel. The reference count
  10549. is bumped and if it transitions from zero to non-zero, we register
  10550. for a halt notification callback with the ClusterNetwork driver.
  10551. If we do open a handle to ClusterNetwork, we must leave it open until
  10552. we're all done.
  10553. Arguments:
  10554. None.
  10555. Return Value:
  10556. NTSTATUS for the request.
  10557. Notes:
  10558. This routine must be called with the ClusDiskSpinLock held.
  10559. --*/
  10560. {
  10561. NTSTATUS status;
  10562. PCLUS_DEVICE_EXTENSION deviceExtension;
  10563. KIRQL irql;
  10564. ULONG haltEnabled;
  10565. HALTPROC_CONTEXT context;
  10566. CDLOG( "EnableHaltProcessing: Entry Irql %!irql!", *Irql );
  10567. haltEnabled = ClusNetRefCount;
  10568. ClusNetRefCount++;
  10569. //
  10570. // If halt processing is already enabled, then leave now if ClusNetHandle
  10571. // is set. Otherwise, fall through, open clusnet driver, and try to save
  10572. // the handle. If multiple threads are saving the handle at the same time,
  10573. // only one will succeed - the other threads will release their handles.
  10574. // Note: the ClusNetHandle might still be null even if the reference
  10575. // count is non-zero. We might be in the process of performing the
  10576. // open on another thread. In this case, we no longer return an error.
  10577. // Instead, we fall through, and try to save the ClusNetHandle later.
  10578. //
  10579. if ( haltEnabled ) {
  10580. if ( ClusNetHandle != NULL ) {
  10581. CDLOG( "EnableHaltProcessing: ClusNetHandle already saved" );
  10582. return(STATUS_SUCCESS);
  10583. }
  10584. }
  10585. deviceExtension = RootDeviceObject->DeviceExtension;
  10586. KeReleaseSpinLock(&ClusDiskSpinLock, *Irql);
  10587. context.FileHandle = NULL;
  10588. context.DeviceExtension = deviceExtension;
  10589. status = ProcessDelayedWorkSynchronous( RootDeviceObject, EnableHaltProcessingWorker, &context );
  10590. KeAcquireSpinLock(&ClusDiskSpinLock, Irql);
  10591. if ( NT_SUCCESS(status) ) {
  10592. //
  10593. // If another thread is running concurrently and managed to save the handle, we need to close
  10594. // the one we just opened.
  10595. //
  10596. if ( ClusNetHandle != NULL ) {
  10597. //
  10598. // Don't close the handle directly - use the work queue. Release the spinlock before
  10599. // closing the handle. The context filehandle is already set.
  10600. //
  10601. KeReleaseSpinLock(&ClusDiskSpinLock, *Irql);
  10602. ProcessDelayedWorkSynchronous( RootDeviceObject, DisableHaltProcessingWorker, &context );
  10603. KeAcquireSpinLock(&ClusDiskSpinLock, Irql);
  10604. } else {
  10605. ClusNetHandle = context.FileHandle;
  10606. }
  10607. } else {
  10608. // Backout refcount
  10609. --ClusNetRefCount;
  10610. }
  10611. CDLOG( "EnableHaltProcessing: Exit Irql %!irql! => %!status!", *Irql, status );
  10612. return(status);
  10613. } // EnableHaltProcessing
  10614. VOID
  10615. EnableHaltProcessingWorker(
  10616. PDEVICE_OBJECT DeviceObject,
  10617. PWORK_CONTEXT WorkContext
  10618. )
  10619. /*++
  10620. Routine Description:
  10621. This routine runs in the system process and registers a callback with the
  10622. clusnet driver.
  10623. Arguments:
  10624. DeviceObject - Unused.
  10625. WorkContext - General context info and routine specific context info.
  10626. Return Value:
  10627. Status returned in WorkContext structure.
  10628. --*/
  10629. {
  10630. PHALTPROC_CONTEXT context = WorkContext->Context;
  10631. NTSTATUS status;
  10632. HANDLE fileHandle;
  10633. IO_STATUS_BLOCK ioStatusBlock;
  10634. UNICODE_STRING ntUnicodeString;
  10635. OBJECT_ATTRIBUTES objectAttributes;
  10636. PCLUS_DEVICE_EXTENSION deviceExtension;
  10637. KIRQL irql;
  10638. HANDLE eventHandle;
  10639. CLUSNET_SET_EVENT_MASK_REQUEST eventCallback;
  10640. ULONG haltEnabled;
  10641. //
  10642. // Create event for notification.
  10643. //
  10644. status = ZwCreateEvent( &eventHandle,
  10645. EVENT_ALL_ACCESS,
  10646. NULL,
  10647. SynchronizationEvent,
  10648. FALSE );
  10649. if ( !NT_SUCCESS(status) ) {
  10650. ClusDiskPrint((
  10651. 1,
  10652. "[ClusDisk] Failed to create event, status %lx\n",
  10653. status ));
  10654. goto FnExit;
  10655. }
  10656. //
  10657. // Setup event mask structure.
  10658. //
  10659. eventCallback.EventMask = ClusnetEventHalt |
  10660. ClusnetEventPoisonPacketReceived;
  10661. eventCallback.KmodeEventCallback = ClusDiskEventCallback;
  10662. //
  10663. // Create device name for the ClusterNetwork device.
  10664. //
  10665. RtlInitUnicodeString(&ntUnicodeString,
  10666. DD_CLUSNET_DEVICE_NAME);
  10667. //
  10668. // Try to open ClusterNetwork device.
  10669. //
  10670. InitializeObjectAttributes( &objectAttributes,
  10671. &ntUnicodeString,
  10672. OBJ_CASE_INSENSITIVE,
  10673. NULL,
  10674. NULL );
  10675. status = ZwCreateFile( &fileHandle,
  10676. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  10677. &objectAttributes,
  10678. &ioStatusBlock,
  10679. 0,
  10680. FILE_ATTRIBUTE_NORMAL,
  10681. FILE_SHARE_READ | FILE_SHARE_WRITE,
  10682. FILE_OPEN_IF,
  10683. 0,
  10684. NULL,
  10685. 0 );
  10686. ASSERT( status != STATUS_PENDING );
  10687. if ( NT_SUCCESS(status) ) {
  10688. status = ZwDeviceIoControlFile( fileHandle,
  10689. eventHandle,
  10690. NULL,
  10691. NULL,
  10692. &ioStatusBlock,
  10693. IOCTL_CLUSNET_SET_EVENT_MASK,
  10694. &eventCallback,
  10695. sizeof(eventCallback),
  10696. NULL,
  10697. 0 );
  10698. } else {
  10699. fileHandle = NULL;
  10700. }
  10701. if ( status == STATUS_PENDING ) {
  10702. status = ZwWaitForSingleObject(eventHandle,
  10703. FALSE,
  10704. NULL);
  10705. ASSERT( NT_SUCCESS(status) );
  10706. status = ioStatusBlock.Status;
  10707. }
  10708. ZwClose( eventHandle );
  10709. if ( !NT_SUCCESS(status) ) {
  10710. ClusDiskPrint((
  10711. 1,
  10712. "[ClusDisk] Failed to register for halt processing. Error %lx.\n",
  10713. status ));
  10714. if ( fileHandle ) {
  10715. ZwClose( fileHandle );
  10716. }
  10717. } else {
  10718. context->FileHandle = fileHandle;
  10719. }
  10720. FnExit:
  10721. ClusDiskPrint(( 3,
  10722. "[ClusDisk] EnableHaltProcessingWorker: Returning status %08X \n", status ));
  10723. WorkContext->FinalStatus = status;
  10724. KeSetEvent( &WorkContext->CompletionEvent, IO_NO_INCREMENT, FALSE );
  10725. } // EnableHaltProcessingWorker
  10726. NTSTATUS
  10727. DisableHaltProcessing(
  10728. IN KIRQL *Irql
  10729. )
  10730. /*++
  10731. Routine Description:
  10732. This routine disables halt processing as needed.
  10733. Arguments:
  10734. Irql - pointer to the irql that we were previously running.
  10735. Return Value:
  10736. NTSTATUS of request.
  10737. Note:
  10738. The ClusDiskSpinLock must be held on entry.
  10739. --*/
  10740. {
  10741. HANDLE clusNetHandle;
  10742. PCLUS_DEVICE_EXTENSION deviceExtension;
  10743. HALTPROC_CONTEXT context;
  10744. CDLOG( "DisableHaltProcessing: Entry Irql %!irql!", *Irql );
  10745. if ( ClusNetRefCount == 0 ) {
  10746. return(STATUS_INVALID_DEVICE_STATE);
  10747. }
  10748. ASSERT( ClusNetHandle != NULL );
  10749. if ( --ClusNetRefCount == 0 ) {
  10750. clusNetHandle = ClusNetHandle;
  10751. ClusNetHandle = NULL;
  10752. deviceExtension = RootDeviceObject->DeviceExtension;
  10753. //
  10754. // We must close the ClusterNetwork handle. But first leave
  10755. // the handle null, so we can release the spinlock and
  10756. // perform the decrement syncrhonized. This is just like
  10757. // the enable case when we release the spinlock.
  10758. //
  10759. KeReleaseSpinLock(&ClusDiskSpinLock, *Irql);
  10760. context.FileHandle = clusNetHandle;
  10761. ProcessDelayedWorkSynchronous( RootDeviceObject, DisableHaltProcessingWorker, &context );
  10762. KeAcquireSpinLock(&ClusDiskSpinLock, Irql);
  10763. // [GorN 12/09/99] We can get here if EnableHaltProcessing
  10764. // occurs while we are doing ZwClose( clusNetHandle );
  10765. // Don't need this assert:
  10766. //
  10767. // ASSERT( ClusNetRefCount == 0 );
  10768. }
  10769. CDLOG( "DisableHaltProcessing: Exit Irql %!irql!", *Irql );
  10770. return(STATUS_SUCCESS);
  10771. } // DisableHaltProcessing
  10772. VOID
  10773. DisableHaltProcessingWorker(
  10774. PDEVICE_OBJECT DeviceObject,
  10775. PWORK_CONTEXT WorkContext
  10776. )
  10777. /*++
  10778. Routine Description:
  10779. This routine runs in the system process and simply closes the clusnet
  10780. file handle.
  10781. Arguments:
  10782. DeviceObject - Unused.
  10783. WorkContext - General context info and routine specific context info.
  10784. Return Value:
  10785. None.
  10786. --*/
  10787. {
  10788. PHALTPROC_CONTEXT context = WorkContext->Context;
  10789. ZwClose( context->FileHandle );
  10790. ClusDiskPrint(( 3,
  10791. "[ClusDisk] DisableHaltProcessingWorker: Returns \n" ));
  10792. KeSetEvent( &WorkContext->CompletionEvent, IO_NO_INCREMENT, FALSE );
  10793. } // DisableHaltProcessingWorker
  10794. VOID
  10795. ClusDiskEventCallback(
  10796. IN CLUSNET_EVENT_TYPE EventType,
  10797. IN CL_NODE_ID NodeId,
  10798. IN CL_NETWORK_ID NetworkId
  10799. )
  10800. /*++
  10801. Routine Description:
  10802. Arguments:
  10803. Return Value:
  10804. None.
  10805. --*/
  10806. {
  10807. NTSTATUS status;
  10808. PDEVICE_OBJECT deviceObject;
  10809. PCLUS_DEVICE_EXTENSION deviceExtension;
  10810. KIRQL irql;
  10811. CDLOG( "ClusDiskEventCallback: Entry EventType %d NodeId %d NetworkId %d" ,
  10812. EventType,
  10813. NodeId,
  10814. NetworkId );
  10815. ClusDiskPrint((
  10816. 3,
  10817. "[ClusDisk] Halt Processing routine was called with event %lx.\n",
  10818. EventType ));
  10819. if ( RootDeviceObject == NULL ) {
  10820. return;
  10821. }
  10822. deviceObject = RootDeviceObject->DriverObject->DeviceObject;
  10823. // stevedz - Why stop the reservation before offline completes?
  10824. #if 0
  10825. // We later call ClusDiskCompletePendedIrps (inside ClusDiskHaltProcessingWorker),
  10826. // to mark disk offline and complete IRPs. ClusDiskCompletePendedIrps will
  10827. // clear the reserve flags.
  10828. //
  10829. // For each ClusDisk device, if we have a persistent reservation, then
  10830. // stop it.
  10831. //
  10832. while ( deviceObject ) {
  10833. deviceExtension = deviceObject->DeviceExtension;
  10834. if ( deviceExtension->BusType != RootBus ) {
  10835. deviceExtension->ReserveTimer = 0;
  10836. // Don't offline the device so that dismount can possibly work!
  10837. }
  10838. deviceObject = deviceObject->NextDevice;
  10839. }
  10840. #endif
  10841. //
  10842. // Now schedule a worker queue item to fully take the devices offline.
  10843. //
  10844. //
  10845. // Globally Synchronize
  10846. //
  10847. KeAcquireSpinLock(&ClusDiskSpinLock, &irql);
  10848. if ( !HaltBusy ) {
  10849. HaltBusy = TRUE;
  10850. ExQueueWorkItem(&HaltWorkItem,
  10851. CriticalWorkQueue );
  10852. }
  10853. KeReleaseSpinLock(&ClusDiskSpinLock, irql);
  10854. CDLOG( "ClusDiskEventCallback: Exit EventType %d NodeId %d NetworkId %d" ,
  10855. EventType,
  10856. NodeId,
  10857. NetworkId );
  10858. return;
  10859. } // ClusDiskEventCallback
  10860. VOID
  10861. ClusDiskLogError(
  10862. IN PDRIVER_OBJECT DriverObject,
  10863. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  10864. IN ULONG SequenceNumber,
  10865. IN UCHAR MajorFunctionCode,
  10866. IN UCHAR RetryCount,
  10867. IN ULONG UniqueErrorValue,
  10868. IN NTSTATUS FinalStatus,
  10869. IN NTSTATUS SpecificIOStatus,
  10870. IN ULONG LengthOfText,
  10871. IN PWCHAR Text
  10872. )
  10873. /*++
  10874. Routine Description:
  10875. This routine allocates an error log entry, copies the supplied data
  10876. to it, and requests that it be written to the error log file.
  10877. Arguments:
  10878. DriverObject - A pointer to the driver object for the device.
  10879. DeviceObject - A pointer to the device object associated with the
  10880. device that had the error, early in initialization, one may not
  10881. yet exist.
  10882. SequenceNumber - A ulong value that is unique to an IRP over the
  10883. life of the irp in this driver - 0 generally means an error not
  10884. associated with an irp.
  10885. MajorFunctionCode - If there is an error associated with the irp,
  10886. this is the major function code of that irp.
  10887. RetryCount - The number of times a particular operation has been
  10888. retried.
  10889. UniqueErrorValue - A unique long word that identifies the particular
  10890. call to this function.
  10891. FinalStatus - The final status given to the irp that was associated
  10892. with this error. If this log entry is being made during one of
  10893. the retries this value will be STATUS_SUCCESS.
  10894. SpecificIOStatus - The IO status for a particular error.
  10895. LengthOfText - The length in bytes (including the terminating NULL)
  10896. of the text insertion string.
  10897. Text - the text to dump.
  10898. Return Value:
  10899. None.
  10900. --*/
  10901. {
  10902. PIO_ERROR_LOG_PACKET errorLogEntry;
  10903. PVOID objectToUse;
  10904. PUCHAR ptrToText;
  10905. ULONG maxTextLength = 104;
  10906. if (ARGUMENT_PRESENT(DeviceObject)) {
  10907. objectToUse = DeviceObject;
  10908. } else {
  10909. objectToUse = DriverObject;
  10910. }
  10911. if ( LengthOfText < maxTextLength ) {
  10912. maxTextLength = LengthOfText;
  10913. }
  10914. errorLogEntry = IoAllocateErrorLogEntry(
  10915. objectToUse,
  10916. (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) + maxTextLength)
  10917. );
  10918. if ( errorLogEntry != NULL ) {
  10919. errorLogEntry->ErrorCode = SpecificIOStatus;
  10920. errorLogEntry->SequenceNumber = SequenceNumber;
  10921. errorLogEntry->MajorFunctionCode = MajorFunctionCode;
  10922. errorLogEntry->RetryCount = RetryCount;
  10923. errorLogEntry->UniqueErrorValue = UniqueErrorValue;
  10924. errorLogEntry->FinalStatus = FinalStatus;
  10925. errorLogEntry->DumpDataSize = 0;
  10926. ptrToText = (PUCHAR)&errorLogEntry->DumpData[0];
  10927. if (maxTextLength) {
  10928. errorLogEntry->NumberOfStrings = 1;
  10929. errorLogEntry->StringOffset = (USHORT)(ptrToText-
  10930. (PUCHAR)errorLogEntry);
  10931. RtlCopyMemory(
  10932. ptrToText,
  10933. Text,
  10934. maxTextLength
  10935. );
  10936. }
  10937. IoWriteErrorLogEntry(errorLogEntry);
  10938. } else {
  10939. ClusDiskPrint((1,
  10940. "[ClusDisk] Failed to allocate system buffer of size %u.\n",
  10941. sizeof(IO_ERROR_LOG_PACKET) + maxTextLength ));
  10942. }
  10943. } // ClusDiskLogError
  10944. NTSTATUS
  10945. CluSetFtMemberComplete(
  10946. IN PDEVICE_OBJECT DeviceObject,
  10947. IN PIRP Irp,
  10948. IN PVOID Context
  10949. )
  10950. /*++
  10951. Routine Description:
  10952. This routine puts the irp back the way it was before we call a lower
  10953. level driver. We don't care if the lower one succeeded or not.
  10954. Arguments:
  10955. DeviceObject - Pointer to the device object for the disk.
  10956. Irp - Pointer to the IRP for the current request.
  10957. Context - not used.
  10958. Return Value:
  10959. Always return status_success.
  10960. Notes:
  10961. This routine can only be called if ClusDisk succeed in changing
  10962. the state of the device.
  10963. --*/
  10964. {
  10965. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  10966. Irp->IoStatus.Status = STATUS_SUCCESS;
  10967. Irp->IoStatus.Information = (ULONG_PTR)currentIrpStack->Parameters.Others.Argument2;
  10968. Irp->AssociatedIrp.SystemBuffer = currentIrpStack->Parameters.Others.Argument1;
  10969. return(STATUS_SUCCESS);
  10970. }
  10971. NTSTATUS
  10972. ClusDiskMarkIrpPending(
  10973. PIRP Irp,
  10974. PDRIVER_CANCEL CancelRoutine
  10975. )
  10976. /*++
  10977. Notes:
  10978. Called with IoCancelSpinLock held.
  10979. --*/
  10980. {
  10981. KIRQL irql;
  10982. //
  10983. // Set up for cancellation
  10984. //
  10985. ASSERT(Irp->CancelRoutine == NULL);
  10986. if (!Irp->Cancel) {
  10987. IoMarkIrpPending(Irp);
  10988. IoSetCancelRoutine(Irp, CancelRoutine);
  10989. #if 0
  10990. ClusDiskPrint((
  10991. 1,
  10992. "[ClusDisk] Pending Irp %p \n",
  10993. Irp
  10994. ));
  10995. #endif
  10996. return(STATUS_SUCCESS);
  10997. }
  10998. //
  10999. // The IRP has already been cancelled.
  11000. //
  11001. ClusDiskPrint((
  11002. 1,
  11003. "[ClusDisk] Irp %lx already cancelled.\n", Irp));
  11004. return(STATUS_CANCELLED);
  11005. } // ClusDiskMarkIrpPending
  11006. VOID
  11007. ClusDiskCompletePendingRequest(
  11008. IN PIRP Irp,
  11009. IN NTSTATUS Status,
  11010. PCLUS_DEVICE_EXTENSION DeviceExtension
  11011. )
  11012. /*++
  11013. Routine Description:
  11014. Completes a pending request.
  11015. Arguments:
  11016. Irp - A pointer to the IRP for this request.
  11017. Status - The final status of the request.
  11018. Return Value:
  11019. None.
  11020. --*/
  11021. {
  11022. PIO_STACK_LOCATION irpSp;
  11023. irpSp = IoGetCurrentIrpStackLocation(Irp);
  11024. #if DBG
  11025. if (Irp->Cancel) {
  11026. ASSERT(Irp->CancelRoutine == NULL);
  11027. }
  11028. #endif // DBG
  11029. IoSetCancelRoutine(Irp, NULL);
  11030. #if 1
  11031. ClusDiskPrint((
  11032. 1,
  11033. "[ClusDisk] Completed waiting Irp %p \n",
  11034. Irp
  11035. ));
  11036. #endif
  11037. if (Irp->Cancel) {
  11038. #if 0
  11039. ClusDiskPrint((
  11040. 1,
  11041. "[ClusDisk] Completed irp %p was cancelled\n", Irp));
  11042. #endif
  11043. Status = STATUS_CANCELLED;
  11044. }
  11045. ReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
  11046. Irp->IoStatus.Status = (NTSTATUS) Status;
  11047. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  11048. return;
  11049. } // ClusDiskCompletePendingRequest
  11050. VOID
  11051. ClusDiskIrpCancel(
  11052. PDEVICE_OBJECT DeviceObject,
  11053. PIRP Irp
  11054. )
  11055. /*++
  11056. Routine Description:
  11057. Cancellation handler pending Irps.
  11058. Return Value:
  11059. None.
  11060. Notes:
  11061. Called with cancel spinlock held.
  11062. Returns with cancel spinlock released.
  11063. --*/
  11064. {
  11065. PCLUS_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  11066. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  11067. NTSTATUS status;
  11068. CDLOG( "IrpCancel: Entry DO %p irp %p", DeviceObject, Irp );
  11069. ClusDiskPrint((
  11070. 1,
  11071. "[ClusDisk] Cancel Irp %p, DevObj %p \n",
  11072. Irp,
  11073. DeviceObject ));
  11074. status = AcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  11075. if ( !NT_SUCCESS(status) ) {
  11076. ClusDiskPrint((
  11077. 1,
  11078. "[ClusDisk] ClusDiskIrpCancel: AcquireRemoveLock for %p failed %08X \n",
  11079. deviceExtension,
  11080. status ));
  11081. Irp->IoStatus.Status = status;
  11082. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  11083. return;
  11084. }
  11085. //
  11086. // If this Irp is associated with the control device object, then make
  11087. // sure the Irp is removed from the WaitingIoctls list first.
  11088. //
  11089. KeAcquireSpinLockAtDpcLevel(&ClusDiskSpinLock);
  11090. RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
  11091. KeReleaseSpinLockFromDpcLevel(&ClusDiskSpinLock);
  11092. IoSetCancelRoutine(Irp, NULL);
  11093. //
  11094. // Release the cancel spinlock here, so that we are not holding the
  11095. // spinlock when we complete the Irp.
  11096. //
  11097. IoReleaseCancelSpinLock(Irp->CancelIrql);
  11098. ReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  11099. Irp->IoStatus.Status = STATUS_CANCELLED;
  11100. Irp->IoStatus.Information = 0;
  11101. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  11102. CDLOG( "IrpCancel: Exit DO %p irp %p", DeviceObject, Irp );
  11103. return;
  11104. } // ClusDiskIrpCancel
  11105. NTSTATUS
  11106. ClusDiskForwardIrpSynchronous(
  11107. IN PDEVICE_OBJECT DeviceObject,
  11108. IN PIRP Irp
  11109. )
  11110. /*++
  11111. Routine Description:
  11112. This routine sends the Irp to the next driver in line
  11113. when the Irp needs to be processed by the lower drivers
  11114. prior to being processed by this one.
  11115. Arguments:
  11116. DeviceObject
  11117. Irp
  11118. Return Value:
  11119. NTSTATUS
  11120. --*/
  11121. {
  11122. PCLUS_DEVICE_EXTENSION deviceExtension;
  11123. KEVENT event;
  11124. NTSTATUS status;
  11125. KeInitializeEvent( &event, NotificationEvent, FALSE );
  11126. deviceExtension = (PCLUS_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
  11127. //
  11128. // copy the irpstack for the next device
  11129. //
  11130. IoCopyCurrentIrpStackLocationToNext( Irp );
  11131. //
  11132. // set a completion routine
  11133. //
  11134. IoSetCompletionRoutine( Irp, ClusDiskIrpCompletion,
  11135. &event, TRUE, TRUE, TRUE );
  11136. //
  11137. // call the next lower device
  11138. //
  11139. status = IoCallDriver( deviceExtension->TargetDeviceObject, Irp );
  11140. //
  11141. // wait for the actual completion
  11142. //
  11143. if ( status == STATUS_PENDING ) {
  11144. KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
  11145. status = Irp->IoStatus.Status;
  11146. }
  11147. return status;
  11148. } // ClusDiskForwardIrpSynchronous()
  11149. #if 0
  11150. NTSTATUS
  11151. EjectVolumes(
  11152. IN PDEVICE_OBJECT DeviceObject
  11153. )
  11154. /*++
  11155. Routine Description:
  11156. This routine tells the partmgr to eject all volumes. For the volume manager
  11157. to re-attach to the volumes, IOCTL_PARTMGR_CHECK_UNCLAIMED_PARTITIONS is used.
  11158. The cluster service calls IOCTL_PARTMGR_CHECK_UNCLAIMED_PARTITIONS when bringing
  11159. the disk online, so it is not necessary to make this call in the driver.
  11160. Note that this routine should only be called for physical devices (partition0)
  11161. and that no one should be using the volumes.
  11162. Arguments:
  11163. Return Value:
  11164. NTSTATUS
  11165. --*/
  11166. {
  11167. PIRP irp;
  11168. PKEVENT event = NULL;
  11169. PCLUS_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  11170. IO_STATUS_BLOCK ioStatusBlock;
  11171. NTSTATUS status = STATUS_SUCCESS;
  11172. // Looks like the IO request will bypass clusdisk at the physical disk level
  11173. // because clusdisk attached after FTDISK went looking for the top of the disk
  11174. // stack and cached the pointer.
  11175. //
  11176. // PnP race condition: occasionally, the device stack was incorrect and clustered
  11177. // disks weren't being protected properly. Since we are using PnP notification
  11178. // instead of an AddDevice routine, there was a small window where we would
  11179. // attach to the device stack correctly, but another driver was also attaching
  11180. // at the same time. So I/O bound for the device would go like this:
  11181. // NTFS -> Volsnap -> Ftdisk -> Disk
  11182. //
  11183. // even though the device stack looked like this:
  11184. // 82171a50 \Driver\ClusDisk 82171b08 ClusDisk1Part0
  11185. // 822be720 \Driver\PartMgr 822be7d8
  11186. // 822bd030 \Driver\Disk 822bd0e8 DR1
  11187. // 822c0990 \Driver\aic78xx 822c0a48 aic78xx1Port2Path0Target0Lun0
  11188. //
  11189. // So we have to tell partmgr to eject all the volume managers and then
  11190. // let the volume managers attach again. This has the effect of removing the
  11191. // cached pointer
  11192. //
  11193. // To tell the volume managers to stop using this disk:
  11194. // IOCTL_PARTMGR_EJECT_VOLUME_MANAGERS
  11195. //
  11196. // To tell the volume managers they can start using the disk:
  11197. // IOCTL_PARTMGR_CHECK_UNCLAIMED_PARTITIONS
  11198. CDLOG( "EjectVolumes: Entry DO %p", DeviceObject );
  11199. if ( !deviceExtension->TargetDeviceObject ) {
  11200. status = STATUS_INVALID_PARAMETER;
  11201. goto FnExit;
  11202. }
  11203. event = ExAllocatePool( NonPagedPool,
  11204. sizeof(KEVENT) );
  11205. if ( NULL == event ) {
  11206. status = STATUS_INSUFFICIENT_RESOURCES;
  11207. goto FnExit;
  11208. }
  11209. //
  11210. // Eject the volume managers.
  11211. //
  11212. irp = IoBuildDeviceIoControlRequest( IOCTL_PARTMGR_EJECT_VOLUME_MANAGERS,
  11213. deviceExtension->TargetDeviceObject,
  11214. NULL,
  11215. 0,
  11216. NULL,
  11217. 0,
  11218. FALSE,
  11219. event,
  11220. &ioStatusBlock );
  11221. if ( !irp ) {
  11222. ClusDiskPrint((
  11223. 1,
  11224. "[ClusDisk] EjectVolumes: Failed to build IRP to eject volume managers. \n"
  11225. ));
  11226. status = STATUS_UNSUCCESSFUL;
  11227. goto FnExit;
  11228. }
  11229. //
  11230. // Set the event object to the unsignaled state.
  11231. // It will be used to signal request completion.
  11232. //
  11233. KeInitializeEvent( event,
  11234. NotificationEvent,
  11235. FALSE );
  11236. status = IoCallDriver( deviceExtension->TargetDeviceObject,
  11237. irp );
  11238. if ( STATUS_PENDING == status ) {
  11239. KeWaitForSingleObject( event,
  11240. Suspended,
  11241. KernelMode,
  11242. FALSE,
  11243. NULL );
  11244. status = ioStatusBlock.Status;
  11245. }
  11246. ClusDiskPrint((3,
  11247. "[ClusDisk] EjectVolumes: Eject IOCTL returns %08X \n",
  11248. status
  11249. ));
  11250. FnExit:
  11251. if ( event ) {
  11252. ExFreePool( event );
  11253. }
  11254. ClusDiskPrint((1,
  11255. "[ClusDisk] EjectVolumes: Target devobj %p Final status %08X \n",
  11256. DeviceObject,
  11257. status
  11258. ));
  11259. CDLOG( "EjectVolumes: Exit DO %p, status %08X", DeviceObject, status );
  11260. return status;
  11261. } // EjectVolumes
  11262. #endif
  11263. #if 0 // Removed 2/27/2001
  11264. NTSTATUS
  11265. ReclaimVolumes(
  11266. IN PDEVICE_OBJECT DeviceObject
  11267. )
  11268. /*++
  11269. Routine Description:
  11270. This routine tells the partmgr to reclaim all volumes.
  11271. Note that this routine should only be called for physical devices (partition0)
  11272. and that no one should be using the volumes.
  11273. Arguments:
  11274. Return Value:
  11275. NTSTATUS
  11276. --*/
  11277. {
  11278. PCLUS_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  11279. PIRP irp = NULL;
  11280. PKEVENT event = NULL;
  11281. IO_STATUS_BLOCK ioStatusBlock;
  11282. NTSTATUS status = STATUS_SUCCESS;
  11283. CDLOG( "ReclaimVolumes: Entry DO %p", DeviceObject );
  11284. InterlockedIncrement( &deviceExtension->ReclaimInProgress );
  11285. if ( !deviceExtension->TargetDeviceObject ) {
  11286. status = STATUS_INVALID_PARAMETER;
  11287. goto FnExit;
  11288. }
  11289. event = ExAllocatePool( NonPagedPool,
  11290. sizeof(KEVENT) );
  11291. if ( NULL == event ) {
  11292. status = STATUS_INSUFFICIENT_RESOURCES;
  11293. goto FnExit;
  11294. }
  11295. //
  11296. // Allow the volume managers to reclaim partitions.
  11297. //
  11298. irp = IoBuildDeviceIoControlRequest( IOCTL_PARTMGR_CHECK_UNCLAIMED_PARTITIONS,
  11299. deviceExtension->TargetDeviceObject,
  11300. NULL,
  11301. 0,
  11302. NULL,
  11303. 0,
  11304. FALSE,
  11305. event,
  11306. &ioStatusBlock );
  11307. if ( !irp ) {
  11308. ClusDiskPrint((
  11309. 1,
  11310. "[ClusDisk] Failed to build IRP to check unclaimed partitions. \n"
  11311. ));
  11312. status = STATUS_UNSUCCESSFUL;
  11313. goto FnExit;
  11314. }
  11315. //
  11316. // Set the event object to the unsignaled state.
  11317. // It will be used to signal request completion.
  11318. //
  11319. KeInitializeEvent( event,
  11320. NotificationEvent,
  11321. FALSE );
  11322. status = IoCallDriver( deviceExtension->TargetDeviceObject,
  11323. irp );
  11324. if ( status == STATUS_PENDING ) {
  11325. KeWaitForSingleObject( event,
  11326. Suspended,
  11327. KernelMode,
  11328. FALSE,
  11329. NULL );
  11330. status = ioStatusBlock.Status;
  11331. }
  11332. FnExit:
  11333. if ( event ) {
  11334. ExFreePool( event );
  11335. }
  11336. ClusDiskPrint((1,
  11337. "[ClusDisk] ReclaimVolumes: Target devobj %p Final status %08X \n",
  11338. DeviceObject,
  11339. status
  11340. ));
  11341. CDLOG( "ReclaimVolumes: Exit DO %p, status %08X", DeviceObject, status );
  11342. InterlockedDecrement( &deviceExtension->ReclaimInProgress );
  11343. return status;
  11344. } // ReclaimVolumes
  11345. #endif
  11346. BOOLEAN
  11347. IsDiskMbr(
  11348. IN PDEVICE_OBJECT DeviceObject
  11349. )
  11350. /*++
  11351. Routine Description:
  11352. Indicate whether the specified disk is MBR or not.
  11353. If the disk is reserved by another node, then the disk must be MBR. In this case,
  11354. IOCTL_DISK_GET_DRIVE_LAYOUT_EX will fail and we return TRUE indicating that this
  11355. could be an MBR disk.
  11356. If the disk is not reserved by another node, then the disk could be GPT or MBR.
  11357. If IOCTL_DISK_GET_DRIVE_LAYOUT_EX succeeds, we check the drive layout info and
  11358. determine the partition style. If it is not MBR, we return FALSE. If the drive
  11359. layout partition style indicates we are MBR, then we return TRUE.
  11360. Arguments:
  11361. DeviceObject - The specific device object to return info about
  11362. Return Value:
  11363. TRUE - if the disk is MBR or we couldn't get the drive layout info.
  11364. --*/
  11365. {
  11366. PDRIVE_LAYOUT_INFORMATION_EX driveLayoutInfo = NULL;
  11367. NTSTATUS status;
  11368. ULONG driveLayoutSize;
  11369. BOOLEAN retVal = TRUE;
  11370. if ( !DeviceObject ) {
  11371. goto FnExit;
  11372. }
  11373. //
  11374. // Allocate a drive layout buffer.
  11375. //
  11376. driveLayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
  11377. (MAX_PARTITIONS * sizeof(PARTITION_INFORMATION_EX));
  11378. driveLayoutInfo = ExAllocatePool( NonPagedPoolCacheAligned,
  11379. driveLayoutSize
  11380. );
  11381. if ( !driveLayoutInfo ) {
  11382. ClusDiskPrint(( 1,
  11383. "[ClusDisk] Failed to allocate drive layout (ex) structure. \n"
  11384. ));
  11385. goto FnExit;
  11386. }
  11387. //
  11388. // Now get the drive layout information
  11389. //
  11390. status = SimpleDeviceIoControl( DeviceObject,
  11391. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  11392. NULL,
  11393. 0,
  11394. driveLayoutInfo,
  11395. driveLayoutSize
  11396. );
  11397. if ( !NT_SUCCESS(status) ) {
  11398. //
  11399. // Couldn't get the drive layout. Free the temporary buffer and return
  11400. // to the caller.
  11401. //
  11402. ClusDiskPrint(( 1,
  11403. "[ClusDisk] Failed to issue IoctlDiskGetDriveLayoutEx. %08X\n",
  11404. status
  11405. ));
  11406. CDLOG( "IsDiskMbr(%p): failed %!status!",
  11407. DeviceObject,
  11408. status );
  11409. goto FnExit;
  11410. }
  11411. //
  11412. // At this point, we have the drive layout. Check if we are working with a
  11413. // MBR disk. If not MBR, set return to FALSE.
  11414. //
  11415. if ( PARTITION_STYLE_MBR != driveLayoutInfo->PartitionStyle ) {
  11416. retVal = FALSE;
  11417. }
  11418. FnExit:
  11419. if ( driveLayoutInfo) {
  11420. ExFreePool( driveLayoutInfo );
  11421. }
  11422. return retVal;
  11423. } // IsDiskMbr
  11424. NTSTATUS
  11425. SetVolumeState(
  11426. PCLUS_DEVICE_EXTENSION PhysicalDisk,
  11427. ULONG NewDiskState
  11428. )
  11429. {
  11430. PVOL_STATE_INFO volStateInfo = NULL;
  11431. NTSTATUS status = STATUS_SUCCESS;
  11432. //
  11433. // If this isn't the physical disk (i.e. partition 0), then exit.
  11434. //
  11435. if ( PhysicalDisk != PhysicalDisk->PhysicalDevice->DeviceExtension ) {
  11436. status = STATUS_INVALID_PARAMETER;
  11437. goto FnExit;
  11438. }
  11439. #if 0
  11440. // Don't use this...
  11441. // Optimization? If new state is equal to old state, we are done.
  11442. // Should work as long as this device extension is set AFTER the
  11443. // call to SetVolumeState. Currently the macros set the device extension
  11444. // state BEFORE calling this routine. Also, some routines set DE state
  11445. // well before calling this routine.
  11446. // More testing...
  11447. if ( NewDiskState == DeviceExtension->DiskState ) {
  11448. goto FnExit;
  11449. }
  11450. #endif
  11451. volStateInfo = ExAllocatePool( NonPagedPool, sizeof( VOL_STATE_INFO ) );
  11452. if ( !volStateInfo ) {
  11453. status = STATUS_INSUFFICIENT_RESOURCES;
  11454. goto FnExit;
  11455. }
  11456. volStateInfo->NewDiskState = NewDiskState;
  11457. volStateInfo->WorkItem = NULL;
  11458. //
  11459. // If IRQL is PASSIVE_LEVEL, call the routine directly.
  11460. // We know the call is direct because the WorkItem portion will
  11461. // be NULL.
  11462. //
  11463. if ( PASSIVE_LEVEL == KeGetCurrentIrql() ) {
  11464. SetVolumeStateWorker( PhysicalDisk->DeviceObject,
  11465. volStateInfo );
  11466. goto FnExit;
  11467. }
  11468. volStateInfo->WorkItem = IoAllocateWorkItem( PhysicalDisk->DeviceObject );
  11469. if ( !volStateInfo->WorkItem ) {
  11470. ExFreePool( volStateInfo );
  11471. status = STATUS_INSUFFICIENT_RESOURCES;
  11472. goto FnExit;
  11473. }
  11474. IoQueueWorkItem( volStateInfo->WorkItem,
  11475. SetVolumeStateWorker,
  11476. CriticalWorkQueue,
  11477. volStateInfo );
  11478. FnExit:
  11479. return status;
  11480. } // SetVolumeState
  11481. VOID
  11482. SetVolumeStateWorker(
  11483. PDEVICE_OBJECT DeviceObject,
  11484. PVOID Context
  11485. )
  11486. /*++
  11487. Routine Description:
  11488. Call volume manager to mark all volumes for this disk offline or online.
  11489. If the IRQL is not PASSIVE_LEVEL, then this routine will return an error.
  11490. Arguments:
  11491. DeviceObject - Clustered disk to set state.
  11492. Context - Contains information whether this routine has been called directly
  11493. or via a work item. Also indicates whether this is an online or
  11494. offline request.
  11495. Return Value:
  11496. None.
  11497. --*/
  11498. {
  11499. PDRIVE_LAYOUT_INFORMATION driveLayoutInfo = NULL;
  11500. PPARTITION_INFORMATION partitionInfo;
  11501. PIO_WORKITEM workItem = ((PVOL_STATE_INFO)Context)->WorkItem;
  11502. PCLUS_DEVICE_EXTENSION PhysicalDisk = DeviceObject->DeviceExtension;
  11503. NTSTATUS status;
  11504. ULONG ioctl;
  11505. ULONG partIndex;
  11506. ULONG newDiskState = ((PVOL_STATE_INFO)Context)->NewDiskState;
  11507. KIRQL irql;
  11508. CDLOG( "SetVolumeState: Entry DevObj %p newstate: %s workItem: %p ",
  11509. PhysicalDisk->DeviceObject,
  11510. ( DiskOnline == newDiskState ? "DiskOnline" : "DiskOffline" ),
  11511. workItem );
  11512. ClusDiskPrint(( 3,
  11513. "[ClusDisk] SetVolumeState: DevObj %p newstate: %s workItem: %p \n",
  11514. PhysicalDisk->DeviceObject,
  11515. DiskStateToString( newDiskState ),
  11516. workItem ));
  11517. irql = KeGetCurrentIrql();
  11518. if ( PASSIVE_LEVEL != irql ) {
  11519. ClusDiskPrint(( 1,
  11520. "[ClusDisk] SetVolumeState: Current IRQL %d not PASSIVE_LEVEL - skipping state change \n",
  11521. irql ));
  11522. ASSERT( FALSE );
  11523. goto FnExit;
  11524. }
  11525. //
  11526. // This should never happen as it was checked earlier.
  11527. //
  11528. if ( PhysicalDisk != PhysicalDisk->PhysicalDevice->DeviceExtension ) {
  11529. ASSERT( FALSE );
  11530. PhysicalDisk = PhysicalDisk->PhysicalDevice->DeviceExtension;
  11531. ClusDiskPrint(( 1,
  11532. "[ClusDisk] SetVolumeState: Resetting physical disk pointer: DevObj %p \n",
  11533. PhysicalDisk->DeviceObject ));
  11534. }
  11535. if ( DiskOnline == newDiskState ) {
  11536. ioctl = IOCTL_VOLUME_ONLINE;
  11537. } else {
  11538. ioctl = IOCTL_VOLUME_OFFLINE;
  11539. }
  11540. //
  11541. // Get the drive layout for the disk.
  11542. //
  11543. status = GetDriveLayout( PhysicalDisk->DeviceObject,
  11544. &driveLayoutInfo,
  11545. FALSE );
  11546. if ( !NT_SUCCESS(status) || !driveLayoutInfo ) {
  11547. ClusDiskPrint(( 1,
  11548. "[ClusDisk] SetVolumeState: Failed to read partition info, status %08X \n",
  11549. status ));
  11550. goto FnExit;
  11551. }
  11552. for ( partIndex = 0;
  11553. partIndex < driveLayoutInfo->PartitionCount;
  11554. partIndex++ ) {
  11555. partitionInfo = &driveLayoutInfo->PartitionEntry[partIndex];
  11556. if ( 0 == partitionInfo->PartitionNumber ) {
  11557. continue;
  11558. }
  11559. // Online/Offline the volume.
  11560. status = SendFtdiskIoctlSync( NULL,
  11561. PhysicalDisk->DiskNumber,
  11562. partitionInfo->PartitionNumber,
  11563. ioctl );
  11564. if ( !NT_SUCCESS(status) ) {
  11565. ClusDiskPrint(( 1,
  11566. "[ClusDisk] SetVolumeState: Failed to set state disk%d part%d , status %08X \n",
  11567. PhysicalDisk->DiskNumber,
  11568. partitionInfo->PartitionNumber,
  11569. status
  11570. ));
  11571. }
  11572. }
  11573. FnExit:
  11574. CDLOG( "SetVolumeState: Exit DevObj %p DiskNumber %d newstate: %s status %x ",
  11575. PhysicalDisk->DeviceObject,
  11576. PhysicalDisk->DiskNumber,
  11577. ( DiskOnline == newDiskState ? "DiskOnline" : "DiskOffline" ),
  11578. status );
  11579. ClusDiskPrint(( 3,
  11580. "[ClusDisk] SetVolumeState: DiskNumber %d newstate: %s final status %08X \n",
  11581. PhysicalDisk->DiskNumber,
  11582. ( DiskOnline == newDiskState ? "DiskOnline" : "DiskOffline" ),
  11583. status
  11584. ));
  11585. if ( driveLayoutInfo ) {
  11586. ExFreePool( driveLayoutInfo );
  11587. }
  11588. if ( workItem ) {
  11589. IoFreeWorkItem( workItem );
  11590. }
  11591. if ( Context ) {
  11592. ExFreePool( Context );
  11593. }
  11594. return;
  11595. } // SetVolumeStateWorker
  11596. NTSTATUS
  11597. SendFtdiskIoctlSync(
  11598. PDEVICE_OBJECT TargetObject,
  11599. ULONG DiskNumber,
  11600. ULONG PartNumber,
  11601. ULONG Ioctl
  11602. )
  11603. {
  11604. PIRP irp;
  11605. PDEVICE_OBJECT targetDevice = NULL;
  11606. KEVENT event;
  11607. NTSTATUS status;
  11608. IO_STATUS_BLOCK ioStatusBlock;
  11609. WCHAR partitionNameBuffer[MAX_PARTITION_NAME_LENGTH];
  11610. UNICODE_STRING targetDeviceName;
  11611. if ( TargetObject ) {
  11612. targetDevice = TargetObject;
  11613. } else {
  11614. //
  11615. // Create device name for the physical disk.
  11616. //
  11617. swprintf( partitionNameBuffer,
  11618. DEVICE_PARTITION_NAME,
  11619. DiskNumber,
  11620. PartNumber );
  11621. WCSLEN_ASSERT( partitionNameBuffer );
  11622. ClusDiskPrint(( 3,
  11623. "[ClusDisk] SendFtdiskIoctlSync: Device %ws \n",
  11624. partitionNameBuffer
  11625. ));
  11626. status = ClusDiskGetTargetDevice( DiskNumber,
  11627. PartNumber,
  11628. &targetDevice,
  11629. &targetDeviceName,
  11630. NULL,
  11631. NULL,
  11632. FALSE );
  11633. if ( targetDeviceName.Buffer ) {
  11634. RtlFreeUnicodeString(&targetDeviceName);
  11635. }
  11636. }
  11637. if ( !targetDevice ) {
  11638. ClusDiskPrint(( 1,
  11639. "[ClusDisk] SendFtdiskIoctlSync: Failed to get devobj for disk %d partition %d \n",
  11640. DiskNumber,
  11641. PartNumber
  11642. ));
  11643. status = STATUS_OBJECT_NAME_NOT_FOUND;
  11644. goto FnExit;
  11645. }
  11646. //
  11647. // Set the event object to the unsignaled state.
  11648. // It will be used to signal request completion.
  11649. //
  11650. KeInitializeEvent( &event,
  11651. NotificationEvent,
  11652. FALSE );
  11653. irp = IoBuildDeviceIoControlRequest( Ioctl,
  11654. targetDevice,
  11655. NULL,
  11656. 0,
  11657. NULL,
  11658. 0,
  11659. FALSE,
  11660. &event,
  11661. &ioStatusBlock );
  11662. if ( !irp ) {
  11663. ClusDiskPrint(( 1,
  11664. "[ClusDisk] SendFtdiskIoctlSync: Failed to build IRP for IOCTL %X \n", Ioctl ));
  11665. status = STATUS_INSUFFICIENT_RESOURCES;
  11666. goto FnExit;
  11667. }
  11668. status = IoCallDriver( targetDevice,
  11669. irp );
  11670. if ( STATUS_PENDING == status ) {
  11671. KeWaitForSingleObject( &event,
  11672. Executive,
  11673. KernelMode,
  11674. FALSE,
  11675. NULL );
  11676. status = ioStatusBlock.Status;
  11677. }
  11678. FnExit:
  11679. if ( !TargetObject ) {
  11680. DEREFERENCE_OBJECT( targetDevice );
  11681. }
  11682. CDLOG( "SendFtDiskIoctlSync: Exit disk %d part %d IOCTL %X status %X",
  11683. DiskNumber, PartNumber, Ioctl, status );
  11684. ClusDiskPrint(( 3,
  11685. "[ClusDisk] SendFtDiskIoctlSync: disk %d part %d IOCTL %X status %08X \n",
  11686. DiskNumber,
  11687. PartNumber,
  11688. Ioctl,
  11689. status
  11690. ));
  11691. return status;
  11692. } // SendFtdiskIoctlSync
  11693. NTSTATUS
  11694. AttachSignatureList(
  11695. PDEVICE_OBJECT DeviceObject,
  11696. PULONG InBuffer,
  11697. ULONG InBufferLen
  11698. )
  11699. {
  11700. ULONG idx;
  11701. ULONG signature;
  11702. NTSTATUS status = STATUS_INVALID_PARAMETER;
  11703. NTSTATUS retVal;
  11704. BOOLEAN stopProcessing = FALSE;
  11705. UNICODE_STRING signatureName;
  11706. UNICODE_STRING availableName;
  11707. signatureName.Buffer = NULL;
  11708. availableName.Buffer = NULL;
  11709. ClusDiskPrint(( 3,
  11710. "[ClusDisk] AttachSignatureList: list at %p, length %d \n",
  11711. InBuffer,
  11712. InBufferLen ));
  11713. CDLOG( "AttachSignatureList: siglist %p, length %d ", InBuffer, InBufferLen );
  11714. if ( !InBufferLen ) {
  11715. status = STATUS_SUCCESS;
  11716. goto FnExit;
  11717. }
  11718. if ( InBuffer &&
  11719. InBufferLen &&
  11720. InBufferLen >= sizeof(ULONG) &&
  11721. ( InBufferLen % sizeof(ULONG) == 0 ) ) {
  11722. //
  11723. // Allocate buffer for Signatures registry key. So we can add
  11724. // the signature.
  11725. //
  11726. status = ClusDiskInitRegistryString( &signatureName,
  11727. CLUSDISK_SIGNATURE_KEYNAME,
  11728. sizeof(CLUSDISK_SIGNATURE_KEYNAME)
  11729. );
  11730. if ( !NT_SUCCESS(status) ) {
  11731. goto FnExit;
  11732. }
  11733. //
  11734. // Allocate buffer for AvailableDisks registry key.
  11735. //
  11736. status = ClusDiskInitRegistryString( &availableName,
  11737. CLUSDISK_AVAILABLE_DISKS_KEYNAME,
  11738. sizeof(CLUSDISK_AVAILABLE_DISKS_KEYNAME) );
  11739. if ( !NT_SUCCESS(status) ) {
  11740. goto FnExit;
  11741. }
  11742. for ( idx = 0; idx < InBufferLen / sizeof(ULONG); idx++ ) {
  11743. signature = InBuffer[idx];
  11744. ClusDiskPrint((1,
  11745. "[ClusDisk] AttachSignatureList: attaching signature %08X\n",
  11746. signature));
  11747. CDLOG( "AttachSignatureList: sig %08x", signature );
  11748. //
  11749. // No signature or system disk signature, don't add it.
  11750. //
  11751. if ( ( 0 == signature ) || SystemDiskSignature == signature ) {
  11752. ClusDiskPrint((2,
  11753. "[ClusDisk] AttachSignatureList: skipping signature %08X\n",
  11754. signature));
  11755. CDLOG( "AttachSignatureList: skipping sig %08x", signature );
  11756. continue;
  11757. }
  11758. // We have to force the signature under \Parameters\Signatures because
  11759. // the disk might not be accessible (i.e. reserved by another node) and
  11760. // ClusDiskAttachDevice will only put the signature there if the
  11761. // disk can really be attached.
  11762. //
  11763. // Create the signature key under \Parameters\Signatures.
  11764. //
  11765. retVal = ClusDiskAddSignature( &signatureName,
  11766. signature,
  11767. FALSE
  11768. );
  11769. //
  11770. // Error adding this signature, save the error for return and continue
  11771. // with the signature list.
  11772. //
  11773. if ( !NT_SUCCESS(retVal) ) {
  11774. status = retVal;
  11775. continue;
  11776. }
  11777. //
  11778. // Delete the signature key under Parameters\AvailableDisks.
  11779. //
  11780. ClusDiskDeleteSignature( &availableName,
  11781. signature );
  11782. //
  11783. // Just try to attach to the device with no bus resets.
  11784. //
  11785. ClusDiskAttachDevice( signature,
  11786. 0,
  11787. DeviceObject->DriverObject,
  11788. FALSE,
  11789. &stopProcessing );
  11790. }
  11791. }
  11792. FnExit:
  11793. if ( signatureName.Buffer ) {
  11794. ExFreePool( signatureName.Buffer );
  11795. }
  11796. if ( availableName.Buffer ) {
  11797. ExFreePool( availableName.Buffer );
  11798. }
  11799. ClusDiskPrint(( 3,
  11800. "[ClusDisk] AttachSignatureList: returning final status %08X \n",
  11801. status ));
  11802. CDLOG( "AttachSignatureList: returning final status %x ", status );
  11803. return status;
  11804. } // AttachSignatureList
  11805. NTSTATUS
  11806. DetachSignatureList(
  11807. PDEVICE_OBJECT DeviceObject,
  11808. PULONG InBuffer,
  11809. ULONG InBufferLen
  11810. )
  11811. {
  11812. ULONG idx;
  11813. ULONG signature;
  11814. NTSTATUS status = STATUS_SUCCESS;
  11815. NTSTATUS retVal;
  11816. ClusDiskPrint(( 3,
  11817. "[ClusDisk] DetachSignatureList: list at %p, length %d \n",
  11818. InBuffer,
  11819. InBufferLen ));
  11820. CDLOG( "DetachSignatureList: list %p, length %d ", InBuffer, InBufferLen );
  11821. if ( !InBufferLen ) {
  11822. status = STATUS_SUCCESS;
  11823. goto FnExit;
  11824. }
  11825. if ( InBuffer &&
  11826. InBufferLen &&
  11827. InBufferLen >= sizeof(ULONG) &&
  11828. ( InBufferLen % sizeof(ULONG) == 0 ) ) {
  11829. for ( idx = 0; idx < InBufferLen / sizeof(ULONG); idx++ ) {
  11830. signature = InBuffer[idx];
  11831. ClusDiskPrint((1,
  11832. "[ClusDisk] DetachSignatureList: detaching signature %08X\n",
  11833. signature));
  11834. CDLOG( "DetachSignatureList: sig %08x", signature );
  11835. // Skip zero signature.
  11836. if ( !signature ) {
  11837. ClusDiskPrint((2,
  11838. "[ClusDisk] DetachSignatureList: skipping signature %08X\n",
  11839. signature));
  11840. CDLOG( "DetachSignatureList: skipping sig %08x", signature );
  11841. continue;
  11842. }
  11843. retVal = ClusDiskDetachDevice( signature, DeviceObject->DriverObject );
  11844. //
  11845. // If any detach fails, return an error. If multiple detachs fail, there
  11846. // is no way to pass back information on which specific signature failed,
  11847. // so simply indicate one of the failures back to the caller.
  11848. // On failure, we still want to continue detaching, so don't break out
  11849. // of the loop.
  11850. //
  11851. if ( !NT_SUCCESS(retVal) ) {
  11852. status = retVal;
  11853. }
  11854. }
  11855. }
  11856. FnExit:
  11857. ClusDiskPrint(( 3,
  11858. "[ClusDisk] DetachSignatureList: returning final status %08X \n",
  11859. status ));
  11860. CDLOG( "DetachSignatureList: returning final status %x ", status );
  11861. // Always return success.
  11862. // Cluster setup will send a NULL buffer with zero length when rejoining a node.
  11863. return status;
  11864. } // DetachSignatureList
  11865. NTSTATUS
  11866. CleanupDeviceList(
  11867. PDEVICE_OBJECT DeviceObject
  11868. )
  11869. {
  11870. /*++
  11871. Routine Description:
  11872. Queue a work item to remove entries from the ClusDiskDeviceList.
  11873. Arguments:
  11874. DeviceObject - Device that is being removed by the system.
  11875. Return Value:
  11876. NTSTATUS
  11877. --*/
  11878. PIO_WORKITEM workItem = NULL;
  11879. CDLOG( "CleanupDeviceList: Entry DO %p", DeviceObject );
  11880. workItem = IoAllocateWorkItem( DeviceObject );
  11881. if ( NULL == workItem ) {
  11882. ClusDiskPrint(( 1,
  11883. "[ClusDisk] CleanupDeviceList: Failed to allocate WorkItem \n" ));
  11884. goto FnExit;
  11885. }
  11886. //
  11887. // Queue the workitem. IoQueueWorkItem will insure that the device object is
  11888. // referenced while the work-item progresses.
  11889. //
  11890. ClusDiskPrint(( 3,
  11891. "[ClusDisk] CleanupDeviceList: Queuing work item \n" ));
  11892. IoQueueWorkItem( workItem,
  11893. CleanupDeviceListWorker,
  11894. DelayedWorkQueue,
  11895. workItem );
  11896. FnExit:
  11897. CDLOG( "CleanupDeviceList: Exit, DO %p", DeviceObject );
  11898. return STATUS_SUCCESS;
  11899. } // CleanupDeviceList
  11900. VOID
  11901. CleanupDeviceListWorker(
  11902. PDEVICE_OBJECT DeviceObject,
  11903. PVOID Context
  11904. )
  11905. /*++
  11906. Routine Description:
  11907. Work item that will walk ClusDiskDeviceList and remove any entries
  11908. that are marked as free.
  11909. Arguments:
  11910. Return Value:
  11911. None.
  11912. --*/
  11913. {
  11914. PDEVICE_LIST_ENTRY deviceEntry;
  11915. PDEVICE_LIST_ENTRY lastEntry;
  11916. PDEVICE_LIST_ENTRY nextEntry;
  11917. ACQUIRE_EXCLUSIVE( &ClusDiskDeviceListLock );
  11918. deviceEntry = ClusDiskDeviceList;
  11919. lastEntry = NULL;
  11920. while ( deviceEntry ) {
  11921. if ( deviceEntry->FreePool ) {
  11922. if ( lastEntry == NULL ) {
  11923. ClusDiskDeviceList = deviceEntry->Next;
  11924. } else {
  11925. lastEntry->Next = deviceEntry->Next;
  11926. }
  11927. nextEntry = deviceEntry->Next;
  11928. ExFreePool( deviceEntry );
  11929. deviceEntry = nextEntry;
  11930. continue;
  11931. }
  11932. lastEntry = deviceEntry;
  11933. deviceEntry = deviceEntry->Next;
  11934. }
  11935. RELEASE_EXCLUSIVE( &ClusDiskDeviceListLock );
  11936. IoFreeWorkItem( (PIO_WORKITEM)Context );
  11937. } // CleanupDeviceListWorker
  11938. #if DBG
  11939. VOID
  11940. ClusDiskDebugPrint(
  11941. ULONG PrintLevel,
  11942. PCHAR DebugMessage,
  11943. ...
  11944. )
  11945. /*++
  11946. Routine Description:
  11947. Debug print routine.
  11948. Arguments:
  11949. PrintLevel - The Debug Print Level.
  11950. DebugMessage - The Debug Message Format String, plus additional args.
  11951. Return:
  11952. None.
  11953. --*/
  11954. {
  11955. va_list args;
  11956. va_start( args, DebugMessage);
  11957. #if !defined(WMI_TRACING)
  11958. if ( PrintLevel <= ClusDiskPrintLevel ) {
  11959. CHAR buffer[256];
  11960. (VOID) vsprintf( buffer, DebugMessage, args );
  11961. DbgPrint( buffer );
  11962. }
  11963. #else
  11964. if ( PrintLevel <= ClusDiskPrintLevel || WPP_LEVEL_ENABLED(LEGACY) ) {
  11965. CHAR buffer[256];
  11966. (VOID) vsprintf( buffer, DebugMessage, args );
  11967. if (PrintLevel <= ClusDiskPrintLevel) {
  11968. DbgPrint( buffer );
  11969. }
  11970. CDLOGF(LEGACY,"LegacyLogging %!ARSTR!", buffer );
  11971. }
  11972. #endif
  11973. va_end( args );
  11974. }
  11975. #endif // DBG
  11976. #if DBG
  11977. NTSTATUS
  11978. AcquireRemoveLock(
  11979. IN PIO_REMOVE_LOCK RemoveLock,
  11980. IN OPTIONAL PVOID Tag
  11981. )
  11982. {
  11983. NTSTATUS status;
  11984. // Don't expect the displayed RemoveLock values to be correct on a heavily utilized system.
  11985. status = IoAcquireRemoveLock(RemoveLock, Tag);
  11986. if ( TrackRemoveLocks || (TrackRemoveLockSpecific == RemoveLock) ) {
  11987. ClusDiskPrint(( 1,
  11988. "ACQ: RemoveLock %p Tag %p Status %08X \n",
  11989. RemoveLock,
  11990. Tag,
  11991. status ));
  11992. ClusDiskPrint(( 1,
  11993. "ACQ: Removed %02X IoCount %08X \n",
  11994. RemoveLock->Common.Removed,
  11995. RemoveLock->Common.IoCount ));
  11996. }
  11997. return status;
  11998. } // AcquireRemoveLock
  11999. VOID
  12000. ReleaseRemoveLock(
  12001. IN PIO_REMOVE_LOCK RemoveLock,
  12002. IN PVOID Tag
  12003. )
  12004. {
  12005. // Don't expect the displayed RemoveLock values to be correct on a heavily utilized system.
  12006. IoReleaseRemoveLock(RemoveLock, Tag);
  12007. if ( TrackRemoveLocks || (TrackRemoveLockSpecific == RemoveLock) ) {
  12008. ClusDiskPrint(( 1,
  12009. "REL: RemoveLock %p Tag %p \n ",
  12010. RemoveLock,
  12011. Tag ));
  12012. ClusDiskPrint(( 1,
  12013. "REL: Removed %02X IoCount %08X \n",
  12014. RemoveLock->Common.Removed,
  12015. RemoveLock->Common.IoCount ));
  12016. }
  12017. if (TrackRemoveLocksEnableChecks) {
  12018. //
  12019. // The IoCount should never be less than 1 (especially never a negative value).
  12020. // Is it possible that a race condition could occur because we are printing the
  12021. // value from the RemoveLock and the remove could have just occurred. RemoveLock
  12022. // IoCount should never be less than zero.
  12023. //
  12024. ASSERTMSG("REL: RemoveLock IoCount possibly corrupt (less than 1) ", (RemoveLock->Common.IoCount >= 1 ));
  12025. //
  12026. // IoCount == 1 is OK, it just means there is no I/O outstanding on the device.
  12027. //
  12028. // ASSERTMSG("REL: IoCount == 1 - check stack ", (RemoveLock->Common.IoCount != 1 ));
  12029. }
  12030. } // ReleaseRemoveLock
  12031. VOID
  12032. ReleaseRemoveLockAndWait(
  12033. IN PIO_REMOVE_LOCK RemoveLock,
  12034. IN PVOID Tag
  12035. )
  12036. {
  12037. // Don't expect the displayed RemoveLock values to be correct on a heavily utilized system.
  12038. ClusDiskPrint(( 1,
  12039. "RELWAIT: RemoveLock %p Tag %p \n ",
  12040. RemoveLock,
  12041. Tag ));
  12042. ClusDiskPrint(( 1,
  12043. "RELWAIT: Removed %02X IoCount %08X \n",
  12044. RemoveLock->Common.Removed,
  12045. RemoveLock->Common.IoCount ));
  12046. IoReleaseRemoveLockAndWait(RemoveLock, Tag);
  12047. ClusDiskPrint(( 1, "RELWAIT: Wait complete \n " ));
  12048. ClusDiskPrint(( 1,
  12049. "RELWAIT: Removed %02X IoCount %08X \n",
  12050. RemoveLock->Common.Removed,
  12051. RemoveLock->Common.IoCount ));
  12052. } // ReleaseRemoveLockAndWait
  12053. PCHAR
  12054. PnPMinorFunctionString(
  12055. UCHAR MinorFunction
  12056. )
  12057. {
  12058. switch (MinorFunction)
  12059. {
  12060. case IRP_MN_START_DEVICE:
  12061. return "IRP_MN_START_DEVICE";
  12062. case IRP_MN_QUERY_REMOVE_DEVICE:
  12063. return "IRP_MN_QUERY_REMOVE_DEVICE";
  12064. case IRP_MN_REMOVE_DEVICE:
  12065. return "IRP_MN_REMOVE_DEVICE";
  12066. case IRP_MN_CANCEL_REMOVE_DEVICE:
  12067. return "IRP_MN_CANCEL_REMOVE_DEVICE";
  12068. case IRP_MN_STOP_DEVICE:
  12069. return "IRP_MN_STOP_DEVICE";
  12070. case IRP_MN_QUERY_STOP_DEVICE:
  12071. return "IRP_MN_QUERY_STOP_DEVICE";
  12072. case IRP_MN_CANCEL_STOP_DEVICE:
  12073. return "IRP_MN_CANCEL_STOP_DEVICE";
  12074. case IRP_MN_QUERY_DEVICE_RELATIONS:
  12075. return "IRP_MN_QUERY_DEVICE_RELATIONS";
  12076. case IRP_MN_QUERY_INTERFACE:
  12077. return "IRP_MN_QUERY_INTERFACE";
  12078. case IRP_MN_QUERY_CAPABILITIES:
  12079. return "IRP_MN_QUERY_CAPABILITIES";
  12080. case IRP_MN_QUERY_RESOURCES:
  12081. return "IRP_MN_QUERY_RESOURCES";
  12082. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  12083. return "IRP_MN_QUERY_RESOURCE_REQUIREMENTS";
  12084. case IRP_MN_QUERY_DEVICE_TEXT:
  12085. return "IRP_MN_QUERY_DEVICE_TEXT";
  12086. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
  12087. return "IRP_MN_FILTER_RESOURCE_REQUIREMENTS";
  12088. case IRP_MN_READ_CONFIG:
  12089. return "IRP_MN_READ_CONFIG";
  12090. case IRP_MN_WRITE_CONFIG:
  12091. return "IRP_MN_WRITE_CONFIG";
  12092. case IRP_MN_EJECT:
  12093. return "IRP_MN_EJECT";
  12094. case IRP_MN_SET_LOCK:
  12095. return "IRP_MN_SET_LOCK";
  12096. case IRP_MN_QUERY_ID:
  12097. return "IRP_MN_QUERY_ID";
  12098. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  12099. return "IRP_MN_QUERY_PNP_DEVICE_STATE";
  12100. case IRP_MN_QUERY_BUS_INFORMATION:
  12101. return "IRP_MN_QUERY_BUS_INFORMATION";
  12102. case IRP_MN_DEVICE_USAGE_NOTIFICATION:
  12103. return "IRP_MN_DEVICE_USAGE_NOTIFICATION";
  12104. case IRP_MN_SURPRISE_REMOVAL:
  12105. return "IRP_MN_SURPRISE_REMOVAL";
  12106. case IRP_MN_QUERY_LEGACY_BUS_INFORMATION:
  12107. return "IRP_MN_QUERY_LEGACY_BUS_INFORMATION";
  12108. default:
  12109. return "Unknown PNP IRP";
  12110. }
  12111. } // PnPMinorFunctionString
  12112. PCHAR
  12113. BoolToString(
  12114. BOOLEAN Value
  12115. )
  12116. {
  12117. if ( Value ) {
  12118. return "TRUE";
  12119. }
  12120. return "FALSE";
  12121. } // BoolToString
  12122. PCHAR
  12123. DiskStateToString(
  12124. ULONG DiskState
  12125. )
  12126. {
  12127. switch ( DiskState ) {
  12128. case DiskOffline:
  12129. return "DiskOffline (0)";
  12130. case DiskOnline:
  12131. return "DiskOnline (1)";
  12132. case DiskFailed:
  12133. return "DiskFailed (2)";
  12134. case DiskStalled:
  12135. return "DiskStalled (3)";
  12136. case DiskOfflinePending:
  12137. return "DiskOfflinePending (4)";
  12138. default:
  12139. return "Unknown DiskState";
  12140. }
  12141. } // DiskStateToString
  12142. #endif