bd0eb8881d6e009504136586f91b3d99c5ef94a8
[reactos.git] / reactos / ntoskrnl / io / iomgr / irp.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/irp.c
5 * PURPOSE: IRP Handling Functions
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Gunnar Dalsnes
8 * Filip Navara (navaraf@reactos.org)
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* Undefine some macros we implement here */
18 #undef IoCallDriver
19 #undef IoCompleteRequest
20
21 /* PRIVATE FUNCTIONS ********************************************************/
22
23 VOID
24 NTAPI
25 IopFreeIrpKernelApc(IN PKAPC Apc,
26 IN PKNORMAL_ROUTINE *NormalRoutine,
27 IN PVOID *NormalContext,
28 IN PVOID *SystemArgument1,
29 IN PVOID *SystemArgument2)
30 {
31 /* Free the IRP */
32 IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc));
33 }
34
35 VOID
36 NTAPI
37 IopAbortIrpKernelApc(IN PKAPC Apc)
38 {
39 /* Free the IRP */
40 IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc));
41 }
42
43 NTSTATUS
44 NTAPI
45 IopCleanupFailedIrp(IN PFILE_OBJECT FileObject,
46 IN PKEVENT EventObject OPTIONAL,
47 IN PVOID Buffer OPTIONAL)
48 {
49 PAGED_CODE();
50
51 /* Dereference the event */
52 if (EventObject) ObDereferenceObject(EventObject);
53
54 /* Free a buffer, if any */
55 if (Buffer) ExFreePool(Buffer);
56
57 /* If this was a file opened for synch I/O, then unlock it */
58 if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopUnlockFileObject(FileObject);
59
60 /* Now dereference it and return */
61 ObDereferenceObject(FileObject);
62 return STATUS_INSUFFICIENT_RESOURCES;
63 }
64
65 VOID
66 NTAPI
67 IopAbortInterruptedIrp(IN PKEVENT EventObject,
68 IN PIRP Irp)
69 {
70 KIRQL OldIrql;
71 BOOLEAN CancelResult;
72 LARGE_INTEGER Wait;
73 PAGED_CODE();
74
75 /* Raise IRQL to APC */
76 KeRaiseIrql(APC_LEVEL, &OldIrql);
77
78 /* Check if nobody completed it yet */
79 if (!KeReadStateEvent(EventObject))
80 {
81 /* First, cancel it */
82 CancelResult = IoCancelIrp(Irp);
83 KeLowerIrql(OldIrql);
84
85 /* Check if we cancelled it */
86 if (CancelResult)
87 {
88 /* Wait for the IRP to be cancelled */
89 Wait.QuadPart = -100000;
90 while (!KeReadStateEvent(EventObject))
91 {
92 /* Delay indefintely */
93 KeDelayExecutionThread(KernelMode, FALSE, &Wait);
94 }
95 }
96 else
97 {
98 /* No cancellation done, so wait for the I/O system to kill it */
99 KeWaitForSingleObject(EventObject,
100 Executive,
101 KernelMode,
102 FALSE,
103 NULL);
104 }
105 }
106 else
107 {
108 /* We got preempted, so give up */
109 KeLowerIrql(OldIrql);
110 }
111 }
112
113 VOID
114 NTAPI
115 IopRemoveThreadIrp(VOID)
116 {
117 KIRQL OldIrql;
118 PIRP DeadIrp;
119 PETHREAD IrpThread;
120 PLIST_ENTRY IrpEntry;
121 PIO_ERROR_LOG_PACKET ErrorLogEntry;
122 PDEVICE_OBJECT DeviceObject = NULL;
123 PIO_STACK_LOCATION IoStackLocation;
124
125 /* First, raise to APC to protect IrpList */
126 KeRaiseIrql(APC_LEVEL, &OldIrql);
127
128 /* Get the Thread and check the list */
129 IrpThread = PsGetCurrentThread();
130 if (IsListEmpty(&IrpThread->IrpList))
131 {
132 /* It got completed now, so quit */
133 KeLowerIrql(OldIrql);
134 return;
135 }
136
137 /* Get the misbehaving IRP */
138 IrpEntry = IrpThread->IrpList.Flink;
139 DeadIrp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry);
140 IOTRACE(IO_IRP_DEBUG,
141 "%s - Deassociating IRP %p for %p\n",
142 __FUNCTION__,
143 DeadIrp,
144 IrpThread);
145
146 /* Don't cancel the IRP if it's already been completed far */
147 if (DeadIrp->CurrentLocation == (DeadIrp->StackCount + 2))
148 {
149 /* Return */
150 KeLowerIrql(OldIrql);
151 return;
152 }
153
154 /* Disown the IRP! */
155 DeadIrp->Tail.Overlay.Thread = NULL;
156 RemoveHeadList(&IrpThread->IrpList);
157 InitializeListHead(&DeadIrp->ThreadListEntry);
158
159 /* Get the stack location and check if it's valid */
160 IoStackLocation = IoGetCurrentIrpStackLocation(DeadIrp);
161 if (DeadIrp->CurrentLocation <= DeadIrp->StackCount)
162 {
163 /* Get the device object */
164 DeviceObject = IoStackLocation->DeviceObject;
165 }
166
167 /* Lower IRQL now, since we have the pointers we need */
168 KeLowerIrql(OldIrql);
169
170 /* Check if we can send an Error Log Entry*/
171 if (DeviceObject)
172 {
173 /* Allocate an entry */
174 ErrorLogEntry = IoAllocateErrorLogEntry(DeviceObject,
175 sizeof(IO_ERROR_LOG_PACKET));
176 if (ErrorLogEntry)
177 {
178 /* Write the entry */
179 ErrorLogEntry->ErrorCode = 0xBAADF00D; /* FIXME */
180 IoWriteErrorLogEntry(ErrorLogEntry);
181 }
182 }
183 }
184
185 VOID
186 NTAPI
187 IopCleanupIrp(IN PIRP Irp,
188 IN PFILE_OBJECT FileObject)
189 {
190 PMDL Mdl;
191 IOTRACE(IO_IRP_DEBUG,
192 "%s - Cleaning IRP %p for %p\n",
193 __FUNCTION__,
194 Irp,
195 FileObject);
196
197 /* Check if there's an MDL */
198 while ((Mdl = Irp->MdlAddress))
199 {
200 /* Clear all of them */
201 Irp->MdlAddress = Mdl->Next;
202 IoFreeMdl(Mdl);
203 }
204
205 /* Check if the IRP has system buffer */
206 if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
207 {
208 /* Free the buffer */
209 ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF);
210 }
211
212 /* Check if this IRP has a user event, a file object, and is async */
213 if ((Irp->UserEvent) &&
214 !(Irp->Flags & IRP_SYNCHRONOUS_API) &&
215 (FileObject))
216 {
217 /* Dereference the User Event */
218 ObDereferenceObject(Irp->UserEvent);
219 }
220
221 /* Check if we have a file object and this isn't a create operation */
222 if ((FileObject) && !(Irp->Flags & IRP_CREATE_OPERATION))
223 {
224 /* Dereference the file object */
225 ObDereferenceObject(FileObject);
226 }
227
228 /* Free the IRP */
229 IoFreeIrp(Irp);
230 }
231
232 VOID
233 NTAPI
234 IopCompleteRequest(IN PKAPC Apc,
235 IN PKNORMAL_ROUTINE* NormalRoutine,
236 IN PVOID* NormalContext,
237 IN PVOID* SystemArgument1,
238 IN PVOID* SystemArgument2)
239 {
240 PFILE_OBJECT FileObject;
241 PIRP Irp;
242 PMDL Mdl, NextMdl;
243 PVOID Port = NULL, Key = NULL;
244 BOOLEAN SignaledCreateRequest = FALSE;
245
246 /* Get data from the APC */
247 FileObject = (PFILE_OBJECT)*SystemArgument1;
248 Irp = CONTAINING_RECORD(Apc, IRP, Tail.Apc);
249 IOTRACE(IO_IRP_DEBUG,
250 "%s - Completing IRP %p for %p\n",
251 __FUNCTION__,
252 Irp,
253 FileObject);
254
255 /* Sanity check */
256 ASSERT(Irp->IoStatus.Status != (NTSTATUS)0xFFFFFFFF);
257
258 /* Check if we have a file object */
259 if (*SystemArgument2)
260 {
261 /* Check if we're reparsing */
262 if ((Irp->IoStatus.Status == STATUS_REPARSE) &&
263 (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT))
264 {
265 /* We should never get this yet */
266 DPRINT1("Reparse support not yet present!\n");
267 while (TRUE);
268 }
269 }
270
271 /* Handle Buffered case first */
272 if (Irp->Flags & IRP_BUFFERED_IO)
273 {
274 /* Check if we have an input buffer and if we succeeded */
275 if ((Irp->Flags & IRP_INPUT_OPERATION) &&
276 (Irp->IoStatus.Status != STATUS_VERIFY_REQUIRED) &&
277 !(NT_ERROR(Irp->IoStatus.Status)))
278 {
279 /* Copy the buffer back to the user */
280 RtlCopyMemory(Irp->UserBuffer,
281 Irp->AssociatedIrp.SystemBuffer,
282 Irp->IoStatus.Information);
283 }
284
285 /* Also check if we should de-allocate it */
286 if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
287 {
288 /* Deallocate it */
289 ExFreePool(Irp->AssociatedIrp.SystemBuffer);
290 }
291 }
292
293 /* Now we got rid of these two... */
294 Irp->Flags &= ~(IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
295
296 /* Check if there's an MDL */
297 for (Mdl = Irp->MdlAddress; Mdl; Mdl = NextMdl)
298 {
299 /* Free it */
300 NextMdl = Mdl->Next;
301 IoFreeMdl(Mdl);
302 }
303
304 /* No MDLs left */
305 Irp->MdlAddress = NULL;
306
307 /*
308 * Check if either the request was completed without any errors
309 * (but warnings are OK!), or if it was completed with an error, but
310 * did return from a pending I/O Operation and is not synchronous.
311 */
312 if (!(NT_ERROR(Irp->IoStatus.Status)) ||
313 (NT_ERROR(Irp->IoStatus.Status) &&
314 (Irp->PendingReturned) &&
315 !(IsIrpSynchronous(Irp, FileObject))))
316 {
317 /* Get any information we need from the FO before we kill it */
318 if ((FileObject) && (FileObject->CompletionContext))
319 {
320 /* Save Completion Data */
321 Port = FileObject->CompletionContext->Port;
322 Key = FileObject->CompletionContext->Key;
323 }
324
325 /* Use SEH to make sure we don't write somewhere invalid */
326 _SEH2_TRY
327 {
328 /* Save the IOSB Information */
329 *Irp->UserIosb = Irp->IoStatus;
330 }
331 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
332 {
333 /* Ignore any error */
334 }
335 _SEH2_END;
336
337 /* Check if we have an event or a file object */
338 if (Irp->UserEvent)
339 {
340 /* At the very least, this is a PKEVENT, so signal it always */
341 KeSetEvent(Irp->UserEvent, 0, FALSE);
342
343 /* Check if we also have a File Object */
344 if (FileObject)
345 {
346 /* Check if this is an Asynch API */
347 if (!(Irp->Flags & IRP_SYNCHRONOUS_API))
348 {
349 /* Dereference the event */
350 ObDereferenceObject(Irp->UserEvent);
351 }
352
353 /*
354 * Now, if this is a Synch I/O File Object, then this event is
355 * NOT an actual Executive Event, so we won't dereference it,
356 * and instead, we will signal the File Object
357 */
358 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) &&
359 !(Irp->Flags & IRP_OB_QUERY_NAME))
360 {
361 /* Signal the file object and set the status */
362 KeSetEvent(&FileObject->Event, 0, FALSE);
363 FileObject->FinalStatus = Irp->IoStatus.Status;
364 }
365
366 /*
367 * This could also be a create operation, in which case we want
368 * to make sure there's no APC fired.
369 */
370 if (Irp->Flags & IRP_CREATE_OPERATION)
371 {
372 /* Clear the APC Routine and remember this */
373 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
374 SignaledCreateRequest = TRUE;
375 }
376 }
377 }
378 else if (FileObject)
379 {
380 /* Signal the file object and set the status */
381 KeSetEvent(&FileObject->Event, 0, FALSE);
382 FileObject->FinalStatus = Irp->IoStatus.Status;
383
384 /*
385 * This could also be a create operation, in which case we want
386 * to make sure there's no APC fired.
387 */
388 if (Irp->Flags & IRP_CREATE_OPERATION)
389 {
390 /* Clear the APC Routine and remember this */
391 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
392 SignaledCreateRequest = TRUE;
393 }
394 }
395
396 /* Update transfer count for everything but create operation */
397 if (!(Irp->Flags & IRP_CREATE_OPERATION))
398 {
399 if (Irp->Flags & IRP_WRITE_OPERATION)
400 {
401 /* Update write transfer count */
402 IopUpdateTransferCount(IopWriteTransfer,
403 (ULONG)Irp->IoStatus.Information);
404 }
405 else if (Irp->Flags & IRP_READ_OPERATION)
406 {
407 /* Update read transfer count */
408 IopUpdateTransferCount(IopReadTransfer,
409 (ULONG)Irp->IoStatus.Information);
410 }
411 else
412 {
413 /* Update other transfer count */
414 IopUpdateTransferCount(IopOtherTransfer,
415 (ULONG)Irp->IoStatus.Information);
416 }
417 }
418
419 /* Now that we've signaled the events, de-associate the IRP */
420 IopUnQueueIrpFromThread(Irp);
421
422 /* Now check if a User APC Routine was requested */
423 if (Irp->Overlay.AsynchronousParameters.UserApcRoutine)
424 {
425 /* Initialize it */
426 KeInitializeApc(&Irp->Tail.Apc,
427 KeGetCurrentThread(),
428 CurrentApcEnvironment,
429 IopFreeIrpKernelApc,
430 IopAbortIrpKernelApc,
431 (PKNORMAL_ROUTINE)Irp->
432 Overlay.AsynchronousParameters.UserApcRoutine,
433 Irp->RequestorMode,
434 Irp->
435 Overlay.AsynchronousParameters.UserApcContext);
436
437 /* Queue it */
438 KeInsertQueueApc(&Irp->Tail.Apc, Irp->UserIosb, NULL, 2);
439 }
440 else if ((Port) &&
441 (Irp->Overlay.AsynchronousParameters.UserApcContext))
442 {
443 /* We have an I/O Completion setup... create the special Overlay */
444 Irp->Tail.CompletionKey = Key;
445 Irp->Tail.Overlay.PacketType = IopCompletionPacketIrp;
446 KeInsertQueue(Port, &Irp->Tail.Overlay.ListEntry);
447 }
448 else
449 {
450 /* Free the IRP since we don't need it anymore */
451 IoFreeIrp(Irp);
452 }
453
454 /* Check if we have a file object that wasn't part of a create */
455 if ((FileObject) && !(SignaledCreateRequest))
456 {
457 /* Dereference it, since it's not needed anymore either */
458 ObDereferenceObjectDeferDelete(FileObject);
459 }
460 }
461 else
462 {
463 /*
464 * Either we didn't return from the request, or we did return but this
465 * request was synchronous.
466 */
467 if ((Irp->PendingReturned) && (FileObject))
468 {
469 /* So we did return with a synch operation, was it the IRP? */
470 if (Irp->Flags & IRP_SYNCHRONOUS_API)
471 {
472 /* Yes, this IRP was synchronous, so return the I/O Status */
473 *Irp->UserIosb = Irp->IoStatus;
474
475 /* Now check if the user gave an event */
476 if (Irp->UserEvent)
477 {
478 /* Signal it */
479 KeSetEvent(Irp->UserEvent, 0, FALSE);
480 }
481 else
482 {
483 /* No event was given, so signal the FO instead */
484 KeSetEvent(&FileObject->Event, 0, FALSE);
485 }
486 }
487 else
488 {
489 /*
490 * It's not the IRP that was synchronous, it was the FO
491 * that was opened this way. Signal its event.
492 */
493 FileObject->FinalStatus = Irp->IoStatus.Status;
494 KeSetEvent(&FileObject->Event, 0, FALSE);
495 }
496 }
497
498 /* Now that we got here, we do this for incomplete I/Os as well */
499 if ((FileObject) && !(Irp->Flags & IRP_CREATE_OPERATION))
500 {
501 /* Dereference the File Object unless this was a create */
502 ObDereferenceObjectDeferDelete(FileObject);
503 }
504
505 /*
506 * Check if this was an Executive Event (remember that we know this
507 * by checking if the IRP is synchronous)
508 */
509 if ((Irp->UserEvent) &&
510 (FileObject) &&
511 !(Irp->Flags & IRP_SYNCHRONOUS_API))
512 {
513 /* This isn't a PKEVENT, so dereference it */
514 ObDereferenceObject(Irp->UserEvent);
515 }
516
517 /* Now that we've signaled the events, de-associate the IRP */
518 IopUnQueueIrpFromThread(Irp);
519
520 /* Free the IRP as well */
521 IoFreeIrp(Irp);
522 }
523 }
524
525 /* FUNCTIONS *****************************************************************/
526
527 /*
528 * @implemented
529 */
530 PIRP
531 NTAPI
532 IoAllocateIrp(IN CCHAR StackSize,
533 IN BOOLEAN ChargeQuota)
534 {
535 PIRP Irp = NULL;
536 USHORT Size = IoSizeOfIrp(StackSize);
537 PKPRCB Prcb;
538 UCHAR Flags = 0;
539 PNPAGED_LOOKASIDE_LIST List = NULL;
540 PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList;
541
542 /* Set Charge Quota Flag */
543 if (ChargeQuota) Flags |= IRP_QUOTA_CHARGED;
544
545 /* FIXME: Implement Lookaside Floats */
546
547 /* Figure out which Lookaside List to use */
548 if ((StackSize <= 8) && (ChargeQuota == FALSE))
549 {
550 /* Set Fixed Size Flag */
551 Flags = IRP_ALLOCATED_FIXED_SIZE;
552
553 /* See if we should use big list */
554 if (StackSize != 1)
555 {
556 Size = IoSizeOfIrp(8);
557 ListType = LookasideLargeIrpList;
558 }
559
560 /* Get the PRCB */
561 Prcb = KeGetCurrentPrcb();
562
563 /* Get the P List First */
564 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;
565
566 /* Attempt allocation */
567 List->L.TotalAllocates++;
568 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
569
570 /* Check if the P List failed */
571 if (!Irp)
572 {
573 /* Let the balancer know */
574 List->L.AllocateMisses++;
575
576 /* Try the L List */
577 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;
578 List->L.TotalAllocates++;
579 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
580 }
581 }
582
583 /* Check if we have to use the pool */
584 if (!Irp)
585 {
586 /* Did we try lookaside and fail? */
587 if (Flags & IRP_ALLOCATED_FIXED_SIZE) List->L.AllocateMisses++;
588
589 /* Check if we should charge quota */
590 if (ChargeQuota)
591 {
592 /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool, Size, TAG_IRP); */
593 /* FIXME */
594 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
595 }
596 else
597 {
598 /* Allocate the IRP With no Quota charge */
599 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
600 }
601
602 /* Make sure it was sucessful */
603 if (!Irp) return(NULL);
604 }
605 else
606 {
607 /* In this case there is no charge quota */
608 Flags &= ~IRP_QUOTA_CHARGED;
609 }
610
611 /* Now Initialize it */
612 IoInitializeIrp(Irp, Size, StackSize);
613
614 /* Set the Allocation Flags */
615 Irp->AllocationFlags = Flags;
616
617 /* Return it */
618 IOTRACE(IO_IRP_DEBUG,
619 "%s - Allocated IRP %p with allocation flags %lx\n",
620 __FUNCTION__,
621 Irp,
622 Flags);
623 return Irp;
624 }
625
626 /*
627 * @implemented
628 */
629 PIRP
630 NTAPI
631 IoBuildAsynchronousFsdRequest(IN ULONG MajorFunction,
632 IN PDEVICE_OBJECT DeviceObject,
633 IN PVOID Buffer,
634 IN ULONG Length,
635 IN PLARGE_INTEGER StartingOffset,
636 IN PIO_STATUS_BLOCK IoStatusBlock)
637 {
638 PIRP Irp;
639 PIO_STACK_LOCATION StackPtr;
640
641 /* Allocate IRP */
642 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
643 if (!Irp) return NULL;
644
645 /* Get the Stack */
646 StackPtr = IoGetNextIrpStackLocation(Irp);
647
648 /* Write the Major function and then deal with it */
649 StackPtr->MajorFunction = (UCHAR)MajorFunction;
650
651 /* Do not handle the following here */
652 if ((MajorFunction != IRP_MJ_FLUSH_BUFFERS) &&
653 (MajorFunction != IRP_MJ_SHUTDOWN) &&
654 (MajorFunction != IRP_MJ_PNP) &&
655 (MajorFunction != IRP_MJ_POWER))
656 {
657 /* Check if this is Buffered IO */
658 if (DeviceObject->Flags & DO_BUFFERED_IO)
659 {
660 /* Allocate the System Buffer */
661 Irp->AssociatedIrp.SystemBuffer =
662 ExAllocatePoolWithTag(NonPagedPool, Length, TAG_SYS_BUF);
663 if (!Irp->AssociatedIrp.SystemBuffer)
664 {
665 /* Free the IRP and fail */
666 IoFreeIrp(Irp);
667 return NULL;
668 }
669
670 /* Set flags */
671 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
672
673 /* Handle special IRP_MJ_WRITE Case */
674 if (MajorFunction == IRP_MJ_WRITE)
675 {
676 /* Copy the buffer data */
677 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
678 }
679 else
680 {
681 /* Set the Input Operation flag and set this as a User Buffer */
682 Irp->Flags |= IRP_INPUT_OPERATION;
683 Irp->UserBuffer = Buffer;
684 }
685 }
686 else if (DeviceObject->Flags & DO_DIRECT_IO)
687 {
688 /* Use an MDL for Direct I/O */
689 Irp->MdlAddress = IoAllocateMdl(Buffer,
690 Length,
691 FALSE,
692 FALSE,
693 NULL);
694 if (!Irp->MdlAddress)
695 {
696 /* Free the IRP and fail */
697 IoFreeIrp(Irp);
698 return NULL;
699 }
700
701 /* Probe and Lock */
702 _SEH2_TRY
703 {
704 /* Do the probe */
705 MmProbeAndLockPages(Irp->MdlAddress,
706 KernelMode,
707 MajorFunction == IRP_MJ_READ ?
708 IoWriteAccess : IoReadAccess);
709 }
710 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
711 {
712 /* Free the IRP and its MDL */
713 IoFreeMdl(Irp->MdlAddress);
714 IoFreeIrp(Irp);
715
716 /* Fail */
717 _SEH2_YIELD(return NULL);
718 }
719 _SEH2_END;
720 }
721 else
722 {
723 /* Neither, use the buffer */
724 Irp->UserBuffer = Buffer;
725 }
726
727 /* Check if this is a read */
728 if (MajorFunction == IRP_MJ_READ)
729 {
730 /* Set the parameters for a read */
731 StackPtr->Parameters.Read.Length = Length;
732 StackPtr->Parameters.Read.ByteOffset = *StartingOffset;
733 }
734 else if (MajorFunction == IRP_MJ_WRITE)
735 {
736 /* Otherwise, set write parameters */
737 StackPtr->Parameters.Write.Length = Length;
738 StackPtr->Parameters.Write.ByteOffset = *StartingOffset;
739 }
740 }
741
742 /* Set the Current Thread and IOSB */
743 Irp->UserIosb = IoStatusBlock;
744 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
745
746 /* Return the IRP */
747 IOTRACE(IO_IRP_DEBUG,
748 "%s - Built IRP %p with Major, Buffer, DO %lx %p %p\n",
749 __FUNCTION__,
750 Irp,
751 MajorFunction,
752 Buffer,
753 DeviceObject);
754 return Irp;
755 }
756
757 /*
758 * @implemented
759 */
760 PIRP
761 NTAPI
762 IoBuildDeviceIoControlRequest(IN ULONG IoControlCode,
763 IN PDEVICE_OBJECT DeviceObject,
764 IN PVOID InputBuffer,
765 IN ULONG InputBufferLength,
766 IN PVOID OutputBuffer,
767 IN ULONG OutputBufferLength,
768 IN BOOLEAN InternalDeviceIoControl,
769 IN PKEVENT Event,
770 IN PIO_STATUS_BLOCK IoStatusBlock)
771 {
772 PIRP Irp;
773 PIO_STACK_LOCATION StackPtr;
774 ULONG BufferLength;
775
776 /* Allocate IRP */
777 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
778 if (!Irp) return NULL;
779
780 /* Get the Stack */
781 StackPtr = IoGetNextIrpStackLocation(Irp);
782
783 /* Set the DevCtl Type */
784 StackPtr->MajorFunction = InternalDeviceIoControl ?
785 IRP_MJ_INTERNAL_DEVICE_CONTROL :
786 IRP_MJ_DEVICE_CONTROL;
787
788 /* Set the IOCTL Data */
789 StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
790 StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
791 StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
792 OutputBufferLength;
793
794 /* Handle the Methods */
795 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
796 {
797 /* Buffered I/O */
798 case METHOD_BUFFERED:
799
800 /* Select the right Buffer Length */
801 BufferLength = InputBufferLength > OutputBufferLength ?
802 InputBufferLength : OutputBufferLength;
803
804 /* Make sure there is one */
805 if (BufferLength)
806 {
807 /* Allocate the System Buffer */
808 Irp->AssociatedIrp.SystemBuffer =
809 ExAllocatePoolWithTag(NonPagedPool,
810 BufferLength,
811 TAG_SYS_BUF);
812 if (!Irp->AssociatedIrp.SystemBuffer)
813 {
814 /* Free the IRP and fail */
815 IoFreeIrp(Irp);
816 return NULL;
817 }
818
819 /* Check if we got a buffer */
820 if (InputBuffer)
821 {
822 /* Copy into the System Buffer */
823 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
824 InputBuffer,
825 InputBufferLength);
826 }
827
828 /* Write the flags */
829 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
830 if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
831
832 /* Save the Buffer */
833 Irp->UserBuffer = OutputBuffer;
834 }
835 else
836 {
837 /* Clear the Flags and Buffer */
838 Irp->Flags = 0;
839 Irp->UserBuffer = NULL;
840 }
841 break;
842
843 /* Direct I/O */
844 case METHOD_IN_DIRECT:
845 case METHOD_OUT_DIRECT:
846
847 /* Check if we got an input buffer */
848 if (InputBuffer)
849 {
850 /* Allocate the System Buffer */
851 Irp->AssociatedIrp.SystemBuffer =
852 ExAllocatePoolWithTag(NonPagedPool,
853 InputBufferLength,
854 TAG_SYS_BUF);
855 if (!Irp->AssociatedIrp.SystemBuffer)
856 {
857 /* Free the IRP and fail */
858 IoFreeIrp(Irp);
859 return NULL;
860 }
861
862 /* Copy into the System Buffer */
863 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
864 InputBuffer,
865 InputBufferLength);
866
867 /* Write the flags */
868 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
869 }
870 else
871 {
872 /* Clear the flags */
873 Irp->Flags = 0;
874 }
875
876 /* Check if we got an output buffer */
877 if (OutputBuffer)
878 {
879 /* Allocate the System Buffer */
880 Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
881 OutputBufferLength,
882 FALSE,
883 FALSE,
884 Irp);
885 if (!Irp->MdlAddress)
886 {
887 /* Free the IRP and fail */
888 IoFreeIrp(Irp);
889 return NULL;
890 }
891
892 /* Probe and Lock */
893 _SEH2_TRY
894 {
895 /* Do the probe */
896 MmProbeAndLockPages(Irp->MdlAddress,
897 KernelMode,
898 IO_METHOD_FROM_CTL_CODE(IoControlCode) ==
899 METHOD_IN_DIRECT ?
900 IoReadAccess : IoWriteAccess);
901 }
902 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
903 {
904 /* Free the MDL */
905 IoFreeMdl(Irp->MdlAddress);
906
907 /* Free the input buffer and IRP */
908 if (InputBuffer) ExFreePool(Irp->AssociatedIrp.SystemBuffer);
909 IoFreeIrp(Irp);
910
911 /* Fail */
912 _SEH2_YIELD(return NULL);
913 }
914 _SEH2_END;
915 }
916 break;
917
918 case METHOD_NEITHER:
919
920 /* Just save the Buffer */
921 Irp->UserBuffer = OutputBuffer;
922 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
923 }
924
925 /* Now write the Event and IoSB */
926 Irp->UserIosb = IoStatusBlock;
927 Irp->UserEvent = Event;
928
929 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
930 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
931 IoQueueThreadIrp(Irp);
932
933 /* Return the IRP */
934 IOTRACE(IO_IRP_DEBUG,
935 "%s - Built IRP %p with IOCTL, Buffers, DO %lx %p %p %p\n",
936 __FUNCTION__,
937 Irp,
938 IoControlCode,
939 InputBuffer,
940 OutputBuffer,
941 DeviceObject);
942 return Irp;
943 }
944
945 /*
946 * @implemented
947 */
948 PIRP
949 NTAPI
950 IoBuildSynchronousFsdRequest(IN ULONG MajorFunction,
951 IN PDEVICE_OBJECT DeviceObject,
952 IN PVOID Buffer,
953 IN ULONG Length,
954 IN PLARGE_INTEGER StartingOffset,
955 IN PKEVENT Event,
956 IN PIO_STATUS_BLOCK IoStatusBlock)
957 {
958 PIRP Irp;
959
960 /* Do the big work to set up the IRP */
961 Irp = IoBuildAsynchronousFsdRequest(MajorFunction,
962 DeviceObject,
963 Buffer,
964 Length,
965 StartingOffset,
966 IoStatusBlock );
967 if (!Irp) return NULL;
968
969 /* Set the Event which makes it Syncronous */
970 Irp->UserEvent = Event;
971
972 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
973 IoQueueThreadIrp(Irp);
974 return Irp;
975 }
976
977 /*
978 * @implemented
979 */
980 BOOLEAN
981 NTAPI
982 IoCancelIrp(IN PIRP Irp)
983 {
984 KIRQL OldIrql;
985 KIRQL IrqlAtEntry;
986 PDRIVER_CANCEL CancelRoutine;
987 IOTRACE(IO_IRP_DEBUG,
988 "%s - Canceling IRP %p\n",
989 __FUNCTION__,
990 Irp);
991 ASSERT(Irp->Type == IO_TYPE_IRP);
992 IrqlAtEntry = KeGetCurrentIrql();
993
994 /* Acquire the cancel lock and cancel the IRP */
995 IoAcquireCancelSpinLock(&OldIrql);
996 Irp->Cancel = TRUE;
997
998 /* Clear the cancel routine and get the old one */
999 CancelRoutine = (PVOID)IoSetCancelRoutine(Irp, NULL);
1000 if (CancelRoutine)
1001 {
1002 /* We had a routine, make sure the IRP isn't completed */
1003 if (Irp->CurrentLocation > (Irp->StackCount + 1))
1004 {
1005 /* It is, bugcheck */
1006 KeBugCheckEx(CANCEL_STATE_IN_COMPLETED_IRP,
1007 (ULONG_PTR)Irp,
1008 0,
1009 0,
1010 0);
1011 }
1012
1013 /* Set the cancel IRQL And call the routine */
1014 Irp->CancelIrql = OldIrql;
1015 CancelRoutine(IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Irp);
1016 ASSERT(IrqlAtEntry == KeGetCurrentIrql());
1017 return TRUE;
1018 }
1019
1020 /* Otherwise, release the cancel lock and fail */
1021 IoReleaseCancelSpinLock(OldIrql);
1022 return FALSE;
1023 }
1024
1025 /*
1026 * @implemented
1027 */
1028 VOID
1029 NTAPI
1030 IoCancelThreadIo(IN PETHREAD Thread)
1031 {
1032 KIRQL OldIrql;
1033 ULONG Retries = 3000;
1034 LARGE_INTEGER Interval;
1035 PLIST_ENTRY ListHead, NextEntry;
1036 PIRP Irp;
1037 IOTRACE(IO_IRP_DEBUG,
1038 "%s - Canceling IRPs for Thread %p\n",
1039 __FUNCTION__,
1040 Thread);
1041
1042 /* Raise to APC to protect the IrpList */
1043 KeRaiseIrql(APC_LEVEL, &OldIrql);
1044
1045 /* Start by cancelling all the IRPs in the current thread queue. */
1046 ListHead = &Thread->IrpList;
1047 NextEntry = ListHead->Flink;
1048 while (ListHead != NextEntry)
1049 {
1050 /* Get the IRP and move to the next entry */
1051 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
1052 NextEntry = NextEntry->Flink;
1053
1054 /* Cancel it */
1055 IoCancelIrp(Irp);
1056 }
1057
1058 /* Wait 100 milliseconds */
1059 Interval.QuadPart = -1000000;
1060
1061 /* Wait till all the IRPs are completed or cancelled. */
1062 while (!IsListEmpty(&Thread->IrpList))
1063 {
1064 /* Now we can lower */
1065 KeLowerIrql(OldIrql);
1066
1067 /* Wait a short while and then look if all our IRPs were completed. */
1068 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1069
1070 /*
1071 * Don't stay here forever if some broken driver doesn't complete
1072 * the IRP.
1073 */
1074 if (!(Retries--))
1075 {
1076 /* Print out a message and remove the IRP */
1077 DPRINT1("Broken driver did not complete!\n");
1078 IopRemoveThreadIrp();
1079 }
1080
1081 /* Raise the IRQL Again */
1082 KeRaiseIrql(APC_LEVEL, &OldIrql);
1083 }
1084
1085 /* We're done, lower the IRQL */
1086 KeLowerIrql(OldIrql);
1087 }
1088
1089 /*
1090 * @implemented
1091 */
1092 NTSTATUS
1093 NTAPI
1094 IoCallDriver(IN PDEVICE_OBJECT DeviceObject,
1095 IN PIRP Irp)
1096 {
1097 /* Call fastcall */
1098 return IofCallDriver(DeviceObject, Irp);
1099 }
1100
1101 /*
1102 * @implemented
1103 */
1104 VOID
1105 NTAPI
1106 IoCompleteRequest(IN PIRP Irp,
1107 IN CCHAR PriorityBoost)
1108 {
1109 /* Call the fastcall */
1110 IofCompleteRequest(Irp, PriorityBoost);
1111 }
1112
1113 /*
1114 * @implemented
1115 */
1116 VOID
1117 NTAPI
1118 IoEnqueueIrp(IN PIRP Irp)
1119 {
1120 /* This is the same as calling IoQueueThreadIrp */
1121 IoQueueThreadIrp(Irp);
1122 }
1123
1124 /*
1125 * @implemented
1126 */
1127 NTSTATUS
1128 FASTCALL
1129 IofCallDriver(IN PDEVICE_OBJECT DeviceObject,
1130 IN PIRP Irp)
1131 {
1132 PDRIVER_OBJECT DriverObject;
1133 PIO_STACK_LOCATION StackPtr;
1134
1135 /* Make sure this is a valid IRP */
1136 ASSERT(Irp->Type == IO_TYPE_IRP);
1137
1138 /* Get the Driver Object */
1139 DriverObject = DeviceObject->DriverObject;
1140
1141 /* Decrease the current location and check if */
1142 Irp->CurrentLocation--;
1143 if (Irp->CurrentLocation <= 0)
1144 {
1145 /* This IRP ran out of stack, bugcheck */
1146 KeBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR)Irp, 0, 0, 0);
1147 }
1148
1149 /* Now update the stack location */
1150 StackPtr = IoGetNextIrpStackLocation(Irp);
1151 Irp->Tail.Overlay.CurrentStackLocation = StackPtr;
1152
1153 /* Get the Device Object */
1154 StackPtr->DeviceObject = DeviceObject;
1155
1156 /* Call it */
1157 return DriverObject->MajorFunction[StackPtr->MajorFunction](DeviceObject,
1158 Irp);
1159 }
1160
1161 FORCEINLINE
1162 VOID
1163 IopClearStackLocation(IN PIO_STACK_LOCATION IoStackLocation)
1164 {
1165 IoStackLocation->MinorFunction = 0;
1166 IoStackLocation->Flags = 0;
1167 IoStackLocation->Control &= SL_ERROR_RETURNED;
1168 IoStackLocation->Parameters.Others.Argument1 = 0;
1169 IoStackLocation->Parameters.Others.Argument2 = 0;
1170 IoStackLocation->Parameters.Others.Argument3 = 0;
1171 IoStackLocation->FileObject = NULL;
1172 }
1173
1174 /*
1175 * @implemented
1176 */
1177 VOID
1178 FASTCALL
1179 IofCompleteRequest(IN PIRP Irp,
1180 IN CCHAR PriorityBoost)
1181 {
1182 PIO_STACK_LOCATION StackPtr, LastStackPtr;
1183 PDEVICE_OBJECT DeviceObject;
1184 PFILE_OBJECT FileObject;
1185 PETHREAD Thread;
1186 NTSTATUS Status;
1187 PMDL Mdl, NextMdl;
1188 ULONG MasterCount;
1189 PIRP MasterIrp;
1190 ULONG Flags;
1191 NTSTATUS ErrorCode = STATUS_SUCCESS;
1192 IOTRACE(IO_IRP_DEBUG,
1193 "%s - Completing IRP %p\n",
1194 __FUNCTION__,
1195 Irp);
1196
1197 /* Make sure this IRP isn't getting completed twice or is invalid */
1198 if ((Irp->CurrentLocation) > (Irp->StackCount + 1))
1199 {
1200 /* Bugcheck */
1201 KeBugCheckEx(MULTIPLE_IRP_COMPLETE_REQUESTS, (ULONG_PTR)Irp, 0, 0, 0);
1202 }
1203
1204 /* Some sanity checks */
1205 ASSERT(Irp->Type == IO_TYPE_IRP);
1206 ASSERT(!Irp->CancelRoutine);
1207 ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
1208 ASSERT(Irp->IoStatus.Status != (NTSTATUS)0xFFFFFFFF);
1209
1210 /* Get the last stack */
1211 LastStackPtr = (PIO_STACK_LOCATION)(Irp + 1);
1212 if (LastStackPtr->Control & SL_ERROR_RETURNED)
1213 {
1214 /* Get the error code */
1215 ErrorCode = PtrToUlong(LastStackPtr->Parameters.Others.Argument4);
1216 }
1217
1218 /*
1219 * Start the loop with the current stack and point the IRP to the next stack
1220 * and then keep incrementing the stack as we loop through. The IRP should
1221 * always point to the next stack location w.r.t the one currently being
1222 * analyzed, so completion routine code will see the appropriate value.
1223 * Because of this, we must loop until the current stack location is +1 of
1224 * the stack count, because when StackPtr is at the end, CurrentLocation is +1.
1225 */
1226 for (StackPtr = IoGetCurrentIrpStackLocation(Irp),
1227 Irp->CurrentLocation++,
1228 Irp->Tail.Overlay.CurrentStackLocation++;
1229 Irp->CurrentLocation <= (Irp->StackCount + 1);
1230 StackPtr++,
1231 Irp->CurrentLocation++,
1232 Irp->Tail.Overlay.CurrentStackLocation++)
1233 {
1234 /* Set Pending Returned */
1235 Irp->PendingReturned = StackPtr->Control & SL_PENDING_RETURNED;
1236
1237 /* Check if we failed */
1238 if (!NT_SUCCESS(Irp->IoStatus.Status))
1239 {
1240 /* Check if it was changed by a completion routine */
1241 if (Irp->IoStatus.Status != ErrorCode)
1242 {
1243 /* Update the error for the current stack */
1244 ErrorCode = Irp->IoStatus.Status;
1245 StackPtr->Control |= SL_ERROR_RETURNED;
1246 LastStackPtr->Parameters.Others.Argument4 = UlongToPtr(ErrorCode);
1247 LastStackPtr->Control |= SL_ERROR_RETURNED;
1248 }
1249 }
1250
1251 /* Check if there is a Completion Routine to Call */
1252 if ((NT_SUCCESS(Irp->IoStatus.Status) &&
1253 (StackPtr->Control & SL_INVOKE_ON_SUCCESS)) ||
1254 (!NT_SUCCESS(Irp->IoStatus.Status) &&
1255 (StackPtr->Control & SL_INVOKE_ON_ERROR)) ||
1256 (Irp->Cancel &&
1257 (StackPtr->Control & SL_INVOKE_ON_CANCEL)))
1258 {
1259 /* Clear the stack location */
1260 IopClearStackLocation(StackPtr);
1261
1262 /* Check for highest-level device completion routines */
1263 if (Irp->CurrentLocation == (Irp->StackCount + 1))
1264 {
1265 /* Clear the DO, since the current stack location is invalid */
1266 DeviceObject = NULL;
1267 }
1268 else
1269 {
1270 /* Otherwise, return the real one */
1271 DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
1272 }
1273
1274 /* Call the completion routine */
1275 Status = StackPtr->CompletionRoutine(DeviceObject,
1276 Irp,
1277 StackPtr->Context);
1278
1279 /* Don't touch the Packet in this case, since it might be gone! */
1280 if (Status == STATUS_MORE_PROCESSING_REQUIRED) return;
1281 }
1282 else
1283 {
1284 /* Otherwise, check if this is a completed IRP */
1285 if ((Irp->CurrentLocation <= Irp->StackCount) &&
1286 (Irp->PendingReturned))
1287 {
1288 /* Mark it as pending */
1289 IoMarkIrpPending(Irp);
1290 }
1291
1292 /* Clear the stack location */
1293 IopClearStackLocation(StackPtr);
1294 }
1295 }
1296
1297 /* Check if the IRP is an associated IRP */
1298 if (Irp->Flags & IRP_ASSOCIATED_IRP)
1299 {
1300 /* Get the master IRP and count */
1301 MasterIrp = Irp->AssociatedIrp.MasterIrp;
1302 MasterCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount);
1303
1304 /* Free the MDLs */
1305 for (Mdl = Irp->MdlAddress; Mdl; Mdl = NextMdl)
1306 {
1307 /* Go to the next one */
1308 NextMdl = Mdl->Next;
1309 IoFreeMdl(Mdl);
1310 }
1311
1312 /* Free the IRP itself */
1313 IoFreeIrp(Irp);
1314
1315 /* Complete the Master IRP */
1316 if (!MasterCount) IofCompleteRequest(MasterIrp, PriorityBoost);
1317 return;
1318 }
1319
1320 /* We don't support this yet */
1321 ASSERT(Irp->IoStatus.Status != STATUS_REPARSE);
1322
1323 /* Check if we have an auxiliary buffer */
1324 if (Irp->Tail.Overlay.AuxiliaryBuffer)
1325 {
1326 /* Free it */
1327 ExFreePool(Irp->Tail.Overlay.AuxiliaryBuffer);
1328 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
1329 }
1330
1331 /* Check if this is a Paging I/O or Close Operation */
1332 if (Irp->Flags & (IRP_PAGING_IO | IRP_CLOSE_OPERATION))
1333 {
1334 /* Handle a Close Operation or Sync Paging I/O */
1335 if (Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_CLOSE_OPERATION))
1336 {
1337 /* Set the I/O Status and Signal the Event */
1338 Flags = Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_PAGING_IO);
1339 *Irp->UserIosb = Irp->IoStatus;
1340 KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE);
1341
1342 /* Free the IRP for a Paging I/O Only, Close is handled by us */
1343 if (Flags) IoFreeIrp(Irp);
1344 }
1345 else
1346 {
1347 #if 0
1348 /* Page 166 */
1349 KeInitializeApc(&Irp->Tail.Apc
1350 &Irp->Tail.Overlay.Thread->Tcb,
1351 Irp->ApcEnvironment,
1352 IopCompletePageWrite,
1353 NULL,
1354 NULL,
1355 KernelMode,
1356 NULL);
1357 KeInsertQueueApc(&Irp->Tail.Apc,
1358 NULL,
1359 NULL,
1360 PriorityBoost);
1361 #else
1362 /* Not implemented yet. */
1363 DPRINT1("Not supported!\n");
1364 while (TRUE);
1365 #endif
1366 }
1367
1368 /* Get out of here */
1369 return;
1370 }
1371
1372 /* Unlock MDL Pages, page 167. */
1373 Mdl = Irp->MdlAddress;
1374 while (Mdl)
1375 {
1376 MmUnlockPages(Mdl);
1377 Mdl = Mdl->Next;
1378 }
1379
1380 /* Check if we should exit because of a Deferred I/O (page 168) */
1381 if ((Irp->Flags & IRP_DEFER_IO_COMPLETION) && !(Irp->PendingReturned))
1382 {
1383 /*
1384 * Return without queuing the completion APC, since the caller will
1385 * take care of doing its own optimized completion at PASSIVE_LEVEL.
1386 */
1387 return;
1388 }
1389
1390 /* Get the thread and file object */
1391 Thread = Irp->Tail.Overlay.Thread;
1392 FileObject = Irp->Tail.Overlay.OriginalFileObject;
1393
1394 /* Make sure the IRP isn't canceled */
1395 if (!Irp->Cancel)
1396 {
1397 /* Initialize the APC */
1398 KeInitializeApc(&Irp->Tail.Apc,
1399 &Thread->Tcb,
1400 Irp->ApcEnvironment,
1401 IopCompleteRequest,
1402 NULL,
1403 NULL,
1404 KernelMode,
1405 NULL);
1406
1407 /* Queue it */
1408 KeInsertQueueApc(&Irp->Tail.Apc,
1409 FileObject,
1410 NULL, /* This is used for REPARSE stuff */
1411 PriorityBoost);
1412 }
1413 else
1414 {
1415 /* The IRP just got canceled... does a thread still own it? */
1416 Thread = Irp->Tail.Overlay.Thread;
1417 if (Thread)
1418 {
1419 /* Yes! There is still hope! Initialize the APC */
1420 KeInitializeApc(&Irp->Tail.Apc,
1421 &Thread->Tcb,
1422 Irp->ApcEnvironment,
1423 IopCompleteRequest,
1424 NULL,
1425 NULL,
1426 KernelMode,
1427 NULL);
1428
1429 /* Queue it */
1430 KeInsertQueueApc(&Irp->Tail.Apc,
1431 FileObject,
1432 NULL, /* This is used for REPARSE stuff */
1433 PriorityBoost);
1434 }
1435 else
1436 {
1437 /* Nothing left for us to do, kill it */
1438 ASSERT(Irp->Cancel);
1439 IopCleanupIrp(Irp, FileObject);
1440 }
1441 }
1442 }
1443
1444 NTSTATUS
1445 NTAPI
1446 IopSynchronousCompletion(IN PDEVICE_OBJECT DeviceObject,
1447 IN PIRP Irp,
1448 IN PVOID Context)
1449 {
1450 if (Irp->PendingReturned)
1451 KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
1452 return STATUS_MORE_PROCESSING_REQUIRED;
1453 }
1454
1455 /*
1456 * @implemented
1457 */
1458 BOOLEAN
1459 NTAPI
1460 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject,
1461 IN PIRP Irp)
1462 {
1463 KEVENT Event;
1464 NTSTATUS Status;
1465
1466 /* Check if next stack location is available */
1467 if (Irp->CurrentLocation < Irp->StackCount)
1468 {
1469 /* No more stack location */
1470 return FALSE;
1471 }
1472
1473 /* Initialize event */
1474 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1475
1476 /* Copy stack location for next driver */
1477 IoCopyCurrentIrpStackLocationToNext(Irp);
1478
1479 /* Set a completion routine, which will signal the event */
1480 IoSetCompletionRoutine(Irp, IopSynchronousCompletion, &Event, TRUE, TRUE, TRUE);
1481
1482 /* Call next driver */
1483 Status = IoCallDriver(DeviceObject, Irp);
1484
1485 /* Check if irp is pending */
1486 if (Status == STATUS_PENDING)
1487 {
1488 /* Yes, wait for its completion */
1489 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
1490 }
1491
1492 /* Return success */
1493 return TRUE;
1494 }
1495
1496 /*
1497 * @implemented
1498 */
1499 VOID
1500 NTAPI
1501 IoFreeIrp(IN PIRP Irp)
1502 {
1503 PNPAGED_LOOKASIDE_LIST List;
1504 PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList;
1505 PKPRCB Prcb;
1506 IOTRACE(IO_IRP_DEBUG,
1507 "%s - Freeing IRPs %p\n",
1508 __FUNCTION__,
1509 Irp);
1510
1511 /* Make sure the Thread IRP list is empty and that it OK to free it */
1512 ASSERT(Irp->Type == IO_TYPE_IRP);
1513 ASSERT(IsListEmpty(&Irp->ThreadListEntry));
1514 ASSERT(Irp->CurrentLocation >= Irp->StackCount);
1515
1516 /* If this was a pool alloc, free it with the pool */
1517 if (!(Irp->AllocationFlags & IRP_ALLOCATED_FIXED_SIZE))
1518 {
1519 /* Free it */
1520 ExFreePoolWithTag(Irp, TAG_IRP);
1521 }
1522 else
1523 {
1524 /* Check if this was a Big IRP */
1525 if (Irp->StackCount != 1) ListType = LookasideLargeIrpList;
1526
1527 /* Get the PRCB */
1528 Prcb = KeGetCurrentPrcb();
1529
1530 /* Use the P List */
1531 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;
1532 List->L.TotalFrees++;
1533
1534 /* Check if the Free was within the Depth or not */
1535 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
1536 {
1537 /* Let the balancer know */
1538 List->L.FreeMisses++;
1539
1540 /* Use the L List */
1541 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;
1542 List->L.TotalFrees++;
1543
1544 /* Check if the Free was within the Depth or not */
1545 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
1546 {
1547 /* All lists failed, use the pool */
1548 List->L.FreeMisses++;
1549 ExFreePoolWithTag(Irp, TAG_IRP);
1550 Irp = NULL;
1551 }
1552 }
1553
1554 /* The free was within the Depth */
1555 if (Irp)
1556 {
1557 InterlockedPushEntrySList(&List->L.ListHead,
1558 (PSLIST_ENTRY)Irp);
1559 }
1560 }
1561 }
1562
1563 /*
1564 * @implemented
1565 */
1566 IO_PAGING_PRIORITY
1567 FASTCALL
1568 IoGetPagingIoPriority(IN PIRP Irp)
1569 {
1570 IO_PAGING_PRIORITY Priority;
1571 ULONG Flags;
1572
1573 /* Get the flags */
1574 Flags = Irp->Flags;
1575
1576 /* Check what priority it has */
1577 if (Flags & 0x8000) // FIXME: Undocumented flag
1578 {
1579 /* High priority */
1580 Priority = IoPagingPriorityHigh;
1581 }
1582 else if (Flags & IRP_PAGING_IO)
1583 {
1584 /* Normal priority */
1585 Priority = IoPagingPriorityNormal;
1586 }
1587 else
1588 {
1589 /* Invalid -- not a paging IRP */
1590 Priority = IoPagingPriorityInvalid;
1591 }
1592
1593 /* Return the priority */
1594 return Priority;
1595 }
1596
1597 /*
1598 * @implemented
1599 */
1600 PEPROCESS
1601 NTAPI
1602 IoGetRequestorProcess(IN PIRP Irp)
1603 {
1604 /* Return the requestor process */
1605 return Irp->Tail.Overlay.Thread->ThreadsProcess;
1606 }
1607
1608 /*
1609 * @implemented
1610 */
1611 ULONG
1612 NTAPI
1613 IoGetRequestorProcessId(IN PIRP Irp)
1614 {
1615 /* Return the requestor process' id */
1616 return PtrToUlong(IoGetRequestorProcess(Irp)->UniqueProcessId);
1617 }
1618
1619 /*
1620 * @implemented
1621 */
1622 NTSTATUS
1623 NTAPI
1624 IoGetRequestorSessionId(IN PIRP Irp,
1625 OUT PULONG pSessionId)
1626 {
1627 /* Return the session */
1628 *pSessionId = IoGetRequestorProcess(Irp)->Session;
1629 return STATUS_SUCCESS;
1630 }
1631
1632 /*
1633 * @implemented
1634 */
1635 PIRP
1636 NTAPI
1637 IoGetTopLevelIrp(VOID)
1638 {
1639 /* Return the IRP */
1640 return (PIRP)PsGetCurrentThread()->TopLevelIrp;
1641 }
1642
1643 /*
1644 * @implemented
1645 */
1646 VOID
1647 NTAPI
1648 IoInitializeIrp(IN PIRP Irp,
1649 IN USHORT PacketSize,
1650 IN CCHAR StackSize)
1651 {
1652 /* Clear it */
1653 IOTRACE(IO_IRP_DEBUG,
1654 "%s - Initializing IRP %p\n",
1655 __FUNCTION__,
1656 Irp);
1657 RtlZeroMemory(Irp, PacketSize);
1658
1659 /* Set the Header and other data */
1660 Irp->Type = IO_TYPE_IRP;
1661 Irp->Size = PacketSize;
1662 Irp->StackCount = StackSize;
1663 Irp->CurrentLocation = StackSize + 1;
1664 Irp->ApcEnvironment = KeGetCurrentThread()->ApcStateIndex;
1665 Irp->Tail.Overlay.CurrentStackLocation = (PIO_STACK_LOCATION)(Irp + 1) + StackSize;
1666
1667 /* Initialize the Thread List */
1668 InitializeListHead(&Irp->ThreadListEntry);
1669 }
1670
1671 /*
1672 * @implemented
1673 */
1674 BOOLEAN
1675 NTAPI
1676 IoIsOperationSynchronous(IN PIRP Irp)
1677 {
1678 /* Check the flags */
1679 if (!(Irp->Flags & (IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO)) &&
1680 ((Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ||
1681 (Irp->Flags & IRP_SYNCHRONOUS_API) ||
1682 (IoGetCurrentIrpStackLocation(Irp)->FileObject->Flags &
1683 FO_SYNCHRONOUS_IO)))
1684 {
1685 /* Synch API or Paging I/O is OK, as is Sync File I/O */
1686 return TRUE;
1687 }
1688
1689 /* Otherwise, it is an asynchronous operation. */
1690 return FALSE;
1691 }
1692
1693 /*
1694 * @unimplemented
1695 */
1696 BOOLEAN
1697 NTAPI
1698 IoIsValidNameGraftingBuffer(IN PIRP Irp,
1699 IN PREPARSE_DATA_BUFFER ReparseBuffer)
1700 {
1701 UNIMPLEMENTED;
1702 return FALSE;
1703 }
1704
1705 /*
1706 * @implemented
1707 */
1708 PIRP
1709 NTAPI
1710 IoMakeAssociatedIrp(IN PIRP Irp,
1711 IN CCHAR StackSize)
1712 {
1713 PIRP AssocIrp;
1714 IOTRACE(IO_IRP_DEBUG,
1715 "%s - Associating IRP %p\n",
1716 __FUNCTION__,
1717 Irp);
1718
1719 /* Allocate the IRP */
1720 AssocIrp = IoAllocateIrp(StackSize, FALSE);
1721 if (!AssocIrp) return NULL;
1722
1723 /* Set the Flags */
1724 AssocIrp->Flags |= IRP_ASSOCIATED_IRP;
1725
1726 /* Set the Thread */
1727 AssocIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
1728
1729 /* Associate them */
1730 AssocIrp->AssociatedIrp.MasterIrp = Irp;
1731 return AssocIrp;
1732 }
1733
1734 /*
1735 * @implemented
1736 */
1737 VOID
1738 NTAPI
1739 IoQueueThreadIrp(IN PIRP Irp)
1740 {
1741 IOTRACE(IO_IRP_DEBUG,
1742 "%s - Queueing IRP %p\n",
1743 __FUNCTION__,
1744 Irp);
1745
1746 /* Use our inlined routine */
1747 IopQueueIrpToThread(Irp);
1748 }
1749
1750 /*
1751 * @implemented
1752 * Reference: Chris Cant's "Writing WDM Device Drivers"
1753 */
1754 VOID
1755 NTAPI
1756 IoReuseIrp(IN OUT PIRP Irp,
1757 IN NTSTATUS Status)
1758 {
1759 UCHAR AllocationFlags;
1760 IOTRACE(IO_IRP_DEBUG,
1761 "%s - Reusing IRP %p\n",
1762 __FUNCTION__,
1763 Irp);
1764
1765 /* Make sure it's OK to reuse it */
1766 ASSERT(!Irp->CancelRoutine);
1767 ASSERT(IsListEmpty(&Irp->ThreadListEntry));
1768
1769 /* Get the old flags */
1770 AllocationFlags = Irp->AllocationFlags;
1771
1772 /* Reinitialize the IRP */
1773 IoInitializeIrp(Irp, Irp->Size, Irp->StackCount);
1774
1775 /* Duplicate the data */
1776 Irp->IoStatus.Status = Status;
1777 Irp->AllocationFlags = AllocationFlags;
1778 }
1779
1780 /*
1781 * @implemented
1782 */
1783 VOID
1784 NTAPI
1785 IoSetTopLevelIrp(IN PIRP Irp)
1786 {
1787 /* Set the IRP */
1788 PsGetCurrentThread()->TopLevelIrp = (ULONG_PTR)Irp;
1789 }