3 Copyright (C) Microsoft Corporation, 1990 - 1998
11 This is the NT SCSI port driver.
19 This module is a driver dll for scsi miniports.
29 LONG LockHighWatermark
= 0;
30 LONG LockLowWatermark
= 0;
31 LONG MaxLockedMinutes
= 5;
34 // Structure used for tracking remove lock allocations in checked builds
36 typedef struct _REMOVE_TRACKING_BLOCK
{
37 struct _REMOVE_TRACKING_BLOCK
*NextBlock
;
39 LARGE_INTEGER TimeLocked
;
42 } REMOVE_TRACKING_BLOCK
, *PREMOVE_TRACKING_BLOCK
;
45 /*++////////////////////////////////////////////////////////////////////////////
47 ClassAcquireRemoveLockEx()
51 This routine is called to acquire the remove lock on the device object.
52 While the lock is held, the caller can assume that no pending pnp REMOVE
53 requests will be completed.
55 The lock should be acquired immediately upon entering a dispatch routine.
56 It should also be acquired before creating any new reference to the
57 device object if there's a chance of releasing the reference before the
60 This routine will return TRUE if the lock was successfully acquired or
61 FALSE if it cannot be because the device object has already been removed.
65 DeviceObject - the device object to lock
67 Tag - Used for tracking lock allocation and release. If an irp is
68 specified when acquiring the lock then the same Tag must be
69 used to release the lock before the Tag is completed.
73 The value of the IsRemoved flag in the device extension. If this is
74 non-zero then the device object has received a Remove irp and non-cleanup
77 If the value is REMOVE_COMPLETE, the caller should not even release the
83 ClassAcquireRemoveLockEx(
84 IN PDEVICE_OBJECT DeviceObject
,
85 IN OPTIONAL PVOID Tag
,
90 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
96 // Grab the remove lock
98 lockValue
= InterlockedIncrement(&commonExtension
->RemoveLock
);
102 DebugPrint((ClassDebugRemoveLock
, "ClassAcquireRemoveLock: "
103 "Acquired for Object %p & irp %p - count is %d\n",
104 DeviceObject
, Tag
, lockValue
));
106 ASSERTMSG("ClassAcquireRemoveLock - lock value was negative : ",
109 ASSERTMSG("RemoveLock increased to meet LockHighWatermark",
110 ((LockHighWatermark
== 0) ||
111 (lockValue
!= LockHighWatermark
)));
113 if (commonExtension
->IsRemoved
!= REMOVE_COMPLETE
){
114 PREMOVE_TRACKING_BLOCK trackingBlock
;
116 trackingBlock
= ExAllocatePool(NonPagedPool
,
117 sizeof(REMOVE_TRACKING_BLOCK
));
119 if(trackingBlock
== NULL
) {
123 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
126 commonExtension
->RemoveTrackingUntrackedCount
++;
128 DebugPrint((ClassDebugWarning
, ">>>>>ClassAcquireRemoveLock: "
129 "Cannot track Tag %p - currently %d untracked requsts\n",
130 Tag
, commonExtension
->RemoveTrackingUntrackedCount
));
132 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
136 PREMOVE_TRACKING_BLOCK
*removeTrackingList
=
137 (PREMOVE_TRACKING_BLOCK
*)&commonExtension
->RemoveTrackingList
;
141 trackingBlock
->Tag
= Tag
;
143 trackingBlock
->File
= File
;
144 trackingBlock
->Line
= Line
;
146 KeQueryTickCount((&trackingBlock
->TimeLocked
));
148 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
151 while(*removeTrackingList
!= NULL
) {
153 if((*removeTrackingList
)->Tag
> Tag
) {
157 if((*removeTrackingList
)->Tag
== Tag
) {
159 DebugPrint((ClassDebugError
, ">>>>>ClassAcquireRemoveLock: "
160 "already tracking Tag %p\n", Tag
));
161 DebugPrint((ClassDebugError
, ">>>>>ClassAcquireRemoveLock: "
162 "acquired in file %s on line %d\n",
163 (*removeTrackingList
)->File
,
164 (*removeTrackingList
)->Line
));
168 removeTrackingList
= &((*removeTrackingList
)->NextBlock
);
171 trackingBlock
->NextBlock
= *removeTrackingList
;
172 *removeTrackingList
= trackingBlock
;
174 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
182 return (commonExtension
->IsRemoved
);
185 /*++////////////////////////////////////////////////////////////////////////////
187 ClassReleaseRemoveLock()
191 This routine is called to release the remove lock on the device object. It
192 must be called when finished using a previously locked reference to the
193 device object. If an Tag was specified when acquiring the lock then the
194 same Tag must be specified when releasing the lock.
196 When the lock count reduces to zero, this routine will signal the waiting
197 remove Tag to delete the device object. As a result the DeviceObject
198 pointer should not be used again once the lock has been released.
202 DeviceObject - the device object to lock
204 Tag - The irp (if any) specified when acquiring the lock. This is used
205 for lock tracking purposes
214 ClassReleaseRemoveLock(
215 IN PDEVICE_OBJECT DeviceObject
,
219 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
223 PREMOVE_TRACKING_BLOCK
*listEntry
=
224 (PREMOVE_TRACKING_BLOCK
*)&commonExtension
->RemoveTrackingList
;
226 BOOLEAN found
= FALSE
;
230 BOOLEAN isRemoved
= (commonExtension
->IsRemoved
== REMOVE_COMPLETE
);
235 DBGTRAP(("ClassReleaseRemoveLock: REMOVE_COMPLETE set; this should never happen"));
236 InterlockedDecrement(&(commonExtension
->RemoveLock
));
241 // Check the tick count and make sure this thing hasn't been locked
242 // for more than MaxLockedMinutes.
245 maxCount
= KeQueryTimeIncrement() * 10; // microseconds
246 maxCount
*= 1000; // milliseconds
247 maxCount
*= 1000; // seconds
248 maxCount
*= 60; // minutes
249 maxCount
*= MaxLockedMinutes
;
251 DebugPrint((ClassDebugRemoveLock
, "ClassReleaseRemoveLock: "
252 "maxCount = %0I64x\n", maxCount
));
254 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
257 while(*listEntry
!= NULL
) {
259 PREMOVE_TRACKING_BLOCK block
;
260 LARGE_INTEGER difference
;
264 KeQueryTickCount((&difference
));
266 difference
.QuadPart
-= block
->TimeLocked
.QuadPart
;
268 DebugPrint((ClassDebugRemoveLock
, "ClassReleaseRemoveLock: "
269 "Object %p (tag %p) locked for %I64d ticks\n",
270 DeviceObject
, block
->Tag
, difference
.QuadPart
));
272 if(difference
.QuadPart
>= maxCount
) {
274 DebugPrint((ClassDebugError
, ">>>>>ClassReleaseRemoveLock: "
275 "Object %p (tag %p) locked for %I64d ticks - TOO LONG\n",
276 DeviceObject
, block
->Tag
, difference
.QuadPart
));
277 DebugPrint((ClassDebugError
, ">>>>>ClassReleaseRemoveLock: "
278 "Lock acquired in file %s on line %d\n",
279 block
->File
, block
->Line
));
283 if((found
== FALSE
) && ((*listEntry
)->Tag
== Tag
)) {
285 *listEntry
= block
->NextBlock
;
291 listEntry
= &((*listEntry
)->NextBlock
);
297 if(commonExtension
->RemoveTrackingUntrackedCount
== 0) {
298 DebugPrint((ClassDebugError
, ">>>>>ClassReleaseRemoveLock: "
299 "Couldn't find Tag %p in the lock tracking list\n",
303 DebugPrint((ClassDebugError
, ">>>>>ClassReleaseRemoveLock: "
304 "Couldn't find Tag %p in the lock tracking list - "
305 "may be one of the %d untracked requests still "
308 commonExtension
->RemoveTrackingUntrackedCount
));
310 commonExtension
->RemoveTrackingUntrackedCount
--;
311 ASSERT(commonExtension
->RemoveTrackingUntrackedCount
>= 0);
315 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
320 lockValue
= InterlockedDecrement(&commonExtension
->RemoveLock
);
322 DebugPrint((ClassDebugRemoveLock
, "ClassReleaseRemoveLock: "
323 "Released for Object %p & irp %p - count is %d\n",
324 DeviceObject
, Tag
, lockValue
));
326 ASSERT(lockValue
>= 0);
328 ASSERTMSG("RemoveLock decreased to meet LockLowWatermark",
329 ((LockLowWatermark
== 0) || !(lockValue
== LockLowWatermark
)));
333 ASSERT(commonExtension
->IsRemoved
);
336 // The device needs to be removed. Signal the remove event
337 // that it's safe to go ahead.
340 DebugPrint((ClassDebugRemoveLock
, "ClassReleaseRemoveLock: "
341 "Release for object %p & irp %p caused lock to go to zero\n",
344 KeSetEvent(&commonExtension
->RemoveEvent
,
352 /*++////////////////////////////////////////////////////////////////////////////
354 ClassCompleteRequest()
358 This routine is a wrapper around (and should be used instead of)
359 IoCompleteRequest. It is used primarily for debugging purposes.
360 The routine will assert if the Irp being completed is still holding
365 DeviceObject - the device object that was handling this request
367 Irp - the irp to be completed by IoCompleteRequest
369 PriorityBoost - the priority boost to pass to IoCompleteRequest
378 ClassCompleteRequest(
379 IN PDEVICE_OBJECT DeviceObject
,
381 IN CCHAR PriorityBoost
386 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
387 PREMOVE_TRACKING_BLOCK
*listEntry
=
388 (PREMOVE_TRACKING_BLOCK
*)&commonExtension
->RemoveTrackingList
;
392 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
395 while(*listEntry
!= NULL
) {
397 if((*listEntry
)->Tag
== Irp
) {
401 listEntry
= &((*listEntry
)->NextBlock
);
404 if(*listEntry
!= NULL
) {
406 DebugPrint((ClassDebugError
, ">>>>>ClassCompleteRequest: "
407 "Irp %p completed while still holding the remove lock\n",
409 DebugPrint((ClassDebugError
, ">>>>>ClassCompleteRequest: "
410 "Lock acquired in file %s on line %d\n",
411 (*listEntry
)->File
, (*listEntry
)->Line
));
415 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
, oldIrql
);
418 IoCompleteRequest(Irp
, PriorityBoost
);
420 } // end ClassCompleteRequest()