/*++ Copyright (c) 2002 Microsoft Corporation Module Name: cancelio.c Abstract: This module implements the Win32 CancelIo service. --*/ #include "basedll.h" #pragma hdrstop #include VOID XapiDpcForCancelIo( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2 ) { PLIST_ENTRY CancelListHead; PLIST_ENTRY NextListEntry; PIRP Irp; CancelListHead = (PLIST_ENTRY)DeferredContext; // // Run through the list of IRPs to be canceled. // NextListEntry = CancelListHead->Flink; while (NextListEntry != CancelListHead) { Irp = CONTAINING_RECORD(NextListEntry, IRP, Tail.Overlay.DeviceQueueEntry.DeviceListEntry); NextListEntry = NextListEntry->Flink; Irp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(Irp, IO_NO_INCREMENT); } } BOOL WINAPI CancelIo( HANDLE hFile ) /*++ Routine Description: This routine cancels all of the outstanding I/O for the specified handle for the specified file. Arguments: hFile - Supplies the handle to the file whose pending I/O is to be canceled. Return Value: TRUE -- The operation was successful. FALSE -- The operation failed. Extended error status is available using GetLastError. --*/ { LIST_ENTRY CancelListHead; NTSTATUS status; PFILE_OBJECT FileObject; KIRQL OldIrql; PLIST_ENTRY NextListEntry; PIRP Irp; KDPC WorkerDpc; ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); InitializeListHead(&CancelListHead); // // Reference the file object. // status = ObReferenceObjectByHandle(hFile, IoFileObjectType, (PVOID*)&FileObject); if (!NT_SUCCESS(status)) { XapiSetLastNTError(status); return FALSE; } // // Scan through the IDEX device queue for any pending IRPs that originated // from the supplied file object. Synchronize with the IDEX channel // dispatcher by raising to DPC level. // OldIrql = KeRaiseIrqlToDpcLevel(); NextListEntry = IdexChannelObject->DeviceQueue.DeviceListHead.Flink; while (NextListEntry != &IdexChannelObject->DeviceQueue.DeviceListHead) { Irp = CONTAINING_RECORD(NextListEntry, IRP, Tail.Overlay.DeviceQueueEntry.DeviceListEntry); NextListEntry = NextListEntry->Flink; if ((Irp->Tail.Overlay.OriginalFileObject == FileObject) && ((Irp->Flags & IRP_NO_CANCELIO) == 0)) { RemoveEntryList(&Irp->Tail.Overlay.DeviceQueueEntry.DeviceListEntry); InsertTailList(&CancelListHead, &Irp->Tail.Overlay.DeviceQueueEntry.DeviceListEntry); } } KeLowerIrql(OldIrql); // // If there are any IRPs that need to be canceled, then do so from a worker // DPC. This is done for two reasons. First, for packets marked as "must // complete" using IoMarkIrpMustComplete, IoCompleteRequest must be called // at DPC level. Second, if the number of "must complete" packets reach // zero and a shutdown request is pending, then the kernel routine // HalMustCompletePacketsFinished expects to be called from a DPC stack, not // an arbitrary thread stack. // if (!IsListEmpty(&CancelListHead)) { KeInitializeDpc(&WorkerDpc, XapiDpcForCancelIo, &CancelListHead); KeInsertQueueDpc(&WorkerDpc, NULL, NULL); } // // Dereference the file object. // ObDereferenceObject(FileObject); return TRUE; }