temp.workaround: allways free irp
[reactos.git] / reactos / ntoskrnl / io / irp.c
1 /* $Id: irp.c,v 1.60 2004/04/20 23:14:35 gdalsnes Exp $
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 InitializeListHead(&Irp->ThreadListEntry);
108 Irp->Tail.Overlay.CurrentStackLocation = &Irp->Stack[(ULONG)StackSize];
109 }
110
111
112 /*
113 * @implemented
114 */
115 NTSTATUS FASTCALL
116 IofCallDriver(PDEVICE_OBJECT DeviceObject,
117 PIRP Irp)
118 /*
119 * FUNCTION: Sends an IRP to the next lower driver
120 */
121 {
122 PDRIVER_OBJECT DriverObject;
123 PIO_STACK_LOCATION Param;
124
125 DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
126
127 assert(Irp);
128 assert(DeviceObject);
129
130 DriverObject = DeviceObject->DriverObject;
131
132 assert(DriverObject);
133
134 IoSetNextIrpStackLocation(Irp);
135 Param = IoGetCurrentIrpStackLocation(Irp);
136
137 DPRINT("IrpSp 0x%X\n", Param);
138
139 Param->DeviceObject = DeviceObject;
140
141 DPRINT("MajorFunction %d\n", Param->MajorFunction);
142 DPRINT("DriverObject->MajorFunction[Param->MajorFunction] %x\n",
143 DriverObject->MajorFunction[Param->MajorFunction]);
144
145 return DriverObject->MajorFunction[Param->MajorFunction](DeviceObject, Irp);
146 }
147
148
149 /*
150 * @implemented
151 */
152 NTSTATUS
153 STDCALL
154 IoCallDriver (PDEVICE_OBJECT DeviceObject, PIRP Irp)
155 {
156 return(IofCallDriver(DeviceObject,
157 Irp));
158 }
159
160
161 /*
162 * @implemented
163 */
164 PIRP STDCALL
165 IoAllocateIrp(CCHAR StackSize,
166 BOOLEAN ChargeQuota)
167 /*
168 * FUNCTION: Allocates an IRP
169 * ARGUMENTS:
170 * StackSize = the size of the stack required for the irp
171 * ChargeQuota = Charge allocation to current threads quota
172 * RETURNS: Irp allocated
173 */
174 {
175 PIRP Irp;
176
177 #if 0
178 DbgPrint("IoAllocateIrp(StackSize %d ChargeQuota %d)\n",
179 StackSize,
180 ChargeQuota);
181 KeDumpStackFrames(0,8);
182 #endif
183
184 if (ChargeQuota)
185 {
186 // Irp = ExAllocatePoolWithQuota(NonPagedPool,IoSizeOfIrp(StackSize));
187 Irp = ExAllocatePoolWithTag(NonPagedPool,
188 IoSizeOfIrp(StackSize),
189 TAG_IRP);
190 }
191 else
192 {
193 Irp = ExAllocatePoolWithTag(NonPagedPool,
194 IoSizeOfIrp(StackSize),
195 TAG_IRP);
196 }
197
198 if (Irp==NULL)
199 {
200 return(NULL);
201 }
202
203 RtlZeroMemory(Irp, IoSizeOfIrp(StackSize));
204 IoInitializeIrp(Irp,
205 IoSizeOfIrp(StackSize),
206 StackSize);
207
208 // DPRINT("Irp %x Irp->StackPtr %d\n", Irp, Irp->CurrentLocation);
209
210 return(Irp);
211 }
212
213
214 /*
215 * @implemented
216 */
217 VOID FASTCALL
218 IofCompleteRequest(PIRP Irp,
219 CCHAR PriorityBoost)
220 /*
221 * FUNCTION: Indicates the caller has finished all processing for a given
222 * I/O request and is returning the given IRP to the I/O manager
223 * ARGUMENTS:
224 * Irp = Irp to be cancelled
225 * PriorityBoost = Increment by which to boost the priority of the
226 * thread making the request
227 */
228 {
229 ULONG i;
230 NTSTATUS Status;
231 PDEVICE_OBJECT DeviceObject;
232 PFILE_OBJECT OriginalFileObject;
233 KIRQL oldIrql;
234 PMDL Mdl;
235
236 DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
237 Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
238
239 assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
240 assert(Irp->CancelRoutine == NULL);
241 assert(Irp->IoStatus.Status != STATUS_PENDING);
242
243 if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
244 {
245 Irp->PendingReturned = TRUE;
246 }
247
248 for (i=Irp->CurrentLocation;i<(ULONG)Irp->StackCount;i++)
249 {
250 /*
251 Completion routines expect the current irp stack location to be the same as when
252 IoSetCompletionRoutine was called to set them. A side effect is that completion
253 routines set by highest level drivers without their own stack location will receive
254 an invalid current stack location (at least it should be considered as invalid).
255 Since the DeviceObject argument passed is taken from the current stack, this value
256 is also invalid (NULL).
257 */
258 if (Irp->CurrentLocation < Irp->StackCount - 1)
259 {
260 IoSetPreviousIrpStackLocation(Irp);
261 DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
262 }
263 else
264 {
265 DeviceObject = NULL;
266 }
267
268 if (Irp->Stack[i].CompletionRoutine != NULL &&
269 ((NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_SUCCESS)) ||
270 (!NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_ERROR)) ||
271 (Irp->Cancel && (Irp->Stack[i].Control & SL_INVOKE_ON_CANCEL))))
272 {
273 Status = Irp->Stack[i].CompletionRoutine(DeviceObject,
274 Irp,
275 Irp->Stack[i].Context);
276
277 if (Status == STATUS_MORE_PROCESSING_REQUIRED)
278 {
279 return;
280 }
281 }
282
283 if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
284 {
285 Irp->PendingReturned = TRUE;
286 }
287 }
288
289 /*
290 * Were done calling completion routines. Now do any cleanup that can be
291 * done in an arbitrarily context.
292 */
293
294 /* Windows NT File System Internals, page 165 */
295 if (Irp->Flags & (IRP_PAGING_IO|IRP_CLOSE_OPERATION))
296 {
297 if (Irp->Flags & IRP_PAGING_IO)
298 {
299 /* FIXME:
300 * The mdl should be freed by the caller!
301 */
302 if (Irp->MdlAddress->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
303 {
304 MmUnmapLockedPages(Irp->MdlAddress->MappedSystemVa, Irp->MdlAddress);
305 }
306
307 ExFreePool(Irp->MdlAddress);
308 }
309
310 if (Irp->UserIosb)
311 {
312 *Irp->UserIosb = Irp->IoStatus;
313 }
314
315 if (Irp->UserEvent)
316 {
317 KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE);
318 }
319
320 /* io manager frees the irp for close operations */
321 // if (Irp->Flags & IRP_PAGING_IO)
322 // {
323 IoFreeIrp(Irp);
324 // }
325
326 return;
327 }
328
329
330 /*
331 Hi Dave,
332
333 I went through my old notes. You are correct and in most cases
334 IoCompleteRequest() will issue an MmUnlockPages() for each MDL in the IRP
335 chain. There are however few exceptions: one is MDLs for associated IRPs,
336 it's expected that those MDLs have been initialized with
337 IoBuildPartialMdl(). Another exception is PAGING_IO irps, the i/o completion
338 code doesn't do anything to MDLs of those IRPs.
339
340 sara
341
342 */
343
344 //Windows NT File System Internals, page 166/167
345 if (!(Irp->Flags & IRP_ASSOCIATED_IRP))
346 {
347 for (Mdl = Irp->MdlAddress; Mdl; Mdl = Mdl->Next)
348 {
349 /*
350 * Undo the MmProbeAndLockPages. If MmGetSystemAddressForMdl was called
351 * on this mdl, this mapping (if any) is also undone by MmUnlockPages.
352 */
353 MmUnlockPages(Irp->MdlAddress);
354 }
355 }
356
357 //Windows NT File System Internals, page 154
358 OriginalFileObject = Irp->Tail.Overlay.OriginalFileObject;
359
360 if (Irp->PendingReturned || KeGetCurrentIrql() == DISPATCH_LEVEL)
361 {
362 BOOLEAN bStatus;
363
364 DPRINT("Dispatching APC\n");
365 KeInitializeApc( &Irp->Tail.Apc,
366 &Irp->Tail.Overlay.Thread->Tcb,
367 OriginalApcEnvironment,
368 IoSecondStageCompletion,//kernel routine
369 NULL,
370 (PKNORMAL_ROUTINE) NULL,
371 KernelMode,
372 OriginalFileObject);
373
374 bStatus = KeInsertQueueApc(&Irp->Tail.Apc,
375 (PVOID)Irp,
376 (PVOID)(ULONG)PriorityBoost,
377 PriorityBoost);
378
379 if (bStatus == FALSE)
380 {
381 DPRINT1("Error queueing APC for thread. Thread has probably exited.\n");
382 }
383
384 DPRINT("Finished dispatching APC\n");
385 }
386 else
387 {
388 DPRINT("Calling IoSecondStageCompletion routine directly\n");
389 KeRaiseIrql(APC_LEVEL, &oldIrql);
390 IoSecondStageCompletion(NULL,NULL,(PVOID)&OriginalFileObject,(PVOID) &Irp,(PVOID) &PriorityBoost);
391 KeLowerIrql(oldIrql);
392 DPRINT("Finished completition routine\n");
393 }
394
395
396 }
397
398
399 /*
400 * @implemented
401 */
402 VOID STDCALL
403 IoCompleteRequest(PIRP Irp,
404 CCHAR PriorityBoost)
405 {
406 IofCompleteRequest(Irp, PriorityBoost);
407 }
408
409
410 /**********************************************************************
411 * NAME EXPORTED
412 * IoIsOperationSynchronous@4
413 *
414 * DESCRIPTION
415 * Check if the I/O operation associated with the given IRP
416 * is synchronous.
417 *
418 * ARGUMENTS
419 * Irp Packet to check.
420 *
421 * RETURN VALUE
422 * TRUE if Irp's operation is synchronous; otherwise FALSE.
423 *
424 * @implemented
425 */
426 BOOLEAN STDCALL
427 IoIsOperationSynchronous(IN PIRP Irp)
428 {
429 PFILE_OBJECT FileObject = NULL;
430
431 FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
432
433 if (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO)
434 {
435 return TRUE;
436 }
437
438 if (Irp->Flags & IRP_PAGING_IO)
439 {
440 return FALSE;
441 }
442
443 //NOTE: Windows 2000 crash if IoStack->FileObject == NULL, so I guess we should too;-)
444 if (Irp->Flags & IRP_SYNCHRONOUS_API || FileObject->Flags & FO_SYNCHRONOUS_IO)
445 {
446 return TRUE;
447 }
448
449 /* Otherwise, it is an asynchronous operation. */
450 return FALSE;
451 }
452
453
454 /*
455 * @implemented
456 */
457 VOID STDCALL
458 IoEnqueueIrp(IN PIRP Irp)
459 {
460 IoQueueThreadIrp(Irp);
461 }
462
463
464 /*
465 * @implemented
466 */
467 VOID STDCALL
468 IoSetTopLevelIrp(IN PIRP Irp)
469 {
470 PETHREAD Thread;
471
472 Thread = PsGetCurrentThread();
473 Thread->TopLevelIrp->TopLevelIrp = Irp;
474 }
475
476
477 /*
478 * @implemented
479 */
480 PIRP STDCALL
481 IoGetTopLevelIrp(VOID)
482 {
483 return(PsGetCurrentThread()->TopLevelIrp->TopLevelIrp);
484 }
485
486
487 /*
488 * @implemented
489 */
490 VOID STDCALL
491 IoQueueThreadIrp(IN PIRP Irp)
492 {
493 /* undefine this when (if ever) implementing irp cancellation */
494 #if 0
495 KIRQL oldIrql;
496
497 oldIrql = KfRaiseIrql(APC_LEVEL);
498
499 /* Synchronous irp's are queued to requestor thread. If they are not completed
500 when the thread exits, they are canceled (cleaned up).
501 -Gunnar */
502 InsertTailList(&PsGetCurrentThread()->IrpList, &Irp->ThreadListEntry);
503
504 KfLowerIrql(oldIrql);
505 #endif
506 }
507
508
509 /*
510 * @implemented
511 */
512 VOID STDCALL
513 IoReuseIrp(
514 IN OUT PIRP Irp,
515 IN NTSTATUS Status)
516 {
517
518 UCHAR AllocationFlags;
519
520 /* Reference: Chris Cant's "Writing WDM Device Drivers" */
521 AllocationFlags = Irp->AllocationFlags;
522 IoInitializeIrp(Irp, Irp->Size, Irp->StackCount);
523 Irp->IoStatus.Status = Status;
524 Irp->AllocationFlags = AllocationFlags;
525 }
526
527 /* EOF */