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.

618 lines
12 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. object.c
  5. Abstract:
  6. This is the NT Watchdog driver implementation.
  7. Author:
  8. Michael Maciesowicz (mmacie) 02-May-2001
  9. Environment:
  10. Kernel mode only.
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include "wd.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text (PAGE, WdpFlushRegistryKey)
  17. #pragma alloc_text (PAGE, WdpInitializeObject)
  18. #endif
  19. //
  20. // Exports.
  21. //
  22. WATCHDOGAPI
  23. PVOID
  24. WdAttachContext(
  25. IN PVOID pWatch,
  26. IN ULONG ulSize
  27. )
  28. /*++
  29. Routine Description:
  30. This routine allocates context buffer of given size from non-paged pool
  31. and associates it with given watchdog object. In case the client code
  32. doesn't detach the context before freeing watchdog object it will be
  33. freed automatically when watchdog object is destroyed.
  34. This routine helps to handle the case when watchdog object is freed
  35. but the context must persist till object is actually destroyed and client
  36. code cannot guarantee that.
  37. Arguments:
  38. pWatch - Points to WATCHDOG_OBJECT.
  39. ulSize - Size in bytes of context to allocate and attach.
  40. Return Value:
  41. A pointer to created and attached context buffer.
  42. --*/
  43. {
  44. PWATCHDOG_OBJECT pWatchdogObject;
  45. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  46. ASSERT_WATCHDOG_OBJECT(pWatch);
  47. WDD_TRACE_CALL((PDEFERRED_WATCHDOG)pWatch, WddWdAttachContext);
  48. pWatchdogObject = (PWATCHDOG_OBJECT)pWatch;
  49. //
  50. // Check for double attach.
  51. //
  52. ASSERT(NULL == pWatchdogObject->Context);
  53. //
  54. // Allocate storage for attached context from non-paged pool.
  55. //
  56. pWatchdogObject->Context = ExAllocatePoolWithTag(NonPagedPool,
  57. ulSize,
  58. pWatchdogObject->OwnerTag);
  59. return pWatchdogObject->Context;
  60. } // WdAttachContext()
  61. WATCHDOGAPI
  62. VOID
  63. WdCompleteEvent(
  64. IN PVOID pWatch,
  65. IN PKTHREAD pThread
  66. )
  67. /*++
  68. Routine Description:
  69. This function *MUST* be called from client handler for watchdog timeout event
  70. before exiting. It removes references from watchdog and thread objects.
  71. It also reenables watchdog event generation for deferred watchdog objects.
  72. Arguments:
  73. pWatch - Points to WATCHDOG_OBJECT.
  74. pThread - Points to KTHREAD object for spinning thread.
  75. Return Value:
  76. None.
  77. --*/
  78. {
  79. //
  80. // Note: pThread is NULL for recovery events.
  81. //
  82. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  83. ASSERT_WATCHDOG_OBJECT(pWatch);
  84. WDD_TRACE_CALL((PDEFERRED_WATCHDOG)pWatch, WddWdCompleteEvent);
  85. //
  86. // Resume event generation for deferred watchdog.
  87. //
  88. if (WdDeferredWatchdog == ((PWATCHDOG_OBJECT)pWatch)->ObjectType)
  89. {
  90. InterlockedExchange(&(((PDEFERRED_WATCHDOG)pWatch)->Trigger), 0);
  91. }
  92. //
  93. // Drop reference counts.
  94. //
  95. if (NULL != pThread)
  96. {
  97. ObDereferenceObject(pThread);
  98. }
  99. WdDereferenceObject(pWatch);
  100. return;
  101. } // WdCompleteEvent()
  102. WATCHDOGAPI
  103. VOID
  104. WdDereferenceObject(
  105. IN PVOID pWatch
  106. )
  107. /*++
  108. Routine Description:
  109. This function decreases reference count of watchdog object.
  110. If remaining count is zero we will remove object here, since it's
  111. been freed already.
  112. Arguments:
  113. pWatch - Points to WATCHDOG_OBJECT.
  114. Return Value:
  115. None.
  116. --*/
  117. {
  118. PWATCHDOG_OBJECT pWatchdogObject;
  119. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  120. ASSERT_WATCHDOG_OBJECT(pWatch);
  121. WDD_TRACE_CALL((PDEFERRED_WATCHDOG)pWatch, WddWdDereferenceObject);
  122. pWatchdogObject = (PWATCHDOG_OBJECT)pWatch;
  123. ASSERT(pWatchdogObject->ReferenceCount > 0);
  124. //
  125. // Drop reference count and remove the object if fully dereferenced.
  126. //
  127. if (InterlockedDecrement(&(pWatchdogObject->ReferenceCount)) == 0)
  128. {
  129. //
  130. // Object already freed - remove it now.
  131. //
  132. WdpDestroyObject(pWatchdogObject);
  133. }
  134. return;
  135. } // WdDereferenceObject()
  136. WATCHDOGAPI
  137. VOID
  138. WdDetachContext(
  139. IN PVOID pWatch
  140. )
  141. /*++
  142. Routine Description:
  143. This routine frees context attached to watchdog object.
  144. NOTE: You don't have to call this routine before freeing watchdog
  145. object - the context, if attached, will be destroyed automatically
  146. when watchdog object is destroyed.
  147. Arguments:
  148. pWatch - Points to WATCHDOG_OBJECT.
  149. Return Value:
  150. None.
  151. --*/
  152. {
  153. PWATCHDOG_OBJECT pWatchdogObject;
  154. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  155. ASSERT_WATCHDOG_OBJECT(pWatch);
  156. WDD_TRACE_CALL((PDEFERRED_WATCHDOG)pWatch, WddWdDetachContext);
  157. pWatchdogObject = (PWATCHDOG_OBJECT)pWatch;
  158. //
  159. // Check for double detach.
  160. //
  161. ASSERT(NULL != pWatchdogObject->Context);
  162. //
  163. // Free storage for attached context and set reference to NULL.
  164. //
  165. // BUGBUG: This is not synchronized with DPCs!
  166. //
  167. ExFreePool(pWatchdogObject->Context);
  168. pWatchdogObject->Context = NULL;
  169. return;
  170. } // WdDetachContext()
  171. WATCHDOGAPI
  172. PDEVICE_OBJECT
  173. WdGetDeviceObject(
  174. IN PVOID pWatch
  175. )
  176. /*++
  177. Routine Description:
  178. This function return pointer to device object associated with watchdog object.
  179. This function increases reference count on DEVICE_OBJECT so the caller must call
  180. ObDereferenceObject() once DEVICE_OBJECT pointer is not needed any more.
  181. Arguments:
  182. pWatch - Points to WATCHDOG_OBJECT.
  183. Return Value:
  184. Pointer to DEVICE_OBJECT.
  185. --*/
  186. {
  187. PDEVICE_OBJECT pDeviceObject;
  188. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  189. ASSERT_WATCHDOG_OBJECT(pWatch);
  190. WDD_TRACE_CALL((PDEFERRED_WATCHDOG)pWatch, WddWdGetDeviceObject);
  191. pDeviceObject = ((PWATCHDOG_OBJECT)pWatch)->DeviceObject;
  192. ASSERT(NULL != pDeviceObject);
  193. ObReferenceObject(pDeviceObject);
  194. return pDeviceObject;
  195. } // WdGetDeviceObject()
  196. WATCHDOGAPI
  197. WD_EVENT_TYPE
  198. WdGetLastEvent(
  199. IN PVOID pWatch
  200. )
  201. /*++
  202. Routine Description:
  203. This function return last event associated with watchdog object.
  204. Arguments:
  205. pWatch - Points to WATCHDOG_OBJECT.
  206. Return Value:
  207. Last event type.
  208. --*/
  209. {
  210. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  211. ASSERT_WATCHDOG_OBJECT(pWatch);
  212. WDD_TRACE_CALL((PDEFERRED_WATCHDOG)pWatch, WddWdGetLastEvent);
  213. return ((PWATCHDOG_OBJECT)pWatch)->LastEvent;
  214. } // WdGetLastEvent()
  215. WATCHDOGAPI
  216. PDEVICE_OBJECT
  217. WdGetLowestDeviceObject(
  218. IN PVOID pWatch
  219. )
  220. /*++
  221. Routine Description:
  222. This function return pointer to the lowest (most likely PDO) DEVICE_OBJECT
  223. associated with watchdog object. This function increases reference count on
  224. returned DEVICE_OBJECT - the caller must call ObDereferenceObject() once
  225. DEVICE_OBJECT pointer is not needed any more.
  226. Arguments:
  227. pWatch - Points to WATCHDOG_OBJECT.
  228. Return Value:
  229. Pointer to DEVICE_OBJECT.
  230. --*/
  231. {
  232. PDEVICE_OBJECT pDeviceObject;
  233. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  234. ASSERT_WATCHDOG_OBJECT(pWatch);
  235. WDD_TRACE_CALL((PDEFERRED_WATCHDOG)pWatch, WddWdGetLowestDeviceObject);
  236. //
  237. // Note: No need to bump reference count here, it is always done when
  238. // watchdog object is created.
  239. //
  240. pDeviceObject = ((PWATCHDOG_OBJECT)pWatch)->DeviceObject;
  241. ASSERT(NULL != pDeviceObject);
  242. //
  243. // Now get the pointer to the lowest device object in the stack.
  244. // Note: This call automatically bumps a reference count on returned object.
  245. //
  246. pDeviceObject = IoGetDeviceAttachmentBaseRef(pDeviceObject);
  247. ASSERT(NULL != pDeviceObject);
  248. return pDeviceObject;
  249. } // WdGetLowestDeviceObject()
  250. WATCHDOGAPI
  251. VOID
  252. WdReferenceObject(
  253. IN PVOID pWatch
  254. )
  255. /*++
  256. Routine Description:
  257. This function increases reference count of watchdog object.
  258. Arguments:
  259. pWatch - Points to WATCHDOG_OBJECT.
  260. Return Value:
  261. None.
  262. --*/
  263. {
  264. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  265. ASSERT_WATCHDOG_OBJECT(pWatch);
  266. WDD_TRACE_CALL((PDEFERRED_WATCHDOG)pWatch, WddWdReferenceObject);
  267. if (InterlockedIncrement(&(((PWATCHDOG_OBJECT)pWatch)->ReferenceCount)) == 1)
  268. {
  269. //
  270. // Somebody referenced removed object.
  271. //
  272. ASSERT(FALSE);
  273. }
  274. //
  275. // Check for overflow.
  276. //
  277. ASSERT(((PWATCHDOG_OBJECT)pWatch)->ReferenceCount > 0);
  278. return;
  279. } // WdReferenceObject()
  280. //
  281. // Non-exports.
  282. //
  283. VOID
  284. WdpDestroyObject(
  285. IN PVOID pWatch
  286. )
  287. /*++
  288. Routine Description:
  289. This function unconditionally frees watchdog object.
  290. Arguments:
  291. pWatch - Points to WATCHDOG_OBJECT.
  292. Return Value:
  293. None.
  294. --*/
  295. {
  296. PWATCHDOG_OBJECT pWatchdogObject;
  297. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  298. ASSERT_WATCHDOG_OBJECT(pWatch);
  299. WDD_TRACE_CALL((PDEFERRED_WATCHDOG)pWatch, WddWdpDestroyObject);
  300. pWatchdogObject = (PWATCHDOG_OBJECT)pWatch;
  301. ASSERT(0 == pWatchdogObject->ReferenceCount);
  302. //
  303. // Drop reference count on device object.
  304. //
  305. ObDereferenceObject(pWatchdogObject->DeviceObject);
  306. //
  307. // We are freeing non-paged pool, it's OK to be at IRQL <= DISPATCH_LEVEL.
  308. // Free attached context first, if any, then free watchdog object.
  309. //
  310. if (NULL != pWatchdogObject->Context)
  311. {
  312. ExFreePool(pWatchdogObject->Context);
  313. }
  314. ExFreePool(pWatch);
  315. return;
  316. } // WdpDestroyObject()
  317. NTSTATUS
  318. WdpFlushRegistryKey(
  319. IN PVOID pWatch,
  320. IN PCWSTR pwszKeyName
  321. )
  322. /*++
  323. Routine Description:
  324. This function forces a registry key to be committed to disk.
  325. Arguments:
  326. pWatch - Points to WATCHDOG_OBJECT.
  327. pwszKeyName - Points to key name string.
  328. Return Value:
  329. Status code.
  330. --*/
  331. {
  332. OBJECT_ATTRIBUTES objectAttributes;
  333. UNICODE_STRING unicodeKeyName;
  334. HANDLE keyHandle;
  335. NTSTATUS ntStatus;
  336. PAGED_CODE();
  337. UNREFERENCED_PARAMETER(pWatch);
  338. ASSERT(NULL != pwszKeyName);
  339. WDD_TRACE_CALL((PDEFERRED_WATCHDOG)pWatch, WddWdpFlushRegistryKey);
  340. RtlInitUnicodeString(&unicodeKeyName, pwszKeyName);
  341. InitializeObjectAttributes(&objectAttributes,
  342. &unicodeKeyName,
  343. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  344. NULL,
  345. NULL);
  346. ntStatus = ZwOpenKey(&keyHandle,
  347. KEY_READ | KEY_WRITE,
  348. &objectAttributes);
  349. if (NT_SUCCESS(ntStatus))
  350. {
  351. ntStatus = ZwFlushKey(keyHandle);
  352. ZwClose(keyHandle);
  353. }
  354. return ntStatus;
  355. } // WdpFlushRegistryKey()
  356. VOID
  357. WdpInitializeObject(
  358. IN PVOID pWatch,
  359. IN PDEVICE_OBJECT pDeviceObject,
  360. IN WD_OBJECT_TYPE objectType,
  361. IN WD_TIME_TYPE timeType,
  362. IN ULONG ulTag
  363. )
  364. /*++
  365. Routine Description:
  366. This function initializes watchdog object.
  367. Arguments:
  368. pWatch - Points to WATCHDOG_OBJECT.
  369. pDeviceObject - Points to DEVICE_OBJECT associated with watchdog.
  370. objectType - Type of watchdog object.
  371. timeType - Kernel, User, Both thread time to monitor.
  372. ulTag - A tag identifying owner.
  373. Return Value:
  374. None.
  375. --*/
  376. {
  377. PWATCHDOG_OBJECT pWatchdogObject;
  378. PAGED_CODE();
  379. ASSERT(NULL != pWatch);
  380. ASSERT(NULL != pDeviceObject);
  381. ASSERT((objectType == WdStandardWatchdog) || (objectType == WdDeferredWatchdog));
  382. ASSERT((timeType >= WdKernelTime) && (timeType <= WdFullTime));
  383. WDD_TRACE_CALL((PDEFERRED_WATCHDOG)pWatch, WddWdpInitializeObject);
  384. pWatchdogObject = (PWATCHDOG_OBJECT)pWatch;
  385. //
  386. // Set initial state of watchdog object.
  387. //
  388. pWatchdogObject->ObjectType = objectType;
  389. pWatchdogObject->ReferenceCount = 1;
  390. pWatchdogObject->OwnerTag = ulTag;
  391. pWatchdogObject->DeviceObject = pDeviceObject;
  392. pWatchdogObject->TimeType = timeType;
  393. pWatchdogObject->LastEvent = WdNoEvent;
  394. pWatchdogObject->LastQueuedThread = NULL;
  395. pWatchdogObject->Context = NULL;
  396. //
  397. // Bump reference count on device object.
  398. //
  399. ObReferenceObject(pDeviceObject);
  400. //
  401. // Initialize encapsulated KSPIN_LOCK object.
  402. //
  403. KeInitializeSpinLock(&(pWatchdogObject->SpinLock));
  404. return;
  405. } // WdpInitializeObject()