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