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.

479 lines
13 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1990 - 1999
  3. Module Name:
  4. lock.c
  5. Abstract:
  6. This is the NT SCSI port driver.
  7. Authors:
  8. Peter Wieland
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. This module is a driver dll for scsi miniports.
  13. Revision History:
  14. --*/
  15. #define KEEP_COMPLETE_REQUEST
  16. #if DBG
  17. static const char *__file__ = __FILE__;
  18. #endif
  19. #include "port.h"
  20. LONG LockHighWatermark = 0;
  21. LONG LockLowWatermark = 0;
  22. LONG MaxLockedMinutes = 5;
  23. VOID
  24. FASTCALL
  25. SpFreeSrbData(
  26. IN PADAPTER_EXTENSION Adapter,
  27. IN PSRB_DATA SrbData
  28. );
  29. VOID
  30. FASTCALL
  31. SpFreeBypassSrbData(
  32. IN PADAPTER_EXTENSION Adapter,
  33. IN PSRB_DATA SrbData
  34. );
  35. #if DBG
  36. ULONG
  37. FASTCALL
  38. SpAcquireRemoveLockEx(
  39. IN PDEVICE_OBJECT DeviceObject,
  40. IN OPTIONAL PVOID Tag,
  41. IN PCSTR File,
  42. IN ULONG Line
  43. )
  44. /*++
  45. Routine Description:
  46. This routine is called to acquire the remove lock on the device object.
  47. While the lock is held, the caller can assume that no pending pnp REMOVE
  48. requests will be completed.
  49. The lock should be acquired immediately upon entering a dispatch routine.
  50. It should also be acquired before creating any new reference to the
  51. device object if there's a chance of releasing the reference before the
  52. new one is done.
  53. This routine will return TRUE if the lock was successfully acquired or
  54. FALSE if it cannot be because the device object has already been removed.
  55. Arguments:
  56. DeviceObject - the device object to lock
  57. Tag - Used for tracking lock allocation and release. If an irp is
  58. specified when acquiring the lock then the same Tag must be
  59. used to release the lock before the Tag is completed.
  60. Return Value:
  61. The value of the IsRemoved flag in the device extension. If this is
  62. non-zero then the device object has received a Remove irp and non-cleanup
  63. IRP's should fail.
  64. If the value is REMOVE_COMPLETE, the caller should not even release the
  65. lock.
  66. --*/
  67. {
  68. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  69. LONG lockValue;
  70. #if DBG
  71. PREMOVE_TRACKING_BLOCK *removeTrackingList =
  72. &((PREMOVE_TRACKING_BLOCK) commonExtension->RemoveTrackingList);
  73. PREMOVE_TRACKING_BLOCK trackingBlock;
  74. #endif
  75. //
  76. // Grab the remove lock
  77. //
  78. lockValue = InterlockedIncrement(&commonExtension->RemoveLock);
  79. DebugPrint((4, "SpAcquireRemoveLock: Acquired for Object %#p & irp "
  80. "%#p - count is %d\n",
  81. DeviceObject,
  82. Tag,
  83. lockValue));
  84. ASSERTMSG("SpAcquireRemoveLock - lock value was negative : ",
  85. (lockValue > 0));
  86. ASSERTMSG("RemoveLock increased to meet LockHighWatermark",
  87. ((LockHighWatermark == 0) ||
  88. (lockValue != LockHighWatermark)));
  89. #if DBG
  90. if(commonExtension->IsRemoved != REMOVE_COMPLETE) {
  91. trackingBlock = ExAllocateFromNPagedLookasideList(
  92. &(commonExtension->RemoveTrackingLookasideList));
  93. if(trackingBlock == NULL) {
  94. KIRQL oldIrql;
  95. KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
  96. &oldIrql);
  97. commonExtension->RemoveTrackingUntrackedCount++;
  98. DebugPrint((1, ">>>>SpAcquireRemoveLock: Cannot track Tag %#p - "
  99. "currently %d untracked requests\n",
  100. Tag,
  101. commonExtension->RemoveTrackingUntrackedCount));
  102. KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock,
  103. oldIrql);
  104. } else {
  105. KIRQL oldIrql;
  106. trackingBlock->Tag = Tag;
  107. trackingBlock->File = File;
  108. trackingBlock->Line = Line;
  109. KeQueryTickCount((&trackingBlock->TimeLocked));
  110. KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
  111. &oldIrql);
  112. while(*removeTrackingList != NULL) {
  113. if((*removeTrackingList)->Tag > Tag) {
  114. break;
  115. }
  116. if((*removeTrackingList)->Tag == Tag) {
  117. DebugPrint((0, ">>>>SpAcquireRemoveLock - already tracking "
  118. "Tag %#p\n", Tag));
  119. DebugPrint((0, ">>>>SpAcquireRemoveLock - acquired in "
  120. "file %s on line %d\n",
  121. (*removeTrackingList)->File,
  122. (*removeTrackingList)->Line));
  123. ASSERT(FALSE);
  124. }
  125. removeTrackingList = &((*removeTrackingList)->NextBlock);
  126. }
  127. trackingBlock->NextBlock = *removeTrackingList;
  128. *removeTrackingList = trackingBlock;
  129. KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock,
  130. oldIrql);
  131. }
  132. }
  133. #endif
  134. return (commonExtension->IsRemoved);
  135. }
  136. #endif
  137. VOID
  138. FASTCALL
  139. SpReleaseRemoveLock(
  140. IN PDEVICE_OBJECT DeviceObject,
  141. IN OPTIONAL PIRP Tag
  142. )
  143. /*++
  144. Routine Description:
  145. This routine is called to release the remove lock on the device object. It
  146. must be called when finished using a previously locked reference to the
  147. device object. If an Tag was specified when acquiring the lock then the
  148. same Tag must be specified when releasing the lock.
  149. When the lock count reduces to zero, this routine will signal the waiting
  150. remove Tag to delete the device object. As a result the DeviceObject
  151. pointer should not be used again once the lock has been released.
  152. Arguments:
  153. DeviceObject - the device object to lock
  154. Tag - The irp (if any) specified when acquiring the lock. This is used
  155. for lock tracking purposes
  156. Return Value:
  157. none
  158. --*/
  159. {
  160. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  161. LONG lockValue;
  162. #if DBG
  163. PREMOVE_TRACKING_BLOCK *listEntry =
  164. &((PREMOVE_TRACKING_BLOCK) commonExtension->RemoveTrackingList);
  165. BOOLEAN found = FALSE;
  166. LONGLONG maxCount;
  167. KIRQL oldIrql;
  168. if(commonExtension->IsRemoved == REMOVE_COMPLETE) {
  169. return;
  170. }
  171. //
  172. // Check the tick count and make sure this thing hasn't been locked
  173. // for more than MaxLockedMinutes.
  174. //
  175. maxCount = KeQueryTimeIncrement() * 10; // microseconds
  176. maxCount *= 1000; // milliseconds
  177. maxCount *= 1000; // seconds
  178. maxCount *= 60; // minutes
  179. maxCount *= MaxLockedMinutes;
  180. DebugPrint((4, "SpReleaseRemoveLock: maxCount = %0I64x\n", maxCount));
  181. KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
  182. &oldIrql);
  183. while(*listEntry != NULL) {
  184. PREMOVE_TRACKING_BLOCK block;
  185. LARGE_INTEGER difference;
  186. block = *listEntry;
  187. KeQueryTickCount((&difference));
  188. difference.QuadPart -= block->TimeLocked.QuadPart;
  189. DebugPrint((4, "SpReleaseRemoveLock: Object %#p (tag %#p) locked "
  190. "for %I64d ticks\n", DeviceObject, block->Tag, difference.QuadPart));
  191. if(difference.QuadPart >= maxCount) {
  192. DebugPrint((0, ">>>>SpReleaseRemoveLock: Object %#p (tag %#p) locked "
  193. "for %I64d ticks - TOO LONG\n", DeviceObject, block->Tag, difference.QuadPart));
  194. DebugPrint((0, ">>>>SpReleaseRemoveLock: Lock acquired in file "
  195. "%s on line %d\n", block->File, block->Line));
  196. ASSERT(FALSE);
  197. }
  198. if((found == FALSE) && ((*listEntry)->Tag == Tag)) {
  199. *listEntry = block->NextBlock;
  200. ExFreeToNPagedLookasideList(
  201. &(commonExtension->RemoveTrackingLookasideList),
  202. block);
  203. found = TRUE;
  204. } else {
  205. listEntry = &((*listEntry)->NextBlock);
  206. }
  207. }
  208. if(!found) {
  209. if(commonExtension->RemoveTrackingUntrackedCount == 0) {
  210. DebugPrint((0, ">>>>SpReleaseRemoveLock: Couldn't find Tag %#p "
  211. "in the lock tracking list\n",
  212. Tag));
  213. ASSERT(FALSE);
  214. } else {
  215. DebugPrint((1, ">>>>SpReleaseRemoveLock: Couldn't find Tag %#p "
  216. "in the lock tracking list - may be one of the "
  217. "%d untracked requests still outstanding\n",
  218. Tag,
  219. commonExtension->RemoveTrackingUntrackedCount));
  220. commonExtension->RemoveTrackingUntrackedCount--;
  221. ASSERT(commonExtension->RemoveTrackingUntrackedCount >= 0);
  222. }
  223. }
  224. KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock, oldIrql);
  225. #endif
  226. lockValue = InterlockedDecrement(&commonExtension->RemoveLock);
  227. DebugPrint((4, "SpReleaseRemoveLock: Released for Object %#p & irp "
  228. "%#p - count is %d\n",
  229. DeviceObject,
  230. Tag,
  231. lockValue));
  232. ASSERT(lockValue >= 0);
  233. ASSERTMSG("RemoveLock decreased to meet LockLowWatermark",
  234. ((LockLowWatermark == 0) || !(lockValue == LockLowWatermark)));
  235. if(lockValue == 0) {
  236. ASSERT(commonExtension->IsRemoved);
  237. //
  238. // The device needs to be removed. Signal the remove event
  239. // that it's safe to go ahead.
  240. //
  241. DebugPrint((3, "SpReleaseRemoveLock: Release for object %#p & "
  242. "irp %#p caused lock to go to zero\n",
  243. DeviceObject,
  244. Tag));
  245. KeSetEvent(&commonExtension->RemoveEvent,
  246. IO_NO_INCREMENT,
  247. FALSE);
  248. }
  249. return;
  250. }
  251. VOID
  252. FASTCALL
  253. SpCompleteRequest(
  254. IN PDEVICE_OBJECT DeviceObject,
  255. IN PIRP Irp,
  256. IN OPTIONAL PSRB_DATA SrbData,
  257. IN CCHAR PriorityBoost
  258. )
  259. /*++
  260. Routine Description:
  261. This routine is a wrapper around IoCompleteRequest. It is used primarily
  262. for debugging purposes. The routine will assert if the Irp being completed
  263. is still holding the release lock.
  264. Arguments:
  265. Return Value:
  266. none
  267. --*/
  268. {
  269. PADAPTER_EXTENSION adapterExtension = DeviceObject->DeviceExtension;
  270. #if DBG
  271. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  272. PREMOVE_TRACKING_BLOCK *listEntry =
  273. &((PREMOVE_TRACKING_BLOCK) commonExtension->RemoveTrackingList);
  274. KIRQL oldIrql;
  275. KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
  276. &oldIrql);
  277. while(*listEntry != NULL) {
  278. if((*listEntry)->Tag == Irp) {
  279. break;
  280. }
  281. listEntry = &((*listEntry)->NextBlock);
  282. }
  283. if(*listEntry != NULL) {
  284. DebugPrint((0, ">>>>SpCompleteRequest: Irp %#p completed while "
  285. "still holding the remove lock\n",
  286. Irp));
  287. DebugPrint((0, ">>>>SpReleaseRemoveLock: Lock acquired in file "
  288. "%s on line %d\n", (*listEntry)->File, (*listEntry)->Line));
  289. ASSERT(FALSE);
  290. }
  291. KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock, oldIrql);
  292. if(ARGUMENT_PRESENT(SrbData)) {
  293. PLOGICAL_UNIT_EXTENSION logicalUnit;
  294. ASSERT_SRB_DATA(SrbData);
  295. ASSERT(SrbData->ScatterGatherList == NULL);
  296. ASSERT_SRB_DATA(SrbData);
  297. ASSERT(SrbData->CurrentIrp == Irp);
  298. logicalUnit = SrbData->LogicalUnit;
  299. ASSERT(logicalUnit != NULL);
  300. ASSERT(logicalUnit->CurrentUntaggedRequest != SrbData);
  301. ASSERT_PDO(logicalUnit->CommonExtension.DeviceObject);
  302. ASSERT(SrbData->RemappedMdl == NULL);
  303. }
  304. #endif
  305. //
  306. // If the caller specified an SRB_DATA structure for the completion then
  307. // we will free it to the lookaside list, fix the OriginalIrp value in the
  308. // srb and release the queue-tag value assigned to the device.
  309. //
  310. if(ARGUMENT_PRESENT(SrbData)) {
  311. PLOGICAL_UNIT_EXTENSION logicalUnit;
  312. logicalUnit = SrbData->LogicalUnit;
  313. ASSERTMSG("Attempt to complete blocked request: ",
  314. ((logicalUnit->ActiveFailedRequest != SrbData) &&
  315. (logicalUnit->BlockedFailedRequest != SrbData)));
  316. if((SrbData->CurrentSrb->Function == SRB_FUNCTION_LOCK_QUEUE) ||
  317. (SrbData->CurrentSrb->Function == SRB_FUNCTION_UNLOCK_QUEUE)) {
  318. ASSERT(logicalUnit->CurrentLockRequest == SrbData);
  319. SpStartLockRequest(logicalUnit, NULL);
  320. }
  321. SrbData->CurrentSrb->OriginalRequest = SrbData->CurrentIrp;
  322. SrbData->CurrentIrp = NULL;
  323. SrbData->CurrentSrb = NULL;
  324. ASSERT(SrbData->FreeRoutine != NULL);
  325. ASSERT((SrbData->FreeRoutine == SpFreeSrbData) ||
  326. (SrbData->FreeRoutine == SpFreeBypassSrbData));
  327. SrbData->FreeRoutine(logicalUnit->AdapterExtension, SrbData);
  328. SpReleaseRemoveLock(logicalUnit->CommonExtension.DeviceObject, Irp);
  329. }
  330. IoCompleteRequest(Irp, PriorityBoost);
  331. return;
  332. }