Source code of Windows XP (NT5)
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.

1488 lines
46 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. enabdisa.c
  5. Abstract:
  6. Enable and disable code
  7. Author:
  8. AlanWar
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "wmikmp.h"
  14. BOOLEAN
  15. WmipIsISFlagsSet(
  16. PBGUIDENTRY GuidEntry,
  17. ULONG Flags
  18. );
  19. NTSTATUS WmipDeliverWnodeToDS(
  20. CHAR ActionCode,
  21. PBDATASOURCE DataSource,
  22. PWNODE_HEADER Wnode,
  23. ULONG BufferSize
  24. );
  25. ULONG WmipSendEnableDisableRequest(
  26. UCHAR ActionCode,
  27. PBGUIDENTRY GuidEntry,
  28. BOOLEAN IsEvent,
  29. BOOLEAN IsTraceLog,
  30. ULONG64 LoggerContext
  31. );
  32. void WmipReleaseCollectionEnabled(
  33. PBGUIDENTRY GuidEntry
  34. );
  35. void WmipWaitForCollectionEnabled(
  36. PBGUIDENTRY GuidEntry
  37. );
  38. ULONG WmipSendEnableRequest(
  39. PBGUIDENTRY GuidEntry,
  40. BOOLEAN IsEvent,
  41. BOOLEAN IsTraceLog,
  42. ULONG64 LoggerContext
  43. );
  44. ULONG WmipDoDisableRequest(
  45. PBGUIDENTRY GuidEntry,
  46. BOOLEAN IsEvent,
  47. BOOLEAN IsTraceLog,
  48. ULONG64 LoggerContext,
  49. ULONG InProgressFlag
  50. );
  51. ULONG WmipSendDisableRequest(
  52. PBGUIDENTRY GuidEntry,
  53. BOOLEAN IsEvent,
  54. BOOLEAN IsTraceLog,
  55. ULONG64 LoggerContext
  56. );
  57. NTSTATUS WmipEnableCollectOrEvent(
  58. PBGUIDENTRY GuidEntry,
  59. ULONG Ioctl,
  60. BOOLEAN *RequestSent,
  61. ULONG64 LoggerContext
  62. );
  63. NTSTATUS WmipDisableCollectOrEvent(
  64. PBGUIDENTRY GuidEntry,
  65. ULONG Ioctl,
  66. ULONG64 LoggerContext
  67. );
  68. NTSTATUS WmipEnableDisableTrace(
  69. IN ULONG Ioctl,
  70. IN PWMITRACEENABLEDISABLEINFO TraceEnableInfo
  71. );
  72. #ifdef ALLOC_PRAGMA
  73. #pragma alloc_text(PAGE,WmipIsISFlagsSet)
  74. #pragma alloc_text(PAGE,WmipDeliverWnodeToDS)
  75. #pragma alloc_text(PAGE,WmipSendEnableDisableRequest)
  76. #pragma alloc_text(PAGE,WmipReleaseCollectionEnabled)
  77. #pragma alloc_text(PAGE,WmipWaitForCollectionEnabled)
  78. #pragma alloc_text(PAGE,WmipSendEnableRequest)
  79. #pragma alloc_text(PAGE,WmipDoDisableRequest)
  80. #pragma alloc_text(PAGE,WmipSendDisableRequest)
  81. #pragma alloc_text(PAGE,WmipEnableCollectOrEvent)
  82. #pragma alloc_text(PAGE,WmipDisableCollectOrEvent)
  83. #pragma alloc_text(PAGE,WmipEnableDisableTrace)
  84. #pragma alloc_text(PAGE,WmipDisableTraceProviders)
  85. #endif
  86. BOOLEAN
  87. WmipIsISFlagsSet(
  88. PBGUIDENTRY GuidEntry,
  89. ULONG Flags
  90. )
  91. /*++
  92. Routine Description:
  93. This routine determines whether any of the instance sets associated
  94. with the GuidEntry has ALL of the flags set
  95. Arguments:
  96. GuidEntry Pointer to the Guid Entry structure.
  97. Flags has flags required
  98. Return Value:
  99. --*/
  100. {
  101. PLIST_ENTRY InstanceSetList;
  102. PBINSTANCESET InstanceSet;
  103. PAGED_CODE();
  104. if (GuidEntry != NULL)
  105. {
  106. WmipEnterSMCritSection();
  107. InstanceSetList = GuidEntry->ISHead.Flink;
  108. while (InstanceSetList != &GuidEntry->ISHead)
  109. {
  110. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  111. INSTANCESET,
  112. GuidISList);
  113. if ( (InstanceSet->Flags & Flags) == Flags )
  114. {
  115. WmipLeaveSMCritSection();
  116. return (TRUE);
  117. }
  118. InstanceSetList = InstanceSetList->Flink;
  119. }
  120. WmipLeaveSMCritSection();
  121. }
  122. return (FALSE);
  123. }
  124. NTSTATUS WmipDeliverWnodeToDS(
  125. CHAR ActionCode,
  126. PBDATASOURCE DataSource,
  127. PWNODE_HEADER Wnode,
  128. ULONG BufferSize
  129. )
  130. {
  131. NTSTATUS Status;
  132. IO_STATUS_BLOCK Iosb;
  133. PWMIGUIDOBJECT GuidObject;
  134. PAGED_CODE();
  135. if (DataSource->Flags & DS_KERNEL_MODE)
  136. {
  137. //
  138. // If KM provider then send an irp
  139. //
  140. Status = WmipSendWmiIrp(ActionCode,
  141. DataSource->ProviderId,
  142. &Wnode->Guid,
  143. BufferSize,
  144. Wnode,
  145. &Iosb);
  146. } else if (DataSource->Flags & DS_USER_MODE) {
  147. //
  148. // If UM provider then send a MB message
  149. //
  150. GuidObject = DataSource->RequestObject;
  151. if (GuidObject != NULL)
  152. {
  153. Wnode->Flags |= WNODE_FLAG_INTERNAL;
  154. Wnode->ProviderId = ActionCode;
  155. Wnode->CountLost = GuidObject->Cookie;
  156. WmipEnterSMCritSection();
  157. Status = WmipWriteWnodeToObject(GuidObject,
  158. Wnode,
  159. TRUE);
  160. WmipLeaveSMCritSection();
  161. } else {
  162. Status = STATUS_SUCCESS;
  163. }
  164. } else {
  165. ASSERT(FALSE);
  166. Status = STATUS_UNSUCCESSFUL;
  167. }
  168. return(Status);
  169. }
  170. ULONG WmipSendEnableDisableRequest(
  171. UCHAR ActionCode,
  172. PBGUIDENTRY GuidEntry,
  173. BOOLEAN IsEvent,
  174. BOOLEAN IsTraceLog,
  175. ULONG64 LoggerContext
  176. )
  177. /*++
  178. Routine Description:
  179. This routine will deliver an event or collection WNODE to all data
  180. providers of a guid. This routine assumes that it is called with the
  181. SM critical section held. The routine does not hold the critical
  182. section for the duration of the call.
  183. Arguments:
  184. ActionCode is WMI_ENABLE_EVENTS, WMI_DISABLE_EVENTS,
  185. WMI_ENABLE_COLLECTION or WMI_DISABLE_COLLECTION
  186. GuidEntry is the guid entry for the guid that is being enabled/disable
  187. or collected/stop collected
  188. IsEvent is TRUE then ActionCode is to enable or disable events.
  189. If FALSE then ActionCode is to enable or disbale collecton
  190. IsTraceLog is TRUE then enable is only sent to those guids registered as
  191. being a tracelog guid
  192. LoggerContext is a logger context handle that should be placed in the
  193. HistoricalContext field of the WNODE_HEADER if IsTraceLog is TRUE.
  194. Return Value:
  195. ERROR_SUCCESS or an error code
  196. --*/
  197. {
  198. #if DBG
  199. #define AVGISPERGUID 1
  200. #else
  201. #define AVGISPERGUID 64
  202. #endif
  203. PLIST_ENTRY InstanceSetList;
  204. PBINSTANCESET InstanceSet;
  205. PBDATASOURCE DataSourceArray[AVGISPERGUID];
  206. PBDATASOURCE *DataSourceList;
  207. ULONG BufferSize;
  208. ULONG Status = 0;
  209. PWNODE_HEADER pWnode;
  210. ULONG i;
  211. PBDATASOURCE DataSource;
  212. ULONG DSCount;
  213. BOOLEAN IsEnable;
  214. ULONG IsFlags, IsUpdate;
  215. WMITRACE_NOTIFY_HEADER TraceNotifyHeader;
  216. PAGED_CODE();
  217. if (GuidEntry->Flags & GE_FLAG_INTERNAL)
  218. {
  219. //
  220. // Guids that have been unregistered and Internally defined guids
  221. // have no data source to send requests to, so just leave happily
  222. return(STATUS_SUCCESS);
  223. }
  224. IsEnable = ((ActionCode == IRP_MN_ENABLE_EVENTS) ||
  225. (ActionCode == IRP_MN_ENABLE_COLLECTION));
  226. IsFlags = IsEvent ? IS_ENABLE_EVENT : IS_ENABLE_COLLECTION;
  227. //
  228. // Determine whether this is an update call and reset the bit
  229. //
  230. IsUpdate = (GuidEntry->Flags & GE_NOTIFICATION_TRACE_UPDATE);
  231. //
  232. // First we make a list of all of the DataSources that need to be called
  233. // while we have the critical section and take a reference on them so
  234. // they don't go away after we release them. Note that the DataSource
  235. // structure will stay, but the actual data provider may in fact go away.
  236. // In this case sending the request will fail.
  237. DSCount = 0;
  238. if (GuidEntry->ISCount > AVGISPERGUID)
  239. {
  240. DataSourceList = WmipAlloc(GuidEntry->ISCount * sizeof(PBDATASOURCE));
  241. if (DataSourceList == NULL)
  242. {
  243. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: alloc failed for DataSource array in WmipSendEnableDisableRequest\n"));
  244. return(STATUS_INSUFFICIENT_RESOURCES);
  245. }
  246. } else {
  247. DataSourceList = &DataSourceArray[0];
  248. }
  249. #if DBG
  250. memset(DataSourceList, 0, GuidEntry->ISCount * sizeof(PBDATASOURCE));
  251. #endif
  252. InstanceSetList = GuidEntry->ISHead.Flink;
  253. while ((InstanceSetList != &GuidEntry->ISHead) &&
  254. (DSCount < GuidEntry->ISCount))
  255. {
  256. WmipAssert(DSCount < GuidEntry->ISCount);
  257. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  258. INSTANCESET,
  259. GuidISList);
  260. //
  261. // We send requests to those data providers that are not inprocs when
  262. // it is an event being enabled or it is collection being enabled
  263. // and they are defined to be expensive (collection needs to be
  264. // enabled)
  265. if (
  266. ( (IsTraceLog && (InstanceSet->Flags & IS_TRACED)) ||
  267. ( ! IsTraceLog && (! (InstanceSet->Flags & IS_TRACED)) &&
  268. (IsEvent || (InstanceSet->Flags & IS_EXPENSIVE))
  269. )
  270. )
  271. )
  272. {
  273. if ( (! IsEnable && (InstanceSet->Flags & IsFlags)) ||
  274. ((IsEnable && ! (InstanceSet->Flags & IsFlags)) ||
  275. (IsUpdate && IsTraceLog))
  276. )
  277. {
  278. DataSourceList[DSCount] = InstanceSet->DataSource;
  279. WmipReferenceDS(DataSourceList[DSCount]);
  280. DSCount++;
  281. }
  282. if (IsEnable)
  283. {
  284. InstanceSet->Flags |= IsFlags;
  285. } else {
  286. InstanceSet->Flags &= ~IsFlags;
  287. }
  288. }
  289. InstanceSetList = InstanceSetList->Flink;
  290. }
  291. if (IsUpdate)
  292. {
  293. GuidEntry->Flags &= ~GE_NOTIFICATION_TRACE_UPDATE;
  294. }
  295. WmipLeaveSMCritSection();
  296. //
  297. // Now without the critical section we send the request to all of the
  298. // data providers. Any new data providers who register after we made our
  299. // list will be enabled by the registration code.
  300. if (DSCount > 0)
  301. {
  302. pWnode = &TraceNotifyHeader.Wnode;
  303. RtlZeroMemory(pWnode, sizeof(TraceNotifyHeader));
  304. RtlCopyMemory(&pWnode->Guid, &GuidEntry->Guid, sizeof(GUID));
  305. BufferSize = sizeof(WNODE_HEADER);
  306. if (IsTraceLog)
  307. {
  308. BufferSize = sizeof(TraceNotifyHeader);
  309. TraceNotifyHeader.LoggerContext = LoggerContext;
  310. pWnode->Flags |= WNODE_FLAG_TRACED_GUID;
  311. //
  312. // If this GUID is already enabled then this must
  313. // an update call. So mark it so.
  314. //
  315. if ( IsEnable && IsUpdate ) {
  316. pWnode->ClientContext = IsUpdate;
  317. }
  318. }
  319. pWnode->BufferSize = BufferSize;
  320. for (i = 0; i < DSCount; i++)
  321. {
  322. DataSource = DataSourceList[i];
  323. WmipAssert(DataSource != NULL);
  324. if (IsTraceLog) {
  325. if (DataSource->Flags & DS_KERNEL_MODE) {
  326. pWnode->HistoricalContext = LoggerContext;
  327. }
  328. else if (DataSource->Flags & DS_USER_MODE) {
  329. pWnode->HistoricalContext = 0;
  330. }
  331. else {
  332. ASSERT(FALSE);
  333. }
  334. }
  335. Status |= WmipDeliverWnodeToDS(ActionCode,
  336. DataSource,
  337. pWnode,
  338. BufferSize);
  339. WmipUnreferenceDS(DataSource);
  340. }
  341. }
  342. if( ! IsTraceLog )
  343. {
  344. Status = STATUS_SUCCESS;
  345. }
  346. if (DataSourceList != DataSourceArray)
  347. {
  348. WmipFree(DataSourceList);
  349. }
  350. WmipEnterSMCritSection();
  351. return(Status);
  352. }
  353. void WmipReleaseCollectionEnabled(
  354. PBGUIDENTRY GuidEntry
  355. )
  356. {
  357. PAGED_CODE();
  358. if (GuidEntry->Flags & GE_FLAG_WAIT_ENABLED)
  359. {
  360. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p enable releasning %p.%p %x event %p\n",
  361. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  362. GuidEntry,
  363. GuidEntry->Flags));
  364. KeSetEvent(GuidEntry->CollectInProgress, 0, FALSE);
  365. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p enable did release %p %x event %p\n",
  366. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  367. GuidEntry,
  368. GuidEntry->Flags));
  369. GuidEntry->Flags &= ~GE_FLAG_WAIT_ENABLED;
  370. }
  371. }
  372. void WmipWaitForCollectionEnabled(
  373. PBGUIDENTRY GuidEntry
  374. )
  375. {
  376. PAGED_CODE();
  377. WmipAssert((GuidEntry->Flags & GE_FLAG_COLLECTION_IN_PROGRESS) ==
  378. GE_FLAG_COLLECTION_IN_PROGRESS);
  379. //
  380. // Collection Enable/Disable is in progress so
  381. // we cannot return just yet. Right now there could be a
  382. // disable request being processed and if we didn't wait, we
  383. // might get back to this caller before that disable request
  384. // got around to realizing that it needs to send and enable
  385. // request (needed by this thread's caller). So we'd have a
  386. // situation where a thread though that collection was enabled
  387. // but in reality it wasn't yet enabled.
  388. if ((GuidEntry->Flags & GE_FLAG_WAIT_ENABLED) == 0)
  389. {
  390. KeInitializeEvent(GuidEntry->CollectInProgress,
  391. NotificationEvent,
  392. FALSE);
  393. GuidEntry->Flags |= GE_FLAG_WAIT_ENABLED;
  394. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p for %p %x created event\n",
  395. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  396. GuidEntry,
  397. GuidEntry->Flags));
  398. }
  399. WmipLeaveSMCritSection();
  400. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p waiting for %p %x on event\n",
  401. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  402. GuidEntry,
  403. GuidEntry->Flags));
  404. KeWaitForSingleObject(GuidEntry->CollectInProgress,
  405. Executive,
  406. KernelMode,
  407. FALSE,
  408. NULL);
  409. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p done %p %x waiting on event\n",
  410. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  411. GuidEntry,
  412. GuidEntry->Flags));
  413. WmipEnterSMCritSection();
  414. }
  415. ULONG WmipSendEnableRequest(
  416. PBGUIDENTRY GuidEntry,
  417. BOOLEAN IsEvent,
  418. BOOLEAN IsTraceLog,
  419. ULONG64 LoggerContext
  420. )
  421. /*++
  422. Routine Description:
  423. This routine will send an enable collection or notification request to
  424. all of the data providers that have registered the guid being enabled.
  425. This routine will manage any race conditions that might occur when
  426. multiple threads are enabling and disabling the notification
  427. simultaneously.
  428. This routine is called while the SM critical section is being held and
  429. will increment the appropriate reference count. if the ref count
  430. transitions from 0 to 1 then the enable request will need to be forwarded
  431. to the data providers otherwise the routine is all done and returns.
  432. Before sending the enable request the routine checks to see if any
  433. enable or disable requests are currently in progress and if not then sets
  434. the in progress flag, releases the critical section and sends the enable
  435. request. If there was a request in progress then the routine does not
  436. send a request, but just returns. When the other thread that was sending
  437. the request returns from processing the request it will recheck the
  438. refcount and notice that it is greater than 0 and then send the enable
  439. request.
  440. Arguments:
  441. GuidEntry is the guid entry that describes the guid being enabled. For
  442. a notification it may be NULL.
  443. NotificationContext is the notification context to use if enabling events
  444. IsEvent is TRUE if notifications are being enables else FALSE if
  445. collection is being enabled
  446. IsTraceLog is TRUE if enable is for a trace log guid
  447. LoggerContext is a context value to forward in the enable request
  448. Return Value:
  449. ERROR_SUCCESS or an error code
  450. --*/
  451. {
  452. ULONG InProgressFlag;
  453. ULONG RefCount;
  454. ULONG Status;
  455. PAGED_CODE();
  456. if (IsEvent)
  457. {
  458. InProgressFlag = GE_FLAG_NOTIFICATION_IN_PROGRESS;
  459. RefCount = GuidEntry->EventRefCount++;
  460. } else {
  461. InProgressFlag = GE_FLAG_COLLECTION_IN_PROGRESS;
  462. RefCount = GuidEntry->CollectRefCount++;
  463. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p enable collect for %p %x\n",
  464. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  465. GuidEntry, GuidEntry->Flags ));
  466. }
  467. //
  468. // If the guid is transitioning from a refcount of 0 to 1 and there
  469. // is not currently a request in progress, then we need to set the
  470. // request in progress flag, release the critical section and
  471. // send an enable request. If there is a request in progress we can't
  472. // do another request. Whenever the current request finishes it
  473. // will notice the ref count change and send the enable request on
  474. // our behalf.
  475. if ((RefCount == 0) &&
  476. ! (GuidEntry->Flags & InProgressFlag))
  477. {
  478. //
  479. // Take an extra ref count so that even if this gets disabled
  480. // while the enable request is in progress the GuidEntry
  481. // will stay valid.
  482. WmipReferenceGE(GuidEntry);
  483. GuidEntry->Flags |= InProgressFlag;
  484. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p NE %p flags -> %x at %d\n",
  485. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  486. GuidEntry,
  487. GuidEntry->Flags,
  488. __LINE__));
  489. EnableNotification:
  490. Status = WmipSendEnableDisableRequest((UCHAR)(IsEvent ?
  491. IRP_MN_ENABLE_EVENTS :
  492. IRP_MN_ENABLE_COLLECTION),
  493. GuidEntry,
  494. IsEvent,
  495. IsTraceLog,
  496. LoggerContext);
  497. RefCount = IsEvent ? GuidEntry->EventRefCount :
  498. GuidEntry->CollectRefCount;
  499. if (RefCount == 0)
  500. {
  501. // This is the bogus situation we were worried about. While
  502. // the enable request was being processed the notification
  503. // was disabled. So leave the in progress flag set and
  504. // send the disable.
  505. Status = WmipSendEnableDisableRequest((UCHAR)(IsEvent ?
  506. IRP_MN_DISABLE_EVENTS :
  507. IRP_MN_DISABLE_COLLECTION),
  508. GuidEntry,
  509. IsEvent,
  510. IsTraceLog,
  511. LoggerContext);
  512. RefCount = IsEvent ? GuidEntry->EventRefCount :
  513. GuidEntry->CollectRefCount;
  514. if (RefCount > 0)
  515. {
  516. //
  517. // We have hit a pathological case. One thread called to
  518. // enable and while the enable request was being processed
  519. // another thread called to disable, but was postponed
  520. // since the enable was in progress. So once the enable
  521. // completed we realized that the ref count reached 0 and
  522. // so we need to disable and sent the disable request.
  523. // But while the disable request was being processed
  524. // an enable request came in so now we need to enable
  525. // the notification. Sheesh.
  526. goto EnableNotification;
  527. }
  528. }
  529. GuidEntry->Flags &= ~InProgressFlag;
  530. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p NE %p flags -> %x at %d\n",
  531. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  532. GuidEntry,
  533. GuidEntry->Flags,
  534. __LINE__));
  535. //
  536. // If there are any other threads that were waiting until all of
  537. // the enable/disable work completed, we close the event handle
  538. // to release them from their wait.
  539. //
  540. if (! IsEvent)
  541. {
  542. WmipReleaseCollectionEnabled(GuidEntry);
  543. }
  544. //
  545. // Get rid of extra ref count we took above. Note that the
  546. // GuidEntry could be going away here if there was a
  547. // disable while the enable was in progress.
  548. WmipUnreferenceGE(GuidEntry);
  549. } else if (IsTraceLog && (GuidEntry->Flags & GE_NOTIFICATION_TRACE_UPDATE) ) {
  550. //
  551. // If it's a tracelog and we have a trace Update enable call, ignore the
  552. // refcount and send it through.
  553. //
  554. WmipReferenceGE(GuidEntry);
  555. Status = WmipSendEnableDisableRequest((UCHAR)(IsEvent ?
  556. IRP_MN_ENABLE_EVENTS :
  557. IRP_MN_ENABLE_COLLECTION),
  558. GuidEntry,
  559. IsEvent,
  560. IsTraceLog,
  561. LoggerContext);
  562. GuidEntry->EventRefCount--;
  563. WmipUnreferenceGE(GuidEntry);
  564. } else {
  565. if ((! IsEvent) && (GuidEntry->Flags & InProgressFlag))
  566. {
  567. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p going to wait for %p %x at %d\n",
  568. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  569. GuidEntry,
  570. GuidEntry->Flags,
  571. __LINE__));
  572. WmipWaitForCollectionEnabled(GuidEntry);
  573. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p done to wait for %p %x at %d\n",
  574. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  575. GuidEntry,
  576. GuidEntry->Flags,
  577. __LINE__));
  578. }
  579. Status = STATUS_SUCCESS;
  580. }
  581. if (! IsEvent)
  582. {
  583. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p enable collect done for %p %x\n",
  584. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  585. GuidEntry,
  586. GuidEntry->Flags));
  587. }
  588. return(Status);
  589. }
  590. ULONG WmipDoDisableRequest(
  591. PBGUIDENTRY GuidEntry,
  592. BOOLEAN IsEvent,
  593. BOOLEAN IsTraceLog,
  594. ULONG64 LoggerContext,
  595. ULONG InProgressFlag
  596. )
  597. {
  598. ULONG RefCount;
  599. ULONG Status;
  600. PAGED_CODE();
  601. DisableNotification:
  602. Status = WmipSendEnableDisableRequest((UCHAR)(IsEvent ?
  603. IRP_MN_DISABLE_EVENTS :
  604. IRP_MN_DISABLE_COLLECTION),
  605. GuidEntry,
  606. IsEvent,
  607. IsTraceLog,
  608. LoggerContext);
  609. RefCount = IsEvent ? GuidEntry->EventRefCount :
  610. GuidEntry->CollectRefCount;
  611. if (RefCount > 0)
  612. {
  613. //
  614. // While we were processing the disable request an
  615. // enable request arrived. Since the in progress
  616. // flag was set the enable request was not sent
  617. // so now we need to do that.
  618. Status = WmipSendEnableDisableRequest((UCHAR)(IsEvent ?
  619. IRP_MN_ENABLE_EVENTS :
  620. IRP_MN_ENABLE_COLLECTION),
  621. GuidEntry,
  622. IsEvent,
  623. IsTraceLog,
  624. LoggerContext);
  625. RefCount = IsEvent ? GuidEntry->EventRefCount:
  626. GuidEntry->CollectRefCount;
  627. if (RefCount == 0)
  628. {
  629. //
  630. // While processing the enable request above the
  631. // notification was disabled and since a request
  632. // was in progress the disable request was not
  633. // forwarded. Now it is time to forward the
  634. // request.
  635. goto DisableNotification;
  636. }
  637. }
  638. GuidEntry->Flags &= ~InProgressFlag;
  639. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p NE %p flags -> %x at %d\n",
  640. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  641. GuidEntry,
  642. GuidEntry->Flags,
  643. __LINE__));
  644. //
  645. // If there are any other threads that were waiting until all of
  646. // the enable/disable work completed, we close the event handle
  647. // to release them from their wait.
  648. //
  649. if (! IsEvent)
  650. {
  651. WmipReleaseCollectionEnabled(GuidEntry);
  652. }
  653. return(Status);
  654. }
  655. ULONG WmipSendDisableRequest(
  656. PBGUIDENTRY GuidEntry,
  657. BOOLEAN IsEvent,
  658. BOOLEAN IsTraceLog,
  659. ULONG64 LoggerContext
  660. )
  661. /*++
  662. Routine Description:
  663. This routine will send an disable collection or notification request to
  664. all of the data providers that have registered the guid being disabled.
  665. This routine will manage any race conditions that might occur when
  666. multiple threads are enabling and disabling the notification
  667. simultaneously.
  668. This routine is called while the SM critical section is being held and
  669. will increment the appropriate reference count. if the ref count
  670. transitions from 1 to 0 then the disable request will need to be forwarded
  671. to the data providers otherwise the routine is all done and returns.
  672. Before sending the disable request the routine checks to see if any
  673. enable or disable requests are currently in progress and if not then sets
  674. the in progress flag, releases the critical section and sends the disable
  675. request. If there was a request in progress then the routine does not
  676. send a request, but just returns. When the other thread that was sending
  677. the request returns from processing the request it will recheck the
  678. refcount and notice that it is 0 and then send the disable
  679. request.
  680. Arguments:
  681. GuidEntry is the Notification entry that describes the guid
  682. being enabled.
  683. GuidEntry is the guid entry that describes the guid being enabled. For
  684. a notification it may be NULL.
  685. NotificationContext is the notification context to use if enabling events
  686. IsEvent is TRUE if notifications are being enables else FALSE if
  687. collection is being enabled
  688. IsTraceLog is TRUE if enable is for a trace log guid
  689. LoggerContext is a context value to forward in the enable request
  690. Return Value:
  691. ERROR_SUCCESS or an error code
  692. --*/
  693. {
  694. ULONG InProgressFlag;
  695. ULONG RefCount;
  696. ULONG Status;
  697. PAGED_CODE();
  698. if (IsEvent)
  699. {
  700. InProgressFlag = GE_FLAG_NOTIFICATION_IN_PROGRESS;
  701. RefCount = GuidEntry->EventRefCount;
  702. if (RefCount == 0)
  703. {
  704. //
  705. // A bad data consumer is disabling his event more
  706. // than once. Just ignore it
  707. return(STATUS_SUCCESS);
  708. }
  709. RefCount = --GuidEntry->EventRefCount;
  710. } else {
  711. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p Disabling for %p %x\n",
  712. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  713. GuidEntry,
  714. GuidEntry->Flags));
  715. InProgressFlag = GE_FLAG_COLLECTION_IN_PROGRESS;
  716. RefCount = --GuidEntry->CollectRefCount;
  717. WmipAssert(RefCount != 0xffffffff);
  718. }
  719. //
  720. // If we have transitioned to a refcount of zero and there is
  721. // not a request in progress then forward the disable request.
  722. if ((RefCount == 0) &&
  723. ! (GuidEntry->Flags & InProgressFlag))
  724. {
  725. //
  726. // Take an extra ref count so that even if this gets
  727. // disabled while the disable request is in progress the
  728. // GuidEntry will stay valid.
  729. GuidEntry->Flags |= InProgressFlag;
  730. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p NE %p flags -> %x at %d\n",
  731. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  732. GuidEntry,
  733. GuidEntry->Flags,
  734. __LINE__));
  735. Status = WmipDoDisableRequest(GuidEntry,
  736. IsEvent,
  737. IsTraceLog,
  738. LoggerContext,
  739. InProgressFlag);
  740. } else {
  741. Status = STATUS_SUCCESS;
  742. }
  743. if (! IsEvent)
  744. {
  745. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p Disable complete for %p %x\n",
  746. PsGetCurrentProcessId(), PsGetCurrentThreadId(),
  747. GuidEntry,
  748. GuidEntry->Flags));
  749. }
  750. return(Status);
  751. }
  752. NTSTATUS WmipEnableCollectOrEvent(
  753. PBGUIDENTRY GuidEntry,
  754. ULONG Ioctl,
  755. BOOLEAN *RequestSent,
  756. ULONG64 LoggerContext
  757. )
  758. {
  759. ULONG EnableFlags;
  760. BOOLEAN DoEnable, IsEvent, IsTracelog;
  761. PLIST_ENTRY InstanceSetList;
  762. PBINSTANCESET InstanceSet;
  763. NTSTATUS Status;
  764. PAGED_CODE();
  765. *RequestSent = FALSE;
  766. switch (Ioctl)
  767. {
  768. case IOCTL_WMI_OPEN_GUID_FOR_QUERYSET:
  769. {
  770. //
  771. // See if the guid requires an enable collection. Loop over all
  772. // instance sets that are not for tracelog or events.
  773. //
  774. DoEnable = FALSE;
  775. IsTracelog = FALSE;
  776. IsEvent = FALSE;
  777. WmipEnterSMCritSection();
  778. InstanceSetList = GuidEntry->ISHead.Flink;
  779. while (InstanceSetList != &GuidEntry->ISHead)
  780. {
  781. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  782. INSTANCESET,
  783. GuidISList);
  784. if ( ! ((InstanceSet->Flags & IS_TRACED) ||
  785. ((InstanceSet->Flags & IS_EVENT_ONLY) && DoEnable)))
  786. {
  787. //
  788. // Only those guids not Traced guids, event only guids
  789. // and unresolved references are not available for queries
  790. DoEnable = (DoEnable || (InstanceSet->Flags & IS_EXPENSIVE));
  791. }
  792. InstanceSetList = InstanceSetList->Flink;
  793. }
  794. WmipLeaveSMCritSection();
  795. break;
  796. }
  797. case IOCTL_WMI_OPEN_GUID_FOR_EVENTS:
  798. {
  799. //
  800. // For events we always send enable request
  801. //
  802. DoEnable = TRUE;
  803. IsEvent = TRUE;
  804. IsTracelog = FALSE;
  805. //
  806. // Note: If this guid has GE_NOTIFICATION_TRACE_FLAG set,
  807. // then it will get enabled for tracelog as well as for
  808. // wmi events.
  809. //
  810. break;
  811. }
  812. case IOCTL_WMI_ENABLE_DISABLE_TRACELOG:
  813. {
  814. //
  815. // Setup for a tracelog enable request
  816. //
  817. DoEnable = TRUE;
  818. IsEvent = TRUE;
  819. IsTracelog = TRUE;
  820. break;
  821. }
  822. default:
  823. {
  824. ASSERT(FALSE);
  825. return(STATUS_ILLEGAL_FUNCTION);
  826. }
  827. }
  828. if (DoEnable)
  829. {
  830. WmipEnterSMCritSection();
  831. Status = WmipSendEnableRequest(GuidEntry,
  832. IsEvent,
  833. IsTracelog,
  834. LoggerContext);
  835. WmipLeaveSMCritSection();
  836. if (NT_SUCCESS(Status))
  837. {
  838. *RequestSent = TRUE;
  839. }
  840. } else {
  841. Status = STATUS_SUCCESS;
  842. }
  843. return(Status);
  844. }
  845. NTSTATUS WmipDisableCollectOrEvent(
  846. PBGUIDENTRY GuidEntry,
  847. ULONG Ioctl,
  848. ULONG64 LoggerContext
  849. )
  850. {
  851. BOOLEAN IsEvent, IsTracelog;
  852. NTSTATUS Status;
  853. PAGED_CODE();
  854. switch(Ioctl)
  855. {
  856. case IOCTL_WMI_OPEN_GUID_FOR_QUERYSET:
  857. {
  858. IsEvent = FALSE;
  859. IsTracelog = FALSE;
  860. break;
  861. }
  862. case IOCTL_WMI_OPEN_GUID_FOR_EVENTS:
  863. {
  864. //
  865. // For events we always send enable request
  866. //
  867. IsEvent = TRUE;
  868. IsTracelog = FALSE;
  869. break;
  870. }
  871. case IOCTL_WMI_ENABLE_DISABLE_TRACELOG:
  872. {
  873. IsEvent = TRUE;
  874. IsTracelog = TRUE;
  875. break;
  876. }
  877. default:
  878. {
  879. ASSERT(FALSE);
  880. return(STATUS_ILLEGAL_FUNCTION);
  881. }
  882. }
  883. WmipEnterSMCritSection();
  884. Status = WmipSendDisableRequest(GuidEntry,
  885. IsEvent,
  886. IsTracelog,
  887. LoggerContext);
  888. WmipLeaveSMCritSection();
  889. return(Status);
  890. }
  891. NTSTATUS WmipEnableDisableTrace(
  892. IN ULONG Ioctl,
  893. IN PWMITRACEENABLEDISABLEINFO TraceEnableInfo
  894. )
  895. /*++
  896. Routine Description:
  897. This routine will enable or disable a tracelog guid
  898. Arguments:
  899. Ioctl is the IOCTL used to call this routine from UM
  900. TraceEnableInfo has all the info needed to enable or disable
  901. Return Value:
  902. --*/
  903. {
  904. NTSTATUS Status;
  905. LPGUID Guid;
  906. PBGUIDENTRY GuidEntry;
  907. BOOLEAN RequestSent;
  908. BOOLEAN IsEnable;
  909. ULONG64 LoggerContext;
  910. PAGED_CODE();
  911. Guid = &TraceEnableInfo->Guid;
  912. Status = WmipCheckGuidAccess(Guid,
  913. TRACELOG_GUID_ENABLE);
  914. if (NT_SUCCESS(Status))
  915. {
  916. //
  917. // The following code is serialized for Trace Guids. Only one
  918. // control application can be enabling or disabling Trace Guids at a time.
  919. // Must be taken before SMCritSection is taken. Otherwise deadlocks will result.
  920. //
  921. WmipEnterTLCritSection();
  922. IsEnable = TraceEnableInfo->Enable;
  923. //
  924. //Check for Heap and Crit Sec Tracing Guid.
  925. //
  926. if( IsEqualGUID(&HeapGuid,Guid)) {
  927. if(IsEnable){
  928. SharedUserData->TraceLogging |= ENABLEHEAPTRACE;
  929. //
  930. // increment counter. The counter
  931. // is composed of first two bytes
  932. //
  933. SharedUserData->TraceLogging += 0x00010000;
  934. } else {
  935. SharedUserData->TraceLogging &= DISABLEHEAPTRACE;
  936. }
  937. WmipLeaveTLCritSection();
  938. return STATUS_SUCCESS;
  939. } else if(IsEqualGUID(&CritSecGuid,Guid)){
  940. if(IsEnable) {
  941. SharedUserData->TraceLogging |= ENABLECRITSECTRACE;
  942. //
  943. // increment counter. The counter
  944. // is composed of first two bytes
  945. //
  946. SharedUserData->TraceLogging += 0x00010000;
  947. } else {
  948. SharedUserData->TraceLogging &= DISABLECRITSECTRACE;
  949. }
  950. WmipLeaveTLCritSection();
  951. return STATUS_SUCCESS;
  952. } else if(IsEqualGUID(&NtdllTraceGuid,Guid)){
  953. if(!IsEnable){
  954. SharedUserData->TraceLogging &= DISABLENTDLLTRACE;
  955. }
  956. }
  957. LoggerContext = TraceEnableInfo->LoggerContext;
  958. WmipEnterSMCritSection();
  959. GuidEntry = WmipFindGEByGuid(Guid, FALSE);
  960. if (GuidEntry == NULL )
  961. {
  962. //
  963. // The guid is not yet registered
  964. //
  965. if (IsEnable )
  966. {
  967. //
  968. // If the NtdllTraceGuid is not in list then we do not want to enable it
  969. // the NtdllTraceGuid will make an entry only to call starttrace
  970. //
  971. if(IsEqualGUID(&NtdllTraceGuid,Guid)){
  972. Status = STATUS_ILLEGAL_FUNCTION;
  973. } else {
  974. //
  975. // If we are enabling a guid that is not yet registered
  976. // we need to create the guid object for it
  977. //
  978. GuidEntry = WmipAllocGuidEntry();
  979. if (GuidEntry != NULL)
  980. {
  981. //
  982. // Initialize the guid entry and keep the ref count
  983. // from creation. When tracelog enables we take a ref
  984. // count and when it disables we release it
  985. //
  986. GuidEntry->Guid = *Guid;
  987. GuidEntry->Flags |= GE_NOTIFICATION_TRACE_FLAG;
  988. GuidEntry->LoggerContext = LoggerContext;
  989. GuidEntry->EventRefCount = 1;
  990. InsertHeadList(WmipGEHeadPtr, &GuidEntry->MainGEList);
  991. Status = STATUS_SUCCESS;
  992. } else {
  993. Status = STATUS_INSUFFICIENT_RESOURCES;
  994. }
  995. }
  996. }
  997. } else {
  998. //
  999. // The control guid is already registered so lets go and
  1000. // enabled or disable it
  1001. //
  1002. if (WmipIsControlGuid(GuidEntry))
  1003. {
  1004. if (IsEnable)
  1005. {
  1006. GuidEntry->LoggerContext = LoggerContext;
  1007. if (GuidEntry->Flags & GE_NOTIFICATION_TRACE_FLAG)
  1008. {
  1009. //
  1010. // We are trying to disable a trace guid that is not
  1011. // registered
  1012. //
  1013. GuidEntry->Flags |= GE_NOTIFICATION_TRACE_UPDATE;
  1014. Status = WmipEnableCollectOrEvent(GuidEntry,
  1015. Ioctl,
  1016. &RequestSent,
  1017. LoggerContext);
  1018. } else {
  1019. GuidEntry->Flags |= GE_NOTIFICATION_TRACE_FLAG;
  1020. Status = WmipEnableCollectOrEvent(GuidEntry,
  1021. Ioctl,
  1022. &RequestSent,
  1023. LoggerContext);
  1024. if (NT_SUCCESS(Status))
  1025. {
  1026. //
  1027. // We are enabling so take an extra ref count
  1028. // to account for it. The refcount will be lost
  1029. // when the control guid is disabled
  1030. //
  1031. WmipReferenceGE(GuidEntry);
  1032. }
  1033. }
  1034. } else {
  1035. if (GuidEntry->Flags & GE_NOTIFICATION_TRACE_FLAG)
  1036. {
  1037. //
  1038. // Send the disable collection call and then remove
  1039. // the refcount that was taken when we enabled
  1040. //
  1041. Status = WmipDisableCollectOrEvent(GuidEntry,
  1042. Ioctl,
  1043. LoggerContext);
  1044. if (NT_SUCCESS(Status))
  1045. {
  1046. GuidEntry->Flags &= ~GE_NOTIFICATION_TRACE_FLAG;
  1047. GuidEntry->LoggerContext = 0;
  1048. WmipUnreferenceGE(GuidEntry);
  1049. }
  1050. } else {
  1051. Status = STATUS_WMI_ALREADY_DISABLED;
  1052. }
  1053. }
  1054. } else if ( IsListEmpty(&GuidEntry->ISHead) && (! IsEnable) ) {
  1055. //
  1056. // If this GUID is not a control GUID, check to see if
  1057. // there are no instance sets for this GUID. If so,
  1058. // it is getting disabled before any instances
  1059. // registered it. Disable the GUID and clean up the GE.
  1060. //
  1061. GuidEntry->Flags &= ~GE_NOTIFICATION_TRACE_FLAG;
  1062. GuidEntry->LoggerContext = 0;
  1063. WmipUnreferenceGE(GuidEntry);
  1064. Status = STATUS_SUCCESS;
  1065. } else if(!IsEqualGUID(&NtdllTraceGuid,Guid)){
  1066. Status = STATUS_ILLEGAL_FUNCTION;
  1067. }
  1068. WmipUnreferenceGE(GuidEntry);
  1069. }
  1070. WmipLeaveSMCritSection();
  1071. WmipLeaveTLCritSection();
  1072. }
  1073. return(Status);
  1074. }
  1075. //
  1076. // When a Logger is shutdown, all providers logging to this logger
  1077. // are notified to stop logging first.
  1078. //
  1079. NTSTATUS
  1080. WmipDisableTraceProviders (
  1081. ULONG StopLoggerId,
  1082. PLIST_ENTRY TraceGMHeadPtr
  1083. )
  1084. {
  1085. PWMIGUIDPROPERTIES GuidPtr;
  1086. PBGUIDENTRY GuidEntry;
  1087. PLIST_ENTRY GuidEntryList;
  1088. ULONG64 LoggerContext;
  1089. ULONG LoggerId;
  1090. NTSTATUS Status = STATUS_SUCCESS;
  1091. PGUIDMAPENTRY GuidMap;
  1092. PLIST_ENTRY GuidMapList;
  1093. PLIST_ENTRY InstanceSetList;
  1094. PBINSTANCESET InstanceSet;
  1095. ULONGLONG SystemTime;
  1096. PTRACEGUIDMAP TraceGuidMapPtr;
  1097. ULONG i;
  1098. PAGED_CODE();
  1099. //
  1100. // Before disabling the trace providers for the stopping
  1101. // logger, pick up their trace guids maps and save.
  1102. //
  1103. if (TraceGMHeadPtr != NULL)
  1104. {
  1105. KeQuerySystemTime((PLARGE_INTEGER)&SystemTime);
  1106. WmipEnterSMCritSection();
  1107. //
  1108. // For all the Guids that are enabled to the StopLoggerId,
  1109. // get the GuidMap from its instance set
  1110. //
  1111. GuidEntryList = WmipGEHeadPtr->Flink;
  1112. while (GuidEntryList != WmipGEHeadPtr)
  1113. {
  1114. GuidEntry = CONTAINING_RECORD(GuidEntryList,
  1115. GUIDENTRY,
  1116. MainGEList);
  1117. if (GuidEntry->Flags & GE_NOTIFICATION_TRACE_FLAG)
  1118. {
  1119. // Guid is enabled for Tracing
  1120. LoggerId = WmiGetLoggerId(GuidEntry->LoggerContext);
  1121. if (LoggerId == StopLoggerId) {
  1122. // Guid is enabled for the StopLoggerId
  1123. InstanceSetList = GuidEntry->ISHead.Flink;
  1124. while (InstanceSetList != &GuidEntry->ISHead)
  1125. {
  1126. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  1127. INSTANCESET,
  1128. GuidISList);
  1129. if ((InstanceSet->Flags & IS_CONTROL_GUID) && (InstanceSet->TraceGuidMap != NULL))
  1130. {
  1131. // InstanceSet is the ControlGuid and has a TraceGuidMap
  1132. // Walk through the TraceGuidMap and return them as a list
  1133. for (i=0, TraceGuidMapPtr = InstanceSet->TraceGuidMap;
  1134. ((i < InstanceSet->TransGuidCount) && (InstanceSet->TraceGuidMap != NULL));
  1135. i++, TraceGuidMapPtr++) {
  1136. GuidMap = (PGUIDMAPENTRY) WmipAllocWithTag(sizeof(GUIDMAPENTRY), WMI_GM_POOLTAG);
  1137. if (GuidMap != NULL) {
  1138. GuidMap->GuidMap.Guid = InstanceSet->TraceGuidMap->Guid;
  1139. GuidMap->GuidMap.GuidMapHandle = (ULONG_PTR)TraceGuidMapPtr;
  1140. GuidMap->LoggerContext = GuidEntry->LoggerContext;
  1141. GuidMap->GuidMap.SystemTime = SystemTime;
  1142. InsertTailList(TraceGMHeadPtr, &GuidMap->Entry);
  1143. }
  1144. }
  1145. }
  1146. InstanceSetList = InstanceSetList->Flink;
  1147. }
  1148. }
  1149. }
  1150. GuidEntryList = GuidEntryList->Flink;
  1151. }
  1152. WmipLeaveSMCritSection();
  1153. }
  1154. //
  1155. // Find all the providers that are logging to this logger
  1156. // and disable them automatically.
  1157. //
  1158. CheckAgain:
  1159. WmipEnterSMCritSection();
  1160. GuidEntryList = WmipGEHeadPtr->Flink;
  1161. while (GuidEntryList != WmipGEHeadPtr)
  1162. {
  1163. GuidEntry = CONTAINING_RECORD(GuidEntryList,
  1164. GUIDENTRY,
  1165. MainGEList);
  1166. if (GuidEntry->Flags & GE_NOTIFICATION_TRACE_FLAG)
  1167. {
  1168. LoggerId = WmiGetLoggerId(GuidEntry->LoggerContext);
  1169. if (LoggerId == StopLoggerId) {
  1170. //
  1171. // Send Disable Notification
  1172. //
  1173. WmipReferenceGE(GuidEntry);
  1174. Status = WmipSendDisableRequest(GuidEntry,
  1175. TRUE,
  1176. TRUE,
  1177. GuidEntry->LoggerContext);
  1178. if (NT_SUCCESS(Status))
  1179. {
  1180. GuidEntry->Flags &= ~GE_NOTIFICATION_TRACE_FLAG;
  1181. GuidEntry->LoggerContext = 0;
  1182. WmipUnreferenceGE(GuidEntry);
  1183. }
  1184. //
  1185. // We have to jump out and restart the loop
  1186. //
  1187. WmipUnreferenceGE(GuidEntry);
  1188. WmipLeaveSMCritSection();
  1189. goto CheckAgain;
  1190. }
  1191. }
  1192. GuidEntryList = GuidEntryList->Flink;
  1193. }
  1194. //
  1195. // Now Walk through the GuidMapEntry list and delete the
  1196. // Guids that were logging to this logger.
  1197. //
  1198. GuidMapList = WmipGMHeadPtr->Flink;
  1199. while (GuidMapList != WmipGMHeadPtr)
  1200. {
  1201. GuidMap = CONTAINING_RECORD(GuidMapList,
  1202. GUIDMAPENTRY,
  1203. Entry);
  1204. GuidMapList = GuidMapList->Flink;
  1205. if (WmiGetLoggerId(GuidMap->LoggerContext) == StopLoggerId)
  1206. {
  1207. RemoveEntryList(&GuidMap->Entry);
  1208. if (TraceGMHeadPtr != NULL)
  1209. {
  1210. InsertTailList(TraceGMHeadPtr, &GuidMap->Entry);
  1211. }
  1212. else
  1213. {
  1214. WmipFree(GuidMap);
  1215. }
  1216. }
  1217. }
  1218. WmipLeaveSMCritSection();
  1219. return Status;
  1220. }