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.

378 lines
8.9 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ioPerf.c
  5. Abstract:
  6. This module contains the routines to collect performance info for driver calls...
  7. Author:
  8. Mike Fortin (mrfortin) May 8, 2000
  9. Revision History:
  10. --*/
  11. #include "iomgr.h"
  12. #if (( defined(_X86_) ) && ( FPO ))
  13. #pragma optimize( "y", off ) // disable FPO for consistent stack traces
  14. #endif
  15. NTSTATUS
  16. IoPerfInit(
  17. );
  18. NTSTATUS
  19. IoPerfReset(
  20. );
  21. NTSTATUS
  22. FASTCALL
  23. IoPerfCallDriver(
  24. IN PDEVICE_OBJECT DeviceObject,
  25. IN OUT PIRP Irp,
  26. IN PVOID ReturnAddress
  27. );
  28. VOID
  29. FASTCALL
  30. IoPerfCompleteRequest (
  31. IN PIRP Irp,
  32. IN CCHAR PriorityBoost
  33. );
  34. #ifndef NTPERF
  35. #ifdef ALLOC_PRAGMA
  36. #pragma alloc_text(PAGEWMI, IoPerfCallDriver)
  37. #pragma alloc_text(PAGEWMI, IoPerfInit)
  38. #pragma alloc_text(PAGEWMI, IoPerfReset)
  39. #pragma alloc_text(PAGEWMI, IopPerfLogFileCreate)
  40. #endif
  41. #endif // NTPERF
  42. NTSTATUS
  43. IoPerfInit(
  44. )
  45. {
  46. if ( IopVerifierOn ){
  47. // We will not log driver hooks if the verifier has
  48. // also been turned on
  49. // Probably want to log some event or make a testenv note about
  50. // the perf implications of having the verifier turned on
  51. //
  52. return STATUS_UNSUCCESSFUL;
  53. }
  54. //
  55. // Enable and hook in the Perf Routines
  56. //
  57. InterlockedExchangePointer((PVOID *)&pIofCallDriver, (PVOID) IoPerfCallDriver);
  58. InterlockedExchangePointer((PVOID *)&pIofCompleteRequest, (PVOID) IoPerfCompleteRequest);
  59. ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
  60. return STATUS_SUCCESS;
  61. }
  62. NTSTATUS
  63. IoPerfReset(
  64. )
  65. {
  66. if ( IopVerifierOn ){
  67. // We did not replace the function ptrs if the verifier
  68. // also was turned on, so just return
  69. //
  70. return STATUS_UNSUCCESSFUL;
  71. }
  72. //
  73. // Reset to init values, see IopSetIoRoutines
  74. //
  75. InterlockedExchangePointer((PVOID *)&pIofCallDriver, NULL);
  76. InterlockedExchangePointer((PVOID *)&pIofCompleteRequest, (PVOID) IopfCompleteRequest);
  77. ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
  78. return STATUS_SUCCESS;
  79. }
  80. LONG IopPerfDriverUniqueMatchId;
  81. NTSTATUS
  82. FASTCALL
  83. IoPerfCallDriver(
  84. IN PDEVICE_OBJECT DeviceObject,
  85. IN OUT PIRP Irp,
  86. IN PVOID ReturnAddress
  87. )
  88. /*++
  89. Routine Description:
  90. This routine is invoked to pass an I/O Request Packet (IRP) to another
  91. driver at its dispatch routine, logging perf data along the way.
  92. Arguments:
  93. DeviceObject - Pointer to device object to which the IRP should be passed.
  94. Irp - Pointer to IRP for request.
  95. Return Value:
  96. Return status from driver's dispatch routine.
  97. --*/
  98. {
  99. PIO_STACK_LOCATION irpSp;
  100. PDRIVER_OBJECT driverObject;
  101. NTSTATUS status;
  102. PVOID PerfInfoRoutineAddr;
  103. ULONG MatchId;
  104. #ifdef NTPERF
  105. ULONGLONG PerfInfoTimeOfCall = PerfGetCycleCount();
  106. #endif // NTPERF
  107. //
  108. // Ensure that this is really an I/O Request Packet.
  109. //
  110. UNREFERENCED_PARAMETER(ReturnAddress);
  111. ASSERT( Irp->Type == IO_TYPE_IRP );
  112. irpSp = IoGetNextIrpStackLocation( Irp );
  113. //
  114. // Invoke the driver at its dispatch routine entry point.
  115. //
  116. driverObject = DeviceObject->DriverObject;
  117. //
  118. // Prevent the driver from unloading.
  119. //
  120. ObReferenceObject(DeviceObject);
  121. MatchId = InterlockedIncrement( &IopPerfDriverUniqueMatchId );
  122. PerfInfoRoutineAddr = (PVOID) (ULONG_PTR) driverObject->MajorFunction[irpSp->MajorFunction];
  123. //
  124. // Log the Call Event
  125. //
  126. if (PERFINFO_IS_GROUP_ON(PERF_DRIVERS)) {
  127. PERFINFO_DRIVER_MAJORFUNCTION MFInfo;
  128. MFInfo.MajorFunction = irpSp->MajorFunction;
  129. MFInfo.MinorFunction = irpSp->MinorFunction;
  130. MFInfo.RoutineAddr = (PVOID) (ULONG_PTR) driverObject->MajorFunction[irpSp->MajorFunction];
  131. MFInfo.Irp = Irp;
  132. MFInfo.UniqMatchId = MatchId;
  133. if (Irp->Flags & IRP_ASSOCIATED_IRP) {
  134. ASSERT (Irp->AssociatedIrp.MasterIrp != NULL);
  135. if (Irp->AssociatedIrp.MasterIrp != NULL) {
  136. //
  137. // The check for MasterIrp is defensive code.
  138. // We have hit a bugcechk when a filter driver set the
  139. // IRP_ASSOCIATED_IRP bit while MasterIrp pointing to NULL.
  140. //
  141. // The ASSERT above was to catch similar problems before we release.
  142. //
  143. MFInfo.FileNamePointer = Irp->AssociatedIrp.MasterIrp->Tail.Overlay.OriginalFileObject;
  144. } else {
  145. MFInfo.FileNamePointer = NULL;
  146. }
  147. } else {
  148. MFInfo.FileNamePointer = Irp->Tail.Overlay.OriginalFileObject;
  149. }
  150. PerfInfoLogBytes(
  151. PERFINFO_LOG_TYPE_DRIVER_MAJORFUNCTION_CALL,
  152. &MFInfo,
  153. sizeof(MFInfo)
  154. );
  155. }
  156. //
  157. // Do the normal IopfCallDriver work
  158. //
  159. status = IopfCallDriver(DeviceObject, Irp );
  160. //
  161. // Log the Return
  162. //
  163. if (PERFINFO_IS_GROUP_ON(PERF_DRIVERS)) {
  164. PERFINFO_DRIVER_MAJORFUNCTION_RET MFInfo;
  165. MFInfo.Irp = Irp;
  166. MFInfo.UniqMatchId = MatchId;
  167. PERFINFO_DRIVER_INTENTIONAL_DELAY();
  168. PerfInfoLogBytes(
  169. PERFINFO_LOG_TYPE_DRIVER_MAJORFUNCTION_RETURN,
  170. &MFInfo,
  171. sizeof(MFInfo)
  172. );
  173. PERFINFO_DRIVER_STACKTRACE();
  174. }
  175. ObDereferenceObject(DeviceObject);
  176. return status;
  177. }
  178. VOID
  179. FASTCALL
  180. IoPerfCompleteRequest (
  181. IN PIRP Irp,
  182. IN CCHAR PriorityBoost
  183. )
  184. /*++
  185. Routine Description:
  186. This routine is invoked when a driver completes an IRP, logging perf data
  187. along the way.
  188. Arguments:
  189. Irp - Pointer to IRP for completed request.
  190. PriorityBoost - Priority boost specified by the driver completing the IRP.
  191. Return Value:
  192. None.
  193. --*/
  194. {
  195. PERFINFO_DRIVER_COMPLETE_REQUEST CompleteRequest;
  196. PERFINFO_DRIVER_COMPLETE_REQUEST_RET CompleteRequestRet;
  197. PIO_STACK_LOCATION irpSp;
  198. PVOID DriverRoutineAddr;
  199. ULONG MatchId;
  200. //
  201. // Initialize locals.
  202. //
  203. DriverRoutineAddr = NULL;
  204. //
  205. // If the packet looks weird/improper pass it on to the real IO completion routine
  206. // directly.
  207. //
  208. if (Irp->Type != IO_TYPE_IRP || Irp->CurrentLocation > (CCHAR) (Irp->StackCount + 1)) {
  209. IopfCompleteRequest(Irp, PriorityBoost);
  210. return;
  211. }
  212. //
  213. // Get current stack location and save the driver routine address to
  214. // identify the driver that was processing the IRP when it got completed. If
  215. // device object is NULL, try to get the completion routine addr.
  216. //
  217. irpSp = IoGetCurrentIrpStackLocation( Irp );
  218. if (irpSp->DeviceObject) {
  219. //
  220. // We don't want to cause a bugcheck in this code even when something else is
  221. // corrupt.
  222. //
  223. ASSERT(irpSp->DeviceObject->DriverObject);
  224. if (irpSp->DeviceObject->DriverObject) {
  225. ASSERT(irpSp->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
  226. if (irpSp->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION) {
  227. DriverRoutineAddr = (PVOID) (ULONG_PTR) irpSp->DeviceObject->DriverObject->MajorFunction[irpSp->MajorFunction];
  228. }
  229. }
  230. } else {
  231. DriverRoutineAddr = (PVOID) (ULONG_PTR) irpSp->CompletionRoutine;
  232. }
  233. //
  234. // Bump the ID that gets used to match COMPLETE_REQUEST and COMPLETE_REQUEST_RET
  235. // entries logged for an IRP completion.
  236. //
  237. MatchId = InterlockedIncrement( &IopPerfDriverUniqueMatchId );
  238. //
  239. // Log the start of the completion.
  240. //
  241. if (PERFINFO_IS_GROUP_ON(PERF_DRIVERS)) {
  242. CompleteRequest.Irp = Irp;
  243. CompleteRequest.UniqMatchId = MatchId;
  244. CompleteRequest.RoutineAddr = DriverRoutineAddr;
  245. PerfInfoLogBytes(
  246. PERFINFO_LOG_TYPE_DRIVER_COMPLETE_REQUEST,
  247. &CompleteRequest,
  248. sizeof(CompleteRequest)
  249. );
  250. }
  251. //
  252. // Do the normal IopfCompleteIrp work.
  253. //
  254. IopfCompleteRequest(Irp, PriorityBoost);
  255. //
  256. // After this point no fields of Irp should be accessed. E.g. the Irp may
  257. // have been freed / reallocated etc. by a completion routine.
  258. //
  259. //
  260. // Log the return.
  261. //
  262. if (PERFINFO_IS_GROUP_ON(PERF_DRIVERS)) {
  263. CompleteRequestRet.Irp = Irp;
  264. CompleteRequestRet.UniqMatchId = MatchId;
  265. PerfInfoLogBytes(
  266. PERFINFO_LOG_TYPE_DRIVER_COMPLETE_REQUEST_RETURN,
  267. &CompleteRequestRet,
  268. sizeof(CompleteRequestRet)
  269. );
  270. }
  271. return;
  272. }
  273. VOID
  274. IopPerfLogFileCreate(
  275. IN PFILE_OBJECT FileObject,
  276. IN PUNICODE_STRING CompleteName
  277. )
  278. {
  279. PERFINFO_LOG_FILE_CREATE(FileObject, CompleteName);
  280. }