Author: ion Date: Tue Jul 4 19:36:55 2006 New Revision: 22836
URL: http://svn.reactos.org/svn/reactos?rev=22836&view=rev Log: - Fix NtQueryInformationFile to use correct sync/async semantics and use deferred I/O completion. This routine doesn't use IopSyncronous/Asyncronous helper routines because it can be optimized to handle some Information classes in-line (not currently being done).
Modified: trunk/reactos/ntoskrnl/io/iomgr/iofunc.c
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 Tue Jul 4 19:36:55 2006 @@ -32,6 +32,7 @@ // - Query/Set File Info // - Add SEH to some places where it's missing (MDLs, etc) // - Add a generic Cleanup/Exception Routine +// - Add probe/alignment checks for Query/Set routines // - Add another parameter to IopCleanupFailedIrp // - Add support for Fast Dispatch I/O // - Add support for some fast-paths when querying/setting data @@ -1506,178 +1507,234 @@ { OBJECT_HANDLE_INFORMATION HandleInformation; PFILE_OBJECT FileObject; - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; PIRP Irp; PDEVICE_OBJECT DeviceObject; PIO_STACK_LOCATION StackPtr; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - KEVENT Event; + PKEVENT Event = NULL; BOOLEAN LocalEvent = FALSE; - BOOLEAN Failed = FALSE; + PKNORMAL_ROUTINE NormalRoutine; + PVOID NormalContext; + KIRQL OldIrql; + IO_STATUS_BLOCK KernelIosb; + + /* Check if we're called from user mode */ + if (PreviousMode != KernelMode) + { + /* Enter SEH for probing */ + _SEH_TRY + { + /* Probe the I/O Status block */ + ProbeForWrite(IoStatusBlock, + sizeof(IO_STATUS_BLOCK), + sizeof(ULONG)); + + /* Probe the information */ + if (Length) ProbeForWrite(FileInformation, Length, 1); + } + _SEH_HANDLE + { + /* Get the exception code */ + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + /* Check if probing failed */ + if (!NT_SUCCESS(Status)) return Status; + }
/* Reference the Handle */ Status = ObReferenceObjectByHandle(FileHandle, - 0, + 0, // FIXME IoFileObjectType, PreviousMode, (PVOID *)&FileObject, &HandleInformation); if (!NT_SUCCESS(Status)) return Status;
- /* Check information class specific access rights */ - switch (FileInformationClass) - { - case FileBasicInformation: - if (!(HandleInformation.GrantedAccess & FILE_READ_ATTRIBUTES)) - Failed = TRUE; - break; - - case FilePositionInformation: - if (!(HandleInformation.GrantedAccess & (FILE_READ_DATA | FILE_WRITE_DATA)) || - !(FileObject->Flags & FO_SYNCHRONOUS_IO)) - Failed = TRUE; - break; - - default: - break; - } - - if (Failed) - { - ObDereferenceObject(FileObject); - return STATUS_ACCESS_DENIED; - } - - if (FileInformationClass == FilePositionInformation) - { - if (Length < sizeof(FILE_POSITION_INFORMATION)) - { - Status = STATUS_BUFFER_OVERFLOW; - } - else - { - _SEH_TRY - { - ((PFILE_POSITION_INFORMATION)FileInformation)->CurrentByteOffset = FileObject->CurrentByteOffset; - IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION); - Status = IoStatusBlock->Status = STATUS_SUCCESS; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - ObDereferenceObject(FileObject); - return Status; - } - /* Check if this is a direct open or not */ if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) { + /* Get the device object */ DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); } else { + /* Get the device object */ DeviceObject = IoGetRelatedDeviceObject(FileObject); }
- if (FileInformationClass == FileAlignmentInformation) - { - if (Length < sizeof(FILE_ALIGNMENT_INFORMATION)) - { - Status = STATUS_BUFFER_OVERFLOW; - } - else - { - _SEH_TRY - { - ((PFILE_ALIGNMENT_INFORMATION)FileInformation)->AlignmentRequirement = DeviceObject->AlignmentRequirement; - IoStatusBlock->Information = sizeof(FILE_ALIGNMENT_INFORMATION); - Status = IoStatusBlock->Status = STATUS_SUCCESS; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - ObDereferenceObject(FileObject); - return Status; - } - - /* Check if we should use Sync IO or not */ + /* Check if this is a file that was opened for Synch I/O */ if (FileObject->Flags & FO_SYNCHRONOUS_IO) { - /* Use File Object event */ - KeClearEvent(&FileObject->Event); + /* Lock it */ + IopLockFileObject(FileObject); + + /* Check if the caller just wants the position */ + if (FileInformationClass == FilePositionInformation) + { + /* Protect write in SEH */ + _SEH_TRY + { + /* Write the offset */ + ((PFILE_POSITION_INFORMATION)FileInformation)-> + CurrentByteOffset = FileObject->CurrentByteOffset; + + /* Fill out the I/O Status Block */ + IoStatusBlock->Information = sizeof(FILE_POSITION_INFORMATION); + Status = IoStatusBlock->Status = STATUS_SUCCESS; + } + _SEH_HANDLE + { + /* Get the exception code */ + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + /* Release the file lock, dereference the file and return */ + IopUnlockFileObject(FileObject); + ObDereferenceObject(FileObject); + return Status; + } } else { /* Use local event */ - KeInitializeEvent(&Event, SynchronizationEvent, FALSE); + Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); + KeInitializeEvent(Event, SynchronizationEvent, FALSE); LocalEvent = TRUE; }
+ /* Clear the File Object event */ + KeClearEvent(&FileObject->Event); + /* Allocate the IRP */ - if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE))) - { - ObDereferenceObject(FileObject); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Allocate the System Buffer */ - Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, - Length, - TAG_SYSB); - if (!Irp->AssociatedIrp.SystemBuffer) - { - IoFreeIrp(Irp); - ObDereferenceObject(FileObject); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Set up the IRP */ + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (!Irp) return IopCleanupFailedIrp(FileObject, NULL); + + /* Set the IRP */ Irp->Tail.Overlay.OriginalFileObject = FileObject; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); Irp->RequestorMode = PreviousMode; - Irp->UserIosb = IoStatusBlock; - Irp->UserEvent = (LocalEvent) ? &Event : NULL; + Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; + Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; + Irp->UserIosb = (LocalEvent) ? &KernelIosb : IoStatusBlock; + Irp->UserEvent = (LocalEvent) ? Event : NULL; + Irp->AssociatedIrp.SystemBuffer = NULL; + Irp->MdlAddress = NULL; Irp->UserBuffer = FileInformation; - Irp->Tail.Overlay.Thread = PsGetCurrentThread(); - Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION; - Irp->Flags |= (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; - - /* Set up Stack Data */ + + /* Set the Stack Data */ StackPtr = IoGetNextIrpStackLocation(Irp); StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION; StackPtr->FileObject = FileObject;
+ /* Allocate a buffer */ + Irp->AssociatedIrp.SystemBuffer = + ExAllocatePoolWithTag(NonPagedPool, + Length, + TAG_SYSB); + + /* Set the flags */ + Irp->Flags = (IRP_BUFFERED_IO | + IRP_DEALLOCATE_BUFFER | + IRP_INPUT_OPERATION | + IRP_DEFER_IO_COMPLETION); + /* Set the Parameters */ StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass; StackPtr->Parameters.QueryFile.Length = Length;
+ /* Queue the IRP */ + //IopQueueIrpToThread(Irp); + + /* Update operation counts */ + IopUpdateOperationCount(IopOtherTransfer); + /* Call the Driver */ Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { + /* Check if this was async I/O */ if (LocalEvent) { - KeWaitForSingleObject(&Event, - Executive, - PreviousMode, - FileObject->Flags & FO_ALERTABLE_IO, - NULL); - Status = IoStatusBlock->Status; + /* Then to a non-alertable wait */ + Status = KeWaitForSingleObject(&Event, + Executive, + PreviousMode, + FALSE, + NULL); + if (Status == STATUS_USER_APC) + { + /* Abort the request */ + IopAbortInterruptedIrp(Event, Irp); + } + + /* Set the final status */ + Status = KernelIosb.Status; + + /* Enter SEH to write the IOSB back */ + _SEH_TRY + { + /* Write it back to the caller */ + *IoStatusBlock = KernelIosb; + } + _SEH_HANDLE + { + /* Get the exception code */ + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + /* Free the event */ + ExFreePool(Event); } else { - KeWaitForSingleObject(&FileObject->Event, - Executive, - PreviousMode, - FileObject->Flags & FO_ALERTABLE_IO, - NULL); + /* Wait for the IRP */ + Status = KeWaitForSingleObject(&FileObject->Event, + Executive, + PreviousMode, + FileObject->Flags & FO_ALERTABLE_IO, + NULL); + if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED)) + { + /* Abort the request */ + IopAbortInterruptedIrp(&FileObject->Event, Irp); + } + + /* Set the final status */ Status = FileObject->FinalStatus; - } + + /* Release the file lock */ + IopUnlockFileObject(FileObject); + } + } + else + { + /* Free the event if we had one */ + if (LocalEvent) + { + /* Clear it in the IRP for completion */ + Irp->UserEvent = NULL; + ExFreePool(Event); + } + + /* Set the caller IOSB */ + Irp->UserIosb = IoStatusBlock; + + /* The IRP wasn't completed, complete it ourselves */ + KeRaiseIrql(APC_LEVEL, &OldIrql); + IopCompleteRequest(&Irp->Tail.Apc, + &NormalRoutine, + &NormalContext, + (PVOID*)&FileObject, + &NormalContext); + KeLowerIrql(OldIrql); + + /* Release the file object if we had locked it*/ + if (!LocalEvent) IopUnlockFileObject(FileObject); }
/* Return the Status */