ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

irp.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            ntoskrnl/io/iomgr/irp.c
00005  * PURPOSE:         IRP Handling Functions
00006  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007  *                  Gunnar Dalsnes
00008  *                  Filip Navara (navaraf@reactos.org)
00009  */
00010 
00011 /* INCLUDES ****************************************************************/
00012 
00013 #include <ntoskrnl.h>
00014 #define NDEBUG
00015 #include <debug.h>
00016 
00017 PIRP IopDeadIrp;
00018 
00019 /* PRIVATE FUNCTIONS  ********************************************************/
00020 
00021 VOID
00022 NTAPI
00023 IopFreeIrpKernelApc(IN PKAPC Apc,
00024                     IN PKNORMAL_ROUTINE *NormalRoutine,
00025                     IN PVOID *NormalContext,
00026                     IN PVOID *SystemArgument1,
00027                     IN PVOID *SystemArgument2)
00028 {
00029     /* Free the IRP */
00030     IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc));
00031 }
00032 
00033 VOID
00034 NTAPI
00035 IopAbortIrpKernelApc(IN PKAPC Apc)
00036 {
00037     /* Free the IRP */
00038     IoFreeIrp(CONTAINING_RECORD(Apc, IRP, Tail.Apc));
00039 }
00040 
00041 NTSTATUS
00042 NTAPI
00043 IopCleanupFailedIrp(IN PFILE_OBJECT FileObject,
00044                     IN PKEVENT EventObject OPTIONAL,
00045                     IN PVOID Buffer OPTIONAL)
00046 {
00047     PAGED_CODE();
00048 
00049     /* Dereference the event */
00050     if (EventObject) ObDereferenceObject(EventObject);
00051 
00052     /* Free a buffer, if any */
00053     if (Buffer) ExFreePool(Buffer);
00054 
00055     /* If this was a file opened for synch I/O, then unlock it */
00056     if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopUnlockFileObject(FileObject);
00057 
00058     /* Now dereference it and return */
00059     ObDereferenceObject(FileObject);
00060     return STATUS_INSUFFICIENT_RESOURCES;
00061 }
00062 
00063 VOID
00064 NTAPI
00065 IopAbortInterruptedIrp(IN PKEVENT EventObject,
00066                        IN PIRP Irp)
00067 {
00068     KIRQL OldIrql;
00069     BOOLEAN CancelResult;
00070     LARGE_INTEGER Wait;
00071     PAGED_CODE();
00072 
00073     /* Raise IRQL to APC */
00074     KeRaiseIrql(APC_LEVEL, &OldIrql);
00075 
00076     /* Check if nobody completed it yet */
00077     if (!KeReadStateEvent(EventObject))
00078     {
00079         /* First, cancel it */
00080         CancelResult = IoCancelIrp(Irp);
00081         KeLowerIrql(OldIrql);
00082 
00083         /* Check if we cancelled it */
00084         if (CancelResult)
00085         {
00086             /* Wait for the IRP to be cancelled */
00087             Wait.QuadPart = -100000;
00088             while (!KeReadStateEvent(EventObject))
00089             {
00090                 /* Delay indefintely */
00091                 KeDelayExecutionThread(KernelMode, FALSE, &Wait);
00092             }
00093         }
00094         else
00095         {
00096             /* No cancellation done, so wait for the I/O system to kill it */
00097             KeWaitForSingleObject(EventObject,
00098                                   Executive,
00099                                   KernelMode,
00100                                   FALSE,
00101                                   NULL);
00102         }
00103     }
00104     else
00105     {
00106         /* We got preempted, so give up */
00107         KeLowerIrql(OldIrql);
00108     }
00109 }
00110 
00111 VOID
00112 NTAPI
00113 IopDisassociateThreadIrp(VOID)
00114 {
00115     KIRQL OldIrql, LockIrql;
00116     PETHREAD IrpThread;
00117     PLIST_ENTRY IrpEntry;
00118     PIO_ERROR_LOG_PACKET ErrorLogEntry;
00119     PDEVICE_OBJECT DeviceObject = NULL;
00120     PIO_STACK_LOCATION IoStackLocation;
00121 
00122     /* First, raise to APC to protect IrpList */
00123     KeRaiseIrql(APC_LEVEL, &OldIrql);
00124 
00125     /* Get the Thread and check the list */
00126     IrpThread = PsGetCurrentThread();
00127     if (IsListEmpty(&IrpThread->IrpList))
00128     {
00129         /* It got completed now, so quit */
00130         KeLowerIrql(OldIrql);
00131         return;
00132     }
00133 
00134     /* Ensure no one will come disturb */
00135     LockIrql = KeAcquireQueuedSpinLock(LockQueueIoCompletionLock);
00136 
00137     /* Get the misbehaving IRP */
00138     IrpEntry = IrpThread->IrpList.Flink;
00139     IopDeadIrp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry);
00140     IOTRACE(IO_IRP_DEBUG,
00141             "%s - Deassociating IRP %p for %p\n",
00142             __FUNCTION__,
00143             IopDeadIrp,
00144             IrpThread);
00145 
00146     /* Don't cancel the IRP if it's already been completed far */
00147     if (IopDeadIrp->CurrentLocation == (IopDeadIrp->StackCount + 2))
00148     {
00149         /* Return */
00150         KeReleaseQueuedSpinLock(LockQueueIoCompletionLock, LockIrql);
00151         KeLowerIrql(OldIrql);
00152         return;
00153     }
00154 
00155     /* Disown the IRP! */
00156     IopDeadIrp->Tail.Overlay.Thread = NULL;
00157     RemoveHeadList(&IrpThread->IrpList);
00158     InitializeListHead(&IopDeadIrp->ThreadListEntry);
00159 
00160     /* Get the stack location and check if it's valid */
00161     IoStackLocation = IoGetCurrentIrpStackLocation(IopDeadIrp);
00162     if (IopDeadIrp->CurrentLocation <= IopDeadIrp->StackCount)
00163     {
00164         /* Get the device object */
00165         DeviceObject = IoStackLocation->DeviceObject;
00166     }
00167 
00168     KeReleaseQueuedSpinLock(LockQueueIoCompletionLock, LockIrql);
00169     /* Lower IRQL now, since we have the pointers we need */
00170     KeLowerIrql(OldIrql);
00171 
00172     /* Check if we can send an Error Log Entry*/
00173     if (DeviceObject)
00174     {
00175         /* Allocate an entry */
00176         ErrorLogEntry = IoAllocateErrorLogEntry(DeviceObject,
00177                                                 sizeof(IO_ERROR_LOG_PACKET));
00178         if (ErrorLogEntry)
00179         {
00180             /* Write the entry */
00181             ErrorLogEntry->ErrorCode = IO_DRIVER_CANCEL_TIMEOUT;
00182             IoWriteErrorLogEntry(ErrorLogEntry);
00183         }
00184     }
00185 }
00186 
00187 VOID
00188 NTAPI
00189 IopCleanupIrp(IN PIRP Irp,
00190               IN PFILE_OBJECT FileObject)
00191 {
00192     PMDL Mdl;
00193     IOTRACE(IO_IRP_DEBUG,
00194             "%s - Cleaning IRP %p for %p\n",
00195             __FUNCTION__,
00196             Irp,
00197             FileObject);
00198 
00199     /* Check if there's an MDL */
00200     while ((Mdl = Irp->MdlAddress))
00201     {
00202         /* Clear all of them */
00203         Irp->MdlAddress = Mdl->Next;
00204         IoFreeMdl(Mdl);
00205     }
00206 
00207     /* Check if the IRP has system buffer */
00208     if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
00209     {
00210         /* Free the buffer */
00211         ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, TAG_SYS_BUF);
00212     }
00213 
00214     /* Check if this IRP has a user event, a file object, and is async */
00215     if ((Irp->UserEvent) &&
00216         !(Irp->Flags & IRP_SYNCHRONOUS_API) &&
00217         (FileObject))
00218     {
00219         /* Dereference the User Event */
00220         ObDereferenceObject(Irp->UserEvent);
00221     }
00222 
00223     /* Check if we have a file object and this isn't a create operation */
00224     if ((FileObject) && !(Irp->Flags & IRP_CREATE_OPERATION))
00225     {
00226         /* Dereference the file object */
00227         ObDereferenceObject(FileObject);
00228     }
00229 
00230     /* Free the IRP */
00231     IoFreeIrp(Irp);
00232 }
00233 
00234 VOID
00235 NTAPI
00236 IopCompleteRequest(IN PKAPC Apc,
00237                    IN PKNORMAL_ROUTINE* NormalRoutine,
00238                    IN PVOID* NormalContext,
00239                    IN PVOID* SystemArgument1,
00240                    IN PVOID* SystemArgument2)
00241 {
00242     PFILE_OBJECT FileObject;
00243     PIRP Irp;
00244     PMDL Mdl, NextMdl;
00245     PVOID Port = NULL, Key = NULL;
00246     BOOLEAN SignaledCreateRequest = FALSE;
00247 
00248     /* Get data from the APC */
00249     FileObject = (PFILE_OBJECT)*SystemArgument1;
00250     Irp = CONTAINING_RECORD(Apc, IRP, Tail.Apc);
00251     IOTRACE(IO_IRP_DEBUG,
00252             "%s - Completing IRP %p for %p\n",
00253             __FUNCTION__,
00254             Irp,
00255             FileObject);
00256 
00257     /* Sanity check */
00258     ASSERT(Irp->IoStatus.Status != (NTSTATUS)0xFFFFFFFF);
00259 
00260     /* Check if we have a file object */
00261     if (*SystemArgument2)
00262     {
00263         /* Check if we're reparsing */
00264         if ((Irp->IoStatus.Status == STATUS_REPARSE) &&
00265             (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT))
00266         {
00267             /* We should never get this yet */
00268             DPRINT1("Reparse support not yet present!\n");
00269             while (TRUE);
00270         }
00271     }
00272 
00273     /* Handle Buffered case first */
00274     if (Irp->Flags & IRP_BUFFERED_IO)
00275     {
00276         /* Check if we have an input buffer and if we succeeded */
00277         if ((Irp->Flags & IRP_INPUT_OPERATION) &&
00278             (Irp->IoStatus.Status != STATUS_VERIFY_REQUIRED) &&
00279             !(NT_ERROR(Irp->IoStatus.Status)))
00280         {
00281             /* Copy the buffer back to the user */
00282             RtlCopyMemory(Irp->UserBuffer,
00283                           Irp->AssociatedIrp.SystemBuffer,
00284                           Irp->IoStatus.Information);
00285         }
00286 
00287         /* Also check if we should de-allocate it */
00288         if (Irp->Flags & IRP_DEALLOCATE_BUFFER)
00289         {
00290             /* Deallocate it */
00291             ExFreePool(Irp->AssociatedIrp.SystemBuffer);
00292         }
00293     }
00294 
00295     /* Now we got rid of these two... */
00296     Irp->Flags &= ~(IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
00297 
00298     /* Check if there's an MDL */
00299     for (Mdl = Irp->MdlAddress; Mdl; Mdl = NextMdl)
00300     {
00301         /* Free it */
00302         NextMdl = Mdl->Next;
00303         IoFreeMdl(Mdl);
00304     }
00305 
00306     /* No MDLs left */
00307     Irp->MdlAddress = NULL;
00308 
00309     /*
00310      * Check if either the request was completed without any errors
00311      * (but warnings are OK!), or if it was completed with an error, but
00312      * did return from a pending I/O Operation and is not synchronous.
00313      */
00314     if (!(NT_ERROR(Irp->IoStatus.Status)) ||
00315          (NT_ERROR(Irp->IoStatus.Status) &&
00316           (Irp->PendingReturned) &&
00317           !(IsIrpSynchronous(Irp, FileObject))))
00318     {
00319         /* Get any information we need from the FO before we kill it */
00320         if ((FileObject) && (FileObject->CompletionContext))
00321         {
00322             /* Save Completion Data */
00323             Port = FileObject->CompletionContext->Port;
00324             Key = FileObject->CompletionContext->Key;
00325         }
00326 
00327         /* Use SEH to make sure we don't write somewhere invalid */
00328         _SEH2_TRY
00329         {
00330             /*  Save the IOSB Information */
00331             *Irp->UserIosb = Irp->IoStatus;
00332         }
00333         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00334         {
00335             /* Ignore any error */
00336         }
00337         _SEH2_END;
00338 
00339         /* Check if we have an event or a file object */
00340         if (Irp->UserEvent)
00341         {
00342             /* At the very least, this is a PKEVENT, so signal it always */
00343             KeSetEvent(Irp->UserEvent, 0, FALSE);
00344 
00345             /* Check if we also have a File Object */
00346             if (FileObject)
00347             {
00348                 /* Check if this is an Asynch API */
00349                 if (!(Irp->Flags & IRP_SYNCHRONOUS_API))
00350                 {
00351                     /* Dereference the event */
00352                     ObDereferenceObject(Irp->UserEvent);
00353                 }
00354 
00355                 /*
00356                  * Now, if this is a Synch I/O File Object, then this event is
00357                  * NOT an actual Executive Event, so we won't dereference it,
00358                  * and instead, we will signal the File Object
00359                  */
00360                 if ((FileObject->Flags & FO_SYNCHRONOUS_IO) &&
00361                     !(Irp->Flags & IRP_OB_QUERY_NAME))
00362                 {
00363                     /* Signal the file object and set the status */
00364                     KeSetEvent(&FileObject->Event, 0, FALSE);
00365                     FileObject->FinalStatus = Irp->IoStatus.Status;
00366                 }
00367 
00368                 /*
00369                  * This could also be a create operation, in which case we want
00370                  * to make sure there's no APC fired.
00371                  */
00372                 if (Irp->Flags & IRP_CREATE_OPERATION)
00373                 {
00374                     /* Clear the APC Routine and remember this */
00375                     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
00376                     SignaledCreateRequest = TRUE;
00377                 }
00378             }
00379         }
00380         else if (FileObject)
00381         {
00382             /* Signal the file object and set the status */
00383             KeSetEvent(&FileObject->Event, 0, FALSE);
00384             FileObject->FinalStatus = Irp->IoStatus.Status;
00385 
00386             /*
00387             * This could also be a create operation, in which case we want
00388             * to make sure there's no APC fired.
00389             */
00390             if (Irp->Flags & IRP_CREATE_OPERATION)
00391             {
00392                 /* Clear the APC Routine and remember this */
00393                 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
00394                 SignaledCreateRequest = TRUE;
00395             }
00396         }
00397 
00398         /* Update transfer count for everything but create operation */
00399         if (!(Irp->Flags & IRP_CREATE_OPERATION))
00400         {
00401             if (Irp->Flags & IRP_WRITE_OPERATION)
00402             {
00403                 /* Update write transfer count */
00404                 IopUpdateTransferCount(IopWriteTransfer,
00405                                        (ULONG)Irp->IoStatus.Information);
00406             }
00407             else if (Irp->Flags & IRP_READ_OPERATION)
00408             {
00409                 /* Update read transfer count */
00410                 IopUpdateTransferCount(IopReadTransfer,
00411                                        (ULONG)Irp->IoStatus.Information);
00412             }
00413             else
00414             {
00415                 /* Update other transfer count */
00416                 IopUpdateTransferCount(IopOtherTransfer,
00417                                        (ULONG)Irp->IoStatus.Information);
00418             }
00419         }
00420 
00421         /* Now that we've signaled the events, de-associate the IRP */
00422         IopUnQueueIrpFromThread(Irp);
00423 
00424         /* Now check if a User APC Routine was requested */
00425         if (Irp->Overlay.AsynchronousParameters.UserApcRoutine)
00426         {
00427             /* Initialize it */
00428             KeInitializeApc(&Irp->Tail.Apc,
00429                             KeGetCurrentThread(),
00430                             CurrentApcEnvironment,
00431                             IopFreeIrpKernelApc,
00432                             IopAbortIrpKernelApc,
00433                             (PKNORMAL_ROUTINE)Irp->
00434                             Overlay.AsynchronousParameters.UserApcRoutine,
00435                             Irp->RequestorMode,
00436                             Irp->
00437                             Overlay.AsynchronousParameters.UserApcContext);
00438 
00439             /* Queue it */
00440             KeInsertQueueApc(&Irp->Tail.Apc, Irp->UserIosb, NULL, 2);
00441         }
00442         else if ((Port) &&
00443                  (Irp->Overlay.AsynchronousParameters.UserApcContext))
00444         {
00445             /* We have an I/O Completion setup... create the special Overlay */
00446             Irp->Tail.CompletionKey = Key;
00447             Irp->Tail.Overlay.PacketType = IopCompletionPacketIrp;
00448             KeInsertQueue(Port, &Irp->Tail.Overlay.ListEntry);
00449         }
00450         else
00451         {
00452             /* Free the IRP since we don't need it anymore */
00453             IoFreeIrp(Irp);
00454         }
00455 
00456         /* Check if we have a file object that wasn't part of a create */
00457         if ((FileObject) && !(SignaledCreateRequest))
00458         {
00459             /* Dereference it, since it's not needed anymore either */
00460             ObDereferenceObjectDeferDelete(FileObject);
00461         }
00462     }
00463     else
00464     {
00465         /*
00466          * Either we didn't return from the request, or we did return but this
00467          * request was synchronous.
00468          */
00469         if ((Irp->PendingReturned) && (FileObject))
00470         {
00471             /* So we did return with a synch operation, was it the IRP? */
00472             if (Irp->Flags & IRP_SYNCHRONOUS_API)
00473             {
00474                 /* Yes, this IRP was synchronous, so return the I/O Status */
00475                 *Irp->UserIosb = Irp->IoStatus;
00476 
00477                 /* Now check if the user gave an event */
00478                 if (Irp->UserEvent)
00479                 {
00480                     /* Signal it */
00481                     KeSetEvent(Irp->UserEvent, 0, FALSE);
00482                 }
00483                 else
00484                 {
00485                     /* No event was given, so signal the FO instead */
00486                     KeSetEvent(&FileObject->Event, 0, FALSE);
00487                 }
00488             }
00489             else
00490             {
00491                 /*
00492                  * It's not the IRP that was synchronous, it was the FO
00493                  * that was opened this way. Signal its event.
00494                  */
00495                 FileObject->FinalStatus = Irp->IoStatus.Status;
00496                 KeSetEvent(&FileObject->Event, 0, FALSE);
00497             }
00498         }
00499 
00500         /* Now that we got here, we do this for incomplete I/Os as well */
00501         if ((FileObject) && !(Irp->Flags & IRP_CREATE_OPERATION))
00502         {
00503             /* Dereference the File Object unless this was a create */
00504             ObDereferenceObjectDeferDelete(FileObject);
00505         }
00506 
00507         /*
00508          * Check if this was an Executive Event (remember that we know this
00509          * by checking if the IRP is synchronous)
00510          */
00511         if ((Irp->UserEvent) &&
00512             (FileObject) &&
00513             !(Irp->Flags & IRP_SYNCHRONOUS_API))
00514         {
00515             /* This isn't a PKEVENT, so dereference it */
00516             ObDereferenceObject(Irp->UserEvent);
00517         }
00518 
00519         /* Now that we've signaled the events, de-associate the IRP */
00520         IopUnQueueIrpFromThread(Irp);
00521 
00522         /* Free the IRP as well */
00523         IoFreeIrp(Irp);
00524     }
00525 }
00526 
00527 /* FUNCTIONS *****************************************************************/
00528 
00529 /*
00530  * @implemented
00531  */
00532 PIRP
00533 NTAPI
00534 IoAllocateIrp(IN CCHAR StackSize,
00535               IN BOOLEAN ChargeQuota)
00536 {
00537     PIRP Irp = NULL;
00538     USHORT Size = IoSizeOfIrp(StackSize);
00539     PKPRCB Prcb;
00540     UCHAR Flags = 0;
00541     PNPAGED_LOOKASIDE_LIST List = NULL;
00542     PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList;
00543 
00544     /* Set Charge Quota Flag */
00545     if (ChargeQuota) Flags |= IRP_QUOTA_CHARGED;
00546 
00547     /* FIXME: Implement Lookaside Floats */
00548 
00549     /* Figure out which Lookaside List to use */
00550     if ((StackSize <= 8) && (ChargeQuota == FALSE))
00551     {
00552         /* Set Fixed Size Flag */
00553         Flags = IRP_ALLOCATED_FIXED_SIZE;
00554 
00555         /* See if we should use big list */
00556         if (StackSize != 1)
00557         {
00558             Size = IoSizeOfIrp(8);
00559             ListType = LookasideLargeIrpList;
00560         }
00561 
00562         /* Get the PRCB */
00563         Prcb = KeGetCurrentPrcb();
00564 
00565         /* Get the P List First */
00566         List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;
00567 
00568         /* Attempt allocation */
00569         List->L.TotalAllocates++;
00570         Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
00571 
00572         /* Check if the P List failed */
00573         if (!Irp)
00574         {
00575             /* Let the balancer know */
00576             List->L.AllocateMisses++;
00577 
00578             /* Try the L List */
00579             List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;
00580             List->L.TotalAllocates++;
00581             Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);
00582         }
00583     }
00584 
00585     /* Check if we have to use the pool */
00586     if (!Irp)
00587     {
00588         /* Did we try lookaside and fail? */
00589         if (Flags & IRP_ALLOCATED_FIXED_SIZE) List->L.AllocateMisses++;
00590 
00591         /* Check if we should charge quota */
00592         if (ChargeQuota)
00593         {
00594             /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool, Size, TAG_IRP); */
00595             /* FIXME */
00596             Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
00597         }
00598         else
00599         {
00600             /* Allocate the IRP With no Quota charge */
00601             Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);
00602         }
00603 
00604         /* Make sure it was sucessful */
00605         if (!Irp) return(NULL);
00606     }
00607     else
00608     {
00609         /* In this case there is no charge quota */
00610         Flags &= ~IRP_QUOTA_CHARGED;
00611     }
00612 
00613     /* Now Initialize it */
00614     IoInitializeIrp(Irp, Size, StackSize);
00615 
00616     /* Set the Allocation Flags */
00617     Irp->AllocationFlags = Flags;
00618 
00619     /* Return it */
00620     IOTRACE(IO_IRP_DEBUG,
00621             "%s - Allocated IRP %p with allocation flags %lx\n",
00622             __FUNCTION__,
00623             Irp,
00624             Flags);
00625     return Irp;
00626 }
00627 
00628 /*
00629  * @implemented
00630  */
00631 PIRP
00632 NTAPI
00633 IoBuildAsynchronousFsdRequest(IN ULONG MajorFunction,
00634                               IN PDEVICE_OBJECT DeviceObject,
00635                               IN PVOID Buffer,
00636                               IN ULONG Length,
00637                               IN PLARGE_INTEGER StartingOffset,
00638                               IN PIO_STATUS_BLOCK IoStatusBlock)
00639 {
00640     PIRP Irp;
00641     PIO_STACK_LOCATION StackPtr;
00642 
00643     /* Allocate IRP */
00644     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
00645     if (!Irp) return NULL;
00646 
00647     /* Get the Stack */
00648     StackPtr = IoGetNextIrpStackLocation(Irp);
00649 
00650     /* Write the Major function and then deal with it */
00651     StackPtr->MajorFunction = (UCHAR)MajorFunction;
00652 
00653     /* Do not handle the following here */
00654     if ((MajorFunction != IRP_MJ_FLUSH_BUFFERS) &&
00655         (MajorFunction != IRP_MJ_SHUTDOWN) &&
00656         (MajorFunction != IRP_MJ_PNP) &&
00657         (MajorFunction != IRP_MJ_POWER))
00658     {
00659         /* Check if this is Buffered IO */
00660         if (DeviceObject->Flags & DO_BUFFERED_IO)
00661         {
00662             /* Allocate the System Buffer */
00663             Irp->AssociatedIrp.SystemBuffer =
00664                 ExAllocatePoolWithTag(NonPagedPool, Length, TAG_SYS_BUF);
00665             if (!Irp->AssociatedIrp.SystemBuffer)
00666             {
00667                 /* Free the IRP and fail */
00668                 IoFreeIrp(Irp);
00669                 return NULL;
00670             }
00671 
00672             /* Set flags */
00673             Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
00674 
00675             /* Handle special IRP_MJ_WRITE Case */
00676             if (MajorFunction == IRP_MJ_WRITE)
00677             {
00678                 /* Copy the buffer data */
00679                 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);
00680             }
00681             else
00682             {
00683                 /* Set the Input Operation flag and set this as a User Buffer */
00684                 Irp->Flags |= IRP_INPUT_OPERATION;
00685                 Irp->UserBuffer = Buffer;
00686             }
00687         }
00688         else if (DeviceObject->Flags & DO_DIRECT_IO)
00689         {
00690             /* Use an MDL for Direct I/O */
00691             Irp->MdlAddress = IoAllocateMdl(Buffer,
00692                                             Length,
00693                                             FALSE,
00694                                             FALSE,
00695                                             NULL);
00696             if (!Irp->MdlAddress)
00697             {
00698                 /* Free the IRP and fail */
00699                 IoFreeIrp(Irp);
00700                 return NULL;
00701             }
00702 
00703             /* Probe and Lock */
00704             _SEH2_TRY
00705             {
00706                 /* Do the probe */
00707                 MmProbeAndLockPages(Irp->MdlAddress,
00708                                     KernelMode,
00709                                     MajorFunction == IRP_MJ_READ ?
00710                                     IoWriteAccess : IoReadAccess);
00711             }
00712             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00713             {
00714                 /* Free the IRP and its MDL */
00715                 IoFreeMdl(Irp->MdlAddress);
00716                 IoFreeIrp(Irp);
00717 
00718                 /* Fail */
00719                 _SEH2_YIELD(return NULL);
00720             }
00721             _SEH2_END;
00722         }
00723         else
00724         {
00725             /* Neither, use the buffer */
00726             Irp->UserBuffer = Buffer;
00727         }
00728 
00729         /* Check if this is a read */
00730         if (MajorFunction == IRP_MJ_READ)
00731         {
00732             /* Set the parameters for a read */
00733             StackPtr->Parameters.Read.Length = Length;
00734             StackPtr->Parameters.Read.ByteOffset = *StartingOffset;
00735         }
00736         else if (MajorFunction == IRP_MJ_WRITE)
00737         {
00738             /* Otherwise, set write parameters */
00739             StackPtr->Parameters.Write.Length = Length;
00740             StackPtr->Parameters.Write.ByteOffset = *StartingOffset;
00741         }
00742     }
00743 
00744     /* Set the Current Thread and IOSB */
00745     Irp->UserIosb = IoStatusBlock;
00746     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
00747 
00748     /* Return the IRP */
00749     IOTRACE(IO_IRP_DEBUG,
00750             "%s - Built IRP %p with Major, Buffer, DO %lx %p %p\n",
00751             __FUNCTION__,
00752             Irp,
00753             MajorFunction,
00754             Buffer,
00755             DeviceObject);
00756     return Irp;
00757 }
00758 
00759 /*
00760  * @implemented
00761  */
00762 PIRP
00763 NTAPI
00764 IoBuildDeviceIoControlRequest(IN ULONG IoControlCode,
00765                               IN PDEVICE_OBJECT DeviceObject,
00766                               IN PVOID InputBuffer,
00767                               IN ULONG InputBufferLength,
00768                               IN PVOID OutputBuffer,
00769                               IN ULONG OutputBufferLength,
00770                               IN BOOLEAN InternalDeviceIoControl,
00771                               IN PKEVENT Event,
00772                               IN PIO_STATUS_BLOCK IoStatusBlock)
00773 {
00774     PIRP Irp;
00775     PIO_STACK_LOCATION StackPtr;
00776     ULONG BufferLength;
00777 
00778     /* Allocate IRP */
00779     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
00780     if (!Irp) return NULL;
00781 
00782     /* Get the Stack */
00783     StackPtr = IoGetNextIrpStackLocation(Irp);
00784 
00785     /* Set the DevCtl Type */
00786     StackPtr->MajorFunction = InternalDeviceIoControl ?
00787                               IRP_MJ_INTERNAL_DEVICE_CONTROL :
00788                               IRP_MJ_DEVICE_CONTROL;
00789 
00790     /* Set the IOCTL Data */
00791     StackPtr->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
00792     StackPtr->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
00793     StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
00794         OutputBufferLength;
00795 
00796     /* Handle the Methods */
00797     switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
00798     {
00799         /* Buffered I/O */
00800         case METHOD_BUFFERED:
00801 
00802             /* Select the right Buffer Length */
00803             BufferLength = InputBufferLength > OutputBufferLength ?
00804                            InputBufferLength : OutputBufferLength;
00805 
00806             /* Make sure there is one */
00807             if (BufferLength)
00808             {
00809                 /* Allocate the System Buffer */
00810                 Irp->AssociatedIrp.SystemBuffer =
00811                     ExAllocatePoolWithTag(NonPagedPool,
00812                                           BufferLength,
00813                                           TAG_SYS_BUF);
00814                 if (!Irp->AssociatedIrp.SystemBuffer)
00815                 {
00816                     /* Free the IRP and fail */
00817                     IoFreeIrp(Irp);
00818                     return NULL;
00819                 }
00820 
00821                 /* Check if we got a buffer */
00822                 if (InputBuffer)
00823                 {
00824                     /* Copy into the System Buffer */
00825                     RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
00826                                   InputBuffer,
00827                                   InputBufferLength);
00828                 }
00829 
00830                 /* Write the flags */
00831                 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
00832                 if (OutputBuffer) Irp->Flags |= IRP_INPUT_OPERATION;
00833 
00834                 /* Save the Buffer */
00835                 Irp->UserBuffer = OutputBuffer;
00836             }
00837             else
00838             {
00839                 /* Clear the Flags and Buffer */
00840                 Irp->Flags = 0;
00841                 Irp->UserBuffer = NULL;
00842             }
00843             break;
00844 
00845         /* Direct I/O */
00846         case METHOD_IN_DIRECT:
00847         case METHOD_OUT_DIRECT:
00848 
00849             /* Check if we got an input buffer */
00850             if (InputBuffer)
00851             {
00852                 /* Allocate the System Buffer */
00853                 Irp->AssociatedIrp.SystemBuffer =
00854                     ExAllocatePoolWithTag(NonPagedPool,
00855                                           InputBufferLength,
00856                                           TAG_SYS_BUF);
00857                 if (!Irp->AssociatedIrp.SystemBuffer)
00858                 {
00859                     /* Free the IRP and fail */
00860                     IoFreeIrp(Irp);
00861                     return NULL;
00862                 }
00863 
00864                 /* Copy into the System Buffer */
00865                 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
00866                               InputBuffer,
00867                               InputBufferLength);
00868 
00869                 /* Write the flags */
00870                 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
00871             }
00872             else
00873             {
00874                 /* Clear the flags */
00875                 Irp->Flags = 0;
00876             }
00877 
00878             /* Check if we got an output buffer */
00879             if (OutputBuffer)
00880             {
00881                 /* Allocate the System Buffer */
00882                 Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
00883                                                 OutputBufferLength,
00884                                                 FALSE,
00885                                                 FALSE,
00886                                                 Irp);
00887                 if (!Irp->MdlAddress)
00888                 {
00889                     /* Free the IRP and fail */
00890                     IoFreeIrp(Irp);
00891                     return NULL;
00892                 }
00893 
00894                 /* Probe and Lock */
00895                 _SEH2_TRY
00896                 {
00897                     /* Do the probe */
00898                     MmProbeAndLockPages(Irp->MdlAddress,
00899                                         KernelMode,
00900                                         IO_METHOD_FROM_CTL_CODE(IoControlCode) ==
00901                                         METHOD_IN_DIRECT ?
00902                                         IoReadAccess : IoWriteAccess);
00903                 }
00904                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00905                 {
00906                     /* Free the MDL */
00907                     IoFreeMdl(Irp->MdlAddress);
00908 
00909                     /* Free the input buffer and IRP */
00910                     if (InputBuffer) ExFreePool(Irp->AssociatedIrp.SystemBuffer);
00911                     IoFreeIrp(Irp);
00912 
00913                     /* Fail */
00914                     _SEH2_YIELD(return NULL);
00915                 }
00916                 _SEH2_END;
00917             }
00918             break;
00919 
00920         case METHOD_NEITHER:
00921 
00922             /* Just save the Buffer */
00923             Irp->UserBuffer = OutputBuffer;
00924             StackPtr->Parameters.DeviceIoControl.Type3InputBuffer = InputBuffer;
00925     }
00926 
00927     /* Now write the Event and IoSB */
00928     Irp->UserIosb = IoStatusBlock;
00929     Irp->UserEvent = Event;
00930 
00931     /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
00932     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
00933     IoQueueThreadIrp(Irp);
00934 
00935     /* Return the IRP */
00936     IOTRACE(IO_IRP_DEBUG,
00937             "%s - Built IRP %p with IOCTL, Buffers, DO %lx %p %p %p\n",
00938             __FUNCTION__,
00939             Irp,
00940             IoControlCode,
00941             InputBuffer,
00942             OutputBuffer,
00943             DeviceObject);
00944     return Irp;
00945 }
00946 
00947 /*
00948  * @implemented
00949  */
00950 PIRP
00951 NTAPI
00952 IoBuildSynchronousFsdRequest(IN ULONG MajorFunction,
00953                              IN PDEVICE_OBJECT DeviceObject,
00954                              IN PVOID Buffer,
00955                              IN ULONG Length,
00956                              IN PLARGE_INTEGER StartingOffset,
00957                              IN PKEVENT Event,
00958                              IN PIO_STATUS_BLOCK IoStatusBlock)
00959 {
00960     PIRP Irp;
00961 
00962     /* Do the big work to set up the IRP */
00963     Irp = IoBuildAsynchronousFsdRequest(MajorFunction,
00964                                         DeviceObject,
00965                                         Buffer,
00966                                         Length,
00967                                         StartingOffset,
00968                                         IoStatusBlock );
00969     if (!Irp) return NULL;
00970 
00971     /* Set the Event which makes it Syncronous */
00972     Irp->UserEvent = Event;
00973 
00974     /* Sync IRPs are queued to requestor thread's irp cancel/cleanup list */
00975     IoQueueThreadIrp(Irp);
00976     return Irp;
00977 }
00978 
00979 /*
00980  * @implemented
00981  */
00982 BOOLEAN
00983 NTAPI
00984 IoCancelIrp(IN PIRP Irp)
00985 {
00986     KIRQL OldIrql;
00987     PDRIVER_CANCEL CancelRoutine;
00988     IOTRACE(IO_IRP_DEBUG,
00989             "%s - Canceling IRP %p\n",
00990             __FUNCTION__,
00991             Irp);
00992     ASSERT(Irp->Type == IO_TYPE_IRP);
00993 
00994     /* Acquire the cancel lock and cancel the IRP */
00995     IoAcquireCancelSpinLock(&OldIrql);
00996     Irp->Cancel = TRUE;
00997 
00998     /* Clear the cancel routine and get the old one */
00999     CancelRoutine = (PVOID)IoSetCancelRoutine(Irp, NULL);
01000     if (CancelRoutine)
01001     {
01002         /* We had a routine, make sure the IRP isn't completed */
01003         if (Irp->CurrentLocation > (Irp->StackCount + 1))
01004         {
01005             /* It is, bugcheck */
01006             KeBugCheckEx(CANCEL_STATE_IN_COMPLETED_IRP,
01007                          (ULONG_PTR)Irp,
01008                          (ULONG_PTR)CancelRoutine,
01009                          0,
01010                          0);
01011         }
01012 
01013         /* Set the cancel IRQL And call the routine */
01014         Irp->CancelIrql = OldIrql;
01015         CancelRoutine(IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Irp);
01016         return TRUE;
01017     }
01018 
01019     /* Otherwise, release the cancel lock and fail */
01020     IoReleaseCancelSpinLock(OldIrql);
01021     return FALSE;
01022 }
01023 
01024 /*
01025  * @implemented
01026  */
01027 VOID
01028 NTAPI
01029 IoCancelThreadIo(IN PETHREAD Thread)
01030 {
01031     KIRQL OldIrql;
01032     ULONG Retries = 3000;
01033     LARGE_INTEGER Interval;
01034     PLIST_ENTRY ListHead, NextEntry;
01035     PIRP Irp;
01036     PAGED_CODE();
01037 
01038     /* Windows isn't using given thread, but using current. */
01039     Thread = PsGetCurrentThread();
01040 
01041     IOTRACE(IO_IRP_DEBUG,
01042             "%s - Canceling IRPs for Thread %p\n",
01043             __FUNCTION__,
01044             Thread);
01045 
01046     /* Raise to APC to protect the IrpList */
01047     KeRaiseIrql(APC_LEVEL, &OldIrql);
01048 
01049     /* Start by cancelling all the IRPs in the current thread queue. */
01050     ListHead = &Thread->IrpList;
01051     NextEntry = ListHead->Flink;
01052     while (ListHead != NextEntry)
01053     {
01054         /* Get the IRP */
01055         Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
01056 
01057         /* Cancel it */
01058         IoCancelIrp(Irp);
01059 
01060         /* Move to the next entry */
01061         NextEntry = NextEntry->Flink;
01062     }
01063 
01064      /* Wait 100 milliseconds */
01065     Interval.QuadPart = -1000000;
01066 
01067     /* Wait till all the IRPs are completed or cancelled. */
01068     while (!IsListEmpty(&Thread->IrpList))
01069     {
01070         /* Now we can lower */
01071         KeLowerIrql(OldIrql);
01072 
01073         /* Wait a short while and then look if all our IRPs were completed. */
01074         KeDelayExecutionThread(KernelMode, FALSE, &Interval);
01075 
01076         /*
01077          * Don't stay here forever if some broken driver doesn't complete
01078          * the IRP.
01079          */
01080         if (!(Retries--))
01081         {
01082             /* Print out a message and remove the IRP */
01083             DPRINT1("Broken driver did not complete!\n");
01084             IopDisassociateThreadIrp();
01085         }
01086 
01087         /* Raise the IRQL Again */
01088         KeRaiseIrql(APC_LEVEL, &OldIrql);
01089     }
01090 
01091     /* We're done, lower the IRQL */
01092     KeLowerIrql(OldIrql);
01093 }
01094 
01095 /*
01096  * @implemented
01097  */
01098 #undef IoCallDriver
01099 NTSTATUS
01100 NTAPI
01101 IoCallDriver(IN PDEVICE_OBJECT DeviceObject,
01102              IN PIRP Irp)
01103 {
01104     /* Call fastcall */
01105     return IofCallDriver(DeviceObject, Irp);
01106 }
01107 
01108 #define IoCallDriver IofCallDriver
01109 
01110 /*
01111  * @implemented
01112  */
01113 #undef IoCompleteRequest
01114 VOID
01115 NTAPI
01116 IoCompleteRequest(IN PIRP Irp,
01117                   IN CCHAR PriorityBoost)
01118 {
01119     /* Call the fastcall */
01120     IofCompleteRequest(Irp, PriorityBoost);
01121 }
01122 
01123 #define IoCompleteRequest IofCompleteRequest
01124 
01125 /*
01126  * @implemented
01127  */
01128 VOID
01129 NTAPI
01130 IoEnqueueIrp(IN PIRP Irp)
01131 {
01132     /* This is the same as calling IoQueueThreadIrp */
01133     IoQueueThreadIrp(Irp);
01134 }
01135 
01136 /*
01137  * @implemented
01138  */
01139 NTSTATUS
01140 FASTCALL
01141 IofCallDriver(IN PDEVICE_OBJECT DeviceObject,
01142               IN PIRP Irp)
01143 {
01144     PDRIVER_OBJECT DriverObject;
01145     PIO_STACK_LOCATION StackPtr;
01146 
01147     /* Make sure this is a valid IRP */
01148     ASSERT(Irp->Type == IO_TYPE_IRP);
01149 
01150     /* Get the Driver Object */
01151     DriverObject = DeviceObject->DriverObject;
01152 
01153     /* Decrease the current location and check if */
01154     Irp->CurrentLocation--;
01155     if (Irp->CurrentLocation <= 0)
01156     {
01157         /* This IRP ran out of stack, bugcheck */
01158         KeBugCheckEx(NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR)Irp, 0, 0, 0);
01159     }
01160 
01161     /* Now update the stack location */
01162     StackPtr = IoGetNextIrpStackLocation(Irp);
01163     Irp->Tail.Overlay.CurrentStackLocation = StackPtr;
01164 
01165     /* Get the Device Object */
01166     StackPtr->DeviceObject = DeviceObject;
01167 
01168     /* Call it */
01169     return DriverObject->MajorFunction[StackPtr->MajorFunction](DeviceObject,
01170                                                                 Irp);
01171 }
01172 
01173 FORCEINLINE
01174 VOID
01175 IopClearStackLocation(IN PIO_STACK_LOCATION IoStackLocation)
01176 {
01177     IoStackLocation->MinorFunction = 0;
01178     IoStackLocation->Flags = 0;
01179     IoStackLocation->Control &= SL_ERROR_RETURNED;
01180     IoStackLocation->Parameters.Others.Argument1 = 0;
01181     IoStackLocation->Parameters.Others.Argument2 = 0;
01182     IoStackLocation->Parameters.Others.Argument3 = 0;
01183     IoStackLocation->FileObject = NULL;
01184 }
01185 
01186 /*
01187  * @implemented
01188  */
01189 VOID
01190 FASTCALL
01191 IofCompleteRequest(IN PIRP Irp,
01192                    IN CCHAR PriorityBoost)
01193 {
01194     PIO_STACK_LOCATION StackPtr, LastStackPtr;
01195     PDEVICE_OBJECT DeviceObject;
01196     PFILE_OBJECT FileObject;
01197     PETHREAD Thread;
01198     NTSTATUS Status;
01199     PMDL Mdl, NextMdl;
01200     ULONG MasterCount;
01201     PIRP MasterIrp;
01202     ULONG Flags;
01203     NTSTATUS ErrorCode = STATUS_SUCCESS;
01204     IOTRACE(IO_IRP_DEBUG,
01205             "%s - Completing IRP %p\n",
01206             __FUNCTION__,
01207             Irp);
01208 
01209     /* Make sure this IRP isn't getting completed twice or is invalid */
01210     if ((Irp->CurrentLocation) > (Irp->StackCount + 1))
01211     {
01212         /* Bugcheck */
01213         KeBugCheckEx(MULTIPLE_IRP_COMPLETE_REQUESTS, (ULONG_PTR)Irp, 0, 0, 0);
01214     }
01215 
01216     /* Some sanity checks */
01217     ASSERT(Irp->Type == IO_TYPE_IRP);
01218     ASSERT(!Irp->CancelRoutine);
01219     ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
01220     ASSERT(Irp->IoStatus.Status != (NTSTATUS)0xFFFFFFFF);
01221 
01222     /* Get the last stack */
01223     LastStackPtr = (PIO_STACK_LOCATION)(Irp + 1);
01224     if (LastStackPtr->Control & SL_ERROR_RETURNED)
01225     {
01226         /* Get the error code */
01227         ErrorCode = PtrToUlong(LastStackPtr->Parameters.Others.Argument4);
01228     }
01229 
01230     /*
01231      * Start the loop with the current stack and point the IRP to the next stack
01232      * and then keep incrementing the stack as we loop through. The IRP should
01233      * always point to the next stack location w.r.t the one currently being
01234      * analyzed, so completion routine code will see the appropriate value.
01235      * Because of this, we must loop until the current stack location is +1 of
01236      * the stack count, because when StackPtr is at the end, CurrentLocation is +1.
01237      */
01238     for (StackPtr = IoGetCurrentIrpStackLocation(Irp),
01239          Irp->CurrentLocation++,
01240          Irp->Tail.Overlay.CurrentStackLocation++;
01241          Irp->CurrentLocation <= (Irp->StackCount + 1);
01242          StackPtr++,
01243          Irp->CurrentLocation++,
01244          Irp->Tail.Overlay.CurrentStackLocation++)
01245     {
01246         /* Set Pending Returned */
01247         Irp->PendingReturned = StackPtr->Control & SL_PENDING_RETURNED;
01248 
01249         /* Check if we failed */
01250         if (!NT_SUCCESS(Irp->IoStatus.Status))
01251         {
01252             /* Check if it was changed by a completion routine */
01253             if (Irp->IoStatus.Status != ErrorCode)
01254             {
01255                 /* Update the error for the current stack */
01256                 ErrorCode = Irp->IoStatus.Status;
01257                 StackPtr->Control |= SL_ERROR_RETURNED;
01258                 LastStackPtr->Parameters.Others.Argument4 = UlongToPtr(ErrorCode);
01259                 LastStackPtr->Control |= SL_ERROR_RETURNED;
01260             }
01261         }
01262 
01263         /* Check if there is a Completion Routine to Call */
01264         if ((NT_SUCCESS(Irp->IoStatus.Status) &&
01265              (StackPtr->Control & SL_INVOKE_ON_SUCCESS)) ||
01266             (!NT_SUCCESS(Irp->IoStatus.Status) &&
01267              (StackPtr->Control & SL_INVOKE_ON_ERROR)) ||
01268             (Irp->Cancel &&
01269              (StackPtr->Control & SL_INVOKE_ON_CANCEL)))
01270         {
01271             /* Clear the stack location */
01272             IopClearStackLocation(StackPtr);
01273 
01274             /* Check for highest-level device completion routines */
01275             if (Irp->CurrentLocation == (Irp->StackCount + 1))
01276             {
01277                 /* Clear the DO, since the current stack location is invalid */
01278                 DeviceObject = NULL;
01279             }
01280             else
01281             {
01282                 /* Otherwise, return the real one */
01283                 DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
01284             }
01285 
01286             /* Call the completion routine */
01287             Status = StackPtr->CompletionRoutine(DeviceObject,
01288                                                  Irp,
01289                                                  StackPtr->Context);
01290 
01291             /* Don't touch the Packet in this case, since it might be gone! */
01292             if (Status == STATUS_MORE_PROCESSING_REQUIRED) return;
01293         }
01294         else
01295         {
01296             /* Otherwise, check if this is a completed IRP */
01297             if ((Irp->CurrentLocation <= Irp->StackCount) &&
01298                 (Irp->PendingReturned))
01299             {
01300                 /* Mark it as pending */
01301                 IoMarkIrpPending(Irp);
01302             }
01303 
01304             /* Clear the stack location */
01305             IopClearStackLocation(StackPtr);
01306         }
01307     }
01308 
01309     /* Check if the IRP is an associated IRP */
01310     if (Irp->Flags & IRP_ASSOCIATED_IRP)
01311     {
01312         /* Get the master IRP and count */
01313         MasterIrp = Irp->AssociatedIrp.MasterIrp;
01314         MasterCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount);
01315 
01316         /* Free the MDLs */
01317         for (Mdl = Irp->MdlAddress; Mdl; Mdl = NextMdl)
01318         {
01319             /* Go to the next one */
01320             NextMdl = Mdl->Next;
01321             IoFreeMdl(Mdl);
01322         }
01323 
01324         /* Free the IRP itself */
01325         IoFreeIrp(Irp);
01326 
01327         /* Complete the Master IRP */
01328         if (!MasterCount) IofCompleteRequest(MasterIrp, PriorityBoost);
01329         return;
01330     }
01331 
01332     /* We don't support this yet */
01333     ASSERT(Irp->IoStatus.Status != STATUS_REPARSE);
01334 
01335     /* Check if we have an auxiliary buffer */
01336     if (Irp->Tail.Overlay.AuxiliaryBuffer)
01337     {
01338         /* Free it */
01339         ExFreePool(Irp->Tail.Overlay.AuxiliaryBuffer);
01340         Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
01341     }
01342 
01343     /* Check if this is a Paging I/O or Close Operation */
01344     if (Irp->Flags & (IRP_PAGING_IO | IRP_CLOSE_OPERATION))
01345     {
01346         /* Handle a Close Operation or Sync Paging I/O */
01347         if (Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_CLOSE_OPERATION))
01348         {
01349             /* Set the I/O Status and Signal the Event */
01350             Flags = Irp->Flags & (IRP_SYNCHRONOUS_PAGING_IO | IRP_PAGING_IO);
01351             *Irp->UserIosb = Irp->IoStatus;
01352             KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE);
01353 
01354             /* Free the IRP for a Paging I/O Only, Close is handled by us */
01355             if (Flags) IoFreeIrp(Irp);
01356         }
01357         else
01358         {
01359 #if 0
01360             /* Page 166 */
01361             KeInitializeApc(&Irp->Tail.Apc
01362                             &Irp->Tail.Overlay.Thread->Tcb,
01363                             Irp->ApcEnvironment,
01364                             IopCompletePageWrite,
01365                             NULL,
01366                             NULL,
01367                             KernelMode,
01368                             NULL);
01369             KeInsertQueueApc(&Irp->Tail.Apc,
01370                              NULL,
01371                              NULL,
01372                              PriorityBoost);
01373 #else
01374             /* Not implemented yet. */
01375             DPRINT1("Not supported!\n");
01376             while (TRUE);
01377 #endif
01378         }
01379 
01380         /* Get out of here */
01381         return;
01382     }
01383 
01384     /* Unlock MDL Pages, page 167. */
01385     Mdl = Irp->MdlAddress;
01386     while (Mdl)
01387     {
01388         MmUnlockPages(Mdl);
01389         Mdl = Mdl->Next;
01390     }
01391 
01392     /* Check if we should exit because of a Deferred I/O (page 168) */
01393     if ((Irp->Flags & IRP_DEFER_IO_COMPLETION) && !(Irp->PendingReturned))
01394     {
01395         /*
01396          * Return without queuing the completion APC, since the caller will
01397          * take care of doing its own optimized completion at PASSIVE_LEVEL.
01398          */
01399         return;
01400     }
01401 
01402     /* Get the thread and file object */
01403     Thread = Irp->Tail.Overlay.Thread;
01404     FileObject = Irp->Tail.Overlay.OriginalFileObject;
01405 
01406     /* Make sure the IRP isn't canceled */
01407     if (!Irp->Cancel)
01408     {
01409         /* Initialize the APC */
01410         KeInitializeApc(&Irp->Tail.Apc,
01411                         &Thread->Tcb,
01412                         Irp->ApcEnvironment,
01413                         IopCompleteRequest,
01414                         NULL,
01415                         NULL,
01416                         KernelMode,
01417                         NULL);
01418 
01419         /* Queue it */
01420         KeInsertQueueApc(&Irp->Tail.Apc,
01421                          FileObject,
01422                          NULL, /* This is used for REPARSE stuff */
01423                          PriorityBoost);
01424     }
01425     else
01426     {
01427         /* The IRP just got canceled... does a thread still own it? */
01428         if (Thread)
01429         {
01430             /* Yes! There is still hope! Initialize the APC */
01431             KeInitializeApc(&Irp->Tail.Apc,
01432                             &Thread->Tcb,
01433                             Irp->ApcEnvironment,
01434                             IopCompleteRequest,
01435                             NULL,
01436                             NULL,
01437                             KernelMode,
01438                             NULL);
01439 
01440             /* Queue it */
01441             KeInsertQueueApc(&Irp->Tail.Apc,
01442                              FileObject,
01443                              NULL, /* This is used for REPARSE stuff */
01444                              PriorityBoost);
01445         }
01446         else
01447         {
01448             /* Nothing left for us to do, kill it */
01449             ASSERT(Irp->Cancel);
01450             IopCleanupIrp(Irp, FileObject);
01451         }
01452     }
01453 }
01454 
01455 NTSTATUS
01456 NTAPI
01457 IopSynchronousCompletion(IN PDEVICE_OBJECT DeviceObject,
01458                          IN PIRP Irp,
01459                          IN PVOID Context)
01460 {
01461     if (Irp->PendingReturned)
01462         KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
01463     return STATUS_MORE_PROCESSING_REQUIRED;
01464 }
01465 
01466 /*
01467  * @implemented
01468  */
01469 BOOLEAN
01470 NTAPI
01471 IoForwardIrpSynchronously(IN PDEVICE_OBJECT DeviceObject,
01472                           IN PIRP Irp)
01473 {
01474     KEVENT Event;
01475     NTSTATUS Status;
01476 
01477     /* Check if next stack location is available */
01478     if (Irp->CurrentLocation < Irp->StackCount)
01479     {
01480         /* No more stack location */
01481         return FALSE;
01482     }
01483 
01484     /* Initialize event */
01485     KeInitializeEvent(&Event, NotificationEvent, FALSE);
01486 
01487     /* Copy stack location for next driver */
01488     IoCopyCurrentIrpStackLocationToNext(Irp);
01489 
01490     /* Set a completion routine, which will signal the event */
01491     IoSetCompletionRoutine(Irp, IopSynchronousCompletion, &Event, TRUE, TRUE, TRUE);
01492 
01493     /* Call next driver */
01494     Status = IoCallDriver(DeviceObject, Irp);
01495 
01496     /* Check if irp is pending */
01497     if (Status == STATUS_PENDING)
01498     {
01499         /* Yes, wait for its completion */
01500         KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
01501     }
01502 
01503     /* Return success */
01504     return TRUE;
01505 }
01506 
01507 /*
01508  * @implemented
01509  */
01510 VOID
01511 NTAPI
01512 IoFreeIrp(IN PIRP Irp)
01513 {
01514     PNPAGED_LOOKASIDE_LIST List;
01515     PP_NPAGED_LOOKASIDE_NUMBER ListType =  LookasideSmallIrpList;
01516     PKPRCB Prcb;
01517     IOTRACE(IO_IRP_DEBUG,
01518             "%s - Freeing IRPs %p\n",
01519             __FUNCTION__,
01520             Irp);
01521 
01522     /* Make sure the Thread IRP list is empty and that it OK to free it */
01523     ASSERT(Irp->Type == IO_TYPE_IRP);
01524     ASSERT(IsListEmpty(&Irp->ThreadListEntry));
01525     ASSERT(Irp->CurrentLocation >= Irp->StackCount);
01526 
01527     /* If this was a pool alloc, free it with the pool */
01528     if (!(Irp->AllocationFlags & IRP_ALLOCATED_FIXED_SIZE))
01529     {
01530         /* Free it */
01531         ExFreePoolWithTag(Irp, TAG_IRP);
01532     }
01533     else
01534     {
01535         /* Check if this was a Big IRP */
01536         if (Irp->StackCount != 1) ListType = LookasideLargeIrpList;
01537 
01538         /* Get the PRCB */
01539         Prcb = KeGetCurrentPrcb();
01540 
01541         /* Use the P List */
01542         List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;
01543         List->L.TotalFrees++;
01544 
01545         /* Check if the Free was within the Depth or not */
01546         if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
01547         {
01548             /* Let the balancer know */
01549             List->L.FreeMisses++;
01550 
01551             /* Use the L List */
01552             List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;
01553             List->L.TotalFrees++;
01554 
01555             /* Check if the Free was within the Depth or not */
01556             if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
01557             {
01558                 /* All lists failed, use the pool */
01559                 List->L.FreeMisses++;
01560                 ExFreePoolWithTag(Irp, TAG_IRP);
01561                 Irp = NULL;
01562             }
01563         }
01564 
01565         /* The free was within the Depth */
01566         if (Irp)
01567         {
01568            InterlockedPushEntrySList(&List->L.ListHead,
01569                                      (PSLIST_ENTRY)Irp);
01570         }
01571     }
01572 }
01573 
01574 /*
01575  * @implemented
01576  */
01577 IO_PAGING_PRIORITY
01578 FASTCALL
01579 IoGetPagingIoPriority(IN PIRP Irp)
01580 {
01581     IO_PAGING_PRIORITY Priority;
01582     ULONG Flags;
01583 
01584     /* Get the flags */
01585     Flags = Irp->Flags;
01586 
01587     /* Check what priority it has */
01588     if (Flags & IRP_CLASS_CACHE_OPERATION)
01589     {
01590         /* High priority */
01591         Priority = IoPagingPriorityHigh;
01592     }
01593     else if (Flags & IRP_PAGING_IO)
01594     {
01595         /* Normal priority */
01596         Priority = IoPagingPriorityNormal;
01597     }
01598     else
01599     {
01600         /* Invalid -- not a paging IRP */
01601         Priority = IoPagingPriorityInvalid;
01602     }
01603 
01604     /* Return the priority */
01605     return Priority;
01606 }
01607 
01608 /*
01609  * @implemented
01610  */
01611 PEPROCESS
01612 NTAPI
01613 IoGetRequestorProcess(IN PIRP Irp)
01614 {
01615     /* Return the requestor process */
01616     if (Irp->Tail.Overlay.Thread)
01617     {
01618         return Irp->Tail.Overlay.Thread->ThreadsProcess;
01619     }
01620 
01621     return NULL;
01622 }
01623 
01624 /*
01625  * @implemented
01626  */
01627 ULONG
01628 NTAPI
01629 IoGetRequestorProcessId(IN PIRP Irp)
01630 {
01631     PEPROCESS Process;
01632 
01633     /* Return the requestor process' id */
01634     if ((Process = IoGetRequestorProcess(Irp)))
01635     {
01636         return PtrToUlong(Process->UniqueProcessId);
01637     }
01638 
01639     return 0;
01640 }
01641 
01642 /*
01643  * @implemented
01644  */
01645 NTSTATUS
01646 NTAPI
01647 IoGetRequestorSessionId(IN PIRP Irp,
01648                         OUT PULONG pSessionId)
01649 {
01650     PEPROCESS Process;
01651 
01652     /* Return the session */
01653     if ((Process = IoGetRequestorProcess(Irp)))
01654     {
01655         // FIXME: broken
01656         *pSessionId = PtrToUlong(Process->Session);
01657         return STATUS_SUCCESS;
01658     }
01659 
01660     *pSessionId = (ULONG)-1;
01661     return STATUS_UNSUCCESSFUL;
01662 }
01663 
01664 /*
01665  * @implemented
01666  */
01667 PIRP
01668 NTAPI
01669 IoGetTopLevelIrp(VOID)
01670 {
01671     /* Return the IRP */
01672     return (PIRP)PsGetCurrentThread()->TopLevelIrp;
01673 }
01674 
01675 /*
01676  * @implemented
01677  */
01678 VOID
01679 NTAPI
01680 IoInitializeIrp(IN PIRP Irp,
01681                 IN USHORT PacketSize,
01682                 IN CCHAR StackSize)
01683 {
01684     /* Clear it */
01685     IOTRACE(IO_IRP_DEBUG,
01686             "%s - Initializing IRP %p\n",
01687             __FUNCTION__,
01688             Irp);
01689     RtlZeroMemory(Irp, PacketSize);
01690 
01691     /* Set the Header and other data */
01692     Irp->Type = IO_TYPE_IRP;
01693     Irp->Size = PacketSize;
01694     Irp->StackCount = StackSize;
01695     Irp->CurrentLocation = StackSize + 1;
01696     Irp->ApcEnvironment =  KeGetCurrentThread()->ApcStateIndex;
01697     Irp->Tail.Overlay.CurrentStackLocation = (PIO_STACK_LOCATION)(Irp + 1) + StackSize;
01698 
01699     /* Initialize the Thread List */
01700     InitializeListHead(&Irp->ThreadListEntry);
01701 }
01702 
01703 /*
01704  * @implemented
01705  */
01706 BOOLEAN
01707 NTAPI
01708 IoIsOperationSynchronous(IN PIRP Irp)
01709 {
01710     BOOLEAN SynchIO;
01711     BOOLEAN ForceAsync;
01712 
01713     /* If the IRP requests synchronous paging I/O, if the file object was opened
01714        for synchronous I/O, if the IRP_SYNCHRONOUS_API flag is set in the IRP
01715        the operation is synchronous */
01716     SynchIO = (IoGetCurrentIrpStackLocation(Irp)->FileObject->Flags & FO_SYNCHRONOUS_IO) ||
01717               (Irp->Flags & IRP_SYNCHRONOUS_API) || (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO);
01718 
01719     /* If the IRP requests asynchronous paging I/O, the operation is asynchronous,
01720        even if one of the above conditions is true */
01721     ForceAsync = (Irp->Flags & IRP_PAGING_IO) && !(Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO);
01722 
01723     /* Check the flags */
01724     if (SynchIO && !ForceAsync)
01725     {
01726         /* Synch API or Paging I/O is OK, as is Sync File I/O */
01727         return TRUE;
01728     }
01729 
01730     /* Otherwise, it is an asynchronous operation. */
01731     return FALSE;
01732 }
01733 
01734 /*
01735  * @unimplemented
01736  */
01737 BOOLEAN
01738 NTAPI
01739 IoIsValidNameGraftingBuffer(IN PIRP Irp,
01740                             IN PREPARSE_DATA_BUFFER ReparseBuffer)
01741 {
01742     UNIMPLEMENTED;
01743     return FALSE;
01744 }
01745 
01746 /*
01747  * @implemented
01748  */
01749 PIRP
01750 NTAPI
01751 IoMakeAssociatedIrp(IN PIRP Irp,
01752                     IN CCHAR StackSize)
01753 {
01754     PIRP AssocIrp;
01755     IOTRACE(IO_IRP_DEBUG,
01756             "%s - Associating IRP %p\n",
01757             __FUNCTION__,
01758             Irp);
01759 
01760    /* Allocate the IRP */
01761    AssocIrp = IoAllocateIrp(StackSize, FALSE);
01762    if (!AssocIrp) return NULL;
01763 
01764    /* Set the Flags */
01765    AssocIrp->Flags |= IRP_ASSOCIATED_IRP;
01766 
01767    /* Set the Thread */
01768    AssocIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
01769 
01770    /* Associate them */
01771    AssocIrp->AssociatedIrp.MasterIrp = Irp;
01772    return AssocIrp;
01773 }
01774 
01775 /*
01776  * @implemented
01777  */
01778 VOID
01779 NTAPI
01780 IoQueueThreadIrp(IN PIRP Irp)
01781 {
01782     IOTRACE(IO_IRP_DEBUG,
01783             "%s - Queueing IRP %p\n",
01784             __FUNCTION__,
01785             Irp);
01786 
01787     /* Use our inlined routine */
01788     IopQueueIrpToThread(Irp);
01789 }
01790 
01791 /*
01792  * @implemented
01793  * Reference: Chris Cant's "Writing WDM Device Drivers"
01794  */
01795 VOID
01796 NTAPI
01797 IoReuseIrp(IN OUT PIRP Irp,
01798            IN NTSTATUS Status)
01799 {
01800     UCHAR AllocationFlags;
01801     IOTRACE(IO_IRP_DEBUG,
01802             "%s - Reusing IRP %p\n",
01803             __FUNCTION__,
01804             Irp);
01805 
01806     /* Make sure it's OK to reuse it */
01807     ASSERT(!Irp->CancelRoutine);
01808     ASSERT(IsListEmpty(&Irp->ThreadListEntry));
01809 
01810     /* Get the old flags */
01811     AllocationFlags = Irp->AllocationFlags;
01812 
01813     /* Reinitialize the IRP */
01814     IoInitializeIrp(Irp, Irp->Size, Irp->StackCount);
01815 
01816     /* Duplicate the data */
01817     Irp->IoStatus.Status = Status;
01818     Irp->AllocationFlags = AllocationFlags;
01819 }
01820 
01821 /*
01822  * @implemented
01823  */
01824 VOID
01825 NTAPI
01826 IoSetTopLevelIrp(IN PIRP Irp)
01827 {
01828     /* Set the IRP */
01829     PsGetCurrentThread()->TopLevelIrp = (ULONG_PTR)Irp;
01830 }
01831 
01832 #if defined (_WIN64)
01833 BOOLEAN
01834 NTAPI
01835 IoIs32bitProcess(
01836     IN PIRP Irp OPTIONAL)
01837 {
01838     UNIMPLEMENTED;
01839     return FALSE;
01840 }
01841 #endif

Generated on Sat May 26 2012 04:26:33 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.