Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

345 lines
9.8 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 = NULL;
  48. BOOLEAN DoUnloadCheck = FALSE;
  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(RegNtPreKeyHandleClose,&KeyHandleCloseInfo);
  59. }
  60. BEGIN_LOCK_CHECKPOINT;
  61. CmpLockRegistry();
  62. KeyBody = (PCM_KEY_BODY)Object;
  63. if (KeyBody->Type==KEY_BODY_TYPE) {
  64. KeyControlBlock = KeyBody->KeyControlBlock;
  65. //
  66. // the keybody should be initialized; when kcb is null, something went wrong
  67. // between the creation and the dereferenciation of the object
  68. //
  69. if( KeyControlBlock != NULL ) {
  70. //
  71. // Clean up any outstanding notifies attached to the KeyBody
  72. //
  73. CmpFlushNotify(KeyBody,FALSE);
  74. //
  75. // Remove our reference to the KeyControlBlock, clean it up, perform any
  76. // pend-till-final-close operations.
  77. //
  78. // NOTE: Delete notification is seen at the parent of the deleted key,
  79. // not the deleted key itself. If any notify was outstanding on
  80. // this key, it was cleared away above us. Only parent/ancestor
  81. // keys will see the report.
  82. //
  83. //
  84. // The dereference will free the KeyControlBlock. If the key was deleted, it
  85. // has already been removed from the hash table, and relevent notifications
  86. // posted then as well. All we are doing is freeing the tombstone.
  87. //
  88. // If it was not deleted, we're both cutting the kcb out of
  89. // the kcb list/tree, AND freeing its storage.
  90. //
  91. BEGIN_KCB_LOCK_GUARD;
  92. CmpLockKCBTree();
  93. CmpLockKCB(KeyControlBlock);
  94. //
  95. // Replace this with the definition so we avoid dropping and reacquiring the lock
  96. //DELIST_KEYBODY_FROM_KEYBODY_LIST(KeyBody);
  97. ASSERT(IsListEmpty(&(KeyBody->KeyControlBlock->KeyBodyListHead)) == FALSE);
  98. RemoveEntryList(&(KeyBody->KeyBodyList));
  99. //
  100. // change of plans. once locked, the kcb will be locked for as long as the machine is up&running
  101. //
  102. /*
  103. if(IsListEmpty(&(KeyBody->KeyControlBlock->KeyBodyListHead)) == TRUE) {
  104. //
  105. // remove the read-only flag on the kcb (if any); as last handle to this key was closed
  106. //
  107. KeyControlBlock->ExtFlags &= (~CM_KCB_READ_ONLY_KEY);
  108. }
  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. CmpUnlockKCB(KeyControlBlock);
  125. CmpUnlockKCBTree();
  126. END_KCB_LOCK_GUARD;
  127. CmpDereferenceKeyControlBlock(KeyControlBlock);
  128. }
  129. } else {
  130. //
  131. // This must be a predefined handle
  132. // some sanity asserts
  133. //
  134. KeyControlBlock = KeyBody->KeyControlBlock;
  135. ASSERT( KeyBody->Type&REG_PREDEF_HANDLE_MASK);
  136. ASSERT( KeyControlBlock->Flags&KEY_PREDEF_HANDLE );
  137. if( KeyControlBlock != NULL ) {
  138. #ifdef NT_UNLOAD_KEY_EX
  139. CmHive = (PCMHIVE)CONTAINING_RECORD(KeyControlBlock->KeyHive, CMHIVE, Hive);
  140. if( IsHiveFrozen(CmHive) ) {
  141. //
  142. // unload is pending for this hive; we shouldn't put the kcb in the delay
  143. // close table
  144. //
  145. DoUnloadCheck = TRUE;
  146. }
  147. #endif //NT_UNLOAD_KEY_EX
  148. CmpDereferenceKeyControlBlock(KeyControlBlock);
  149. }
  150. }
  151. #ifdef NT_UNLOAD_KEY_EX
  152. //
  153. // if a handle inside a frozen hive has been closed, we may need to unload the hive
  154. //
  155. if( DoUnloadCheck == TRUE ) {
  156. ASSERT( CmHive->RootKcb != NULL );
  157. //
  158. // NB: Hive lock has higher precedence; We don't need the kcb lock as we are only checking the refcount
  159. //
  160. CmLockHive(CmHive);
  161. if( (CmHive->RootKcb->RefCount == 1) && (CmHive->UnloadWorkItem == NULL) ) {
  162. //
  163. // the only reference on the rookcb is the one that we artificially created
  164. // queue a work item to late unload the hive
  165. //
  166. CmHive->UnloadWorkItem = ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM));
  167. if (CmHive->UnloadWorkItem != NULL) {
  168. ExInitializeWorkItem(CmHive->UnloadWorkItem,
  169. CmpLateUnloadHiveWorker,
  170. CmHive);
  171. ExQueueWorkItem(CmHive->UnloadWorkItem, DelayedWorkQueue);
  172. }
  173. }
  174. CmUnlockHive(CmHive);
  175. }
  176. #endif //NT_UNLOAD_KEY_EX
  177. CmpUnlockRegistry();
  178. END_LOCK_CHECKPOINT;
  179. //
  180. // just a notification; disregard the return status
  181. //
  182. CmPostCallbackNotification(RegNtPostKeyHandleClose,NULL,STATUS_SUCCESS);
  183. return;
  184. }
  185. #ifdef NT_UNLOAD_KEY_EX
  186. VOID
  187. CmpLateUnloadHiveWorker(
  188. IN PVOID Hive
  189. )
  190. /*++
  191. Routine Description:
  192. "Late" unloads the hive; If nothing goes badly wrong (i.e. insufficient resources),
  193. this function should succeed
  194. Arguments:
  195. CmHive - the frozen hive to be unloaded
  196. Return Value:
  197. NONE.
  198. --*/
  199. {
  200. NTSTATUS Status;
  201. HCELL_INDEX Cell;
  202. PCM_KEY_CONTROL_BLOCK RootKcb;
  203. PCMHIVE CmHive;
  204. PAGED_CODE();
  205. //
  206. // first, load the registry exclusive
  207. //
  208. CmpLockRegistryExclusive();
  209. #ifdef CHECK_REGISTRY_USECOUNT
  210. CmpCheckRegistryUseCount();
  211. #endif //CHECK_REGISTRY_USECOUNT
  212. //
  213. // hive is the parameter to this worker; make sure we free the work item
  214. // allocated by CmpDeleteKeyObject
  215. //
  216. CmHive = (PCMHIVE)Hive;
  217. ASSERT( CmHive->UnloadWorkItem != NULL );
  218. ExFreePool( CmHive->UnloadWorkItem );
  219. //
  220. // if this attempt doesn't succeed, mark that we can try another
  221. //
  222. CmHive->UnloadWorkItem = NULL;
  223. //
  224. // this is just about the only possible way the hive can get corrupted in between
  225. //
  226. if( HvShutdownComplete == TRUE ) {
  227. // too late to do anything
  228. CmpUnlockRegistry();
  229. return;
  230. }
  231. //
  232. // hive should be frozen, otherwise we wouldn't get here
  233. //
  234. ASSERT( CmHive->Frozen == TRUE );
  235. RootKcb = CmHive->RootKcb;
  236. //
  237. // root kcb must be valid and has only our "artificial" refcount on it
  238. //
  239. ASSERT( RootKcb != NULL );
  240. if( RootKcb->RefCount > 1 ) {
  241. //
  242. // somebody else must've gotten in between dropping/reacquiring the reglock
  243. // and opened a handle inside this hive; bad luck, we can't unload
  244. //
  245. CmpUnlockRegistry();
  246. return;
  247. }
  248. ASSERT_KCB(RootKcb);
  249. Cell = RootKcb->KeyCell;
  250. Status = CmUnloadKey(&(CmHive->Hive),Cell,RootKcb,0);
  251. ASSERT( (Status != STATUS_CANNOT_DELETE) && (Status != STATUS_INVALID_PARAMETER) );
  252. if(NT_SUCCESS(Status)) {
  253. //
  254. // Mark the root kcb as deleted so that it won't get put on the delayed close list.
  255. //
  256. RootKcb->Delete = TRUE;
  257. //
  258. // If the parent has the subkey info or hint cached, free it.
  259. //
  260. CmpCleanUpSubKeyInfo(RootKcb->ParentKcb);
  261. CmpRemoveKeyControlBlock(RootKcb);
  262. CmpDereferenceKeyControlBlockWithLock(RootKcb);
  263. }
  264. CmpUnlockRegistry();
  265. }
  266. #endif //NT_UNLOAD_KEY_EX