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.
27 LONG LockHighWatermark
= 0;
28 LONG LockLowWatermark
= 0;
29 LONG MaxLockedMinutes
= 5;
32 // Structure used for tracking remove lock allocations in checked builds
34 typedef struct _REMOVE_TRACKING_BLOCK
{
35 struct _REMOVE_TRACKING_BLOCK
*NextBlock
;
37 LARGE_INTEGER TimeLocked
;
40 } REMOVE_TRACKING_BLOCK
, *PREMOVE_TRACKING_BLOCK
;
43 /*++////////////////////////////////////////////////////////////////////////////
45 ClassAcquireRemoveLockEx()
49 This routine is called to acquire the remove lock on the device object.
50 While the lock is held, the caller can assume that no pending pnp REMOVE
51 requests will be completed.
53 The lock should be acquired immediately upon entering a dispatch routine.
54 It should also be acquired before creating any new reference to the
55 device object if there's a chance of releasing the reference before the
58 This routine will return TRUE if the lock was successfully acquired or
59 FALSE if it cannot be because the device object has already been removed.
63 DeviceObject - the device object to lock
65 Tag - Used for tracking lock allocation and release. If an irp is
66 specified when acquiring the lock then the same Tag must be
67 used to release the lock before the Tag is completed.
71 The value of the IsRemoved flag in the device extension. If this is
72 non-zero then the device object has received a Remove irp and non-cleanup
75 If the value is REMOVE_COMPLETE, the caller should not even release the
81 ClassAcquireRemoveLockEx(
82 IN PDEVICE_OBJECT DeviceObject
,
83 IN OPTIONAL PVOID Tag
,
88 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
94 // Grab the remove lock
96 lockValue
= InterlockedIncrement(&commonExtension
->RemoveLock
);
100 DebugPrint((ClassDebugRemoveLock
, "ClassAcquireRemoveLock: "
101 "Acquired for Object %p & irp %p - count is %d\n",
102 DeviceObject
, Tag
, lockValue
));
104 ASSERTMSG("ClassAcquireRemoveLock - lock value was negative : ",
107 ASSERTMSG("RemoveLock increased to meet LockHighWatermark",
108 ((LockHighWatermark
== 0) ||
109 (lockValue
!= LockHighWatermark
)));
111 if (commonExtension
->IsRemoved
!= REMOVE_COMPLETE
){
112 PREMOVE_TRACKING_BLOCK trackingBlock
;
114 trackingBlock
= ExAllocatePool(NonPagedPool
,
115 sizeof(REMOVE_TRACKING_BLOCK
));
117 if(trackingBlock
== NULL
) {
121 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
124 commonExtension
->RemoveTrackingUntrackedCount
++;
126 DebugPrint((ClassDebugWarning
, ">>>>>ClassAcquireRemoveLock: "
127 "Cannot track Tag %p - currently %d untracked requsts\n",
128 Tag
, commonExtension
->RemoveTrackingUntrackedCount
));
130 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
134 PREMOVE_TRACKING_BLOCK
*removeTrackingList
=
135 (PREMOVE_TRACKING_BLOCK
*)&commonExtension
->RemoveTrackingList
;
139 trackingBlock
->Tag
= Tag
;
141 trackingBlock
->File
= File
;
142 trackingBlock
->Line
= Line
;
144 KeQueryTickCount((&trackingBlock
->TimeLocked
));
146 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
149 while(*removeTrackingList
!= NULL
) {
151 if((*removeTrackingList
)->Tag
> Tag
) {
155 if((*removeTrackingList
)->Tag
== Tag
) {
157 DebugPrint((ClassDebugError
, ">>>>>ClassAcquireRemoveLock: "
158 "already tracking Tag %p\n", Tag
));
159 DebugPrint((ClassDebugError
, ">>>>>ClassAcquireRemoveLock: "
160 "acquired in file %s on line %d\n",
161 (*removeTrackingList
)->File
,
162 (*removeTrackingList
)->Line
));
166 removeTrackingList
= &((*removeTrackingList
)->NextBlock
);
169 trackingBlock
->NextBlock
= *removeTrackingList
;
170 *removeTrackingList
= trackingBlock
;
172 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
180 return (commonExtension
->IsRemoved
);
183 /*++////////////////////////////////////////////////////////////////////////////
185 ClassReleaseRemoveLock()
189 This routine is called to release the remove lock on the device object. It
190 must be called when finished using a previously locked reference to the
191 device object. If an Tag was specified when acquiring the lock then the
192 same Tag must be specified when releasing the lock.
194 When the lock count reduces to zero, this routine will signal the waiting
195 remove Tag to delete the device object. As a result the DeviceObject
196 pointer should not be used again once the lock has been released.
200 DeviceObject - the device object to lock
202 Tag - The irp (if any) specified when acquiring the lock. This is used
203 for lock tracking purposes
212 ClassReleaseRemoveLock(
213 IN PDEVICE_OBJECT DeviceObject
,
217 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
221 PREMOVE_TRACKING_BLOCK
*listEntry
=
222 (PREMOVE_TRACKING_BLOCK
*)&commonExtension
->RemoveTrackingList
;
224 BOOLEAN found
= FALSE
;
228 BOOLEAN isRemoved
= (commonExtension
->IsRemoved
== REMOVE_COMPLETE
);
233 DBGTRAP(("ClassReleaseRemoveLock: REMOVE_COMPLETE set; this should never happen"));
234 InterlockedDecrement(&(commonExtension
->RemoveLock
));
239 // Check the tick count and make sure this thing hasn't been locked
240 // for more than MaxLockedMinutes.
243 maxCount
= KeQueryTimeIncrement() * 10; // microseconds
244 maxCount
*= 1000; // milliseconds
245 maxCount
*= 1000; // seconds
246 maxCount
*= 60; // minutes
247 maxCount
*= MaxLockedMinutes
;
249 DebugPrint((ClassDebugRemoveLock
, "ClassReleaseRemoveLock: "
250 "maxCount = %0I64x\n", maxCount
));
252 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
255 while(*listEntry
!= NULL
) {
257 PREMOVE_TRACKING_BLOCK block
;
258 LARGE_INTEGER difference
;
262 KeQueryTickCount((&difference
));
264 difference
.QuadPart
-= block
->TimeLocked
.QuadPart
;
266 DebugPrint((ClassDebugRemoveLock
, "ClassReleaseRemoveLock: "
267 "Object %p (tag %p) locked for %I64d ticks\n",
268 DeviceObject
, block
->Tag
, difference
.QuadPart
));
270 if(difference
.QuadPart
>= maxCount
) {
272 DebugPrint((ClassDebugError
, ">>>>>ClassReleaseRemoveLock: "
273 "Object %p (tag %p) locked for %I64d ticks - TOO LONG\n",
274 DeviceObject
, block
->Tag
, difference
.QuadPart
));
275 DebugPrint((ClassDebugError
, ">>>>>ClassReleaseRemoveLock: "
276 "Lock acquired in file %s on line %d\n",
277 block
->File
, block
->Line
));
281 if((found
== FALSE
) && ((*listEntry
)->Tag
== Tag
)) {
283 *listEntry
= block
->NextBlock
;
289 listEntry
= &((*listEntry
)->NextBlock
);
295 if(commonExtension
->RemoveTrackingUntrackedCount
== 0) {
296 DebugPrint((ClassDebugError
, ">>>>>ClassReleaseRemoveLock: "
297 "Couldn't find Tag %p in the lock tracking list\n",
301 DebugPrint((ClassDebugError
, ">>>>>ClassReleaseRemoveLock: "
302 "Couldn't find Tag %p in the lock tracking list - "
303 "may be one of the %d untracked requests still "
306 commonExtension
->RemoveTrackingUntrackedCount
));
308 commonExtension
->RemoveTrackingUntrackedCount
--;
309 ASSERT(commonExtension
->RemoveTrackingUntrackedCount
>= 0);
313 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
318 lockValue
= InterlockedDecrement(&commonExtension
->RemoveLock
);
320 DebugPrint((ClassDebugRemoveLock
, "ClassReleaseRemoveLock: "
321 "Released for Object %p & irp %p - count is %d\n",
322 DeviceObject
, Tag
, lockValue
));
324 ASSERT(lockValue
>= 0);
326 ASSERTMSG("RemoveLock decreased to meet LockLowWatermark",
327 ((LockLowWatermark
== 0) || !(lockValue
== LockLowWatermark
)));
331 ASSERT(commonExtension
->IsRemoved
);
334 // The device needs to be removed. Signal the remove event
335 // that it's safe to go ahead.
338 DebugPrint((ClassDebugRemoveLock
, "ClassReleaseRemoveLock: "
339 "Release for object %p & irp %p caused lock to go to zero\n",
342 KeSetEvent(&commonExtension
->RemoveEvent
,
350 /*++////////////////////////////////////////////////////////////////////////////
352 ClassCompleteRequest()
356 This routine is a wrapper around (and should be used instead of)
357 IoCompleteRequest. It is used primarily for debugging purposes.
358 The routine will assert if the Irp being completed is still holding
363 DeviceObject - the device object that was handling this request
365 Irp - the irp to be completed by IoCompleteRequest
367 PriorityBoost - the priority boost to pass to IoCompleteRequest
376 ClassCompleteRequest(
377 IN PDEVICE_OBJECT DeviceObject
,
379 IN CCHAR PriorityBoost
384 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
385 PREMOVE_TRACKING_BLOCK
*listEntry
=
386 (PREMOVE_TRACKING_BLOCK
*)&commonExtension
->RemoveTrackingList
;
390 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
393 while(*listEntry
!= NULL
) {
395 if((*listEntry
)->Tag
== Irp
) {
399 listEntry
= &((*listEntry
)->NextBlock
);
402 if(*listEntry
!= NULL
) {
404 DebugPrint((ClassDebugError
, ">>>>>ClassCompleteRequest: "
405 "Irp %p completed while still holding the remove lock\n",
407 DebugPrint((ClassDebugError
, ">>>>>ClassCompleteRequest: "
408 "Lock acquired in file %s on line %d\n",
409 (*listEntry
)->File
, (*listEntry
)->Line
));
413 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
, oldIrql
);
416 IoCompleteRequest(Irp
, PriorityBoost
);
418 } // end ClassCompleteRequest()