Sync to trunk head (35333)
[reactos.git] / reactos / ntoskrnl / io / iomgr / irp.c
1
2 /*
3 * PROJECT: ReactOS Kernel
4 * LICENSE: GPL - See COPYING in the top level directory
5 * FILE: ntoskrnl/io/irp.c
6 * PURPOSE: IRP Handling Functions
7 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
8 * Gunnar Dalsnes
9 * Filip Navara (navaraf@reactos.org)
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* Undefine some macros we implement here */
19 #undef IoCallDriver
20 #undef IoCompleteRequest
21
22 /* PRIVATE FUNCTIONS ********************************************************/
23
24 VOID
25 NTAPI
26 IopFreeIrpKernelApc(IN PKAPC Apc,
27 IN PKNORMAL_ROUTINE *NormalRoutine,
28 IN PVOID *NormalContext,
29 IN PVOID *SystemArgument1,
30 IN PVOID *SystemArgument2)
31 {
32 /* Free the IRP */
33 IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc));
34 }
35
36 VOID
37 NTAPI
38 IopAbortIrpKernelApc(IN PKAPC Apc)
39 {
40 /* Free the IRP */
41 IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc));
42 }
43
44 NTSTATUS
45 NTAPI
46 IopCleanupFailedIrp(IN PFILE_OBJECT FileObject,
47 IN PKEVENT EventObject OPTIONAL,
48 IN PVOID Buffer OPTIONAL)
49 {
50 PAGED_CODE();
51
52 /* Dereference the event */
53 if (EventObject) ObDereferenceObject(EventObject);
54
55 /* Free a buffer, if any */
56 if (Buffer) ExFreePool(Buffer);
57
58 /* If this was a file opened for synch I/O, then unlock it */
59 if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopUnlockFileObject(FileObject);
60
61 /* Now dereference it and return */
62 ObDereferenceObject(FileObject);
63 return STATUS_INSUFFICIENT_RESOURCES;
64 }
65
66 VOID
67 NTAPI
68 IopAbortInterruptedIrp(IN PKEVENT EventObject,
69 IN PIRP Irp)
70 {
71 KIRQL OldIrql;
72 BOOLEAN CancelResult;
73 LARGE_INTEGER Wait;
74 PAGED_CODE();
75
76 /* Raise IRQL to APC */
77 KeRaiseIrql(APC_LEVEL, &OldIrql);
78
79 /* Check if nobody completed it yet */
80 if (!KeReadStateEvent(EventObject))
81 {
82 /* First, cancel it */
83 CancelResult = IoCancelIrp(Irp);
84 KeLowerIrql(OldIrql);
85
86 /* Check if we cancelled it */
87 if (CancelResult)
88 {
89 /* Wait for the IRP to be cancelled */
90 Wait.QuadPart = -100000;
91 while (!KeReadStateEvent(EventObject))
92 {
93 /* Delay indefintely */
94 KeDelayExecutionThread(KernelMode, FALSE, &Wait);
95 }
96 }
97 else
98 {
99 /* No cancellation done, so wait for the I/O system to kill it */
100 KeWaitForSingleObject(EventObject,
101 Executive,
102 KernelMode,
103 FALSE,
104 NULL);
105 }
106 }
107 else
108 {
109 /* We got preempted, so give up */
110 KeLowerIrql(OldIrql);
111 }
112 }
113
114 VOID
115 NTAPI
116 IopRemoveThreadIrp(VOID)
117 {
118 KIRQL OldIrql;
119 PIRP DeadIrp;
120 PETHREAD IrpThread;
121 PLIST_ENTRY IrpEntry;
122 PIO_ERROR_LOG_PACKET ErrorLogEntry;
123 PDEVICE_OBJECT DeviceObject = NULL;
124 PIO_STACK_LOCATION IoStackLocation;
125
126 /* First, raise to APC to protect IrpList */
127 KeRaiseIrql(APC_LEVEL, &OldIrql);
128
129 /* Get the Thread and check the list */
130 IrpThread = PsGetCurrentThread();
131 if (IsListEmpty(&IrpThread->IrpList))
132 {
133 /* It got completed now, so quit */
134 KeLowerIrql(OldIrql);
135 return;
136 }
137
138 /* Get the misbehaving IRP */
139 IrpEntry = IrpThread->IrpList.Flink;
140 DeadIrp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry);
141 IOTRACE(IO_IRP_DEBUG,
142 "%s - Deassociating IRP %p for %p\n",
143 __FUNCTION__,
144 DeadIrp,
145 IrpThread);
146
147 /* Don't cancel the IRP if it's already been completed far */
148 if (DeadIrp->CurrentLocation == (DeadIrp->StackCount + 2))
149 {
150 /* Return */
151 KeLowerIrql(OldIrql);
152 return;
153 }
154
155 /* Disown the IRP! */
156 DeadIrp->Tail.Overlay.Thread = NULL;
157 RemoveHeadList(&IrpThread->IrpList);
158 InitializeListHead(&DeadIrp->ThreadListEntry);
159
160 /* Get the stack location and check if it's valid */
161 IoStackLocation = IoGetCurrentIrpStackLocation(DeadIrp);
162 if (DeadIrp->CurrentLocation <= DeadIrp->StackCount)
163 {
164 /* Get the device object */
165 DeviceObject = IoStackLocation->DeviceObject;
166 }
167
168 /* Lower IRQL now, since we have the pointers we need */
169 KeLowerIrql(OldIrql);
170
171 /* Check if we can send an Error Log Entry*/
172 if (DeviceObject)
173 {
174 /* Allocate an entry */
175 ErrorLogEntry = IoAllocateErrorLogEntry(DeviceObject,
176 sizeof(IO_ERROR_LOG_PACKET));
177 if (ErrorLogEntry)
178 {
179 /* Write the entry */
180 ErrorLogEntry->ErrorCode = 0xBAADF00D; /* FIXME */
181 IoWriteErrorLogEntry(ErrorLogEntry);
182 }
183 }
184 }
185
186 VOID
187 NTAPI
188 IopCleanupIrp(IN PIRP Irp,
189 IN PFILE_OBJECT FileObject)
190 {
191 PMDL Mdl;
192 IOTRACE(IO_IRP_DEBUG,
193 "%s - Cleaning IRP %p for %p\n",
194 __FUNCTION__,
195 Irp,
196 FileObject);
197
198 /* Check if there's an MDL */
199 while ((Mdl = Irp->MdlAddress))
200 {
201 /* Clear all of them */
202 Irp->MdlAddress = Mdl->Next;
203 IoFreeMdl(Mdl);
204 }
205
206 /* Check if the IRP has system buffer */
207 if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
208 {
209 /* Free the buffer */
210 ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF);
211 }
212
213 /* Check if this IRP has a user event, a file object, and is async */
214 if ((Irp->UserEvent) &&
215 !(Irp->Flags & IRP_SYNCHRONOUS_API) &&
216 (FileObject))
217 {
218 /* Dereference the User Event */
219 ObDereferenceObject(Irp->UserEvent);
220 }
221
222 /* Check if we have a file object and this isn't a create operation */
223 if ((FileObject) && !(Irp->Flags & IRP_CREATE_OPERATION))
224 {
225 /* Dereference the file object */
226 ObDereferenceObject(FileObject);
227 }
228
229 /* Free the IRP */
230 IoFreeIrp(Irp);
231 }
232
233 VOID
234 NTAPI
235 IopCompleteRequest(IN PKAPC Apc,
236 IN PKNORMAL_ROUTINE* NormalRoutine,
237 IN PVOID* NormalContext,
238 IN PVOID* SystemArgument1,
239 IN PVOID* SystemArgument2)
240 {
241 PFILE_OBJECT FileObject;
242 PIRP Irp;
243 PMDL Mdl, NextMdl;
244 PVOID Port = NULL, Key = NULL;
245 BOOLEAN SignaledCreateRequest = FALSE;
246
247 /* Get data from the APC */
248 FileObject = (PFILE_OBJECT)*SystemArgument1;
249 Irp = CONTAINING_RECORD(Apc, IRP, Tail.Apc);
250 IOTRACE(IO_IRP_DEBUG,
251 "%s - Completing IRP %p for %p\n",
252 __FUNCTION__,
253 Irp,
254 FileObject);
255
256 /* Sanity check */
257 ASSERT(Irp->IoStatus.Status != 0xFFFFFFFF);
258
259 /* Check if we have a file object */
260 if (*SystemArgument2)
261 {
262 /* Check if we're reparsing */
263 if ((Irp->IoStatus.Status == STATUS_REPARSE) &&
264 (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT))
265 {
266 /* We should never get this yet */
267 DPRINT1("Reparse support not yet present!\n");
268 while (TRUE);
269 }
270 }
271
272 /* Handle Buffered case first */
273 if (Irp->Flags & IRP_BUFFERED_IO)
274 {
275 /* Check if we have an input buffer and if we succeeded */
276 if ((Irp->Flags & IRP_INPUT_OPERATION) &&
277 (Irp->IoStatus.Status != STATUS_VERIFY_REQUIRED) &&
278 !(NT_ERROR(Irp->IoStatus.Status)))
279 {
280 /* Copy the buffer back to the user */
281 RtlCopyMemory(Irp->UserBuffer,
282 Irp->AssociatedIrp.SystemBuffer,
283 Irp->IoStatus.Information);
284 }
285
286 /* Also check if we should de-allocate it */
287 if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
288 {
289 /* Deallocate it */
290 ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF);
291 }
292 }
293
294 /* Now we got rid of these two... */
295 Irp->Flags &= ~(IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
296
297 /* Check if there's an MDL */
298 for (Mdl = Irp->MdlAddress; Mdl; Mdl = NextMdl)
299 {
300 /* Free it */
301 NextMdl = Mdl->Next;
302 IoFreeMdl(Mdl);
303 }
304
305 /* No MDLs left */
306 Irp->MdlAddress = NULL;
307
308 /*
309 * Check if either the request was completed without any errors
310 * (but warnings are OK!), or if it was completed with an error, but
311 * did return from a pending I/O Operation and is not synchronous.
312 */
313 if (!(NT_ERROR(Irp->IoStatus.Status)) ||
314 (NT_ERROR(Irp->IoStatus.Status) &&
315 (Irp->PendingReturned) &&
316 !(IsIrpSynchronous(Irp, FileObject))))
317 {
318 /* Get any information we need from the FO before we kill it */
319 if ((FileObject) && (FileObject->CompletionContext))
320 {
321 /* Save Completion Data */
322 Port = FileObject->CompletionContext->Port;
323 Key = FileObject->CompletionContext->Key;
324 }
325
326 /* Use SEH to make sure we don't write somewhere invalid */
327 _SEH_TRY
328 {
329 /* Save the IOSB Information */
330 *Irp->UserIosb = Irp->IoStatus;
331 }
332 _SEH_HANDLE
333 {
334 /* Ignore any error */
335 }
336 _SEH_END;
337
338 /* Check if we have an event or a file object */
339 if (Irp->UserEvent)
340 {
341 /* At the very least, this is a PKEVENT, so signal it always */
342 KeSetEvent(Irp->UserEvent, 0, FALSE);
343
344 /* Check if we also have a File Object */
345 if (FileObject)
346 {
347 /* Check if this is an Asynch API */
348 if (!(Irp->Flags & IRP_SYNCHRONOUS_API))
349 {
350 /* HACK */
351 if (*((PULONG)(Irp->UserEvent) - 1) != 0x87878787)
352 {
353 /* Dereference the event */
354 ObDereferenceObject(Irp->UserEvent);
355 }
356 else
357 {
358 DPRINT1("Not an executive event -- should not be dereferenced\n");
359 }
360 }
361
362 /*
363 * Now, if this is a Synch I/O File Object, then this event is
364 * NOT an actual Executive Event, so we won't dereference it,
365 * and instead, we will signal the File Object
366 */
367 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) &&
368 !(Irp->Flags & IRP_OB_QUERY_NAME))
369 {
370 /* Signal the file object and set the status */
371 KeSetEvent(&FileObject->Event, 0, FALSE);
372 FileObject->FinalStatus = Irp->IoStatus.Status;
373 }
374
375 /*
376 * This could also be a create operation, in which case we want
377 * to make sure there's no APC fired.
378 */
379 if (Irp->Flags & IRP_CREATE_OPERATION)
380 {
381 /* Clear the APC Routine and remember this */
382 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
383 SignaledCreateRequest = TRUE;
384 }
385 }
386 }
387 else if (FileObject)
388 {
389 /* Signal the file object and set the status */
390 KeSetEvent(&FileObject->Event, 0, FALSE);
391 FileObject->FinalStatus = Irp->IoStatus.Status;
392
393 /*
394 * This could also be a create operation, in which case we want
395 * to make sure there's no APC fired.
396 */
397 if (Irp->Flags & IRP_CREATE_OPERATION)
398 {
399 /* Clear the APC Routine and remember this */
400 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
401 SignaledCreateRequest = TRUE;
402 }
403 }
404
405 /* Now that we've signaled the events, de-associate the IRP */
406 IopUnQueueIrpFromThread(Irp);
407
408 /* Now check if a User APC Routine was requested */
409 if (Irp->Overlay.AsynchronousParameters.UserApcRoutine)
410 {
411 /* Initialize it */
412 KeInitializeApc(&Irp->Tail.Apc,
413 KeGetCurrentThread(),
414 CurrentApcEnvironment,
415 IopFreeIrpKernelApc,
416 IopAbortIrpKernelApc,
417 (PKNORMAL_ROUTINE)Irp->
418 Overlay.AsynchronousParameters.UserApcRoutine,
419 Irp->RequestorMode,
420 Irp->
421 Overlay.AsynchronousParameters.UserApcContext);
422
423 /* Queue it */
424 KeInsertQueueApc(&Irp->Tail.Apc, Irp->UserIosb, NULL, 2);
425 }
426 else if ((Port) &&
427 (Irp->Overlay.AsynchronousParameters.UserApcContext))
428 {
429 /* We have an I/O Completion setup... create the special Overlay */
430 Irp->Tail.CompletionKey = Key;
431 Irp->Tail.Overlay.PacketType = IrpCompletionPacket;
432 KeInsertQueue(Port, &Irp->Tail.Overlay.ListEntry);
433 }
434 else
435 {
436 /* Free the IRP since we don't need it anymore */
437 IoFreeIrp(Irp);
438 }
439
440 /* Check if we have a file object that wasn't part of a create */
441 if ((FileObject) && !(SignaledCreateRequest))
442 {
443 /* Dereference it, since it's not needed anymore either */
444 ObDereferenceObjectDeferDelete(FileObject);
445 }
446 }
447 else
448 {
449 /*
450 * Either we didn't return from the request, or we did return but this
451 * request was synchronous.
452 */
453 if ((Irp->PendingReturned) && (FileObject))
454 {
455 /* So we did return with a synch operation, was it the IRP? */
456 if (Irp->Flags & IRP_SYNCHRONOUS_API)
457 {
458 /* Yes, this IRP was synchronous, so return the I/O Status */
459 *Irp->UserIosb = Irp->IoStatus;
460
461 /* Now check if the user gave an event */
462 if (Irp->UserEvent)
463 {
464 /* Signal it */
465 KeSetEvent(Irp->UserEvent, 0, FALSE);
466 }
467 else
468 {
469 /* No event was given, so signal the FO instead */
470 KeSetEvent(&FileObject->Event, 0, FALSE);
471 }
472 }
473 else
474 {
475 /*
476 * It's not the IRP that was synchronous, it was the FO
477 * that was opened this way. Signal its event.
478 */
479 FileObject->FinalStatus = Irp->IoStatus.Status;
480 KeSetEvent(&FileObject->Event, 0, FALSE);
481 }
482 }
483
484 /* Now that we got here, we do this for incomplete I/Os as well */
485 if ((FileObject) && !(Irp->Flags & IRP_CREATE_OPERATION))
486 {
487 /* Dereference the File Object unless this was a create */
488 ObDereferenceObjectDeferDelete(FileObject);
489 }
490
491 /*
492 * Check if this was an Executive Event (remember that we know this
493 * by checking if the IRP is synchronous)
494 */
495 if ((Irp->UserEvent) &&
496 (FileObject) &&
497 !(Irp->Flags & IRP_SYNCHRONOUS_API))
498 {
499 /* This isn't a PKEVENT, so dereference it */
500 ObDereferenceObject(Irp->UserEvent);
501 }
502
503 /* Now that we've signaled the events, de-associate the IRP */
504 IopUnQueueIrpFromThread(Irp);
505
506 /* Free the IRP as well */
507 IoFreeIrp(Irp);
508 }
509 }
510
511 /* FUNCTIONS *****************************************************************/
512
513 /*
514 * @implemented
515 */
516 PIRP
517 NTAPI
518 IoAllocateIrp(IN CCHAR StackSize,
519 IN BOOLEAN ChargeQuota)
520 {
521 PIRP Irp = NULL;
522 USHORT Size = IoSizeOfIrp(StackSize);
523 PKPRCB Prcb;
524 UCHAR Flags = 0;
525 PNPAGED_LOOKASIDE_LIST List = NULL;
526 PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList;
527
528 /* Set Charge Quota Flag */
529 if (ChargeQuota) Flags |= IRP_QUOTA_CHARGED;
530
531 /* Figure out which Lookaside List to use */
532 if ((StackSize <= 8) && (ChargeQuota == FALSE))
533 {
534 /* Set Fixed Size Flag */
535 Flags = IRP_ALLOCATED_FIXED_SIZE;
536
537 /* See if we should use big list */
538 if (StackSize != 1)
539 {
540 Size = IoSizeOfIrp(8);
541 ListType = LookasideLargeIrpList;
542 }
543
544 /* Get the PRCB */
545 Prcb = KeGetCurrentPrcb();
546
547 /* Get the P List First */
548 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;
549
550 /* Attempt allocation */
551 List->L.TotalAllocates++;
552 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
553
554 /* Check if the P List failed */
555 if (!Irp)
556 {
557 /* Let the balancer know */
558 List->L.AllocateMisses++;
559
560 /* Try the L List */
561 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;
562 List->L.TotalAllocates++;
563 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
564 }
565 }
566
567 /* Check if we have to use the pool */
568 if (!Irp)
569 {
570 /* Did we try lookaside and fail? */
571 if (Flags & IRP_ALLOCATED_FIXED_SIZE) List->L.AllocateMisses++;
572
573 /* Check if we should charge quota */
574 if (ChargeQuota)
575 {
576 /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool, Size, TAG_IRP); */
577 /* FIXME */
578 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
579 }
580 else
581 {
582 /* Allocate the IRP With no Quota charge */
583 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
584 }
585
586 /* Make sure it was sucessful */
587 if (!Irp) return(NULL);
588 }
589 else
590 {
591 /* We have an IRP from Lookaside */
592 if (ChargeQuota) Flags |= IRP_LOOKASIDE_ALLOCATION;
593
594 /* In this case there is no charge quota */
595 Flags &= ~IRP_QUOTA_CHARGED;
596 }
597
598 /* Now Initialize it */
599 IoInitializeIrp(Irp, Size, StackSize);
600
601 /* Set the Allocation Flags */
602 Irp->AllocationFlags = Flags;
603
604 /* Return it */
605 IOTRACE(IO_IRP_DEBUG,
606 "%s - Allocated IRP %p with allocation flags %lx\n",
607 __FUNCTION__,
608 Irp,
609 Flags);
610 return Irp;
611 }
612
613 /*
614 * @implemented
615 */
616 PIRP
617 NTAPI
618 IoBuildAsynchronousFsdRequest(IN ULONG MajorFunction,
619 IN PDEVICE_OBJECT DeviceObject,
620 IN PVOID Buffer,
621 IN ULONG Length,
622 IN PLARGE_INTEGER StartingOffset,
623 IN PIO_STATUS_BLOCK IoStatusBlock)
624 {
625 PIRP Irp;
626 PIO_STACK_LOCATION StackPtr;
627
628 /* Allocate IRP */
629 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
630 if (!Irp) return Irp;
631
632 /* Get the Stack */
633 StackPtr = IoGetNextIrpStackLocation(Irp);
634
635 /* Write the Major function and then deal with it */
636 StackPtr->MajorFunction = (UCHAR)MajorFunction;
637
638 /* Do not handle the following here */
639 if ((MajorFunction != IRP_MJ_FLUSH_BUFFERS) &&
640 (MajorFunction != IRP_MJ_SHUTDOWN) &&
641 (MajorFunction != IRP_MJ_PNP) &&
642 (MajorFunction != IRP_MJ_POWER))
643 {
644 /* Check if this is Buffered IO */
645 if (DeviceObject->Flags & DO_BUFFERED_IO)
646 {
647 /* Allocate the System Buffer */
648 Irp->AssociatedIrp.SystemBuffer =
649 ExAllocatePoolWithTag(NonPagedPool, Length, TAG_SYS_BUF);
650 if (!Irp->AssociatedIrp.SystemBuffer)
651 {
652 /* Free the IRP and fail */
653 IoFreeIrp(Irp);
654 return NULL;
655 }
656
657 /* Set flags */
658 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
659
660 /* Handle special IRP_MJ_WRITE Case */
661 if (MajorFunction == IRP_MJ_WRITE)
662 {
663 /* Copy the buffer data */
664 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
665 }
666 else
667 {
668 /* Set the Input Operation flag and set this as a User Buffer */
669 Irp->Flags |= IRP_INPUT_OPERATION;
670 Irp->UserBuffer = Buffer;
671 }
672 }
673 else if (DeviceObject->Flags & DO_DIRECT_IO)
674 {
675 /* Use an MDL for Direct I/O */
676 Irp->MdlAddress = IoAllocateMdl(Buffer,
677 Length,
678 FALSE,
679 FALSE,
680 NULL);
681 if (!Irp->MdlAddress)
682 {
683 /* Free the IRP and fail */
684 IoFreeIrp(Irp);
685 return NULL;
686 }
687
688 /* Probe and Lock */
689 _SEH_TRY
690 {
691 /* Do the probe */
692 MmProbeAndLockPages(Irp->MdlAddress,
693 KernelMode,
694 MajorFunction == IRP_MJ_READ ?
695 IoWriteAccess : IoReadAccess);
696 }
697 _SEH_HANDLE
698 {
699 /* Free the IRP and its MDL */
700 IoFreeMdl(Irp->MdlAddress);
701 IoFreeIrp(Irp);
702 Irp = NULL;
703 }
704 _SEH_END;
705
706 /* This is how we know if we failed during the probe */
707 if (!Irp) return NULL;
708 }
709 else
710 {
711 /* Neither, use the buffer */
712 Irp->UserBuffer = Buffer;
713 }
714
715 /* Check if this is a read */
716 if (MajorFunction == IRP_MJ_READ)
717 {
718 /* Set the parameters for a read */
719 StackPtr->Parameters.Read.Length = Length;
720 StackPtr->Parameters.Read.ByteOffset = *StartingOffset;
721 }
722 else if (MajorFunction == IRP_MJ_WRITE)
723 {
724 /* Otherwise, set write parameters */
725 StackPtr->Parameters.Write.Length = Length;
726 StackPtr->Parameters.Write.ByteOffset = *StartingOffset;
727 }
728 }
729
730 /* Set the Current Thread and IOSB */
731 Irp->UserIosb = IoStatusBlock;
732 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
733
734 /* Set the Status Block after all is done */
735 IOTRACE(IO_IRP_DEBUG,
736 "%s - Built IRP %p with Major, Buffer, DO %lx %p %p\n",
737 __FUNCTION__,
738 Irp,
739 MajorFunction,
740 Buffer,
741 DeviceObject);
742 return Irp;
743 }
744
745 /*
746 * @implemented
747 */
748 PIRP
749 NTAPI
750 IoBuildDeviceIoControlRequest(IN ULONG IoControlCode,
751 IN PDEVICE_OBJECT DeviceObject,
752 IN PVOID InputBuffer,
753 IN ULONG InputBufferLength,
754 IN PVOID OutputBuffer,
755 IN ULONG OutputBufferLength,
756 IN BOOLEAN InternalDeviceIoControl,
757 IN PKEVENT Event,
758 IN PIO_STATUS_BLOCK IoStatusBlock)
759 {
760 PIRP Irp;
761 PIO_STACK_LOCATION StackPtr;
762 ULONG BufferLength;
763
764 /* Allocate IRP */
765 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
766 if (!Irp) return Irp;
767
768 /* Get the Stack */
769 StackPtr = IoGetNextIrpStackLocation(Irp);
770
771 /* Set the DevCtl Type */
772 StackPtr->MajorFunction = InternalDeviceIoControl ?
773 IRP_MJ_INTERNAL_DEVICE_CONTROL :
774 IRP_MJ_DEVICE_CONTROL;
775
776 /* Set the IOCTL Data */
777 StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
778 StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
779 StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
780 OutputBufferLength;
781
782 /* Handle the Methods */
783 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
784 {
785 /* Buffered I/O */
786 case METHOD_BUFFERED:
787
788 /* Select the right Buffer Length */
789 BufferLength = InputBufferLength > OutputBufferLength ?
790 InputBufferLength : OutputBufferLength;
791
792 /* Make sure there is one */
793 if (BufferLength)
794 {
795 /* Allocate the System Buffer */
796 Irp->AssociatedIrp.SystemBuffer =
797 ExAllocatePoolWithTag(NonPagedPool,
798 BufferLength,
799 TAG_SYS_BUF);
800 if (!Irp->AssociatedIrp.SystemBuffer)
801 {
802 /* Free the IRP and fail */
803 IoFreeIrp(Irp);
804 return NULL;
805 }
806
807 /* Check if we got a buffer */
808 if (InputBuffer)
809 {
810 /* Copy into the System Buffer */
811 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
812 InputBuffer,
813 InputBufferLength);
814 }
815
816 /* Write the flags */
817 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
818 if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
819
820 /* Save the Buffer */
821 Irp->UserBuffer = OutputBuffer;
822 }
823 else
824 {
825 /* Clear the Flags and Buffer */
826 Irp->Flags = 0;
827 Irp->UserBuffer = NULL;
828 }
829 break;
830
831 /* Direct I/O */
832 case METHOD_IN_DIRECT:
833 case METHOD_OUT_DIRECT:
834
835 /* Check if we got an input buffer */
836 if (InputBuffer)
837 {
838 /* Allocate the System Buffer */
839 Irp->AssociatedIrp.SystemBuffer =
840 ExAllocatePoolWithTag(NonPagedPool,
841 InputBufferLength,
842 TAG_SYS_BUF);
843 if (!Irp->AssociatedIrp.SystemBuffer)
844 {
845 /* Free the IRP and fail */
846 IoFreeIrp(Irp);
847 return NULL;
848 }
849
850 /* Copy into the System Buffer */
851 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
852 InputBuffer,
853 InputBufferLength);
854
855 /* Write the flags */
856 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
857 }
858 else
859 {
860 Irp->Flags = 0;
861 }
862
863 /* Check if we got an output buffer */
864 if (OutputBuffer)
865 {
866 /* Allocate the System Buffer */
867 Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
868 OutputBufferLength,
869 FALSE,
870 FALSE,
871 Irp);
872 if (!Irp->MdlAddress)
873 {
874 /* Free the IRP and fail */
875 IoFreeIrp(Irp);
876 return NULL;
877 }
878
879 /* Probe and Lock */
880 _SEH_TRY
881 {
882 /* Do the probe */
883 MmProbeAndLockPages(Irp->MdlAddress,
884 KernelMode,
885 IO_METHOD_FROM_CTL_CODE(IoControlCode) ==
886 METHOD_IN_DIRECT ?
887 IoReadAccess : IoWriteAccess);
888 }
889 _SEH_HANDLE
890 {
891 /* Free the MDL */
892 IoFreeMdl(Irp->MdlAddress);
893
894 /* Free the input buffer and IRP */
895 if (InputBuffer) ExFreePool(Irp->AssociatedIrp.SystemBuffer);
896 IoFreeIrp(Irp);
897 Irp = NULL;
898 }
899 _SEH_END;
900
901 /* This is how we know if probing failed */
902 if (!Irp) return NULL;
903 }
904 break;
905
906 case METHOD_NEITHER:
907
908 /* Just save the Buffer */
909 Irp->UserBuffer = OutputBuffer;
910 StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
911 }
912
913 /* Now write the Event and IoSB */
914 Irp->UserIosb = IoStatusBlock;
915 Irp->UserEvent = Event;
916
917 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
918 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
919 IoQueueThreadIrp(Irp);
920
921 /* Return the IRP */
922 IOTRACE(IO_IRP_DEBUG,
923 "%s - Built IRP %p with IOCTL, Buffers, DO %lx %p %p %p\n",
924 __FUNCTION__,
925 Irp,
926 IoControlCode,
927 InputBuffer,
928 OutputBuffer,
929 DeviceObject);
930 return Irp;
931 }
932
933 /*
934 * @implemented
935 */
936 PIRP
937 NTAPI
938 IoBuildSynchronousFsdRequest(IN ULONG MajorFunction,
939 IN PDEVICE_OBJECT DeviceObject,
940 IN PVOID Buffer,
941 IN ULONG Length,
942 IN PLARGE_INTEGER StartingOffset,
943 IN PKEVENT Event,
944 IN PIO_STATUS_BLOCK IoStatusBlock)
945 {
946 PIRP Irp;
947
948 /* Do the big work to set up the IRP */
949 Irp = IoBuildAsynchronousFsdRequest(MajorFunction,
950 DeviceObject,
951 Buffer,
952 Length,
953 StartingOffset,
954 IoStatusBlock );
955 if (!Irp) return NULL;
956
957 /* Set the Event which makes it Syncronous */
958 Irp->UserEvent = Event;
959
960 /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
961 IoQueueThreadIrp(Irp);
962 return Irp;
963 }
964
965 /*
966 * @implemented
967 */
968 BOOLEAN
969 NTAPI
970 IoCancelIrp(IN PIRP Irp)
971 {
972 KIRQL OldIrql;
973 PDRIVER_CANCEL CancelRoutine;
974 IOTRACE(IO_IRP_DEBUG,
975 "%s - Canceling IRP %p\n",
976 __FUNCTION__,
977 Irp);
978 ASSERT(Irp->Type == IO_TYPE_IRP);
979
980 /* Acquire the cancel lock and cancel the IRP */
981 IoAcquireCancelSpinLock(&OldIrql);
982 Irp->Cancel = TRUE;
983
984 /* Clear the cancel routine and get the old one */
985 CancelRoutine = IoSetCancelRoutine(Irp, NULL);
986 if (CancelRoutine)
987 {
988 /* We had a routine, make sure the IRP isn't completed */
989 if (Irp->CurrentLocation > (Irp->StackCount + 1))
990 {
991 /* It is, bugcheck */
992 KeBugCheckEx(CANCEL_STATE_IN_COMPLETED_IRP,
993 (ULONG_PTR)Irp,
994 0,
995 0,
996 0);
997 }
998
999 /* Set the cancel IRQL And call the routine */
1000 Irp->CancelIrql = OldIrql;
1001 CancelRoutine(IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Irp);
1002 return TRUE;
1003 }
1004
1005 /* Otherwise, release the cancel lock and fail */
1006 IoReleaseCancelSpinLock(OldIrql);
1007 return FALSE;
1008 }
1009
1010 /*
1011 * @implemented
1012 */
1013 VOID
1014 NTAPI
1015 IoCancelThreadIo(IN PETHREAD Thread)
1016 {
1017 KIRQL OldIrql;
1018 ULONG Retries = 3000;
1019 LARGE_INTEGER Interval;
1020 PLIST_ENTRY ListHead, NextEntry;
1021 PIRP Irp;
1022 IOTRACE(IO_IRP_DEBUG,
1023 "%s - Canceling IRPs for Thread %p\n",
1024 __FUNCTION__,
1025 Thread);
1026
1027 /* Raise to APC to protect the IrpList */
1028 KeRaiseIrql(APC_LEVEL, &OldIrql);
1029
1030 /* Start by cancelling all the IRPs in the current thread queue. */
1031 ListHead = &Thread->IrpList;
1032 NextEntry = ListHead->Flink;
1033 while (ListHead != NextEntry)
1034 {
1035 /* Get the IRP */
1036 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
1037
1038 /* Cancel it */
1039 IoCancelIrp(Irp);
1040
1041 /* Move to the next entry */
1042 NextEntry = NextEntry->Flink;
1043 }
1044
1045 /* Wait 100 milliseconds */
1046 Interval.QuadPart = -1000000;
1047
1048 /* Wait till all the IRPs are completed or cancelled. */
1049 while (!IsListEmpty(&Thread->IrpList))
1050 {
1051 /* Now we can lower */
1052 KeLowerIrql(OldIrql);
1053
1054 /* Wait a short while and then look if all our IRPs were completed. */
1055 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1056
1057 /*
1058 * Don't stay here forever if some broken driver doesn't complete
1059 * the IRP.
1060 */
1061 if (!(Retries--)) IopRemoveThreadIrp();
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 fast call */
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 Param;
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 Param = IoGetNextIrpStackLocation(Irp);
1130 Irp->Tail.Overlay.CurrentStackLocation = Param;
1131
1132 /* Get the Device Object */
1133 Param->DeviceObject = DeviceObject;
1134
1135 /* Call it */
1136 return DriverObject->MajorFunction[Param->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 = (NTSTATUS)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 = (PVOID)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(
1421 IN PDEVICE_OBJECT DeviceObject,
1422 IN PIRP Irp,
1423 IN PVOID Context)
1424 {
1425 if (Irp->PendingReturned)
1426 KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
1427 return STATUS_MORE_PROCESSING_REQUIRED;
1428 }
1429
1430 /*
1431 * @implemented
1432 */
1433 BOOLEAN
1434 NTAPI
1435 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject,
1436 IN PIRP Irp)
1437 {
1438 KEVENT Event;
1439 NTSTATUS Status;
1440
1441 /* Check if next stack location is available */
1442 if (Irp->CurrentLocation < Irp->StackCount)
1443 {
1444 /* No more stack location */
1445 return FALSE;
1446 }
1447
1448 /* Initialize event */
1449 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1450
1451 /* Copy stack location for next driver */
1452 IoCopyCurrentIrpStackLocationToNext(Irp);
1453
1454 /* Set a completion routine, which will signal the event */
1455 IoSetCompletionRoutine(Irp, IopSynchronousCompletion, &Event, TRUE, TRUE, TRUE);
1456
1457 /* Call next driver */
1458 Status = IoCallDriver(DeviceObject, Irp);
1459
1460 /* Check if irp is pending */
1461 if (Status == STATUS_PENDING)
1462 {
1463 /* Yes, wait for its completion */
1464 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
1465 }
1466
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 ExFreePool(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 ExFreePool(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 * @unimplemented
1539 */
1540 IO_PAGING_PRIORITY
1541 NTAPI
1542 IoGetPagingIoPriority(IN PIRP Irp)
1543 {
1544 UNIMPLEMENTED;
1545
1546 /* Lie and say this isn't a paging IRP -- FIXME! */
1547 return IoPagingPriorityInvalid;
1548 }
1549
1550 /*
1551 * @implemented
1552 */
1553 PEPROCESS NTAPI
1554 IoGetRequestorProcess(IN PIRP Irp)
1555 {
1556 return(Irp->Tail.Overlay.Thread->ThreadsProcess);
1557 }
1558
1559 /*
1560 * @implemented
1561 */
1562 ULONG
1563 NTAPI
1564 IoGetRequestorProcessId(IN PIRP Irp)
1565 {
1566 return (ULONG)(IoGetRequestorProcess(Irp)->UniqueProcessId);
1567 }
1568
1569 /*
1570 * @implemented
1571 */
1572 NTSTATUS
1573 NTAPI
1574 IoGetRequestorSessionId(IN PIRP Irp,
1575 OUT PULONG pSessionId)
1576 {
1577 /* Return the session */
1578 *pSessionId = IoGetRequestorProcess(Irp)->Session;
1579 return STATUS_SUCCESS;
1580 }
1581
1582 /*
1583 * @implemented
1584 */
1585 PIRP
1586 NTAPI
1587 IoGetTopLevelIrp(VOID)
1588 {
1589 return (PIRP)PsGetCurrentThread()->TopLevelIrp;
1590 }
1591
1592 /*
1593 * @implemented
1594 */
1595 VOID
1596 NTAPI
1597 IoInitializeIrp(IN PIRP Irp,
1598 IN USHORT PacketSize,
1599 IN CCHAR StackSize)
1600 {
1601 /* Clear it */
1602 IOTRACE(IO_IRP_DEBUG,
1603 "%s - Initializing IRP %p\n",
1604 __FUNCTION__,
1605 Irp);
1606 RtlZeroMemory(Irp, PacketSize);
1607
1608 /* Set the Header and other data */
1609 Irp->Type = IO_TYPE_IRP;
1610 Irp->Size = PacketSize;
1611 Irp->StackCount = StackSize;
1612 Irp->CurrentLocation = StackSize + 1;
1613 Irp->ApcEnvironment = KeGetCurrentThread()->ApcStateIndex;
1614 Irp->Tail.Overlay.CurrentStackLocation = (PIO_STACK_LOCATION)(Irp + 1) + StackSize;
1615
1616 /* Initialize the Thread List */
1617 InitializeListHead(&Irp->ThreadListEntry);
1618 }
1619
1620 /*
1621 * @implemented
1622 */
1623 BOOLEAN
1624 NTAPI
1625 IoIsOperationSynchronous(IN PIRP Irp)
1626 {
1627 /* Check the flags */
1628 if (!(Irp->Flags & (IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO)) &&
1629 ((Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ||
1630 (Irp->Flags & IRP_SYNCHRONOUS_API) ||
1631 (IoGetCurrentIrpStackLocation(Irp)->FileObject->Flags &
1632 FO_SYNCHRONOUS_IO)))
1633 {
1634 /* Synch API or Paging I/O is OK, as is Sync File I/O */
1635 return TRUE;
1636 }
1637
1638 /* Otherwise, it is an asynchronous operation. */
1639 return FALSE;
1640 }
1641
1642 /*
1643 * @unimplemented
1644 */
1645 BOOLEAN
1646 NTAPI
1647 IoIsValidNameGraftingBuffer(IN PIRP Irp,
1648 IN PREPARSE_DATA_BUFFER ReparseBuffer)
1649 {
1650 UNIMPLEMENTED;
1651 return FALSE;
1652 }
1653
1654 /*
1655 * @implemented
1656 */
1657 PIRP
1658 NTAPI
1659 IoMakeAssociatedIrp(IN PIRP Irp,
1660 IN CCHAR StackSize)
1661 {
1662 PIRP AssocIrp;
1663 IOTRACE(IO_IRP_DEBUG,
1664 "%s - Associating IRP %p\n",
1665 __FUNCTION__,
1666 Irp);
1667
1668 /* Allocate the IRP */
1669 AssocIrp = IoAllocateIrp(StackSize, FALSE);
1670 if (!AssocIrp) return NULL;
1671
1672 /* Set the Flags */
1673 AssocIrp->Flags |= IRP_ASSOCIATED_IRP;
1674
1675 /* Set the Thread */
1676 AssocIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
1677
1678 /* Associate them */
1679 AssocIrp->AssociatedIrp.MasterIrp = Irp;
1680 return AssocIrp;
1681 }
1682
1683 /*
1684 * @implemented
1685 */
1686 VOID
1687 NTAPI
1688 IoQueueThreadIrp(IN PIRP Irp)
1689 {
1690 IOTRACE(IO_IRP_DEBUG,
1691 "%s - Queueing IRP %p\n",
1692 __FUNCTION__,
1693 Irp);
1694
1695 /* Use our inlined routine */
1696 IopQueueIrpToThread(Irp);
1697 }
1698
1699 /*
1700 * @implemented
1701 * Reference: Chris Cant's "Writing WDM Device Drivers"
1702 */
1703 VOID
1704 NTAPI
1705 IoReuseIrp(IN OUT PIRP Irp,
1706 IN NTSTATUS Status)
1707 {
1708 UCHAR AllocationFlags;
1709 IOTRACE(IO_IRP_DEBUG,
1710 "%s - Reusing IRP %p\n",
1711 __FUNCTION__,
1712 Irp);
1713
1714 /* Make sure it's OK to reuse it */
1715 ASSERT(!Irp->CancelRoutine);
1716 ASSERT(IsListEmpty(&Irp->ThreadListEntry));
1717
1718 /* Get the old flags */
1719 AllocationFlags = Irp->AllocationFlags;
1720
1721 /* Reinitialize the IRP */
1722 IoInitializeIrp(Irp, Irp->Size, Irp->StackCount);
1723
1724 /* Duplicate the data */
1725 Irp->IoStatus.Status = Status;
1726 Irp->AllocationFlags = AllocationFlags;
1727 }
1728
1729 /*
1730 * @implemented
1731 */
1732 VOID
1733 NTAPI
1734 IoSetTopLevelIrp(IN PIRP Irp)
1735 {
1736 /* Set the IRP */
1737 PsGetCurrentThread()->TopLevelIrp = (ULONG)Irp;
1738 }
1739
1740 /* EOF */