update for HEAD-2003091401
[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 IoDeviceControlCompletion(PDEVICE_OBJECT DeviceObject,
25                                PIRP Irp,
26                                PIO_STACK_LOCATION IoStack)
27 {
28    ULONG IoControlCode;
29    ULONG OutputBufferLength;
30
31    if (IoStack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL)
32      {
33        IoControlCode = 
34          ((PEXTENDED_IO_STACK_LOCATION)IoStack)->Parameters.FileSystemControl.FsControlCode;
35        OutputBufferLength = 
36          ((PEXTENDED_IO_STACK_LOCATION)IoStack)->Parameters.FileSystemControl.OutputBufferLength;
37      }
38    else
39      {
40        IoControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
41        OutputBufferLength = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
42      }
43    
44    switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
45      {
46       case METHOD_BUFFERED:
47         DPRINT ("Using METHOD_BUFFERED!\n");
48         
49         /* copy output buffer back and free it */
50         if (Irp->AssociatedIrp.SystemBuffer)
51           {
52              if (OutputBufferLength)
53                {
54                   RtlCopyMemory(Irp->UserBuffer,
55                                 Irp->AssociatedIrp.SystemBuffer,
56                                 OutputBufferLength);
57                }
58              ExFreePool (Irp->AssociatedIrp.SystemBuffer);
59           }
60         break;
61         
62       case METHOD_IN_DIRECT:
63         DPRINT ("Using METHOD_IN_DIRECT!\n");
64
65         /* copy output buffer back and free it */
66         if (Irp->AssociatedIrp.SystemBuffer)
67           {
68              if (OutputBufferLength)
69                {
70                   RtlCopyMemory(Irp->UserBuffer,
71                                 Irp->AssociatedIrp.SystemBuffer,
72                                 OutputBufferLength);
73                }
74             ExFreePool (Irp->AssociatedIrp.SystemBuffer);
75           }
76         
77         /* free input buffer (data transfer buffer) */
78         if (Irp->MdlAddress)
79           IoFreeMdl (Irp->MdlAddress);
80         break;
81         
82       case METHOD_OUT_DIRECT:
83         DPRINT ("Using METHOD_OUT_DIRECT!\n");
84         
85         /* free input buffer (control buffer) */
86         if (Irp->AssociatedIrp.SystemBuffer)
87           ExFreePool (Irp->AssociatedIrp.SystemBuffer);
88         
89         /* free output buffer (data transfer buffer) */
90         if (Irp->MdlAddress)
91           IoFreeMdl (Irp->MdlAddress);
92         break;
93         
94       case METHOD_NEITHER:
95         DPRINT ("Using METHOD_NEITHER!\n");
96         /* nothing to do */
97         break;
98      }
99 }
100
101 VOID IoReadWriteCompletion(PDEVICE_OBJECT DeviceObject,
102                            PIRP Irp,
103                            PIO_STACK_LOCATION IoStack)
104 {   
105    PFILE_OBJECT FileObject;
106    
107    FileObject = IoStack->FileObject;
108    
109    if (DeviceObject->Flags & DO_BUFFERED_IO)     
110      {
111         if (IoStack->MajorFunction == IRP_MJ_READ)
112           {
113              DPRINT("Copying buffered io back to user\n");
114              memcpy(Irp->UserBuffer,Irp->AssociatedIrp.SystemBuffer,
115                     IoStack->Parameters.Read.Length);
116           }
117         ExFreePool(Irp->AssociatedIrp.SystemBuffer);
118      }
119    if (DeviceObject->Flags & DO_DIRECT_IO)
120      {
121         /* FIXME: Is the MDL destroyed on a paging i/o, check all cases. */
122         DPRINT("Tearing down MDL\n");
123         if (Irp->MdlAddress->MappedSystemVa != NULL)
124           {          
125              MmUnmapLockedPages(Irp->MdlAddress->MappedSystemVa,
126                                 Irp->MdlAddress);
127           }
128         MmUnlockPages(Irp->MdlAddress);
129         ExFreePool(Irp->MdlAddress);
130      }
131 }
132
133 VOID IoVolumeInformationCompletion(PDEVICE_OBJECT DeviceObject,
134                                    PIRP Irp,
135                                    PIO_STACK_LOCATION IoStack)
136 {
137 }
138
139
140 VOID STDCALL
141 IoSecondStageCompletion_KernelApcRoutine(
142     IN PKAPC Apc,
143     IN OUT PKNORMAL_ROUTINE *NormalRoutine,
144     IN OUT PVOID *NormalContext,
145     IN OUT PVOID *SystemArgument1,
146     IN OUT PVOID *SystemArgument2
147     )
148 {
149    IoFreeIrp((PIRP)(*SystemArgument1));
150 }
151
152
153 VOID STDCALL
154 IoSecondStageCompletion_RundownApcRoutine(
155    IN PKAPC Apc
156    )
157 {
158    PIRP Irp;
159
160    Irp = CONTAINING_RECORD(Apc, IRP, Tail.Apc);
161    IoFreeIrp(Irp);
162 }
163
164
165 /*
166  * FUNCTION: Performs the second stage of irp completion for read/write irps
167  * 
168  * Called as a special kernel APC or directly from IofCompleteRequest()
169  */
170 VOID STDCALL
171 IoSecondStageCompletion(
172    PKAPC Apc,
173    PKNORMAL_ROUTINE* NormalRoutine,
174    PVOID* NormalContext,
175    PVOID* SystemArgument1,
176    PVOID* SystemArgument2)
177
178 {
179    PIO_STACK_LOCATION   IoStack;
180    PDEVICE_OBJECT       DeviceObject;
181    PFILE_OBJECT         OriginalFileObject;
182    PIRP                 Irp;
183    CCHAR                PriorityBoost;
184
185    OriginalFileObject = (PFILE_OBJECT)(*NormalContext);
186    Irp = (PIRP)(*SystemArgument1);
187    PriorityBoost = (CCHAR)(LONG)(*SystemArgument2);
188    
189    IoStack = &Irp->Stack[(ULONG)Irp->CurrentLocation];
190    DeviceObject = IoStack->DeviceObject;
191
192    DPRINT("IoSecondStageCompletion(Irp %x, PriorityBoost %d)\n", Irp, PriorityBoost);
193
194    switch (IoStack->MajorFunction)
195      {
196       case IRP_MJ_CREATE:
197       case IRP_MJ_FLUSH_BUFFERS:
198         /* NOP */
199         break;
200    
201       case IRP_MJ_READ:
202       case IRP_MJ_WRITE:
203         IoReadWriteCompletion(DeviceObject,Irp,IoStack);
204         break;
205    
206       case IRP_MJ_DEVICE_CONTROL:
207       case IRP_MJ_INTERNAL_DEVICE_CONTROL:
208       case IRP_MJ_FILE_SYSTEM_CONTROL:
209         IoDeviceControlCompletion(DeviceObject, Irp, IoStack);
210         break;
211    
212       case IRP_MJ_QUERY_VOLUME_INFORMATION:
213       case IRP_MJ_SET_VOLUME_INFORMATION:
214         IoVolumeInformationCompletion(DeviceObject, Irp, IoStack);
215         break;
216    
217       default:
218         break;
219      }
220    
221    if (Irp->UserIosb!=NULL)
222    {
223       *Irp->UserIosb=Irp->IoStatus;
224    }
225
226    if (Irp->UserEvent)
227    {
228       KeSetEvent(Irp->UserEvent,PriorityBoost,FALSE);
229    }
230
231    //Windows NT File System Internals, page 169
232    if (OriginalFileObject)
233    {
234       if (Irp->UserEvent == NULL)
235       {
236          KeSetEvent(&OriginalFileObject->Event,PriorityBoost,FALSE);         
237       }
238       else if (OriginalFileObject->Flags & FO_SYNCHRONOUS_IO && Irp->UserEvent != &OriginalFileObject->Event)
239       {
240          KeSetEvent(&OriginalFileObject->Event,PriorityBoost,FALSE);         
241       }
242    }
243
244    //Windows NT File System Internals, page 154
245    if (!(Irp->Flags & IRP_PAGING_IO) && OriginalFileObject)
246    {
247       // if the event is not the one in the file object, it needs dereferenced   
248       if (Irp->UserEvent && Irp->UserEvent != &OriginalFileObject->Event)   
249       {
250          ObDereferenceObject(Irp->UserEvent);
251       }
252   
253       if (IoStack->MajorFunction != IRP_MJ_CLOSE)
254       {
255          ObDereferenceObject(OriginalFileObject);
256       }
257    }
258
259    if (Irp->Overlay.AsynchronousParameters.UserApcRoutine != NULL)
260    {
261       PKNORMAL_ROUTINE UserApcRoutine;
262       PVOID UserApcContext;
263    
264       DPRINT("Dispatching user APC\n");
265
266       UserApcRoutine = (PKNORMAL_ROUTINE)Irp->Overlay.AsynchronousParameters.UserApcRoutine;
267       UserApcContext = (PVOID)Irp->Overlay.AsynchronousParameters.UserApcContext;
268
269       KeInitializeApc(  &Irp->Tail.Apc,
270                         KeGetCurrentThread(),
271                         OriginalApcEnvironment,
272                         IoSecondStageCompletion_KernelApcRoutine,
273                         IoSecondStageCompletion_RundownApcRoutine,
274                         UserApcRoutine,
275                         UserMode,
276                         UserApcContext);
277
278       KeInsertQueueApc( &Irp->Tail.Apc,
279                         Irp,
280                         NULL,
281                         PriorityBoost);
282
283       //NOTE: kernel (or rundown) routine frees the IRP
284
285       return;
286
287    }
288
289    IoFreeIrp(Irp);
290    
291 }