mirror of
https://github.com/reactos/reactos.git
synced 2025-07-03 10:01:24 +00:00
- Implement NtCancelIoFile.
- Queue the IRP to correct thread in IoQueueThreadIrp. - Cancel I/O requests when thread is about to be terminated. - Do not queue close requests to thread IRP list. svn path=/trunk/; revision=13824
This commit is contained in:
parent
3d5ac6b2be
commit
594c2c424b
5 changed files with 213 additions and 22 deletions
|
@ -426,6 +426,11 @@ IopBootLog(PUNICODE_STRING DriverName, BOOLEAN Success);
|
||||||
VOID
|
VOID
|
||||||
IopSaveBootLogToFile(VOID);
|
IopSaveBootLogToFile(VOID);
|
||||||
|
|
||||||
|
/* cancel.c */
|
||||||
|
|
||||||
|
VOID STDCALL
|
||||||
|
IoCancelThreadIo(PETHREAD Thread);
|
||||||
|
|
||||||
/* errlog.c */
|
/* errlog.c */
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
|
|
|
@ -20,12 +20,181 @@ static KSPIN_LOCK CancelSpinLock;
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name NtCancelIoFile
|
||||||
|
*
|
||||||
|
* Cancel all pending I/O operations in the current thread for specified
|
||||||
|
* file object.
|
||||||
|
*
|
||||||
|
* @param FileHandle
|
||||||
|
* Handle to file object to cancel requests for. No specific
|
||||||
|
* access rights are needed.
|
||||||
|
* @param IoStatusBlock
|
||||||
|
* Pointer to status block which is filled with final completition
|
||||||
|
* status on successful return.
|
||||||
|
*
|
||||||
|
* @return Status.
|
||||||
|
*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
|
||||||
NTSTATUS STDCALL
|
NTSTATUS STDCALL
|
||||||
NtCancelIoFile (IN HANDLE FileHandle,
|
NtCancelIoFile(
|
||||||
|
IN HANDLE FileHandle,
|
||||||
OUT PIO_STATUS_BLOCK IoStatusBlock)
|
OUT PIO_STATUS_BLOCK IoStatusBlock)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
NTSTATUS Status;
|
||||||
return(STATUS_NOT_IMPLEMENTED);
|
PFILE_OBJECT FileObject;
|
||||||
|
PETHREAD Thread;
|
||||||
|
PLIST_ENTRY IrpEntry;
|
||||||
|
PIRP Irp;
|
||||||
|
KIRQL OldIrql;
|
||||||
|
BOOLEAN OurIrpsInList = FALSE;
|
||||||
|
LARGE_INTEGER Interval;
|
||||||
|
|
||||||
|
if ((ULONG_PTR)IoStatusBlock >= MmUserProbeAddress &&
|
||||||
|
KeGetPreviousMode() == UserMode)
|
||||||
|
return STATUS_ACCESS_VIOLATION;
|
||||||
|
|
||||||
|
Status = ObReferenceObjectByHandle(FileHandle, 0, IoFileObjectType,
|
||||||
|
KeGetPreviousMode(), (PVOID*)&FileObject,
|
||||||
|
NULL);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
return Status;
|
||||||
|
|
||||||
|
/* IRP cancellations are synchronized at APC_LEVEL. */
|
||||||
|
OldIrql = KfRaiseIrql(APC_LEVEL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Walk the list of active IRPs and cancel the ones that belong to
|
||||||
|
* our file object.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Thread = PsGetCurrentThread();
|
||||||
|
for (IrpEntry = Thread->IrpList.Flink;
|
||||||
|
IrpEntry != &Thread->IrpList;
|
||||||
|
IrpEntry = IrpEntry->Flink)
|
||||||
|
{
|
||||||
|
Irp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry);
|
||||||
|
if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
|
||||||
|
{
|
||||||
|
IoCancelIrp(Irp);
|
||||||
|
/* Don't break here, we want to cancel all IRPs for the file object. */
|
||||||
|
OurIrpsInList = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KfLowerIrql(OldIrql);
|
||||||
|
|
||||||
|
while (OurIrpsInList)
|
||||||
|
{
|
||||||
|
OurIrpsInList = FALSE;
|
||||||
|
|
||||||
|
/* Wait a short while and then look if all our IRPs were completed. */
|
||||||
|
Interval.QuadPart = -1000000; /* 100 milliseconds */
|
||||||
|
KeDelayExecutionThread(KernelMode, FALSE, &Interval);
|
||||||
|
|
||||||
|
OldIrql = KfRaiseIrql(APC_LEVEL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look in the list if all IRPs for the specified file object
|
||||||
|
* are completed (or cancelled). If someone sends a new IRP
|
||||||
|
* for our file object while we're here we can happily loop
|
||||||
|
* forever.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (IrpEntry = Thread->IrpList.Flink;
|
||||||
|
IrpEntry != &Thread->IrpList;
|
||||||
|
IrpEntry = IrpEntry->Flink)
|
||||||
|
{
|
||||||
|
Irp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry);
|
||||||
|
if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
|
||||||
|
{
|
||||||
|
OurIrpsInList = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KfLowerIrql(OldIrql);
|
||||||
|
}
|
||||||
|
|
||||||
|
_SEH_TRY
|
||||||
|
{
|
||||||
|
IoStatusBlock->Status = STATUS_SUCCESS;
|
||||||
|
IoStatusBlock->Information = 0;
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
Status = STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
|
||||||
|
ObDereferenceObject(FileObject);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name IoCancelThreadIo
|
||||||
|
*
|
||||||
|
* Cancel all pending I/O request associated with specified thread.
|
||||||
|
*
|
||||||
|
* @param Thread
|
||||||
|
* Thread to cancel requests for.
|
||||||
|
*/
|
||||||
|
|
||||||
|
VOID STDCALL
|
||||||
|
IoCancelThreadIo(PETHREAD Thread)
|
||||||
|
{
|
||||||
|
PLIST_ENTRY IrpEntry;
|
||||||
|
PIRP Irp;
|
||||||
|
KIRQL OldIrql;
|
||||||
|
ULONG Retries = 3000;
|
||||||
|
LARGE_INTEGER Interval;
|
||||||
|
|
||||||
|
OldIrql = KfRaiseIrql(APC_LEVEL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start by cancelling all the IRPs in the current thread queue.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (IrpEntry = Thread->IrpList.Flink;
|
||||||
|
IrpEntry != &Thread->IrpList;
|
||||||
|
IrpEntry = IrpEntry->Flink)
|
||||||
|
{
|
||||||
|
Irp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry);
|
||||||
|
IoCancelIrp(Irp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait till all the IRPs are completed or cancelled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
while (!IsListEmpty(&Thread->IrpList))
|
||||||
|
{
|
||||||
|
KfLowerIrql(OldIrql);
|
||||||
|
|
||||||
|
/* Wait a short while and then look if all our IRPs were completed. */
|
||||||
|
Interval.QuadPart = -1000000; /* 100 milliseconds */
|
||||||
|
KeDelayExecutionThread(KernelMode, FALSE, &Interval);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't stay here forever if some broken driver doesn't complete
|
||||||
|
* the IRP.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (Retries-- == 0)
|
||||||
|
{
|
||||||
|
/* FIXME: Handle this gracefully. */
|
||||||
|
DPRINT1("Thread with dead IRPs!");
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
OldIrql = KfRaiseIrql(APC_LEVEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
KfLowerIrql(OldIrql);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -105,15 +105,24 @@ IopDeleteFile(PVOID ObjectBody)
|
||||||
UserMode);
|
UserMode);
|
||||||
#endif
|
#endif
|
||||||
KeResetEvent( &FileObject->Event );
|
KeResetEvent( &FileObject->Event );
|
||||||
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_CLOSE,
|
|
||||||
FileObject->DeviceObject,
|
Irp = IoAllocateIrp(FileObject->DeviceObject->StackSize, TRUE);
|
||||||
NULL,
|
if (Irp == NULL)
|
||||||
0,
|
{
|
||||||
NULL,
|
/*
|
||||||
&FileObject->Event,
|
* FIXME: This case should eventually be handled. We should wait
|
||||||
NULL);
|
* until enough memory is available to allocate the IRP.
|
||||||
|
*/
|
||||||
|
ASSERT(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Irp->UserEvent = &FileObject->Event;
|
||||||
|
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
||||||
Irp->Flags |= IRP_CLOSE_OPERATION;
|
Irp->Flags |= IRP_CLOSE_OPERATION;
|
||||||
|
|
||||||
StackPtr = IoGetNextIrpStackLocation(Irp);
|
StackPtr = IoGetNextIrpStackLocation(Irp);
|
||||||
|
StackPtr->MajorFunction = IRP_MJ_CLOSE;
|
||||||
|
StackPtr->DeviceObject = FileObject->DeviceObject;
|
||||||
StackPtr->FileObject = FileObject;
|
StackPtr->FileObject = FileObject;
|
||||||
|
|
||||||
Status = IoCallDriver(FileObject->DeviceObject, Irp);
|
Status = IoCallDriver(FileObject->DeviceObject, Irp);
|
||||||
|
|
|
@ -268,7 +268,6 @@ IoAllocateIrp(CCHAR StackSize,
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
RtlZeroMemory(Irp, IoSizeOfIrp(StackSize));
|
|
||||||
IoInitializeIrp(Irp,
|
IoInitializeIrp(Irp,
|
||||||
IoSizeOfIrp(StackSize),
|
IoSizeOfIrp(StackSize),
|
||||||
StackSize);
|
StackSize);
|
||||||
|
@ -364,6 +363,9 @@ IofCompleteRequest(PIRP Irp,
|
||||||
ULONG MasterIrpCount;
|
ULONG MasterIrpCount;
|
||||||
PIRP MasterIrp = Irp->AssociatedIrp.MasterIrp;
|
PIRP MasterIrp = Irp->AssociatedIrp.MasterIrp;
|
||||||
|
|
||||||
|
/* This should never happen! */
|
||||||
|
ASSERT(IsListEmpty(&Irp->ThreadListEntry));
|
||||||
|
|
||||||
MasterIrpCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount);
|
MasterIrpCount = InterlockedDecrement(&MasterIrp->AssociatedIrp.IrpCount);
|
||||||
while ((Mdl = Irp->MdlAddress))
|
while ((Mdl = Irp->MdlAddress))
|
||||||
{
|
{
|
||||||
|
@ -386,6 +388,9 @@ IofCompleteRequest(PIRP Irp,
|
||||||
/* Windows NT File System Internals, page 165 */
|
/* Windows NT File System Internals, page 165 */
|
||||||
if (Irp->Flags & (IRP_PAGING_IO|IRP_CLOSE_OPERATION))
|
if (Irp->Flags & (IRP_PAGING_IO|IRP_CLOSE_OPERATION))
|
||||||
{
|
{
|
||||||
|
/* This should never happen! */
|
||||||
|
ASSERT(IsListEmpty(&Irp->ThreadListEntry));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If MDL_IO_PAGE_READ is set, then the caller is responsible
|
* If MDL_IO_PAGE_READ is set, then the caller is responsible
|
||||||
* for deallocating of the mdl.
|
* for deallocating of the mdl.
|
||||||
|
@ -582,19 +587,19 @@ IoGetTopLevelIrp(VOID)
|
||||||
VOID STDCALL
|
VOID STDCALL
|
||||||
IoQueueThreadIrp(IN PIRP Irp)
|
IoQueueThreadIrp(IN PIRP Irp)
|
||||||
{
|
{
|
||||||
/* undefine this when (if ever) implementing irp cancellation */
|
KIRQL OldIrql;
|
||||||
#if 0
|
|
||||||
KIRQL oldIrql;
|
|
||||||
|
|
||||||
oldIrql = KfRaiseIrql(APC_LEVEL);
|
OldIrql = KfRaiseIrql(APC_LEVEL);
|
||||||
|
|
||||||
/* Synchronous irp's are queued to requestor thread. If they are not completed
|
/*
|
||||||
when the thread exits, they are canceled (cleaned up).
|
* Synchronous irp's are queued to requestor thread. If they are not
|
||||||
-Gunnar */
|
* completed when the thread exits, they are canceled (cleaned up).
|
||||||
InsertTailList(&PsGetCurrentThread()->IrpList, &Irp->ThreadListEntry);
|
* - Gunnar
|
||||||
|
*/
|
||||||
|
|
||||||
KfLowerIrql(oldIrql);
|
InsertTailList(&Irp->Tail.Overlay.Thread->IrpList, &Irp->ThreadListEntry);
|
||||||
#endif
|
|
||||||
|
KfLowerIrql(OldIrql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -158,6 +158,9 @@ PsTerminateCurrentThread(NTSTATUS ExitStatus)
|
||||||
|
|
||||||
PsLockProcess(CurrentProcess, FALSE);
|
PsLockProcess(CurrentProcess, FALSE);
|
||||||
|
|
||||||
|
/* Cancel I/O for the thread. */
|
||||||
|
IoCancelThreadIo(CurrentThread);
|
||||||
|
|
||||||
/* Remove the thread from the thread list of its process */
|
/* Remove the thread from the thread list of its process */
|
||||||
RemoveEntryList(&CurrentThread->ThreadListEntry);
|
RemoveEntryList(&CurrentThread->ThreadListEntry);
|
||||||
Last = IsListEmpty(&CurrentProcess->ThreadListHead);
|
Last = IsListEmpty(&CurrentProcess->ThreadListHead);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue