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.

437 lines
13 KiB

  1. /*++
  2. Copyright (c) 1989 - 1999 Microsoft Corporation
  3. Module Name:
  4. recursvc.c
  5. Abstract:
  6. This module implements the recurrent services in the mini rdr. These are services that
  7. are not triggered as a response to some request from the wrapper, they are autonomous
  8. services that aid in the functioning of the mini redirector.
  9. Scavenging -- The construction of the SMB mini redirector counterparts to SRV_CALL,
  10. NET_ROOT and V_NET_ROOT involve network traffic. Therefore the SMB mini redirector
  11. introduces a hystersis between the deletion of the data structures by the wrapper and
  12. effecting those changes in the mini redirector data structures and the remote server.
  13. This is done by transitioning the deleted data structures to a dormant state and
  14. scavenging them after a suitable interval( approximately 45 sec).
  15. Probing Servers -- Sometimes the server response to a client request is delayed. The
  16. mini redirector has a probing mechanism which enables it to cope with overloaded
  17. servers. When a response is not forthcoming from a server it sends it an ECHO SMB.
  18. Since the server can respond to an ECHO SMB without having to commit many resources,
  19. a reply to the ECHO SMB is interpreted as a sign that the server is indeed alive and
  20. well.
  21. Notes:
  22. A recurrent service can be either periodic or aperiodic. The periodic services are
  23. triggered at regular time intervals. These services then perform some tasks if
  24. required. The advantage of having periodic recurrent services is the guarantee that
  25. work will get done and the disadvantage is that it consumes system resources when
  26. there is no work to be done. Also if the handling time happens to straddle the
  27. service time period multiple threads wil
  28. An aperiodic recurrent service is a one shot mechanism. The service once invoked gets
  29. to decide when the next invocation will be. The advantage of such services is that
  30. it provides an inbuilt throttling mechanism.
  31. --*/
  32. #include "precomp.h"
  33. #pragma hdrstop
  34. #ifdef ALLOC_PRAGMA
  35. #pragma alloc_text(PAGE, MRxSmbInitializeRecurrentService)
  36. #pragma alloc_text(PAGE, MRxSmbCancelRecurrentService)
  37. #pragma alloc_text(PAGE, MRxSmbActivateRecurrentService)
  38. #pragma alloc_text(PAGE, MRxSmbInitializeRecurrentServices)
  39. #pragma alloc_text(PAGE, MRxSmbTearDownRecurrentServices)
  40. #pragma alloc_text(PAGE, MRxSmbInitializeScavengerService)
  41. #pragma alloc_text(PAGE, MRxSmbTearDownScavengerService)
  42. #endif
  43. MRXSMB_ECHO_PROBE_SERVICE_CONTEXT MRxSmbEchoProbeServiceContext;
  44. MRXSMB_SCAVENGER_SERVICE_CONTEXT MRxSmbScavengerServiceContext;
  45. extern VOID
  46. MRxSmbRecurrentServiceDispatcher(
  47. PVOID pContext);
  48. VOID
  49. MRxSmbInitializeRecurrentService(
  50. PRECURRENT_SERVICE_CONTEXT pRecurrentServiceContext,
  51. PRECURRENT_SERVICE_ROUTINE pServiceRoutine,
  52. PVOID pServiceRoutineParameter,
  53. PLARGE_INTEGER pTimeInterval)
  54. /*++
  55. Routine Description:
  56. This routine initializes a recurrent service
  57. Arguments:
  58. pRecurrentServiceContext - the recurrent service to be initialized
  59. pServiceRoutine - the recurrent service routine
  60. pServiceRoutineParameter - the recurrent service routine parameter
  61. pTimeInterval - the time interval which controls the frequency of the recurrent
  62. service
  63. --*/
  64. {
  65. NTSTATUS Status;
  66. PAGED_CODE();
  67. pRecurrentServiceContext->State = RECURRENT_SERVICE_DORMANT;
  68. pRecurrentServiceContext->pServiceRoutine = pServiceRoutine;
  69. pRecurrentServiceContext->pServiceRoutineParameter = pServiceRoutineParameter;
  70. pRecurrentServiceContext->Interval.QuadPart = pTimeInterval->QuadPart;
  71. // Initialize the cancel completion event associated with the service
  72. KeInitializeEvent(
  73. &pRecurrentServiceContext->CancelCompletionEvent,
  74. NotificationEvent,
  75. FALSE);
  76. }
  77. VOID
  78. MRxSmbCancelRecurrentService(
  79. PRECURRENT_SERVICE_CONTEXT pRecurrentServiceContext)
  80. /*++
  81. Routine Description:
  82. This routine cancels a recurrent service
  83. Arguments:
  84. pRecurrentServiceContext - the recurrent service to be initialized
  85. Notes:
  86. When the cancel request is handled the recurrent service can be in one
  87. of two states -- either active or on the timer queue awaiting dispatch.
  88. The service state is changed and an attempt is made to cancel the service
  89. in the timer queue and if it fails this request is suspended till the
  90. active invocation of the service is completed
  91. --*/
  92. {
  93. NTSTATUS Status;
  94. LONG State;
  95. PAGED_CODE();
  96. State = InterlockedCompareExchange(
  97. &pRecurrentServiceContext->State,
  98. RECURRENT_SERVICE_CANCELLED,
  99. RECURRENT_SERVICE_ACTIVE);
  100. if (State == RECURRENT_SERVICE_ACTIVE) {
  101. // Cancel the echo processing timer request.
  102. Status = RxCancelTimerRequest(
  103. MRxSmbDeviceObject,
  104. MRxSmbRecurrentServiceDispatcher,
  105. pRecurrentServiceContext);
  106. if (Status != STATUS_SUCCESS) {
  107. // The request is currently active. Wait for it to be completed.
  108. KeWaitForSingleObject(
  109. &pRecurrentServiceContext->CancelCompletionEvent,
  110. Executive,
  111. KernelMode,
  112. FALSE,
  113. NULL);
  114. }
  115. }
  116. }
  117. VOID
  118. MRxSmbRecurrentServiceDispatcher(
  119. PVOID pContext)
  120. /*++
  121. Routine Description:
  122. This routine dispatches the recurrent service
  123. Arguments:
  124. pRecurrentServiceContext - the recurrent service to be initialized
  125. Notes:
  126. The dispatcher provides a centralized location for monitoring the state
  127. of the recurrent service prior to and after invocation. Based on the
  128. state a decision as to whether a subsequent request must be posted
  129. is made.
  130. --*/
  131. {
  132. NTSTATUS Status;
  133. PRECURRENT_SERVICE_CONTEXT pRecurrentServiceContext;
  134. LONG State;
  135. pRecurrentServiceContext = (PRECURRENT_SERVICE_CONTEXT)pContext;
  136. State = InterlockedCompareExchange(
  137. &pRecurrentServiceContext->State,
  138. RECURRENT_SERVICE_ACTIVE,
  139. RECURRENT_SERVICE_ACTIVE);
  140. // If the state of the service is active invoke the handler
  141. if (State == RECURRENT_SERVICE_ACTIVE) {
  142. Status = (pRecurrentServiceContext->pServiceRoutine)(
  143. pRecurrentServiceContext->pServiceRoutineParameter);
  144. State = InterlockedCompareExchange(
  145. &pRecurrentServiceContext->State,
  146. RECURRENT_SERVICE_ACTIVE,
  147. RECURRENT_SERVICE_ACTIVE);
  148. if (State == RECURRENT_SERVICE_ACTIVE) {
  149. // If the service is still active and further continuation
  150. // was desired by the handler post another timer request
  151. if (Status == STATUS_SUCCESS) {
  152. Status = RxPostOneShotTimerRequest(
  153. MRxSmbDeviceObject,
  154. &pRecurrentServiceContext->WorkItem,
  155. MRxSmbRecurrentServiceDispatcher,
  156. pRecurrentServiceContext,
  157. pRecurrentServiceContext->Interval);
  158. } else {
  159. do {
  160. State = InterlockedCompareExchange(
  161. &pRecurrentServiceContext->State,
  162. RECURRENT_SERVICE_DORMANT,
  163. State);
  164. } while (State != RECURRENT_SERVICE_DORMANT);
  165. }
  166. }
  167. }
  168. if (State == RECURRENT_SERVICE_CANCELLED) {
  169. // if the recurrent service was cancelled resume the cancel request
  170. KeSetEvent(
  171. &pRecurrentServiceContext->CancelCompletionEvent,
  172. 0,
  173. FALSE );
  174. }
  175. }
  176. NTSTATUS
  177. MRxSmbActivateRecurrentService(
  178. PRECURRENT_SERVICE_CONTEXT pRecurrentServiceContext)
  179. /*++
  180. Routine Description:
  181. This routine activates a recurrent service
  182. Arguments:
  183. pRecurrentServiceContext - the recurrent service to be initialized
  184. Notes:
  185. --*/
  186. {
  187. NTSTATUS Status;
  188. LONG State;
  189. PAGED_CODE();
  190. State = InterlockedCompareExchange(
  191. &pRecurrentServiceContext->State,
  192. RECURRENT_SERVICE_ACTIVE,
  193. RECURRENT_SERVICE_DORMANT);
  194. if (State == RECURRENT_SERVICE_DORMANT) {
  195. Status = RxPostOneShotTimerRequest(
  196. MRxSmbDeviceObject,
  197. &pRecurrentServiceContext->WorkItem,
  198. MRxSmbRecurrentServiceDispatcher,
  199. pRecurrentServiceContext,
  200. pRecurrentServiceContext->Interval);
  201. } else if (State == RECURRENT_SERVICE_ACTIVE) {
  202. Status = STATUS_SUCCESS;
  203. } else if (State == RECURRENT_SERVICE_CANCELLED) {
  204. Status = STATUS_CANCELLED;
  205. }
  206. else if (State == RECURRENT_SERVICE_SHUTDOWN) {
  207. Status = STATUS_UNSUCCESSFUL;
  208. } else {
  209. ASSERT(!"Valid State for Recurrent Service");
  210. Status = STATUS_UNSUCCESSFUL;
  211. }
  212. return Status;
  213. }
  214. NTSTATUS
  215. MRxSmbInitializeRecurrentServices()
  216. /*++
  217. Routine Description:
  218. This routine initializes all the recurrent services associated with the SMB
  219. mini redirector
  220. Notes:
  221. --*/
  222. {
  223. NTSTATUS Status;
  224. LARGE_INTEGER RecurrentServiceInterval;
  225. BOOLEAN fEchoProbeServiceInitialized = FALSE;
  226. BOOLEAN fScavengerServiceInitialized = FALSE;
  227. PAGED_CODE();
  228. try {
  229. RecurrentServiceInterval.QuadPart = 30 * 1000 * 10000; // 30 seconds in 100 ns intervals
  230. MRxSmbInitializeRecurrentService(
  231. &MRxSmbEchoProbeServiceContext.RecurrentServiceContext,
  232. SmbCeProbeServers,
  233. &MRxSmbEchoProbeServiceContext,
  234. &RecurrentServiceInterval);
  235. Status = MRxSmbInitializeEchoProbeService(
  236. &MRxSmbEchoProbeServiceContext);
  237. if (Status == STATUS_SUCCESS) {
  238. fEchoProbeServiceInitialized = TRUE;
  239. Status = MRxSmbActivateRecurrentService(
  240. &MRxSmbEchoProbeServiceContext.RecurrentServiceContext);
  241. }
  242. if (Status != STATUS_SUCCESS) {
  243. try_return(Status);
  244. }
  245. MRxSmbInitializeRecurrentService(
  246. &MRxSmbScavengerServiceContext.RecurrentServiceContext,
  247. SmbCeScavenger,
  248. &MRxSmbScavengerServiceContext,
  249. &RecurrentServiceInterval);
  250. Status = MRxSmbInitializeScavengerService(
  251. &MRxSmbScavengerServiceContext);
  252. if (Status == STATUS_SUCCESS) {
  253. fScavengerServiceInitialized = TRUE;
  254. }
  255. try_exit: NOTHING;
  256. } finally {
  257. if (Status != STATUS_SUCCESS) {
  258. if (fEchoProbeServiceInitialized) {
  259. SmbCeLog(("Tearing down Echo Probe Service\n"));
  260. MRxSmbTearDownEchoProbeService(
  261. &MRxSmbEchoProbeServiceContext);
  262. }
  263. }
  264. };
  265. return Status;
  266. }
  267. VOID
  268. MRxSmbTearDownRecurrentServices()
  269. /*++
  270. Routine Description:
  271. This routine tears down the recurrent services associated with the
  272. SMB mini redirector
  273. Notes:
  274. --*/
  275. {
  276. PAGED_CODE();
  277. MRxSmbCancelRecurrentService(
  278. &MRxSmbEchoProbeServiceContext.RecurrentServiceContext);
  279. MRxSmbEchoProbeServiceContext.RecurrentServiceContext.State = RECURRENT_SERVICE_SHUTDOWN;
  280. MRxSmbTearDownEchoProbeService(
  281. &MRxSmbEchoProbeServiceContext);
  282. MRxSmbCancelRecurrentService(
  283. &MRxSmbScavengerServiceContext.RecurrentServiceContext);
  284. MRxSmbScavengerServiceContext.RecurrentServiceContext.State = RECURRENT_SERVICE_SHUTDOWN;
  285. MRxSmbTearDownScavengerService(
  286. &MRxSmbScavengerServiceContext);
  287. }
  288. NTSTATUS
  289. MRxSmbInitializeScavengerService(
  290. PMRXSMB_SCAVENGER_SERVICE_CONTEXT pScavengerServiceContext)
  291. /*++
  292. Routine Description:
  293. This routine initializes the scavenger recurrent service
  294. Arguments:
  295. pScavengerServiceContext - the recurrent service to be initialized
  296. Notes:
  297. --*/
  298. {
  299. PAGED_CODE();
  300. InitializeListHead(
  301. &pScavengerServiceContext->VNetRootContexts.ListHead);
  302. return STATUS_SUCCESS;
  303. }
  304. VOID
  305. MRxSmbTearDownScavengerService(
  306. PMRXSMB_SCAVENGER_SERVICE_CONTEXT pScavengerServiceContext)
  307. /*++
  308. Routine Description:
  309. This routine tears down the scavenger recurrent service
  310. Arguments:
  311. pScavengerServiceContext - the recurrent service to be initialized
  312. Notes:
  313. --*/
  314. {
  315. PAGED_CODE();
  316. SmbCeScavenger(pScavengerServiceContext);
  317. }