Author: ion Date: Sun Jul 2 22:20:37 2006 New Revision: 22772
URL: http://svn.reactos.org/svn/reactos?rev=22772&view=rev Log: - Move NtCancelIoFile and NtDeleteFile to file.c, they don't deal with IRPs. - Create IopFinalizeAsynchronousIo to deal with Sync APIs working on Async file objects, which need to be waited on differently and have the IOSB copied manually. - Update NtFlushBuffersFile to new semantics (ie, usage of the new implemented functions).
Modified: trunk/reactos/ntoskrnl/io/iomgr/file.c trunk/reactos/ntoskrnl/io/iomgr/iofunc.c
Modified: trunk/reactos/ntoskrnl/io/iomgr/file.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/file.c?re... ============================================================================== --- trunk/reactos/ntoskrnl/io/iomgr/file.c (original) +++ trunk/reactos/ntoskrnl/io/iomgr/file.c Sun Jul 2 22:20:37 2006 @@ -1469,6 +1469,141 @@ FileInformation); }
+/** + * @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 +NTAPI +NtCancelIoFile(IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock) +{ + PFILE_OBJECT FileObject; + PETHREAD Thread; + PIRP Irp; + KIRQL OldIrql; + BOOLEAN OurIrpsInList = FALSE; + LARGE_INTEGER Interval; + KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); + NTSTATUS Status = STATUS_SUCCESS; + PAGED_CODE(); + + if (PreviousMode != KernelMode) + { + _SEH_TRY + { + ProbeForWrite(IoStatusBlock, + sizeof(IO_STATUS_BLOCK), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if (!NT_SUCCESS(Status)) return Status; + } + + Status = ObReferenceObjectByHandle(FileHandle, + 0, + IoFileObjectType, + PreviousMode, + (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(); + + LIST_FOR_EACH(Irp, &Thread->IrpList, 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. + */ + + LIST_FOR_EACH(Irp, &Thread->IrpList, 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 + { + + } + _SEH_END; + + ObDereferenceObject(FileObject); + return Status; +} + +/* + * @unimplemented + */ +NTSTATUS +NTAPI +NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes) +{ + UNIMPLEMENTED; + return(STATUS_NOT_IMPLEMENTED); +} + /* * @unimplemented */
Modified: trunk/reactos/ntoskrnl/io/iomgr/iofunc.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/iofunc.c?... ============================================================================== --- trunk/reactos/ntoskrnl/io/iomgr/iofunc.c (original) +++ trunk/reactos/ntoskrnl/io/iomgr/iofunc.c Sun Jul 2 22:20:37 2006 @@ -89,6 +89,54 @@ /* We got preempted, so give up */ KeLowerIrql(OldIrql); } +} + +NTSTATUS +NTAPI +IopFinalizeAsynchronousIo(IN NTSTATUS SynchStatus, + IN PKEVENT Event, + IN PIRP Irp, + IN KPROCESSOR_MODE PreviousMode, + IN PIO_STATUS_BLOCK KernelIosb, + OUT PIO_STATUS_BLOCK IoStatusBlock) +{ + NTSTATUS FinalStatus = SynchStatus; + PAGED_CODE(); + + /* Make sure the IRP was completed, but returned pending */ + if (FinalStatus == STATUS_PENDING) + { + /* Wait for the IRP */ + FinalStatus = KeWaitForSingleObject(Event, + Executive, + PreviousMode, + FALSE, + NULL); + if (FinalStatus == STATUS_USER_APC) + { + /* Abort the request */ + IopAbortInterruptedIrp(Event, Irp); + } + + /* Set the final status */ + FinalStatus = KernelIosb->Status; + } + + /* Wrap potential user-mode write in SEH */ + _SEH_TRY + { + *IoStatusBlock = *KernelIosb; + } + _SEH_HANDLE + { + /* Get the exception code */ + FinalStatus = _SEH_GetExceptionCode(); + } + _SEH_END; + + /* Free the event and return status */ + ExFreePool(Event); + return FinalStatus; }
NTSTATUS @@ -734,141 +782,6 @@
/* NATIVE SERVICES ***********************************************************/
-/** - * @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 -NTAPI -NtCancelIoFile(IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock) -{ - PFILE_OBJECT FileObject; - PETHREAD Thread; - PIRP Irp; - KIRQL OldIrql; - BOOLEAN OurIrpsInList = FALSE; - LARGE_INTEGER Interval; - KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); - NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - - if (PreviousMode != KernelMode) - { - _SEH_TRY - { - ProbeForWrite(IoStatusBlock, - sizeof(IO_STATUS_BLOCK), - sizeof(ULONG)); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if (!NT_SUCCESS(Status)) return Status; - } - - Status = ObReferenceObjectByHandle(FileHandle, - 0, - IoFileObjectType, - PreviousMode, - (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(); - - LIST_FOR_EACH(Irp, &Thread->IrpList, 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. - */ - - LIST_FOR_EACH(Irp, &Thread->IrpList, 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 - { - - } - _SEH_END; - - ObDereferenceObject(FileObject); - return Status; -} - -/* - * @unimplemented - */ -NTSTATUS -NTAPI -NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes) -{ - UNIMPLEMENTED; - return(STATUS_NOT_IMPLEMENTED); -} - /* * @implemented */ @@ -933,32 +846,36 @@ NtFlushBuffersFile(IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock) { - PFILE_OBJECT FileObject = NULL; + PFILE_OBJECT FileObject; PIRP Irp; PIO_STACK_LOCATION StackPtr; NTSTATUS Status = STATUS_SUCCESS; PDEVICE_OBJECT DeviceObject; - KEVENT Event; + PKEVENT Event = NULL; BOOLEAN LocalEvent = FALSE; - ACCESS_MASK DesiredAccess = FILE_WRITE_DATA; OBJECT_HANDLE_INFORMATION ObjectHandleInfo; KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); + IO_STATUS_BLOCK KernelIosb; PAGED_CODE();
if (PreviousMode != KernelMode) { + /* Protect probes */ _SEH_TRY { + /* Probe the I/O Status block */ ProbeForWrite(IoStatusBlock, sizeof(IO_STATUS_BLOCK), sizeof(ULONG)); } _SEH_HANDLE { + /* Get the exception code */ Status = _SEH_GetExceptionCode(); } _SEH_END;
+ /* Return exception code, if any */ if (!NT_SUCCESS(Status)) return Status; }
@@ -969,58 +886,55 @@ PreviousMode, (PVOID*)&FileObject, &ObjectHandleInfo); - if (!NT_SUCCESS(Status)) return(Status); - - /* check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was - granted. However, if this is a named pipe, make sure we don't ask for - FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE - access right! */ - if (!(FileObject->Flags & FO_NAMED_PIPE)) - DesiredAccess |= FILE_APPEND_DATA; - if (!RtlAreAnyAccessesGranted(ObjectHandleInfo.GrantedAccess, - DesiredAccess)) - { + if (!NT_SUCCESS(Status)) return Status; + + /* + * Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was + * granted. However, if this is a named pipe, make sure we don't ask for + * FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE + * access right! + */ + if (!(ObjectHandleInfo.GrantedAccess & + ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) | + FILE_WRITE_DATA))) + { + /* We failed */ ObDereferenceObject(FileObject); return STATUS_ACCESS_DENIED; }
- /* Check if this is a direct open or not */ - if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) - { - DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); - } - else - { - DeviceObject = IoGetRelatedDeviceObject(FileObject); - } - /* Check if we should use Sync IO or not */ if (FileObject->Flags & FO_SYNCHRONOUS_IO) { - /* Use File Object event */ - KeClearEvent(&FileObject->Event); + /* Lock it */ + IopLockFileObject(FileObject); } else { /* Use local event */ - KeInitializeEvent(&Event, SynchronizationEvent, FALSE); + Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); + KeInitializeEvent(Event, SynchronizationEvent, FALSE); LocalEvent = TRUE; }
+ /* Get the Device Object */ + DeviceObject = IoGetRelatedDeviceObject(FileObject); + + /* Clear the event */ + KeClearEvent(&FileObject->Event); + /* Allocate the IRP */ - if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE))) - { - ObDereferenceObject(FileObject); - return STATUS_INSUFFICIENT_RESOURCES; - } + Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); + if (!Irp) return IopCleanupFailedIrp(FileObject, NULL);
/* Set up the IRP */ Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; + Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; + Irp->UserEvent = (LocalEvent) ? Event : NULL; Irp->RequestorMode = PreviousMode; - Irp->UserIosb = IoStatusBlock; - Irp->UserEvent = (LocalEvent) ? &Event : NULL; Irp->Tail.Overlay.Thread = PsGetCurrentThread(); Irp->Tail.Overlay.OriginalFileObject = FileObject; + Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
/* Set up Stack Data */ StackPtr = IoGetNextIrpStackLocation(Irp); @@ -1028,27 +942,24 @@ StackPtr->FileObject = FileObject;
/* Call the Driver */ - Status = IoCallDriver(DeviceObject, Irp); - if (Status == STATUS_PENDING) - { - if (LocalEvent) - { - KeWaitForSingleObject(&Event, - Executive, - PreviousMode, - FileObject->Flags & FO_ALERTABLE_IO, - NULL); - Status = IoStatusBlock->Status; - } - else - { - KeWaitForSingleObject(&FileObject->Event, - Executive, - PreviousMode, - FileObject->Flags & FO_ALERTABLE_IO, - NULL); - Status = FileObject->FinalStatus; - } + Status = IopPerformSynchronousRequest(DeviceObject, + Irp, + FileObject, + FALSE, + PreviousMode, + !LocalEvent, + IopOtherTransfer); + + /* Check if this was async I/O */ + if (LocalEvent) + { + /* It was, finalize this request */ + Status = IopFinalizeAsynchronousIo(Status, + Event, + Irp, + PreviousMode, + &KernelIosb, + IoStatusBlock); }
/* Return the Status */