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.

448 lines
13 KiB

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