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