IoSecondStageCompletion(): +Handle/set 'Irp->UserIosb'
[reactos.git] / ntoskrnl / io / cleanup.c
1 /*
2  * COPYRIGHT:      See COPYING in the top level directory
3  * PROJECT:        ReactOS kernel
4  * FILE:           ntoskrnl/io/cleanup.c
5  * PURPOSE:        IRP cleanup
6  * PROGRAMMER:     David Welch (welch@mcmail.com)
7  * UPDATE HISTORY:
8  *                 30/05/98: Created
9  */
10
11 /* INCLUDES ****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <internal/io.h>
15 #include <internal/ob.h>
16 #include <internal/mm.h>
17 #include <internal/ps.h>
18
19 #define NDEBUG
20 #include <internal/debug.h>
21
22 /* FUNCTIONS ***************************************************************/
23
24 VOID STDCALL
25 IopCompleteRequest1(struct _KAPC* Apc,
26                     PKNORMAL_ROUTINE* NormalRoutine,
27                     PVOID* NormalContext,
28                     PVOID* SystemArgument1,
29                     PVOID* SystemArgument2)
30 {
31    PIRP Irp;
32    CCHAR PriorityBoost;
33    PIO_STACK_LOCATION IoStack;
34    PFILE_OBJECT FileObject;
35    
36    DPRINT("IopCompleteRequest1()\n");
37    
38    Irp = (PIRP)(*SystemArgument1);
39    PriorityBoost = (CCHAR)(LONG)(*SystemArgument2);
40    
41    IoStack = &Irp->Stack[(ULONG)Irp->CurrentLocation];
42    FileObject = IoStack->FileObject;
43    
44    (*SystemArgument1) = (PVOID)Irp->UserIosb;
45    (*SystemArgument2) = (PVOID)Irp->IoStatus.Information;
46    
47    if (Irp->UserIosb!=NULL)
48      {
49         *Irp->UserIosb=Irp->IoStatus;
50      }
51
52    if (Irp->UserEvent)
53    {
54       KeSetEvent(Irp->UserEvent,PriorityBoost,FALSE);
55    }
56
57    if (!(Irp->Flags & IRP_PAGING_IO) && FileObject)
58    {
59       // if the event is not the one in the file object, it needs dereferenced
60       if (Irp->UserEvent && Irp->UserEvent != &FileObject->Event)
61          ObDereferenceObject(Irp->UserEvent);
62
63       if (IoStack->MajorFunction != IRP_MJ_CLOSE)
64       {
65          ObDereferenceObject(FileObject);
66       }
67    }
68    
69    IoFreeIrp(Irp);
70
71 }
72
73 VOID IoDeviceControlCompletion(PDEVICE_OBJECT DeviceObject,
74                                PIRP Irp,
75                                PIO_STACK_LOCATION IoStack)
76 {
77    ULONG IoControlCode;
78    
79    IoControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
80    
81    switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
82      {
83       case METHOD_BUFFERED:
84         DPRINT ("Using METHOD_BUFFERED!\n");
85         
86         /* copy output buffer back and free it */
87         if (Irp->AssociatedIrp.SystemBuffer)
88           {
89              if (IoStack->Parameters.DeviceIoControl.OutputBufferLength)
90                {
91                   RtlCopyMemory(Irp->UserBuffer,
92                                 Irp->AssociatedIrp.SystemBuffer,
93                                 IoStack->Parameters.DeviceIoControl.
94                                 OutputBufferLength);
95                }
96              ExFreePool (Irp->AssociatedIrp.SystemBuffer);
97           }
98         break;
99         
100       case METHOD_IN_DIRECT:
101         DPRINT ("Using METHOD_IN_DIRECT!\n");
102         
103         /* free input buffer (control buffer) */
104         if (Irp->AssociatedIrp.SystemBuffer)
105           ExFreePool (Irp->AssociatedIrp.SystemBuffer);
106         
107         /* free output buffer (data transfer buffer) */
108         if (Irp->MdlAddress)
109           IoFreeMdl (Irp->MdlAddress);
110         break;
111         
112       case METHOD_OUT_DIRECT:
113         DPRINT ("Using METHOD_OUT_DIRECT!\n");
114         
115         /* free input buffer (control buffer) */
116         if (Irp->AssociatedIrp.SystemBuffer)
117           ExFreePool (Irp->AssociatedIrp.SystemBuffer);
118         
119         /* free output buffer (data transfer buffer) */
120         if (Irp->MdlAddress)
121           IoFreeMdl (Irp->MdlAddress);
122         break;
123         
124       case METHOD_NEITHER:
125         DPRINT ("Using METHOD_NEITHER!\n");
126         /* nothing to do */
127         break;
128      }
129 }
130
131 VOID IoReadWriteCompletion(PDEVICE_OBJECT DeviceObject,
132                            PIRP Irp,
133                            PIO_STACK_LOCATION IoStack)
134 {   
135    PFILE_OBJECT FileObject;
136    
137    FileObject = IoStack->FileObject;
138    
139    if (DeviceObject->Flags & DO_BUFFERED_IO)     
140      {
141         if (IoStack->MajorFunction == IRP_MJ_READ)
142           {
143              DPRINT("Copying buffered io back to user\n");
144              memcpy(Irp->UserBuffer,Irp->AssociatedIrp.SystemBuffer,
145                     IoStack->Parameters.Read.Length);
146           }
147         ExFreePool(Irp->AssociatedIrp.SystemBuffer);
148      }
149    if (DeviceObject->Flags & DO_DIRECT_IO)
150      {
151         /* FIXME: Is the MDL destroyed on a paging i/o, check all cases. */
152         DPRINT("Tearing down MDL\n");
153         if (Irp->MdlAddress->MappedSystemVa != NULL)
154           {          
155              MmUnmapLockedPages(Irp->MdlAddress->MappedSystemVa,
156                                 Irp->MdlAddress);
157           }
158         MmUnlockPages(Irp->MdlAddress);
159         ExFreePool(Irp->MdlAddress);
160      }
161 }
162
163 VOID IoVolumeInformationCompletion(PDEVICE_OBJECT DeviceObject,
164                                    PIRP Irp,
165                                    PIO_STACK_LOCATION IoStack)
166 {
167 }
168
169 VOID IoSecondStageCompletion(PIRP Irp, CCHAR PriorityBoost)
170 /*
171  * FUNCTION: Performs the second stage of irp completion for read/write irps
172  * ARGUMENTS:
173  *          Irp = Irp to completion
174  *          FromDevice = True if the operation transfered data from the device
175  */
176 {
177    PIO_STACK_LOCATION IoStack;
178    PDEVICE_OBJECT DeviceObject;
179    PFILE_OBJECT FileObject;
180    
181    DPRINT("IoSecondStageCompletion(Irp %x, PriorityBoost %d)\n",
182           Irp, PriorityBoost);
183    
184    /* FIXME: Should we set 'Irp->UserIosb' only on MasterIrp finalization
185     * or we should set it for each subrequest?
186     */
187    if (Irp->UserIosb)
188       {
189          *Irp->UserIosb=Irp->IoStatus;
190       }
191    
192    /* Handling only subrequest of AssociatedIrp group from MasterIrp?
193     * Is it the last subrequest?
194     * FIXME: It appears to me as if 'Irp->AssociatedIrp.IrpCount' is +1 than expected. :-?
195     */
196    if (Irp->Flags & IRP_ASSOCIATED_IRP)
197       {
198          Irp=Irp->AssociatedIrp.MasterIrp;
199          if (!Irp)
200             KeBugCheck(0);
201          if (!Irp->AssociatedIrp.IrpCount)
202             KeBugCheck(0);      /* Completion of already completed MasterIrp? */
203          /* TODO:thread */
204          if (--Irp->AssociatedIrp.IrpCount)
205             return;     /* not yet fully completed MasterIrp */
206          if (Irp->UserIosb)
207             {
208                *Irp->UserIosb=Irp->IoStatus;
209             }
210       }
211    
212    IoStack = &Irp->Stack[(ULONG)Irp->CurrentLocation];
213    FileObject = IoStack->FileObject;
214    
215    DeviceObject = IoStack->DeviceObject;
216    
217    switch (IoStack->MajorFunction)
218      {
219       case IRP_MJ_CREATE:
220       case IRP_MJ_FLUSH_BUFFERS:
221           /* NOP */
222         break;
223         
224       case IRP_MJ_READ:
225       case IRP_MJ_WRITE:
226         IoReadWriteCompletion(DeviceObject,Irp,IoStack);
227         break;
228         
229       case IRP_MJ_DEVICE_CONTROL:
230       case IRP_MJ_INTERNAL_DEVICE_CONTROL:
231         IoDeviceControlCompletion(DeviceObject, Irp, IoStack);
232         break;
233         
234       case IRP_MJ_QUERY_VOLUME_INFORMATION:
235       case IRP_MJ_SET_VOLUME_INFORMATION:
236         IoVolumeInformationCompletion(DeviceObject, Irp, IoStack);
237         break;
238         
239       default:
240         break;
241      }
242    
243    if (Irp->Overlay.AsynchronousParameters.UserApcRoutine != NULL)
244      {
245 #ifndef LIBCAPTIVE
246         PKTHREAD Thread;
247         PKNORMAL_ROUTINE UserApcRoutine;
248         PVOID UserApcContext;
249 #endif /* LIBCAPTIVE */
250         
251         DPRINT("Dispatching APC\n");
252 #ifndef LIBCAPTIVE
253         Thread = &Irp->Tail.Overlay.Thread->Tcb;
254         UserApcRoutine = (PKNORMAL_ROUTINE)
255           Irp->Overlay.AsynchronousParameters.UserApcRoutine;
256         UserApcContext = (PVOID)
257           Irp->Overlay.AsynchronousParameters.UserApcContext;
258         KeInitializeApc(&Irp->Tail.Apc,
259                         Thread,
260                         0,
261                         IopCompleteRequest1,
262                         NULL,
263                         UserApcRoutine,
264                         UserMode,
265                         UserApcContext);
266         KeInsertQueueApc(&Irp->Tail.Apc,
267                          Irp,
268                          (PVOID)(LONG)PriorityBoost,
269                          KernelMode);
270 #else /* !LIBCAPTIVE */
271         KeBugCheck(0);
272 #endif /* !LIBCAPTIVE */
273         return;
274      }
275    
276    DPRINT("Irp->UserIosb %x &Irp->UserIosb %x\n", 
277            Irp->UserIosb,
278            &Irp->UserIosb);
279    if (Irp->UserIosb!=NULL)
280      {
281         *Irp->UserIosb=Irp->IoStatus;
282      }
283
284    if (Irp->UserEvent)
285    {
286       KeSetEvent(Irp->UserEvent,PriorityBoost,FALSE);
287    }
288
289    if (!(Irp->Flags & IRP_PAGING_IO) && FileObject)
290    {
291       // if the event is not the one in the file object, it needs dereferenced
292       if (Irp->UserEvent && Irp->UserEvent != &FileObject->Event)
293          ObDereferenceObject(Irp->UserEvent);
294
295       if (IoStack->MajorFunction != IRP_MJ_CLOSE)
296       {
297          ObDereferenceObject(FileObject);
298       }
299    }
300
301    IoFreeIrp(Irp);
302 }