ReactOS  0.4.14-dev-583-g2a1ba2c
queue.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
3  * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE: USB block storage device driver.
5  * COPYRIGHT: 2005-2006 James Tabor
6  * 2011-2012 Michael Martin (michael.martin@reactos.org)
7  * 2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org)
8  */
9 
10 #include "usbstor.h"
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 
16 VOID
18  PFDO_DEVICE_EXTENSION FDODeviceExtension)
19 {
20  ASSERT(FDODeviceExtension->Common.IsFDO);
21  KeInitializeSpinLock(&FDODeviceExtension->IrpListLock);
22  InitializeListHead(&FDODeviceExtension->IrpListHead);
23  KeInitializeEvent(&FDODeviceExtension->NoPendingRequests, NotificationEvent, TRUE);
24 }
25 
26 VOID
27 NTAPI
30  IN PIRP Irp)
31 {
32  PFDO_DEVICE_EXTENSION FDODeviceExtension;
33 
34  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
36  ASSERT(FDODeviceExtension->Common.IsFDO);
37 
38  // this IRP isn't in our list here
39  // now release the cancel lock
40  IoReleaseCancelSpinLock(Irp->CancelIrql);
41  Irp->IoStatus.Status = STATUS_CANCELLED;
42 
45 
47 }
48 
49 VOID
50 NTAPI
53  IN PIRP Irp)
54 {
55  PFDO_DEVICE_EXTENSION FDODeviceExtension;
56 
57  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
59  ASSERT(FDODeviceExtension->Common.IsFDO);
60 
61  KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension->IrpListLock);
62  RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
63  KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->IrpListLock);
64 
65  IoReleaseCancelSpinLock(Irp->CancelIrql);
66  Irp->IoStatus.Status = STATUS_CANCELLED;
67 
70 
72 }
73 
74 BOOLEAN
77  IN PIRP Irp)
78 {
79  PDRIVER_CANCEL OldDriverCancel;
80  KIRQL OldLevel;
81  PFDO_DEVICE_EXTENSION FDODeviceExtension;
82  BOOLEAN IrpListFreeze;
83  BOOLEAN SrbProcessing;
85  PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
86 
87  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
88  ASSERT(FDODeviceExtension->Common.IsFDO);
89 
91 
92  KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
93 
94  SrbProcessing = FDODeviceExtension->IrpPendingCount != 0;
95 
96  if (SrbProcessing)
97  {
98  // add irp to queue
99  InsertTailList(&FDODeviceExtension->IrpListHead, &Irp->Tail.Overlay.ListEntry);
100  }
101 
102  FDODeviceExtension->IrpPendingCount++;
103  KeClearEvent(&FDODeviceExtension->NoPendingRequests);
104 
105  // check if queue is freezed
106  IrpListFreeze = BooleanFlagOn(FDODeviceExtension->Flags, USBSTOR_FDO_FLAGS_IRP_LIST_FREEZE);
107 
108  KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
109 
110  // synchronize with cancellations by holding the cancel lock
111  IoAcquireCancelSpinLock(&Irp->CancelIrql);
112 
113  if (SrbProcessing)
114  {
115  ASSERT(FDODeviceExtension->ActiveSrb != NULL);
116 
117  OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_Cancel);
118  }
119  else
120  {
121  ASSERT(FDODeviceExtension->ActiveSrb == NULL);
122 
123  FDODeviceExtension->ActiveSrb = Request;
124  OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_CancelIo);
125  }
126 
127  // check if the irp has already been cancelled
128  if (Irp->Cancel && OldDriverCancel == NULL)
129  {
130  // cancel irp
131  Irp->CancelRoutine(DeviceObject, Irp);
132  return FALSE;
133  }
134 
135  IoReleaseCancelSpinLock(Irp->CancelIrql);
136 
137  // if list is freezed, dont start this packet
138  DPRINT("IrpListFreeze: %lu IrpPendingCount %lu\n", IrpListFreeze, FDODeviceExtension->IrpPendingCount);
139 
140  return (IrpListFreeze || SrbProcessing);
141 }
142 
143 PIRP
146 {
147  KIRQL OldLevel;
148  PFDO_DEVICE_EXTENSION FDODeviceExtension;
150  PIRP Irp = NULL;
151 
152  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
153  ASSERT(FDODeviceExtension->Common.IsFDO);
154 
155  KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
156 
157  if (!IsListEmpty(&FDODeviceExtension->IrpListHead))
158  {
159  Entry = RemoveHeadList(&FDODeviceExtension->IrpListHead);
160 
161  // get offset to start of irp
162  Irp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
163  }
164 
165  KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
166 
167  return Irp;
168 }
169 
170 VOID
173 {
174  PFDO_DEVICE_EXTENSION FDODeviceExtension;
175 
176  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
177 
178  KeWaitForSingleObject(&FDODeviceExtension->NoPendingRequests,
179  Executive,
180  KernelMode,
181  FALSE,
182  NULL);
183 }
184 
185 VOID
187  IN PDEVICE_OBJECT FDODeviceObject,
188  IN PIRP Irp)
189 {
190  KIRQL OldLevel;
191  PFDO_DEVICE_EXTENSION FDODeviceExtension;
193  PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
194 
195  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FDODeviceObject->DeviceExtension;
196  ASSERT(FDODeviceExtension->Common.IsFDO);
197 
198  KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
199 
200  FDODeviceExtension->IrpPendingCount--;
201 
202  // check if this was our current active SRB
203  if (FDODeviceExtension->ActiveSrb == Request)
204  {
205  // indicate processing is completed
206  FDODeviceExtension->ActiveSrb = NULL;
207  }
208 
209  // Set the event if nothing else is pending
210  if (FDODeviceExtension->IrpPendingCount == 0 &&
211  FDODeviceExtension->ActiveSrb == NULL)
212  {
213  KeSetEvent(&FDODeviceExtension->NoPendingRequests, IO_NO_INCREMENT, FALSE);
214  }
215 
216  KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
217 }
218 
219 VOID
222 {
223  PFDO_DEVICE_EXTENSION FDODeviceExtension;
224  PIRP Irp;
225  PIO_STACK_LOCATION IoStack;
227 
228  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
229  ASSERT(FDODeviceExtension->Common.IsFDO);
230 
231  // check first if there's already a request pending or the queue is frozen
232  if (FDODeviceExtension->ActiveSrb != NULL ||
234  {
235  // no work to do yet
236  return;
237  }
238 
239  // remove first irp from list
241 
242  // is there an irp pending
243  if (!Irp)
244  {
245  // no work to do
247  return;
248  }
249 
251  Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
252  ASSERT(Request);
253 
254  FDODeviceExtension->ActiveSrb = Request;
255 
256  // start next packet
259 }
260 
261 VOID
264 {
265  PFDO_DEVICE_EXTENSION FDODeviceExtension;
266  PIRP Irp;
267  KIRQL OldLevel;
268  PIO_STACK_LOCATION IoStack;
270 
271  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
272  ASSERT(FDODeviceExtension->Common.IsFDO);
273 
274  KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
275 
276  // clear freezed status
277  FDODeviceExtension->Flags &= ~USBSTOR_FDO_FLAGS_IRP_LIST_FREEZE;
278 
279  KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
280 
281  // grab newest irp
283 
284  if (!Irp)
285  {
286  return;
287  }
288 
290  Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
291 
293  Irp,
294  &Request->QueueSortKey,
296 }
297 
298 VOID
299 NTAPI
302  PIRP Irp)
303 {
304  PIO_STACK_LOCATION IoStack;
306  PFDO_DEVICE_EXTENSION FDODeviceExtension;
307  PPDO_DEVICE_EXTENSION PDODeviceExtension;
308  KIRQL OldLevel;
309  BOOLEAN ResetInProgress;
310 
311  DPRINT("USBSTOR_StartIo\n");
312 
313  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
314  ASSERT(FDODeviceExtension->Common.IsFDO);
315 
316  IoAcquireCancelSpinLock(&OldLevel);
317 
319 
320  // check if the irp has been cancelled
321  if (Irp->Cancel)
322  {
323  IoReleaseCancelSpinLock(OldLevel);
324 
325  Irp->IoStatus.Status = STATUS_CANCELLED;
326  Irp->IoStatus.Information = 0;
327 
331  return;
332  }
333 
334  IoReleaseCancelSpinLock(OldLevel);
335 
336  KeAcquireSpinLock(&FDODeviceExtension->CommonLock, &OldLevel);
337  ResetInProgress = BooleanFlagOn(FDODeviceExtension->Flags, USBSTOR_FDO_FLAGS_DEVICE_RESETTING);
338  KeReleaseSpinLock(&FDODeviceExtension->CommonLock, OldLevel);
339 
341 
342  PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension;
343  Request = IoStack->Parameters.Scsi.Srb;
344  ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
345 
346  if (ResetInProgress)
347  {
348  // hard reset is in progress
349  Request->SrbStatus = SRB_STATUS_NO_DEVICE;
350  Request->DataTransferLength = 0;
351  Irp->IoStatus.Information = 0;
352  Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
356  return;
357  }
358 
360 
361  // FIXME: handle error
362 }
#define STATUS_DEVICE_DOES_NOT_EXIST
Definition: ntstatus.h:414
#define IN
Definition: typedefs.h:38
DRIVER_CANCEL * PDRIVER_CANCEL
Definition: iotypes.h:2405
#define TRUE
Definition: types.h:120
VOID NTAPI USBSTOR_CancelIo(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: queue.c:28
struct _Entry Entry
Definition: kefuncs.h:640
struct _SCSI_REQUEST_BLOCK * PSCSI_REQUEST_BLOCK
_In_ PIRP Irp
Definition: csq.h:116
#define BooleanFlagOn(F, SF)
Definition: ext2fs.h:183
#define ASSERT_IRQL_EQUAL(x)
Definition: debug.h:43
LIST_ENTRY ListEntry
Definition: pci.h:82
VOID NTAPI KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:192
VOID NTAPI IoAcquireCancelSpinLock(OUT PKIRQL Irql)
Definition: util.c:56
struct _PDO_DEVICE_EXTENSION * PPDO_DEVICE_EXTENSION
BOOLEAN USBSTOR_QueueAddIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: queue.c:75
#define SRB_STATUS_NO_DEVICE
Definition: srb.h:340
NTSTATUS USBSTOR_HandleExecuteSCSI(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: scsi.c:560
IRP
Definition: iotypes.h:2463
#define InsertTailList(ListHead, Entry)
IoSetCancelRoutine(Irp, CancelRoutine)
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
struct _FDO_DEVICE_EXTENSION * PFDO_DEVICE_EXTENSION
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
_In_ NDIS_HANDLE _In_ PNDIS_REQUEST Request
Definition: ndis.h:5173
UCHAR KIRQL
Definition: env_spec_w32.h:591
VOID USBSTOR_QueueNextRequest(IN PDEVICE_OBJECT DeviceObject)
Definition: queue.c:220
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
VOID USBSTOR_QueueRelease(IN PDEVICE_OBJECT DeviceObject)
Definition: queue.c:262
FORCEINLINE VOID KeInitializeSpinLock(_Out_ PKSPIN_LOCK SpinLock)
Definition: kefuncs.h:251
VOID NTAPI IoStartPacket(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PULONG Key, IN PDRIVER_CANCEL CancelFunction)
Definition: device.c:1876
PVOID DeviceExtension
Definition: env_spec_w32.h:418
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define IoCompleteRequest
Definition: irp.c:1240
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
COMMON_DEVICE_EXTENSION Common
Definition: pci.h:55
void DPRINT(...)
Definition: polytest.cpp:61
VOID USBSTOR_QueueTerminateRequest(IN PDEVICE_OBJECT FDODeviceObject, IN PIRP Irp)
Definition: queue.c:186
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
VOID NTAPI KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:215
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
PDEVICE_OBJECT DeviceObject
Definition: iotypes.h:2867
VOID USBSTOR_QueueInitialize(PFDO_DEVICE_EXTENSION FDODeviceExtension)
Definition: queue.c:17
VOID NTAPI USBSTOR_StartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: queue.c:300
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define USBSTOR_FDO_FLAGS_DEVICE_RESETTING
Definition: usbstor.h:45
Definition: typedefs.h:117
COMMON_DEVICE_EXTENSION Common
Definition: pci.h:80
VOID NTAPI IoReleaseCancelSpinLock(IN KIRQL Irql)
Definition: util.c:150
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
VOID USBSTOR_QueueWaitForPendingRequests(IN PDEVICE_OBJECT DeviceObject)
Definition: queue.c:171
PVOID PIRP
Definition: usb.h:38
#define USBSTOR_FDO_FLAGS_IRP_LIST_FREEZE
Definition: usbstor.h:46
#define IO_NO_INCREMENT
Definition: iotypes.h:566
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2772
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
IoMarkIrpPending(Irp)
PIRP USBSTOR_RemoveIrp(IN PDEVICE_OBJECT DeviceObject)
Definition: queue.c:144
base of all file and directory entries
Definition: entries.h:82
VOID NTAPI USBSTOR_Cancel(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: queue.c:51
VOID NTAPI IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject, IN BOOLEAN Cancelable)
Definition: device.c:1847