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