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
82 ClassAcquireRemoveLockEx(
83 IN PDEVICE_OBJECT DeviceObject
,
84 IN OPTIONAL PVOID Tag
,
89 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
95 // Grab the remove lock
97 lockValue
= InterlockedIncrement(&commonExtension
->RemoveLock
);
101 DebugPrint((ClassDebugRemoveLock
, "ClassAcquireRemoveLock: "
102 "Acquired for Object %p & irp %p - count is %d\n",
103 DeviceObject
, Tag
, lockValue
));
105 ASSERTMSG("ClassAcquireRemoveLock - lock value was negative : ",
108 ASSERTMSG("RemoveLock increased to meet LockHighWatermark",
109 ((LockHighWatermark
== 0) ||
110 (lockValue
!= LockHighWatermark
)));
112 if (commonExtension
->IsRemoved
!= REMOVE_COMPLETE
){
113 PREMOVE_TRACKING_BLOCK trackingBlock
;
115 trackingBlock
= ExAllocatePool(NonPagedPool
,
116 sizeof(REMOVE_TRACKING_BLOCK
));
118 if(trackingBlock
== NULL
) {
122 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
125 commonExtension
->RemoveTrackingUntrackedCount
++;
127 DebugPrint((ClassDebugWarning
, ">>>>>ClassAcquireRemoveLock: "
128 "Cannot track Tag %p - currently %d untracked requsts\n",
129 Tag
, commonExtension
->RemoveTrackingUntrackedCount
));
131 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
135 PREMOVE_TRACKING_BLOCK
*removeTrackingList
=
136 (PREMOVE_TRACKING_BLOCK
)&commonExtension
->RemoveTrackingList
;
140 trackingBlock
->Tag
= Tag
;
142 trackingBlock
->File
= File
;
143 trackingBlock
->Line
= Line
;
145 KeQueryTickCount((&trackingBlock
->TimeLocked
));
147 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
150 while(*removeTrackingList
!= NULL
) {
152 if((*removeTrackingList
)->Tag
> Tag
) {
156 if((*removeTrackingList
)->Tag
== Tag
) {
158 DebugPrint((ClassDebugError
, ">>>>>ClassAcquireRemoveLock: "
159 "already tracking Tag %p\n", Tag
));
160 DebugPrint((ClassDebugError
, ">>>>>ClassAcquireRemoveLock: "
161 "acquired in file %s on line %d\n",
162 (*removeTrackingList
)->File
,
163 (*removeTrackingList
)->Line
));
167 removeTrackingList
= &((*removeTrackingList
)->NextBlock
);
170 trackingBlock
->NextBlock
= *removeTrackingList
;
171 *removeTrackingList
= trackingBlock
;
173 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
181 return (commonExtension
->IsRemoved
);
184 /*++////////////////////////////////////////////////////////////////////////////
186 ClassReleaseRemoveLock()
190 This routine is called to release the remove lock on the device object. It
191 must be called when finished using a previously locked reference to the
192 device object. If an Tag was specified when acquiring the lock then the
193 same Tag must be specified when releasing the lock.
195 When the lock count reduces to zero, this routine will signal the waiting
196 remove Tag to delete the device object. As a result the DeviceObject
197 pointer should not be used again once the lock has been released.
201 DeviceObject - the device object to lock
203 Tag - The irp (if any) specified when acquiring the lock. This is used
204 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
375 ClassCompleteRequest(
376 IN PDEVICE_OBJECT DeviceObject
,
378 IN CCHAR PriorityBoost
383 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
384 PREMOVE_TRACKING_BLOCK
*listEntry
=
385 (PREMOVE_TRACKING_BLOCK
)&commonExtension
->RemoveTrackingList
;
389 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
392 while(*listEntry
!= NULL
) {
394 if((*listEntry
)->Tag
== Irp
) {
398 listEntry
= &((*listEntry
)->NextBlock
);
401 if(*listEntry
!= NULL
) {
403 DebugPrint((ClassDebugError
, ">>>>>ClassCompleteRequest: "
404 "Irp %p completed while still holding the remove lock\n",
406 DebugPrint((ClassDebugError
, ">>>>>ClassCompleteRequest: "
407 "Lock acquired in file %s on line %d\n",
408 (*listEntry
)->File
, (*listEntry
)->Line
));
412 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
, oldIrql
);
415 IoCompleteRequest(Irp
, PriorityBoost
);
417 } // end ClassCompleteRequest()