Leaked source code of windows server 2003
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.

1330 lines
38 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. arbitrat.c
  5. Abstract:
  6. DiskArbitration, DiskReservationThread
  7. Author:
  8. Gor Nishanov (gorn) 5-Jun-1998
  9. Revision History:
  10. gorn: different arbitration algorithm implemented
  11. --*/
  12. //
  13. // Cannot use DoReserve/Release/BreakReserve from
  14. // filter.c . Because of hold io we won't be
  15. // able to open \Device\HarddiskX\ParitionY device
  16. //
  17. #define DoReserve DoReserve_don_t_use
  18. #define DoRelease DoRelease_don_t_use
  19. #define DoBreakReserve DoBreakReserve_don_t_use
  20. #include "disksp.h"
  21. #include "diskarbp.h"
  22. #include "arbitrat.h"
  23. #include "newmount.h"
  24. #include <strsafe.h> // Should be included last.
  25. #undef DoReserve
  26. #undef DoRelease
  27. #undef DoBreakReserve
  28. #define LOG_CURRENT_MODULE LOG_MODULE_DISK
  29. #define DISKARB_MAX_WORK_THREADS 1
  30. #define DISKARB_WORK_THREAD_PRIORITY THREAD_PRIORITY_ABOVE_NORMAL
  31. #define ARBITRATION_ATTEMPTS_SZ L"ArbitrationAttempts"
  32. #define ARBITRATION_SLEEP_SZ L"ArbitrationSleepBeforeRetry"
  33. #define RESERVATION_TIMER (1000*RESERVE_TIMER) // Reservation timer in milliseconds //
  34. // RESERVE_TIMER is defined in diskarbp.h //
  35. #define WAIT_FOR_RESERVATION_TO_BE_RESTORED (RESERVATION_TIMER + 2000)
  36. #define BUS_SETTLE_TIME (2000)
  37. #define FAST_MUTEX_DELAY (1000)
  38. #define DEFAULT_SLEEP_BEFORE_RETRY (500)
  39. #define MIN_SLEEP_BEFORE_RETRY (0)
  40. #define MAX_SLEEP_BEFORE_RETRY (30000)
  41. #define DEFAULT_ARBITRATION_ATTEMPTS (5)
  42. #define MIN_ARBITRATION_ATTEMPTS (1)
  43. #define MAX_ARBITRATION_ATTEMPTS (9)
  44. //
  45. // Variables Local To Arbitration Module
  46. //
  47. static DWORD ArbitrationAttempts = DEFAULT_ARBITRATION_ATTEMPTS;
  48. static DWORD ArbitratationSleepBeforeRetry = DEFAULT_SLEEP_BEFORE_RETRY;
  49. static CRITICAL_SECTION ArbitrationLock;
  50. static PCLRTL_WORK_QUEUE WorkQueue = 0;
  51. static BOOLEAN AllGlobalsInitialized = FALSE;
  52. static UCHAR NodeName[MAX_COMPUTERNAME_LENGTH + 1];
  53. enum { NAME_LENGTH = min(MAX_COMPUTERNAME_LENGTH,
  54. sizeof ( ((PARBITRATION_ID)0)->NodeSignature ) ) };
  55. DWORD
  56. ArbitrateOnce(
  57. IN PDISK_RESOURCE ResourceEntry,
  58. IN HANDLE FileHandle,
  59. LPVOID buf
  60. );
  61. DWORD
  62. VerifySectorSize(
  63. IN OUT PDISK_RESOURCE ResourceEntry,
  64. IN HANDLE FileHandle
  65. );
  66. DWORD
  67. DoReadWrite(
  68. IN PDISK_RESOURCE ResourceEntry,
  69. IN ULONG Operation,
  70. IN HANDLE FileHandle,
  71. IN DWORD BlockNumber,
  72. IN PVOID Buffer
  73. );
  74. DWORD
  75. DiskReservationThread(
  76. IN PDISK_RESOURCE ResourceEntry
  77. );
  78. VOID
  79. ReadArbitrationParameters(
  80. VOID
  81. );
  82. DWORD
  83. AsyncCheckReserve(
  84. IN OUT PDISK_RESOURCE ResourceEntry
  85. );
  86. DWORD
  87. DoArbEscape(
  88. IN PDISK_RESOURCE ResourceEntry,
  89. IN HANDLE FileHandle,
  90. IN ULONG Operation,
  91. IN PWCHAR OperationName,
  92. IN PVOID OutBuffer,
  93. IN ULONG OutBufferSize
  94. );
  95. #define DoBlockRead(RE,FH,BN,BUF) DoReadWrite(RE, AE_READ, FH, BN, BUF)
  96. #define DoBlockWrite(RE,FH,BN,BUF) DoReadWrite(RE, AE_WRITE, FH, BN, BUF)
  97. #define DoReserve(FH,RE) DoArbEscape(RE,FH,AE_RESERVE,L"Reserve",NULL,0)
  98. #define DoRelease(FH,RE) DoArbEscape(RE,FH,AE_RELEASE,L"Release",NULL,0)
  99. #define DoBreakReserve(FH,RE) DoArbEscape(RE,FH,AE_RESET,L"BusReset",NULL,0)
  100. #define GetSectorSize(RE,FH,buf) DoArbEscape(RE,FH,AE_SECTORSIZE,L"GetSectorSize",buf,sizeof(ULONG) )
  101. #define PokeDiskStack(RE,FH) DoArbEscape(RE,FH,AE_POKE,L"GetPartInfo",NULL,0)
  102. #define OldFashionedRIP(ResEntry) \
  103. ( ( (ResEntry)->StopTimerHandle != NULL) || ( (ResEntry)->DiskInfo.ControlHandle != NULL) )
  104. /**************************************************************************************/
  105. VOID
  106. ArbitrationInitialize(
  107. VOID
  108. )
  109. /*++
  110. Routine Description:
  111. To be called from DllProcessAttach
  112. Arguments:
  113. Return Value:
  114. --*/
  115. {
  116. InitializeCriticalSection( &ArbitrationLock );
  117. //
  118. // Read ArbitrationAttempts and ArbitratationSleepBeforeRetry from the registry
  119. //
  120. ReadArbitrationParameters();
  121. }
  122. VOID
  123. ArbitrationCleanup(
  124. VOID
  125. )
  126. /*++
  127. Routine Description:
  128. To be called from DllProcessDetach
  129. Arguments:
  130. Return Value:
  131. --*/
  132. {
  133. DeleteCriticalSection( &ArbitrationLock );
  134. }
  135. VOID
  136. DestroyArbWorkQueue(
  137. VOID
  138. )
  139. /*++
  140. Routine Description:
  141. To be called from DllProcessDetach
  142. Arguments:
  143. Return Value:
  144. --*/
  145. {
  146. if (WorkQueue) {
  147. ClRtlDestroyWorkQueue(WorkQueue);
  148. WorkQueue = NULL;
  149. }
  150. }
  151. DWORD
  152. CreateArbWorkQueue(
  153. IN RESOURCE_HANDLE ResourceHandle
  154. )
  155. /*++
  156. Routine Description:
  157. Arguments:
  158. Return Value:
  159. --*/
  160. {
  161. if (WorkQueue) {
  162. return ERROR_SUCCESS;
  163. }
  164. //
  165. // Create a work queue to process overlapped I/O completions
  166. //
  167. WorkQueue = ClRtlCreateWorkQueue(
  168. DISKARB_MAX_WORK_THREADS,
  169. DISKARB_WORK_THREAD_PRIORITY
  170. );
  171. if (WorkQueue == NULL) {
  172. DWORD status = GetLastError();
  173. (DiskpLogEvent)(
  174. ResourceHandle,
  175. LOG_ERROR,
  176. L"[DiskArb] Unable to create work queue. Error: %1!u!.\n",
  177. status );
  178. return status;
  179. }
  180. return ERROR_SUCCESS;
  181. }
  182. DWORD ArbitrationInitializeGlobals(
  183. IN OUT PDISK_RESOURCE ResourceEntry
  184. )
  185. /*++
  186. Routine Description:
  187. Additional initialization of global variables.
  188. The ones that might fail and we want to
  189. to log the failure.
  190. Otherwise we could have just added the stuff we are doing here
  191. to ArbitrationInitialize which is called from DllEntryPoint.
  192. Currently we are using it only to initialize ArbitrationWork queue.
  193. Called with ArbitrationLock held
  194. Arguments:
  195. Return Value:
  196. --*/
  197. {
  198. DWORD status;
  199. DWORD NameSize;
  200. NameSize = sizeof(NodeName);
  201. RtlZeroMemory(NodeName, NameSize);
  202. if( !GetComputerNameA( NodeName, &NameSize ) ) {
  203. status = GetLastError();
  204. (DiskpLogEvent)(
  205. ResourceEntry->ResourceHandle,
  206. LOG_ERROR,
  207. L"[DiskArb] GetComputerName failed, error %1!u!.\n", status);
  208. return status;
  209. }
  210. AllGlobalsInitialized = TRUE;
  211. return ERROR_SUCCESS;
  212. }
  213. DWORD
  214. ArbitrationInfoInit(
  215. IN OUT PDISK_RESOURCE ResourceEntry
  216. )
  217. {
  218. DWORD status = ERROR_SUCCESS;
  219. EnterCriticalSection( &ArbitrationLock );
  220. if (!AllGlobalsInitialized) {
  221. status = ArbitrationInitializeGlobals(ResourceEntry);
  222. }
  223. LeaveCriticalSection( &ArbitrationLock );
  224. if(status != ERROR_SUCCESS) {
  225. return status;
  226. }
  227. InitializeCriticalSection( &(ResourceEntry->ArbitrationInfo.DiskLock) );
  228. return ERROR_SUCCESS;
  229. }
  230. VOID
  231. ArbitrationInfoCleanup(
  232. IN OUT PDISK_RESOURCE ResourceEntry
  233. )
  234. {
  235. (DiskpLogEvent)(
  236. ResourceEntry->ResourceHandle,
  237. LOG_INFORMATION,
  238. L"[DiskArb] ArbitrationInfoCleanup.\n");
  239. DeleteCriticalSection( &(ResourceEntry->ArbitrationInfo.DiskLock) );
  240. return;
  241. }
  242. #if 0
  243. BOOL
  244. DoesNotNeedExpensiveReservations(
  245. IN PDISK_RESOURCE ResourceEntry)
  246. {
  247. return (ResourceEntry->LostQuorum) == NULL;
  248. }
  249. #endif
  250. void
  251. ComputeArbitrationId(
  252. IN PDISK_RESOURCE ResourceEntry,
  253. OUT PARBITRATION_ID UniqueId
  254. )
  255. /*++
  256. Routine Description:
  257. Arguments:
  258. Return Value:
  259. --*/
  260. {
  261. RtlZeroMemory(UniqueId, sizeof(ARBITRATION_ID));
  262. GetSystemTimeAsFileTime( (LPFILETIME) &(UniqueId->SystemTime) );
  263. RtlCopyMemory(UniqueId->NodeSignature, NodeName, NAME_LENGTH );
  264. } // ComputeArbitrationId //
  265. DWORD
  266. ArbitrateOnce(
  267. IN PDISK_RESOURCE ResourceEntry,
  268. IN HANDLE FileHandle,
  269. LPVOID buf
  270. )
  271. /*++
  272. Routine Description:
  273. Perform full arbitration for a disk. Once arbitration has succeeded,
  274. a thread is started that will keep reservations on the disk.
  275. Arguments:
  276. ResourceEntry - the disk info structure for the disk.
  277. FileHandle - the file handle to use for arbitration.
  278. Return Value:
  279. ERROR_SUCCESS if successful.
  280. A Win32 error code on failure.
  281. --*/
  282. {
  283. DWORD status;
  284. ARBITRATION_ID id, old_y, empty;
  285. (DiskpLogEvent)(
  286. ResourceEntry->ResourceHandle,
  287. LOG_INFORMATION,
  288. L"[DiskArb] Read the partition info to insure the disk is accessible.\n");
  289. PokeDiskStack(ResourceEntry, FileHandle);
  290. (DiskpLogEvent)(
  291. ResourceEntry->ResourceHandle,
  292. LOG_INFORMATION,
  293. L"[DiskArb] Arbitrate for ownership of the disk by reading/writing various disk sectors.\n");
  294. ComputeArbitrationId(ResourceEntry, &id);
  295. RtlZeroMemory( &empty, sizeof(empty) );
  296. RtlZeroMemory( &old_y, sizeof(old_y) );
  297. status = DoBlockRead(ResourceEntry, FileHandle, BLOCK_Y, buf);
  298. if ( (status == ERROR_SUCCESS)
  299. && ( (0 == memcmp(&empty, buf, sizeof(empty)) ) // clean release
  300. ||(0 == memcmp(&id.NodeSignature,
  301. &(((PARBITRATION_ID)buf)->NodeSignature),
  302. sizeof(id.NodeSignature) ) ) // we dropped this disk
  303. )
  304. )
  305. {
  306. // Disk was voluntary released
  307. // or we are picking up the disk that was dropped by us
  308. // and nobody was using it while we were away
  309. //
  310. // => Fast Arbitration
  311. CopyMemory( &old_y ,buf, sizeof(old_y) );
  312. goto FastMutex;
  313. }
  314. if (status != ERROR_SUCCESS) {
  315. // Breaker //
  316. (DiskpLogEvent)(
  317. ResourceEntry->ResourceHandle,
  318. LOG_INFORMATION,
  319. L"[DiskArb] We are about to break reserve.\n");
  320. status = DoBreakReserve( FileHandle, ResourceEntry );
  321. if( ERROR_SUCCESS != status ) {
  322. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  323. LOG_ERROR,
  324. L"[DiskArb] Failed to break reservation, error %1!u!.\n",
  325. status
  326. );
  327. return status;
  328. }
  329. Sleep( BUS_SETTLE_TIME );
  330. (DiskpLogEvent)(
  331. ResourceEntry->ResourceHandle,
  332. LOG_INFORMATION,
  333. L"[DiskArb] Read the partition info from the disk to insure disk is accessible.\n");
  334. PokeDiskStack(ResourceEntry, FileHandle);
  335. #if 0
  336. status = DoBlockRead(ResourceEntry, FileHandle, BLOCK_Y, buf);
  337. #else
  338. CopyMemory(buf, &id, sizeof(id)); id.SeqNo.QuadPart ++;
  339. status = DoBlockWrite(ResourceEntry, FileHandle, BLOCK_Y, buf);
  340. #endif
  341. if(status != ERROR_SUCCESS) { return status; }
  342. } else {
  343. (DiskpLogEvent)(
  344. ResourceEntry->ResourceHandle,
  345. LOG_INFORMATION,
  346. L"[DiskArb] No reservation found. Read'n'wait.\n");
  347. Sleep( BUS_SETTLE_TIME ); // so that reader would not get an advantages
  348. }
  349. CopyMemory(&old_y, buf, sizeof(ARBITRATION_ID));
  350. Sleep( WAIT_FOR_RESERVATION_TO_BE_RESTORED );
  351. status = DoBlockRead(ResourceEntry, FileHandle, BLOCK_Y, buf);
  352. if(status != ERROR_SUCCESS) { return status; }
  353. if( 0 == memcmp(&empty, buf, sizeof(ARBITRATION_ID)) ) {;} else
  354. if( 0 != memcmp(&old_y, buf, sizeof(ARBITRATION_ID)) ) { return ERROR_QUORUM_OWNER_ALIVE; }
  355. // Fast Mutex Code //
  356. FastMutex:
  357. // write(x, id) //
  358. CopyMemory(buf, &id, sizeof(id));
  359. status = DoBlockWrite(ResourceEntry, FileHandle, BLOCK_X, buf);
  360. if(status != ERROR_SUCCESS) { return status; }
  361. // if(y != old_y && y != empty) return FALSE; //
  362. status = DoBlockRead(ResourceEntry, FileHandle, BLOCK_Y, buf);
  363. if(status != ERROR_SUCCESS) { return status; }
  364. if( 0 == memcmp(&empty, buf, sizeof(ARBITRATION_ID)) ) {;} else
  365. if( 0 != memcmp(&old_y, buf, sizeof(ARBITRATION_ID)) ) { return ERROR_QUORUM_OWNER_ALIVE; }
  366. // write(y, id) //
  367. CopyMemory(buf, &id, sizeof(id));
  368. status = DoBlockWrite(ResourceEntry, FileHandle, BLOCK_Y, buf);
  369. if(status != ERROR_SUCCESS) { return status; }
  370. // if(x != id) ...
  371. status = DoBlockRead(ResourceEntry, FileHandle, BLOCK_X, buf);
  372. if(status != ERROR_SUCCESS) { return status; }
  373. if( 0 != memcmp(&id, buf, sizeof(ARBITRATION_ID)) ) {
  374. Sleep(FAST_MUTEX_DELAY);
  375. // if(y == 0) goto FastMutex //
  376. // if(y != id) return FALSE //
  377. status = DoBlockRead(ResourceEntry, FileHandle, BLOCK_Y, buf);
  378. if(status != ERROR_SUCCESS) { return status; }
  379. if( 0 == memcmp(&empty, buf, sizeof(ARBITRATION_ID)) ) {
  380. RtlZeroMemory( &old_y, sizeof(old_y) );
  381. goto FastMutex;
  382. }
  383. if( 0 != memcmp(&id, buf, sizeof(ARBITRATION_ID)) ) { return ERROR_QUORUM_OWNER_ALIVE; }
  384. }
  385. status = StartPersistentReservations(ResourceEntry, FileHandle);
  386. return(status);
  387. } // ArbitrateOnce //
  388. DWORD
  389. DiskArbitration(
  390. IN PDISK_RESOURCE ResourceEntry,
  391. IN HANDLE FileHandle
  392. )
  393. /*++
  394. Routine Description:
  395. Perform arbitration for a disk. Once arbitration has succeeded,
  396. a thread is started that will keep reservations on the disk.
  397. If arbitration fails, the routine will retry to arbitrate in ArbitratationSleepBeforeRetry
  398. milliseconds. A number of arbitration attempts is controlled by ArbitrationAttempts variable.
  399. ArbitrationAttempts and ArbitratationSleepBeforeRetry are read from the registry on
  400. start up.
  401. Arguments:
  402. ResourceEntry - the disk info structure for the disk.
  403. FileHandle - the file handle to use for arbitration.
  404. Return Value:
  405. ERROR_SUCCESS if successful.
  406. A Win32 error code on failure.
  407. --*/
  408. {
  409. DWORD status;
  410. int repeat;
  411. LPVOID unalignedBuf = 0;
  412. LPVOID buf = 0;
  413. __try {
  414. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  415. LOG_INFORMATION,
  416. L"[DiskArb] Arbitration Parameters: ArbAttempts %1!u!, SleepBeforeRetry %2!u! ms.\n",
  417. ArbitrationAttempts, ArbitratationSleepBeforeRetry);
  418. EnterCriticalSection( &(ResourceEntry->ArbitrationInfo.DiskLock) );
  419. //
  420. // If we already are performing reservations, then just leave now.
  421. //
  422. if ( ReservationInProgress(ResourceEntry) ) {
  423. status = ERROR_SUCCESS;
  424. __leave;
  425. }
  426. status = VerifySectorSize(ResourceEntry, FileHandle);
  427. if ( status != ERROR_SUCCESS ) {
  428. // VerifySectorSize logs an error //
  429. __leave;
  430. }
  431. unalignedBuf = LocalAlloc(LPTR, ResourceEntry->ArbitrationInfo.SectorSize * 2);
  432. if( unalignedBuf == 0 ) {
  433. status = GetLastError();
  434. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  435. LOG_ERROR,
  436. L"[DiskArb] Failed to allocate arbitration buffer X, error %1!u!.\n", status );
  437. __leave;
  438. }
  439. // Alignment code assumes that ResourceEntry->ArbitrationInfo.SectorSize is the power of two //
  440. buf = (LPVOID)( ((ULONG_PTR)unalignedBuf + ResourceEntry->ArbitrationInfo.SectorSize
  441. ) & ~((ULONG_PTR)(ResourceEntry->ArbitrationInfo.SectorSize - 1))
  442. );
  443. repeat = ArbitrationAttempts;
  444. for(;;) {
  445. status = ArbitrateOnce(ResourceEntry, FileHandle, buf);
  446. if(status == ERROR_SUCCESS) {
  447. break;
  448. }
  449. if(--repeat <= 0) {
  450. break;
  451. }
  452. Sleep(ArbitratationSleepBeforeRetry);
  453. (DiskpLogEvent)(
  454. ResourceEntry->ResourceHandle,
  455. LOG_WARNING,
  456. L"[DiskArb] Retry arbitration, %1!u! attempts left \n", repeat );
  457. }
  458. if(status != ERROR_SUCCESS) {
  459. __leave;
  460. }
  461. (DiskpLogEvent)(
  462. ResourceEntry->ResourceHandle,
  463. LOG_WARNING,
  464. L"[DiskArb] Assume ownership of the device.\n");
  465. } __finally {
  466. LeaveCriticalSection( &(ResourceEntry->ArbitrationInfo.DiskLock) );
  467. if(unalignedBuf) {
  468. LocalFree(unalignedBuf);
  469. }
  470. }
  471. return(status);
  472. } // DiskArbitration //
  473. DWORD
  474. DoArbEscape(
  475. IN PDISK_RESOURCE ResourceEntry,
  476. IN HANDLE FileHandle,
  477. IN ULONG Operation,
  478. IN PWCHAR OperationName,
  479. IN PVOID OutBuffer,
  480. IN ULONG OutBufferSize
  481. )
  482. {
  483. DWORD bytesReturned;
  484. DWORD status;
  485. DWORD LogLevel = LOG_INFORMATION;
  486. ARBITRATION_READ_WRITE_PARAMS params;
  487. params.Operation = Operation;
  488. params.SectorSize = 0;
  489. params.SectorNo = 0;
  490. params.Buffer = 0;
  491. params.Signature = ResourceEntry->DiskInfo.Params.Signature;
  492. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  493. LOG_INFORMATION,
  494. L"[DiskArb] Issuing %1!ws! on signature %2!x!.\n",
  495. OperationName,
  496. params.Signature );
  497. status = DeviceIoControl( FileHandle,
  498. IOCTL_DISK_CLUSTER_ARBITRATION_ESCAPE,
  499. &params,
  500. sizeof(params),
  501. OutBuffer,
  502. OutBufferSize,
  503. &bytesReturned,
  504. FALSE );
  505. if( status == FALSE) {
  506. status = GetLastError();
  507. LogLevel = LOG_ERROR;
  508. } else {
  509. status = ERROR_SUCCESS;
  510. }
  511. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  512. LogLevel,
  513. L"[DiskArb] %1!ws! completed, status %2!u!.\n",
  514. OperationName, status );
  515. return status;
  516. }
  517. DWORD
  518. DoReadWrite(
  519. IN PDISK_RESOURCE ResourceEntry,
  520. IN ULONG Operation,
  521. IN HANDLE FileHandle,
  522. IN DWORD BlockNumber,
  523. IN PVOID Buffer
  524. )
  525. /*++
  526. Routine Description:
  527. Arguments:
  528. Return Value:
  529. --*/
  530. {
  531. DWORD bytesReturned;
  532. DWORD status;
  533. PWCHAR opname = (Operation == AE_READ)?L"read ":L"write";
  534. ARBITRATION_READ_WRITE_PARAMS params;
  535. params.Operation = Operation;
  536. params.SectorSize = ResourceEntry->ArbitrationInfo.SectorSize;
  537. params.SectorNo = BlockNumber;
  538. params.Buffer = Buffer;
  539. params.Signature = ResourceEntry->DiskInfo.Params.Signature;
  540. status = DeviceIoControl( FileHandle,
  541. IOCTL_DISK_CLUSTER_ARBITRATION_ESCAPE,
  542. &params,
  543. sizeof(params),
  544. NULL,
  545. 0,
  546. &bytesReturned,
  547. FALSE );
  548. if( status == 0) {
  549. status = GetLastError();
  550. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  551. LOG_ERROR,
  552. L"[DiskArb] Failed to %1!ws! (sector %2!u!), error %3!u!.\n",
  553. opname,
  554. BlockNumber,
  555. status );
  556. return status;
  557. } else {
  558. #if 0
  559. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  560. LOG_INFORMATION,
  561. L"[DiskArb] Successful %1!ws! (sector %2!u!).\n",
  562. opname,
  563. BlockNumber,
  564. #else
  565. WCHAR buf[64];
  566. mbstowcs(buf, ((PARBITRATION_ID)Buffer)->NodeSignature, sizeof(((PARBITRATION_ID)Buffer)->NodeSignature));
  567. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  568. LOG_INFORMATION,
  569. L"[DiskArb] Successful %1!ws! (sector %2!u!) [%3!ws!:%4!u!] (%5!x!,%6!08x!:%7!08x!).\n",
  570. opname,
  571. BlockNumber,
  572. buf,
  573. ((PARBITRATION_ID)Buffer)->SeqNo.LowPart,
  574. ((PARBITRATION_ID)Buffer)->SeqNo.HighPart,
  575. ((PARBITRATION_ID)Buffer)->SystemTime.LowPart,
  576. ((PARBITRATION_ID)Buffer)->SystemTime.HighPart
  577. );
  578. #endif
  579. }
  580. return ERROR_SUCCESS;
  581. } // DoReadWrite //
  582. DWORD
  583. VerifySectorSize(
  584. IN OUT PDISK_RESOURCE ResourceEntry,
  585. IN HANDLE FileHandle
  586. )
  587. /*++
  588. Routine Description:
  589. The routine checks whether
  590. a ResourceEntry->ArbitrationInfo.SectorSize has a value assigned to it.
  591. If ResourceEntry->ArbitrationInfo.SectorSize is 0 then the routine tries
  592. to obtain a correct sector size using GetDriveGeometry IOCTL.
  593. Arguments:
  594. Return Value:
  595. ERROR_SUCCESS
  596. or
  597. Error Code returned by IOCTL_DISK_GET_DRIVE_GEOMETRY
  598. Comment:
  599. The routine always succeeds. If it cannot obtain
  600. disk geometry it will use a default sector size.
  601. --*/
  602. {
  603. DWORD status;
  604. DWORD sectorSize;
  605. if (ResourceEntry->ArbitrationInfo.SectorSize)
  606. {
  607. return ERROR_SUCCESS;
  608. }
  609. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  610. LOG_INFORMATION,
  611. L"[DiskArb] Read disk geometry to get the sector size.\n" );
  612. status = GetSectorSize(ResourceEntry, FileHandle, &sectorSize);
  613. if (status == ERROR_SUCCESS) {
  614. ResourceEntry->ArbitrationInfo.SectorSize = sectorSize;
  615. } else {
  616. ResourceEntry->ArbitrationInfo.SectorSize = DEFAULT_SECTOR_SIZE;
  617. // GetDiskGeometry logs an error //
  618. return status;
  619. }
  620. // ArbitrationInfo.SectorSize should be at least 64 bytes //
  621. if( ResourceEntry->ArbitrationInfo.SectorSize < sizeof(ARBITRATION_ID) ) {
  622. (DiskpLogEvent)(
  623. ResourceEntry->ResourceHandle,
  624. LOG_ERROR,
  625. L"[DiskArb] ArbitrationInfo.SectorSize is too small %1!u!\n", ResourceEntry->ResourceHandle);
  626. ResourceEntry->ArbitrationInfo.SectorSize = DEFAULT_SECTOR_SIZE;
  627. return ERROR_INSUFFICIENT_BUFFER;
  628. }
  629. // ArbitrationInfo.SectorSize should be a power of two //
  630. if( (ResourceEntry->ArbitrationInfo.SectorSize & (ResourceEntry->ArbitrationInfo.SectorSize - 1)) != 0 ) {
  631. (DiskpLogEvent)(
  632. ResourceEntry->ResourceHandle,
  633. LOG_ERROR,
  634. L"[DiskArb] ArbitrationInfo.SectorSize is not a power of two %1!u!\n", ResourceEntry->ResourceHandle);
  635. ResourceEntry->ArbitrationInfo.SectorSize = DEFAULT_SECTOR_SIZE;
  636. return ERROR_INSUFFICIENT_BUFFER;
  637. }
  638. (DiskpLogEvent)(
  639. ResourceEntry->ResourceHandle,
  640. LOG_INFORMATION,
  641. L"[DiskArb] ArbitrationInfo.SectorSize is %1!u!\n", ResourceEntry->ArbitrationInfo.SectorSize);
  642. return ERROR_SUCCESS;
  643. } // VerifySectorSize //
  644. VOID
  645. ReadArbitrationParameters(
  646. VOID
  647. )
  648. /*++
  649. Routine Description:
  650. Reads
  651. DWORD ArbitrationAttempts = DEFAULT_ARBITRATION_ATTEMPTS;
  652. DWORD ArbitratationSleepBeforeRetry = DEFAULT_SLEEP_BEFORE_RETRY;
  653. from the registry
  654. Arguments:
  655. NONE
  656. Return Value:
  657. NONE
  658. --*/
  659. {
  660. DWORD status;
  661. HKEY key;
  662. DWORD size;
  663. status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  664. L"Cluster",
  665. 0,
  666. KEY_READ,
  667. &key );
  668. if ( status != ERROR_SUCCESS ) {
  669. ArbitrationAttempts = DEFAULT_ARBITRATION_ATTEMPTS;
  670. ArbitratationSleepBeforeRetry = DEFAULT_SLEEP_BEFORE_RETRY;
  671. return;
  672. }
  673. size = sizeof(ArbitrationAttempts);
  674. status = RegQueryValueEx(key,
  675. ARBITRATION_ATTEMPTS_SZ,
  676. 0,
  677. NULL,
  678. (LPBYTE)&ArbitrationAttempts,
  679. &size);
  680. if(status != ERROR_SUCCESS) {
  681. ArbitrationAttempts = DEFAULT_ARBITRATION_ATTEMPTS;
  682. }
  683. if(ArbitrationAttempts < MIN_ARBITRATION_ATTEMPTS
  684. || ArbitrationAttempts > MAX_ARBITRATION_ATTEMPTS)
  685. {
  686. ArbitrationAttempts = DEFAULT_ARBITRATION_ATTEMPTS;
  687. }
  688. size = sizeof(ArbitratationSleepBeforeRetry);
  689. status = RegQueryValueEx(key,
  690. ARBITRATION_SLEEP_SZ,
  691. 0,
  692. NULL,
  693. (LPBYTE)&ArbitratationSleepBeforeRetry,
  694. &size);
  695. if(status != ERROR_SUCCESS) {
  696. ArbitratationSleepBeforeRetry = DEFAULT_SLEEP_BEFORE_RETRY;
  697. }
  698. //
  699. // Removed this part of the check:
  700. // ArbitratationSleepBeforeRetry < MIN_SLEEP_BEFORE_RETRY
  701. // as DWORD/ULONG cannot be less than zero and it always evaluated
  702. // to FALSE.
  703. //
  704. if(ArbitratationSleepBeforeRetry > MAX_SLEEP_BEFORE_RETRY)
  705. {
  706. ArbitratationSleepBeforeRetry = DEFAULT_SLEEP_BEFORE_RETRY;
  707. }
  708. RegCloseKey(key);
  709. } // ReadArbitrationParameters //
  710. VOID
  711. CompletionRoutine(
  712. IN PCLRTL_WORK_ITEM WorkItem,
  713. IN DWORD Status,
  714. IN DWORD BytesTransferred,
  715. IN ULONG_PTR IoContext
  716. )
  717. /*++
  718. Routine Description:
  719. Arguments:
  720. Return Value:
  721. --*/
  722. {
  723. PDISK_RESOURCE ResourceEntry;
  724. if( IoContext ) {
  725. ResourceEntry = (PDISK_RESOURCE)IoContext;
  726. (DiskpLogEvent)(
  727. ResourceEntry->ResourceHandle,
  728. LOG_INFORMATION,
  729. L"[DiskArb] CompletionRoutine, status %1!u!.\n", Status);
  730. } else {
  731. PARBITRATION_INFO info = CONTAINING_RECORD(
  732. WorkItem, // Expr //
  733. ARBITRATION_INFO,
  734. WorkItem); // FieldName //
  735. ResourceEntry = CONTAINING_RECORD(
  736. info,
  737. DISK_RESOURCE,
  738. ArbitrationInfo);
  739. (DiskpLogEvent)(
  740. ResourceEntry->ResourceHandle,
  741. LOG_INFORMATION,
  742. L"[DiskArb] CompletionRoutine starts.\n", Status);
  743. }
  744. if (Status == ERROR_SUCCESS) {
  745. if (ResourceEntry->ArbitrationInfo.StopReserveInProgress) {
  746. return;
  747. }
  748. //
  749. // Repost the request
  750. //
  751. Status = AsyncCheckReserve(ResourceEntry);
  752. if (Status == ERROR_SUCCESS) {
  753. return;
  754. }
  755. }
  756. //
  757. // Some kind of error occurred,
  758. // but if we are in the middle of StopReserve
  759. // then everything is fine.
  760. //
  761. if (ResourceEntry->ArbitrationInfo.StopReserveInProgress) {
  762. return;
  763. }
  764. (DiskpLogEvent)(
  765. ResourceEntry->ResourceHandle,
  766. Status == ERROR_OPERATION_ABORTED ? LOG_WARNING : LOG_ERROR,
  767. L"[DiskArb] CompletionRoutine: reservation lost! Status %1!u! \n", Status );
  768. if ( ERROR_OPERATION_ABORTED != Status ) {
  769. ClusResLogSystemEventByKey(ResourceEntry->ResourceKey,
  770. LOG_CRITICAL,
  771. RES_DISK_RESERVATION_LOST);
  772. }
  773. //
  774. // Callout to cluster service to indicate that quorum has
  775. // been lost.
  776. //
  777. if (ResourceEntry->LostQuorum != NULL) {
  778. (ResourceEntry->LostQuorum)(ResourceEntry->ResourceHandle);
  779. }
  780. ResourceEntry->DiskInfo.FailStatus = Status;
  781. ResourceEntry->Reserved = FALSE;
  782. return;
  783. } // CompletionRoutine //
  784. DWORD
  785. AsyncCheckReserve(
  786. IN OUT PDISK_RESOURCE ResourceEntry
  787. )
  788. /*++
  789. Routine Description:
  790. Description
  791. Arguments:
  792. FileHandle - Handle for device to check reserve.
  793. ResourceHandle - The resource handle for reporting errors
  794. Return Value:
  795. Error Status - zero if success.
  796. --*/
  797. {
  798. BOOL success;
  799. DWORD errorCode;
  800. DWORD bytesReturned;
  801. PARBITRATION_INFO Info = &ResourceEntry->ArbitrationInfo;
  802. (DiskpLogEvent)(
  803. ResourceEntry->ResourceHandle,
  804. LOG_INFORMATION,
  805. L"[DiskArb] Posting request to check reserve progress.\n");
  806. ClRtlInitializeWorkItem(
  807. &(Info->WorkItem),
  808. CompletionRoutine,
  809. ResourceEntry
  810. );
  811. success = DeviceIoControl( Info->ControlHandle,
  812. IOCTL_DISK_CLUSTER_ALIVE_CHECK,
  813. &Info->InputData,
  814. sizeof(Info->InputData),
  815. &Info->OutputData,
  816. sizeof(Info->OutputData),
  817. &bytesReturned,
  818. &Info->WorkItem.Overlapped);
  819. if ( !success ) {
  820. errorCode = GetLastError();
  821. if( errorCode == ERROR_IO_PENDING ) {
  822. (DiskpLogEvent)(
  823. ResourceEntry->ResourceHandle,
  824. LOG_INFORMATION,
  825. L"[DiskArb] ********* IO_PENDING ********** - Request to insure reserves working is now posted.\n");
  826. return ERROR_SUCCESS;
  827. }
  828. if ( ERROR_OPERATION_ABORTED == errorCode ) {
  829. (DiskpLogEvent)(
  830. ResourceEntry->ResourceHandle,
  831. LOG_WARNING,
  832. L"[DiskArb] disk reservation thread canceled, status %1!u!.\n",
  833. errorCode);
  834. } else {
  835. (DiskpLogEvent)(
  836. ResourceEntry->ResourceHandle,
  837. LOG_ERROR,
  838. L"[DiskArb] error checking disk reservation thread, error %1!u!.\n",
  839. errorCode);
  840. }
  841. return(errorCode);
  842. }
  843. (DiskpLogEvent)(
  844. ResourceEntry->ResourceHandle,
  845. LOG_ERROR,
  846. L"[DiskArb] Premature completion of check reserve I/O.\n");
  847. return(ERROR_CAN_NOT_COMPLETE);
  848. } // AsyncCheckReserve
  849. DWORD
  850. StartPersistentReservations(
  851. IN OUT PDISK_RESOURCE ResourceEntry,
  852. IN HANDLE FileHandle
  853. )
  854. /*++
  855. Routine Description:
  856. Starts driver level persistent reservations.
  857. Also starts a user-mode thread to keep an eye on driver level reservations.
  858. Arguments:
  859. ResourceEntry - the disk info structure for the disk.
  860. FileHandle - the file handle to use for arbitration.
  861. Return Value:
  862. ERROR_SUCCESS if successful.
  863. A Win32 error code on failure.
  864. --*/
  865. {
  866. DWORD status;
  867. //
  868. // If we already are performing reservations, then just leave now.
  869. //
  870. if ( ReservationInProgress(ResourceEntry) ) {
  871. return(ERROR_SUCCESS);
  872. }
  873. CL_ASSERT(WorkQueue != NULL);
  874. VerifySectorSize(ResourceEntry, FileHandle);
  875. status = DoReserve( FileHandle, ResourceEntry );
  876. if(status != ERROR_SUCCESS) {
  877. return status;
  878. }
  879. {
  880. START_RESERVE_DATA params;
  881. DWORD paramsSize;
  882. // Preparing parameters to call StartReserveEx //
  883. params.DiskSignature = ResourceEntry->DiskInfo.Params.Signature;
  884. params.Version = START_RESERVE_DATA_V1_SIG;
  885. params.ArbitrationSector = BLOCK_Y;
  886. params.SectorSize = ResourceEntry->ArbitrationInfo.SectorSize;
  887. params.NodeSignatureSize = sizeof(params.NodeSignature);
  888. RtlZeroMemory(params.NodeSignature, sizeof(params.NodeSignature) );
  889. RtlCopyMemory(params.NodeSignature, NodeName, NAME_LENGTH );
  890. #if 0
  891. // When we have a reliable way of determining
  892. // whether this disk resource is a quorum
  893. // this code can be enabled
  894. if ( DoesNotNeedExpensiveReservations(ResourceEntry) ) {
  895. paramsSize = sizeof( params.DiskSignature );
  896. } else {
  897. paramsSize = sizeof( params );
  898. }
  899. #else
  900. paramsSize = sizeof( params );
  901. #endif
  902. status = StartReserveEx( &ResourceEntry->ArbitrationInfo.ControlHandle,
  903. &params,
  904. paramsSize,
  905. ResourceEntry->ResourceHandle );
  906. }
  907. if ( status != ERROR_SUCCESS ) {
  908. (DiskpLogEvent)(
  909. ResourceEntry->ResourceHandle,
  910. LOG_ERROR,
  911. L"[DiskArb] Failed to start driver reservation thread, error %1!u!.\n",
  912. status );
  913. DoRelease( FileHandle, ResourceEntry );
  914. return(status);
  915. }
  916. ResourceEntry->ArbitrationInfo.StopReserveInProgress = FALSE;
  917. status = ClRtlAssociateIoHandleWorkQueue(
  918. WorkQueue,
  919. ResourceEntry->ArbitrationInfo.ControlHandle,
  920. (ULONG_PTR)ResourceEntry
  921. );
  922. if ( status != ERROR_SUCCESS ) {
  923. (DiskpLogEvent)(
  924. ResourceEntry->ResourceHandle,
  925. LOG_ERROR,
  926. L"[DiskArb] ClRtlAssociateIoHandleWorkQueue failed, error %1!u!.\n",
  927. status );
  928. StopPersistentReservations( ResourceEntry );
  929. DoRelease( FileHandle, ResourceEntry );
  930. return(status);
  931. }
  932. ClRtlInitializeWorkItem(
  933. &(ResourceEntry->ArbitrationInfo.WorkItem),
  934. CompletionRoutine,
  935. 0
  936. );
  937. status = ClRtlPostItemWorkQueue(
  938. WorkQueue,
  939. &ResourceEntry->ArbitrationInfo.WorkItem,
  940. 0,0);
  941. if ( status != ERROR_SUCCESS ) {
  942. (DiskpLogEvent)(
  943. ResourceEntry->ResourceHandle,
  944. LOG_ERROR,
  945. L"[DiskArb] ClRtlPostItemWorkQueue failed, error %1!u!.\n",
  946. status );
  947. StopPersistentReservations( ResourceEntry );
  948. DoRelease( FileHandle, ResourceEntry );
  949. return(status);
  950. }
  951. ResourceEntry->Reserved = TRUE;
  952. return ERROR_SUCCESS;
  953. } // StartPersistentReservations //
  954. DWORD
  955. CleanupArbitrationSector(
  956. IN PDISK_RESOURCE ResourceEntry
  957. )
  958. /*++
  959. Routine Description:
  960. Arguments:
  961. ResourceEntry - the disk info structure for the disk.
  962. Return Value:
  963. ERROR_SUCCESS if successful.
  964. A Win32 error code on failure.
  965. --*/
  966. {
  967. HANDLE FileHandle = DiskspClusDiskZero;
  968. DWORD status;
  969. LPVOID unalignedBuf = 0;
  970. PARBITRATION_ID buf = 0;
  971. try {
  972. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  973. LOG_INFORMATION,
  974. L"[ArbCleanup] Verifying sector size. \n" );
  975. VerifySectorSize(ResourceEntry, FileHandle);
  976. unalignedBuf = LocalAlloc(LMEM_FIXED, ResourceEntry->ArbitrationInfo.SectorSize * 2);
  977. if( unalignedBuf == 0 ) {
  978. status = GetLastError();
  979. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  980. LOG_ERROR,
  981. L"[ArbCleanup] Failed to allocate buffer, error %1!u!.\n", status );
  982. leave;
  983. }
  984. // Alignment code assumes that ResourceEntry->ArbitrationInfo.SectorSize is the power of two //
  985. buf = (PARBITRATION_ID)
  986. (
  987. ( (ULONG_PTR)unalignedBuf + ResourceEntry->ArbitrationInfo.SectorSize )
  988. & ~((ULONG_PTR)(ResourceEntry->ArbitrationInfo.SectorSize - 1))
  989. );
  990. ZeroMemory(buf, ResourceEntry->ArbitrationInfo.SectorSize);
  991. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  992. LOG_INFORMATION,
  993. L"[ArbCleanup] Reading arbitration block. \n" );
  994. status = DoBlockRead(ResourceEntry, FileHandle, BLOCK_Y, buf);
  995. if (status != ERROR_SUCCESS) { leave; }
  996. if( 0 != memcmp(buf->NodeSignature, NodeName, NAME_LENGTH) ) {
  997. //
  998. // Somebody is challenging us. No need to clean up the sector
  999. //
  1000. status = ERROR_OPERATION_ABORTED;
  1001. leave;
  1002. }
  1003. ZeroMemory(buf, ResourceEntry->ArbitrationInfo.SectorSize);
  1004. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  1005. LOG_INFORMATION,
  1006. L"[ArbCleanup] Writing arbitration block. \n" );
  1007. status = DoBlockWrite(ResourceEntry, FileHandle, BLOCK_Y, buf);
  1008. if(status != ERROR_SUCCESS) {
  1009. leave;
  1010. }
  1011. } finally {
  1012. if(unalignedBuf) {
  1013. LocalFree(unalignedBuf);
  1014. }
  1015. }
  1016. (DiskpLogEvent)( ResourceEntry->ResourceHandle,
  1017. LOG_INFORMATION,
  1018. L"[ArbCleanup] Returning status %1!u!. \n", status );
  1019. return(status);
  1020. } // CleanupArbitrationSector //
  1021. VOID
  1022. StopPersistentReservations(
  1023. IN OUT PDISK_RESOURCE ResourceEntry
  1024. )
  1025. /*++
  1026. Routine Description:
  1027. Arguments:
  1028. Return Value:
  1029. --*/
  1030. {
  1031. HANDLE localHandle;
  1032. (DiskpLogEvent)(
  1033. ResourceEntry->ResourceHandle,
  1034. LOG_INFORMATION,
  1035. L"[DiskArb] StopPersistentReservations is called.\n");
  1036. //
  1037. // ReservationInProgress returns current contents of
  1038. // ResourceEntry->ArbitrationInfo.ControlHandle
  1039. //
  1040. localHandle = ReservationInProgress(ResourceEntry);
  1041. if ( localHandle ) {
  1042. DWORD status;
  1043. HANDLE ExchangeResult;
  1044. ExchangeResult = InterlockedCompareExchangePointer(
  1045. &ResourceEntry->ArbitrationInfo.ControlHandle,
  1046. 0,
  1047. localHandle);
  1048. if (ExchangeResult == localHandle) {
  1049. //
  1050. // Only one thread is allowed in here
  1051. //
  1052. ResourceEntry->ArbitrationInfo.StopReserveInProgress = TRUE;
  1053. (DiskpLogEvent)(
  1054. ResourceEntry->ResourceHandle,
  1055. LOG_INFORMATION,
  1056. L"[DiskArb] Stopping reservation thread.\n");
  1057. //
  1058. // Close the Control Handle, which stops the reservation thread and
  1059. // dismounts the volume, releases the disk, and marks it offline.
  1060. //
  1061. status = StopReserve( localHandle,
  1062. ResourceEntry->ResourceHandle );
  1063. if ( status != ERROR_SUCCESS ) {
  1064. (DiskpLogEvent)(
  1065. ResourceEntry->ResourceHandle,
  1066. LOG_ERROR,
  1067. L"[DiskArb] Error stopping reservation thread, error %1!u!.\n",
  1068. status);
  1069. }
  1070. status = CleanupArbitrationSector( ResourceEntry );
  1071. if (status != ERROR_SUCCESS) {
  1072. (DiskpLogEvent)(
  1073. ResourceEntry->ResourceHandle,
  1074. LOG_ERROR,
  1075. L"[DiskArb] Error cleaning arbitration sector, error %1!u!.\n",
  1076. status);
  1077. }
  1078. }
  1079. }
  1080. (DiskpLogEvent)(
  1081. ResourceEntry->ResourceHandle,
  1082. LOG_INFORMATION,
  1083. L"[DiskArb] StopPersistentReservations is complete.\n");
  1084. ResourceEntry->ArbitrationInfo.ControlHandle = NULL;
  1085. ResourceEntry->Reserved = FALSE;
  1086. ResourceEntry->LostQuorum = NULL;
  1087. }