Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

cmnotify.c File Reference

#include "cmp.h"

Go to the source code of this file.

Defines

#define CmpCheckPostBlock(a)

Functions

VOID CmpReportNotifyHelper (PCM_KEY_CONTROL_BLOCK KeyControlBlock, IN PHHIVE SearchHive, IN PHHIVE Hive, IN PCM_KEY_NODE Node, IN ULONG Filter)
VOID CmpCancelSlavePost (PCM_POST_BLOCK PostBlock, PLIST_ENTRY DelayedDeref)
VOID CmpFreeSlavePost (PCM_POST_BLOCK MasterPostBlock)
VOID CmpAddToDelayedDeref (PCM_POST_BLOCK PostBlock, PLIST_ENTRY DelayedDeref)
VOID CmpDelayedDerefKeys (PLIST_ENTRY DelayedDeref)
BOOLEAN CmpNotifyTriggerCheck (IN PCM_NOTIFY_BLOCK NotifyBlock, IN PHHIVE Hive, IN PCM_KEY_NODE Node)
VOID CmpDummyApc (struct _KAPC *Apc, PVOID *SystemArgument1, PVOID *SystemArgument2)
VOID CmpReportNotify (PCM_KEY_CONTROL_BLOCK KeyControlBlock, PHHIVE Hive, HCELL_INDEX Cell, ULONG Filter)
VOID CmpPostNotify (PCM_NOTIFY_BLOCK NotifyBlock, PUNICODE_STRING Name OPTIONAL, ULONG Filter, NTSTATUS Status, PLIST_ENTRY ExternalKeyDeref OPTIONAL)
VOID CmpPostApc (struct _KAPC *Apc, PKNORMAL_ROUTINE *NormalRoutine, PVOID *NormalContext, PVOID *SystemArgument1, PVOID *SystemArgument2)
VOID CmpPostApcRunDown (struct _KAPC *Apc)
VOID CmNotifyRunDown (PETHREAD Thread)
VOID CmpFlushNotify (PCM_KEY_BODY KeyBody)
NTSTATUS CmpNotifyChangeKey (IN PCM_KEY_BODY KeyBody, IN PCM_POST_BLOCK PostBlock, IN ULONG CompletionFilter, IN BOOLEAN WatchTree, IN PVOID Buffer, IN ULONG BufferSize, IN PCM_POST_BLOCK MasterPostBlock)

Variables

PCMHIVE CmpMasterHive


Define Documentation

#define CmpCheckPostBlock  ) 
 

Definition at line 85 of file cmnotify.c.

Referenced by CmpPostApc().


Function Documentation

VOID CmNotifyRunDown PETHREAD  Thread  ) 
 

Definition at line 1028 of file cmnotify.c.

References _CM_ASYNC_USER_POST_BLOCK::Apc, APC_LEVEL, _CM_POST_BLOCK_UNION::AsyncUser, _CM_POST_BLOCK::CancelPostList, CML_API, CMLOG, CmpCancelSlavePost(), CmpClearListEntry, CmpFreePostBlock(), CmpFreeSlavePost(), CmpLockRegistryExclusive(), CmpRemoveEntryList, CmpSetIoStatus, CmpUnlockRegistry(), CMS_EXCEPTION, CMS_NTAPI, EXCEPTION_EXECUTE_HANDLER, FALSE, _CM_ASYNC_USER_POST_BLOCK::IoStatusBlock, IsMasterPostBlock, KeLowerIrql(), KeRaiseIrql(), KeRemoveQueueApc(), KeSetEvent(), L, _CM_POST_BLOCK::NotifyList, NULL, ObDereferenceObject, PAGED_CODE, PostAsyncUser, _ETHREAD::PostBlockList, PostBlockType, PsGetCurrentProcess, _CM_POST_BLOCK::ThreadList, TRUE, _CM_POST_BLOCK::u, and _CM_ASYNC_USER_POST_BLOCK::UserEvent.

Referenced by PspExitThread().

