ec4514911a18533fcf86bf21801f04374101b0dc
[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 #ifndef LIBCAPTIVE
64
65 /*
66  * @unimplemented
67  */
68 PIRP STDCALL
69 IoMakeAssociatedIrp(PIRP Irp,
70                     CCHAR StackSize)
71 /*
72  * FUNCTION: Allocates and initializes an irp to associated with a master irp
73  * ARGUMENTS:
74  *       Irp = Master irp
75  *       StackSize = Number of stack locations to be allocated in the irp
76  * RETURNS: The irp allocated
77  */
78 {
79   PIRP AssocIrp;
80   
81   AssocIrp = IoAllocateIrp(StackSize,FALSE);
82   UNIMPLEMENTED;
83   return NULL;
84 }
85
86 #endif /* LIBCAPTIVE */
87
88 /*
89  * @implemented
90  */
91 VOID STDCALL
92 IoInitializeIrp(PIRP Irp,
93                 USHORT PacketSize,
94                 CCHAR StackSize)
95 /*
96  * FUNCTION: Initalizes an irp allocated by the caller
97  * ARGUMENTS:
98  *          Irp = IRP to initalize
99  *          PacketSize = Size in bytes of the IRP
100  *          StackSize = Number of stack locations in the IRP
101  */
102 {
103   assert(Irp != NULL);
104
105   memset(Irp, 0, PacketSize);
106   Irp->Type = IO_TYPE_IRP;
107   Irp->Size = PacketSize;
108   Irp->StackCount = StackSize;
109   Irp->CurrentLocation = StackSize;
110   Irp->Tail.Overlay.CurrentStackLocation = &Irp->Stack[(ULONG)StackSize];
111 }
112
113
114 /*
115  * @implemented
116  */
117 NTSTATUS FASTCALL
118 IofCallDriver(PDEVICE_OBJECT DeviceObject,
119               PIRP Irp)
120 /*
121   * FUNCTION: Sends an IRP to the next lower driver
122  */
123 {
124   PDRIVER_OBJECT DriverObject;
125   PIO_STACK_LOCATION Param;
126   
127   DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
128   
129   assert(Irp);
130   assert(DeviceObject);
131
132   DriverObject = DeviceObject->DriverObject;
133
134   assert(DriverObject);
135
136   IoSetNextIrpStackLocation(Irp);
137   Param = IoGetCurrentIrpStackLocation(Irp);
138
139   DPRINT("IrpSp 0x%X\n", Param);
140   
141   Param->DeviceObject = DeviceObject;
142
143   DPRINT("MajorFunction %d\n", Param->MajorFunction);
144   DPRINT("DriverObject->MajorFunction[Param->MajorFunction] %x\n",
145     DriverObject->MajorFunction[Param->MajorFunction]);
146
147   if (!DriverObject->MajorFunction[Param->MajorFunction])
148     {
149       if (Param->MajorFunction==IRP_MJ_FLUSH_BUFFERS)
150         {
151           ObDereferenceObject(Param->FileObject);
152           return STATUS_SUCCESS;
153         }
154       KeBugCheck(0);
155     }
156
157 #ifndef LIBCAPTIVE
158   return DriverObject->MajorFunction[Param->MajorFunction](DeviceObject, Irp);
159 #else /* !LIBCAPTIVE */
160         return (NTSTATUS)captive_stdcall_call_8(
161                         (CaptiveStdCallFunc8)DriverObject->MajorFunction[Param->MajorFunction],
162                         DeviceObject,
163                         Irp);
164 #endif /* LIBCAPTIVE */
165 }
166
167
168 /*
169  * @implemented
170  */
171 NTSTATUS
172 STDCALL
173 IoCallDriver (PDEVICE_OBJECT DeviceObject, PIRP Irp)
174 {
175   return(IofCallDriver(DeviceObject,
176                        Irp));
177 }
178
179
180 /*
181  * @implemented
182  */
183 PIRP STDCALL
184 IoAllocateIrp(CCHAR StackSize,
185               BOOLEAN ChargeQuota)
186 /*
187  * FUNCTION: Allocates an IRP
188  * ARGUMENTS:
189  *          StackSize = the size of the stack required for the irp
190  *          ChargeQuota = Charge allocation to current threads quota
191  * RETURNS: Irp allocated
192  */
193 {
194   PIRP Irp;
195
196 #if 0
197   DbgPrint("IoAllocateIrp(StackSize %d ChargeQuota %d)\n",
198            StackSize,
199            ChargeQuota);
200   KeDumpStackFrames(0,8);
201 #endif
202   
203   if (ChargeQuota)
204     {
205 //      Irp = ExAllocatePoolWithQuota(NonPagedPool,IoSizeOfIrp(StackSize));
206       Irp = ExAllocatePoolWithTag(NonPagedPool,
207                                   IoSizeOfIrp(StackSize),
208                                   TAG_IRP);
209     }
210   else
211     {
212       Irp = ExAllocatePoolWithTag(NonPagedPool,
213                                   IoSizeOfIrp(StackSize),
214                                   TAG_IRP);
215     }
216
217   if (Irp==NULL)
218     {
219       return(NULL);
220     }
221
222   IoInitializeIrp(Irp,
223                   IoSizeOfIrp(StackSize),
224                   StackSize);
225
226 //  DPRINT("Irp %x Irp->StackPtr %d\n", Irp, Irp->CurrentLocation);
227
228   return(Irp);
229 }
230
231
232 #ifdef LIBCAPTIVE
233 /* file-scope of libcaptive/io/irp.c: */
234 extern void IofCompleteRequest_register_APC(PFILE_OBJECT OriginalFileObject,PIRP Irp,CCHAR PriorityBoost);
235 #endif /* LIBCAPTIVE */
236
237 /*
238  * @implemented
239  */
240 VOID FASTCALL
241 IofCompleteRequest(PIRP Irp,
242          CCHAR PriorityBoost)
243 /*
244  * FUNCTION: Indicates the caller has finished all processing for a given
245  * I/O request and is returning the given IRP to the I/O manager
246  * ARGUMENTS:
247  *         Irp = Irp to be cancelled
248  *         PriorityBoost = Increment by which to boost the priority of the
249  *                         thread making the request
250  */
251 {
252    ULONG             i;
253    NTSTATUS          Status;
254    PDEVICE_OBJECT    DeviceObject;
255    PFILE_OBJECT      OriginalFileObject;
256
257    DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
258       Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
259
260    assert(Irp->CancelRoutine == NULL);
261    assert(Irp->IoStatus.Status != STATUS_PENDING);
262
263    if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
264    {
265       Irp->PendingReturned = TRUE;
266    }
267
268    for (i=Irp->CurrentLocation;i<(ULONG)Irp->StackCount;i++)
269    {
270       /*
271       Completion routines expect the current irp stack location to be the same as when
272       IoSetCompletionRoutine was called to set them. A side effect is that completion
273       routines set by highest level drivers without their own stack location will receive
274       an invalid current stack location (at least it should be considered as invalid).
275       Since the DeviceObject argument passed is taken from the current stack, this value
276       is also invalid (NULL).
277       */
278       if (Irp->CurrentLocation < Irp->StackCount - 1)
279       {
280          IoSetPreviousIrpStackLocation(Irp);
281          DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
282       }
283       else
284       {
285          DeviceObject = NULL;
286       }
287
288       if (Irp->Stack[i].CompletionRoutine != NULL &&
289          ((NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_SUCCESS)) ||
290          (!NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_ERROR)) ||
291          (Irp->Cancel && (Irp->Stack[i].Control & SL_INVOKE_ON_CANCEL))))
292       {
293          Status = Irp->Stack[i].CompletionRoutine(DeviceObject,
294                                                   Irp,
295                                                   Irp->Stack[i].Context);
296
297          if (Status == STATUS_MORE_PROCESSING_REQUIRED)
298          {
299             if (Irp->UserIosb)
300                {
301                   *Irp->UserIosb=Irp->IoStatus;
302                }
303             return;
304          }
305       }
306    
307       if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
308       {
309          Irp->PendingReturned = TRUE;
310       }
311    }
312
313    //Windows NT File System Internals, page 154
314    OriginalFileObject = Irp->Tail.Overlay.OriginalFileObject;
315
316    if (Irp->PendingReturned)
317    {
318 #ifndef LIBCAPTIVE
319       BOOLEAN bStatus;
320 #endif /* LIBCAPTIVE */
321
322 #ifdef LIBCAPTIVE
323       /* FIXME: Why the hell should we bother with some damned APCs?!?
324        * Call it directly below!
325        */
326       DPRINT("IofCompleteRequest() dispatching APC: using g_idle_add_full()\n");
327       IofCompleteRequest_register_APC(OriginalFileObject,Irp,PriorityBoost);
328 #else /* !LIBCAPTIVE */
329       DPRINT("Dispatching APC\n");
330       KeInitializeApc(  &Irp->Tail.Apc,
331                         &Irp->Tail.Overlay.Thread->Tcb,
332                         OriginalApcEnvironment,
333                         IoSecondStageCompletion,
334                         NULL,
335                         (PKNORMAL_ROUTINE) NULL,
336                         KernelMode,
337                         OriginalFileObject);
338       
339       bStatus = KeInsertQueueApc(&Irp->Tail.Apc,
340                                  (PVOID)Irp,
341                                  (PVOID)(ULONG)PriorityBoost,
342                                  PriorityBoost);
343
344       if (bStatus == FALSE)
345       {
346          DPRINT1("Error queueing APC for thread. Thread has probably exited.\n");
347       }
348 #endif /* !LIBCAPTIVE */
349
350       DPRINT("Finished dispatching APC\n");
351    }
352    else
353    {
354       DPRINT("Calling IoSecondStageCompletion routine directly\n");
355       IoSecondStageCompletion(NULL,NULL,(PVOID)&OriginalFileObject,(PVOID) &Irp,(PVOID) &PriorityBoost);
356       DPRINT("Finished completition routine\n");
357    }
358
359 }
360
361
362 /*
363  * @implemented
364  */
365 VOID STDCALL
366 IoCompleteRequest(PIRP Irp,
367                   CCHAR PriorityBoost)
368 {
369   IofCompleteRequest(Irp,
370                      PriorityBoost);
371 }
372
373
374 /**********************************************************************
375  * NAME                                                 EXPORTED
376  *      IoIsOperationSynchronous@4
377  *
378  * DESCRIPTION
379  *      Check if the I/O operation associated with the given IRP
380  *      is synchronous.
381  *
382  * ARGUMENTS
383  *      Irp     Packet to check.
384  *
385  * RETURN VALUE
386  *      TRUE if Irp's operation is synchronous; otherwise FALSE.
387  *
388  * @implemented
389  */
390 BOOLEAN STDCALL
391 IoIsOperationSynchronous(IN PIRP Irp)
392 {
393    PFILE_OBJECT FileObject = NULL;
394    ULONG Flags;
395
396   /* Check the FILE_OBJECT's flags first. */
397   FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
398   if (FileObject == NULL)
399     KeBugCheck(0);
400   if (!(FO_SYNCHRONOUS_IO & FileObject->Flags))
401     {
402       /* Check IRP's flags. */
403       Flags = Irp->Flags;
404       if (!((IRP_SYNCHRONOUS_API | IRP_SYNCHRONOUS_PAGING_IO) & Flags))
405         {
406 #ifdef LIBCAPTIVE
407           /* libcaptive is fully single-thread/single-process synchronous model. */
408           return TRUE;
409 #endif /* LIBCAPTIVE */
410           return(FALSE);
411         }
412     }
413   
414    if (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO)
415    {
416       return TRUE;
417    }
418
419    if (Irp->Flags & IRP_PAGING_IO)
420    {
421 #ifdef LIBCAPTIVE
422       /* libcaptive is fully single-thread/single-process synchronous model. */
423       return TRUE;
424 #endif /* LIBCAPTIVE */
425       return FALSE;
426    }
427
428    //NOTE: Windows 2000 crash if IoStack->FileObject == NULL, so I guess we should too;-)
429    if (Irp->Flags & IRP_SYNCHRONOUS_API || FileObject->Flags & FO_SYNCHRONOUS_IO)
430    {
431       return TRUE;
432    }
433
434    /* Otherwise, it is an asynchronous operation. */
435 #ifdef LIBCAPTIVE
436   /* libcaptive is fully single-thread/single-process synchronous model. */
437   return TRUE;
438 #endif /* LIBCAPTIVE */
439    return FALSE;
440 }
441
442 #ifndef LIBCAPTIVE
443
444 /*
445  * @unimplemented
446  */
447 VOID STDCALL
448 IoEnqueueIrp(IN PIRP Irp)
449 {
450   UNIMPLEMENTED;
451 }
452
453 #endif /* LIBCAPTIVE */
454
455 /*
456  * @implemented
457  */
458 VOID STDCALL
459 IoSetTopLevelIrp(IN PIRP Irp)
460 {
461   PETHREAD Thread;
462
463   Thread = PsGetCurrentThread();
464   Thread->TopLevelIrp->TopLevelIrp = Irp;
465 }
466
467
468 /*
469  * @implemented
470  */
471 PIRP STDCALL
472 IoGetTopLevelIrp(VOID)
473 {
474   return(PsGetCurrentThread()->TopLevelIrp->TopLevelIrp);
475 }
476
477 #ifndef LIBCAPTIVE
478
479 /*
480  * @unimplemented
481  */
482 VOID STDCALL
483 IoQueueThreadIrp(IN PIRP Irp)
484 {
485   UNIMPLEMENTED;
486 }
487
488 #endif /* LIBCAPTIVE */
489
490 /* EOF */