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