01033 : 01034 01035 This routine is called from PspExitThread to clean up any pending 01036 notify requests. 01037 01038 It will traverse the thread's PostBlockList, for each PostBlock it 01039 finds, it will: 01040 01041 1. Remove it from the relevent NotifyBlock. This requires 01042 that we hold the Registry mutex. 01043 01044 2. Remove it from the thread's PostBlockList. This requires 01045 that we run at APC level. 01046 01047 3. By the time this procedure runs, user apcs are not interesting 01048 and neither are SystemEvents, so do not bother processing 01049 them. 01050 01051 UserEvents and IoStatusBlocks could be refered to by other 01052 threads in the same process, or even a different process, 01053 so process them so those threads know what happened, use 01054 status code of STATUS_NOTIFY_CLEANUP. 01055 01056 If the notify is a master one, cancel all slave notifications. 01057 Else only remove this notification from the master CancelPortList 01058 01059 4. Free the post block. 01060 01061 Arguments: 01062 01063 Thread - pointer to the executive thread object for the thread 01064 we wish to do rundown on. 01065 01066 Return Value: 01067 01068 NONE. 01069 01070 --*/ 01071 { 01072 PCM_POST_BLOCK PostBlock; 01073 PCM_NOTIFY_BLOCK NotifyBlock; 01074 KIRQL OldIrql; 01075 01076 PAGED_CODE(); 01077 01078 if ( IsListEmpty(&(Thread->PostBlockList)) == TRUE ) { 01079 return; 01080 } 01081 01082 CMLOG(CML_API, CMS_NTAPI) { 01083 KdPrint(("CmNotifyRunDown: ethread:%08lx\n", Thread)); 01084 } 01085 01086 CmpLockRegistryExclusive(); 01087 01088 // 01089 // Aquire exclusive access over the postlist(s) 01090 // 01091 // This is not needed (see the rule above) 01092 //LOCK_POST_LIST(); 01093 01094 KeRaiseIrql(APC_LEVEL, &OldIrql); 01095 while (IsListEmpty(&(Thread->PostBlockList)) == FALSE) { 01096 01097 // 01098 // remove from thread list 01099 // 01100 PostBlock = (PCM_POST_BLOCK)RemoveHeadList(&(Thread->PostBlockList)); 01101 PostBlock = CONTAINING_RECORD( 01102 PostBlock, 01103 CM_POST_BLOCK, 01104 ThreadList 01105 ); 01106 01107 // Protect for multiple deletion of the same object 01108 CmpClearListEntry(&(PostBlock->ThreadList)); 01109 01110 CMLOG(CML_API, CMS_NTAPI) { 01111 #if DBG 01112 if(PostBlock->TraceIntoDebugger) { 01113 KdPrint(("[CM]CmpNotifyRunDown: ethread:%08lx, PostBlock:%08lx\n", Thread,PostBlock)); 01114 } 01115 #endif 01116 } 01117 01118 // 01119 // Canceling a master notification implies canceling all the slave notifications 01120 // from the CancelPostList 01121 // 01122 if(IsMasterPostBlock(PostBlock)) { 01123 CMLOG(CML_API, CMS_NTAPI) { 01124 #if DBG 01125 if(PostBlock->TraceIntoDebugger) { 01126 KdPrint(("[CM]\tCmpNotifyRunDown: PostBlock:%08lx is a master block\n", PostBlock)); 01127 } 01128 #endif 01129 } 01130 // 01131 // at this point, CmpReportNotify and friends will no longer 01132 // attempt to post this post block. 01133 // 01134 if (PostBlockType(PostBlock) == PostAsyncUser) { 01135 // 01136 // report status and wake up any threads that might otherwise 01137 // be stuck. also drop any event references we hold 01138 // 01139 // Sundown only: Use a 32bit IO_STATUS_BLOCK if the caller is 32bit. 01140 01141 try { 01142 CmpSetIoStatus(PostBlock->u->AsyncUser.IoStatusBlock, 01143 STATUS_NOTIFY_CLEANUP, 01144 0L, 01145 PsGetCurrentProcess()->Wow64Process != NULL); 01146 } except (EXCEPTION_EXECUTE_HANDLER) { 01147 CMLOG(CML_API, CMS_EXCEPTION) { 01148 KdPrint(("!!CmNotifyRundown: code:%08lx\n", GetExceptionCode())); 01149 } 01150 NOTHING; 01151 } 01152 01153 if (PostBlock->u->AsyncUser.UserEvent != NULL) { 01154 KeSetEvent( 01155 PostBlock->u->AsyncUser.UserEvent, 01156 0, 01157 FALSE 01158 ); 01159 ObDereferenceObject(PostBlock->u->AsyncUser.UserEvent); 01160 } 01161 01162 // 01163 // Cancel the APC. Otherwise the rundown routine will also 01164 // free the post block if the APC happens to be queued at 01165 // this point. If the APC is queued, then the post block has 01166 // already been removed from the notify list, so don't remove 01167 // it again. 01168 // 01169 if (!KeRemoveQueueApc(PostBlock->u->AsyncUser.Apc)) { 01170 01171 // 01172 // remove from notify block's list 01173 // 01174 // Use Cmp variant to protect for multiple deletion of the same object 01175 CmpRemoveEntryList(&(PostBlock->NotifyList)); 01176 } 01177 } else { 01178 // 01179 // remove from notify block's list 01180 // 01181 // Use Cmp variant to protect for multiple deletion of the same object 01182 CmpRemoveEntryList(&(PostBlock->NotifyList)); 01183 } 01184 01185 // 01186 // Cancel all slave Post requests that may be linked to self 01187 // 01188 CmpCancelSlavePost(PostBlock,NULL); // we do not want delayed deref 01189 // 01190 // Free the slave Post blocks too 01191 // 01192 CmpFreeSlavePost(PostBlock); 01193 } else { 01194 01195 CMLOG(CML_API, CMS_NTAPI) { 01196 #if DBG 01197 if(PostBlock->TraceIntoDebugger) { 01198 KdPrint(("[CM]\tCmpNotifyRunDown: PostBlock:%08lx is a slave block\n", PostBlock)); 01199 } 01200 #endif 01201 } 01202 // 01203 // Is a slave PostBlock, just remove self from the Notify PostList 01204 // 01205 // Use Cmp variant to protect for multiple deletion of the same object 01206 CmpRemoveEntryList(&(PostBlock->NotifyList)); 01207 01208 // 01209 // and unchain from the Master CancelPostList 01210 // 01211 // Use Cmp variant to protect for multiple deletion of the same object 01212 CmpRemoveEntryList(&(PostBlock->CancelPostList)); 01213 01214 } 01215 01216 // 01217 // Free the post block. Use Ex call because PostBlocks are NOT 01218 // part of the global registry pool computation, but are instead 01219 // part of NonPagedPool with Quota. 01220 // 01221 CmpFreePostBlock(PostBlock); 01222 } 01223 01224 KeLowerIrql(OldIrql); 01225 01226 // This is not needed (see the rule above) 01227 //UNLOCK_POST_LIST(); 01228 01229 CmpUnlockRegistry(); 01230 return; 01231 }

VOID CmpAddToDelayedDeref PCM_POST_BLOCK  PostBlock,
PLIST_ENTRY  DelayedDeref
 

Definition at line 1845 of file cmnotify.c.

References ASSERT, _CM_POST_KEY_BODY::KeyBody, _CM_POST_KEY_BODY::KeyBodyList, NULL, PAGED_CODE, and _CM_POST_BLOCK::PostKeyBody.

Referenced by CmpCancelSlavePost(), and CmpPostNotify().

01851 : 01852 01853 Add the key body attached to the post block to the delayed deref list. 01854 Cleans the post block KeyBody member, so it will not be dereferenced 01855 when the post block is freed. 01856 01857 Arguments: 01858 01859 PostBlock - pointer to structure that describes the post requests. 01860 01861 DelayedDeref - the delayed deref list 01862 01863 Return Value: 01864 01865 NONE. 01866 01867 --*/ 01868 01869 { 01870 PAGED_CODE(); 01871 01872 // common sense 01873 ASSERT( PostBlock != NULL ); 01874 01875 if( PostBlock->PostKeyBody ) { 01876 // 01877 // If the post block has a keybody attached, add it to delayed deref list and 01878 // clear the post block member. The key body will be deref'd prior after 01879 // postblock lock is released. 01880 // 01881 01882 // extra validation 01883 ASSERT(PostBlock->PostKeyBody->KeyBody != NULL); 01884 ASSERT(DelayedDeref); 01885 01886 // add it to the end of the list 01887 InsertTailList( 01888 DelayedDeref, 01889 &(PostBlock->PostKeyBody->KeyBodyList) 01890 ); 01891 01892 // make sure we don't deref it in CmpFreePostBlock 01893 PostBlock->PostKeyBody = NULL; 01894 } 01895 01896 return; 01897 }

VOID CmpCancelSlavePost PCM_POST_BLOCK  PostBlock,
PLIST_ENTRY  DelayedDeref
 

Definition at line 1738 of file cmnotify.c.

References ASSERT, ASSERT_CM_LOCK_OWNED, _CM_POST_BLOCK::CancelPostList, CML_MAJOR, CMLOG, CmpAddToDelayedDeref(), CmpRemoveEntryList, CMS_NOTIFY, IsMasterPostBlock, _CM_POST_BLOCK::NotifyList, PAGED_CODE, and TRUE.

Referenced by CmNotifyRunDown(), and CmpPostNotify().

01744 : 01745 01746 Unlink the slave postblock from its notify list and dereferences (or adds to the delayed deref list) 01747 the keybody related to this thread. This should disable the slave post block. 01748 It will be cleared later in CmpPostApc. 01749 01750 Arguments: 01751 01752 MasterPostBlock - pointer to structure that describes the post requests. 01753 It should be a master post!! 01754 DelayedDeref - pointer to list of delayed deref keybodies. If this parameter is not NULL, 01755 the keybody for the slave is not cleared before calling CmpFreePostBlock, 01756 and instead is added to the list 01757 01758 01759 Return Value: 01760 01761 NONE. 01762 01763 --*/ 01764 { 01765 PCM_POST_BLOCK SlavePostBlock; 01766 01767 PAGED_CODE(); 01768 CMLOG(CML_MAJOR, CMS_NOTIFY) { 01769 KdPrint(("CmpCancelSlavePost:\t")); 01770 KdPrint(("MasterPostBlock:%08lx\n", MasterPostBlock)); 01771 } 01772 01773 ASSERT_CM_LOCK_OWNED(); 01774 01775 ASSERT(IsMasterPostBlock(MasterPostBlock)); 01776 01777 CMLOG(CML_MAJOR, CMS_NOTIFY) { 01778 #if DBG 01779 if(MasterPostBlock->TraceIntoDebugger) { 01780 KdPrint(("[CM]CmCancelSlavePost: MasterPostBlock:%08lx\n", MasterPostBlock)); 01781 } 01782 #endif 01783 } 01784 01785 if (IsListEmpty(&(MasterPostBlock->CancelPostList)) == TRUE) { 01786 // 01787 // Nothing to cancel, just return 01788 // 01789 CMLOG(CML_MAJOR, CMS_NOTIFY) { 01790 #if DBG 01791 if(MasterPostBlock->TraceIntoDebugger) { 01792 KdPrint(("[CM]CmCancelSlavePost: MasterPostBlock:%08lx has no slaves\n", MasterPostBlock)); 01793 } 01794 #endif 01795 } 01796 01797 return; 01798 } 01799 01800 01801 // 01802 // Pull all the entries in the cancel post list and unlink them (when they are slave requests) 01803 // We base here on the assumption that there is only one slave. 01804 // 01805 // NOTE!!! 01806 // When more than slave allowed, here to modify 01807 // 01808 01809 01810 SlavePostBlock = (PCM_POST_BLOCK)MasterPostBlock->CancelPostList.Flink; 01811 SlavePostBlock = CONTAINING_RECORD(SlavePostBlock, 01812 CM_POST_BLOCK, 01813 CancelPostList); 01814 01815 CMLOG(CML_MAJOR, CMS_NOTIFY) { 01816 #if DBG 01817 if(MasterPostBlock->TraceIntoDebugger) { 01818 KdPrint(("[CM]CmCancelSlavePost: Cleaning SlavePostBlock:%08lx\n", SlavePostBlock)); 01819 } 01820 #endif 01821 } 01822 01823 // 01824 // This should be true ! 01825 // 01826 ASSERT( !IsMasterPostBlock(SlavePostBlock) ); 01827 01828 // 01829 // Remove it from notify block's list 01830 // 01831 // Use Cmp variant to protect for multiple deletion of the same object 01832 // This will disable the notifications that might come on the slave key 01833 // 01834 CmpRemoveEntryList(&(SlavePostBlock->NotifyList)); 01835 01836 if( DelayedDeref ) { 01837 // 01838 // the caller wants to handle key body dereferenciation by himself 01839 // 01840 CmpAddToDelayedDeref(SlavePostBlock,DelayedDeref); 01841 } 01842 }

VOID CmpDelayedDerefKeys PLIST_ENTRY  DelayedDeref  ) 
 

Definition at line 1900 of file cmnotify.c.

References ASSERT, CM_POST_KEY_BODY, ExFreePool(), FALSE, KEY_BODY_TYPE, _CM_POST_KEY_BODY::KeyBody, NULL, ObDereferenceObject, PAGED_CODE, PCM_POST_KEY_BODY, and _CM_KEY_BODY::Type.

Referenced by CmpPostNotify(), and CmpReportNotifyHelper().

01905 : 01906 01907 Walk through the entire list, dereference each keybody and free storage for the 01908 CM_POST_KEY_BODY allocated for this purpose. 01909 01910 Arguments: 01911 01912 DelayedDeref - the delayed deref list 01913 01914 Return Value: 01915 01916 NONE. 01917 01918 --*/ 01919 { 01920 PCM_POST_KEY_BODY PostKeyBody; 01921 01922 PAGED_CODE(); 01923 01924 // common sense 01925 ASSERT( DelayedDeref != NULL ); 01926 01927 while(IsListEmpty(DelayedDeref) == FALSE) { 01928 // 01929 // Remove from the delayed deref list and deref the coresponding keybody 01930 // free the storage associated with CM_POST_KEY_BODY 01931 // 01932 PostKeyBody = (PCM_POST_KEY_BODY)RemoveHeadList(DelayedDeref); 01933 PostKeyBody = CONTAINING_RECORD(PostKeyBody, 01934 CM_POST_KEY_BODY, 01935 KeyBodyList); 01936 01937 // extra validation 01938 ASSERT(PostKeyBody->KeyBody != NULL); 01939 // this should be a valid key body 01940 ASSERT(PostKeyBody->KeyBody->Type == KEY_BODY_TYPE); 01941 01942 // at last ..... dereference the key object 01943 ObDereferenceObject(PostKeyBody->KeyBody); 01944 01945 // Free the storage for the CM_POST_KEY_BODY object (allocated by CmpAllocatePostBlock) 01946 ExFreePool(PostKeyBody); 01947 } 01948 }

VOID CmpDummyApc struct _KAPC Apc,
PVOID *  SystemArgument1,
PVOID *  SystemArgument2
 

Definition at line 159 of file cmnotify.c.

Referenced by NtNotifyChangeMultipleKeys().

00166 : 00167 00168 Dummy routine to prevent user-mode callers to set special kernel apcs 00169 00170 Arguments: 00171 00172 Apc - pointer to apc object 00173 00174 SystemArgument1 - IN: Status value for IoStatusBlock 00175 OUT: Ptr to IoStatusBlock (2nd arg to user apc routine) 00176 00177 SystemArgument2 - Pointer to the PostBlock 00178 00179 Return Value: 00180 00181 NONE. 00182 00183 --*/ 00184 { 00185 UNREFERENCED_PARAMETER(Apc); 00186 UNREFERENCED_PARAMETER(SystemArgument1); 00187 UNREFERENCED_PARAMETER(SystemArgument2); 00188 }

VOID CmpFlushNotify PCM_KEY_BODY  KeyBody  ) 
 

Definition at line 1235 of file cmnotify.c.

References ASSERT, ASSERT_CM_LOCK_OWNED, CML_MAJOR, CmLockHive, CMLOG, CmpClearListEntry, CmpInitializeKeyNameString(), CmpPostNotify(), CMS_NOTIFY, CmUnlockHive, DbgPrint, _CM_KEY_CONTROL_BLOCK::Delete, ExAllocatePool, ExFreePool(), FALSE, Hive, _CM_NOTIFY_BLOCK::HiveList, HiveList, _CM_KEY_BODY::KeyControlBlock, _CM_KEY_CONTROL_BLOCK::KeyHive, KeyName, _CM_KEY_CONTROL_BLOCK::KeyNode, MAX_KEY_NAME_LENGTH, _CM_KEY_BODY::NotifyBlock, NULL, PAGED_CODE, PagedPool, _CM_NOTIFY_BLOCK::PostList, SeReleaseSubjectContext(), and _CM_NOTIFY_BLOCK::SubjectContext.

Referenced by CmDeleteKey(), CmpDeleteKeyObject(), CmpRefreshHive(), and NtUnloadKey().

01240 : 01241 01242 Clean up notifyblock when a handle is closed or the key it refers 01243 to is deleted. 01244 01245 Arguments: 01246 01247 KeyBody - supplies pointer to key object body for handle we 01248 are cleaning up. 01249 01250 Return Value: 01251 01252 NONE 01253 01254 --*/ 01255 { 01256 PCM_NOTIFY_BLOCK NotifyBlock; 01257 PCMHIVE Hive; 01258 01259 PAGED_CODE(); 01260 ASSERT_CM_LOCK_OWNED(); 01261 01262 if (KeyBody->NotifyBlock == NULL) { 01263 return; 01264 } 01265 01266 #ifdef KCB_TO_KEYBODY_LINK 01267 ASSERT( KeyBody->KeyControlBlock->Delete == FALSE ); 01268 #endif 01269 01270 CMLOG(CML_MAJOR, CMS_NOTIFY) { 01271 #if DBG 01272 WCHAR *NameBuffer = NULL; 01273 UNICODE_STRING KeyName; 01274 01275 KdPrint(("[CM]CmpFlushNotify: NotifyBlock = %08lx\n",KeyBody->NotifyBlock)); 01276 NameBuffer = ExAllocatePool(PagedPool, MAX_KEY_NAME_LENGTH); 01277 if(NameBuffer && KeyBody->KeyControlBlock->KeyNode) { 01278 CmpInitializeKeyNameString(KeyBody->KeyControlBlock->KeyNode,&KeyName,NameBuffer); 01279 KdPrint(("\t[CM]CmpFlushNotify: Key = %.*S\n",KeyName.Length / sizeof(WCHAR),KeyName.Buffer)); 01280 ExFreePool(NameBuffer); 01281 } 01282 #endif 01283 } 01284 01285 // 01286 // Lock the hive exclusively to prevent multiple threads from whacking 01287 // on the list. 01288 // 01289 Hive = CONTAINING_RECORD(KeyBody->KeyControlBlock->KeyHive, 01290 CMHIVE, 01291 Hive); 01292 CmLockHive(Hive); 01293 // 01294 // Reread the notify block in case it has already been freed. 01295 // 01296 NotifyBlock = KeyBody->NotifyBlock; 01297 if (NotifyBlock == NULL) { 01298 CmUnlockHive(Hive); 01299 return; 01300 } 01301 01302 // 01303 // Clean up all PostBlocks waiting on the NotifyBlock 01304 // 01305 if (IsListEmpty(&(NotifyBlock->PostList)) == FALSE) { 01306 CmpPostNotify( 01307 NotifyBlock, 01308 NULL, 01309 0, 01310 STATUS_NOTIFY_CLEANUP, 01311 NULL 01312 ); 01313 } 01314 01315 // 01316 // Release the subject context 01317 // 01318 SeReleaseSubjectContext(&NotifyBlock->SubjectContext); 01319 01320 // 01321 // IMPLEMENTATION NOTE: 01322 // If we ever do code to report names and types of events, 01323 // this is the place to free the buffer. 01324 // 01325 01326 // 01327 // Remove the NotifyBlock from the hive chain 01328 // 01329 NotifyBlock->HiveList.Blink->Flink = NotifyBlock->HiveList.Flink; 01330 if (NotifyBlock->HiveList.Flink != NULL) { 01331 NotifyBlock->HiveList.Flink->Blink = NotifyBlock->HiveList.Blink; 01332 } 01333 01334 // Protect for multiple deletion of the same object 01335 CmpClearListEntry(&(NotifyBlock->HiveList)); 01336 01337 KeyBody->NotifyBlock = NULL; 01338 01339 #ifdef _CM_ENTRYLIST_MANIPULATION 01340 if (IsListEmpty(&(NotifyBlock->PostList)) == FALSE) { 01341 DbgPrint("CmpFlushNotify: NotifyBlock %08lx\n",NotifyBlock); 01342 DbgBreakPoint(); 01343 } 01344 //check is the notify has been deleted from the hive notify list 01345 { 01346 PCM_NOTIFY_BLOCK ValidNotifyBlock; 01347 PLIST_ENTRY NotifyPtr; 01348 01349 NotifyPtr = &(Hive->NotifyList); 01350 01351 while (NotifyPtr->Flink != NULL) { 01352 NotifyPtr = NotifyPtr->Flink; 01353 01354 ValidNotifyBlock = CONTAINING_RECORD(NotifyPtr, CM_NOTIFY_BLOCK, HiveList); 01355 if( ValidNotifyBlock == NotifyBlock ) { 01356 DbgPrint("CmpFlushNotify: NotifyBlock %08lx is about to be deleted but is still in the hive notify list\n",NotifyBlock); 01357 DbgBreakPoint(); 01358 } 01359 } 01360 } 01361 RtlZeroMemory((PVOID)NotifyBlock, sizeof(CM_NOTIFY_BLOCK)); 01362 #endif 01363 01364 CmUnlockHive(Hive); 01365 01366 // 01367 // Free the block, clean up the KeyBody 01368 // 01369 ExFreePool(NotifyBlock); 01370 return; 01371 }

VOID CmpFreeSlavePost PCM_POST_BLOCK  MasterPostBlock  ) 
 

Definition at line 1634 of file cmnotify.c.

References ASSERT, _CM_POST_BLOCK::CancelPostList, CML_MAJOR, CMLOG, CmpFreePostBlock(), CmpRemoveEntryList, CMS_NOTIFY, IsMasterPostBlock, PAGED_CODE, _CM_POST_BLOCK::ThreadList, and TRUE.

Referenced by CmNotifyRunDown(), CmpPostApc(), and CmpPostApcRunDown().

01639 : 01640 01641 Free the slave post block related to this master post block 01642 01643 Arguments: 01644 01645 MasterPostBlock - pointer to structure that describes the post requests. 01646 It should be a master post!! 01647 Return Value: 01648 01649 NONE. 01650 01651 --*/ 01652 { 01653 PCM_POST_BLOCK SlavePostBlock; 01654 01655 PAGED_CODE(); 01656 CMLOG(CML_MAJOR, CMS_NOTIFY) { 01657 KdPrint(("CmpCancelSlavePost:\t")); 01658 KdPrint(("MasterPostBlock:%08lx\n", MasterPostBlock)); 01659 } 01660 01661 ASSERT(IsMasterPostBlock(MasterPostBlock)); 01662 01663 CMLOG(CML_MAJOR, CMS_NOTIFY) { 01664 #if DBG 01665 if(MasterPostBlock->TraceIntoDebugger) { 01666 KdPrint(("[CM]CmCancelSlavePost: MasterPostBlock:%08lx\n", MasterPostBlock)); 01667 } 01668 #endif 01669 } 01670 01671 if (IsListEmpty(&(MasterPostBlock->CancelPostList)) == TRUE) { 01672 // 01673 // Nothing to cancel, just return 01674 // 01675 CMLOG(CML_MAJOR, CMS_NOTIFY) { 01676 #if DBG 01677 if(MasterPostBlock->TraceIntoDebugger) { 01678 KdPrint(("[CM]CmCancelSlavePost: MasterPostBlock:%08lx has no slaves\n", MasterPostBlock)); 01679 } 01680 #endif 01681 } 01682 01683 return; 01684 } 01685 01686 01687 // 01688 // Pull all the entries in the cancel post list and unlink them (when they are slave requests) 01689 // We base here on the assumption that there is only one slave. 01690 // 01691 // NOTE!!! 01692 // When more than slave allowed, here to modify 01693 // 01694 01695 01696 SlavePostBlock = (PCM_POST_BLOCK)MasterPostBlock->CancelPostList.Flink; 01697 SlavePostBlock = CONTAINING_RECORD(SlavePostBlock, 01698 CM_POST_BLOCK, 01699 CancelPostList); 01700 01701 CMLOG(CML_MAJOR, CMS_NOTIFY) { 01702 #if DBG 01703 if(MasterPostBlock->TraceIntoDebugger) { 01704 KdPrint(("[CM]CmCancelSlavePost: Cleaning SlavePostBlock:%08lx\n", SlavePostBlock)); 01705 } 01706 #endif 01707 } 01708 01709 // 01710 // This should be true ! 01711 // 01712 ASSERT( !IsMasterPostBlock(SlavePostBlock) ); 01713 01714 // 01715 // Unchain from the Master CancelPostList 01716 // 01717 // Use Cmp variant to protect for multiple deletion of the same object 01718 CmpRemoveEntryList(&(SlavePostBlock->CancelPostList)); 01719 01720 // 01721 // delist the post block from the thread postblocklist 01722 // 01723 // Use Cmp variant to protect for multiple deletion of the same object 01724 CmpRemoveEntryList(&(SlavePostBlock->ThreadList)); 01725 01726 // 01727 // Free the post block. 01728 // 01729 CmpFreePostBlock(SlavePostBlock); 01730 01731 // 01732 // Result validation. was it the only slave? 01733 // 01734 ASSERT(IsListEmpty(&(MasterPostBlock->CancelPostList))); 01735 }

NTSTATUS CmpNotifyChangeKey IN PCM_KEY_BODY  KeyBody,
IN PCM_POST_BLOCK  PostBlock,
IN ULONG  CompletionFilter,
IN BOOLEAN  WatchTree,
IN PVOID  Buffer,
IN ULONG  BufferSize,
IN PCM_POST_BLOCK  MasterPostBlock
 

Definition at line 1378 of file cmnotify.c.

References APC_LEVEL, ASSERT, ASSERT_CM_LOCK_OWNED_EXCLUSIVE, CM_NOTIFY_BLOCK, CML_MINOR, CML_WORKER, CMLOG, CmpFreePostBlock(), CmpInitializeKeyNameString(), CmpPostNotify(), CMS_NOTIFY, CMS_POOL, ExAllocatePool, ExAllocatePoolWithQuotaTag, ExFreePool(), FALSE, _CM_NOTIFY_BLOCK::Filter, Hive, _CM_NOTIFY_BLOCK::HiveList, HiveList, IsMasterPostBlock, KeLowerIrql(), KeRaiseIrql(), _CM_NOTIFY_BLOCK::KeyBody, _CM_NOTIFY_BLOCK::KeyControlBlock, KeyName, MAX_KEY_NAME_LENGTH, _CM_NOTIFY_BLOCK::NotifyPending, NULL, PAGED_CODE, PagedPool, POOL_QUOTA_FAIL_INSTEAD_OF_RAISE, _CM_NOTIFY_BLOCK::PostList, PsGetCurrentThread, SeCaptureSubjectContext(), _CM_NOTIFY_BLOCK::SubjectContext, _CM_KEY_CONTROL_BLOCK::TotalLevels, TRUE, WatchTree, and _CM_NOTIFY_BLOCK::WatchTree.

Referenced by NtNotifyChangeMultipleKeys().

01389 : 01390 01391 This routine sets up the NotifyBlock, and attaches the PostBlock 01392 to it. When it returns, the Notify is visible to the system, 01393 and will receive event reports. 01394 01395 If there is already an event report pending, then the notify 01396 call will be satisified at once. 01397 01398 Arguments: 01399 01400 KeyBody - pointer to key object that handle refers to, allows access 01401 to key control block, notify block, etc. 01402 01403 PostBlock - pointer to structure that describes how/where the caller 01404 is to be notified. 01405 01406 WARNING: PostBlock must come from Pool, THIS routine 01407 will keep it, back side will free it. This 01408 routine WILL free it in case of error. 01409 01410 CompletionFilter - what types of events the caller wants to see 01411 01412 WatchTree - TRUE to watch whole subtree, FALSE to watch only immediate 01413 key the notify is applied to 01414 01415 Buffer - pointer to area to recieve notify data 01416 01417 BufferSize - size of buffer, also size user would like to allocate 01418 for internal buffer 01419 01420 MasterPostBlock - the post block of the master notification. Used to 01421 insert the PostBlock into the CancelPostList list. 01422 01423 Return Value: 01424 01425 Status. 01426 01427 --*/ 01428 { 01429 PCM_NOTIFY_BLOCK NotifyBlock; 01430 PCM_NOTIFY_BLOCK node; 01431 PLIST_ENTRY ptr; 01432 PCMHIVE Hive; 01433 KIRQL OldIrql; 01434 01435 PAGED_CODE(); 01436 CMLOG(CML_WORKER, CMS_NOTIFY) { 01437 KdPrint(("CmpNotifyChangeKey:\n")); 01438 KdPrint(("\tKeyBody:%08lx PostBlock:%08lx ", KeyBody, PostBlock)); 01439 KdPrint(("Filter:%08lx WatchTree:%08lx\n", CompletionFilter, WatchTree)); 01440 #if DBG 01441 if(PostBlock->TraceIntoDebugger) { 01442 WCHAR *NameBuffer = NULL; 01443 UNICODE_STRING KeyName; 01444 01445 KdPrint(("[CM]CmpNotifyChangeKey: PostBlock:%08lx\tMasterBlock: %08lx\n", PostBlock,MasterPostBlock)); 01446 NameBuffer = ExAllocatePool(PagedPool, MAX_KEY_NAME_LENGTH); 01447 if(NameBuffer&&KeyBody->KeyControlBlock->KeyNode) { 01448 CmpInitializeKeyNameString(KeyBody->KeyControlBlock->KeyNode,&KeyName,NameBuffer); 01449 KdPrint(("\t[CM]CmpNotifyChangeKey: Key = %.*S\n",KeyName.Length / sizeof(WCHAR),KeyName.Buffer)); 01450 ExFreePool(NameBuffer); 01451 } 01452 } 01453 #endif 01454 } 01455 01456 // 01457 // The registry lock should be aquired exclusively by the caller !!! 01458 // 01459 ASSERT_CM_LOCK_OWNED_EXCLUSIVE(); 01460 01461 if (KeyBody->KeyControlBlock->Delete) { 01462 #ifdef KCB_TO_KEYBODY_LINK 01463 ASSERT( KeyBody->NotifyBlock == NULL ); 01464 #endif 01465 CmpFreePostBlock(PostBlock); 01466 return STATUS_KEY_DELETED; 01467 } 01468 01469 Hive = (PCMHIVE)KeyBody->KeyControlBlock->KeyHive; 01470 Hive = CONTAINING_RECORD(Hive, CMHIVE, Hive); 01471 NotifyBlock = KeyBody->NotifyBlock; 01472 01473 if (NotifyBlock == NULL) { 01474 // 01475 // Set up new notify session 01476 // 01477 NotifyBlock = ExAllocatePoolWithQuotaTag(PagedPool|POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,sizeof(CM_NOTIFY_BLOCK),CM_NOTIFYBLOCK_TAG); 01478 CMLOG(CML_MINOR, CMS_POOL) { 01479 KdPrint(("**CmpNotifyChangeKey: allocate:%08lx, ", sizeof(CM_NOTIFY_BLOCK))); 01480 KdPrint(("type:%d, at:%08lx\n", PagedPool, NotifyBlock)); 01481 } 01482 01483 if (NotifyBlock == NULL) { 01484 CmpFreePostBlock(PostBlock); 01485 return STATUS_INSUFFICIENT_RESOURCES; 01486 } 01487 NotifyBlock->KeyControlBlock = KeyBody->KeyControlBlock; 01488 NotifyBlock->Filter = CompletionFilter; 01489 NotifyBlock->WatchTree = WatchTree; 01490 NotifyBlock->NotifyPending = FALSE; 01491 InitializeListHead(&(NotifyBlock->PostList)); 01492 KeyBody->NotifyBlock = NotifyBlock; 01493 NotifyBlock->KeyBody = KeyBody; 01494 ASSERT( KeyBody->KeyControlBlock->Delete == FALSE ); 01495 01496 CMLOG(CML_WORKER, CMS_NOTIFY) { 01497 #if DBG 01498 if(PostBlock->TraceIntoDebugger) { 01499 WCHAR *NameBuffer = NULL; 01500 UNICODE_STRING KeyName; 01501 01502 NameBuffer = ExAllocatePool(PagedPool, MAX_KEY_NAME_LENGTH); 01503 if(NameBuffer) { 01504 CmpInitializeKeyNameString(KeyBody->KeyControlBlock->KeyNode,&KeyName,NameBuffer); 01505 KdPrint(("[CM]\tCmpNotifyChangeKey: New NotifyBlock at:%08lx was allocated for Key = %.*S\n",NotifyBlock,KeyName.Length / sizeof(WCHAR),KeyName.Buffer)); 01506 ExFreePool(NameBuffer); 01507 } 01508 } 01509 #endif 01510 } 01511 01512 // 01513 // IMPLEMENTATION NOTE: 01514 // If we ever want to actually return the buffers full of 01515 // data, the buffer should be allocated and its address 01516 // stored in the notify block here. 01517 // 01518 01519 // 01520 // Capture the subject context so we can do checking once the 01521 // notify goes off. 01522 // 01523 SeCaptureSubjectContext(&NotifyBlock->SubjectContext); 01524 01525 // 01526 // Attach notify block to hive in properly sorted order 01527 // 01528 ptr = &(Hive->NotifyList); 01529 while (TRUE) { 01530 if (ptr->Flink == NULL) { 01531 // 01532 // End of list, add self after ptr. 01533 // 01534 ptr->Flink = &(NotifyBlock->HiveList); 01535 NotifyBlock->HiveList.Flink = NULL; 01536 NotifyBlock->HiveList.Blink = ptr; 01537 break; 01538 } 01539 01540 ptr = ptr->Flink; 01541 01542 node = CONTAINING_RECORD(ptr, CM_NOTIFY_BLOCK, HiveList); 01543 01544 if (node->KeyControlBlock->TotalLevels > 01545 KeyBody->KeyControlBlock->TotalLevels) 01546 { 01547 // 01548 // ptr -> notify with longer name than us, insert in FRONT 01549 // 01550 NotifyBlock->HiveList.Flink = ptr; 01551 ptr->Blink->Flink = &(NotifyBlock->HiveList); 01552 NotifyBlock->HiveList.Blink = ptr->Blink; 01553 ptr->Blink = &(NotifyBlock->HiveList); 01554 break; 01555 } 01556 } 01557 } 01558 01559 01560 // 01561 // Add post block to front of notify block's list, and add it to thread list. 01562 // 01563 InsertHeadList( 01564 &(NotifyBlock->PostList), 01565 &(PostBlock->NotifyList) 01566 ); 01567 01568 01569 01570 if( IsMasterPostBlock(PostBlock) ) { 01571 // 01572 // Protect against outrageous calls 01573 // 01574 ASSERT(PostBlock == MasterPostBlock); 01575 01576 // 01577 // When the notification is a master one, initialize the CancelPostList list 01578 // 01579 InitializeListHead(&(PostBlock->CancelPostList)); 01580 } else { 01581 // 01582 // Add PostBlock at the end of the CancelPostList list from the master post 01583 // 01584 InsertTailList( 01585 &(MasterPostBlock->CancelPostList), 01586 &(PostBlock->CancelPostList) 01587 ); 01588 } 01589 01590 01591 KeRaiseIrql(APC_LEVEL, &OldIrql); 01592 InsertHeadList( 01593 &(PsGetCurrentThread()->PostBlockList), 01594 &(PostBlock->ThreadList) 01595 ); 01596 01597 CMLOG(CML_WORKER, CMS_NOTIFY) { 01598 #if DBG 01599 if(PostBlock->TraceIntoDebugger) { 01600 KdPrint(("[CM]\tCmpNotifyChangeKey: Attaching the post:%08lx\t to thread:%08lx\n",PostBlock,PsGetCurrentThread())); 01601 } 01602 #endif 01603 } 01604 01605 KeLowerIrql(OldIrql); 01606 01607 // 01608 // If there is a notify pending (will not be if we just created 01609 // the notify block) then post it at once. Note that this call 01610 // ALWAYS returns STATUS_PENDING unless it fails. Caller must 01611 // ALWAYS look in IoStatusBlock to see what happened. 01612 // 01613 if (NotifyBlock->NotifyPending == TRUE) { 01614 CmpPostNotify( 01615 NotifyBlock, 01616 NULL, 01617 0, 01618 STATUS_NOTIFY_ENUM_DIR, 01619 NULL 01620 ); 01621 // 01622 // return STATUS_SUCCESS to signal to the caller the the notify already been triggered 01623 // 01624 return STATUS_SUCCESS; 01625 } 01626 01627 // 01628 // return STATUS_PENDING to signal to the caller the the notify has not been triggered yet 01629 // 01630 return STATUS_PENDING; 01631 }

BOOLEAN CmpNotifyTriggerCheck IN PCM_NOTIFY_BLOCK  NotifyBlock,
IN PHHIVE  Hive,
IN PCM_KEY_NODE  Node
 

Definition at line 281 of file cmnotify.c.

References ASSERT, CM_POST_BLOCK, CmpCheckNotifyAccess(), FALSE, Hive, _CM_POST_BLOCK::NotifyList, PAGED_CODE, POST_BLOCK_TYPE, PostAsyncKernel, PostBlockType, and TRUE.

Referenced by CmpReportNotifyHelper().

00288 : 00289 00290 Checks if a notify can be triggered 00291 00292 Arguments: 00293 00294 NotifyBlock - the notify block 00295 00296 Hive - Supplies hive containing node to match with. 00297 00298 Node - pointer to key to match with (and check access to) 00299 00300 00301 Return Value: 00302 00303 TRUE - yes. 00304 FALSE - no 00305 00306 --*/ 00307 { 00308 PCM_POST_BLOCK PostBlock; 00309 POST_BLOCK_TYPE NotifyType; 00310 00311 PAGED_CODE(); 00312 00313 if(IsListEmpty(&(NotifyBlock->PostList)) == FALSE) { 00314 00315 // 00316 // check if it is a kernel notify. Look at the first post block 00317 // to see that. If is a kernel post-block, then all posts in 00318 // the list should be kernel notifies 00319 // 00320 PostBlock = (PCM_POST_BLOCK)NotifyBlock->PostList.Flink; 00321 PostBlock = CONTAINING_RECORD(PostBlock, 00322 CM_POST_BLOCK, 00323 NotifyList); 00324 00325 NotifyType = PostBlockType(PostBlock); 00326 00327 if( NotifyType == PostAsyncKernel ) { 00328 // this is a kernel notify; always trigger it 00329 #if DBG 00330 // 00331 // DEBUG only code: All post blocks should be of the same type 00332 // (kernel/user) 00333 // 00334 while( PostBlock->NotifyList.Flink != &(NotifyBlock->PostList) ) { 00335 PostBlock = (PCM_POST_BLOCK)PostBlock->NotifyList.Flink; 00336 PostBlock = CONTAINING_RECORD(PostBlock, 00337 CM_POST_BLOCK, 00338 NotifyList); 00339 00340 //KdPrint(("CmpNotifyTriggerCheck : NotifyBlock = %lx\n",NotifyBlock)); 00341 00342 ASSERT( PostBlockType(PostBlock) == NotifyType ); 00343 } 00344 #endif 00345 00346 return TRUE; 00347 } 00348 } 00349 00350 // 00351 // else, check if the caller has the right access 00352 // 00353 return CmpCheckNotifyAccess(NotifyBlock,Hive,Node); 00354 }

VOID CmpPostApc struct _KAPC Apc,
PKNORMAL_ROUTINE NormalRoutine,
PVOID *  NormalContext,
PVOID *  SystemArgument1,
PVOID *  SystemArgument2
 

Definition at line 804 of file cmnotify.c.

References _CM_POST_BLOCK_UNION::AsyncUser, CML_MAJOR, CMLOG, CmpCheckPostBlock, CmpFreePostBlock(), CmpFreeSlavePost(), CmpRemoveEntryList, CmpSetIoStatus, CMS_NOTIFY, EXCEPTION_EXECUTE_HANDLER, FALSE, _CM_ASYNC_USER_POST_BLOCK::IoStatusBlock, KeSetEvent(), L, NULL, ObDereferenceObject, PAGED_CODE, PsGetCurrentProcess, _CM_POST_BLOCK::ThreadList, _CM_POST_BLOCK::u, and _CM_ASYNC_USER_POST_BLOCK::UserEvent.

Referenced by NtNotifyChangeMultipleKeys().

00813 : 00814 00815 This is the kernel apc routine. It is called for all notifies, 00816 regardless of what form of notification the caller requested. 00817 00818 We compute the postblock address from the apc object address. 00819 IoStatus is set. SystemEvent and UserEvent will be signalled 00820 as appropriate. If the user requested an APC, then NormalRoutine 00821 will be set at entry and executed when we exit. The PostBlock 00822 is freed here. 00823 00824 Arguments: 00825 00826 Apc - pointer to apc object 00827 00828 NormalRoutine - Will be called when we return 00829 00830 NormalContext - will be 1st argument to normal routine, ApcContext 00831 passed in when NtNotifyChangeKey was called 00832 00833 SystemArgument1 - IN: Status value for IoStatusBlock 00834 OUT: Ptr to IoStatusBlock (2nd arg to user apc routine) 00835 00836 SystemArgument2 - Pointer to the PostBlock 00837 00838 Return Value: 00839 00840 NONE. 00841 00842 --*/ 00843 { 00844 PCM_POST_BLOCK PostBlock; 00845 00846 PAGED_CODE(); 00847 CMLOG(CML_MAJOR, CMS_NOTIFY) { 00848 KdPrint(("CmpPostApc:\n")); 00849 KdPrint(("\tApc:%08lx ", Apc)); 00850 KdPrint(("NormalRoutine:%08lx\n", NormalRoutine)); 00851 KdPrint(("\tNormalContext:%08lx", NormalContext)); 00852 KdPrint(("\tSystemArgument1=IoStatusBlock:%08lx\n", SystemArgument1)); 00853 } 00854 00855 00856 PostBlock = *(PCM_POST_BLOCK *)SystemArgument2; 00857 00858 CMLOG(CML_MAJOR, CMS_NOTIFY) { 00859 #if DBG 00860 if(PostBlock->TraceIntoDebugger) { 00861 KdPrint(("[CM]CmpPostApc: PostBlock:%08lx\n", PostBlock)); 00862 } 00863 #endif 00864 } 00865 // 00866 // Fill in IO Status Block 00867 // 00868 // IMPLEMENTATION NOTE: 00869 // If we ever want to actually implement the code that returns 00870 // names of things that changed, this is the place to copy the 00871 // buffer into the caller's buffer. 00872 // 00873 // Sundown only: Use a 32bit IO_STATUS_BLOCK if the caller is 32bit. 00874 00875 try { 00876 CmpSetIoStatus(PostBlock->u->AsyncUser.IoStatusBlock, 00877 *((ULONG *)SystemArgument1), 00878 0L, 00879 PsGetCurrentProcess()->Wow64Process != NULL); 00880 } except (EXCEPTION_EXECUTE_HANDLER) { 00881 NOTHING; 00882 } 00883 *SystemArgument1 = PostBlock->u->AsyncUser.IoStatusBlock; 00884 00885 // 00886 // This is an Async notify, do all work here, including 00887 // cleaning up the post block 00888 // 00889 00890 // 00891 // Signal UserEvent if present, and deref it. 00892 // 00893 if (PostBlock->u->AsyncUser.UserEvent != NULL) { 00894 KeSetEvent(PostBlock->u->AsyncUser.UserEvent, 00895 0, 00896 FALSE); 00897 ObDereferenceObject(PostBlock->u->AsyncUser.UserEvent); 00898 } 00899 00900 // 00901 // remove the post block from the thread list, and free it 00902 // 00903 // Use Cmp variant to protect for multiple deletion of the same object 00904 CmpRemoveEntryList(&(PostBlock->ThreadList)); 00905 00906 // debug only checks 00907 CmpCheckPostBlock(PostBlock); 00908 // 00909 // Free the slave post block to avoid "dangling" postblocks 00910 // 00911 CmpFreeSlavePost(PostBlock); 00912 // 00913 // free this post block 00914 // 00915 CmpFreePostBlock(PostBlock); 00916 00917 return; 00918 }

VOID CmpPostApcRunDown struct _KAPC Apc  ) 
 

Definition at line 922 of file cmnotify.c.

References APC_LEVEL, _CM_POST_BLOCK_UNION::AsyncUser, CML_MAJOR, CMLOG, CmpFreePostBlock(), CmpFreeSlavePost(), CmpRemoveEntryList, CmpSetIoStatus, CMS_NOTIFY, EXCEPTION_EXECUTE_HANDLER, FALSE, _CM_ASYNC_USER_POST_BLOCK::IoStatusBlock, KeLowerIrql(), KeRaiseIrql(), KeSetEvent(), L, NULL, ObDereferenceObject, PAGED_CODE, PsGetCurrentProcess, _KAPC::SystemArgument2, _CM_POST_BLOCK::ThreadList, _CM_POST_BLOCK::u, and _CM_ASYNC_USER_POST_BLOCK::UserEvent.

Referenced by NtNotifyChangeMultipleKeys().

00927 : 00928 00929 This routine is called to clear away apcs in the apc queue 00930 of a thread that has been terminated. 00931 00932 Since the apc is in the apc queue, we know that it is NOT in 00933 any NotifyBlock's post list. It is, however, in the threads's 00934 PostBlockList. 00935 00936 Therefore, poke any user events so that waiters are not stuck, 00937 drop the references so the event can be cleaned up, delist the 00938 PostBlock and free it. 00939 00940 Since we are cleaning up the thread, SystemEvents are not interesting. 00941 00942 Since the apc is in the apc queue, we know that if there were any other 00943 notifications related to this one, they are cleaned up by the 00944 CmPostNotify routine 00945 00946 Arguments: 00947 00948 Apc - pointer to apc object 00949 00950 Return Value: 00951 00952 NONE. 00953 00954 --*/ 00955 { 00956 PCM_POST_BLOCK PostBlock; 00957 KIRQL OldIrql; 00958 00959 PAGED_CODE(); 00960 CMLOG(CML_MAJOR, CMS_NOTIFY) { 00961 KdPrint(("CmpApcRunDown:")); 00962 KdPrint(("\tApc:%08lx \n", Apc)); 00963 } 00964 00965 KeRaiseIrql(APC_LEVEL, &OldIrql); 00966 00967 PostBlock = (PCM_POST_BLOCK)Apc->SystemArgument2; 00968 00969 CMLOG(CML_MAJOR, CMS_NOTIFY) { 00970 #if DBG 00971 if(PostBlock->TraceIntoDebugger) { 00972 KdPrint(("[CM]CmpPostApcRunDown: PostBlock:%08lx\n", PostBlock)); 00973 } 00974 #endif 00975 } 00976 00977 // 00978 // report status and wake up any threads that might otherwise 00979 // be stuck. also drop any event references we hold 00980 // 00981 // Sundown only: Use a 32bit IO_STATUS_BLOCK if the caller is 32bit. 00982 00983 try { 00984 CmpSetIoStatus(PostBlock->u->AsyncUser.IoStatusBlock, 00985 STATUS_NOTIFY_CLEANUP, 00986 0L, 00987 PsGetCurrentProcess()->Wow64Process != NULL); 00988 } except (EXCEPTION_EXECUTE_HANDLER) { 00989 NOTHING; 00990 } 00991 00992 if (PostBlock->u->AsyncUser.UserEvent != NULL) { 00993 KeSetEvent( 00994 PostBlock->u->AsyncUser.UserEvent, 00995 0, 00996 FALSE 00997 ); 00998 ObDereferenceObject(PostBlock->u->AsyncUser.UserEvent); 00999 } 01000 01001 // 01002 // delist the post block 01003 // 01004 // Use Cmp variant to protect for multiple deletion of the same object 01005 CmpRemoveEntryList(&(PostBlock->ThreadList)); 01006 01007 // 01008 // Free the slave post block to avoid "dangling" postblocks 01009 // 01010 CmpFreeSlavePost(PostBlock); 01011 // 01012 // Free the post block. Use Ex call because PostBlocks are NOT 01013 // part of the global registry pool computation, but are instead 01014 // part of NonPagedPool with Quota. 01015 // 01016 CmpFreePostBlock(PostBlock); 01017 01018 KeLowerIrql(OldIrql); 01019 01020 return; 01021 }

VOID CmpPostNotify PCM_NOTIFY_BLOCK  NotifyBlock,
PUNICODE_STRING Name  OPTIONAL,
ULONG  Filter,
NTSTATUS  Status,
PLIST_ENTRY ExternalKeyDeref  OPTIONAL
 

Definition at line 487 of file cmnotify.c.

References _CM_ASYNC_USER_POST_BLOCK::Apc, APC_LEVEL, ASSERT, ASSERT_CM_LOCK_OWNED, _CM_POST_BLOCK_UNION::AsyncUser, _CM_POST_BLOCK::CancelPostList, ClearMasterPostBlockFlag, CML_MAJOR, CMLOG, CmpAddToDelayedDeref(), CmpCancelSlavePost(), CmpClearListEntry, CmpDelayedDerefKeys(), CmpFreePostBlock(), CmpInitializeKeyNameString(), CmpRemoveEntryList, CMS_NOTIFY, ExAllocatePool, ExFreePool(), ExQueueWorkItem(), FALSE, Filter, IsMasterPostBlock, KeInsertQueueApc(), KeLowerIrql(), KeRaiseIrql(), KeSetEvent(), _CM_NOTIFY_BLOCK::KeyControlBlock, KeyName, _CM_KEY_CONTROL_BLOCK::KeyNode, LOCK_POST_LIST, MAX_KEY_NAME_LENGTH, Name, _CM_POST_BLOCK::NotifyList, _CM_NOTIFY_BLOCK::NotifyPending, _CM_POST_BLOCK::NotifyType, NULL, ObDereferenceObject, PAGED_CODE, PagedPool, PostAsyncKernel, PostAsyncUser, PostBlockType, _CM_NOTIFY_BLOCK::PostList, PostSynchronous, SetMasterPostBlockFlag, Status, _CM_SYNC_POST_BLOCK::Status, _CM_POST_BLOCK_UNION::Sync, _CM_SYNC_POST_BLOCK::SystemEvent, _CM_POST_BLOCK::ThreadList, TRUE, _CM_POST_BLOCK::u, and UNLOCK_POST_LIST.

Referenced by CmpCloseKeyObject(), CmpFlushNotify(), CmpNotifyChangeKey(), and CmpReportNotifyHelper().

00496 : 00497 00498 Actually report the notify event by signalling events, enqueing 00499 APCs, and so forth. 00500 00501 When Status is STATUS_NOTIFY_CLEANUP: 00502 00503 - if the post block is a slave one, just cancel it. 00504 - if the post block is a master one, cancel all slave post blocks 00505 and trigger event on the master block. 00506 00507 Comments: 00508 00509 This routine is using a "delayed dereferencing" technique to prevent 00510 deadlocks that may appear when a keybody is dereferenced while holding 00511 the post block lock. As for this, a list with keybodies that have to be 00512 dereferenced is constructed while walking the list of postblocks attached 00513 to the current notify block and the related (slave or master) post blocks. 00514 The list is built by tricking postblocks. For all postblock about to be 00515 freed the PostKeyBody member is added to the local list and then set to NULL 00516 on the postblock. This will avoid the key body dereferencing in CmpFreePostBlock. 00517 Instead, after the postblock lock is released, the local list is iterated and 00518 the keybodies are dereferenced and the storage for associated CM_POST_KEY_BODY 00519 objects is freed. 00520 00521 00522 Arguments: 00523 00524 NotifyBlock - pointer to structure that describes the notify 00525 operation. (Where to post to) 00526 00527 Name - name of key at which event occurred. 00528 00529 Filter - nature of event 00530 00531 Status - completion status to report 00532 00533 ExternalKeyDeref - this parameter (when not NULL) specifies that the caller doesn't 00534 want any keybody to be dereferenced while in this routine 00535 00536 Return Value: 00537 00538 NONE. 00539 00540 --*/ 00541 { 00542 PCM_POST_BLOCK PostBlock; 00543 PCM_POST_BLOCK SlavePostBlock; 00544 LIST_ENTRY LocalDelayedDeref; 00545 KIRQL OldIrql; 00546 PLIST_ENTRY DelayedDeref; 00547 00548 Filter; 00549 Name; 00550 00551 PAGED_CODE(); 00552 CMLOG(CML_MAJOR, CMS_NOTIFY) { 00553 KdPrint(("CmpPostNotify:\n")); 00554 KdPrint(("\tNotifyBlock:%08lx ", NotifyBlock)); 00555 KdPrint(("\tName = %wZ\n", Name)); 00556 KdPrint(("\tFilter:%08lx Status=%08lx\n", Filter, Status)); 00557 } 00558 ASSERT_CM_LOCK_OWNED(); 00559 00560 if( ARGUMENT_PRESENT(ExternalKeyDeref) ) { 00561 // 00562 // The caller want to do all keybody dereferencing by himself 00563 // 00564 DelayedDeref = ExternalKeyDeref; 00565 } else { 00566 // local delayed dereferencing (the caller doesn't care!) 00567 DelayedDeref = &LocalDelayedDeref; 00568 InitializeListHead(DelayedDeref); 00569 } 00570 00571 // 00572 // Aquire exclusive access over the postlist(s) 00573 // 00574 LOCK_POST_LIST(); 00575 00576 if (IsListEmpty(&(NotifyBlock->PostList)) == TRUE) { 00577 // 00578 // Nothing to post, set a mark and return 00579 // 00580 NotifyBlock->NotifyPending = TRUE; 00581 UNLOCK_POST_LIST(); 00582 return; 00583 } 00584 NotifyBlock->NotifyPending = FALSE; 00585 00586 // 00587 // IMPLEMENTATION NOTE: 00588 // If we ever want to actually implement the code that returns 00589 // names of things that changed, this is the place to add the 00590 // name and operation type to the buffer. 00591 // 00592 00593 // 00594 // Pull and post all the entries in the post list 00595 // 00596 while (IsListEmpty(&(NotifyBlock->PostList)) == FALSE) { 00597 00598 // 00599 // Remove from the notify block list, and enqueue the apc. 00600 // The apc will remove itself from the thread list 00601 // 00602 PostBlock = (PCM_POST_BLOCK)RemoveHeadList(&(NotifyBlock->PostList)); 00603 PostBlock = CONTAINING_RECORD(PostBlock, 00604 CM_POST_BLOCK, 00605 NotifyList); 00606 00607 // Protect for multiple deletion of the same object 00608 CmpClearListEntry(&(PostBlock->NotifyList)); 00609 00610 CMLOG(CML_MAJOR, CMS_NOTIFY) { 00611 #if DBG 00612 if(PostBlock->TraceIntoDebugger) { 00613 WCHAR *NameBuffer = NULL; 00614 UNICODE_STRING KeyName; 00615 00616 NameBuffer = ExAllocatePool(PagedPool, MAX_KEY_NAME_LENGTH); 00617 if(NameBuffer) { 00618 CmpInitializeKeyNameString(NotifyBlock->KeyControlBlock->KeyNode,&KeyName,NameBuffer); 00619 KdPrint(("[CM]CmpPostNotify: NotifyBlock:%08lx\tKey = %.*S\n",NotifyBlock,KeyName.Length / sizeof(WCHAR),KeyName.Buffer)); 00620 ExFreePool(NameBuffer); 00621 } 00622 KdPrint(("[CM]\tCmpPostNotify: PostBlock:%08lx\n", PostBlock)); 00623 } 00624 #endif 00625 } 00626 00627 if( (Status == STATUS_NOTIFY_CLEANUP) && !IsMasterPostBlock(PostBlock) ) { 00628 // 00629 // Cleanup notification (i.e. the key handle was closed or the key was deleted) 00630 // When the post is a slave one, just cancel it. Canceling means: 00631 // 1. Removing from the notify PostList (aldready done at this point - see above) 00632 // 2. Unchaining from the Master Block CancelPostList 00633 // 3. Delisting from the thread PostBlockList 00634 // 4. Actually freeing the memory 00635 // 00636 00637 // Use Cmp variant to protect for multiple deletion of the same object 00638 CmpRemoveEntryList(&(PostBlock->CancelPostList)); 00639 // 00640 // FIX 289351 00641 // 00642 // Use Cmp variant to protect for multiple deletion of the same object 00643 KeRaiseIrql(APC_LEVEL, &OldIrql); 00644 CmpRemoveEntryList(&(PostBlock->ThreadList)); 00645 KeLowerIrql(OldIrql); 00646 00647 if( PostBlock->NotifyType != PostSynchronous ) { 00648 00649 // add to the deref list and clean the post block 00650 CmpAddToDelayedDeref(PostBlock,DelayedDeref); 00651 00652 // 00653 // Front-end routine will do self cleanup for syncrounous notifications 00654 CmpFreePostBlock(PostBlock); 00655 } 00656 00657 CMLOG(CML_MAJOR, CMS_NOTIFY) { 00658 #if DBG 00659 if(PostBlock->TraceIntoDebugger) { 00660 KdPrint(("[CM]\tCmpPostNotify: PostBlock:%08lx is a slave block,and notify is CLEANUP==> just cleanning\n", PostBlock)); 00661 } 00662 #endif 00663 } 00664 00665 continue; //try the next one 00666 } 00667 00668 // 00669 // Simulate that this block is the master one, so we can free the others 00670 // Doing that will ensure the right memory dealocation when the master 00671 // (from now on this block) will be freed. 00672 // 00673 if(!IsMasterPostBlock(PostBlock)) { 00674 // 00675 // oops.,this is not the master block, we have some more work to do 00676 // 00677 SlavePostBlock = PostBlock; 00678 do { 00679 SlavePostBlock = (PCM_POST_BLOCK)SlavePostBlock->CancelPostList.Flink; 00680 SlavePostBlock = CONTAINING_RECORD(SlavePostBlock, 00681 CM_POST_BLOCK, 00682 CancelPostList); 00683 // 00684 // reset the "master flag" if set 00685 // 00686 ClearMasterPostBlockFlag(SlavePostBlock); 00687 } while (SlavePostBlock != PostBlock); 00688 00689 // 00690 // Make this post block the master one 00691 // 00692 SetMasterPostBlockFlag(PostBlock); 00693 } 00694 00695 CMLOG(CML_MAJOR, CMS_NOTIFY) { 00696 #if DBG 00697 if(PostBlock->TraceIntoDebugger) { 00698 KdPrint(("[CM]\tCmpPostNotify: Master block switched to :%08lx\n", PostBlock)); 00699 } 00700 #endif 00701 } 00702 00703 // 00704 // Cancel all slave Post requests that may be linked to self 00705 // 00706 00707 if( PostBlockType(PostBlock) != PostSynchronous ) { 00708 // 00709 // Front-end routine will do self cleanup for syncrounous notifications 00710 CmpCancelSlavePost(PostBlock,DelayedDeref); 00711 // 00712 // Do the same for the master (in case master and slave got switched) 00713 // This will avoid dereferencing the keybody from CmpPostApc 00714 CmpAddToDelayedDeref(PostBlock,DelayedDeref); 00715 } 00716 00717 switch (PostBlockType(PostBlock)) { 00718 case PostSynchronous: 00719 // 00720 // This is a SYNC notify call. There will be no user event, 00721 // and no user apc routine. Quick exit here, just fill in 00722 // the Status and poke the event. 00723 // 00724 // Holder of the systemevent will wake up and free the 00725 // postblock. If we free it here, we get a race & bugcheck. 00726 // 00727 // Set the flink to NULL so that the front side can tell this 00728 // has been removed if its wait aborts. 00729 // 00730 PostBlock->NotifyList.Flink = NULL; 00731 PostBlock->u->Sync.Status = Status; 00732 KeSetEvent(PostBlock->u->Sync.SystemEvent, 00733 0, 00734 FALSE); 00735 break; 00736 00737 case PostAsyncUser: 00738 // 00739 // Insert the APC into the queue 00740 // 00741 KeInsertQueueApc(PostBlock->u->AsyncUser.Apc, 00742 (PVOID)ULongToPtr(Status), 00743 (PVOID)PostBlock, 00744 0); 00745 break; 00746 00747 case PostAsyncKernel: 00748 // 00749 // Queue the work item, then free the post block. 00750 // 00751 if (PostBlock->u->AsyncKernel.WorkItem != NULL) { 00752 ExQueueWorkItem(PostBlock->u->AsyncKernel.WorkItem, 00753 PostBlock->u->AsyncKernel.QueueType); 00754 } 00755 // 00756 // Signal Event if present, and deref it. 00757 // 00758 if (PostBlock->u->AsyncKernel.Event != NULL) { 00759 KeSetEvent(PostBlock->u->AsyncKernel.Event, 00760 0, 00761 FALSE); 00762 ObDereferenceObject(PostBlock->u->AsyncKernel.Event); 00763 } 00764 00765 // 00766 // Multiple async kernel notification are not allowed 00767 // 00768 ASSERT(IsListEmpty(&(PostBlock->CancelPostList)) == TRUE); 00769 // 00770 // remove the post block from the thread list, and free it 00771 // 00772 // Use Cmp variant to protect for multiple deletion of the same object 00773 KeRaiseIrql(APC_LEVEL, &OldIrql); 00774 CmpRemoveEntryList(&(PostBlock->ThreadList)); 00775 KeLowerIrql(OldIrql); 00776 00777 // it was already added to delayed deref. 00778 CmpFreePostBlock(PostBlock); 00779 break; 00780 } 00781 } 00782 00783 UNLOCK_POST_LIST(); 00784 00785 // 00786 // At this point we have a list of keybody elements that have to be dereferenciated 00787 // and the associated storage for the covering objects freed. The keybodies in this 00788 // list have only one reference count on them (they were referenced only in 00789 // NtNotifyChangeMultipleKeys), dereferencing them here should free the object 00790 // 00791 00792 if( ARGUMENT_PRESENT(ExternalKeyDeref) ) { 00793 // do nothing; the caller wants to handle the dereferenciation by himself! 00794 } else { 00795 // dereferenciate all keybodies in the delayed list 00796 CmpDelayedDerefKeys(DelayedDeref); 00797 } 00798 00799 return; 00800 }

VOID CmpReportNotify PCM_KEY_CONTROL_BLOCK  KeyControlBlock,
PHHIVE  Hive,
HCELL_INDEX  Cell,
ULONG  Filter
 

Definition at line 191 of file cmnotify.c.

00199 : 00200 00201 This routine is called when a notifiable event occurs. It will 00202 apply CmpReportNotifyHelper to the hive the event occured in, 00203 and the master hive if different. 00204 00205 Arguments: 00206 00207 KeyControlBlock - KCB of the key at which the event occured. 00208 For create or delete this is the created or deleted key. 00209 00210 Hive - pointer to hive containing cell of Key at which event occured. 00211 00212 Cell - cell of Key at which event occured 00213 00214 (hive and cell correspond with name.) 00215 00216 Filter - event to be reported 00217 00218 Return Value: 00219 00220 NONE. 00221 00222 --*/ 00223 { 00224 PCM_KEY_NODE pcell; 00225 ULONG flags; 00226 ULONG i; 00227 00228 PAGED_CODE(); 00229 CMLOG(CML_WORKER, CMS_NOTIFY) { 00230 KdPrint(("CmpReportNotify:\n")); 00231 KdPrint(("\tHive:%08lx Cell:%08lx Filter:%08lx\n", Hive, Cell, Filter)); 00232 } 00233 00234 pcell = (PCM_KEY_NODE)HvGetCell(Hive, Cell); 00235 // 00236 // If the operation was create or delete, treat it as a change 00237 // to the parent. 00238 // 00239 if (Filter == REG_NOTIFY_CHANGE_NAME) { 00240 flags = pcell->Flags; 00241 Cell = pcell->Parent; 00242 if (flags & KEY_HIVE_ENTRY) { 00243 Hive = &(CmpMasterHive->Hive); 00244 pcell = (PCM_KEY_NODE)HvGetCell(Hive, Cell); 00245 } 00246 00247 00248 KeyControlBlock = KeyControlBlock->ParentKcb; 00249 00250 // 00251 // if we're at an exit/link node, back up the real node 00252 // that MUST be it's parent. 00253 // 00254 if (pcell->Flags & KEY_HIVE_EXIT) { 00255 Cell = pcell->Parent; 00256 } 00257 pcell = (PCM_KEY_NODE)HvGetCell(Hive, Cell); 00258 } 00259 00260 // 00261 // Report to notifies waiting on the event's hive 00262 // 00263 CmpReportNotifyHelper(KeyControlBlock, Hive, Hive, pcell, Filter); 00264 00265 00266 // 00267 // If containing hive is not the master hive, apply to master hive 00268 // 00269 if (Hive != &(CmpMasterHive->Hive)) { 00270 CmpReportNotifyHelper(KeyControlBlock, 00271 &(CmpMasterHive->Hive), 00272 Hive, 00273 pcell, 00274 Filter); 00275 } 00276 00277 return; 00278 }

VOID CmpReportNotifyHelper PCM_KEY_CONTROL_BLOCK  KeyControlBlock,
IN PHHIVE  SearchHive,
IN PHHIVE  Hive,
IN PCM_KEY_NODE  Node,
IN ULONG  Filter
 

Definition at line 357 of file cmnotify.c.

References APC_LEVEL, CM_NOTIFY_BLOCK, CmpDelayedDerefKeys(), CmpNotifyTriggerCheck(), CmpPostNotify(), Filter, _CM_NOTIFY_BLOCK::Filter, Hive, HiveList, kcb(), KeLowerIrql(), KeRaiseIrql(), _CM_NOTIFY_BLOCK::KeyControlBlock, _CM_KEY_CONTROL_BLOCK::KeyNode, _CMHIVE::NotifyList, NULL, PAGED_CODE, _CM_KEY_CONTROL_BLOCK::TotalLevels, TRUE, USHORT, and _CM_NOTIFY_BLOCK::WatchTree.

Referenced by CmpReportNotify().

00366 : 00367 00368 Scan the list of active notifies for the specified hive. For 00369 any with scope including KeyControlBlock and filter matching 00370 Filter, and with proper security access, post the notify. 00371 00372 Arguments: 00373 00374 Name - canonical path name (as in a key control block) of the key 00375 at which the event occured. (This is the name for 00376 reporting purposes.) 00377 00378 SearchHive - hive to search for matches (which notify list to check) 00379 00380 Hive - Supplies hive containing node to match with. 00381 00382 Node - pointer to key to match with (and check access to) 00383 00384 Filter - type of event 00385 00386 Return Value: 00387 00388 NONE. 00389 00390 --*/ 00391 { 00392 PLIST_ENTRY NotifyPtr; 00393 PCM_NOTIFY_BLOCK NotifyBlock; 00394 PCMHIVE CmSearchHive; 00395 PUNICODE_STRING NotifyName; 00396 KIRQL OldIrql; 00397 LIST_ENTRY DelayedDeref; 00398 00399 PAGED_CODE(); 00400 00401 KeRaiseIrql(APC_LEVEL, &OldIrql); 00402 00403 CmSearchHive = CONTAINING_RECORD(SearchHive, CMHIVE, Hive); 00404 00405 NotifyPtr = &(CmSearchHive->NotifyList); 00406 00407 InitializeListHead(&(DelayedDeref)); 00408 00409 while (NotifyPtr->Flink != NULL) { 00410 00411 NotifyPtr = NotifyPtr->Flink; 00412 00413 NotifyBlock = CONTAINING_RECORD(NotifyPtr, CM_NOTIFY_BLOCK, HiveList); 00414 if (NotifyBlock->KeyControlBlock->TotalLevels > KeyControlBlock->TotalLevels) { 00415 // 00416 // list is level sorted, we're past all shorter entries 00417 // 00418 break; 00419 } else { 00420 PCM_KEY_CONTROL_BLOCK kcb; 00421 USHORT LevelDiff, l; 00422 00423 LevelDiff = KeyControlBlock->TotalLevels - NotifyBlock->KeyControlBlock->TotalLevels; 00424 00425 kcb = KeyControlBlock; 00426 for (l=0; l<LevelDiff; l++) { 00427 kcb = kcb->ParentKcb; 00428 } 00429 00430 if (kcb == NotifyBlock->KeyControlBlock) { 00431 // 00432 // This Notify path is the prefix of this kcb. 00433 // 00434 if ((NotifyBlock->Filter & Filter) 00435 && 00436 ((NotifyBlock->WatchTree == TRUE) || 00437 (Node == NotifyBlock->KeyControlBlock->KeyNode)) 00438 ) 00439 { 00440 // Filter matches, this event is relevent to this notify 00441 // AND 00442 // Either the notify spans the whole subtree, or the cell 00443 // (key) of interest is the one it applies to 00444 // 00445 // THEREFORE: The notify is relevent. 00446 // 00447 00448 // 00449 // Correct scope, does caller have access? 00450 // 00451 if (CmpNotifyTriggerCheck(NotifyBlock,Hive,Node)) { 00452 // 00453 // Notify block has KEY_NOTIFY access to the node 00454 // the event occured at. It is relevent. Therefore, 00455 // it gets to see this event. Post and be done. 00456 // 00457 // we specify that we want no key body dereferenciation 00458 // during the CmpPostNotify call. This is to prevent the 00459 // deletion of the current notify block 00460 // 00461 CmpPostNotify( 00462 NotifyBlock, 00463 NULL, 00464 Filter, 00465 STATUS_NOTIFY_ENUM_DIR, 00466 &DelayedDeref 00467 ); 00468 00469 } // else no KEY_NOTIFY access to node event occured at 00470 } // else not relevent (wrong scope, filter, etc) 00471 } 00472 } 00473 } 00474 00475 // 00476 // finish the job started in CmpPostNotify (i.e. dereference the keybodies 00477 // we prevented. this may cause some notifyblocks to be freed 00478 // 00479 CmpDelayedDerefKeys(&DelayedDeref); 00480 00481 KeLowerIrql(OldIrql); 00482 return; 00483 }


Variable Documentation

PCMHIVE CmpMasterHive
 

Definition at line 93 of file cmnotify.c.


Generated on Sat May 15 19:43:09 2004 for test by doxygen 1.3.7