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.

359 lines
9.4 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. rmnotify.c
  5. Abstract:
  6. Interfaces with the resource monitor to detect notification
  7. of resource state changes.
  8. Author:
  9. John Vert (jvert) 12-Jan-1996
  10. Revision History:
  11. --*/
  12. #include "fmp.h"
  13. #define LOG_MODULE RMNOTIFY
  14. //
  15. // Local Data
  16. //
  17. CL_QUEUE NotifyQueue;
  18. HANDLE RmNotifyThread;
  19. //
  20. // Local Functions
  21. //
  22. DWORD
  23. FmpRmWorkerThread(
  24. IN LPVOID lpThreadParameter
  25. );
  26. VOID
  27. FmpRmWorkItemHandler(
  28. IN PCLRTL_WORK_ITEM WorkItem,
  29. IN DWORD Ignored1,
  30. IN DWORD Ignored2,
  31. IN ULONG_PTR Ignored3
  32. );
  33. DWORD
  34. FmpInitializeNotify(
  35. VOID
  36. )
  37. /*++
  38. Routine Description:
  39. Initialization routine for notification engine
  40. Arguments:
  41. None.
  42. Return Value:
  43. ERROR_SUCCESS if successful
  44. Win32 error code otherwise.
  45. --*/
  46. {
  47. DWORD ThreadId;
  48. DWORD Status;
  49. Status = ClRtlInitializeQueue(&NotifyQueue);
  50. if (Status != ERROR_SUCCESS) {
  51. CL_LOGFAILURE(Status);
  52. return(Status);
  53. }
  54. RmNotifyThread = CreateThread(NULL,
  55. 0,
  56. FmpRmWorkerThread,
  57. NULL,
  58. 0,
  59. &ThreadId);
  60. if (RmNotifyThread == NULL) {
  61. CsInconsistencyHalt(GetLastError());
  62. }
  63. return(ERROR_SUCCESS);
  64. }
  65. DWORD
  66. FmpRmWorkerThread(
  67. IN LPVOID lpThreadParameter
  68. )
  69. /*++
  70. Routine Description:
  71. This thread processes deferred Resource Monitor events.
  72. Arguments:
  73. lpThreadParameter - not used.
  74. Return Value:
  75. None.
  76. --*/
  77. {
  78. DWORD status = ERROR_SUCCESS;
  79. PRM_EVENT event;
  80. PLIST_ENTRY entry;
  81. while (TRUE)
  82. {
  83. entry = ClRtlRemoveHeadQueue(&NotifyQueue);
  84. if ( entry == NULL ) {
  85. break;
  86. }
  87. event = CONTAINING_RECORD(entry,
  88. RM_EVENT,
  89. Linkage);
  90. if (event->EventType == RmWorkerTerminate)
  91. {
  92. LocalFree(event);
  93. break;
  94. }
  95. status = FmpRmDoHandleCriticalResourceStateChange( event,
  96. NULL,
  97. event->Parameters.ResourceTransition.NewState);
  98. LocalFree(event);
  99. if (status != ERROR_SUCCESS)
  100. {
  101. break;
  102. }
  103. }
  104. return(status);
  105. }
  106. BOOL
  107. FmpPostNotification(
  108. IN RM_NOTIFY_KEY NotifyKey,
  109. IN DWORD NotifyEvent,
  110. IN CLUSTER_RESOURCE_STATE CurrentState
  111. )
  112. /*++
  113. Routine Description:
  114. Callback routine used by resource monitor for resource state
  115. change notification. This routine queues the notification to
  116. a worker thread for deferred processing.
  117. Arguments:
  118. NotifyKey - Supplies the notification key for the resource
  119. that changed
  120. NotifyEvent - The event type.
  121. CurrentState - Supplies the (new) current state of the resource
  122. Return Value:
  123. TRUE - continue receiving notifications
  124. FALSE - abort notifications
  125. --*/
  126. {
  127. PRM_EVENT event;
  128. event = LocalAlloc(LMEM_FIXED, sizeof(RM_EVENT));
  129. if (event != NULL) {
  130. ClRtlLogPrint(LOG_NOISE,
  131. "[FM] NotifyCallBackRoutine: enqueuing event\n");
  132. event->EventType = NotifyEvent;
  133. event->Parameters.ResourceTransition.NotifyKey = NotifyKey;
  134. event->Parameters.ResourceTransition.NewState = CurrentState;
  135. //
  136. // Enqueue the event for the worker thread.
  137. //
  138. ClRtlInsertTailQueue(&NotifyQueue, &event->Linkage);
  139. } else {
  140. ClRtlLogPrint(LOG_UNUSUAL, "[FM] NotifyCallBackRoutine: Unable to post item, memory alloc failure %1!u!\n",
  141. GetLastError());
  142. }
  143. return(TRUE);
  144. }
  145. DWORD
  146. FmpRmDoHandleCriticalResourceStateChange(
  147. IN PRM_EVENT pEvent,
  148. IN OPTIONAL PFM_RESOURCE pTransitionedResource,
  149. IN CLUSTER_RESOURCE_STATE NewState
  150. )
  151. /*++
  152. Routine Description:
  153. Does an interlocked decrement of the gdwQuoBlockingResources variable.
  154. Handle the transition of the quorum resource state via a separate
  155. thread.
  156. Arguments:
  157. pEvent - The Resource Monitor Event
  158. pTransitionedResource - The resource whose state has changed.
  159. NewState - New state of the resource.
  160. Return Value:
  161. ERROR_SUCCESS on success, a Win32 error code otherwise.
  162. Comments:
  163. DO NOT hold any locks (such as group lock, gQuoChangeLock, etc.)
  164. in this function. You could deadlock the system quite easily.
  165. --*/
  166. {
  167. RM_NOTIFY_KEY NotifyKey;
  168. DWORD dwOldBlockingFlag;
  169. PFM_RESOURCE pResource = pTransitionedResource;
  170. DWORD status = ERROR_SUCCESS;
  171. //
  172. // Chittur Subbaraman (chitturs) - 4/19/99
  173. //
  174. // This function decrements the blocking resources count when the
  175. // resource state has stabilized. It is important to do this
  176. // decrement in a non-blocking mode so that the quorum resource
  177. // does not get caught forever waiting for this count to go down to
  178. // zero in the offline call, FmpRmOfflineResource. This code was
  179. // originally located in FmpHandleResourceTransition and was moved
  180. // here since you could run out of FmpRmWorkItemHandler threads
  181. // (which service the CsDelayedWorkQueue) since all of them could
  182. // get blocked on the local resource lock in
  183. // FmpHandleResourceTransition and consequently any new notifications
  184. // from resmon which could potentially decrement this count will
  185. // not get serviced.
  186. //
  187. if ( !ARGUMENT_PRESENT ( pTransitionedResource ) )
  188. {
  189. //SS: have no idea what this was for, but only do this check if pEvent is passed in
  190. if (pEvent)
  191. {
  192. NotifyKey = pEvent->Parameters.ResourceResuscitate.NotifyKey;
  193. pResource = FmpFindResourceByNotifyKey(
  194. NotifyKey
  195. );
  196. if ( pResource == NULL ) {
  197. ClRtlLogPrint(LOG_UNUSUAL,
  198. "[FM] FmpRmDoHandleCriticalResourceStateChange, bad resource NotifyKey %1!u!\n",
  199. NotifyKey);
  200. goto FnExit;
  201. }
  202. if ( pEvent->EventType != ResourceTransition )
  203. {
  204. goto FnExit;
  205. }
  206. }
  207. }
  208. if ( pResource->QuorumResource )
  209. {
  210. //
  211. // Chittur Subbaraman (chitturs) - 6/25/99
  212. //
  213. // If this resource is the quorum resource, then let
  214. // FmpHandleResourceTransition take care of the sync notifications.
  215. // Note that this function only does the notifications for the
  216. // non-quorum resources as well as does the decrement on the
  217. // blocking resources count. The decrement MUST be done
  218. // without holding any locks to avoid potential deadlocks with
  219. // the quorum resource offline getting stuck in FmpRmOfflineResource
  220. // waiting for the blocking resources count to go to 0.
  221. // As far as the quorum resource goes, the sync notifications
  222. // must be done with gQuoChangeLock held since we want to
  223. // synchronize with other threads such as the FmCheckQuorumState
  224. // called by the DM node down handler. FmpHandleResourceTransition
  225. // does hold the gQuoChangeLock.
  226. //
  227. // Note also that for the quorum resource a separate thread
  228. // handles the resource transition since if we depend on the
  229. // worker threads servicing the CsDelayedWorkQueue to do this,
  230. // this notification could be starved from being processed since
  231. // some thread could hold the group lock and be stuck in the
  232. // resource onlining waiting for the quorum resource to go
  233. // online and all the worker threads servicing the CsDelayedWorkQueue
  234. // could be blocked on the group lock preventing the propagation
  235. // of the quorum resource state.
  236. //
  237. FmpCreateResStateChangeHandler( pResource, NewState, pResource->State );
  238. goto FnExit;
  239. }
  240. //
  241. // Comments from sunitas: Call the synchronous notifications.
  242. // This is done before the count is decremented as the synchronous
  243. // callbacks like the registry replication must get a chance to
  244. // finish before the quorum resource state is allowed to change.
  245. //
  246. // Note, there is no synchronization here with the resmon's
  247. // online/offline code. They are using the LocalResourceLocks.
  248. //
  249. FmpCallResourceNotifyCb( pResource, NewState );
  250. dwOldBlockingFlag = InterlockedExchange( &pResource->BlockingQuorum, 0 );
  251. if ( dwOldBlockingFlag ) {
  252. ClRtlLogPrint(LOG_NOISE,
  253. "[FM] FmpRmDoHandleCriticalResourceStateChange: call InterlockedDecrement on gdwQuoBlockingResources, Resource %1!ws!\n",
  254. OmObjectId(pResource));
  255. InterlockedDecrement( &gdwQuoBlockingResources );
  256. }
  257. //post a work item to the fm worker thread to handle the rest
  258. OmReferenceObject(pResource);
  259. FmpPostWorkItem(FM_EVENT_RES_RESOURCE_TRANSITION,
  260. pResource,
  261. NewState);
  262. FnExit:
  263. return( status );
  264. }