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.

3114 lines
88 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. MajorityNodeSet.c
  5. Abstract:
  6. Resource DLL for Majority Node Set (MajorityNodeSet).
  7. Author:
  8. Ahmed Mohamed (ahmedm) 12, 01, 2000
  9. Revision History:
  10. George Potts (gpotts) 05, 17, 2001
  11. Renamed from Node Quorum to Majority Node Set
  12. --*/
  13. #pragma comment(lib, "clusapi.lib")
  14. #pragma comment(lib, "resutils.lib")
  15. #define UNICODE 1
  16. #pragma warning( disable : 4115 ) // named type definition in parentheses
  17. #pragma warning( disable : 4201 ) // nonstandard extension used : nameless struct/union
  18. #pragma warning( disable : 4214 ) // nonstandard extension used : bit field types other than int
  19. #include <nt.h>
  20. #include <ntrtl.h>
  21. #include <nturtl.h>
  22. #include <windows.h>
  23. #include <stdlib.h>
  24. #pragma warning( default : 4214 ) // nonstandard extension used : bit field types other than int
  25. #pragma warning( default : 4201 ) // nonstandard extension used : nameless struct/union
  26. #pragma warning( default : 4115 ) // named type definition in parentheses
  27. #include <clusapi.h>
  28. #include <clusudef.h>
  29. #include <resapi.h>
  30. #include <stdio.h>
  31. #include "clusres.h"
  32. #include "fsapi.h"
  33. #include "pipe.h"
  34. #include "crs.h" // for crssetforcedquorumsize()
  35. #include "clusrtl.h"
  36. // Enable MNS to auconfig, allowing MNS config parameters can be a security risk.
  37. //
  38. #define ENABLE_MNS_AUTOCONFIG_ONLY 1
  39. //
  40. // Define a separate MNS resource Class. So that DTC doesn't try to use it a disk #573603.
  41. // Use a unique ID obtained from [email protected].
  42. //
  43. #define CLUS_RESCLASS_MAJORITY_NODE_SET 32775
  44. //
  45. // Type and constant definitions.
  46. //
  47. #ifdef STANDALONE_DLL
  48. #define MajorityNodeSetDllEntryPoint DllEntryPoint
  49. #define MNS_RESNAME L"Majority Node Set"
  50. // Event Logging routine.
  51. PLOG_EVENT_ROUTINE g_LogEvent = NULL;
  52. // Resource Status routine for pending Online and Offline calls.
  53. PSET_RESOURCE_STATUS_ROUTINE g_SetResourceStatus = NULL;
  54. #else
  55. // Event Logging routine.
  56. #define g_LogEvent ClusResLogEvent
  57. // Resource Status routine for pending Online and Offline calls.
  58. #define g_SetResourceStatus ClusResSetResourceStatus
  59. #endif // end of standalone_DLL
  60. // ADDPARAM: Add new parameters here.
  61. #define PARAM_NAME__PATH L"Path"
  62. #define PARAM_NAME__ALLOWREMOTEACCESS L"AllowRemoteAccess"
  63. #define PARAM_NAME__DISKLIST L"DiskList"
  64. #define PARAM_MIN__ALLOWREMOTEACCESS (0)
  65. #define PARAM_MAX__ALLOWREMOTEACCESS (4294967295)
  66. #define PARAM_DEFAULT__ALLOWREMOTEACCESS (0)
  67. #define MUTEX_FILE_NAME L"MajorityNodeSet_FileMutex"
  68. // ADDPARAM: Add new parameters here.
  69. typedef struct _MNS_PARAMS {
  70. PWSTR Path;
  71. DWORD AllowRemoteAccess;
  72. PWSTR DiskList;
  73. DWORD DiskListSize;
  74. } MNS_PARAMS, *PMNS_PARAMS;
  75. // Once we have UNC support in service, we need to disable this flag
  76. // #define USE_DRIVE_LETTER 1
  77. typedef struct _MNS_SETUP {
  78. LPWSTR Path;
  79. #ifdef USE_DRIVE_LETTER
  80. WCHAR DriveLetter[10];
  81. #else
  82. #define DriveLetter Path
  83. #endif
  84. LPWSTR DiskList[FsMaxNodes];
  85. DWORD DiskListSz;
  86. DWORD Nic;
  87. LPWSTR Transport;
  88. DWORD ArbTime;
  89. } MNS_SETUP, *PMNS_SETUP;
  90. typedef struct _MNS_RESOURCE {
  91. RESID ResId; // for validation
  92. MNS_PARAMS Params;
  93. HKEY ParametersKey;
  94. RESOURCE_HANDLE ResourceHandle;
  95. LPWSTR ResourceName;
  96. CLUS_WORKER OnlineThread;
  97. CLUS_WORKER ReserveThread;
  98. CLUSTER_RESOURCE_STATE State;
  99. PQUORUM_RESOURCE_LOST LostQuorumResource;
  100. CRITICAL_SECTION Lock;
  101. HANDLE ArbThread;
  102. HANDLE hMutexFile;
  103. PVOID PipeHdl;
  104. PVOID FsHdl;
  105. PVOID VolHdl;
  106. MNS_SETUP Setup;
  107. } MNS_RESOURCE, *PMNS_RESOURCE;
  108. #define MNS_ONLINE_PERIOD (4 * 1000)
  109. #define MNS_RESERVE_PERIOD (4 * 1000)
  110. //
  111. // Global data.
  112. //
  113. RESOURCE_HANDLE g_resHdl = 0;
  114. // Forward reference to our RESAPI function table.
  115. extern CLRES_FUNCTION_TABLE MajorityNodeSetFunctionTable;
  116. #ifdef ENABLE_MNS_AUTOCONFIG_ONLY
  117. RESUTIL_PROPERTY_ITEM
  118. MajorityNodeSetResourcePrivateProperties[] = {{ 0 }};
  119. #else
  120. //
  121. // MajorityNodeSet resource read-write private properties.
  122. //
  123. RESUTIL_PROPERTY_ITEM
  124. MajorityNodeSetResourcePrivateProperties[] = {
  125. { PARAM_NAME__PATH, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(MNS_PARAMS,Path) },
  126. { PARAM_NAME__ALLOWREMOTEACCESS, NULL, CLUSPROP_FORMAT_DWORD, PARAM_DEFAULT__ALLOWREMOTEACCESS, PARAM_MIN__ALLOWREMOTEACCESS, PARAM_MAX__ALLOWREMOTEACCESS, 0, FIELD_OFFSET(MNS_PARAMS,AllowRemoteAccess) },
  127. { PARAM_NAME__DISKLIST, NULL, CLUSPROP_FORMAT_MULTI_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(MNS_PARAMS,DiskList) },
  128. { 0 }
  129. };
  130. #endif
  131. #define MajorityNodeSetIoctlPhase1 CLUSCTL_USER_CODE(0, CLUS_OBJECT_RESOURCE)
  132. //
  133. // Function prototypes.
  134. //
  135. extern
  136. DWORD
  137. SetupIoctlQuorumResource(LPWSTR ResType, DWORD ControlCode);
  138. extern
  139. DWORD
  140. SetupDelete(IN LPWSTR Path);
  141. extern
  142. DWORD
  143. SetupStart(LPWSTR ResourceName, LPWSTR *SrvPath,
  144. LPWSTR *DiskList, DWORD *DiskListSize,
  145. DWORD *NicId, LPWSTR *Transport, DWORD *ArbTime);
  146. DWORD
  147. GetIDFromRegistry(IN HKEY hClusKey, IN LPWSTR resname, OUT LPWSTR *id);
  148. DWORD
  149. SetupShare(LPWSTR name, LPWSTR *lpath);
  150. extern
  151. DWORD
  152. SetupTree(
  153. IN LPTSTR TreeName,
  154. IN LPTSTR DlBuf,
  155. IN OUT DWORD *DlBufSz,
  156. IN LPTSTR TransportName OPTIONAL,
  157. IN LPVOID SecurityDescriptor OPTIONAL
  158. );
  159. RESID
  160. WINAPI
  161. MajorityNodeSetOpen(
  162. IN LPCWSTR ResourceName,
  163. IN HKEY ResourceKey,
  164. IN RESOURCE_HANDLE ResourceHandle
  165. );
  166. VOID
  167. WINAPI
  168. MajorityNodeSetClose(
  169. IN RESID ResourceId
  170. );
  171. DWORD
  172. WINAPI
  173. MajorityNodeSetOnline(
  174. IN RESID ResourceId,
  175. IN OUT PHANDLE EventHandle
  176. );
  177. DWORD
  178. WINAPI
  179. MajorityNodeSetOnlineThread(
  180. PCLUS_WORKER WorkerPtr,
  181. IN PMNS_RESOURCE ResourceEntry
  182. );
  183. DWORD
  184. WINAPI
  185. MajorityNodeSetOffline(
  186. IN RESID ResourceId
  187. );
  188. VOID
  189. WINAPI
  190. MajorityNodeSetTerminate(
  191. IN RESID ResourceId
  192. );
  193. DWORD
  194. MajorityNodeSetDoTerminate(
  195. IN PMNS_RESOURCE ResourceEntry
  196. );
  197. BOOL
  198. WINAPI
  199. MajorityNodeSetLooksAlive(
  200. IN RESID ResourceId
  201. );
  202. BOOL
  203. WINAPI
  204. MajorityNodeSetIsAlive(
  205. IN RESID ResourceId
  206. );
  207. BOOL
  208. MajorityNodeSetCheckIsAlive(
  209. IN PMNS_RESOURCE ResourceEntry
  210. );
  211. DWORD
  212. WINAPI
  213. MajorityNodeSetResourceControl(
  214. IN RESID ResourceId,
  215. IN DWORD ControlCode,
  216. IN PVOID InBuffer,
  217. IN DWORD InBufferSize,
  218. OUT PVOID OutBuffer,
  219. IN DWORD OutBufferSize,
  220. OUT LPDWORD BytesReturned
  221. );
  222. DWORD
  223. MajorityNodeSetGetPrivateResProperties(
  224. IN OUT PMNS_RESOURCE ResourceEntry,
  225. OUT PVOID OutBuffer,
  226. IN DWORD OutBufferSize,
  227. OUT LPDWORD BytesReturned
  228. );
  229. DWORD
  230. MajorityNodeSetValidatePrivateResProperties(
  231. IN OUT PMNS_RESOURCE ResourceEntry,
  232. IN const PVOID InBuffer,
  233. IN DWORD InBufferSize,
  234. OUT PMNS_PARAMS Params
  235. );
  236. DWORD
  237. MajorityNodeSetSetPrivateResProperties(
  238. IN OUT PMNS_RESOURCE ResourceEntry,
  239. IN const PVOID InBuffer,
  240. IN DWORD InBufferSize
  241. );
  242. DWORD
  243. MajorityNodeSetGetDiskInfo(
  244. IN LPWSTR lpszPath,
  245. OUT PVOID *OutBuffer,
  246. IN DWORD OutBufferSize,
  247. OUT LPDWORD BytesReturned
  248. ) ;
  249. DWORD
  250. WINAPI
  251. MajorityNodeSetReserveThread(
  252. PCLUS_WORKER WorkerPtr,
  253. IN PMNS_RESOURCE ResourceEntry
  254. );
  255. DWORD
  256. WINAPI
  257. MajorityNodeSetRelease(
  258. IN RESID ResourceId
  259. );
  260. DWORD
  261. MajorityNodeSetReadDefaultValues(
  262. PMNS_RESOURCE ResourceEntry
  263. );
  264. BOOLEAN
  265. WINAPI
  266. MajorityNodeSetDllEntryPoint(
  267. IN HINSTANCE DllHandle,
  268. IN DWORD Reason,
  269. IN LPVOID Reserved
  270. )
  271. /*++
  272. Routine Description:
  273. Main DLL entry point.
  274. Arguments:
  275. DllHandle - DLL instance handle.
  276. Reason - Reason for being called.
  277. Reserved - Reserved argument.
  278. Return Value:
  279. TRUE - Success.
  280. FALSE - Failure.
  281. --*/
  282. {
  283. switch( Reason ) {
  284. case DLL_PROCESS_ATTACH:
  285. break;
  286. case DLL_PROCESS_DETACH:
  287. break;
  288. }
  289. return(TRUE);
  290. } // DllMain
  291. #ifdef STANDALONE_DLL
  292. DWORD
  293. WINAPI
  294. Startup(
  295. IN LPCWSTR ResourceType,
  296. IN DWORD MinVersionSupported,
  297. IN DWORD MaxVersionSupported,
  298. IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  299. IN PLOG_EVENT_ROUTINE LogEvent,
  300. OUT PCLRES_FUNCTION_TABLE *FunctionTable
  301. )
  302. /*++
  303. Routine Description:
  304. Startup the resource DLL. This routine verifies that at least one
  305. currently supported version of the resource DLL is between
  306. MinVersionSupported and MaxVersionSupported. If not, then the resource
  307. DLL should return ERROR_REVISION_MISMATCH.
  308. If more than one version of the resource DLL interface is supported by
  309. the resource DLL, then the highest version (up to MaxVersionSupported)
  310. should be returned as the resource DLL's interface. If the returned
  311. version is not within range, then startup fails.
  312. The ResourceType is passed in so that if the resource DLL supports more
  313. than one ResourceType, it can pass back the correct function table
  314. associated with the ResourceType.
  315. Arguments:
  316. ResourceType - The type of resource requesting a function table.
  317. MinVersionSupported - The minimum resource DLL interface version
  318. supported by the cluster software.
  319. MaxVersionSupported - The maximum resource DLL interface version
  320. supported by the cluster software.
  321. SetResourceStatus - Pointer to a routine that the resource DLL should
  322. call to update the state of a resource after the Online or Offline
  323. routine returns a status of ERROR_IO_PENDING.
  324. LogEvent - Pointer to a routine that handles the reporting of events
  325. from the resource DLL.
  326. FunctionTable - Returns a pointer to the function table defined for the
  327. version of the resource DLL interface returned by the resource DLL.
  328. Return Value:
  329. ERROR_SUCCESS - The operation was successful.
  330. ERROR_MOD_NOT_FOUND - The resource type is unknown by this DLL.
  331. ERROR_REVISION_MISMATCH - The version of the cluster service doesn't
  332. match the versrion of the DLL.
  333. Win32 error code - The operation failed.
  334. --*/
  335. {
  336. if ( (MinVersionSupported > CLRES_VERSION_V1_00) ||
  337. (MaxVersionSupported < CLRES_VERSION_V1_00) ) {
  338. return(ERROR_REVISION_MISMATCH);
  339. }
  340. if ( lstrcmpiW( ResourceType, MNS_RESNAME ) != 0 ) {
  341. (LogEvent)(
  342. NULL,
  343. LOG_ERROR,
  344. L"MajorityNodeSet: %1 %2.\n", ResourceType, MNS_RESNAME);
  345. return(ERROR_MOD_NOT_FOUND);
  346. }
  347. if ( !g_LogEvent ) {
  348. g_LogEvent = LogEvent;
  349. g_SetResourceStatus = SetResourceStatus;
  350. }
  351. *FunctionTable = &MajorityNodeSetFunctionTable;
  352. return(ERROR_SUCCESS);
  353. } // Startup
  354. #endif
  355. DWORD OpenMutexFileExclusive(
  356. IN RESOURCE_HANDLE ResourceHandle,
  357. IN LPWSTR Name,
  358. OUT HANDLE* pHandle
  359. )
  360. {
  361. WCHAR fname[MAX_PATH];
  362. DWORD Status;
  363. int ccLen = wcslen(Name);
  364. *pHandle = INVALID_HANDLE_VALUE;
  365. if ( ( Status = ClRtlGetClusterDirectory( fname, MAX_PATH - ccLen - 1) ) != ERROR_SUCCESS )
  366. {
  367. (g_LogEvent)(
  368. ResourceHandle,
  369. LOG_ERROR,
  370. L"OpenMutexFileExclusive: Error %1!d! in getting cluster dir !!!\n", Status);
  371. goto exit_gracefully;
  372. }
  373. wcscat(fname, L"\\");
  374. wcscat(fname, Name);
  375. *pHandle = CreateFile(
  376. fname, // file name
  377. GENERIC_READ | GENERIC_WRITE, // access mode
  378. 0, // No sharing whatsoever
  379. NULL, // SD
  380. CREATE_ALWAYS,
  381. FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_HIDDEN | FILE_FLAG_DELETE_ON_CLOSE, // file attributes
  382. NULL // handle to template file
  383. );
  384. if (*pHandle == INVALID_HANDLE_VALUE) {
  385. Status = GetLastError();
  386. (g_LogEvent)(
  387. ResourceHandle,
  388. LOG_ERROR,
  389. L"Only one resource of MNS type is supported. Status: %1!u!.\n",
  390. Status );
  391. }
  392. exit_gracefully:
  393. return Status;
  394. }
  395. RESID
  396. WINAPI
  397. MajorityNodeSetOpen(
  398. IN LPCWSTR ResourceName,
  399. IN HKEY ResourceKey,
  400. IN RESOURCE_HANDLE ResourceHandle
  401. )
  402. /*++
  403. Routine Description:
  404. Open routine for MajorityNodeSet resources.
  405. Open the specified resource (create an instance of the resource).
  406. Allocate all structures necessary to bring the specified resource
  407. online.
  408. Arguments:
  409. ResourceName - Supplies the name of the resource to open.
  410. ResourceKey - Supplies handle to the resource's cluster configuration
  411. database key.
  412. ResourceHandle - A handle that is passed back to the resource monitor
  413. when the SetResourceStatus or LogEvent method is called. See the
  414. description of the SetResourceStatus and LogEvent methods on the
  415. MajorityNodeSetStatup routine. This handle should never be closed or used
  416. for any purpose other than passing it as an argument back to the
  417. Resource Monitor in the SetResourceStatus or LogEvent callback.
  418. Return Value:
  419. RESID of created resource.
  420. NULL on failure.
  421. --*/
  422. {
  423. DWORD status;
  424. DWORD disposition;
  425. RESID resid = 0;
  426. HKEY parametersKey = NULL;
  427. PMNS_RESOURCE resourceEntry = NULL;
  428. //
  429. // Open the Parameters registry key for this resource.
  430. //
  431. status = ClusterRegOpenKey( ResourceKey,
  432. L"Parameters",
  433. KEY_READ,
  434. &parametersKey);
  435. if ( status != ERROR_SUCCESS ) {
  436. (g_LogEvent)(
  437. ResourceHandle,
  438. LOG_ERROR,
  439. L"Unable to open Parameters key. Error: %1!u!.\n",
  440. status );
  441. goto exit;
  442. }
  443. //
  444. // Allocate a resource entry.
  445. //
  446. resourceEntry = (PMNS_RESOURCE) LocalAlloc( LMEM_FIXED, sizeof(MNS_RESOURCE) );
  447. if ( resourceEntry == NULL ) {
  448. status = GetLastError();
  449. (g_LogEvent)(
  450. ResourceHandle,
  451. LOG_ERROR,
  452. L"Unable to allocate resource entry structure. Error: %1!u!.\n",
  453. status );
  454. goto exit;
  455. }
  456. //
  457. // Initialize the resource entry..
  458. //
  459. ZeroMemory( resourceEntry, sizeof(MNS_RESOURCE) );
  460. resourceEntry->ResId = (RESID)resourceEntry; // for validation
  461. resourceEntry->ResourceHandle = ResourceHandle;
  462. resourceEntry->ParametersKey = parametersKey;
  463. resourceEntry->State = ClusterResourceOffline;
  464. resourceEntry->hMutexFile = INVALID_HANDLE_VALUE;
  465. // todo: get ride off this hack. See bug # 389483
  466. if (g_resHdl == 0)
  467. g_resHdl = resourceEntry->ResourceHandle;
  468. // initialize lock
  469. InitializeCriticalSection(&resourceEntry->Lock);
  470. //
  471. // Save the name of the resource.
  472. //
  473. resourceEntry->ResourceName = LocalAlloc( LMEM_FIXED, (lstrlenW( ResourceName ) + 1) * sizeof(WCHAR) );
  474. if ( resourceEntry->ResourceName == NULL ) {
  475. status = GetLastError();
  476. goto exit;
  477. }
  478. lstrcpyW( resourceEntry->ResourceName, ResourceName );
  479. status = OpenMutexFileExclusive(ResourceHandle, MUTEX_FILE_NAME, &resourceEntry->hMutexFile);
  480. if (status != ERROR_SUCCESS) {
  481. goto exit;
  482. }
  483. //
  484. // Setup stuff
  485. //
  486. memset(&resourceEntry->Setup, 0, sizeof(resourceEntry->Setup));
  487. //
  488. // If we are the quorum, we need to make sure the share has been created. So,
  489. // we call setup now.
  490. //
  491. #if 0
  492. {
  493. HKEY hClusKey=NULL;
  494. LPWSTR guid=NULL, lpath=NULL;
  495. status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, CLUSREG_KEYNAME_CLUSTER, 0, KEY_READ, &hClusKey);
  496. if (status != ERROR_SUCCESS) {
  497. goto setup_done;
  498. }
  499. status = GetIDFromRegistry(hClusKey, resourceEntry->ResourceName, &guid);
  500. if (status != ERROR_SUCCESS) {
  501. goto setup_done;
  502. }
  503. wcscat(guid, L"$");
  504. status = SetupShare(guid, &lpath);
  505. setup_done:
  506. if (guid) {
  507. LocalFree(guid);
  508. }
  509. if (lpath) {
  510. LocalFree(lpath);
  511. }
  512. if (hClusKey) {
  513. RegCloseKey(hClusKey);
  514. }
  515. }
  516. (g_LogEvent)(
  517. resourceEntry->ResourceHandle,
  518. LOG_INFORMATION,
  519. L"Open share setup status %1!u!.\n", status);
  520. #else
  521. // read from private properties
  522. status = MajorityNodeSetReadDefaultValues(resourceEntry);
  523. if (status != ERROR_SUCCESS || resourceEntry->Setup.DiskListSz == 0) {
  524. // read from our own setup stuff
  525. status = SetupStart(resourceEntry->ResourceName,
  526. &resourceEntry->Setup.Path,
  527. resourceEntry->Setup.DiskList,
  528. &resourceEntry->Setup.DiskListSz,
  529. &resourceEntry->Setup.Nic,
  530. &resourceEntry->Setup.Transport,
  531. &resourceEntry->Setup.ArbTime);
  532. (g_LogEvent)(
  533. resourceEntry->ResourceHandle,
  534. LOG_INFORMATION,
  535. L"Open %1 setup status %2!u!.\n", ResourceName, status);
  536. }
  537. #endif
  538. // init fs
  539. if (status == ERROR_SUCCESS) {
  540. status = FsInit((PVOID)resourceEntry, &resourceEntry->FsHdl);
  541. (g_LogEvent)(
  542. resourceEntry->ResourceHandle,
  543. LOG_INFORMATION,
  544. L"Open %1 fs status %2!u!.\n", ResourceName, status);
  545. }
  546. // init pipe srv
  547. if (status == ERROR_SUCCESS) {
  548. status = PipeInit((PVOID)resourceEntry, resourceEntry->FsHdl,
  549. &resourceEntry->PipeHdl);
  550. (g_LogEvent)(
  551. resourceEntry->ResourceHandle,
  552. LOG_INFORMATION,
  553. L"Open %1 pipe status %2!u!.\n", ResourceName, status);
  554. }
  555. #ifdef ENABLE_SMB
  556. // init srv
  557. if (status == ERROR_SUCCESS) {
  558. status = SrvInit((PVOID)resourceEntry, resourceEntry->FsHdl,
  559. &resourceEntry->SrvHdl);
  560. (g_LogEvent)(
  561. resourceEntry->ResourceHandle,
  562. LOG_INFORMATION,
  563. L"Open %1 srv status %2!u!.\n", ResourceName, status);
  564. }
  565. #endif
  566. if (status == ERROR_SUCCESS) {
  567. resid = (RESID)resourceEntry;
  568. //
  569. // Startup for the resource.
  570. //
  571. }
  572. exit:
  573. (g_LogEvent)(
  574. ResourceHandle,
  575. LOG_INFORMATION,
  576. L"Open %1 status %2!u!.\n", ResourceName, status);
  577. if ( resid == 0 ) {
  578. if (resourceEntry) {
  579. if (g_resHdl == resourceEntry->ResourceHandle) {
  580. g_resHdl = NULL;
  581. }
  582. MajorityNodeSetClose((RESID)resourceEntry);
  583. } else if ( parametersKey != NULL ) {
  584. ClusterRegCloseKey( parametersKey );
  585. }
  586. }
  587. if ( status != ERROR_SUCCESS ) {
  588. SetLastError( status );
  589. }
  590. return(resid);
  591. } // MajorityNodeSetOpen
  592. VOID
  593. WINAPI
  594. MajorityNodeSetClose(
  595. IN RESID ResourceId
  596. )
  597. /*++
  598. Routine Description:
  599. Close routine for MajorityNodeSet resources.
  600. Close the specified resource and deallocate all structures, etc.,
  601. allocated in the Open call. If the resource is not in the offline state,
  602. then the resource should be taken offline (by calling Terminate) before
  603. the close operation is performed.
  604. Arguments:
  605. ResourceId - Supplies the RESID of the resource to close.
  606. Return Value:
  607. None.
  608. --*/
  609. {
  610. PMNS_RESOURCE resourceEntry;
  611. resourceEntry = (PMNS_RESOURCE)ResourceId;
  612. if ( resourceEntry == NULL ) {
  613. return;
  614. }
  615. if ( resourceEntry->ResId != ResourceId ) {
  616. (g_LogEvent)(
  617. resourceEntry->ResourceHandle,
  618. LOG_ERROR,
  619. L"Close resource sanity check failed! ResourceId = %1!u!.\n",
  620. ResourceId );
  621. return;
  622. }
  623. (g_LogEvent)(
  624. resourceEntry->ResourceHandle,
  625. LOG_INFORMATION,
  626. L"Close request.\n" );
  627. //
  628. // Hack: Check if we are online, just return. This must be the RPC run-down stuff
  629. //
  630. if (resourceEntry->VolHdl &&
  631. (FsIsOnlineReadonly(resourceEntry->VolHdl) == ERROR_SUCCESS))
  632. return;
  633. //
  634. // Close the Parameters key.
  635. //
  636. if ( resourceEntry->ParametersKey ) {
  637. ClusterRegCloseKey( resourceEntry->ParametersKey );
  638. }
  639. //
  640. // Sync any arb threads
  641. //
  642. if (resourceEntry->ArbThread) {
  643. WaitForSingleObject(resourceEntry->ArbThread, INFINITE);
  644. CloseHandle(resourceEntry->ArbThread);
  645. resourceEntry->ArbThread = NULL;
  646. }
  647. if (resourceEntry->PipeHdl) {
  648. PipeExit(resourceEntry->PipeHdl);
  649. }
  650. if (resourceEntry->FsHdl) {
  651. FsExit(resourceEntry->FsHdl);
  652. }
  653. //
  654. // Deallocate setup stuff
  655. //
  656. if (resourceEntry->Setup.Path) {
  657. LocalFree( resourceEntry->Setup.Path);
  658. }
  659. if (resourceEntry->Setup.DiskList) {
  660. DWORD i;
  661. for (i = 0; i < FsMaxNodes; i++) {
  662. if (resourceEntry->Setup.DiskList[i] != NULL)
  663. LocalFree(resourceEntry->Setup.DiskList[i]);
  664. }
  665. }
  666. if (resourceEntry->Setup.Transport) {
  667. LocalFree( resourceEntry->Setup.Transport);
  668. }
  669. // ADDPARAM: Add new parameters here.
  670. if ( resourceEntry->Params.Path )
  671. LocalFree( resourceEntry->Params.Path );
  672. if ( resourceEntry->Params.DiskList )
  673. LocalFree( resourceEntry->Params.DiskList );
  674. if ( resourceEntry->ResourceName )
  675. LocalFree( resourceEntry->ResourceName );
  676. if (resourceEntry->hMutexFile != INVALID_HANDLE_VALUE) {
  677. CloseHandle(resourceEntry->hMutexFile);
  678. }
  679. DeleteCriticalSection(&resourceEntry->Lock);
  680. LocalFree( resourceEntry );
  681. g_resHdl = 0; // [HACKHACK] Assumes that there could be only one MNS resource
  682. } // MajorityNodeSetClose
  683. DWORD
  684. WINAPI
  685. MajorityNodeSetOnline(
  686. IN RESID ResourceId,
  687. IN OUT PHANDLE EventHandle
  688. )
  689. /*++
  690. Routine Description:
  691. Online routine for MajorityNodeSet resources.
  692. Bring the specified resource online (available for use). The resource
  693. DLL should attempt to arbitrate for the resource if it is present on a
  694. shared medium, like a shared SCSI bus.
  695. Arguments:
  696. ResourceId - Supplies the resource id for the resource to be brought
  697. online (available for use).
  698. EventHandle - Returns a signalable handle that is signaled when the
  699. resource DLL detects a failure on the resource. This argument is
  700. NULL on input, and the resource DLL returns NULL if asynchronous
  701. notification of failures is not supported, otherwise this must be
  702. the address of a handle that is signaled on resource failures.
  703. Return Value:
  704. ERROR_SUCCESS - The operation was successful, and the resource is now
  705. online.
  706. ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  707. ERROR_RESOURCE_NOT_AVAILABLE - If the resource was arbitrated with some
  708. other systems and one of the other systems won the arbitration.
  709. ERROR_IO_PENDING - The request is pending, a thread has been activated
  710. to process the online request. The thread that is processing the
  711. online request will periodically report status by calling the
  712. SetResourceStatus callback method, until the resource is placed into
  713. the ClusterResourceOnline state (or the resource monitor decides to
  714. timeout the online request and Terminate the resource. This pending
  715. timeout value is settable and has a default value of 3 minutes.).
  716. Win32 error code - The operation failed.
  717. --*/
  718. {
  719. PMNS_RESOURCE resourceEntry = NULL;
  720. DWORD status;
  721. resourceEntry = (PMNS_RESOURCE)ResourceId;
  722. if ( resourceEntry == NULL ) {
  723. return(ERROR_RESOURCE_NOT_FOUND);
  724. }
  725. if ( resourceEntry->ResId != ResourceId ) {
  726. (g_LogEvent)(
  727. resourceEntry->ResourceHandle,
  728. LOG_ERROR,
  729. L"Online service sanity check failed! ResourceId = %1!u!.\n",
  730. ResourceId );
  731. return(ERROR_RESOURCE_NOT_FOUND);
  732. }
  733. (g_LogEvent)(
  734. resourceEntry->ResourceHandle,
  735. LOG_INFORMATION,
  736. L"Online request.\n" );
  737. resourceEntry->State = ClusterResourceOffline;
  738. ClusWorkerTerminate( &resourceEntry->OnlineThread );
  739. status = ClusWorkerCreate( &resourceEntry->OnlineThread,
  740. (PWORKER_START_ROUTINE)MajorityNodeSetOnlineThread,
  741. resourceEntry );
  742. if ( status != ERROR_SUCCESS ) {
  743. resourceEntry->State = ClusterResourceFailed;
  744. (g_LogEvent)(
  745. resourceEntry->ResourceHandle,
  746. LOG_ERROR,
  747. L"Online: Unable to start thread, status %1!u!.\n",
  748. status
  749. );
  750. } else {
  751. status = ERROR_IO_PENDING;
  752. }
  753. return(status);
  754. } // MajorityNodeSetOnline
  755. DWORD
  756. MajorityNodeSetReadDefaultValues(PMNS_RESOURCE ResourceEntry)
  757. {
  758. return ERROR_NOT_SUPPORTED;
  759. } // MajorityNodeSetReadDefaultValues
  760. DWORD
  761. MajorityNodeSetDoRegister(IN PMNS_RESOURCE ResourceEntry)
  762. {
  763. DWORD status = ERROR_SUCCESS;
  764. if (ResourceEntry->VolHdl == NULL) {
  765. // if we have no volume handle, read config now
  766. // read from private properties
  767. status = MajorityNodeSetReadDefaultValues(ResourceEntry);
  768. if ((status != ERROR_SUCCESS) || (ResourceEntry->Setup.DiskListSz == 0)) {
  769. // read from our own setup stuff
  770. status = SetupStart(ResourceEntry->ResourceName,
  771. &ResourceEntry->Setup.Path,
  772. ResourceEntry->Setup.DiskList,
  773. &ResourceEntry->Setup.DiskListSz,
  774. &ResourceEntry->Setup.Nic,
  775. &ResourceEntry->Setup.Transport,
  776. &ResourceEntry->Setup.ArbTime);
  777. }
  778. if (status == ERROR_SUCCESS) {
  779. LPWSTR ShareName, IpcName;
  780. // register volume
  781. ShareName = ResourceEntry->Setup.Path + 2;
  782. ShareName = wcschr(ShareName, L'\\');
  783. ASSERT(ShareName);
  784. ShareName++;
  785. ASSERT(*ShareName != L'\0');
  786. IpcName = ResourceEntry->Setup.DiskList[0];
  787. if (IpcName == NULL) {
  788. // We use first replica. This must be the case when our private property is set
  789. IpcName = ResourceEntry->Setup.DiskList[1];
  790. }
  791. ASSERT(IpcName);
  792. status = FsRegister(ResourceEntry->FsHdl,
  793. ShareName, // share name
  794. IpcName, // ipc local name
  795. ResourceEntry->Setup.DiskList, // replica set
  796. ResourceEntry->Setup.DiskListSz, // num of replicas
  797. ResourceEntry->Setup.ArbTime,
  798. &ResourceEntry->VolHdl);
  799. }
  800. }
  801. return status;
  802. }
  803. DWORD
  804. WINAPI
  805. MajorityNodeSetOnlineThread(
  806. PCLUS_WORKER WorkerPtr,
  807. IN PMNS_RESOURCE ResourceEntry
  808. )
  809. /*++
  810. Routine Description:
  811. Worker function which brings a resource from the resource table online.
  812. This function is executed in a separate thread.
  813. Arguments:
  814. WorkerPtr - Supplies the worker structure
  815. ResourceEntry - A pointer to the MNS_RESOURCE block for this resource.
  816. Returns:
  817. ERROR_SUCCESS - The operation completed successfully.
  818. Win32 error code - The operation failed.
  819. --*/
  820. {
  821. RESOURCE_STATUS resourceStatus;
  822. DWORD i, status = ERROR_SUCCESS, status1;
  823. ASSERT(ResourceEntry != NULL);
  824. ResUtilInitializeResourceStatus( &resourceStatus );
  825. resourceStatus.ResourceState = ClusterResourceFailed;
  826. resourceStatus.WaitHint = 0;
  827. resourceStatus.CheckPoint = 1;
  828. (g_LogEvent)(
  829. ResourceEntry->ResourceHandle,
  830. LOG_INFORMATION,
  831. L"onlinethread request.\n"
  832. );
  833. // Get lock
  834. EnterCriticalSection(&ResourceEntry->Lock);
  835. // There are two cases here. If the MNS resource is the quorum, arbitration has
  836. // already been called, then try to avoid arbitrating again. To do this call into
  837. // FsIsOnlineReadWrite(). If MNS is not the quorum we would have to do arbitration.
  838. //
  839. // NOTE: Here we are trying to get MNS online. This is a bit different from just arbitrate
  840. // path. Arbitrate path is optimized to return ASAP, even before FspJoin completes, but here
  841. // we need to wait till FspJoin completes and then verify that the volume is in
  842. // VolumeStateOnlineReadWrite state.
  843. //
  844. status = MajorityNodeSetDoRegister(ResourceEntry);
  845. if (status == ERROR_SUCCESS) {
  846. HANDLE th;
  847. PVOID arb;
  848. HANDLE Cleanup;
  849. ASSERT(ResourceEntry->VolHdl);
  850. status = FsIsOnlineReadWrite(ResourceEntry->VolHdl);
  851. if (status != ERROR_SUCCESS) {
  852. // We need to start a new arbitration or else wait for the current arbitrate
  853. // thread to complete.
  854. //
  855. status = ERROR_SUCCESS;
  856. if (ResourceEntry->ArbThread != NULL) {
  857. // check if this is an old completed handle
  858. status1 = WaitForSingleObject(ResourceEntry->ArbThread, 0);
  859. if (status1 != WAIT_TIMEOUT) {
  860. CloseHandle(ResourceEntry->ArbThread);
  861. ResourceEntry->ArbThread = NULL;
  862. arb = FsArbitrate(ResourceEntry->VolHdl, &Cleanup, &ResourceEntry->ArbThread);
  863. if (arb == NULL) {
  864. status = GetLastError();
  865. }
  866. else {
  867. // Set the cleanup event now, else the arbitrate thread would get
  868. // stuck forever.
  869. SetEvent(Cleanup);
  870. }
  871. }
  872. }
  873. else {
  874. arb = FsArbitrate(ResourceEntry->VolHdl, &Cleanup, &ResourceEntry->ArbThread);
  875. if (arb == NULL) {
  876. status = GetLastError();
  877. }
  878. else {
  879. SetEvent(Cleanup);
  880. }
  881. }
  882. if (status == ERROR_SUCCESS) {
  883. // Now wait for the arbitrate thread to exit.
  884. //
  885. while (ResourceEntry->ArbThread != NULL) {
  886. // The ArbThread handle might be closed from other places, so duplicate it
  887. // instead of copying.
  888. //
  889. th = INVALID_HANDLE_VALUE;
  890. DuplicateHandle(
  891. GetCurrentProcess(),
  892. ResourceEntry->ArbThread,
  893. GetCurrentProcess(),
  894. &th,
  895. 0,
  896. FALSE,
  897. DUPLICATE_SAME_ACCESS);
  898. ASSERT(th != INVALID_HANDLE_VALUE);
  899. LeaveCriticalSection(&ResourceEntry->Lock);
  900. do {
  901. // inform rcmon that we are working
  902. resourceStatus.ResourceState = ClusterResourceOnlinePending;
  903. resourceStatus.CheckPoint++;
  904. g_SetResourceStatus( ResourceEntry->ResourceHandle,
  905. &resourceStatus );
  906. (g_LogEvent)(
  907. ResourceEntry->ResourceHandle,
  908. LOG_INFORMATION,
  909. L"waiting for fs to online %1!u!.\n",
  910. status );
  911. status = WaitForSingleObject(th, MNS_ONLINE_PERIOD);
  912. } while (status == WAIT_TIMEOUT);
  913. CloseHandle(th);
  914. EnterCriticalSection(&ResourceEntry->Lock);
  915. if (ResourceEntry->ArbThread != NULL) {
  916. status1 = WaitForSingleObject(ResourceEntry->ArbThread, 0);
  917. if (status1 != WAIT_TIMEOUT) {
  918. CloseHandle(ResourceEntry->ArbThread);
  919. ResourceEntry->ArbThread = NULL;
  920. }
  921. }
  922. }
  923. LeaveCriticalSection(&ResourceEntry->Lock);
  924. }
  925. else {
  926. LeaveCriticalSection(&ResourceEntry->Lock);
  927. }
  928. // arbitrate thread must have finished, check if we are online or not
  929. status = FsIsOnlineReadWrite(ResourceEntry->VolHdl);
  930. }
  931. else {
  932. LeaveCriticalSection(&ResourceEntry->Lock);
  933. }
  934. }
  935. else {
  936. // drop lock
  937. LeaveCriticalSection(&ResourceEntry->Lock);
  938. }
  939. if (status == ERROR_SUCCESS) {
  940. status = PipeOnline(ResourceEntry->PipeHdl, ResourceEntry->Setup.Path);
  941. }
  942. #ifdef ENABLE_SMB
  943. if (status == ERROR_SUCCESS) {
  944. LPWSTR SrvName;
  945. // Online server
  946. SrvName = ResourceEntry->Setup.Path + 2;
  947. status = SrvOnline(ResourceEntry->SrvHdl, SrvName,
  948. ResourceEntry->Setup.Nic);
  949. }
  950. //
  951. // Bring drive letter online
  952. //
  953. if (status == ERROR_SUCCESS) {
  954. PDWORD psz = NULL;
  955. #ifdef USE_DRIVE_LETTER
  956. DWORD sz;
  957. sz = sizeof(ResourceEntry->Setup.DriveLetter);
  958. psz = &sz;
  959. #endif
  960. // todo: create security descriptor and pass it onto tree
  961. status = SetupTree(ResourceEntry->Setup.Path,
  962. ResourceEntry->Setup.DriveLetter, psz,
  963. ResourceEntry->Setup.Transport, NULL);
  964. status = ERROR_SUCCESS;
  965. #ifdef USE_DRIVE_LETTERxx
  966. if (status == ERROR_DUP_NAME)
  967. status = ERROR_SUCCESS;
  968. #endif
  969. if (status == ERROR_SUCCESS) {
  970. #ifdef USE_DRIVE_LETTER
  971. ResourceEntry->Setup.DriveLetter[sz] = L'\0';
  972. #endif
  973. (g_LogEvent)(
  974. ResourceEntry->ResourceHandle,
  975. LOG_INFORMATION,
  976. L"Resource %1 mounted on drive %2.\n",
  977. ResourceEntry->ResourceName,
  978. ResourceEntry->Setup.DriveLetter);
  979. } else {
  980. (g_LogEvent)(
  981. ResourceEntry->ResourceHandle,
  982. LOG_ERROR,
  983. L"failed to setup tree path %1 drive %2 %3!u!.\n",
  984. ResourceEntry->Setup.Path,
  985. ResourceEntry->Setup.DriveLetter,
  986. status);
  987. }
  988. }
  989. #endif
  990. if ( status != ERROR_SUCCESS ) {
  991. (g_LogEvent)(
  992. ResourceEntry->ResourceHandle,
  993. LOG_ERROR,
  994. L"Error %1!u! bringing resource online.\n",
  995. status );
  996. resourceStatus.ResourceState = ClusterResourceFailed;
  997. } else {
  998. resourceStatus.ResourceState = ClusterResourceOnline;
  999. }
  1000. // _ASSERTE(g_SetResourceStatus != NULL);
  1001. g_SetResourceStatus( ResourceEntry->ResourceHandle, &resourceStatus );
  1002. ResourceEntry->State = resourceStatus.ResourceState;
  1003. return(status);
  1004. } // MajorityNodeSetOnlineThread
  1005. DWORD
  1006. WINAPI
  1007. MajorityNodeSetOffline(
  1008. IN RESID ResourceId
  1009. )
  1010. /*++
  1011. Routine Description:
  1012. Offline routine for MajorityNodeSet resources.
  1013. Take the specified resource offline gracefully (unavailable for use).
  1014. Wait for any cleanup operations to complete before returning.
  1015. Arguments:
  1016. ResourceId - Supplies the resource id for the resource to be shutdown
  1017. gracefully.
  1018. Return Value:
  1019. ERROR_SUCCESS - The request completed successfully and the resource is
  1020. offline.
  1021. ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  1022. ERROR_IO_PENDING - The request is still pending, a thread has been
  1023. activated to process the offline request. The thread that is
  1024. processing the offline will periodically report status by calling
  1025. the SetResourceStatus callback method, until the resource is placed
  1026. into the ClusterResourceOffline state (or the resource monitor decides
  1027. to timeout the offline request and Terminate the resource).
  1028. Win32 error code - Will cause the resource monitor to log an event and
  1029. call the Terminate routine.
  1030. --*/
  1031. {
  1032. PMNS_RESOURCE resourceEntry;
  1033. resourceEntry = (PMNS_RESOURCE)ResourceId;
  1034. if ( resourceEntry == NULL ) {
  1035. return(ERROR_RESOURCE_NOT_FOUND);
  1036. }
  1037. if ( resourceEntry->ResId != ResourceId ) {
  1038. (g_LogEvent)(
  1039. resourceEntry->ResourceHandle,
  1040. LOG_ERROR,
  1041. L"Offline resource sanity check failed! ResourceId = %1!u!.\n",
  1042. ResourceId );
  1043. return(ERROR_RESOURCE_NOT_FOUND);
  1044. }
  1045. (g_LogEvent)(
  1046. resourceEntry->ResourceHandle,
  1047. LOG_INFORMATION,
  1048. L"Offline request.\n" );
  1049. // TODO: Offline code
  1050. // NOTE: Offline should try to shut the resource down gracefully, whereas
  1051. // Terminate must shut the resource down immediately. If there are no
  1052. // differences between a graceful shut down and an immediate shut down,
  1053. // Terminate can be called for Offline, as it is below. However, if there
  1054. // are differences, replace the call to Terminate below with your graceful
  1055. // shutdown code.
  1056. //
  1057. // Terminate the resource.
  1058. //
  1059. return MajorityNodeSetDoTerminate( resourceEntry );
  1060. } // MajorityNodeSetOffline
  1061. VOID
  1062. WINAPI
  1063. MajorityNodeSetTerminate(
  1064. IN RESID ResourceId
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. Terminate routine for MajorityNodeSet resources.
  1069. Take the specified resource offline immediately (the resource is
  1070. unavailable for use).
  1071. Arguments:
  1072. ResourceId - Supplies the resource id for the resource to be brought
  1073. offline.
  1074. Return Value:
  1075. None.
  1076. --*/
  1077. {
  1078. PMNS_RESOURCE resourceEntry;
  1079. resourceEntry = (PMNS_RESOURCE)ResourceId;
  1080. if ( resourceEntry == NULL ) {
  1081. return;
  1082. }
  1083. if ( resourceEntry->ResId != ResourceId ) {
  1084. (g_LogEvent)(
  1085. resourceEntry->ResourceHandle,
  1086. LOG_ERROR,
  1087. L"Terminate resource sanity check failed! ResourceId = %1!u!.\n",
  1088. ResourceId );
  1089. return;
  1090. }
  1091. (g_LogEvent)(
  1092. resourceEntry->ResourceHandle,
  1093. LOG_INFORMATION,
  1094. L"Terminate request.\n" );
  1095. //
  1096. // Terminate the resource.
  1097. //
  1098. MajorityNodeSetDoTerminate( resourceEntry );
  1099. resourceEntry->State = ClusterResourceOffline;
  1100. } // MajorityNodeSetTerminate
  1101. DWORD
  1102. MajorityNodeSetDoTerminate(
  1103. IN PMNS_RESOURCE ResourceEntry
  1104. )
  1105. /*++
  1106. Routine Description:
  1107. Do the actual Terminate work for MajorityNodeSet resources.
  1108. Arguments:
  1109. ResourceEntry - Supplies resource entry for resource to be terminated
  1110. Return Value:
  1111. ERROR_SUCCESS - The request completed successfully and the resource is
  1112. offline.
  1113. Win32 error code - Will cause the resource monitor to log an event and
  1114. call the Terminate routine.
  1115. --*/
  1116. {
  1117. DWORD status = ERROR_SUCCESS;
  1118. // Set the volume going away flag.
  1119. FsSignalShutdown(ResourceEntry->VolHdl);
  1120. // Get lock
  1121. EnterCriticalSection(&ResourceEntry->Lock);
  1122. //
  1123. // wait for arb thread if any
  1124. //
  1125. (g_LogEvent)(
  1126. ResourceEntry->ResourceHandle,
  1127. LOG_INFORMATION,
  1128. L"DoTerminate: Wait for any arbitration threads to finish.\n" );
  1129. while (ResourceEntry->ArbThread) {
  1130. HANDLE th = ResourceEntry->ArbThread;
  1131. // drop lock
  1132. LeaveCriticalSection(&ResourceEntry->Lock);
  1133. WaitForSingleObject(ResourceEntry->ArbThread, INFINITE);
  1134. // Get lock
  1135. EnterCriticalSection(&ResourceEntry->Lock);
  1136. if (th == ResourceEntry->ArbThread) {
  1137. CloseHandle(ResourceEntry->ArbThread);
  1138. ResourceEntry->ArbThread = NULL;
  1139. }
  1140. }
  1141. // Drop lock
  1142. LeaveCriticalSection(&ResourceEntry->Lock);
  1143. (g_LogEvent)(
  1144. ResourceEntry->ResourceHandle,
  1145. LOG_INFORMATION,
  1146. L"DoTerminate: Now kill off any pending Online or Reserve threads.\n" );
  1147. //
  1148. // Kill off any pending threads.
  1149. //
  1150. ClusWorkerTerminate( &ResourceEntry->OnlineThread );
  1151. ClusWorkerTerminate( &ResourceEntry->ReserveThread );
  1152. //
  1153. // Terminate the resource.
  1154. //
  1155. (g_LogEvent)(
  1156. ResourceEntry->ResourceHandle,
  1157. LOG_INFORMATION,
  1158. L"Offlining server.\n" );
  1159. #ifdef ENABLE_SMB
  1160. // Remove our network name now
  1161. ASSERT(ResourceEntry->SrvHdl);
  1162. SrvOffline(ResourceEntry->SrvHdl);
  1163. #endif
  1164. PipeOffline(ResourceEntry->PipeHdl);
  1165. #ifdef ENABLE_SMB
  1166. // disconnect network connection
  1167. status = WNetCancelConnection2(ResourceEntry->Setup.DriveLetter, FALSE, TRUE);
  1168. if (status != NO_ERROR) {
  1169. (g_LogEvent)(
  1170. ResourceEntry->ResourceHandle,
  1171. LOG_INFORMATION,
  1172. L"Failed to disconnect '%1' err %2!d!.\n",
  1173. ResourceEntry->Setup.DriveLetter, status);
  1174. status = ERROR_SUCCESS;
  1175. } else {
  1176. (g_LogEvent)(
  1177. ResourceEntry->ResourceHandle,
  1178. LOG_INFORMATION,
  1179. L"DoTerminate: Server is now offline and connections cancelled.\n" );
  1180. }
  1181. #endif
  1182. // xxx: call our release since resmon won't do it
  1183. MajorityNodeSetRelease((RESID)ResourceEntry);
  1184. if ( status == ERROR_SUCCESS ) {
  1185. ResourceEntry->State = ClusterResourceOffline;
  1186. }
  1187. return(status);
  1188. } // MajorityNodeSetDoTerminate
  1189. BOOL
  1190. WINAPI
  1191. MajorityNodeSetLooksAlive(
  1192. IN RESID ResourceId
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. LooksAlive routine for MajorityNodeSet resources.
  1197. Perform a quick check to determine if the specified resource is probably
  1198. online (available for use). This call should not block for more than
  1199. 300 ms, preferably less than 50 ms.
  1200. Arguments:
  1201. ResourceId - Supplies the resource id for the resource to polled.
  1202. Return Value:
  1203. TRUE - The specified resource is probably online and available for use.
  1204. FALSE - The specified resource is not functioning normally.
  1205. --*/
  1206. {
  1207. PMNS_RESOURCE resourceEntry;
  1208. resourceEntry = (PMNS_RESOURCE)ResourceId;
  1209. if ( resourceEntry == NULL ) {
  1210. return(FALSE);
  1211. }
  1212. if ( resourceEntry->ResId != ResourceId ) {
  1213. (g_LogEvent)(
  1214. resourceEntry->ResourceHandle,
  1215. LOG_ERROR,
  1216. L"LooksAlive sanity check failed! ResourceId = %1!u!.\n",
  1217. ResourceId );
  1218. return(FALSE);
  1219. }
  1220. #ifdef LOG_VERBOSE
  1221. (g_LogEvent)(
  1222. resourceEntry->ResourceHandle,
  1223. LOG_INFORMATION,
  1224. L"LooksAlive request.\n" );
  1225. #endif
  1226. // TODO: LooksAlive code
  1227. // NOTE: LooksAlive should be a quick check to see if the resource is
  1228. // available or not, whereas IsAlive should be a thorough check. If
  1229. // there are no differences between a quick check and a thorough check,
  1230. // IsAlive can be called for LooksAlive, as it is below. However, if there
  1231. // are differences, replace the call to IsAlive below with your quick
  1232. // check code.
  1233. //
  1234. // Check to see if the resource is alive.
  1235. //
  1236. return(MajorityNodeSetCheckIsAlive( resourceEntry ));
  1237. } // MajorityNodeSetLooksAlive
  1238. BOOL
  1239. WINAPI
  1240. MajorityNodeSetIsAlive(
  1241. IN RESID ResourceId
  1242. )
  1243. /*++
  1244. Routine Description:
  1245. IsAlive routine for MajorityNodeSet resources.
  1246. Perform a thorough check to determine if the specified resource is online
  1247. (available for use). This call should not block for more than 400 ms,
  1248. preferably less than 100 ms.
  1249. Arguments:
  1250. ResourceId - Supplies the resource id for the resource to polled.
  1251. Return Value:
  1252. TRUE - The specified resource is online and functioning normally.
  1253. FALSE - The specified resource is not functioning normally.
  1254. --*/
  1255. {
  1256. PMNS_RESOURCE resourceEntry;
  1257. resourceEntry = (PMNS_RESOURCE)ResourceId;
  1258. if ( resourceEntry == NULL ) {
  1259. return(FALSE);
  1260. }
  1261. if ( resourceEntry->ResId != ResourceId ) {
  1262. (g_LogEvent)(
  1263. resourceEntry->ResourceHandle,
  1264. LOG_ERROR,
  1265. L"IsAlive sanity check failed! ResourceId = %1!u!.\n",
  1266. ResourceId );
  1267. return(FALSE);
  1268. }
  1269. #ifdef LOG_VERBOSE
  1270. (g_LogEvent)(
  1271. resourceEntry->ResourceHandle,
  1272. LOG_INFORMATION,
  1273. L"IsAlive request.\n" );
  1274. #endif
  1275. //
  1276. // Check to see if the resource is alive.
  1277. //
  1278. return(MajorityNodeSetCheckIsAlive( resourceEntry ));
  1279. } // MajorityNodeSetIsAlive
  1280. BOOL
  1281. MajorityNodeSetCheckIsAlive(
  1282. IN PMNS_RESOURCE ResourceEntry
  1283. )
  1284. /*++
  1285. Routine Description:
  1286. Check to see if the resource is alive for MajorityNodeSet resources.
  1287. Arguments:
  1288. ResourceEntry - Supplies the resource entry for the resource to polled.
  1289. Return Value:
  1290. TRUE - The specified resource is online and functioning normally.
  1291. FALSE - The specified resource is not functioning normally.
  1292. --*/
  1293. {
  1294. DWORD err;
  1295. HANDLE vol;
  1296. //
  1297. // Check to see if the resource is alive.
  1298. //
  1299. if (ResourceEntry->State == ClusterResourceFailed) {
  1300. return FALSE;
  1301. }
  1302. else {
  1303. return TRUE;
  1304. }
  1305. // Not reliable in the new design.
  1306. // Get lock
  1307. EnterCriticalSection(&ResourceEntry->Lock);
  1308. vol = ResourceEntry->VolHdl;
  1309. // Drop lock
  1310. LeaveCriticalSection(&ResourceEntry->Lock);
  1311. if (vol) {
  1312. err = FsIsOnlineReadonly(vol);
  1313. }
  1314. else {
  1315. err = ERROR_INVALID_PARAMETER;
  1316. }
  1317. if (err != ERROR_SUCCESS && err != ERROR_IO_PENDING) {
  1318. return FALSE;
  1319. }
  1320. return(TRUE);
  1321. } // MajorityNodeSetCheckIsAlive
  1322. /////////////////////////////////////////////////////////////////////////////
  1323. //++
  1324. //
  1325. // MajorityNodeSetNameHandler
  1326. //
  1327. // Description:
  1328. // Handle the CLUSCTL_RESOURCE_SET_NAME control code by saving the new
  1329. // name of the resource.
  1330. //
  1331. // Arguments:
  1332. // pResourceEntry [IN OUT]
  1333. // Supplies the resource entry on which to operate.
  1334. //
  1335. // pszName [IN]
  1336. // The new name of the resource.
  1337. //
  1338. // Return Value:
  1339. // ERROR_SUCCESS
  1340. // The function completed successfully.
  1341. //
  1342. // Win32 error code
  1343. // The function failed.
  1344. //
  1345. //--
  1346. /////////////////////////////////////////////////////////////////////////////
  1347. DWORD MajorityNodeSetNameHandler(
  1348. IN OUT PMNS_RESOURCE pResourceEntry,
  1349. IN LPWSTR pszName
  1350. )
  1351. {
  1352. DWORD nStatus = ERROR_SUCCESS;
  1353. DWORD cbNameBuffer;
  1354. HRESULT hr = S_OK;
  1355. //
  1356. // Save the name of the resource.
  1357. //
  1358. if (pResourceEntry->ResourceName != NULL) {
  1359. LocalFree(pResourceEntry->ResourceName);
  1360. }
  1361. cbNameBuffer = (lstrlenW(pszName) + 1) * sizeof(WCHAR);
  1362. pResourceEntry->ResourceName = LocalAlloc(LMEM_FIXED, cbNameBuffer);
  1363. if (pResourceEntry->ResourceName == NULL)
  1364. {
  1365. nStatus = GetLastError();
  1366. (g_LogEvent)(
  1367. pResourceEntry->ResourceHandle,
  1368. LOG_ERROR,
  1369. L"Failed to allocate memory for the new resource name '%1'. Error %2!u!.\n",
  1370. pszName,
  1371. nStatus
  1372. );
  1373. goto Cleanup;
  1374. } // if: error allocating memory for the name.
  1375. lstrcpyW( pResourceEntry->ResourceName, pszName );
  1376. Cleanup:
  1377. return nStatus;
  1378. } //*** MajorityNodeSetNameHandler()
  1379. /////////////////////////////////////////////////////////////////////////////
  1380. //
  1381. // System Check Functions.
  1382. //
  1383. /////////////////////////////////////////////////////////////////////////////
  1384. DWORD
  1385. WINAPI
  1386. MajorityNodeSetResourceControl(
  1387. IN RESID ResourceId,
  1388. IN DWORD ControlCode,
  1389. IN PVOID InBuffer,
  1390. IN DWORD InBufferSize,
  1391. OUT PVOID OutBuffer,
  1392. IN DWORD OutBufferSize,
  1393. OUT LPDWORD BytesReturned
  1394. )
  1395. /*++
  1396. Routine Description:
  1397. ResourceControl routine for MajorityNodeSet resources.
  1398. Perform the control request specified by ControlCode on the specified
  1399. resource.
  1400. Arguments:
  1401. ResourceId - Supplies the resource id for the specific resource.
  1402. ControlCode - Supplies the control code that defines the action
  1403. to be performed.
  1404. InBuffer - Supplies a pointer to a buffer containing input data.
  1405. InBufferSize - Supplies the size, in bytes, of the data pointed
  1406. to by InBuffer.
  1407. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1408. OutBufferSize - Supplies the size, in bytes, of the available space
  1409. pointed to by OutBuffer.
  1410. BytesReturned - Returns the number of bytes of OutBuffer actually
  1411. filled in by the resource. If OutBuffer is too small, BytesReturned
  1412. contains the total number of bytes for the operation to succeed.
  1413. Return Value:
  1414. ERROR_SUCCESS - The function completed successfully.
  1415. ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  1416. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1417. In some cases, this allows the cluster software to perform the work.
  1418. Win32 error code - The function failed.
  1419. --*/
  1420. {
  1421. DWORD status;
  1422. PMNS_RESOURCE resourceEntry;
  1423. DWORD required;
  1424. resourceEntry = (PMNS_RESOURCE)ResourceId;
  1425. if ( resourceEntry == NULL ) {
  1426. return(ERROR_RESOURCE_NOT_FOUND);
  1427. }
  1428. if ( resourceEntry->ResId != ResourceId ) {
  1429. (g_LogEvent)(
  1430. resourceEntry->ResourceHandle,
  1431. LOG_ERROR,
  1432. L"ResourceControl sanity check failed! ResourceId = %1!u!.\n",
  1433. ResourceId );
  1434. return(ERROR_RESOURCE_NOT_FOUND);
  1435. }
  1436. switch ( ControlCode ) {
  1437. case CLUSCTL_RESOURCE_UNKNOWN:
  1438. *BytesReturned = 0;
  1439. status = ERROR_SUCCESS;
  1440. break;
  1441. case CLUSCTL_RESOURCE_SET_NAME:
  1442. if (InBuffer != NULL) {
  1443. status = MajorityNodeSetNameHandler(
  1444. resourceEntry,
  1445. InBuffer
  1446. );
  1447. }
  1448. else {
  1449. status = ERROR_INVALID_PARAMETER;
  1450. }
  1451. break;
  1452. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTY_FMTS:
  1453. status = ResUtilGetPropertyFormats( MajorityNodeSetResourcePrivateProperties,
  1454. OutBuffer,
  1455. OutBufferSize,
  1456. BytesReturned,
  1457. &required );
  1458. if ( status == ERROR_MORE_DATA ) {
  1459. *BytesReturned = required;
  1460. }
  1461. break;
  1462. case CLUSCTL_RESOURCE_FORCE_QUORUM:
  1463. *BytesReturned = 0;
  1464. status = ERROR_SUCCESS;
  1465. if (InBufferSize >= sizeof(CLUS_FORCE_QUORUM_INFO)) {
  1466. PCLUS_FORCE_QUORUM_INFO p = (PCLUS_FORCE_QUORUM_INFO)InBuffer;
  1467. DWORD mask = p->dwNodeBitMask;
  1468. // count number of set bits.
  1469. for (required = 0; mask != 0; mask = mask >> 1) {
  1470. if (mask & 0x1)
  1471. required++;
  1472. }
  1473. (g_LogEvent)(
  1474. resourceEntry->ResourceHandle,
  1475. LOG_INFORMATION,
  1476. L"Setting quorum size = %1!u!.\n",
  1477. required/2+1);
  1478. // BugFix: 653110
  1479. CrsSetForcedQuorumSize((required/2)+1);
  1480. } else {
  1481. status = ERROR_INVALID_PARAMETER;
  1482. }
  1483. break;
  1484. case CLUSCTL_RESOURCE_GET_CHARACTERISTICS:
  1485. *BytesReturned = sizeof(DWORD);
  1486. if ( OutBufferSize < sizeof(DWORD) ) {
  1487. status = ERROR_MORE_DATA;
  1488. } else {
  1489. LPDWORD ptrDword = OutBuffer;
  1490. *ptrDword = CLUS_CHAR_QUORUM | CLUS_CHAR_DELETE_REQUIRES_ALL_NODES | CLUS_CHAR_REQUIRES_STATE_CHANGE_REASON;
  1491. status = ERROR_SUCCESS;
  1492. }
  1493. break;
  1494. case CLUSCTL_RESOURCE_STATE_CHANGE_REASON:
  1495. status = ERROR_SUCCESS;
  1496. if (InBufferSize == sizeof(CLUSCTL_RESOURCE_STATE_CHANGE_REASON_STRUCT)) {
  1497. PCLUSCTL_RESOURCE_STATE_CHANGE_REASON_STRUCT pStateChangeReason=(PCLUSCTL_RESOURCE_STATE_CHANGE_REASON_STRUCT)InBuffer;
  1498. // Do this only for rundown not shutdown.
  1499. if (pStateChangeReason->eReason == eResourceStateChangeReasonRundown) {
  1500. FsSignalShutdown(resourceEntry->VolHdl);
  1501. }
  1502. } else {
  1503. status = ERROR_INVALID_PARAMETER;
  1504. }
  1505. break;
  1506. case CLUSCTL_RESOURCE_GET_CLASS_INFO:
  1507. *BytesReturned = sizeof(CLUS_RESOURCE_CLASS_INFO);
  1508. if ( OutBufferSize < sizeof(CLUS_RESOURCE_CLASS_INFO) ) {
  1509. status = ERROR_MORE_DATA;
  1510. } else {
  1511. PCLUS_RESOURCE_CLASS_INFO ptrResClassInfo = (PCLUS_RESOURCE_CLASS_INFO) OutBuffer;
  1512. ptrResClassInfo->rc = CLUS_RESCLASS_MAJORITY_NODE_SET;
  1513. ptrResClassInfo->SubClass = (DWORD) CLUS_RESSUBCLASS_SHARED;
  1514. status = ERROR_SUCCESS;
  1515. }
  1516. break;
  1517. case CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO:
  1518. //
  1519. // If the local quorum drive letter cannot be found in the
  1520. // path parameter, it defaults to "SystemDrive" environment
  1521. // variable.
  1522. //
  1523. status = MajorityNodeSetGetDiskInfo(resourceEntry->Setup.DriveLetter,
  1524. &OutBuffer,
  1525. OutBufferSize,
  1526. BytesReturned);
  1527. // Add the endmark.
  1528. if ( OutBufferSize > *BytesReturned ) {
  1529. OutBufferSize -= *BytesReturned;
  1530. } else {
  1531. OutBufferSize = 0;
  1532. }
  1533. *BytesReturned += sizeof(CLUSPROP_SYNTAX);
  1534. if ( OutBufferSize >= sizeof(CLUSPROP_SYNTAX) ) {
  1535. PCLUSPROP_SYNTAX ptrSyntax = (PCLUSPROP_SYNTAX) OutBuffer;
  1536. ptrSyntax->dw = CLUSPROP_SYNTAX_ENDMARK;
  1537. }
  1538. break;
  1539. case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
  1540. status = ResUtilEnumProperties( MajorityNodeSetResourcePrivateProperties,
  1541. (LPWSTR)OutBuffer,
  1542. OutBufferSize,
  1543. BytesReturned,
  1544. &required );
  1545. if ( status == ERROR_MORE_DATA ) {
  1546. *BytesReturned = required;
  1547. }
  1548. break;
  1549. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
  1550. status = MajorityNodeSetGetPrivateResProperties( resourceEntry,
  1551. OutBuffer,
  1552. OutBufferSize,
  1553. BytesReturned );
  1554. break;
  1555. case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
  1556. status = MajorityNodeSetValidatePrivateResProperties( resourceEntry,
  1557. InBuffer,
  1558. InBufferSize,
  1559. NULL );
  1560. break;
  1561. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  1562. status = MajorityNodeSetSetPrivateResProperties( resourceEntry,
  1563. InBuffer,
  1564. InBufferSize );
  1565. break;
  1566. case CLUSCTL_RESOURCE_DELETE:
  1567. // todo: we need to only do this if are using local defaults.
  1568. // we need to remove our share and directory now
  1569. if (resourceEntry->Setup.DiskList[0]) {
  1570. // need to end IPC session in order to be able to delete
  1571. // directory
  1572. FsEnd(resourceEntry->FsHdl);
  1573. status = SetupDelete(resourceEntry->Setup.DiskList[0]);
  1574. } else {
  1575. status = ERROR_INVALID_PARAMETER;
  1576. }
  1577. (g_LogEvent)(
  1578. resourceEntry->ResourceHandle,
  1579. LOG_INFORMATION,
  1580. L"Delete ResourceId = %1 err %2!u!.\n",
  1581. resourceEntry->ResourceName, status);
  1582. break;
  1583. // We need to find which node got added and adjust our
  1584. // disklist. If we are online or we own quorum, then we need
  1585. // to add this new replica to current filesystem set.
  1586. case CLUSCTL_RESOURCE_INSTALL_NODE:
  1587. case CLUSCTL_RESOURCE_EVICT_NODE:
  1588. (g_LogEvent)(
  1589. resourceEntry->ResourceHandle,
  1590. LOG_INFORMATION,
  1591. L"Recompute %1 quorum set changed, Install or Evict node = '%2'.\n",
  1592. resourceEntry->ResourceName, (InBuffer ? InBuffer : L""));
  1593. // fall through
  1594. case MajorityNodeSetIoctlPhase1:
  1595. // we need to enumerate the current cluster and check it against
  1596. // our disklist. we need to do this only if we actually have some
  1597. if (1) {
  1598. MNS_SETUP Setup;
  1599. memset(&Setup, 0, sizeof(Setup));
  1600. status = SetupStart(resourceEntry->ResourceName,
  1601. &Setup.Path,
  1602. Setup.DiskList,
  1603. &Setup.DiskListSz,
  1604. &Setup.Nic,
  1605. &Setup.Transport,
  1606. &Setup.ArbTime);
  1607. if (status != ERROR_SUCCESS)
  1608. return status;
  1609. EnterCriticalSection(&resourceEntry->Lock);
  1610. if (resourceEntry->Setup.DiskListSz != Setup.DiskListSz)
  1611. status = ERROR_INVALID_PARAMETER;
  1612. else {
  1613. DWORD i;
  1614. for (i = 0; i < FsMaxNodes; i++) {
  1615. if (Setup.DiskList[i] == NULL && resourceEntry->Setup.DiskList[i] == NULL)
  1616. continue;
  1617. if (Setup.DiskList[i] == NULL || resourceEntry->Setup.DiskList[i] == NULL) {
  1618. status = ERROR_INVALID_PARAMETER;
  1619. break;
  1620. }
  1621. if (wcscmp(Setup.DiskList[i],
  1622. resourceEntry->Setup.DiskList[i])) {
  1623. status = ERROR_INVALID_PARAMETER;
  1624. break;
  1625. }
  1626. }
  1627. }
  1628. if (status != ERROR_SUCCESS && resourceEntry->VolHdl) {
  1629. // Update ourself now
  1630. status = FsUpdateReplicaSet(resourceEntry->VolHdl,
  1631. Setup.DiskList,
  1632. Setup.DiskListSz);
  1633. if (status == ERROR_SUCCESS) {
  1634. DWORD i;
  1635. // we need to free the current disklist, careful with slot 0
  1636. if (Setup.DiskList[0])
  1637. LocalFree(Setup.DiskList[0]);
  1638. for (i = 1; i < FsMaxNodes; i++) {
  1639. if (resourceEntry->Setup.DiskList[i]) {
  1640. LocalFree(resourceEntry->Setup.DiskList[i]);
  1641. }
  1642. resourceEntry->Setup.DiskList[i] = Setup.DiskList[i];
  1643. }
  1644. resourceEntry->Setup.DiskListSz = Setup.DiskListSz;
  1645. }
  1646. // set new arb timeout value
  1647. resourceEntry->Setup.ArbTime = Setup.ArbTime;
  1648. (g_LogEvent)(
  1649. resourceEntry->ResourceHandle,
  1650. LOG_WARNING,
  1651. L"Configuration change, new set size %1!u! status %2!u!.\n",
  1652. Setup.DiskListSz, status
  1653. );
  1654. }
  1655. LeaveCriticalSection(&resourceEntry->Lock);
  1656. // free stuff
  1657. if (Setup.Path)
  1658. LocalFree(Setup.Path);
  1659. if (Setup.Transport)
  1660. LocalFree(Setup.Transport);
  1661. }
  1662. break;
  1663. default:
  1664. status = ERROR_INVALID_FUNCTION;
  1665. break;
  1666. }
  1667. return(status);
  1668. } // MajorityNodeSetResourceControl
  1669. DWORD
  1670. WINAPI
  1671. MajorityNodeSetResourceTypeControl(
  1672. IN LPCWSTR ResourceTypeName,
  1673. IN DWORD ControlCode,
  1674. IN PVOID InBuffer,
  1675. IN DWORD InBufferSize,
  1676. OUT PVOID OutBuffer,
  1677. IN DWORD OutBufferSize,
  1678. OUT LPDWORD BytesReturned
  1679. )
  1680. /*++
  1681. Routine Description:
  1682. ResourceTypeControl routine for MajorityNodeSet resources.
  1683. Perform the control request specified by ControlCode.
  1684. Arguments:
  1685. ResourceTypeName - Supplies the name of the resource type.
  1686. ControlCode - Supplies the control code that defines the action
  1687. to be performed.
  1688. InBuffer - Supplies a pointer to a buffer containing input data.
  1689. InBufferSize - Supplies the size, in bytes, of the data pointed
  1690. to by InBuffer.
  1691. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1692. OutBufferSize - Supplies the size, in bytes, of the available space
  1693. pointed to by OutBuffer.
  1694. BytesReturned - Returns the number of bytes of OutBuffer actually
  1695. filled in by the resource. If OutBuffer is too small, BytesReturned
  1696. contains the total number of bytes for the operation to succeed.
  1697. Return Value:
  1698. ERROR_SUCCESS - The function completed successfully.
  1699. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1700. In some cases, this allows the cluster software to perform the work.
  1701. Win32 error code - The function failed.
  1702. --*/
  1703. {
  1704. DWORD status = ERROR_INVALID_FUNCTION;
  1705. DWORD required;
  1706. switch ( ControlCode ) {
  1707. case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
  1708. *BytesReturned = 0;
  1709. status = ERROR_SUCCESS;
  1710. break;
  1711. case CLUSCTL_RESOURCE_TYPE_GET_ARB_TIMEOUT:
  1712. {
  1713. PCLUSPROP_DWORD ptrDword;
  1714. DWORD bytesReturned;
  1715. // Return the Arbitration Timeout value needed - 180.
  1716. bytesReturned = sizeof(CLUSPROP_DWORD);
  1717. *BytesReturned = bytesReturned;
  1718. if ( bytesReturned <= OutBufferSize ) {
  1719. ptrDword = (PCLUSPROP_DWORD)OutBuffer;
  1720. ptrDword->Syntax.dw = CLUSPROP_SYNTAX_LIST_VALUE_DWORD;
  1721. ptrDword->cbLength = sizeof(DWORD);
  1722. ptrDword->dw = 180;
  1723. status = ERROR_SUCCESS;
  1724. } else {
  1725. status = ERROR_MORE_DATA;
  1726. }
  1727. break;
  1728. }
  1729. case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_RESOURCE_PROPERTY_FMTS:
  1730. status = ResUtilGetPropertyFormats( MajorityNodeSetResourcePrivateProperties,
  1731. OutBuffer,
  1732. OutBufferSize,
  1733. BytesReturned,
  1734. &required );
  1735. if ( status == ERROR_MORE_DATA ) {
  1736. *BytesReturned = required;
  1737. }
  1738. break;
  1739. case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
  1740. status = ResUtilEnumProperties( MajorityNodeSetResourcePrivateProperties,
  1741. (LPWSTR)OutBuffer,
  1742. OutBufferSize,
  1743. BytesReturned,
  1744. &required );
  1745. if ( status == ERROR_MORE_DATA ) {
  1746. *BytesReturned = required;
  1747. }
  1748. break;
  1749. case CLUSCTL_RESOURCE_TYPE_STARTING_PHASE1:
  1750. status = SetupIoctlQuorumResource(CLUS_RESTYPE_NAME_MAJORITYNODESET,
  1751. MajorityNodeSetIoctlPhase1);
  1752. break;
  1753. case CLUSCTL_RESOURCE_TYPE_STARTING_PHASE2:
  1754. status = ERROR_SUCCESS;
  1755. break;
  1756. default:
  1757. status = ERROR_INVALID_FUNCTION;
  1758. break;
  1759. }
  1760. return(status);
  1761. } // MajorityNodeSetResourceTypeControl
  1762. DWORD
  1763. MajorityNodeSetGetPrivateResProperties(
  1764. IN OUT PMNS_RESOURCE ResourceEntry,
  1765. OUT PVOID OutBuffer,
  1766. IN DWORD OutBufferSize,
  1767. OUT LPDWORD BytesReturned
  1768. )
  1769. /*++
  1770. Routine Description:
  1771. Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
  1772. for resources of type MajorityNodeSet.
  1773. Arguments:
  1774. ResourceEntry - Supplies the resource entry on which to operate.
  1775. OutBuffer - Returns the output data.
  1776. OutBufferSize - Supplies the size, in bytes, of the data pointed
  1777. to by OutBuffer.
  1778. BytesReturned - The number of bytes returned in OutBuffer.
  1779. Return Value:
  1780. ERROR_SUCCESS - The function completed successfully.
  1781. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1782. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1783. Win32 error code - The function failed.
  1784. --*/
  1785. {
  1786. DWORD status;
  1787. DWORD required;
  1788. status = ResUtilGetAllProperties( ResourceEntry->ParametersKey,
  1789. MajorityNodeSetResourcePrivateProperties,
  1790. OutBuffer,
  1791. OutBufferSize,
  1792. BytesReturned,
  1793. &required );
  1794. if ( status == ERROR_MORE_DATA ) {
  1795. *BytesReturned = required;
  1796. }
  1797. return(status);
  1798. } // MajorityNodeSetGetPrivateResProperties
  1799. DWORD
  1800. MajorityNodeSetValidatePrivateResProperties(
  1801. IN OUT PMNS_RESOURCE ResourceEntry,
  1802. IN PVOID InBuffer,
  1803. IN DWORD InBufferSize,
  1804. OUT PMNS_PARAMS Params
  1805. )
  1806. /*++
  1807. Routine Description:
  1808. Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
  1809. function for resources of type MajorityNodeSet.
  1810. Arguments:
  1811. ResourceEntry - Supplies the resource entry on which to operate.
  1812. InBuffer - Supplies a pointer to a buffer containing input data.
  1813. InBufferSize - Supplies the size, in bytes, of the data pointed
  1814. to by InBuffer.
  1815. Params - Supplies the parameter block to fill in.
  1816. Return Value:
  1817. ERROR_SUCCESS - The function completed successfully.
  1818. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1819. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1820. Win32 error code - The function failed.
  1821. --*/
  1822. {
  1823. DWORD status = ERROR_SUCCESS;
  1824. MNS_PARAMS params;
  1825. PMNS_PARAMS pParams;
  1826. //
  1827. // Check if there is input data.
  1828. //
  1829. if ( (InBuffer == NULL) ||
  1830. (InBufferSize < sizeof(DWORD)) ) {
  1831. return(ERROR_INVALID_DATA);
  1832. }
  1833. //
  1834. // Duplicate the resource parameter block.
  1835. //
  1836. if ( Params == NULL ) {
  1837. pParams = &params;
  1838. } else {
  1839. pParams = Params;
  1840. }
  1841. ZeroMemory( pParams, sizeof(MNS_PARAMS) );
  1842. status = ResUtilDupParameterBlock( (LPBYTE) pParams,
  1843. (LPBYTE) &ResourceEntry->Params,
  1844. MajorityNodeSetResourcePrivateProperties );
  1845. if ( status != ERROR_SUCCESS ) {
  1846. return(status);
  1847. }
  1848. //
  1849. // Parse and validate the properties.
  1850. //
  1851. status = ResUtilVerifyPropertyTable( MajorityNodeSetResourcePrivateProperties,
  1852. NULL,
  1853. TRUE, // AllowUnknownProperties
  1854. InBuffer,
  1855. InBufferSize,
  1856. (LPBYTE) pParams );
  1857. if ( status == ERROR_SUCCESS ) {
  1858. //
  1859. // Validate the parameter values.
  1860. //
  1861. // TODO: Code to validate interactions between parameters goes here.
  1862. // we need to validate that the user specified '\\srvname\share'
  1863. if (pParams->Path != NULL) {
  1864. if (pParams->Path[0] != L'\\' || pParams->Path[1] != L'\\' || lstrlenW(pParams->Path) < 3) {
  1865. status = ERROR_INVALID_PARAMETER;
  1866. } else {
  1867. LPWSTR sharename;
  1868. sharename = wcschr(&pParams->Path[2], L'\\');
  1869. if (sharename == NULL || sharename[1] == L'\0') {
  1870. status = ERROR_INVALID_PARAMETER;
  1871. }
  1872. }
  1873. }
  1874. // we need to validate user specified disklist 'drive:\path or \\srv\path'
  1875. if (pParams->DiskList != NULL) {
  1876. DWORD cnt = 0, i, len;
  1877. LPWSTR p;
  1878. p = pParams->DiskList;
  1879. for (i = 0; p != NULL && *p != L'\0' && i < pParams->DiskListSize; ) {
  1880. // validate format as '\\srvname\share'
  1881. if (p[0] == L'\\' && p[1] == L'\\' && p[2] != L'\0') {
  1882. if (wcschr(&p[2],L'\\') == NULL) {
  1883. status = ERROR_INVALID_PARAMETER;
  1884. }
  1885. } else if (p[0] == L'\0' || !iswalpha(p[0]) || p[1] != L':' || p[2] != L'\\') {
  1886. status = ERROR_INVALID_PARAMETER;
  1887. }
  1888. if (status != ERROR_INVALID_PARAMETER)
  1889. break;
  1890. cnt++;
  1891. len = wcslen(p) + 1;
  1892. i += (len * sizeof(WCHAR));
  1893. p += len;
  1894. }
  1895. if (cnt == 0)
  1896. status = ERROR_INVALID_PARAMETER;
  1897. }
  1898. }
  1899. //
  1900. // Cleanup our parameter block.
  1901. //
  1902. if ( pParams == &params ) {
  1903. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1904. (LPBYTE) &ResourceEntry->Params,
  1905. MajorityNodeSetResourcePrivateProperties );
  1906. }
  1907. return status;
  1908. } // MajorityNodeSetValidatePrivateResProperties
  1909. DWORD
  1910. MajorityNodeSetSetPrivateResProperties(
  1911. IN OUT PMNS_RESOURCE ResourceEntry,
  1912. IN PVOID InBuffer,
  1913. IN DWORD InBufferSize
  1914. )
  1915. /*++
  1916. Routine Description:
  1917. Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
  1918. for resources of type MajorityNodeSet.
  1919. Arguments:
  1920. ResourceEntry - Supplies the resource entry on which to operate.
  1921. InBuffer - Supplies a pointer to a buffer containing input data.
  1922. InBufferSize - Supplies the size, in bytes, of the data pointed
  1923. to by InBuffer.
  1924. Return Value:
  1925. ERROR_SUCCESS - The function completed successfully.
  1926. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1927. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1928. Win32 error code - The function failed.
  1929. --*/
  1930. {
  1931. DWORD status = ERROR_SUCCESS;
  1932. MNS_PARAMS params;
  1933. //
  1934. // Parse the properties so they can be validated together.
  1935. // This routine does individual property validation.
  1936. //
  1937. ZeroMemory( &params, sizeof(params));
  1938. status = MajorityNodeSetValidatePrivateResProperties( ResourceEntry, InBuffer, InBufferSize, &params );
  1939. if ( status != ERROR_SUCCESS ) {
  1940. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1941. (LPBYTE) &ResourceEntry->Params,
  1942. MajorityNodeSetResourcePrivateProperties );
  1943. return(status);
  1944. }
  1945. //
  1946. // Save the parameter values.
  1947. //
  1948. status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
  1949. MajorityNodeSetResourcePrivateProperties,
  1950. NULL,
  1951. (LPBYTE) &params,
  1952. InBuffer,
  1953. InBufferSize,
  1954. (LPBYTE) &ResourceEntry->Params );
  1955. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1956. (LPBYTE) &ResourceEntry->Params,
  1957. MajorityNodeSetResourcePrivateProperties );
  1958. //
  1959. // If the resource is online, return a non-success status.
  1960. //
  1961. // TODO: Modify the code below if your resource can handle
  1962. // changes to properties while it is still online.
  1963. if ( status == ERROR_SUCCESS ) {
  1964. if ( ResourceEntry->State == ClusterResourceOnline ) {
  1965. status = ERROR_RESOURCE_PROPERTIES_STORED;
  1966. } else if ( ResourceEntry->State == ClusterResourceOnlinePending ) {
  1967. status = ERROR_RESOURCE_PROPERTIES_STORED;
  1968. } else {
  1969. status = ERROR_SUCCESS;
  1970. }
  1971. }
  1972. return status;
  1973. } // MajorityNodeSetSetPrivateResProperties
  1974. DWORD
  1975. WINAPI
  1976. MajorityNodeSetReserveThread(
  1977. PCLUS_WORKER WorkerPtr,
  1978. IN PMNS_RESOURCE ResourceEntry
  1979. )
  1980. /*++
  1981. Routine Description:
  1982. Worker function which brings a resource from the resource table online.
  1983. This function is executed in a separate thread.
  1984. Arguments:
  1985. WorkerPtr - Supplies the worker structure
  1986. ResourceEntry - A pointer to the MNS_RESOURCE block for this resource.
  1987. Returns:
  1988. ERROR_SUCCESS - The operation completed successfully.
  1989. Win32 error code - The operation failed.
  1990. --*/
  1991. {
  1992. DWORD status = ERROR_SUCCESS;
  1993. PVOID vol;
  1994. (g_LogEvent)(
  1995. ResourceEntry->ResourceHandle,
  1996. LOG_INFORMATION,
  1997. L"MNS FsReserve thread start.\n"
  1998. );
  1999. //
  2000. // todo: this should wait on a notify port and listen for
  2001. // 1- New nodes added to the cluster.
  2002. // 2- Nodes removed from the cluster.
  2003. // 3- Network priority changes.
  2004. // 4- Network binding (added, removed, state) changes.
  2005. //
  2006. // check if we are being killed
  2007. do {
  2008. if (ResourceEntry->State != ClusterResourceFailed) {
  2009. #if 0
  2010. vol=NULL;
  2011. // don't hold any locks as not to hold back an arb
  2012. EnterCriticalSection(&ResourceEntry->Lock);
  2013. // Check if arbitration is going on, then don't do this.
  2014. if (ResourceEntry->ArbThread != NULL) {
  2015. DWORD err;
  2016. err = WaitForSingleObject(ResourceEntry->ArbThread, 0);
  2017. if (err != WAIT_TIMEOUT) {
  2018. vol = ResourceEntry->VolHdl;
  2019. }
  2020. }
  2021. else {
  2022. vol = ResourceEntry->VolHdl;
  2023. }
  2024. LeaveCriticalSection(&ResourceEntry->Lock);
  2025. #else
  2026. vol = ResourceEntry->VolHdl;
  2027. WaitForArbCompletion(vol);
  2028. #endif
  2029. if (vol)
  2030. status = FsReserve(vol);
  2031. } else {
  2032. status = ERROR_INVALID_PARAMETER;
  2033. }
  2034. if (status == ERROR_SHUTDOWN_IN_PROGRESS) {
  2035. goto error_exit;
  2036. }
  2037. else if (status != ERROR_SUCCESS) {
  2038. PQUORUM_RESOURCE_LOST func;
  2039. (g_LogEvent)(
  2040. ResourceEntry->ResourceHandle,
  2041. LOG_ERROR,
  2042. L"Reserve thread failed status %1!u!, resource '%2'.\n",
  2043. status, ResourceEntry->ResourceName);
  2044. #if 0
  2045. EnterCriticalSection(&ResourceEntry->Lock);
  2046. func = ResourceEntry->LostQuorumResource;
  2047. LeaveCriticalSection(&ResourceEntry->Lock);
  2048. if (func) {
  2049. func(ResourceEntry->ResourceHandle);
  2050. }
  2051. break;
  2052. #endif
  2053. }
  2054. // Check every x seconds.
  2055. // todo: need to make this a private property
  2056. Sleep(MNS_RESERVE_PERIOD);
  2057. } while(!ClusWorkerCheckTerminate(&ResourceEntry->ReserveThread));
  2058. error_exit:
  2059. (g_LogEvent)(
  2060. ResourceEntry->ResourceHandle,
  2061. LOG_INFORMATION,
  2062. L"Reserve thread exiting, resource '%1' %2!u!.\n",ResourceEntry->ResourceName,
  2063. status);
  2064. return(status);
  2065. } // MajorityNodeSetReserveThread
  2066. DWORD WINAPI MajorityNodeSetArbitrate(
  2067. RESID ResourceId,
  2068. PQUORUM_RESOURCE_LOST LostQuorumResource
  2069. )
  2070. /*++
  2071. Routine Description:
  2072. Perform full arbitration for a disk. Once arbitration has succeeded,
  2073. a thread is started that will keep reservations on the disk, one per second.
  2074. Arguments:
  2075. DiskResource - the disk info structure for the disk.
  2076. Return Value:
  2077. ERROR_SUCCESS if successful.
  2078. A Win32 error code on failure.
  2079. --*/
  2080. {
  2081. DWORD status=ERROR_SUCCESS;
  2082. PMNS_RESOURCE ResourceEntry;
  2083. PVOID arb;
  2084. HANDLE Cleanup;
  2085. ResourceEntry = (PMNS_RESOURCE)ResourceId;
  2086. if ( ResourceEntry == NULL ) {
  2087. return(FALSE);
  2088. }
  2089. if ( ResourceEntry->ResId != ResourceId ) {
  2090. (g_LogEvent)(
  2091. ResourceEntry->ResourceHandle,
  2092. LOG_ERROR,
  2093. L"IsAlive sanity check failed! ResourceId = %1!u!.\n",
  2094. ResourceId );
  2095. return(FALSE);
  2096. }
  2097. (g_LogEvent)(
  2098. ResourceEntry->ResourceHandle,
  2099. LOG_INFORMATION,
  2100. L"Arbitrate request.\n"
  2101. );
  2102. // If an arbitration is in progress wait for it to complete and directly return
  2103. // it's result. No need to rearbitrate.
  2104. //
  2105. if ((status = FsIsOnlineReadWrite(ResourceEntry->VolHdl)) == ERROR_SUCCESS) {
  2106. goto Finally;
  2107. }
  2108. else if (IsArbInProgress(ResourceEntry->VolHdl)) {
  2109. PVOID vol=ResourceEntry->VolHdl;
  2110. WaitForArbCompletion(vol);
  2111. status = FsIsOnlineReadWrite(vol);
  2112. if (status == ERROR_SUCCESS) {
  2113. goto Finally;
  2114. }
  2115. }
  2116. // Get lock
  2117. EnterCriticalSection(&ResourceEntry->Lock);
  2118. status = MajorityNodeSetDoRegister(ResourceEntry);
  2119. // If an arbitrate thread is active we need to wait for it to complete.
  2120. while (ResourceEntry->ArbThread != NULL) {
  2121. HANDLE th = ResourceEntry->ArbThread;
  2122. LeaveCriticalSection(&ResourceEntry->Lock);
  2123. WaitForSingleObject(th, INFINITE);
  2124. EnterCriticalSection(&ResourceEntry->Lock);
  2125. if (th == ResourceEntry->ArbThread) {
  2126. CloseHandle(ResourceEntry->ArbThread);
  2127. ResourceEntry->ArbThread = NULL;
  2128. }
  2129. }
  2130. if (status == ERROR_SUCCESS) {
  2131. // we wait for arbitration timeout in worse case
  2132. DWORD delta = ResourceEntry->Setup.ArbTime;
  2133. // NOTE: There might be another srbitrate thread active, but we cannot wait for that.
  2134. // FsArbitrate() routine is reentrant (hopefully).
  2135. ASSERT(ResourceEntry->VolHdl);
  2136. if((arb = FsArbitrate(ResourceEntry->VolHdl, &Cleanup, &ResourceEntry->ArbThread)) == NULL) {
  2137. status = GetLastError();
  2138. }
  2139. else {
  2140. status = FsCompleteArbitration(arb, delta);
  2141. }
  2142. }
  2143. if (status == ERROR_SUCCESS) {
  2144. (g_LogEvent)(
  2145. ResourceEntry->ResourceHandle,
  2146. LOG_INFORMATION,
  2147. L"Arb: status %1!u!.\n",
  2148. status
  2149. );
  2150. // we remember the callback and create a thread to monitor the quorum if we
  2151. // don't have one already
  2152. if (ResourceEntry->LostQuorumResource == NULL) {
  2153. status = ClusWorkerCreate( &ResourceEntry->ReserveThread,
  2154. (PWORKER_START_ROUTINE)MajorityNodeSetReserveThread,
  2155. ResourceEntry );
  2156. }
  2157. ResourceEntry->LostQuorumResource = LostQuorumResource;
  2158. if ( status != ERROR_SUCCESS ) {
  2159. (g_LogEvent)(
  2160. ResourceEntry->ResourceHandle,
  2161. LOG_ERROR,
  2162. L"Arb: Unable to start thread, status %1!u!.\n",
  2163. status
  2164. );
  2165. }
  2166. }
  2167. // Drop lock
  2168. LeaveCriticalSection(&ResourceEntry->Lock);
  2169. Finally:
  2170. (g_LogEvent)(
  2171. ResourceEntry->ResourceHandle,
  2172. LOG_INFORMATION,
  2173. L"Arbitrate request status %1!u!.\n",status);
  2174. return status;
  2175. }
  2176. DWORD
  2177. WINAPI
  2178. MajorityNodeSetRelease(
  2179. IN RESID ResourceId
  2180. )
  2181. /*++
  2182. Routine Description:
  2183. Release arbitration for a device by stopping the reservation thread.
  2184. Arguments:
  2185. Resource - supplies resource id to be brought online
  2186. Return Value:
  2187. ERROR_SUCCESS if successful.
  2188. ERROR_HOST_NODE_NOT_OWNER if the resource is not owned.
  2189. A Win32 error code if other failure.
  2190. --*/
  2191. {
  2192. DWORD status = ERROR_SUCCESS ;
  2193. PMNS_RESOURCE resourceEntry;
  2194. resourceEntry = (PMNS_RESOURCE)ResourceId;
  2195. again:
  2196. (g_LogEvent)(
  2197. resourceEntry->ResourceHandle,
  2198. LOG_INFORMATION,
  2199. L"Release request resource %1.\n",resourceEntry->ResourceName);
  2200. // Get lock
  2201. EnterCriticalSection(&resourceEntry->Lock);
  2202. // clear callback and stop thread
  2203. resourceEntry->LostQuorumResource = NULL;
  2204. // Drop lock
  2205. LeaveCriticalSection(&resourceEntry->Lock);
  2206. // kill reserve thread
  2207. ClusWorkerTerminate( &resourceEntry->ReserveThread );
  2208. // Get lock
  2209. EnterCriticalSection(&resourceEntry->Lock);
  2210. // clear callback and stop thread
  2211. if (resourceEntry->LostQuorumResource != NULL) {
  2212. // dam arb got called again
  2213. goto again;
  2214. }
  2215. // issue FsRelease
  2216. if (resourceEntry->VolHdl) {
  2217. status = FsRelease(resourceEntry->VolHdl);
  2218. if (status == ERROR_SUCCESS)
  2219. resourceEntry->VolHdl = NULL;
  2220. }
  2221. // Drop lock
  2222. LeaveCriticalSection(&resourceEntry->Lock);
  2223. (g_LogEvent)(
  2224. resourceEntry->ResourceHandle,
  2225. LOG_INFORMATION,
  2226. L"Release request status %1!u!.\n",status);
  2227. return status ;
  2228. }
  2229. DWORD
  2230. MajorityNodeSetGetDiskInfo(
  2231. IN LPWSTR lpszPath,
  2232. OUT PVOID * OutBuffer,
  2233. IN DWORD OutBufferSize,
  2234. OUT LPDWORD BytesReturned
  2235. )
  2236. /*++
  2237. Routine Description:
  2238. Gets all of the disk information for a given signature.
  2239. Arguments:
  2240. Signature - the signature of the disk to return info.
  2241. OutBuffer - pointer to the output buffer to return the data.
  2242. OutBufferSize - size of the output buffer.
  2243. BytesReturned - the actual number of bytes that were returned (or
  2244. the number of bytes that should have been returned if
  2245. OutBufferSize is too small).
  2246. Return Value:
  2247. ERROR_SUCCESS if successful.
  2248. A Win32 error on failure.
  2249. --*/
  2250. {
  2251. DWORD status;
  2252. DWORD bytesReturned = *BytesReturned;
  2253. PVOID ptrBuffer = *OutBuffer;
  2254. PCLUSPROP_DWORD ptrDword;
  2255. PCLUSPROP_PARTITION_INFO ptrPartitionInfo;
  2256. // Return the signature - a DWORD
  2257. bytesReturned += sizeof(CLUSPROP_DWORD);
  2258. if ( bytesReturned <= OutBufferSize ) {
  2259. ptrDword = (PCLUSPROP_DWORD)ptrBuffer;
  2260. ptrDword->Syntax.dw = CLUSPROP_SYNTAX_DISK_SIGNATURE;
  2261. ptrDword->cbLength = sizeof(DWORD);
  2262. ptrDword->dw = 777;//return a bogus signature for now
  2263. ptrDword++;
  2264. ptrBuffer = ptrDword;
  2265. }
  2266. status = ERROR_SUCCESS;
  2267. if (g_resHdl)
  2268. (g_LogEvent)(
  2269. g_resHdl,
  2270. LOG_INFORMATION,
  2271. L"Expanded path '%1'\n",lpszPath);
  2272. bytesReturned += sizeof(CLUSPROP_PARTITION_INFO);
  2273. if ( bytesReturned <= OutBufferSize ) {
  2274. ptrPartitionInfo = (PCLUSPROP_PARTITION_INFO) ptrBuffer;
  2275. ZeroMemory( ptrPartitionInfo, sizeof(CLUSPROP_PARTITION_INFO) );
  2276. ptrPartitionInfo->Syntax.dw = CLUSPROP_SYNTAX_PARTITION_INFO;
  2277. ptrPartitionInfo->cbLength = sizeof(CLUSPROP_PARTITION_INFO) - sizeof(CLUSPROP_VALUE);
  2278. // set flags
  2279. // ptrPartitionInfo->dwFlags = CLUSPROP_PIFLAG_STICKY;
  2280. ptrPartitionInfo->dwFlags |= CLUSPROP_PIFLAG_USABLE;
  2281. // copy device name
  2282. if (lpszPath[0] == L'\\') {
  2283. wcscpy(ptrPartitionInfo->szDeviceName, lpszPath);
  2284. wcscat(ptrPartitionInfo->szDeviceName, L"\\");
  2285. } else {
  2286. ptrPartitionInfo->szDeviceName[0] = lpszPath[0];
  2287. ptrPartitionInfo->szDeviceName[1] = L':';
  2288. ptrPartitionInfo->szDeviceName[2] = L'\\';
  2289. ptrPartitionInfo->szDeviceName[3] = L'\0';
  2290. }
  2291. #ifdef ENABLE_SMB
  2292. if ( !GetVolumeInformationW( ptrPartitionInfo->szDeviceName,
  2293. ptrPartitionInfo->szVolumeLabel,
  2294. sizeof(ptrPartitionInfo->szVolumeLabel)/sizeof(WCHAR),
  2295. &ptrPartitionInfo->dwSerialNumber,
  2296. &ptrPartitionInfo->rgdwMaximumComponentLength,
  2297. &ptrPartitionInfo->dwFileSystemFlags,
  2298. ptrPartitionInfo->szFileSystem,
  2299. sizeof(ptrPartitionInfo->szFileSystem)/sizeof(WCHAR) ) )
  2300. #endif
  2301. {
  2302. ptrPartitionInfo->szVolumeLabel[0] = L'\0';
  2303. }
  2304. //set the partition name to the path, nothing to do
  2305. if (ptrPartitionInfo->szDeviceName[0] == L'\\')
  2306. wcscpy(ptrPartitionInfo->szDeviceName, lpszPath);
  2307. else
  2308. ptrPartitionInfo->szDeviceName[2] = L'\0';
  2309. ptrPartitionInfo++;
  2310. ptrBuffer = ptrPartitionInfo;
  2311. }
  2312. //
  2313. // Check if we got what we were looking for.
  2314. //
  2315. *OutBuffer = ptrBuffer;
  2316. *BytesReturned = bytesReturned;
  2317. return(status);
  2318. } // MajorityNodeSetGetDiskInfo
  2319. VOID
  2320. MajorityNodeSetCallLostquorumCallback(PVOID arg)
  2321. {
  2322. PMNS_RESOURCE ResourceEntry=(PMNS_RESOURCE)arg;
  2323. PQUORUM_RESOURCE_LOST func;
  2324. if (!ResourceEntry) {
  2325. return;
  2326. }
  2327. (g_LogEvent)(
  2328. ResourceEntry->ResourceHandle,
  2329. LOG_ERROR,
  2330. L"Lost quorum resource '%1'.\n",
  2331. ResourceEntry->ResourceName);
  2332. EnterCriticalSection(&ResourceEntry->Lock);
  2333. func = ResourceEntry->LostQuorumResource;
  2334. LeaveCriticalSection(&ResourceEntry->Lock);
  2335. if (func) {
  2336. FsSignalShutdown(ResourceEntry->VolHdl);
  2337. func(ResourceEntry->ResourceHandle);
  2338. }
  2339. }
  2340. //***********************************************************
  2341. //
  2342. // Define Function Table
  2343. //
  2344. //***********************************************************
  2345. CLRES_V1_FUNCTION_TABLE( MajorityNodeSetFunctionTable, // Name
  2346. CLRES_VERSION_V1_00, // Version
  2347. MajorityNodeSet, // Prefix
  2348. MajorityNodeSetArbitrate, // Arbitrate
  2349. MajorityNodeSetRelease, // Release
  2350. MajorityNodeSetResourceControl, // ResControl
  2351. MajorityNodeSetResourceTypeControl); // ResTypeControl
  2352. void
  2353. msg_log(int level, char *buf, int cnt)
  2354. {
  2355. WCHAR wbuf[1024];
  2356. cnt = mbstowcs(wbuf, buf, cnt-1);
  2357. wbuf[cnt] = L'\0';
  2358. if (g_resHdl)
  2359. g_LogEvent(g_resHdl, level, L"%1\n", wbuf);
  2360. }
  2361. void
  2362. WINAPI
  2363. debug_log(char *format, ...)
  2364. {
  2365. va_list marker;
  2366. char buf[1024];
  2367. int cnt;
  2368. va_start(marker, format);
  2369. cnt = vsprintf(buf, format, marker);
  2370. msg_log(LOG_INFORMATION, buf, cnt);
  2371. va_end(marker);
  2372. }
  2373. void
  2374. WINAPI
  2375. error_log(char *format, ...)
  2376. {
  2377. va_list marker;
  2378. char buf[1024];
  2379. int cnt;
  2380. va_start(marker, format);
  2381. cnt = vsprintf(buf, format, marker);
  2382. msg_log(LOG_ERROR, buf, cnt);
  2383. va_end(marker);
  2384. }