e3695e9d2fbf5989210f3379a3244c75ba1eccc7
[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 /* Now check if the user gave an event */
473 if (Irp->UserEvent)
474 {
475 /* Signal it */
476 KeSetEvent(Irp->UserEvent, 0, FALSE);
477 }
478 else
479 {
480 /* No event was given, so signal the FO instead */
481 KeSetEvent(&FileObject->Event, 0, FALSE);
482 }
483 }
484 else
485 {
486 /*
487 * It's not the IRP that was synchronous, it was the FO
488 * that was opened this way. Signal its event.
489 */
490 FileObject->FinalStatus = Irp->IoStatus.Status;
491 KeSetEvent(&FileObject->Event, 0, FALSE);
492 }
493 }
494
495 /* Check if we have an associated user IOSB */
496 if (Irp->UserIosb)
497 {
498 /* We do, so let's give them the final status */
499 _SEH2_TRY
500 {
501 /* Save the IOSB Information */
502 *Irp->UserIosb = Irp->IoStatus;
503 }
504 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
505 {
506 /* Ignore any error */
507 }
508 _SEH2_END;
509 }
510
511 /* Now that we got here, we do this for incomplete I/Os as well */
512 if ((FileObject) && !(Irp->Flags & IRP_CREATE_OPERATION))
513 {
514 /* Dereference the File Object unless this was a create */
515 ObDereferenceObjectDeferDelete(FileObject);
516 }
517
518 /*
519 * Check if this was an Executive Event (remember that we know this
520 * by checking if the IRP is synchronous)
521 */
522 if ((Irp->UserEvent) &&
523 (FileObject) &&
524 !(Irp->Flags & IRP_SYNCHRONOUS_API))
525 {
526 /* This isn't a PKEVENT, so dereference it */
527 ObDereferenceObject(Irp->UserEvent);
528 }
529
530 /* Now that we've signaled the events, de-associate the IRP */
531 IopUnQueueIrpFromThread(Irp);
532
533 /* Free the IRP as well */
534 IoFreeIrp(Irp);
535 }
536 }
537
538 /* FUNCTIONS *****************************************************************/
539
540 /*
541 * @implemented
542 */
543 PIRP
544 NTAPI
545 IoAllocateIrp(IN CCHAR StackSize,
546 IN BOOLEAN ChargeQuota)
547 {
548 PIRP Irp = NULL;
549 USHORT Size = IoSizeOfIrp(StackSize);
550 PKPRCB Prcb;
551 UCHAR Flags = 0;
552 PNPAGED_LOOKASIDE_LIST List = NULL;
553 PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList;
554
555 /* Set Charge Quota Flag */
556 if (ChargeQuota) Flags |= IRP_QUOTA_CHARGED;
557
558 /* FIXME: Implement Lookaside Floats */
559
560 /* Figure out which Lookaside List to use */
561 if ((StackSize <= 8) && (ChargeQuota == FALSE))
562 {
563 /* Set Fixed Size Flag */
564 Flags = IRP_ALLOCATED_FIXED_SIZE;
565
566 /* See if we should use big list */
567 if (StackSize != 1)
568 {
569 Size = IoSizeOfIrp(8);
570 ListType = LookasideLargeIrpList;
571 }
572
573 /* Get the PRCB */
574 Prcb = KeGetCurrentPrcb();
575
576 /* Get the P List First */
577 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;
578
579 /* Attempt allocation */
580 List->L.TotalAllocates++;
581 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
582
583 /* Check if the P List failed */
584 if (!Irp)
585 {
586 /* Let the balancer know */
587 List->L.AllocateMisses++;
588
589 /* Try the L List */
590 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;
591 List->L.TotalAllocates++;
592 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
593 }
594 }
595
596 /* Check if we have to use the pool */
597 if (!Irp)
598 {
599 /* Did we try lookaside and fail? */
600 if (Flags & IRP_ALLOCATED_FIXED_SIZE) List->L.AllocateMisses++;
601
602 /* Check if we should charge quota */
603 if (ChargeQuota)
604 {
605 /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool, Size, TAG_IRP); */
606 /* FIXME */
607 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
608 }
609 else
610 {
611 /* Allocate the IRP With no Quota charge */
612 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
613 }
614
615 /* Make sure it was sucessful */
616 if (!Irp) return(NULL);
617 }
618 else
619 {
620 /* In this case there is no charge quota */
621 Flags &= ~IRP_QUOTA_CHARGED;
622 }
623
624 /* Now Initialize it */
625 IoInitializeIrp(Irp, Size, StackSize);
626
627 /* Set the Allocation Flags */
628 Irp->AllocationFlags = Flags;
629
630 /* Return it */
631 IOTRACE(IO_IRP_DEBUG,
632 "%s - Allocated IRP %p with allocation flags %lx\n",
633 __FUNCTION__,
634 Irp,
635 Flags);
636 return Irp;
637 }
638
639 /*
640 * @implemented
641 */
642 PIRP
643 NTAPI
644 IoBuildAsynchronousFsdRequest(IN ULONG MajorFunction,
645 IN PDEVICE_OBJECT DeviceObject,
646 IN PVOID Buffer,
647 IN ULONG Length,
648 IN PLARGE_INTEGER StartingOffset,
649 IN PIO_STATUS_BLOCK IoStatusBlock)
650 {
651 PIRP Irp;
652 PIO_STACK_LOCATION StackPtr;
653
654 /* Allocate IRP */
655 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
656 if (!Irp) return NULL;
657
658 /* Get the Stack */
659 StackPtr = IoGetNextIrpStackLocation(Irp);
660
661 /* Write the Major function and then deal with it */
662 StackPtr->MajorFunction = (UCHAR)MajorFunction;
663
664 /* Do not handle the following here */
665 if ((MajorFunction != IRP_MJ_FLUSH_BUFFERS) &&
666 (MajorFunction != IRP_MJ_SHUTDOWN) &&
667 (MajorFunction != IRP_MJ_PNP) &&
668 (MajorFunction != IRP_MJ_POWER))
669 {
670 /* Check if this is Buffered IO */
671 if (DeviceObject->Flags & DO_BUFFERED_IO)
672 {
673 /* Allocate the System Buffer */
674 Irp->AssociatedIrp.SystemBuffer =
675 ExAllocatePoolWithTag(NonPagedPool, Length, TAG_SYS_BUF);
676 if (!Irp->AssociatedIrp.SystemBuffer)
677 {
678 /* Free the IRP and fail */
679 IoFreeIrp(Irp);
680 return NULL;
681 }
682
683 /* Set flags */
684 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
685
686 /* Handle special IRP_MJ_WRITE Case */
687 if (MajorFunction == IRP_MJ_WRITE)
688 {
689 /* Copy the buffer data */
690 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
691 }
692 else
693 {
694 /* Set the Input Operation flag and set this as a User Buffer */
695 Irp->Flags |= IRP_INPUT_OPERATION;
696 Irp->UserBuffer = Buffer;
697 }
698 }
699 else if (DeviceObject->Flags & DO_DIRECT_IO)
700 {
701 /* Use an MDL for Direct I/O */
702 Irp->MdlAddress = IoAllocateMdl(Buffer,
703 Length,
704 FALSE,
705 FALSE,
706 NULL);
707 if (!Irp->MdlAddress)
708 {
709 /* Free the IRP and fail */
710 IoFreeIrp(Irp);
711 return NULL;
712 }
713
714 /* Probe and Lock */
715 _SEH2_TRY
716 {
717 /* Do the probe */
718 MmProbeAndLockPages(Irp->MdlAddress,
719 KernelMode,
720 MajorFunction == IRP_MJ_READ ?
721 IoWriteAccess : IoReadAccess);
722 }
723 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
724 {
725 /* Free the IRP and its MDL */
726 IoFreeMdl(Irp->MdlAddress);
727 IoFreeIrp(Irp);
728
729 /* Fail */
730 _SEH2_YIELD(return NULL);
731 }
732 _SEH2_END;
733 }
734 else
735 {
736 /* Neither, use the buffer */
737 Irp->UserBuffer = Buffer;
738 }
739
740 /* Check if this is a read */
741 if (MajorFunction == IRP_MJ_READ)
742 {
743 /* Set the parameters for a read */
744 StackPtr->Parameters.Read.Length = Length;
745 StackPtr->Parameters.Read.ByteOffset = *StartingOffset;
746 }
747 else if (MajorFunction == IRP_MJ_WRITE)
748 {
749 /* Otherwise, set write parameters */
750 StackPtr->Parameters.Write.Length = Length;
751 StackPtr->Parameters.Write.ByteOffset = *StartingOffset;
752 }
753 }
754
755 /* Set the Current Thread and IOSB */
756 Irp->UserIosb = IoStatusBlock;
757 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
758
759 /* Return the IRP */
760 IOTRACE(IO_IRP_DEBUG,
761 "%s - Built IRP %p with Major, Buffer, DO %lx %p %p\n",
762 __FUNCTION__,
763 Irp,
764 MajorFunction,
765 Buffer,
766 DeviceObject);
767 return Irp;
768 }
769
770 /*
771 * @implemented
772 */
773 PIRP
774 NTAPI
775 IoBuildDeviceIoControlRequest(IN ULONG IoControlCode,
776 IN PDEVICE_OBJECT DeviceObject,
777 IN PVOID InputBuffer,
778 IN ULONG InputBufferLength,
779 IN PVOID OutputBuffer,
780 IN ULONG OutputBufferLength,
781 IN BOOLEAN InternalDeviceIoControl,
782 IN PKEVENT Event,
783 IN PIO_STATUS_BLOCK IoStatusBlock)
784 {
785 PIRP Irp;
786 PIO_STACK_LOCATION StackPtr;
787 ULONG BufferLength;
788
789 /* Allocate IRP */
790 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
791 if (!Irp) return NULL;
792
793 /* Get the Stack */
794 StackPtr = IoGetNextIrpStackLocation(Irp);
795
796 /* Set the DevCtl Type */
797 StackPtr->MajorFunction = InternalDeviceIoControl ?
798 IRP_MJ_INTERNAL_DEVICE_CONTROL :
799 IRP_MJ_DEVICE_CONTROL;
800
801 /* Set the IOCTL Data */
802 StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
803 StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
804 StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
805 OutputBufferLength;
806
807 /* Handle the Methods */
808 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
809 {
810 /* Buffered I/O */
811 case METHOD_BUFFERED:
812
813 /* Select the right Buffer Length */
814 BufferLength = InputBufferLength > OutputBufferLength ?
815 InputBufferLength : OutputBufferLength;
816
817 /* Make sure there is one */
818 if (BufferLength)
819 {
820 /* Allocate the System Buffer */
821 Irp->AssociatedIrp.SystemBuffer =
822 ExAllocatePoolWithTag(NonPagedPool,
823 BufferLength,
824 TAG_SYS_BUF);
825 if (!Irp->AssociatedIrp.SystemBuffer)
826 {
827 /* Free the IRP and fail */
828 IoFreeIrp(Irp);
829 return NULL;
830 }
831
832 /* Check if we got a buffer */
833 if (InputBuffer)
834 {
835 /* Copy into the System Buffer */
836 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
837 InputBuffer,
838 InputBufferLength);
839 }
840
841 /* Write the flags */
842 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
843 if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
844
845 /* Save the Buffer */
846 Irp->UserBuffer = OutputBuffer;
847 }
848 else
849 {
850 /* Clear the Flags and Buffer */
851 Irp->Flags = 0;
852 Irp->UserBuffer = NULL;
853 }
854 break;
855
856 /* Direct I/O */
857 case METHOD_IN_DIRECT:
858 case METHOD_OUT_DIRECT:
859
860 /* Check if we got an input buffer */
861 if (InputBuffer)
862 {
863 /* Allocate the System Buffer */
864 Irp->AssociatedIrp.SystemBuffer =
865 ExAllocatePoolWithTag(NonPagedPool,
866 InputBufferLength,
867 TAG_SYS_BUF);
868 if (!Irp->AssociatedIrp.SystemBuffer)
869 {
870 /* Free the IRP and fail */
871 IoFreeIrp(Irp);
872 return NULL;
873 }
874
875 /* Copy into the System Buffer */
876 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
877 InputBuffer,
878 InputBufferLength);
879
880 /* Write the flags */
881 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
882 }
883 else
884 {
885 /* Clear the flags */
886 Irp->Flags = 0;
887 }
888
889 /* Check if we got an output buffer */
890 if (OutputBuffer)
891 {
892 /* Allocate the System Buffer */
893 Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
894 OutputBufferLength,
895 FALSE,
896 FALSE,
897 Irp);
898 if (!Irp->MdlAddress)
899 {
900 /* Free the IRP and fail */
901 IoFreeIrp(Irp);
902 return NULL;
903 }
904
905 /* Probe and Lock */
906 _SEH2_TRY
907 {
908 /* Do the probe */
909 MmProbeAndLockPages(Irp->MdlAddress,
910 KernelMode,
911 IO_METHOD_FROM_CTL_CODE(IoControlCode) ==
912 METHOD_IN_DIRECT ?
913 IoReadAccess : IoWriteAccess);
914 }
915 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
916 {
917 /* Free the MDL */
918 IoFreeMdl(Irp->MdlAddress);
919
920 /* Free the input buffer and IRP */
921 if (InputBuffer) ExFreePool(Irp->AssociatedIrp.SystemBuffer);
922 IoFreeIrp(Irp);
923
924 /* Fail */
925 _SEH2_YIELD(return NULL);
926 }
927 _SEH2_END;
928 }
929 break;
930
931 case METHOD_NEITHER:
932
933 /* Just save the Buffer */
934 Irp->UserBuffer = OutputBuffer;
935 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
936 }
937
938 /* Now write the Event and IoSB */
939 Irp->UserIosb = IoStatusBlock;
940 Irp->UserEvent = Event;
941
942 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
943 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
944 IoQueueThreadIrp(Irp);
945
946 /* Return the IRP */
947 IOTRACE(IO_IRP_DEBUG,
948 "%s - Built IRP %p with IOCTL, Buffers, DO %lx %p %p %p\n",
949 __FUNCTION__,
950 Irp,
951 IoControlCode,
952 InputBuffer,
953 OutputBuffer,
954 DeviceObject);
955 return Irp;
956 }
957
958 /*
959 * @implemented
960 */
961 PIRP
962 NTAPI
963 IoBuildSynchronousFsdRequest(IN ULONG MajorFunction,
964 IN PDEVICE_OBJECT DeviceObject,
965 IN PVOID Buffer,
966 IN ULONG Length,
967 IN PLARGE_INTEGER StartingOffset,
968 IN PKEVENT Event,
969 IN PIO_STATUS_BLOCK IoStatusBlock)
970 {
971 PIRP Irp;
972
973 /* Do the big work to set up the IRP */
974 Irp = IoBuildAsynchronousFsdRequest(MajorFunction,
975 DeviceObject,
976 Buffer,
977 Length,
978 StartingOffset,
979 IoStatusBlock );
980 if (!Irp) return NULL;
981
982 /* Set the Event which makes it Syncronous */
983 Irp->UserEvent = Event;
984
985 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
986 IoQueueThreadIrp(Irp);
987 return Irp;
988 }
989
990 /*
991 * @implemented
992 */
993 BOOLEAN
994 NTAPI
995 IoCancelIrp(IN PIRP Irp)
996 {
997 KIRQL OldIrql;
998 KIRQL IrqlAtEntry;
999 PDRIVER_CANCEL CancelRoutine;
1000 IOTRACE(IO_IRP_DEBUG,
1001 "%s - Canceling IRP %p\n",
1002 __FUNCTION__,
1003 Irp);
1004 ASSERT(Irp->Type == IO_TYPE_IRP);
1005 IrqlAtEntry = KeGetCurrentIrql();
1006
1007 /* Acquire the cancel lock and cancel the IRP */
1008 IoAcquireCancelSpinLock(&OldIrql);
1009 Irp->Cancel = TRUE;
1010
1011 /* Clear the cancel routine and get the old one */
1012 CancelRoutine = (PVOID)IoSetCancelRoutine(Irp, NULL);
1013 if (CancelRoutine)
1014 {
1015 /* We had a routine, make sure the IRP isn't completed */
1016 if (Irp->CurrentLocation > (Irp->StackCount + 1))
1017 {
1018 /* It is, bugcheck */
1019 KeBugCheckEx(CANCEL_STATE_IN_COMPLETED_IRP,
1020 (ULONG_PTR)Irp,
1021 0,
1022 0,
1023 0);
1024 }
1025
1026 /* Set the cancel IRQL And call the routine */
1027 Irp->CancelIrql = OldIrql;
1028 CancelRoutine(IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Irp);
1029 ASSERT(IrqlAtEntry == KeGetCurrentIrql());
1030 return TRUE;
1031 }
1032
1033 /* Otherwise, release the cancel lock and fail */
1034 IoReleaseCancelSpinLock(OldIrql);
1035 return FALSE;
1036 }
1037
1038 /*
1039 * @implemented
1040 */
1041 VOID
1042 NTAPI
1043 IoCancelThreadIo(IN PETHREAD Thread)
1044 {
1045 KIRQL OldIrql;
1046 ULONG Retries = 3000;
1047 LARGE_INTEGER Interval;
1048 PLIST_ENTRY ListHead, NextEntry;
1049 PIRP Irp;
1050 IOTRACE(IO_IRP_DEBUG,
1051 "%s - Canceling IRPs for Thread %p\n",
1052 __FUNCTION__,
1053 Thread);
1054
1055 /* Raise to APC to protect the IrpList */
1056 KeRaiseIrql(APC_LEVEL, &OldIrql);
1057
1058 /* Start by cancelling all the IRPs in the current thread queue. */
1059 ListHead = &Thread->IrpList;
1060 NextEntry = ListHead->Flink;
1061 while (ListHead != NextEntry)
1062 {
1063 /* Get the IRP */
1064 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
1065
1066 /* Cancel it */
1067 IoCancelIrp(Irp);
1068
1069 /* Move to the next entry */
1070 NextEntry = NextEntry->Flink;
1071 }
1072
1073 /* Wait 100 milliseconds */
1074 Interval.QuadPart = -1000000;
1075
1076 /* Wait till all the IRPs are completed or cancelled. */
1077 while (!IsListEmpty(&Thread->IrpList))
1078 {
1079 /* Now we can lower */
1080 KeLowerIrql(OldIrql);
1081
1082 /* Wait a short while and then look if all our IRPs were completed. */
1083 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1084
1085 /*
1086 * Don't stay here forever if some broken driver doesn't complete
1087 * the IRP.
1088 */
1089 if (!(Retries--))
1090 {
1091 /* Print out a message and remove the IRP */
1092 DPRINT1("Broken driver did not complete!\n");
1093 IopRemoveThreadIrp();
1094 }
1095
1096 /* Raise the IRQL Again */
1097 KeRaiseIrql(APC_LEVEL, &OldIrql);
1098 }
1099
1100 /* We're done, lower the IRQL */
1101 KeLowerIrql(OldIrql);
1102 }
1103
1104 /*
1105 * @implemented
1106 */
1107 NTSTATUS
1108 NTAPI
1109 IoCallDriver(IN PDEVICE_OBJECT DeviceObject,
1110 IN PIRP Irp)
1111 {
1112 /* Call fastcall */
1113 return IofCallDriver(DeviceObject, Irp);
1114 }
1115
1116 /*
1117 * @implemented
1118 */
1119 VOID
1120 NTAPI
1121 IoCompleteRequest(IN PIRP Irp,
1122 IN CCHAR PriorityBoost)
1123 {
1124 /* Call the fastcall */
1125 IofCompleteRequest(Irp, PriorityBoost);
1126 }
1127
1128 /*
1129 * @implemented
1130 */
1131 VOID
1132 NTAPI
1133 IoEnqueueIrp(IN PIRP Irp)
1134 {
1135 /* This is the same as calling IoQueueThreadIrp */
1136 IoQueueThreadIrp(Irp);
1137 }
1138
1139 /*
1140 * @implemented
1141 */
1142 NTSTATUS
1143 FASTCALL
1144 IofCallDriver(IN PDEVICE_OBJECT DeviceObject,
1145 IN PIRP Irp)
1146 {
1147 PDRIVER_OBJECT DriverObject;
1148 PIO_STACK_LOCATION StackPtr;
1149
1150 /* Make sure this is a valid IRP */
1151 ASSERT(Irp->Type == IO_TYPE_IRP);
1152
1153 /* Get the Driver Object */
1154 DriverObject = DeviceObject->DriverObject;
1155
1156 /* Decrease the current location and check if */
1157 Irp->CurrentLocation--;
1158 if (Irp->CurrentLocation <= 0)
1159 {
1160 /* This IRP ran out of stack, bugcheck */
1161 KeBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR)Irp, 0, 0, 0);
1162 }
1163
1164 /* Now update the stack location */
1165 StackPtr = IoGetNextIrpStackLocation(Irp);
1166 Irp->Tail.Overlay.CurrentStackLocation = StackPtr;
1167
1168 /* Get the Device Object */
1169 StackPtr->DeviceObject = DeviceObject;
1170
1171 /* Call it */
1172 return DriverObject->MajorFunction[StackPtr->MajorFunction](DeviceObject,
1173 Irp);
1174 }
1175
1176 FORCEINLINE
1177 VOID
1178 IopClearStackLocation(IN PIO_STACK_LOCATION IoStackLocation)
1179 {
1180 IoStackLocation->MinorFunction = 0;
1181 IoStackLocation->Flags = 0;
1182 IoStackLocation->Control &= SL_ERROR_RETURNED;
1183 IoStackLocation->Parameters.Others.Argument1 = 0;
1184 IoStackLocation->Parameters.Others.Argument2 = 0;
1185 IoStackLocation->Parameters.Others.Argument3 = 0;
1186 IoStackLocation->FileObject = NULL;
1187 }
1188
1189 /*
1190 * @implemented
1191 */
1192 VOID
1193 FASTCALL
1194 IofCompleteRequest(IN PIRP Irp,
1195 IN CCHAR PriorityBoost)
1196 {
1197 PIO_STACK_LOCATION StackPtr, LastStackPtr;
1198 PDEVICE_OBJECT DeviceObject;
1199 PFILE_OBJECT FileObject;
1200 PETHREAD Thread;
1201 NTSTATUS Status;
1202 PMDL Mdl, NextMdl;
1203 ULONG MasterCount;
1204 PIRP MasterIrp;
1205 ULONG Flags;
1206 NTSTATUS ErrorCode = STATUS_SUCCESS;
1207 IOTRACE(IO_IRP_DEBUG,
1208 "%s - Completing IRP %p\n",
1209 __FUNCTION__,
1210 Irp);
1211
1212 /* Make sure this IRP isn't getting completed twice or is invalid */
1213 if ((Irp->CurrentLocation) > (Irp->StackCount + 1))
1214 {
1215 /* Bugcheck */
1216 KeBugCheckEx(MULTIPLE_IRP_COMPLETE_REQUESTS, (ULONG_PTR)Irp, 0, 0, 0);
1217 }
1218
1219 /* Some sanity checks */
1220 ASSERT(Irp->Type == IO_TYPE_IRP);
1221 ASSERT(!Irp->CancelRoutine);
1222 ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
1223 ASSERT(Irp->IoStatus.Status != (NTSTATUS)0xFFFFFFFF);
1224
1225 /* Get the last stack */
1226 LastStackPtr = (PIO_STACK_LOCATION)(Irp + 1);
1227 if (LastStackPtr->Control & SL_ERROR_RETURNED)
1228 {
1229 /* Get the error code */
1230 ErrorCode = PtrToUlong(LastStackPtr->Parameters.Others.Argument4);
1231 }
1232
1233 /* Get the Current Stack */
1234 StackPtr = IoGetCurrentIrpStackLocation(Irp);
1235
1236 /* Loop the Stacks and complete the IRPs */
1237 do
1238 {
1239 /* Skip current stack location */
1240 IoSkipCurrentIrpStackLocation(Irp);
1241
1242 /* Set Pending Returned */
1243 Irp->PendingReturned = StackPtr->Control & SL_PENDING_RETURNED;
1244
1245 /* Check if we failed */
1246 if (!NT_SUCCESS(Irp->IoStatus.Status))
1247 {
1248 /* Check if it was changed by a completion routine */
1249 if (Irp->IoStatus.Status != ErrorCode)
1250 {
1251 /* Update the error for the current stack */
1252 ErrorCode = Irp->IoStatus.Status;
1253 StackPtr->Control |= SL_ERROR_RETURNED;
1254 LastStackPtr->Parameters.Others.Argument4 = UlongToPtr(ErrorCode);
1255 LastStackPtr->Control |= SL_ERROR_RETURNED;
1256 }
1257 }
1258
1259 /* Check if there is a Completion Routine to Call */
1260 if ((NT_SUCCESS(Irp->IoStatus.Status) &&
1261 (StackPtr->Control & SL_INVOKE_ON_SUCCESS)) ||
1262 (!NT_SUCCESS(Irp->IoStatus.Status) &&
1263 (StackPtr->Control & SL_INVOKE_ON_ERROR)) ||
1264 (Irp->Cancel &&
1265 (StackPtr->Control & SL_INVOKE_ON_CANCEL)))
1266 {
1267 /* Clear the stack location */
1268 IopClearStackLocation(StackPtr);
1269
1270 /* Check for highest-level device completion routines */
1271 if (Irp->CurrentLocation == (Irp->StackCount + 1))
1272 {
1273 /* Clear the DO, since the current stack location is invalid */
1274 DeviceObject = NULL;
1275 }
1276 else
1277 {
1278 /* Otherwise, return the real one */
1279 DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
1280 }
1281
1282 /* Call the completion routine */
1283 Status = StackPtr->CompletionRoutine(DeviceObject,
1284 Irp,
1285 StackPtr->Context);
1286
1287 /* Don't touch the Packet in this case, since it might be gone! */
1288 if (Status == STATUS_MORE_PROCESSING_REQUIRED) return;
1289 }
1290 else
1291 {
1292 /* Otherwise, check if this is a completed IRP */
1293 if ((Irp->CurrentLocation <= Irp->StackCount) &&
1294 (Irp->PendingReturned))
1295 {
1296 /* Mark it as pending */
1297 IoMarkIrpPending(Irp);
1298 }
1299
1300 /* Clear the stack location */
1301 IopClearStackLocation(StackPtr);
1302 }
1303
1304 /* Move pointer to next stack location */
1305 StackPtr++;
1306 } while (Irp->CurrentLocation <= Irp->StackCount);
1307
1308 /* Check if the IRP is an associated IRP */
1309 if (Irp->Flags & IRP_ASSOCIATED_IRP)
1310 {
1311 /* Get the master IRP and count */
1312 MasterIrp = Irp->AssociatedIrp.MasterIrp;
1313 MasterCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount);
1314
1315 /* Free the MDLs */
1316 for (Mdl = Irp->MdlAddress; Mdl; Mdl = NextMdl)
1317 {
1318 /* Go to the next one */
1319 NextMdl = Mdl->Next;
1320 IoFreeMdl(Mdl);
1321 }
1322
1323 /* Free the IRP itself */
1324 IoFreeIrp(Irp);
1325
1326 /* Complete the Master IRP */
1327 if (!MasterCount) IofCompleteRequest(MasterIrp, PriorityBoost);
1328 return;
1329 }
1330
1331 /* We don't support this yet */
1332 ASSERT(Irp->IoStatus.Status != STATUS_REPARSE);
1333
1334 /* Check if we have an auxiliary buffer */
1335 if (Irp->Tail.Overlay.AuxiliaryBuffer)
1336 {
1337 /* Free it */
1338 ExFreePool(Irp->Tail.Overlay.AuxiliaryBuffer);
1339 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
1340 }
1341
1342 /* Check if this is a Paging I/O or Close Operation */
1343 if (Irp->Flags & (IRP_PAGING_IO | IRP_CLOSE_OPERATION))
1344 {
1345 /* Handle a Close Operation or Sync Paging I/O */
1346 if (Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_CLOSE_OPERATION))
1347 {
1348 /* Set the I/O Status and Signal the Event */
1349 Flags = Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_PAGING_IO);
1350 *Irp->UserIosb = Irp->IoStatus;
1351 KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE);
1352
1353 /* Free the IRP for a Paging I/O Only, Close is handled by us */
1354 if (Flags) IoFreeIrp(Irp);
1355 }
1356 else
1357 {
1358 #if 0
1359 /* Page 166 */
1360 KeInitializeApc(&Irp->Tail.Apc
1361 &Irp->Tail.Overlay.Thread->Tcb,
1362 Irp->ApcEnvironment,
1363 IopCompletePageWrite,
1364 NULL,
1365 NULL,
1366 KernelMode,
1367 NULL);
1368 KeInsertQueueApc(&Irp->Tail.Apc,
1369 NULL,
1370 NULL,
1371 PriorityBoost);
1372 #else
1373 /* Not implemented yet. */
1374 DPRINT1("Not supported!\n");
1375 while (TRUE);
1376 #endif
1377 }
1378
1379 /* Get out of here */
1380 return;
1381 }
1382
1383 /* Unlock MDL Pages, page 167. */
1384 Mdl = Irp->MdlAddress;
1385 while (Mdl)
1386 {
1387 MmUnlockPages(Mdl);
1388 Mdl = Mdl->Next;
1389 }
1390
1391 /* Check if we should exit because of a Deferred I/O (page 168) */
1392 if ((Irp->Flags & IRP_DEFER_IO_COMPLETION) && !(Irp->PendingReturned))
1393 {
1394 /*
1395 * Return without queuing the completion APC, since the caller will
1396 * take care of doing its own optimized completion at PASSIVE_LEVEL.
1397 */
1398 return;
1399 }
1400
1401 /* Get the thread and file object */
1402 Thread = Irp->Tail.Overlay.Thread;
1403 FileObject = Irp->Tail.Overlay.OriginalFileObject;
1404
1405 /* Make sure the IRP isn't canceled */
1406 if (!Irp->Cancel)
1407 {
1408 /* Initialize the APC */
1409 KeInitializeApc(&Irp->Tail.Apc,
1410 &Thread->Tcb,
1411 Irp->ApcEnvironment,
1412 IopCompleteRequest,
1413 NULL,
1414 NULL,
1415 KernelMode,
1416 NULL);
1417
1418 /* Queue it */
1419 KeInsertQueueApc(&Irp->Tail.Apc,
1420 FileObject,
1421 NULL, /* This is used for REPARSE stuff */
1422 PriorityBoost);
1423 }
1424 else
1425 {
1426 /* The IRP just got canceled... does a thread still own it? */
1427 Thread = Irp->Tail.Overlay.Thread;
1428 if (Thread)
1429 {
1430 /* Yes! There is still hope! Initialize the APC */
1431 KeInitializeApc(&Irp->Tail.Apc,
1432 &Thread->Tcb,
1433 Irp->ApcEnvironment,
1434 IopCompleteRequest,
1435 NULL,
1436 NULL,
1437 KernelMode,
1438 NULL);
1439
1440 /* Queue it */
1441 KeInsertQueueApc(&Irp->Tail.Apc,
1442 FileObject,
1443 NULL, /* This is used for REPARSE stuff */
1444 PriorityBoost);
1445 }
1446 else
1447 {
1448 /* Nothing left for us to do, kill it */
1449 ASSERT(Irp->Cancel);
1450 IopCleanupIrp(Irp, FileObject);
1451 }
1452 }
1453 }
1454
1455 NTSTATUS
1456 NTAPI
1457 IopSynchronousCompletion(IN PDEVICE_OBJECT DeviceObject,
1458 IN PIRP Irp,
1459 IN PVOID Context)
1460 {
1461 if (Irp->PendingReturned)
1462 KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
1463 return STATUS_MORE_PROCESSING_REQUIRED;
1464 }
1465
1466 /*
1467 * @implemented
1468 */
1469 BOOLEAN
1470 NTAPI
1471 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject,
1472 IN PIRP Irp)
1473 {
1474 KEVENT Event;
1475 NTSTATUS Status;
1476
1477 /* Check if next stack location is available */
1478 if (Irp->CurrentLocation < Irp->StackCount)
1479 {
1480 /* No more stack location */
1481 return FALSE;
1482 }
1483
1484 /* Initialize event */
1485 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1486
1487 /* Copy stack location for next driver */
1488 IoCopyCurrentIrpStackLocationToNext(Irp);
1489
1490 /* Set a completion routine, which will signal the event */
1491 IoSetCompletionRoutine(Irp, IopSynchronousCompletion, &Event, TRUE, TRUE, TRUE);
1492
1493 /* Call next driver */
1494 Status = IoCallDriver(DeviceObject, Irp);
1495
1496 /* Check if irp is pending */
1497 if (Status == STATUS_PENDING)
1498 {
1499 /* Yes, wait for its completion */
1500 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
1501 }
1502
1503 /* Return success */
1504 return TRUE;
1505 }
1506
1507 /*
1508 * @implemented
1509 */
1510 VOID
1511 NTAPI
1512 IoFreeIrp(IN PIRP Irp)
1513 {
1514 PNPAGED_LOOKASIDE_LIST List;
1515 PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList;
1516 PKPRCB Prcb;
1517 IOTRACE(IO_IRP_DEBUG,
1518 "%s - Freeing IRPs %p\n",
1519 __FUNCTION__,
1520 Irp);
1521
1522 /* Make sure the Thread IRP list is empty and that it OK to free it */
1523 ASSERT(Irp->Type == IO_TYPE_IRP);
1524 ASSERT(IsListEmpty(&Irp->ThreadListEntry));
1525 ASSERT(Irp->CurrentLocation >= Irp->StackCount);
1526
1527 /* If this was a pool alloc, free it with the pool */
1528 if (!(Irp->AllocationFlags & IRP_ALLOCATED_FIXED_SIZE))
1529 {
1530 /* Free it */
1531 ExFreePoolWithTag(Irp, TAG_IRP);
1532 }
1533 else
1534 {
1535 /* Check if this was a Big IRP */
1536 if (Irp->StackCount != 1) ListType = LookasideLargeIrpList;
1537
1538 /* Get the PRCB */
1539 Prcb = KeGetCurrentPrcb();
1540
1541 /* Use the P List */
1542 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;
1543 List->L.TotalFrees++;
1544
1545 /* Check if the Free was within the Depth or not */
1546 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
1547 {
1548 /* Let the balancer know */
1549 List->L.FreeMisses++;
1550
1551 /* Use the L List */
1552 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;
1553 List->L.TotalFrees++;
1554
1555 /* Check if the Free was within the Depth or not */
1556 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
1557 {
1558 /* All lists failed, use the pool */
1559 List->L.FreeMisses++;
1560 ExFreePoolWithTag(Irp, TAG_IRP);
1561 Irp = NULL;
1562 }
1563 }
1564
1565 /* The free was within the Depth */
1566 if (Irp)
1567 {
1568 InterlockedPushEntrySList(&List->L.ListHead,
1569 (PSINGLE_LIST_ENTRY)Irp);
1570 }
1571 }
1572 }
1573
1574 /*
1575 * @implemented
1576 */
1577 IO_PAGING_PRIORITY
1578 FASTCALL
1579 IoGetPagingIoPriority(IN PIRP Irp)
1580 {
1581 IO_PAGING_PRIORITY Priority;
1582 ULONG Flags;
1583
1584 /* Get the flags */
1585 Flags = Irp->Flags;
1586
1587 /* Check what priority it has */
1588 if (Flags & 0x8000) // FIXME: Undocumented flag
1589 {
1590 /* High priority */
1591 Priority = IoPagingPriorityHigh;
1592 }
1593 else if (Flags & IRP_PAGING_IO)
1594 {
1595 /* Normal priority */
1596 Priority = IoPagingPriorityNormal;
1597 }
1598 else
1599 {
1600 /* Invalid -- not a paging IRP */
1601 Priority = IoPagingPriorityInvalid;
1602 }
1603
1604 /* Return the priority */
1605 return Priority;
1606 }
1607
1608 /*
1609 * @implemented
1610 */
1611 PEPROCESS
1612 NTAPI
1613 IoGetRequestorProcess(IN PIRP Irp)
1614 {
1615 /* Return the requestor process */
1616 return Irp->Tail.Overlay.Thread->ThreadsProcess;
1617 }
1618
1619 /*
1620 * @implemented
1621 */
1622 ULONG
1623 NTAPI
1624 IoGetRequestorProcessId(IN PIRP Irp)
1625 {
1626 /* Return the requestor process' id */
1627 return PtrToUlong(IoGetRequestorProcess(Irp)->UniqueProcessId);
1628 }
1629
1630 /*
1631 * @implemented
1632 */
1633 NTSTATUS
1634 NTAPI
1635 IoGetRequestorSessionId(IN PIRP Irp,
1636 OUT PULONG pSessionId)
1637 {
1638 /* Return the session */
1639 *pSessionId = IoGetRequestorProcess(Irp)->Session;
1640 return STATUS_SUCCESS;
1641 }
1642
1643 /*
1644 * @implemented
1645 */
1646 PIRP
1647 NTAPI
1648 IoGetTopLevelIrp(VOID)
1649 {
1650 /* Return the IRP */
1651 return (PIRP)PsGetCurrentThread()->TopLevelIrp;
1652 }
1653
1654 /*
1655 * @implemented
1656 */
1657 VOID
1658 NTAPI
1659 IoInitializeIrp(IN PIRP Irp,
1660 IN USHORT PacketSize,
1661 IN CCHAR StackSize)
1662 {
1663 /* Clear it */
1664 IOTRACE(IO_IRP_DEBUG,
1665 "%s - Initializing IRP %p\n",
1666 __FUNCTION__,
1667 Irp);
1668 RtlZeroMemory(Irp, PacketSize);
1669
1670 /* Set the Header and other data */
1671 Irp->Type = IO_TYPE_IRP;
1672 Irp->Size = PacketSize;
1673 Irp->StackCount = StackSize;
1674 Irp->CurrentLocation = StackSize + 1;
1675 Irp->ApcEnvironment = KeGetCurrentThread()->ApcStateIndex;
1676 Irp->Tail.Overlay.CurrentStackLocation = (PIO_STACK_LOCATION)(Irp + 1) + StackSize;
1677
1678 /* Initialize the Thread List */
1679 InitializeListHead(&Irp->ThreadListEntry);
1680 }
1681
1682 /*
1683 * @implemented
1684 */
1685 BOOLEAN
1686 NTAPI
1687 IoIsOperationSynchronous(IN PIRP Irp)
1688 {
1689 /* Check the flags */
1690 if (!(Irp->Flags & (IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO)) &&
1691 ((Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ||
1692 (Irp->Flags & IRP_SYNCHRONOUS_API) ||
1693 (IoGetCurrentIrpStackLocation(Irp)->FileObject->Flags &
1694 FO_SYNCHRONOUS_IO)))
1695 {
1696 /* Synch API or Paging I/O is OK, as is Sync File I/O */
1697 return TRUE;
1698 }
1699
1700 /* Otherwise, it is an asynchronous operation. */
1701 return FALSE;
1702 }
1703
1704 /*
1705 * @unimplemented
1706 */
1707 BOOLEAN
1708 NTAPI
1709 IoIsValidNameGraftingBuffer(IN PIRP Irp,
1710 IN PREPARSE_DATA_BUFFER ReparseBuffer)
1711 {
1712 UNIMPLEMENTED;
1713 return FALSE;
1714 }
1715
1716 /*
1717 * @implemented
1718 */
1719 PIRP
1720 NTAPI
1721 IoMakeAssociatedIrp(IN PIRP Irp,
1722 IN CCHAR StackSize)
1723 {
1724 PIRP AssocIrp;
1725 IOTRACE(IO_IRP_DEBUG,
1726 "%s - Associating IRP %p\n",
1727 __FUNCTION__,
1728 Irp);
1729
1730 /* Allocate the IRP */
1731 AssocIrp = IoAllocateIrp(StackSize, FALSE);
1732 if (!AssocIrp) return NULL;
1733
1734 /* Set the Flags */
1735 AssocIrp->Flags |= IRP_ASSOCIATED_IRP;
1736
1737 /* Set the Thread */
1738 AssocIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
1739
1740 /* Associate them */
1741 AssocIrp->AssociatedIrp.MasterIrp = Irp;
1742 return AssocIrp;
1743 }
1744
1745 /*
1746 * @implemented
1747 */
1748 VOID
1749 NTAPI
1750 IoQueueThreadIrp(IN PIRP Irp)
1751 {
1752 IOTRACE(IO_IRP_DEBUG,
1753 "%s - Queueing IRP %p\n",
1754 __FUNCTION__,
1755 Irp);
1756
1757 /* Use our inlined routine */
1758 IopQueueIrpToThread(Irp);
1759 }
1760
1761 /*
1762 * @implemented
1763 * Reference: Chris Cant's "Writing WDM Device Drivers"
1764 */
1765 VOID
1766 NTAPI
1767 IoReuseIrp(IN OUT PIRP Irp,
1768 IN NTSTATUS Status)
1769 {
1770 UCHAR AllocationFlags;
1771 IOTRACE(IO_IRP_DEBUG,
1772 "%s - Reusing IRP %p\n",
1773 __FUNCTION__,
1774 Irp);
1775
1776 /* Make sure it's OK to reuse it */
1777 ASSERT(!Irp->CancelRoutine);
1778 ASSERT(IsListEmpty(&Irp->ThreadListEntry));
1779
1780 /* Get the old flags */
1781 AllocationFlags = Irp->AllocationFlags;
1782
1783 /* Reinitialize the IRP */
1784 IoInitializeIrp(Irp, Irp->Size, Irp->StackCount);
1785
1786 /* Duplicate the data */
1787 Irp->IoStatus.Status = Status;
1788 Irp->AllocationFlags = AllocationFlags;
1789 }
1790
1791 /*
1792 * @implemented
1793 */
1794 VOID
1795 NTAPI
1796 IoSetTopLevelIrp(IN PIRP Irp)
1797 {
1798 /* Set the IRP */
1799 PsGetCurrentThread()->TopLevelIrp = (ULONG_PTR)Irp;
1800 }