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
84 ClassAcquireRemoveLockEx(
85 IN PDEVICE_OBJECT DeviceObject
,
86 IN OPTIONAL PVOID Tag
,
91 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
97 // Grab the remove lock
99 lockValue
= InterlockedIncrement(&commonExtension
->RemoveLock
);
103 DebugPrint((ClassDebugRemoveLock
, "ClassAcquireRemoveLock: "
104 "Acquired for Object %p & irp %p - count is %d\n",
105 DeviceObject
, Tag
, lockValue
));
107 ASSERTMSG("ClassAcquireRemoveLock - lock value was negative : ",
110 ASSERTMSG("RemoveLock increased to meet LockHighWatermark",
111 ((LockHighWatermark
== 0) ||
112 (lockValue
!= LockHighWatermark
)));
114 if (commonExtension
->IsRemoved
!= REMOVE_COMPLETE
){
115 PREMOVE_TRACKING_BLOCK trackingBlock
;
117 trackingBlock
= ExAllocatePool(NonPagedPool
,
118 sizeof(REMOVE_TRACKING_BLOCK
));
120 if(trackingBlock
== NULL
) {
124 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
127 commonExtension
->RemoveTrackingUntrackedCount
++;
129 DebugPrint((ClassDebugWarning
, ">>>>>ClassAcquireRemoveLock: "
130 "Cannot track Tag %p - currently %d untracked requsts\n",
131 Tag
, commonExtension
->RemoveTrackingUntrackedCount
));
133 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
137 PREMOVE_TRACKING_BLOCK
*removeTrackingList
=
138 (PREMOVE_TRACKING_BLOCK
)&commonExtension
->RemoveTrackingList
;
142 trackingBlock
->Tag
= Tag
;
144 trackingBlock
->File
= File
;
145 trackingBlock
->Line
= Line
;
147 KeQueryTickCount((&trackingBlock
->TimeLocked
));
149 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
152 while(*removeTrackingList
!= NULL
) {
154 if((*removeTrackingList
)->Tag
> Tag
) {
158 if((*removeTrackingList
)->Tag
== Tag
) {
160 DebugPrint((ClassDebugError
, ">>>>>ClassAcquireRemoveLock: "
161 "already tracking Tag %p\n", Tag
));
162 DebugPrint((ClassDebugError
, ">>>>>ClassAcquireRemoveLock: "
163 "acquired in file %s on line %d\n",
164 (*removeTrackingList
)->File
,
165 (*removeTrackingList
)->Line
));
169 removeTrackingList
= &((*removeTrackingList
)->NextBlock
);
172 trackingBlock
->NextBlock
= *removeTrackingList
;
173 *removeTrackingList
= trackingBlock
;
175 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
183 return (commonExtension
->IsRemoved
);
186 /*++////////////////////////////////////////////////////////////////////////////
188 ClassReleaseRemoveLock()
192 This routine is called to release the remove lock on the device object. It
193 must be called when finished using a previously locked reference to the
194 device object. If an Tag was specified when acquiring the lock then the
195 same Tag must be specified when releasing the lock.
197 When the lock count reduces to zero, this routine will signal the waiting
198 remove Tag to delete the device object. As a result the DeviceObject
199 pointer should not be used again once the lock has been released.
203 DeviceObject - the device object to lock
205 Tag - The irp (if any) specified when acquiring the lock. This is used
206 for lock tracking purposes
216 ClassReleaseRemoveLock(
217 IN PDEVICE_OBJECT DeviceObject
,
221 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
225 PREMOVE_TRACKING_BLOCK
*listEntry
=
226 (PREMOVE_TRACKING_BLOCK
)&commonExtension
->RemoveTrackingList
;
228 BOOLEAN found
= FALSE
;
232 BOOLEAN isRemoved
= (commonExtension
->IsRemoved
== REMOVE_COMPLETE
);
237 DBGTRAP(("ClassReleaseRemoveLock: REMOVE_COMPLETE set; this should never happen"));
238 InterlockedDecrement(&(commonExtension
->RemoveLock
));
243 // Check the tick count and make sure this thing hasn't been locked
244 // for more than MaxLockedMinutes.
247 maxCount
= KeQueryTimeIncrement() * 10; // microseconds
248 maxCount
*= 1000; // milliseconds
249 maxCount
*= 1000; // seconds
250 maxCount
*= 60; // minutes
251 maxCount
*= MaxLockedMinutes
;
253 DebugPrint((ClassDebugRemoveLock
, "ClassReleaseRemoveLock: "
254 "maxCount = %0I64x\n", maxCount
));
256 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
259 while(*listEntry
!= NULL
) {
261 PREMOVE_TRACKING_BLOCK block
;
262 LARGE_INTEGER difference
;
266 KeQueryTickCount((&difference
));
268 difference
.QuadPart
-= block
->TimeLocked
.QuadPart
;
270 DebugPrint((ClassDebugRemoveLock
, "ClassReleaseRemoveLock: "
271 "Object %p (tag %p) locked for %I64d ticks\n",
272 DeviceObject
, block
->Tag
, difference
.QuadPart
));
274 if(difference
.QuadPart
>= maxCount
) {
276 DebugPrint((ClassDebugError
, ">>>>>ClassReleaseRemoveLock: "
277 "Object %p (tag %p) locked for %I64d ticks - TOO LONG\n",
278 DeviceObject
, block
->Tag
, difference
.QuadPart
));
279 DebugPrint((ClassDebugError
, ">>>>>ClassReleaseRemoveLock: "
280 "Lock acquired in file %s on line %d\n",
281 block
->File
, block
->Line
));
285 if((found
== FALSE
) && ((*listEntry
)->Tag
== Tag
)) {
287 *listEntry
= block
->NextBlock
;
293 listEntry
= &((*listEntry
)->NextBlock
);
299 if(commonExtension
->RemoveTrackingUntrackedCount
== 0) {
300 DebugPrint((ClassDebugError
, ">>>>>ClassReleaseRemoveLock: "
301 "Couldn't find Tag %p in the lock tracking list\n",
305 DebugPrint((ClassDebugError
, ">>>>>ClassReleaseRemoveLock: "
306 "Couldn't find Tag %p in the lock tracking list - "
307 "may be one of the %d untracked requests still "
310 commonExtension
->RemoveTrackingUntrackedCount
));
312 commonExtension
->RemoveTrackingUntrackedCount
--;
313 ASSERT(commonExtension
->RemoveTrackingUntrackedCount
>= 0);
317 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
322 lockValue
= InterlockedDecrement(&commonExtension
->RemoveLock
);
324 DebugPrint((ClassDebugRemoveLock
, "ClassReleaseRemoveLock: "
325 "Released for Object %p & irp %p - count is %d\n",
326 DeviceObject
, Tag
, lockValue
));
328 ASSERT(lockValue
>= 0);
330 ASSERTMSG("RemoveLock decreased to meet LockLowWatermark",
331 ((LockLowWatermark
== 0) || !(lockValue
== LockLowWatermark
)));
335 ASSERT(commonExtension
->IsRemoved
);
338 // The device needs to be removed. Signal the remove event
339 // that it's safe to go ahead.
342 DebugPrint((ClassDebugRemoveLock
, "ClassReleaseRemoveLock: "
343 "Release for object %p & irp %p caused lock to go to zero\n",
346 KeSetEvent(&commonExtension
->RemoveEvent
,
354 /*++////////////////////////////////////////////////////////////////////////////
356 ClassCompleteRequest()
360 This routine is a wrapper around (and should be used instead of)
361 IoCompleteRequest. It is used primarily for debugging purposes.
362 The routine will assert if the Irp being completed is still holding
367 DeviceObject - the device object that was handling this request
369 Irp - the irp to be completed by IoCompleteRequest
371 PriorityBoost - the priority boost to pass to IoCompleteRequest
381 ClassCompleteRequest(
382 IN PDEVICE_OBJECT DeviceObject
,
384 IN CCHAR PriorityBoost
389 PCOMMON_DEVICE_EXTENSION commonExtension
= DeviceObject
->DeviceExtension
;
390 PREMOVE_TRACKING_BLOCK
*listEntry
=
391 (PREMOVE_TRACKING_BLOCK
)&commonExtension
->RemoveTrackingList
;
395 KeAcquireSpinLock(&commonExtension
->RemoveTrackingSpinlock
,
398 while(*listEntry
!= NULL
) {
400 if((*listEntry
)->Tag
== Irp
) {
404 listEntry
= &((*listEntry
)->NextBlock
);
407 if(*listEntry
!= NULL
) {
409 DebugPrint((ClassDebugError
, ">>>>>ClassCompleteRequest: "
410 "Irp %p completed while still holding the remove lock\n",
412 DebugPrint((ClassDebugError
, ">>>>>ClassCompleteRequest: "
413 "Lock acquired in file %s on line %d\n",
414 (*listEntry
)->File
, (*listEntry
)->Line
));
418 KeReleaseSpinLock(&commonExtension
->RemoveTrackingSpinlock
, oldIrql
);
421 IoCompleteRequest(Irp
, PriorityBoost
);
423 } // end ClassCompleteRequest()