1619680ecba52de8d1f8c7e2c67b331651bebba9
[reactos.git] / ntoskrnl / io / irp.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/io/irp.c
6  * PURPOSE:         Handle IRPs
7  * PROGRAMMER:      David Welch (welch@mcmail.com)
8  * UPDATE HISTORY: 
9  *                  24/05/98: Created 
10  */
11
12 /* NOTES *******************************************************************
13  * 
14  * Layout of an IRP 
15  * 
16  *             ################
17  *             #    Headers   #
18  *             ################
19  *             #              #
20  *             #   Variable   #
21  *             # length list  #
22  *             # of io stack  #
23  *             #  locations   #
24  *             #              #
25  *             ################
26  * 
27  * 
28  * 
29  */
30
31 /* INCLUDES ****************************************************************/
32
33 #include <ddk/ntddk.h>
34 #include <internal/io.h>
35 #include <internal/ps.h>
36 #include <internal/pool.h>
37
38 #define NDEBUG
39 #include <internal/debug.h>
40
41 /* GLOBALS *******************************************************************/
42
43 #define TAG_IRP     TAG('I', 'R', 'P', ' ')
44
45
46 /* FUNCTIONS ****************************************************************/
47
48
49 /*
50  * @implemented
51  */
52 VOID STDCALL
53 IoFreeIrp(PIRP Irp)
54 /*
55  * FUNCTION: Releases a caller allocated irp
56  * ARGUMENTS:
57  *      Irp = Irp to free
58  */
59 {
60   ExFreePool(Irp);
61 }
62
63
64 /*
65  * @unimplemented
66  */
67 PIRP STDCALL
68 IoMakeAssociatedIrp(PIRP Irp,
69                     CCHAR StackSize)
70 /*
71  * FUNCTION: Allocates and initializes an irp to associated with a master irp
72  * ARGUMENTS:
73  *       Irp = Master irp
74  *       StackSize = Number of stack locations to be allocated in the irp
75  * RETURNS: The irp allocated
76  */
77 {
78   PIRP AssocIrp;
79   
80   AssocIrp = IoAllocateIrp(StackSize,FALSE);
81   UNIMPLEMENTED;
82   return NULL;
83 }
84
85
86 /*
87  * @implemented
88  */
89 VOID STDCALL
90 IoInitializeIrp(PIRP Irp,
91                 USHORT PacketSize,
92                 CCHAR StackSize)
93 /*
94  * FUNCTION: Initalizes an irp allocated by the caller
95  * ARGUMENTS:
96  *          Irp = IRP to initalize
97  *          PacketSize = Size in bytes of the IRP
98  *          StackSize = Number of stack locations in the IRP
99  */
100 {
101   assert(Irp != NULL);
102
103   memset(Irp, 0, PacketSize);
104   Irp->Size = PacketSize;
105   Irp->StackCount = StackSize;
106   Irp->CurrentLocation = StackSize;
107   Irp->Tail.Overlay.CurrentStackLocation = &Irp->Stack[(ULONG)StackSize];
108 }
109
110
111 /*
112  * @implemented
113  */
114 NTSTATUS FASTCALL
115 IofCallDriver(PDEVICE_OBJECT DeviceObject,
116               PIRP Irp)
117 /*
118   * FUNCTION: Sends an IRP to the next lower driver
119  */
120 {
121   PDRIVER_OBJECT DriverObject;
122   PIO_STACK_LOCATION Param;
123   
124   DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
125   
126   assert(Irp);
127   assert(DeviceObject);
128
129   DriverObject = DeviceObject->DriverObject;
130
131   assert(DriverObject);
132
133   IoSetNextIrpStackLocation(Irp);
134   Param = IoGetCurrentIrpStackLocation(Irp);
135
136   DPRINT("IrpSp 0x%X\n", Param);
137   
138   Param->DeviceObject = DeviceObject;
139
140   DPRINT("MajorFunction %d\n", Param->MajorFunction);
141   DPRINT("DriverObject->MajorFunction[Param->MajorFunction] %x\n",
142     DriverObject->MajorFunction[Param->MajorFunction]);
143
144   return DriverObject->MajorFunction[Param->MajorFunction](DeviceObject, Irp);
145 }
146
147
148 /*
149  * @implemented
150  */
151 NTSTATUS
152 STDCALL
153 IoCallDriver (PDEVICE_OBJECT DeviceObject, PIRP Irp)
154 {
155   return(IofCallDriver(DeviceObject,
156                        Irp));
157 }
158
159
160 /*
161  * @implemented
162  */
163 PIRP STDCALL
164 IoAllocateIrp(CCHAR StackSize,
165               BOOLEAN ChargeQuota)
166 /*
167  * FUNCTION: Allocates an IRP
168  * ARGUMENTS:
169  *          StackSize = the size of the stack required for the irp
170  *          ChargeQuota = Charge allocation to current threads quota
171  * RETURNS: Irp allocated
172  */
173 {
174   PIRP Irp;
175
176 #if 0
177   DbgPrint("IoAllocateIrp(StackSize %d ChargeQuota %d)\n",
178            StackSize,
179            ChargeQuota);
180   KeDumpStackFrames(0,8);
181 #endif
182   
183   if (ChargeQuota)
184     {
185 //      Irp = ExAllocatePoolWithQuota(NonPagedPool,IoSizeOfIrp(StackSize));
186       Irp = ExAllocatePoolWithTag(NonPagedPool,
187                                   IoSizeOfIrp(StackSize),
188                                   TAG_IRP);
189     }
190   else
191     {
192       Irp = ExAllocatePoolWithTag(NonPagedPool,
193                                   IoSizeOfIrp(StackSize),
194                                   TAG_IRP);
195     }
196
197   if (Irp==NULL)
198     {
199       return(NULL);
200     }
201
202   IoInitializeIrp(Irp,
203                   IoSizeOfIrp(StackSize),
204                   StackSize);
205
206 //  DPRINT("Irp %x Irp->StackPtr %d\n", Irp, Irp->CurrentLocation);
207
208   return(Irp);
209 }
210
211
212 /*
213  * @implemented
214  */
215 VOID FASTCALL
216 IofCompleteRequest(PIRP Irp,
217          CCHAR PriorityBoost)
218 /*
219  * FUNCTION: Indicates the caller has finished all processing for a given
220  * I/O request and is returning the given IRP to the I/O manager
221  * ARGUMENTS:
222  *         Irp = Irp to be cancelled
223  *         PriorityBoost = Increment by which to boost the priority of the
224  *                         thread making the request
225  */
226 {
227    ULONG             i;
228    NTSTATUS          Status;
229    PDEVICE_OBJECT    DeviceObject;
230    PFILE_OBJECT      OriginalFileObject;
231
232    DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
233       Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
234
235    assert(Irp->CancelRoutine == NULL);
236    assert(Irp->IoStatus.Status != STATUS_PENDING);
237
238    if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
239    {
240       Irp->PendingReturned = TRUE;
241    }
242
243    for (i=Irp->CurrentLocation;i<(ULONG)Irp->StackCount;i++)
244    {
245       /*
246       Completion routines expect the current irp stack location to be the same as when
247       IoSetCompletionRoutine was called to set them. A side effect is that completion
248       routines set by highest level drivers without their own stack location will receive
249       an invalid current stack location (at least it should be considered as invalid).
250       Since the DeviceObject argument passed is taken from the current stack, this value
251       is also invalid (NULL).
252       */
253       if (Irp->CurrentLocation < Irp->StackCount - 1)
254       {
255          IoSetPreviousIrpStackLocation(Irp);
256          DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
257       }
258       else
259       {
260          DeviceObject = NULL;
261       }
262
263       if (Irp->Stack[i].CompletionRoutine != NULL &&
264          ((NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_SUCCESS)) ||
265          (!NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_ERROR)) ||
266          (Irp->Cancel && (Irp->Stack[i].Control & SL_INVOKE_ON_CANCEL))))
267       {
268          Status = Irp->Stack[i].CompletionRoutine(DeviceObject,
269                                                   Irp,
270                                                   Irp->Stack[i].Context);
271
272          if (Status == STATUS_MORE_PROCESSING_REQUIRED)
273          {
274             return;
275          }
276       }
277    
278       if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
279       {
280          Irp->PendingReturned = TRUE;
281       }
282    }
283
284    //Windows NT File System Internals, page 154
285    OriginalFileObject = Irp->Tail.Overlay.OriginalFileObject;
286
287    if (Irp->PendingReturned)
288    {
289       BOOLEAN bStatus;
290
291       DPRINT("Dispatching APC\n");
292       KeInitializeApc(  &Irp->Tail.Apc,
293                         &Irp->Tail.Overlay.Thread->Tcb,
294                         OriginalApcEnvironment,
295                         IoSecondStageCompletion,
296                         NULL,
297                         (PKNORMAL_ROUTINE) NULL,
298                         KernelMode,
299                         OriginalFileObject);
300       
301       bStatus = KeInsertQueueApc(&Irp->Tail.Apc,
302                                  (PVOID)Irp,
303                                  (PVOID)(ULONG)PriorityBoost,
304                                  PriorityBoost);
305
306       if (bStatus == FALSE)
307       {
308          DPRINT1("Error queueing APC for thread. Thread has probably exited.\n");
309       }
310
311       DPRINT("Finished dispatching APC\n");
312    }
313    else
314    {
315       DPRINT("Calling IoSecondStageCompletion routine directly\n");
316       IoSecondStageCompletion(NULL,NULL,(PVOID)&OriginalFileObject,(PVOID) &Irp,(PVOID) &PriorityBoost);
317       DPRINT("Finished completition routine\n");
318    }
319
320 }
321
322
323 /*
324  * @implemented
325  */
326 VOID STDCALL
327 IoCompleteRequest(PIRP Irp,
328                   CCHAR PriorityBoost)
329 {
330   IofCompleteRequest(Irp,
331                      PriorityBoost);
332 }
333
334
335 /**********************************************************************
336  * NAME                                                 EXPORTED
337  *      IoIsOperationSynchronous@4
338  *
339  * DESCRIPTION
340  *      Check if the I/O operation associated with the given IRP
341  *      is synchronous.
342  *
343  * ARGUMENTS
344  *      Irp     Packet to check.
345  *
346  * RETURN VALUE
347  *      TRUE if Irp's operation is synchronous; otherwise FALSE.
348  *
349  * @implemented
350  */
351 BOOLEAN STDCALL
352 IoIsOperationSynchronous(IN PIRP Irp)
353 {
354    PFILE_OBJECT FileObject = NULL;
355
356    FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
357   
358    if (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO)
359    {
360       return TRUE;
361    }
362
363    if (Irp->Flags & IRP_PAGING_IO)
364    {
365       return FALSE;
366    }
367
368    //NOTE: Windows 2000 crash if IoStack->FileObject == NULL, so I guess we should too;-)
369    if (Irp->Flags & IRP_SYNCHRONOUS_API || FileObject->Flags & FO_SYNCHRONOUS_IO)
370    {
371       return TRUE;
372    }
373
374    /* Otherwise, it is an asynchronous operation. */
375    return FALSE;
376 }
377
378
379 /*
380  * @unimplemented
381  */
382 VOID STDCALL
383 IoEnqueueIrp(IN PIRP Irp)
384 {
385   UNIMPLEMENTED;
386 }
387
388
389 /*
390  * @implemented
391  */
392 VOID STDCALL
393 IoSetTopLevelIrp(IN PIRP Irp)
394 {
395   PETHREAD Thread;
396
397   Thread = PsGetCurrentThread();
398   Thread->TopLevelIrp->TopLevelIrp = Irp;
399 }
400
401
402 /*
403  * @implemented
404  */
405 PIRP STDCALL
406 IoGetTopLevelIrp(VOID)
407 {
408   return(PsGetCurrentThread()->TopLevelIrp->TopLevelIrp);
409 }
410
411
412 /*
413  * @unimplemented
414  */
415 VOID STDCALL
416 IoQueueThreadIrp(IN PIRP Irp)
417 {
418   UNIMPLEMENTED;
419 }
420
421 /* EOF */