sync to trunk head (35945)
[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 ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF);
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 /* HACK */
350 if (*((PULONG)(Irp->UserEvent) - 1) != 0x87878787)
351 {
352 /* Dereference the event */
353 ObDereferenceObject(Irp->UserEvent);
354 }
355 else
356 {
357 DPRINT1("Not an executive event -- should not be dereferenced\n");
358 }
359 }
360
361 /*
362 * Now, if this is a Synch I/O File Object, then this event is
363 * NOT an actual Executive Event, so we won't dereference it,
364 * and instead, we will signal the File Object
365 */
366 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) &&
367 !(Irp->Flags & IRP_OB_QUERY_NAME))
368 {
369 /* Signal the file object and set the status */
370 KeSetEvent(&FileObject->Event, 0, FALSE);
371 FileObject->FinalStatus = Irp->IoStatus.Status;
372 }
373
374 /*
375 * This could also be a create operation, in which case we want
376 * to make sure there's no APC fired.
377 */
378 if (Irp->Flags & IRP_CREATE_OPERATION)
379 {
380 /* Clear the APC Routine and remember this */
381 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
382 SignaledCreateRequest = TRUE;
383 }
384 }
385 }
386 else if (FileObject)
387 {
388 /* Signal the file object and set the status */
389 KeSetEvent(&FileObject->Event, 0, FALSE);
390 FileObject->FinalStatus = Irp->IoStatus.Status;
391
392 /*
393 * This could also be a create operation, in which case we want
394 * to make sure there's no APC fired.
395 */
396 if (Irp->Flags & IRP_CREATE_OPERATION)
397 {
398 /* Clear the APC Routine and remember this */
399 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
400 SignaledCreateRequest = TRUE;
401 }
402 }
403
404 /* Now that we've signaled the events, de-associate the IRP */
405 IopUnQueueIrpFromThread(Irp);
406
407 /* Now check if a User APC Routine was requested */
408 if (Irp->Overlay.AsynchronousParameters.UserApcRoutine)
409 {
410 /* Initialize it */
411 KeInitializeApc(&Irp->Tail.Apc,
412 KeGetCurrentThread(),
413 CurrentApcEnvironment,
414 IopFreeIrpKernelApc,
415 IopAbortIrpKernelApc,
416 (PKNORMAL_ROUTINE)Irp->
417 Overlay.AsynchronousParameters.UserApcRoutine,
418 Irp->RequestorMode,
419 Irp->
420 Overlay.AsynchronousParameters.UserApcContext);
421
422 /* Queue it */
423 KeInsertQueueApc(&Irp->Tail.Apc, Irp->UserIosb, NULL, 2);
424 }
425 else if ((Port) &&
426 (Irp->Overlay.AsynchronousParameters.UserApcContext))
427 {
428 /* We have an I/O Completion setup... create the special Overlay */
429 Irp->Tail.CompletionKey = Key;
430 Irp->Tail.Overlay.PacketType = IrpCompletionPacket;
431 KeInsertQueue(Port, &Irp->Tail.Overlay.ListEntry);
432 }
433 else
434 {
435 /* Free the IRP since we don't need it anymore */
436 IoFreeIrp(Irp);
437 }
438
439 /* Check if we have a file object that wasn't part of a create */
440 if ((FileObject) && !(SignaledCreateRequest))
441 {
442 /* Dereference it, since it's not needed anymore either */
443 ObDereferenceObjectDeferDelete(FileObject);
444 }
445 }
446 else
447 {
448 /*
449 * Either we didn't return from the request, or we did return but this
450 * request was synchronous.
451 */
452 if ((Irp->PendingReturned) && (FileObject))
453 {
454 /* So we did return with a synch operation, was it the IRP? */
455 if (Irp->Flags & IRP_SYNCHRONOUS_API)
456 {
457 /* Yes, this IRP was synchronous, so return the I/O Status */
458 *Irp->UserIosb = Irp->IoStatus;
459
460 /* Now check if the user gave an event */
461 if (Irp->UserEvent)
462 {
463 /* Signal it */
464 KeSetEvent(Irp->UserEvent, 0, FALSE);
465 }
466 else
467 {
468 /* No event was given, so signal the FO instead */
469 KeSetEvent(&FileObject->Event, 0, FALSE);
470 }
471 }
472 else
473 {
474 /*
475 * It's not the IRP that was synchronous, it was the FO
476 * that was opened this way. Signal its event.
477 */
478 FileObject->FinalStatus = Irp->IoStatus.Status;
479 KeSetEvent(&FileObject->Event, 0, FALSE);
480 }
481 }
482
483 /* Now that we got here, we do this for incomplete I/Os as well */
484 if ((FileObject) && !(Irp->Flags & IRP_CREATE_OPERATION))
485 {
486 /* Dereference the File Object unless this was a create */
487 ObDereferenceObjectDeferDelete(FileObject);
488 }
489
490 /*
491 * Check if this was an Executive Event (remember that we know this
492 * by checking if the IRP is synchronous)
493 */
494 if ((Irp->UserEvent) &&
495 (FileObject) &&
496 !(Irp->Flags & IRP_SYNCHRONOUS_API))
497 {
498 /* This isn't a PKEVENT, so dereference it */
499 ObDereferenceObject(Irp->UserEvent);
500 }
501
502 /* Now that we've signaled the events, de-associate the IRP */
503 IopUnQueueIrpFromThread(Irp);
504
505 /* Free the IRP as well */
506 IoFreeIrp(Irp);
507 }
508 }
509
510 /* FUNCTIONS *****************************************************************/
511
512 /*
513 * @implemented
514 */
515 PIRP
516 NTAPI
517 IoAllocateIrp(IN CCHAR StackSize,
518 IN BOOLEAN ChargeQuota)
519 {
520 PIRP Irp = NULL;
521 USHORT Size = IoSizeOfIrp(StackSize);
522 PKPRCB Prcb;
523 UCHAR Flags = 0;
524 PNPAGED_LOOKASIDE_LIST List = NULL;
525 PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList;
526
527 /* Set Charge Quota Flag */
528 if (ChargeQuota) Flags |= IRP_QUOTA_CHARGED;
529
530 /* Figure out which Lookaside List to use */
531 if ((StackSize <= 8) && (ChargeQuota == FALSE))
532 {
533 /* Set Fixed Size Flag */
534 Flags = IRP_ALLOCATED_FIXED_SIZE;
535
536 /* See if we should use big list */
537 if (StackSize != 1)
538 {
539 Size = IoSizeOfIrp(8);
540 ListType = LookasideLargeIrpList;
541 }
542
543 /* Get the PRCB */
544 Prcb = KeGetCurrentPrcb();
545
546 /* Get the P List First */
547 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;
548
549 /* Attempt allocation */
550 List->L.TotalAllocates++;
551 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
552
553 /* Check if the P List failed */
554 if (!Irp)
555 {
556 /* Let the balancer know */
557 List->L.AllocateMisses++;
558
559 /* Try the L List */
560 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;
561 List->L.TotalAllocates++;
562 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
563 }
564 }
565
566 /* Check if we have to use the pool */
567 if (!Irp)
568 {
569 /* Did we try lookaside and fail? */
570 if (Flags & IRP_ALLOCATED_FIXED_SIZE) List->L.AllocateMisses++;
571
572 /* Check if we should charge quota */
573 if (ChargeQuota)
574 {
575 /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool, Size, TAG_IRP); */
576 /* FIXME */
577 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
578 }
579 else
580 {
581 /* Allocate the IRP With no Quota charge */
582 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
583 }
584
585 /* Make sure it was sucessful */
586 if (!Irp) return(NULL);
587 }
588 else
589 {
590 /* We have an IRP from Lookaside */
591 if (ChargeQuota) Flags |= IRP_LOOKASIDE_ALLOCATION;
592
593 /* In this case there is no charge quota */
594 Flags &= ~IRP_QUOTA_CHARGED;
595 }
596
597 /* Now Initialize it */
598 IoInitializeIrp(Irp, Size, StackSize);
599
600 /* Set the Allocation Flags */
601 Irp->AllocationFlags = Flags;
602
603 /* Return it */
604 IOTRACE(IO_IRP_DEBUG,
605 "%s - Allocated IRP %p with allocation flags %lx\n",
606 __FUNCTION__,
607 Irp,
608 Flags);
609 return Irp;
610 }
611
612 /*
613 * @implemented
614 */
615 PIRP
616 NTAPI
617 IoBuildAsynchronousFsdRequest(IN ULONG MajorFunction,
618 IN PDEVICE_OBJECT DeviceObject,
619 IN PVOID Buffer,
620 IN ULONG Length,
621 IN PLARGE_INTEGER StartingOffset,
622 IN PIO_STATUS_BLOCK IoStatusBlock)
623 {
624 PIRP Irp;
625 PIO_STACK_LOCATION StackPtr;
626
627 /* Allocate IRP */
628 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
629 if (!Irp) return NULL;
630
631 /* Get the Stack */
632 StackPtr = IoGetNextIrpStackLocation(Irp);
633
634 /* Write the Major function and then deal with it */
635 StackPtr->MajorFunction = (UCHAR)MajorFunction;
636
637 /* Do not handle the following here */
638 if ((MajorFunction != IRP_MJ_FLUSH_BUFFERS) &&
639 (MajorFunction != IRP_MJ_SHUTDOWN) &&
640 (MajorFunction != IRP_MJ_PNP) &&
641 (MajorFunction != IRP_MJ_POWER))
642 {
643 /* Check if this is Buffered IO */
644 if (DeviceObject->Flags & DO_BUFFERED_IO)
645 {
646 /* Allocate the System Buffer */
647 Irp->AssociatedIrp.SystemBuffer =
648 ExAllocatePoolWithTag(NonPagedPool, Length, TAG_SYS_BUF);
649 if (!Irp->AssociatedIrp.SystemBuffer)
650 {
651 /* Free the IRP and fail */
652 IoFreeIrp(Irp);
653 return NULL;
654 }
655
656 /* Set flags */
657 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
658
659 /* Handle special IRP_MJ_WRITE Case */
660 if (MajorFunction == IRP_MJ_WRITE)
661 {
662 /* Copy the buffer data */
663 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
664 }
665 else
666 {
667 /* Set the Input Operation flag and set this as a User Buffer */
668 Irp->Flags |= IRP_INPUT_OPERATION;
669 Irp->UserBuffer = Buffer;
670 }
671 }
672 else if (DeviceObject->Flags & DO_DIRECT_IO)
673 {
674 /* Use an MDL for Direct I/O */
675 Irp->MdlAddress = IoAllocateMdl(Buffer,
676 Length,
677 FALSE,
678 FALSE,
679 NULL);
680 if (!Irp->MdlAddress)
681 {
682 /* Free the IRP and fail */
683 IoFreeIrp(Irp);
684 return NULL;
685 }
686
687 /* Probe and Lock */
688 _SEH_TRY
689 {
690 /* Do the probe */
691 MmProbeAndLockPages(Irp->MdlAddress,
692 KernelMode,
693 MajorFunction == IRP_MJ_READ ?
694 IoWriteAccess : IoReadAccess);
695 }
696 _SEH_HANDLE
697 {
698 /* Free the IRP and its MDL */
699 IoFreeMdl(Irp->MdlAddress);
700 IoFreeIrp(Irp);
701 Irp = NULL;
702 }
703 _SEH_END;
704
705 /* This is how we know if we failed during the probe */
706 if (!Irp) return NULL;
707 }
708 else
709 {
710 /* Neither, use the buffer */
711 Irp->UserBuffer = Buffer;
712 }
713
714 /* Check if this is a read */
715 if (MajorFunction == IRP_MJ_READ)
716 {
717 /* Set the parameters for a read */
718 StackPtr->Parameters.Read.Length = Length;
719 StackPtr->Parameters.Read.ByteOffset = *StartingOffset;
720 }
721 else if (MajorFunction == IRP_MJ_WRITE)
722 {
723 /* Otherwise, set write parameters */
724 StackPtr->Parameters.Write.Length = Length;
725 StackPtr->Parameters.Write.ByteOffset = *StartingOffset;
726 }
727 }
728
729 /* Set the Current Thread and IOSB */
730 Irp->UserIosb = IoStatusBlock;
731 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
732
733 /* Return the IRP */
734 IOTRACE(IO_IRP_DEBUG,
735 "%s - Built IRP %p with Major, Buffer, DO %lx %p %p\n",
736 __FUNCTION__,
737 Irp,
738 MajorFunction,
739 Buffer,
740 DeviceObject);
741 return Irp;
742 }
743
744 /*
745 * @implemented
746 */
747 PIRP
748 NTAPI
749 IoBuildDeviceIoControlRequest(IN ULONG IoControlCode,
750 IN PDEVICE_OBJECT DeviceObject,
751 IN PVOID InputBuffer,
752 IN ULONG InputBufferLength,
753 IN PVOID OutputBuffer,
754 IN ULONG OutputBufferLength,
755 IN BOOLEAN InternalDeviceIoControl,
756 IN PKEVENT Event,
757 IN PIO_STATUS_BLOCK IoStatusBlock)
758 {
759 PIRP Irp;
760 PIO_STACK_LOCATION StackPtr;
761 ULONG BufferLength;
762
763 /* Allocate IRP */
764 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
765 if (!Irp) return NULL;
766
767 /* Get the Stack */
768 StackPtr = IoGetNextIrpStackLocation(Irp);
769
770 /* Set the DevCtl Type */
771 StackPtr->MajorFunction = InternalDeviceIoControl ?
772 IRP_MJ_INTERNAL_DEVICE_CONTROL :
773 IRP_MJ_DEVICE_CONTROL;
774
775 /* Set the IOCTL Data */
776 StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
777 StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
778 StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
779 OutputBufferLength;
780
781 /* Handle the Methods */
782 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
783 {
784 /* Buffered I/O */
785 case METHOD_BUFFERED:
786
787 /* Select the right Buffer Length */
788 BufferLength = InputBufferLength > OutputBufferLength ?
789 InputBufferLength : OutputBufferLength;
790
791 /* Make sure there is one */
792 if (BufferLength)
793 {
794 /* Allocate the System Buffer */
795 Irp->AssociatedIrp.SystemBuffer =
796 ExAllocatePoolWithTag(NonPagedPool,
797 BufferLength,
798 TAG_SYS_BUF);
799 if (!Irp->AssociatedIrp.SystemBuffer)
800 {
801 /* Free the IRP and fail */
802 IoFreeIrp(Irp);
803 return NULL;
804 }
805
806 /* Check if we got a buffer */
807 if (InputBuffer)
808 {
809 /* Copy into the System Buffer */
810 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
811 InputBuffer,
812 InputBufferLength);
813 }
814
815 /* Write the flags */
816 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
817 if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
818
819 /* Save the Buffer */
820 Irp->UserBuffer = OutputBuffer;
821 }
822 else
823 {
824 /* Clear the Flags and Buffer */
825 Irp->Flags = 0;
826 Irp->UserBuffer = NULL;
827 }
828 break;
829
830 /* Direct I/O */
831 case METHOD_IN_DIRECT:
832 case METHOD_OUT_DIRECT:
833
834 /* Check if we got an input buffer */
835 if (InputBuffer)
836 {
837 /* Allocate the System Buffer */
838 Irp->AssociatedIrp.SystemBuffer =
839 ExAllocatePoolWithTag(NonPagedPool,
840 InputBufferLength,
841 TAG_SYS_BUF);
842 if (!Irp->AssociatedIrp.SystemBuffer)
843 {
844 /* Free the IRP and fail */
845 IoFreeIrp(Irp);
846 return NULL;
847 }
848
849 /* Copy into the System Buffer */
850 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
851 InputBuffer,
852 InputBufferLength);
853
854 /* Write the flags */
855 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
856 }
857 else
858 {
859 /* Clear the flags */
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 KIRQL IrqlAtEntry;
974 PDRIVER_CANCEL CancelRoutine;
975 IOTRACE(IO_IRP_DEBUG,
976 "%s - Canceling IRP %p\n",
977 __FUNCTION__,
978 Irp);
979 ASSERT(Irp->Type == IO_TYPE_IRP);
980 IrqlAtEntry = KeGetCurrentIrql();
981
982 /* Acquire the cancel lock and cancel the IRP */
983 IoAcquireCancelSpinLock(&OldIrql);
984 Irp->Cancel = TRUE;
985
986 /* Clear the cancel routine and get the old one */
987 CancelRoutine = IoSetCancelRoutine(Irp, NULL);
988 if (CancelRoutine)
989 {
990 /* We had a routine, make sure the IRP isn't completed */
991 if (Irp->CurrentLocation > (Irp->StackCount + 1))
992 {
993 /* It is, bugcheck */
994 KeBugCheckEx(CANCEL_STATE_IN_COMPLETED_IRP,
995 (ULONG_PTR)Irp,
996 0,
997 0,
998 0);
999 }
1000
1001 /* Set the cancel IRQL And call the routine */
1002 Irp->CancelIrql = OldIrql;
1003 CancelRoutine(IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Irp);
1004 ASSERT(IrqlAtEntry == KeGetCurrentIrql());
1005 return TRUE;
1006 }
1007
1008 /* Otherwise, release the cancel lock and fail */
1009 IoReleaseCancelSpinLock(OldIrql);
1010 return FALSE;
1011 }
1012
1013 /*
1014 * @implemented
1015 */
1016 VOID
1017 NTAPI
1018 IoCancelThreadIo(IN PETHREAD Thread)
1019 {
1020 KIRQL OldIrql;
1021 ULONG Retries = 3000;
1022 LARGE_INTEGER Interval;
1023 PLIST_ENTRY ListHead, NextEntry;
1024 PIRP Irp;
1025 IOTRACE(IO_IRP_DEBUG,
1026 "%s - Canceling IRPs for Thread %p\n",
1027 __FUNCTION__,
1028 Thread);
1029
1030 /* Raise to APC to protect the IrpList */
1031 KeRaiseIrql(APC_LEVEL, &OldIrql);
1032
1033 /* Start by cancelling all the IRPs in the current thread queue. */
1034 ListHead = &Thread->IrpList;
1035 NextEntry = ListHead->Flink;
1036 while (ListHead != NextEntry)
1037 {
1038 /* Get the IRP */
1039 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
1040
1041 /* Cancel it */
1042 IoCancelIrp(Irp);
1043
1044 /* Move to the next entry */
1045 NextEntry = NextEntry->Flink;
1046 }
1047
1048 /* Wait 100 milliseconds */
1049 Interval.QuadPart = -1000000;
1050
1051 /* Wait till all the IRPs are completed or cancelled. */
1052 while (!IsListEmpty(&Thread->IrpList))
1053 {
1054 /* Now we can lower */
1055 KeLowerIrql(OldIrql);
1056
1057 /* Wait a short while and then look if all our IRPs were completed. */
1058 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1059
1060 /*
1061 * Don't stay here forever if some broken driver doesn't complete
1062 * the IRP.
1063 */
1064 if (!(Retries--))
1065 {
1066 /* Print out a message and remove the IRP */
1067 DPRINT1("Broken driver did not complete!\n");
1068 IopRemoveThreadIrp();
1069 }
1070
1071 /* Raise the IRQL Again */
1072 KeRaiseIrql(APC_LEVEL, &OldIrql);
1073 }
1074
1075 /* We're done, lower the IRQL */
1076 KeLowerIrql(OldIrql);
1077 }
1078
1079 /*
1080 * @implemented
1081 */
1082 NTSTATUS
1083 NTAPI
1084 IoCallDriver(IN PDEVICE_OBJECT DeviceObject,
1085 IN PIRP Irp)
1086 {
1087 /* Call fastcall */
1088 return IofCallDriver(DeviceObject, Irp);
1089 }
1090
1091 /*
1092 * @implemented
1093 */
1094 VOID
1095 NTAPI
1096 IoCompleteRequest(IN PIRP Irp,
1097 IN CCHAR PriorityBoost)
1098 {
1099 /* Call the fastcall */
1100 IofCompleteRequest(Irp, PriorityBoost);
1101 }
1102
1103 /*
1104 * @implemented
1105 */
1106 VOID
1107 NTAPI
1108 IoEnqueueIrp(IN PIRP Irp)
1109 {
1110 /* This is the same as calling IoQueueThreadIrp */
1111 IoQueueThreadIrp(Irp);
1112 }
1113
1114 /*
1115 * @implemented
1116 */
1117 NTSTATUS
1118 FASTCALL
1119 IofCallDriver(IN PDEVICE_OBJECT DeviceObject,
1120 IN PIRP Irp)
1121 {
1122 PDRIVER_OBJECT DriverObject;
1123 PIO_STACK_LOCATION StackPtr;
1124
1125 /* Get the Driver Object */
1126 DriverObject = DeviceObject->DriverObject;
1127
1128 /* Decrease the current location and check if */
1129 Irp->CurrentLocation--;
1130 if (Irp->CurrentLocation <= 0)
1131 {
1132 /* This IRP ran out of stack, bugcheck */
1133 KeBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR)Irp, 0, 0, 0);
1134 }
1135
1136 /* Now update the stack location */
1137 StackPtr = IoGetNextIrpStackLocation(Irp);
1138 Irp->Tail.Overlay.CurrentStackLocation = StackPtr;
1139
1140 /* Get the Device Object */
1141 StackPtr->DeviceObject = DeviceObject;
1142
1143 /* Call it */
1144 return DriverObject->MajorFunction[StackPtr->MajorFunction](DeviceObject,
1145 Irp);
1146 }
1147
1148 FORCEINLINE
1149 VOID
1150 IopClearStackLocation(IN PIO_STACK_LOCATION IoStackLocation)
1151 {
1152 IoStackLocation->MinorFunction = 0;
1153 IoStackLocation->Flags = 0;
1154 IoStackLocation->Control &= SL_ERROR_RETURNED;
1155 IoStackLocation->Parameters.Others.Argument1 = 0;
1156 IoStackLocation->Parameters.Others.Argument2 = 0;
1157 IoStackLocation->Parameters.Others.Argument3 = 0;
1158 IoStackLocation->FileObject = NULL;
1159 }
1160
1161 /*
1162 * @implemented
1163 */
1164 VOID
1165 FASTCALL
1166 IofCompleteRequest(IN PIRP Irp,
1167 IN CCHAR PriorityBoost)
1168 {
1169 PIO_STACK_LOCATION StackPtr, LastStackPtr;
1170 PDEVICE_OBJECT DeviceObject;
1171 PFILE_OBJECT FileObject;
1172 PETHREAD Thread;
1173 NTSTATUS Status;
1174 PMDL Mdl, NextMdl;
1175 ULONG MasterCount;
1176 PIRP MasterIrp;
1177 ULONG Flags;
1178 NTSTATUS ErrorCode = STATUS_SUCCESS;
1179 IOTRACE(IO_IRP_DEBUG,
1180 "%s - Completing IRP %p\n",
1181 __FUNCTION__,
1182 Irp);
1183
1184 /* Make sure this IRP isn't getting completed twice or is invalid */
1185 if ((Irp->CurrentLocation) > (Irp->StackCount + 1))
1186 {
1187 /* Bugcheck */
1188 KeBugCheckEx(MULTIPLE_IRP_COMPLETE_REQUESTS, (ULONG_PTR)Irp, 0, 0, 0);
1189 }
1190
1191 /* Some sanity checks */
1192 ASSERT(Irp->Type == IO_TYPE_IRP);
1193 ASSERT(!Irp->CancelRoutine);
1194 ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
1195 ASSERT(Irp->IoStatus.Status != 0xFFFFFFFF);
1196
1197 /* Get the last stack */
1198 LastStackPtr = (PIO_STACK_LOCATION)(Irp + 1);
1199 if (LastStackPtr->Control & SL_ERROR_RETURNED)
1200 {
1201 /* Get the error code */
1202 ErrorCode = (NTSTATUS)LastStackPtr->Parameters.Others.Argument4;
1203 }
1204
1205 /* Get the Current Stack and skip it */
1206 StackPtr = IoGetCurrentIrpStackLocation(Irp);
1207 IoSkipCurrentIrpStackLocation(Irp);
1208
1209 /* Loop the Stacks and complete the IRPs */
1210 do
1211 {
1212 /* Set Pending Returned */
1213 Irp->PendingReturned = StackPtr->Control & SL_PENDING_RETURNED;
1214
1215 /* Check if we failed */
1216 if (!NT_SUCCESS(Irp->IoStatus.Status))
1217 {
1218 /* Check if it was changed by a completion routine */
1219 if (Irp->IoStatus.Status != ErrorCode)
1220 {
1221 /* Update the error for the current stack */
1222 ErrorCode = Irp->IoStatus.Status;
1223 StackPtr->Control |= SL_ERROR_RETURNED;
1224 LastStackPtr->Parameters.Others.Argument4 = (PVOID)ErrorCode;
1225 LastStackPtr->Control |= SL_ERROR_RETURNED;
1226 }
1227 }
1228
1229 /* Check if there is a Completion Routine to Call */
1230 if ((NT_SUCCESS(Irp->IoStatus.Status) &&
1231 (StackPtr->Control & SL_INVOKE_ON_SUCCESS)) ||
1232 (!NT_SUCCESS(Irp->IoStatus.Status) &&
1233 (StackPtr->Control & SL_INVOKE_ON_ERROR)) ||
1234 (Irp->Cancel &&
1235 (StackPtr->Control & SL_INVOKE_ON_CANCEL)))
1236 {
1237 /* Clear the stack location */
1238 IopClearStackLocation(StackPtr);
1239
1240 /* Check for highest-level device completion routines */
1241 if (Irp->CurrentLocation == (Irp->StackCount + 1))
1242 {
1243 /* Clear the DO, since the current stack location is invalid */
1244 DeviceObject = NULL;
1245 }
1246 else
1247 {
1248 /* Otherwise, return the real one */
1249 DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
1250 }
1251
1252 /* Call the completion routine */
1253 Status = StackPtr->CompletionRoutine(DeviceObject,
1254 Irp,
1255 StackPtr->Context);
1256
1257 /* Don't touch the Packet in this case, since it might be gone! */
1258 if (Status == STATUS_MORE_PROCESSING_REQUIRED) return;
1259 }
1260 else
1261 {
1262 /* Otherwise, check if this is a completed IRP */
1263 if ((Irp->CurrentLocation <= Irp->StackCount) &&
1264 (Irp->PendingReturned))
1265 {
1266 /* Mark it as pending */
1267 IoMarkIrpPending(Irp);
1268 }
1269
1270 /* Clear the stack location */
1271 IopClearStackLocation(StackPtr);
1272 }
1273
1274 /* Move to next stack location and pointer */
1275 IoSkipCurrentIrpStackLocation(Irp);
1276 StackPtr++;
1277 } while (Irp->CurrentLocation <= (Irp->StackCount + 1));
1278
1279 /* Check if the IRP is an associated IRP */
1280 if (Irp->Flags & IRP_ASSOCIATED_IRP)
1281 {
1282 /* Get the master IRP and count */
1283 MasterIrp = Irp->AssociatedIrp.MasterIrp;
1284 MasterCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount);
1285
1286 /* Free the MDLs */
1287 for (Mdl = Irp->MdlAddress; Mdl; Mdl = NextMdl)
1288 {
1289 /* Go to the next one */
1290 NextMdl = Mdl->Next;
1291 IoFreeMdl(Mdl);
1292 }
1293
1294 /* Free the IRP itself */
1295 IoFreeIrp(Irp);
1296
1297 /* Complete the Master IRP */
1298 if (!MasterCount) IofCompleteRequest(MasterIrp, PriorityBoost);
1299 return;
1300 }
1301
1302 /* We don't support this yet */
1303 ASSERT(Irp->IoStatus.Status != STATUS_REPARSE);
1304
1305 /* Check if we have an auxiliary buffer */
1306 if (Irp->Tail.Overlay.AuxiliaryBuffer)
1307 {
1308 /* Free it */
1309 ExFreePool(Irp->Tail.Overlay.AuxiliaryBuffer);
1310 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
1311 }
1312
1313 /* Check if this is a Paging I/O or Close Operation */
1314 if (Irp->Flags & (IRP_PAGING_IO | IRP_CLOSE_OPERATION))
1315 {
1316 /* Handle a Close Operation or Sync Paging I/O */
1317 if (Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_CLOSE_OPERATION))
1318 {
1319 /* Set the I/O Status and Signal the Event */
1320 Flags = Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_PAGING_IO);
1321 *Irp->UserIosb = Irp->IoStatus;
1322 KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE);
1323
1324 /* Free the IRP for a Paging I/O Only, Close is handled by us */
1325 if (Flags) IoFreeIrp(Irp);
1326 }
1327 else
1328 {
1329 #if 0
1330 /* Page 166 */
1331 KeInitializeApc(&Irp->Tail.Apc
1332 &Irp->Tail.Overlay.Thread->Tcb,
1333 Irp->ApcEnvironment,
1334 IopCompletePageWrite,
1335 NULL,
1336 NULL,
1337 KernelMode,
1338 NULL);
1339 KeInsertQueueApc(&Irp->Tail.Apc,
1340 NULL,
1341 NULL,
1342 PriorityBoost);
1343 #else
1344 /* Not implemented yet. */
1345 DPRINT1("Not supported!\n");
1346 while (TRUE);
1347 #endif
1348 }
1349
1350 /* Get out of here */
1351 return;
1352 }
1353
1354 /* Unlock MDL Pages, page 167. */
1355 Mdl = Irp->MdlAddress;
1356 while (Mdl)
1357 {
1358 MmUnlockPages(Mdl);
1359 Mdl = Mdl->Next;
1360 }
1361
1362 /* Check if we should exit because of a Deferred I/O (page 168) */
1363 if ((Irp->Flags & IRP_DEFER_IO_COMPLETION) && !(Irp->PendingReturned))
1364 {
1365 /*
1366 * Return without queuing the completion APC, since the caller will
1367 * take care of doing its own optimized completion at PASSIVE_LEVEL.
1368 */
1369 return;
1370 }
1371
1372 /* Get the thread and file object */
1373 Thread = Irp->Tail.Overlay.Thread;
1374 FileObject = Irp->Tail.Overlay.OriginalFileObject;
1375
1376 /* Make sure the IRP isn't canceled */
1377 if (!Irp->Cancel)
1378 {
1379 /* Initialize the APC */
1380 KeInitializeApc(&Irp->Tail.Apc,
1381 &Thread->Tcb,
1382 Irp->ApcEnvironment,
1383 IopCompleteRequest,
1384 NULL,
1385 NULL,
1386 KernelMode,
1387 NULL);
1388
1389 /* Queue it */
1390 KeInsertQueueApc(&Irp->Tail.Apc,
1391 FileObject,
1392 NULL, /* This is used for REPARSE stuff */
1393 PriorityBoost);
1394 }
1395 else
1396 {
1397 /* The IRP just got canceled... does a thread still own it? */
1398 Thread = Irp->Tail.Overlay.Thread;
1399 if (Thread)
1400 {
1401 /* Yes! There is still hope! Initialize the APC */
1402 KeInitializeApc(&Irp->Tail.Apc,
1403 &Thread->Tcb,
1404 Irp->ApcEnvironment,
1405 IopCompleteRequest,
1406 NULL,
1407 NULL,
1408 KernelMode,
1409 NULL);
1410
1411 /* Queue it */
1412 KeInsertQueueApc(&Irp->Tail.Apc,
1413 FileObject,
1414 NULL, /* This is used for REPARSE stuff */
1415 PriorityBoost);
1416 }
1417 else
1418 {
1419 /* Nothing left for us to do, kill it */
1420 ASSERT(Irp->Cancel);
1421 IopCleanupIrp(Irp, FileObject);
1422 }
1423 }
1424 }
1425
1426 NTSTATUS
1427 NTAPI
1428 IopSynchronousCompletion(IN PDEVICE_OBJECT DeviceObject,
1429 IN PIRP Irp,
1430 IN PVOID Context)
1431 {
1432 if (Irp->PendingReturned)
1433 KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
1434 return STATUS_MORE_PROCESSING_REQUIRED;
1435 }
1436
1437 /*
1438 * @implemented
1439 */
1440 BOOLEAN
1441 NTAPI
1442 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject,
1443 IN PIRP Irp)
1444 {
1445 KEVENT Event;
1446 NTSTATUS Status;
1447
1448 /* Check if next stack location is available */
1449 if (Irp->CurrentLocation < Irp->StackCount)
1450 {
1451 /* No more stack location */
1452 return FALSE;
1453 }
1454
1455 /* Initialize event */
1456 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1457
1458 /* Copy stack location for next driver */
1459 IoCopyCurrentIrpStackLocationToNext(Irp);
1460
1461 /* Set a completion routine, which will signal the event */
1462 IoSetCompletionRoutine(Irp, IopSynchronousCompletion, &Event, TRUE, TRUE, TRUE);
1463
1464 /* Call next driver */
1465 Status = IoCallDriver(DeviceObject, Irp);
1466
1467 /* Check if irp is pending */
1468 if (Status == STATUS_PENDING)
1469 {
1470 /* Yes, wait for its completion */
1471 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
1472 }
1473
1474 /* Return success */
1475 return TRUE;
1476 }
1477
1478 /*
1479 * @implemented
1480 */
1481 VOID
1482 NTAPI
1483 IoFreeIrp(IN PIRP Irp)
1484 {
1485 PNPAGED_LOOKASIDE_LIST List;
1486 PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList;
1487 PKPRCB Prcb;
1488 IOTRACE(IO_IRP_DEBUG,
1489 "%s - Freeing IRPs %p\n",
1490 __FUNCTION__,
1491 Irp);
1492
1493 /* Make sure the Thread IRP list is empty and that it OK to free it */
1494 ASSERT(Irp->Type == IO_TYPE_IRP);
1495 ASSERT(IsListEmpty(&Irp->ThreadListEntry));
1496 ASSERT(Irp->CurrentLocation >= Irp->StackCount);
1497
1498 /* If this was a pool alloc, free it with the pool */
1499 if (!(Irp->AllocationFlags & IRP_ALLOCATED_FIXED_SIZE))
1500 {
1501 /* Free it */
1502 ExFreePoolWithTag(Irp, TAG_IRP);
1503 }
1504 else
1505 {
1506 /* Check if this was a Big IRP */
1507 if (Irp->StackCount != 1) ListType = LookasideLargeIrpList;
1508
1509 /* Get the PRCB */
1510 Prcb = KeGetCurrentPrcb();
1511
1512 /* Use the P List */
1513 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;
1514 List->L.TotalFrees++;
1515
1516 /* Check if the Free was within the Depth or not */
1517 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
1518 {
1519 /* Let the balancer know */
1520 List->L.FreeMisses++;
1521
1522 /* Use the L List */
1523 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;
1524 List->L.TotalFrees++;
1525
1526 /* Check if the Free was within the Depth or not */
1527 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
1528 {
1529 /* All lists failed, use the pool */
1530 List->L.FreeMisses++;
1531 ExFreePoolWithTag(Irp, TAG_IRP);
1532 Irp = NULL;
1533 }
1534 }
1535
1536 /* The free was within the Depth */
1537 if (Irp)
1538 {
1539 InterlockedPushEntrySList(&List->L.ListHead,
1540 (PSINGLE_LIST_ENTRY)Irp);
1541 }
1542 }
1543 }
1544
1545 /*
1546 * @unimplemented
1547 */
1548 IO_PAGING_PRIORITY
1549 NTAPI
1550 IoGetPagingIoPriority(IN PIRP Irp)
1551 {
1552 UNIMPLEMENTED;
1553
1554 /* Lie and say this isn't a paging IRP -- FIXME! */
1555 return IoPagingPriorityInvalid;
1556 }
1557
1558 /*
1559 * @implemented
1560 */
1561 PEPROCESS
1562 NTAPI
1563 IoGetRequestorProcess(IN PIRP Irp)
1564 {
1565 /* Return the requestor process */
1566 return Irp->Tail.Overlay.Thread->ThreadsProcess;
1567 }
1568
1569 /*
1570 * @implemented
1571 */
1572 ULONG
1573 NTAPI
1574 IoGetRequestorProcessId(IN PIRP Irp)
1575 {
1576 /* Return the requestor process' id */
1577 return (ULONG)(IoGetRequestorProcess(Irp)->UniqueProcessId);
1578 }
1579
1580 /*
1581 * @implemented
1582 */
1583 NTSTATUS
1584 NTAPI
1585 IoGetRequestorSessionId(IN PIRP Irp,
1586 OUT PULONG pSessionId)
1587 {
1588 /* Return the session */
1589 *pSessionId = IoGetRequestorProcess(Irp)->Session;
1590 return STATUS_SUCCESS;
1591 }
1592
1593 /*
1594 * @implemented
1595 */
1596 PIRP
1597 NTAPI
1598 IoGetTopLevelIrp(VOID)
1599 {
1600 /* Return the IRP */
1601 return (PIRP)PsGetCurrentThread()->TopLevelIrp;
1602 }
1603
1604 /*
1605 * @implemented
1606 */
1607 VOID
1608 NTAPI
1609 IoInitializeIrp(IN PIRP Irp,
1610 IN USHORT PacketSize,
1611 IN CCHAR StackSize)
1612 {
1613 /* Clear it */
1614 IOTRACE(IO_IRP_DEBUG,
1615 "%s - Initializing IRP %p\n",
1616 __FUNCTION__,
1617 Irp);
1618 RtlZeroMemory(Irp, PacketSize);
1619
1620 /* Set the Header and other data */
1621 Irp->Type = IO_TYPE_IRP;
1622 Irp->Size = PacketSize;
1623 Irp->StackCount = StackSize;
1624 Irp->CurrentLocation = StackSize + 1;
1625 Irp->ApcEnvironment = KeGetCurrentThread()->ApcStateIndex;
1626 Irp->Tail.Overlay.CurrentStackLocation = (PIO_STACK_LOCATION)(Irp + 1) + StackSize;
1627
1628 /* Initialize the Thread List */
1629 InitializeListHead(&Irp->ThreadListEntry);
1630 }
1631
1632 /*
1633 * @implemented
1634 */
1635 BOOLEAN
1636 NTAPI
1637 IoIsOperationSynchronous(IN PIRP Irp)
1638 {
1639 /* Check the flags */
1640 if (!(Irp->Flags & (IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO)) &&
1641 ((Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ||
1642 (Irp->Flags & IRP_SYNCHRONOUS_API) ||
1643 (IoGetCurrentIrpStackLocation(Irp)->FileObject->Flags &
1644 FO_SYNCHRONOUS_IO)))
1645 {
1646 /* Synch API or Paging I/O is OK, as is Sync File I/O */
1647 return TRUE;
1648 }
1649
1650 /* Otherwise, it is an asynchronous operation. */
1651 return FALSE;
1652 }
1653
1654 /*
1655 * @unimplemented
1656 */
1657 BOOLEAN
1658 NTAPI
1659 IoIsValidNameGraftingBuffer(IN PIRP Irp,
1660 IN PREPARSE_DATA_BUFFER ReparseBuffer)
1661 {
1662 UNIMPLEMENTED;
1663 return FALSE;
1664 }
1665
1666 /*
1667 * @implemented
1668 */
1669 PIRP
1670 NTAPI
1671 IoMakeAssociatedIrp(IN PIRP Irp,
1672 IN CCHAR StackSize)
1673 {
1674 PIRP AssocIrp;
1675 IOTRACE(IO_IRP_DEBUG,
1676 "%s - Associating IRP %p\n",
1677 __FUNCTION__,
1678 Irp);
1679
1680 /* Allocate the IRP */
1681 AssocIrp = IoAllocateIrp(StackSize, FALSE);
1682 if (!AssocIrp) return NULL;
1683
1684 /* Set the Flags */
1685 AssocIrp->Flags |= IRP_ASSOCIATED_IRP;
1686
1687 /* Set the Thread */
1688 AssocIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
1689
1690 /* Associate them */
1691 AssocIrp->AssociatedIrp.MasterIrp = Irp;
1692 return AssocIrp;
1693 }
1694
1695 /*
1696 * @implemented
1697 */
1698 VOID
1699 NTAPI
1700 IoQueueThreadIrp(IN PIRP Irp)
1701 {
1702 IOTRACE(IO_IRP_DEBUG,
1703 "%s - Queueing IRP %p\n",
1704 __FUNCTION__,
1705 Irp);
1706
1707 /* Use our inlined routine */
1708 IopQueueIrpToThread(Irp);
1709 }
1710
1711 /*
1712 * @implemented
1713 * Reference: Chris Cant's "Writing WDM Device Drivers"
1714 */
1715 VOID
1716 NTAPI
1717 IoReuseIrp(IN OUT PIRP Irp,
1718 IN NTSTATUS Status)
1719 {
1720 UCHAR AllocationFlags;
1721 IOTRACE(IO_IRP_DEBUG,
1722 "%s - Reusing IRP %p\n",
1723 __FUNCTION__,
1724 Irp);
1725
1726 /* Make sure it's OK to reuse it */
1727 ASSERT(!Irp->CancelRoutine);
1728 ASSERT(IsListEmpty(&Irp->ThreadListEntry));
1729
1730 /* Get the old flags */
1731 AllocationFlags = Irp->AllocationFlags;
1732
1733 /* Reinitialize the IRP */
1734 IoInitializeIrp(Irp, Irp->Size, Irp->StackCount);
1735
1736 /* Duplicate the data */
1737 Irp->IoStatus.Status = Status;
1738 Irp->AllocationFlags = AllocationFlags;
1739 }
1740
1741 /*
1742 * @implemented
1743 */
1744 VOID
1745 NTAPI
1746 IoSetTopLevelIrp(IN PIRP Irp)
1747 {
1748 /* Set the IRP */
1749 PsGetCurrentThread()->TopLevelIrp = (ULONG)Irp;
1750 }