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.

338 lines
9.0 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. cmdelete.c
  5. Abstract:
  6. This module contains the delete object method (used to delete key
  7. control blocks when last handle to a key is closed, and to delete
  8. keys marked for deletetion when last reference to them goes away.)
  9. Author:
  10. Bryan M. Willman (bryanwi) 13-Nov-91
  11. Revision History:
  12. --*/
  13. #include "cmp.h"
  14. extern BOOLEAN HvShutdownComplete;
  15. #ifdef NT_UNLOAD_KEY_EX
  16. VOID
  17. CmpLateUnloadHiveWorker(
  18. IN PVOID Hive
  19. );
  20. #endif //NT_UNLOAD_KEY_EX
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text(PAGE,CmpDeleteKeyObject)
  23. #ifdef NT_UNLOAD_KEY_EX
  24. #pragma alloc_text(PAGE,CmpLateUnloadHiveWorker)
  25. #endif //NT_UNLOAD_KEY_EX
  26. #endif
  27. VOID
  28. CmpDeleteKeyObject(
  29. IN PVOID Object
  30. )
  31. /*++
  32. Routine Description:
  33. This routine interfaces to the NT Object Manager. It is invoked when
  34. the last reference to a particular Key object (or Key Root object)
  35. is destroyed.
  36. If the Key object going away holds the last reference to
  37. the extension it is associated with, that extension is destroyed.
  38. Arguments:
  39. Object - supplies a pointer to a KeyRoot or Key, thus -> KEY_BODY.
  40. Return Value:
  41. NONE.
  42. --*/
  43. {
  44. PCM_KEY_CONTROL_BLOCK KeyControlBlock;
  45. PCM_KEY_BODY KeyBody;
  46. #ifdef NT_UNLOAD_KEY_EX
  47. PCMHIVE CmHive;
  48. BOOLEAN DoUnloadCheck;
  49. #endif //NT_UNLOAD_KEY_EX
  50. PAGED_CODE();
  51. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"CmpDeleteKeyObject: Object = %p\n", Object));
  52. //
  53. // HandleClose callback
  54. //
  55. if ( CmAreCallbacksRegistered() ) {
  56. REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo;
  57. KeyHandleCloseInfo.Object = Object;
  58. CmpCallCallBacks(RegNtKeyHandleClose,&KeyHandleCloseInfo);
  59. }
  60. BEGIN_LOCK_CHECKPOINT;
  61. CmpLockRegistry();
  62. #ifdef NT_UNLOAD_KEY_EX
  63. DoUnloadCheck = FALSE;
  64. #endif //NT_UNLOAD_KEY_EX
  65. KeyBody = (PCM_KEY_BODY)Object;
  66. if (KeyBody->Type==KEY_BODY_TYPE) {
  67. KeyControlBlock = KeyBody->KeyControlBlock;
  68. //
  69. // the keybody should be initialized; when kcb is null, something went wrong
  70. // between the creation and the dereferenciation of the object
  71. //
  72. if( KeyControlBlock != NULL ) {
  73. //
  74. // Clean up any outstanding notifies attached to the KeyBody
  75. //
  76. CmpFlushNotify(KeyBody);
  77. //
  78. // Remove our reference to the KeyControlBlock, clean it up, perform any
  79. // pend-till-final-close operations.
  80. //
  81. // NOTE: Delete notification is seen at the parent of the deleted key,
  82. // not the deleted key itself. If any notify was outstanding on
  83. // this key, it was cleared away above us. Only parent/ancestor
  84. // keys will see the report.
  85. //
  86. //
  87. // The dereference will free the KeyControlBlock. If the key was deleted, it
  88. // has already been removed from the hash table, and relevent notifications
  89. // posted then as well. All we are doing is freeing the tombstone.
  90. //
  91. // If it was not deleted, we're both cutting the kcb out of
  92. // the kcb list/tree, AND freeing its storage.
  93. //
  94. DELIST_KEYBODY_FROM_KEYBODY_LIST(KeyBody);
  95. //
  96. // change of plans. once locked, the kcb will be locked for as long as the machine is up&running
  97. //
  98. /*
  99. BEGIN_KCB_LOCK_GUARD;
  100. CmpLockKCBTreeExclusive();
  101. if(IsListEmpty(&(KeyBody->KeyControlBlock->KeyBodyListHead)) == TRUE) {
  102. //
  103. // remove the read-only flag on the kcb (if any); as last handle to this key was closed
  104. //
  105. KeyControlBlock->ExtFlags &= (~CM_KCB_READ_ONLY_KEY);
  106. }
  107. CmpUnlockKCBTree();
  108. END_KCB_LOCK_GUARD
  109. */
  110. #ifdef NT_UNLOAD_KEY_EX
  111. //
  112. // take aditional precaution in the case the hive has been unloaded and this is the root
  113. //
  114. if( !KeyControlBlock->Delete ) {
  115. CmHive = (PCMHIVE)CONTAINING_RECORD(KeyControlBlock->KeyHive, CMHIVE, Hive);
  116. if( IsHiveFrozen(CmHive) ) {
  117. //
  118. // unload is pending for this hive;
  119. //
  120. DoUnloadCheck = TRUE;
  121. }
  122. }
  123. #endif //NT_UNLOAD_KEY_EX
  124. CmpDereferenceKeyControlBlock(KeyControlBlock);
  125. }
  126. } else {
  127. //
  128. // This must be a predefined handle
  129. // some sanity asserts
  130. //
  131. KeyControlBlock = KeyBody->KeyControlBlock;
  132. ASSERT( KeyBody->Type&REG_PREDEF_HANDLE_MASK);
  133. ASSERT( KeyControlBlock->Flags&KEY_PREDEF_HANDLE );
  134. if( KeyControlBlock != NULL ) {
  135. #ifdef NT_UNLOAD_KEY_EX
  136. CmHive = (PCMHIVE)CONTAINING_RECORD(KeyControlBlock->KeyHive, CMHIVE, Hive);
  137. if( IsHiveFrozen(CmHive) ) {
  138. //
  139. // unload is pending for this hive; we shouldn't put the kcb in the delay
  140. // close table
  141. //
  142. DoUnloadCheck = TRUE;
  143. }
  144. #endif //NT_UNLOAD_KEY_EX
  145. CmpDereferenceKeyControlBlock(KeyControlBlock);
  146. }
  147. }
  148. #ifdef NT_UNLOAD_KEY_EX
  149. //
  150. // if a handle inside a frozen hive has been closed, we may need to unload the hive
  151. //
  152. if( DoUnloadCheck == TRUE ) {
  153. ASSERT( CmHive->RootKcb != NULL );
  154. BEGIN_KCB_LOCK_GUARD;
  155. CmpLockKCBTree();
  156. CmLockHive(CmHive);
  157. if( (CmHive->RootKcb->RefCount == 1) && (CmHive->UnloadWorkItem == NULL) ) {
  158. //
  159. // the only reference on the rookcb is the one that we artificially created
  160. // queue a work item to late unload the hive
  161. //
  162. CmHive->UnloadWorkItem = ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM));
  163. if (CmHive->UnloadWorkItem != NULL) {
  164. ExInitializeWorkItem(CmHive->UnloadWorkItem,
  165. CmpLateUnloadHiveWorker,
  166. CmHive);
  167. ExQueueWorkItem(CmHive->UnloadWorkItem, DelayedWorkQueue);
  168. }
  169. }
  170. CmUnlockHive(CmHive);
  171. CmpUnlockKCBTree();
  172. END_KCB_LOCK_GUARD;
  173. }
  174. #endif //NT_UNLOAD_KEY_EX
  175. CmpUnlockRegistry();
  176. END_LOCK_CHECKPOINT;
  177. return;
  178. }
  179. #ifdef NT_UNLOAD_KEY_EX
  180. VOID
  181. CmpLateUnloadHiveWorker(
  182. IN PVOID Hive
  183. )
  184. /*++
  185. Routine Description:
  186. "Late" unloads the hive; If nothing goes badly wrong (i.e. insufficient resources),
  187. this function should succeed
  188. Arguments:
  189. CmHive - the frozen hive to be unloaded
  190. Return Value:
  191. NONE.
  192. --*/
  193. {
  194. NTSTATUS Status;
  195. HCELL_INDEX Cell;
  196. PCM_KEY_CONTROL_BLOCK RootKcb;
  197. PCMHIVE CmHive;
  198. PAGED_CODE();
  199. //
  200. // first, load the registry exclusive
  201. //
  202. CmpLockRegistryExclusive();
  203. #ifdef CHECK_REGISTRY_USECOUNT
  204. CmpCheckRegistryUseCount();
  205. #endif //CHECK_REGISTRY_USECOUNT
  206. //
  207. // hive is the parameter to this worker; make sure we free the work item
  208. // allocated by CmpDeleteKeyObject
  209. //
  210. CmHive = (PCMHIVE)Hive;
  211. ASSERT( CmHive->UnloadWorkItem != NULL );
  212. ExFreePool( CmHive->UnloadWorkItem );
  213. //
  214. // if this attempt doesn't succeed, mark that we can try another
  215. //
  216. CmHive->UnloadWorkItem = NULL;
  217. //
  218. // this is just about the only possible way the hive can get corrupted in between
  219. //
  220. if( HvShutdownComplete == TRUE ) {
  221. // too late to do anything
  222. CmpUnlockRegistry();
  223. return;
  224. }
  225. //
  226. // hive should be frozen, otherwise we wouldn't get here
  227. //
  228. ASSERT( CmHive->Frozen == TRUE );
  229. RootKcb = CmHive->RootKcb;
  230. //
  231. // root kcb must be valid and has only our "artificial" refcount on it
  232. //
  233. ASSERT( RootKcb != NULL );
  234. if( RootKcb->RefCount > 1 ) {
  235. //
  236. // somebody else must've gotten in between dropping/reacquiring the reglock
  237. // and opened a handle inside this hive; bad luck, we can't unload
  238. //
  239. CmpUnlockRegistry();
  240. return;
  241. }
  242. ASSERT_KCB(RootKcb);
  243. Cell = RootKcb->KeyCell;
  244. Status = CmUnloadKey(&(CmHive->Hive),Cell,RootKcb);
  245. ASSERT( (Status != STATUS_CANNOT_DELETE) && (Status != STATUS_INVALID_PARAMETER) );
  246. if(NT_SUCCESS(Status)) {
  247. //
  248. // Mark the root kcb as deleted so that it won't get put on the delayed close list.
  249. //
  250. RootKcb->Delete = TRUE;
  251. //
  252. // If the parent has the subkey info or hint cached, free it.
  253. //
  254. CmpCleanUpSubKeyInfo(RootKcb->ParentKcb);
  255. CmpRemoveKeyControlBlock(RootKcb);
  256. CmpDereferenceKeyControlBlockWithLock(RootKcb);
  257. }
  258. CmpUnlockRegistry();
  259. }
  260. #endif //NT_UNLOAD_KEY_EX