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.

604 lines
16 KiB

  1. /***********
  2. //joejoe
  3. Joelinn 2-13-95
  4. This is the pits......i have to pull in the browser in order to be started form
  5. the lanman network provider DLL. the browser should be moved elsewhere........
  6. **********************/
  7. /*++
  8. Copyright (c) 1993 Microsoft Corporation
  9. Module Name:
  10. disccode.c
  11. Abstract:
  12. This module contains the code to manage the NT redirectors discardable
  13. code sections.
  14. Author:
  15. Larry Osterman (larryo) 12-Nov-1993
  16. Environment:
  17. Kernel mode.
  18. Revision History:
  19. 12-Nov-1993
  20. Created
  21. --*/
  22. //
  23. // Include modules
  24. //
  25. #include "precomp.h"
  26. #pragma hdrstop
  27. #include <ntbowsif.h>
  28. //
  29. // The Bug check file id for this module
  30. //
  31. #define BugCheckFileId (RDBSS_BUG_CHECK_NTBOWSIF)
  32. //
  33. // The local debug trace level
  34. //
  35. #define Dbg (DEBUG_TRACE_DISCCODE)
  36. BOOLEAN DiscCodeInitialized = FALSE;
  37. VOID
  38. RdrDiscardableCodeRoutine(
  39. IN PVOID Context
  40. );
  41. #ifdef ALLOC_PRAGMA
  42. #pragma alloc_text(PAGE, RdrReferenceDiscardableCode)
  43. #pragma alloc_text(PAGE, RdrDereferenceDiscardableCode)
  44. #pragma alloc_text(PAGE, RdrDiscardableCodeRoutine)
  45. #pragma alloc_text(INIT, RdrInitializeDiscardableCode)
  46. #pragma alloc_text(PAGE, RdrUninitializeDiscardableCode)
  47. #endif
  48. //
  49. // These 7 variables maintain the state needed to manage the redirector
  50. // discardable code section.
  51. //
  52. // The redirector discardable code section is referenced via a call to
  53. // RdrReferenceDiscardableCodeSection, and dereferenced via a call to
  54. // RdrDereferenceDiscardableCodeSection.
  55. //
  56. // If the discardable code section is already mapped into memory, then
  57. // referencing the discardable code section is extremely quick.
  58. //
  59. // When the reference count on the discardable code section drops to 0, a
  60. // timer is set that will actually perform the work needed to uninitalize the
  61. // section. This means that if the reference count goes from 0 to 1 to 0
  62. // frequently, we won't thrash inside MmLockPagableCodeSection.
  63. //
  64. #define POOL_DISCTIMER 'wbxR'
  65. ERESOURCE
  66. RdrDiscardableCodeLock = {0};
  67. ULONG
  68. RdrDiscardableCodeTimeout = 10;
  69. RDR_SECTION
  70. RdrSectionInfo[RdrMaxDiscardableSection] = {0};
  71. extern
  72. PVOID
  73. BowserAllocateViewBuffer(VOID);
  74. extern
  75. VOID
  76. BowserNetlogonCopyMessage(int,int);
  77. VOID
  78. RdrReferenceDiscardableCode(
  79. DISCARDABLE_SECTION_NAME SectionName
  80. )
  81. /*++
  82. Routine Description:
  83. RdrReferenceDiscardableCode is called to reference the redirectors
  84. discardable code section.
  85. If the section is not present in memory, MmLockPagableCodeSection is
  86. called to fault the section into memory.
  87. Arguments:
  88. None.
  89. Return Value:
  90. None.
  91. --*/
  92. {
  93. #if DBG
  94. PVOID caller, callersCaller;
  95. #endif
  96. PRDR_SECTION Section = &RdrSectionInfo[SectionName];
  97. PAGED_CODE();
  98. ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
  99. ASSERT( DiscCodeInitialized );
  100. #if DBG
  101. RtlGetCallersAddress(&caller, &callersCaller);
  102. //dprintf(DPRT_DISCCODE, (" RdrReferenceDiscardableCode: %ld: Caller: %lx, Callers Caller: %lx\n", SectionName, caller, callersCaller));
  103. RxDbgTrace(0, Dbg, (" RdrReferenceDiscardableCode: %ld: Caller: %lx, Callers Caller: %lx\n",
  104. SectionName, caller, callersCaller ));
  105. #endif
  106. //
  107. // If the reference count is already non zero, just increment it and
  108. // return.
  109. //
  110. if (Section->ReferenceCount) {
  111. Section->ReferenceCount += 1;
  112. //dprintf(DPRT_DISCCODE, (" RdrReferenceDiscardableCode: %d: Early out, Refcount now %ld\n", SectionName, Section->ReferenceCount));
  113. RxDbgTrace(0, Dbg, (" RdrReferenceDiscardableCode: %d: Early out, Refcount now %ld\n",
  114. SectionName, Section->ReferenceCount ));
  115. //
  116. // Wait for the pages to be faulted in.
  117. //
  118. ExReleaseResource(&RdrDiscardableCodeLock);
  119. return;
  120. }
  121. Section->ReferenceCount += 1;
  122. //
  123. // Cancel the timer, if it is running, we won't be discarding the code
  124. // at this time.
  125. //
  126. // If the cancel timer fails, this is not a problem, since we will be
  127. // bumping a reference count in the MmLockPagableCodeSection, so when
  128. // the timer actually runs and the call to MmUnlockPagableImageSection
  129. // is called, we will simply unlock it.
  130. //
  131. if (Section->Timer != NULL) {
  132. Section->TimerCancelled = TRUE;
  133. if (KeCancelTimer(Section->Timer)) {
  134. //
  135. // Free the timer and DPC, they aren't going to fire anymore.
  136. //
  137. RxFreePool(Section->Timer);
  138. Section->Timer = NULL;
  139. //
  140. // Set the active event to the signalled state, since we're
  141. // done canceling the timer.
  142. //
  143. KeSetEvent(&Section->TimerDoneEvent, 0, FALSE);
  144. } else {
  145. //
  146. // The timer was active, and we weren't able to cancel it.
  147. // But we marked it for cancellation, and the timer routine
  148. // will recognize this and leave the section locked.
  149. //
  150. }
  151. }
  152. //
  153. // If the discardable code section is still locked, then we're done,
  154. // and we can return right away.
  155. //
  156. if (Section->Locked) {
  157. //dprintf(DPRT_DISCCODE, (" RdrReferenceDiscardableCode: %d: Already locked, Refcount now %ld\n", SectionName, Section->ReferenceCount));
  158. RxDbgTrace(0, Dbg, (" RdrReferenceDiscardableCode: %d: Already locked, Refcount now %ld\n",
  159. SectionName, Section->ReferenceCount ));
  160. ExReleaseResource(&RdrDiscardableCodeLock);
  161. return;
  162. }
  163. ASSERT (Section->CodeHandle == NULL);
  164. ASSERT (Section->DataHandle == NULL);
  165. //
  166. // Lock down the pagable image section.
  167. //
  168. //dprintf(DPRT_DISCCODE, (" RdrReferenceDiscardableCode: %d: Lock, Refcount now %ld\n", SectionName, Section->ReferenceCount));
  169. RxDbgTrace(0, Dbg, (" RdrReferenceDiscardableCode: %d: Lock, Refcount now %ld\n",
  170. SectionName, Section->ReferenceCount ));
  171. if (Section->CodeBase != NULL) {
  172. Section->CodeHandle = MmLockPagableCodeSection(Section->CodeBase);
  173. ASSERT (Section->CodeHandle != NULL);
  174. }
  175. if (Section->DataBase != NULL) {
  176. Section->DataHandle = MmLockPagableDataSection(Section->DataBase);
  177. ASSERT (Section->DataHandle != NULL);
  178. }
  179. Section->Locked = TRUE;
  180. ExReleaseResource(&RdrDiscardableCodeLock);
  181. }
  182. VOID
  183. RdrDiscardableCodeDpcRoutine(
  184. IN PKDPC Dpc,
  185. IN PVOID Context,
  186. IN PVOID SystemArgument1,
  187. IN PVOID SystemArgument2
  188. )
  189. /*++
  190. Routine Description:
  191. This routine is called when the timeout expires. It is called at Dpc level
  192. to queue a WorkItem to a system worker thread.
  193. Arguments:
  194. IN PKDPC Dpc,
  195. IN PVOID Context,
  196. IN PVOID SystemArgument1,
  197. IN PVOID SystemArgument2
  198. Return Value
  199. None.
  200. --*/
  201. {
  202. PWORK_QUEUE_ITEM discardableWorkItem = Context;
  203. ExQueueWorkItem(discardableWorkItem, CriticalWorkQueue);
  204. UNREFERENCED_PARAMETER(Dpc);
  205. UNREFERENCED_PARAMETER(SystemArgument1);
  206. UNREFERENCED_PARAMETER(SystemArgument2);
  207. }
  208. VOID
  209. RdrDiscardableCodeRoutine(
  210. IN PVOID Context
  211. )
  212. /*++
  213. Routine Description:
  214. RdrDiscardableCodeRoutine is called at task time after the redirector
  215. discardable code timer has fired to actually perform the unlock on the
  216. discardable code section.
  217. Arguments:
  218. Context - Ignored.
  219. Return Value:
  220. None.
  221. --*/
  222. {
  223. PRDR_SECTION Section = Context;
  224. PAGED_CODE();
  225. ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
  226. if (Section->TimerCancelled) {
  227. //
  228. // The timer was cancelled after it was scheduled to run.
  229. // Don't unlock the section.
  230. //
  231. } else if (Section->Locked) {
  232. //
  233. // The timer was not cancelled. Unlock the section.
  234. //
  235. Section->Locked = FALSE;
  236. ASSERT (Section->CodeHandle != NULL ||
  237. Section->DataHandle != NULL);
  238. //dprintf(DPRT_DISCCODE, ("RDR: Unlock %x\n", Section));
  239. RxDbgTrace(0,Dbg,("RDR: Unlock %x\n", Section));
  240. if (Section->CodeHandle != NULL) {
  241. MmUnlockPagableImageSection(Section->CodeHandle);
  242. Section->CodeHandle = NULL;
  243. }
  244. if (Section->DataHandle != NULL) {
  245. MmUnlockPagableImageSection(Section->DataHandle);
  246. Section->DataHandle = NULL;
  247. }
  248. }
  249. //
  250. // Free the timer and DPC, they aren't going to fire anymore.
  251. //
  252. RxFreePool(Section->Timer);
  253. Section->Timer = NULL;
  254. ExReleaseResource(&RdrDiscardableCodeLock);
  255. KeSetEvent(&Section->TimerDoneEvent, 0, FALSE);
  256. }
  257. VOID
  258. RdrDereferenceDiscardableCode(
  259. DISCARDABLE_SECTION_NAME SectionName
  260. )
  261. /*++
  262. Routine Description:
  263. RdrDereferenceDiscardableCode is called to dereference the redirectors
  264. discardable code section.
  265. When the reference count drops to 0, a timer is set that will fire in <n>
  266. seconds, after which time the section will be unlocked.
  267. Arguments:
  268. None.
  269. Return Value:
  270. None.
  271. --*/
  272. {
  273. #if DBG
  274. PVOID caller, callersCaller;
  275. #endif
  276. PRDR_SECTION Section = &RdrSectionInfo[SectionName];
  277. LARGE_INTEGER discardableCodeTimeout;
  278. PKTIMER Timer;
  279. PKDPC Dpc;
  280. PWORK_QUEUE_ITEM WorkItem;
  281. PAGED_CODE();
  282. ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
  283. ASSERT( DiscCodeInitialized );
  284. #if DBG
  285. RtlGetCallersAddress(&caller, &callersCaller);
  286. //dprintf(DPRT_DISCCODE, ("RdrDereferenceDiscardableCode: %ld: Caller: %lx, Callers Caller: %lx\n", SectionName, caller, callersCaller));
  287. RxDbgTrace(0, Dbg,("RdrDereferenceDiscardableCode: %ld: Caller: %lx, Callers Caller: %lx\n",
  288. SectionName, caller, callersCaller ));
  289. #endif
  290. ASSERT (Section->ReferenceCount > 0);
  291. //
  292. // If the reference count is above 1, just decrement it and
  293. // return.
  294. //
  295. Section->ReferenceCount -= 1;
  296. if (Section->ReferenceCount) {
  297. //dprintf(DPRT_DISCCODE, ("RdrDereferenceDiscardableCode: %d: Early out, Refcount now %ld\n", SectionName, Section->ReferenceCount));
  298. RxDbgTrace(0, Dbg, ("RdrDereferenceDiscardableCode: %d: Early out, Refcount now %ld\n",
  299. SectionName, Section->ReferenceCount ));
  300. ExReleaseResource(&RdrDiscardableCodeLock);
  301. return;
  302. }
  303. //
  304. // If the discardable code timer is still active (which might happen if
  305. // the RdrReferenceDiscardableCode failed to cancel the timer), we just
  306. // want to bail out and let the timer do the work. It means that we
  307. // discard the code sooner, but that shouldn't be that big a deal.
  308. //
  309. if (Section->Timer != NULL) {
  310. ExReleaseResource(&RdrDiscardableCodeLock);
  311. return;
  312. }
  313. //
  314. // The reference count just went to 0, set a timer to fire in
  315. // RdrDiscardableCodeTimeout seconds. When the timer fires,
  316. // we queue a request to a worker thread and it will lock down
  317. // the pagable code.
  318. //
  319. ASSERT (Section->Timer == NULL);
  320. Timer = RxAllocatePoolWithTag(NonPagedPool,
  321. sizeof(KTIMER) + sizeof(KDPC) + sizeof(WORK_QUEUE_ITEM),
  322. POOL_DISCTIMER
  323. );
  324. if (Timer == NULL) {
  325. ExReleaseResource(&RdrDiscardableCodeLock);
  326. return;
  327. }
  328. Section->Timer = Timer;
  329. KeInitializeTimer(Timer);
  330. Dpc = (PKDPC)(Timer + 1);
  331. WorkItem = (PWORK_QUEUE_ITEM)(Dpc + 1);
  332. KeClearEvent(&Section->TimerDoneEvent);
  333. Section->TimerCancelled = FALSE;
  334. ExInitializeWorkItem(WorkItem, RdrDiscardableCodeRoutine, Section);
  335. KeInitializeDpc(Dpc, RdrDiscardableCodeDpcRoutine, WorkItem);
  336. discardableCodeTimeout.QuadPart = Int32x32To64(RdrDiscardableCodeTimeout, 1000 * -10000);
  337. KeSetTimer(Timer, discardableCodeTimeout, Dpc);
  338. //dprintf(DPRT_DISCCODE, ("RdrDereferenceDiscardableCode: %d: Set timer, Refcount now %ld\n", SectionName, Section->ReferenceCount));
  339. RxDbgTrace(0, Dbg, ("RdrDereferenceDiscardableCode: %d: Set timer, Refcount now %ld\n",
  340. SectionName, Section->ReferenceCount ));
  341. ExReleaseResource(&RdrDiscardableCodeLock);
  342. }
  343. VOID
  344. RdrInitializeDiscardableCode(
  345. VOID
  346. )
  347. {
  348. DISCARDABLE_SECTION_NAME SectionName;
  349. PRDR_SECTION Section;
  350. for (SectionName = 0, Section = &RdrSectionInfo[0];
  351. SectionName < RdrMaxDiscardableSection;
  352. SectionName += 1, Section++ ) {
  353. KeInitializeEvent(&Section->TimerDoneEvent,
  354. NotificationEvent,
  355. TRUE);
  356. }
  357. RdrSectionInfo[RdrFileDiscardableSection].CodeBase = NULL; //RdrBackOff;
  358. RdrSectionInfo[RdrFileDiscardableSection].DataBase = NULL;
  359. RdrSectionInfo[RdrVCDiscardableSection].CodeBase = NULL; //RdrTdiDisconnectHandler;
  360. RdrSectionInfo[RdrVCDiscardableSection].DataBase = NULL; //RdrSmbErrorMap;
  361. RdrSectionInfo[RdrConnectionDiscardableSection].CodeBase = NULL; //RdrReferenceServer;
  362. RdrSectionInfo[RdrConnectionDiscardableSection].DataBase = NULL;
  363. RdrSectionInfo[BowserDiscardableCodeSection].CodeBase = BowserAllocateViewBuffer;
  364. RdrSectionInfo[BowserDiscardableCodeSection].DataBase = NULL;
  365. RdrSectionInfo[BowserNetlogonDiscardableCodeSection].CodeBase = BowserNetlogonCopyMessage;
  366. RdrSectionInfo[BowserNetlogonDiscardableCodeSection].DataBase = NULL;
  367. ExInitializeResource(&RdrDiscardableCodeLock);
  368. DiscCodeInitialized = TRUE;
  369. }
  370. VOID
  371. RdrUninitializeDiscardableCode(
  372. VOID
  373. )
  374. {
  375. DISCARDABLE_SECTION_NAME SectionName;
  376. PRDR_SECTION Section;
  377. PAGED_CODE();
  378. ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
  379. DiscCodeInitialized = FALSE;
  380. for (SectionName = 0, Section = &RdrSectionInfo[0];
  381. SectionName < RdrMaxDiscardableSection;
  382. SectionName += 1, Section++ ) {
  383. //
  384. // Cancel the timer if it is running.
  385. //
  386. if (Section->Timer != NULL) {
  387. if (!KeCancelTimer(Section->Timer)) {
  388. //
  389. // The timer was active, and we weren't able to cancel it,
  390. // wait until the timer finishes firing.
  391. //
  392. ExReleaseResource(&RdrDiscardableCodeLock);
  393. KeWaitForSingleObject(&Section->TimerDoneEvent,
  394. KernelMode, Executive, FALSE, NULL);
  395. ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
  396. } else {
  397. RxFreePool(Section->Timer);
  398. Section->Timer = NULL;
  399. }
  400. }
  401. if (Section->Locked) {
  402. //
  403. // Unlock the section.
  404. //
  405. Section->Locked = FALSE;
  406. ASSERT (Section->CodeHandle != NULL ||
  407. Section->DataHandle != NULL);
  408. //dprintf(DPRT_DISCCODE, ("RDR: Uninitialize unlock %x\n", Section));
  409. RxDbgTrace(0,Dbg,("RDR: Uninitialize unlock %x\n", Section));
  410. if (Section->CodeHandle != NULL) {
  411. MmUnlockPagableImageSection(Section->CodeHandle);
  412. Section->CodeHandle = NULL;
  413. }
  414. if (Section->DataHandle != NULL) {
  415. MmUnlockPagableImageSection(Section->DataHandle);
  416. Section->DataHandle = NULL;
  417. }
  418. }
  419. }
  420. ExReleaseResource(&RdrDiscardableCodeLock);
  421. ExDeleteResource(&RdrDiscardableCodeLock);
  422. }