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