Standardize comment headers. Patch by Trevor McCort
[reactos.git] / reactos / 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 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /* NOTES *******************************************************************
12 *
13 * Layout of an IRP
14 *
15 * ################
16 * # Headers #
17 * ################
18 * # #
19 * # Variable #
20 * # length list #
21 * # of io stack #
22 * # locations #
23 * # #
24 * ################
25 *
26 *
27 *
28 */
29
30 /* INCLUDES ****************************************************************/
31
32 #include <ntoskrnl.h>
33 #define NDEBUG
34 #include <internal/debug.h>
35
36 /* GLOBALS *******************************************************************/
37
38 #define TAG_IRP TAG('I', 'R', 'P', ' ')
39
40
41 /* FUNCTIONS ****************************************************************/
42
43 /*
44 * @unimplemented
45 */
46 BOOLEAN
47 STDCALL
48 IoForwardIrpSynchronously(
49 IN PDEVICE_OBJECT DeviceObject,
50 IN PIRP Irp
51 )
52 {
53 UNIMPLEMENTED;
54 return FALSE;
55 }
56
57 /*
58 * @implemented
59 */
60 VOID STDCALL
61 IoFreeIrp(PIRP Irp)
62 /*
63 * FUNCTION: Releases a caller allocated irp
64 * ARGUMENTS:
65 * Irp = Irp to free
66 */
67 {
68 ExFreePool(Irp);
69 }
70
71 /*
72 * @unimplemented
73 */
74 ULONG
75 STDCALL
76 IoGetRequestorProcessId(
77 IN PIRP Irp
78 )
79 {
80 UNIMPLEMENTED;
81 return 0;
82 }
83
84 /*
85 * @unimplemented
86 */
87 NTSTATUS
88 STDCALL
89 IoGetRequestorSessionId(
90 IN PIRP Irp,
91 OUT PULONG pSessionId
92 )
93 {
94 UNIMPLEMENTED;
95 return STATUS_NOT_IMPLEMENTED;
96 }
97
98
99 /*
100 * @unimplemented
101 */
102 BOOLEAN
103 STDCALL
104 IoIsValidNameGraftingBuffer(
105 IN PIRP Irp,
106 IN PREPARSE_DATA_BUFFER ReparseBuffer
107 )
108 {
109 UNIMPLEMENTED;
110 return FALSE;
111 }
112
113 /*
114 * @implemented
115 */
116 PIRP STDCALL
117 IoMakeAssociatedIrp(PIRP Irp,
118 CCHAR StackSize)
119 /*
120 * FUNCTION: Allocates and initializes an irp to associated with a master irp
121 * ARGUMENTS:
122 * Irp = Master irp
123 * StackSize = Number of stack locations to be allocated in the irp
124 * RETURNS: The irp allocated
125 * NOTE: The caller is responsible for incrementing
126 * Irp->AssociatedIrp.IrpCount.
127 */
128 {
129 PIRP AssocIrp;
130
131 /* Allocate the IRP */
132 AssocIrp = IoAllocateIrp(StackSize,FALSE);
133 if (AssocIrp == NULL)
134 return NULL;
135
136 /* Set the Flags */
137 AssocIrp->Flags |= IRP_ASSOCIATED_IRP;
138
139 /* Set the Thread */
140 AssocIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
141
142 /* Associate them */
143 AssocIrp->AssociatedIrp.MasterIrp = Irp;
144
145 return AssocIrp;
146 }
147
148
149 /*
150 * @implemented
151 */
152 VOID STDCALL
153 IoInitializeIrp(PIRP Irp,
154 USHORT PacketSize,
155 CCHAR StackSize)
156 /*
157 * FUNCTION: Initalizes an irp allocated by the caller
158 * ARGUMENTS:
159 * Irp = IRP to initalize
160 * PacketSize = Size in bytes of the IRP
161 * StackSize = Number of stack locations in the IRP
162 */
163 {
164 ASSERT(Irp != NULL);
165
166 DPRINT("IoInitializeIrp(StackSize %x, Irp %x)\n",StackSize, Irp);
167 memset(Irp, 0, PacketSize);
168 Irp->Size = PacketSize;
169 Irp->StackCount = StackSize;
170 Irp->CurrentLocation = StackSize;
171 InitializeListHead(&Irp->ThreadListEntry);
172 Irp->Tail.Overlay.CurrentStackLocation = (PIO_STACK_LOCATION)(Irp + 1) + StackSize;
173 DPRINT("Irp->Tail.Overlay.CurrentStackLocation %x\n", Irp->Tail.Overlay.CurrentStackLocation);
174 Irp->ApcEnvironment = KeGetCurrentThread()->ApcStateIndex;
175 }
176
177
178 /*
179 * @implemented
180 */
181 NTSTATUS FASTCALL
182 IofCallDriver(PDEVICE_OBJECT DeviceObject,
183 PIRP Irp)
184 /*
185 * FUNCTION: Sends an IRP to the next lower driver
186 */
187 {
188 PDRIVER_OBJECT DriverObject;
189 PIO_STACK_LOCATION Param;
190
191 DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
192
193 ASSERT(Irp);
194 ASSERT(DeviceObject);
195
196 DriverObject = DeviceObject->DriverObject;
197
198 ASSERT(DriverObject);
199
200 IoSetNextIrpStackLocation(Irp);
201 Param = IoGetCurrentIrpStackLocation(Irp);
202
203 DPRINT("IrpSp 0x%X\n", Param);
204
205 Param->DeviceObject = DeviceObject;
206
207 DPRINT("MajorFunction %d\n", Param->MajorFunction);
208 DPRINT("DriverObject->MajorFunction[Param->MajorFunction] %x\n",
209 DriverObject->MajorFunction[Param->MajorFunction]);
210
211 return DriverObject->MajorFunction[Param->MajorFunction](DeviceObject, Irp);
212 }
213
214 #ifdef IoCallDriver
215 #undef IoCallDriver
216 #endif
217 /*
218 * @implemented
219 */
220 NTSTATUS
221 STDCALL
222 IoCallDriver (PDEVICE_OBJECT DeviceObject, PIRP Irp)
223 {
224 return(IofCallDriver(DeviceObject,
225 Irp));
226 }
227
228
229 /*
230 * @implemented
231 */
232 PIRP STDCALL
233 IoAllocateIrp(CCHAR StackSize,
234 BOOLEAN ChargeQuota)
235 /*
236 * FUNCTION: Allocates an IRP
237 * ARGUMENTS:
238 * StackSize = the size of the stack required for the irp
239 * ChargeQuota = Charge allocation to current threads quota
240 * RETURNS: Irp allocated
241 */
242 {
243 PIRP Irp;
244
245 #if 0
246 DbgPrint("IoAllocateIrp(StackSize %d ChargeQuota %d)\n",
247 StackSize,
248 ChargeQuota);
249 KeDumpStackFrames(0,8);
250 #endif
251
252 if (ChargeQuota)
253 {
254 // Irp = ExAllocatePoolWithQuota(NonPagedPool,IoSizeOfIrp(StackSize));
255 Irp = ExAllocatePoolWithTag(NonPagedPool,
256 IoSizeOfIrp(StackSize),
257 TAG_IRP);
258 }
259 else
260 {
261 Irp = ExAllocatePoolWithTag(NonPagedPool,
262 IoSizeOfIrp(StackSize),
263 TAG_IRP);
264 }
265
266 if (Irp==NULL)
267 {
268 return(NULL);
269 }
270
271 RtlZeroMemory(Irp, IoSizeOfIrp(StackSize));
272 IoInitializeIrp(Irp,
273 IoSizeOfIrp(StackSize),
274 StackSize);
275
276 // DPRINT("Irp %x Irp->StackPtr %d\n", Irp, Irp->CurrentLocation);
277
278 return(Irp);
279 }
280
281 #ifdef IoCompleteRequest
282 #undef IoCompleteRequest
283 #endif
284 /*
285 * @implemented
286 */
287 VOID FASTCALL
288 IofCompleteRequest(PIRP Irp,
289 CCHAR PriorityBoost)
290 /*
291 * FUNCTION: Indicates the caller has finished all processing for a given
292 * I/O request and is returning the given IRP to the I/O manager
293 * ARGUMENTS:
294 * Irp = Irp to be cancelled
295 * PriorityBoost = Increment by which to boost the priority of the
296 * thread making the request
297 */
298 {
299 ULONG i;
300 NTSTATUS Status;
301 PFILE_OBJECT OriginalFileObject;
302 PDEVICE_OBJECT DeviceObject;
303 KIRQL oldIrql;
304 PMDL Mdl;
305 PIO_STACK_LOCATION Stack = (PIO_STACK_LOCATION)(Irp + 1);
306
307 DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
308 Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
309
310 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
311 ASSERT(Irp->CancelRoutine == NULL);
312 ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
313
314 Irp->PendingReturned = IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED;
315
316 /*
317 * Run the completion routines.
318 */
319
320 for (i=Irp->CurrentLocation;i<(ULONG)Irp->StackCount;i++)
321 {
322 /*
323 Completion routines expect the current irp stack location to be the same as when
324 IoSetCompletionRoutine was called to set them. A side effect is that completion
325 routines set by highest level drivers without their own stack location will receive
326 an invalid current stack location (at least it should be considered as invalid).
327 Since the DeviceObject argument passed is taken from the current stack, this value
328 is also invalid (NULL).
329 */
330 if (Irp->CurrentLocation < Irp->StackCount - 1)
331 {
332 IoSkipCurrentIrpStackLocation(Irp);
333 DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
334 }
335 else
336 {
337 DeviceObject = NULL;
338 }
339
340 if (Stack[i].CompletionRoutine != NULL &&
341 ((NT_SUCCESS(Irp->IoStatus.Status) && (Stack[i].Control & SL_INVOKE_ON_SUCCESS)) ||
342 (!NT_SUCCESS(Irp->IoStatus.Status) && (Stack[i].Control & SL_INVOKE_ON_ERROR)) ||
343 (Irp->Cancel && (Stack[i].Control & SL_INVOKE_ON_CANCEL))))
344 {
345 Status = Stack[i].CompletionRoutine(DeviceObject,
346 Irp,
347 Stack[i].Context);
348
349 if (Status == STATUS_MORE_PROCESSING_REQUIRED)
350 {
351 return;
352 }
353 }
354
355 if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
356 {
357 Irp->PendingReturned = TRUE;
358 }
359 }
360
361 /* Windows NT File System Internals, page 165 */
362 if (Irp->Flags & IRP_ASSOCIATED_IRP)
363 {
364 ULONG MasterIrpCount;
365 PIRP MasterIrp = Irp->AssociatedIrp.MasterIrp;
366
367 MasterIrpCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount);
368 while ((Mdl = Irp->MdlAddress))
369 {
370 Irp->MdlAddress = Mdl->Next;
371 IoFreeMdl(Mdl);
372 }
373 IoFreeIrp(Irp);
374 if (MasterIrpCount == 0)
375 {
376 IofCompleteRequest(MasterIrp, IO_NO_INCREMENT);
377 }
378 return;
379 }
380
381 /*
382 * Were done calling completion routines. Now do any cleanup that can be
383 * done in an arbitrarily context.
384 */
385
386 /* Windows NT File System Internals, page 165 */
387 if (Irp->Flags & (IRP_PAGING_IO|IRP_CLOSE_OPERATION))
388 {
389 /*
390 * If MDL_IO_PAGE_READ is set, then the caller is responsible
391 * for deallocating of the mdl.
392 */
393 if (Irp->Flags & IRP_PAGING_IO &&
394 Irp->MdlAddress &&
395 !(Irp->MdlAddress->MdlFlags & MDL_IO_PAGE_READ))
396 {
397
398 if (Irp->MdlAddress->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
399 {
400 MmUnmapLockedPages(Irp->MdlAddress->MappedSystemVa, Irp->MdlAddress);
401 }
402
403 ExFreePool(Irp->MdlAddress);
404 }
405
406 if (Irp->UserIosb)
407 {
408 *Irp->UserIosb = Irp->IoStatus;
409 }
410
411 if (Irp->UserEvent)
412 {
413 KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE);
414 }
415
416 /* io manager frees the irp for close operations */
417 // if (Irp->Flags & IRP_PAGING_IO)
418 // {
419 IoFreeIrp(Irp);
420 // }
421
422 return;
423 }
424
425
426 /*
427 Hi Dave,
428
429 I went through my old notes. You are correct and in most cases
430 IoCompleteRequest() will issue an MmUnlockPages() for each MDL in the IRP
431 chain. There are however few exceptions: one is MDLs for associated IRPs,
432 it's expected that those MDLs have been initialized with
433 IoBuildPartialMdl(). Another exception is PAGING_IO irps, the i/o completion
434 code doesn't do anything to MDLs of those IRPs.
435
436 sara
437
438 */
439
440
441 for (Mdl = Irp->MdlAddress; Mdl; Mdl = Mdl->Next)
442 {
443 /*
444 * Undo the MmProbeAndLockPages. If MmGetSystemAddressForMdl was called
445 * on this mdl, this mapping (if any) is also undone by MmUnlockPages.
446 */
447 MmUnlockPages(Mdl);
448 }
449
450 //Windows NT File System Internals, page 154
451 OriginalFileObject = Irp->Tail.Overlay.OriginalFileObject;
452
453 if (Irp->PendingReturned || KeGetCurrentIrql() == DISPATCH_LEVEL)
454 {
455 BOOLEAN bStatus;
456
457 DPRINT("Dispatching APC\n");
458
459 KeInitializeApc( &Irp->Tail.Apc,
460 &Irp->Tail.Overlay.Thread->Tcb,
461 Irp->ApcEnvironment,
462 IoSecondStageCompletion,//kernel routine
463 NULL,
464 (PKNORMAL_ROUTINE) NULL,
465 KernelMode,
466 NULL);
467
468 bStatus = KeInsertQueueApc(&Irp->Tail.Apc,
469 (PVOID)OriginalFileObject,
470 NULL, // This is used for REPARSE stuff
471 PriorityBoost);
472
473 if (bStatus == FALSE)
474 {
475 DPRINT1("Error queueing APC for thread. Thread has probably exited.\n");
476 }
477
478 DPRINT("Finished dispatching APC\n");
479 }
480 else
481 {
482 DPRINT("Calling IoSecondStageCompletion routine directly\n");
483 KeRaiseIrql(APC_LEVEL, &oldIrql);
484 IoSecondStageCompletion(&Irp->Tail.Apc,NULL,NULL,(PVOID)&OriginalFileObject, NULL);
485 KeLowerIrql(oldIrql);
486 DPRINT("Finished completition routine\n");
487 }
488 }
489
490
491 /*
492 * @implemented
493 */
494 VOID STDCALL
495 IoCompleteRequest(PIRP Irp,
496 CCHAR PriorityBoost)
497 {
498 IofCompleteRequest(Irp, PriorityBoost);
499 }
500
501
502 /**********************************************************************
503 * NAME EXPORTED
504 * IoIsOperationSynchronous@4
505 *
506 * DESCRIPTION
507 * Check if the I/O operation associated with the given IRP
508 * is synchronous.
509 *
510 * ARGUMENTS
511 * Irp Packet to check.
512 *
513 * RETURN VALUE
514 * TRUE if Irp's operation is synchronous; otherwise FALSE.
515 *
516 * @implemented
517 */
518 BOOLEAN STDCALL
519 IoIsOperationSynchronous(IN PIRP Irp)
520 {
521 PFILE_OBJECT FileObject = NULL;
522
523 FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
524
525 if (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO)
526 {
527 return TRUE;
528 }
529
530 if (Irp->Flags & IRP_PAGING_IO)
531 {
532 return FALSE;
533 }
534
535 //NOTE: Windows 2000 crash if IoStack->FileObject == NULL, so I guess we should too;-)
536 if (Irp->Flags & IRP_SYNCHRONOUS_API || FileObject->Flags & FO_SYNCHRONOUS_IO)
537 {
538 return TRUE;
539 }
540
541 /* Otherwise, it is an asynchronous operation. */
542 return FALSE;
543 }
544
545
546 /*
547 * @implemented
548 */
549 VOID STDCALL
550 IoEnqueueIrp(IN PIRP Irp)
551 {
552 IoQueueThreadIrp(Irp);
553 }
554
555
556 /*
557 * @implemented
558 */
559 VOID STDCALL
560 IoSetTopLevelIrp(IN PIRP Irp)
561 {
562 PETHREAD Thread;
563
564 Thread = PsGetCurrentThread();
565 Thread->TopLevelIrp = Irp;
566 }
567
568
569 /*
570 * @implemented
571 */
572 PIRP STDCALL
573 IoGetTopLevelIrp(VOID)
574 {
575 return(PsGetCurrentThread()->TopLevelIrp);
576 }
577
578
579 /*
580 * @implemented
581 */
582 VOID STDCALL
583 IoQueueThreadIrp(IN PIRP Irp)
584 {
585 /* undefine this when (if ever) implementing irp cancellation */
586 #if 0
587 KIRQL oldIrql;
588
589 oldIrql = KfRaiseIrql(APC_LEVEL);
590
591 /* Synchronous irp's are queued to requestor thread. If they are not completed
592 when the thread exits, they are canceled (cleaned up).
593 -Gunnar */
594 InsertTailList(&PsGetCurrentThread()->IrpList, &Irp->ThreadListEntry);
595
596 KfLowerIrql(oldIrql);
597 #endif
598 }
599
600
601 /*
602 * @implemented
603 */
604 VOID STDCALL
605 IoReuseIrp(
606 IN OUT PIRP Irp,
607 IN NTSTATUS Status)
608 {
609
610 UCHAR AllocationFlags;
611
612 /* Reference: Chris Cant's "Writing WDM Device Drivers" */
613 AllocationFlags = Irp->AllocationFlags;
614 IoInitializeIrp(Irp, Irp->Size, Irp->StackCount);
615 Irp->IoStatus.Status = Status;
616 Irp->AllocationFlags = AllocationFlags;
617 }
618
619 /* EOF */