Author: ion Date: Mon Jul 3 03:02:38 2006 New Revision: 22789
URL: http://svn.reactos.org/svn/reactos?rev=22789&view=rev Log: - NtReadFile: - Allow async i/o access on mailslots, without a byte offset. - Fix sync semantics just like for the other functions until now. - Fix a potential object leak in a failure case. - Don't call IoBuildSyncronousFsdRequest since we want to build the IRP ourselves. - Use deferred I/O as an optimization.
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 Mon Jul 3 03:02:38 2006 @@ -1699,7 +1699,7 @@ { NTSTATUS Status = STATUS_SUCCESS; PFILE_OBJECT FileObject; - PIRP Irp = NULL; + PIRP Irp; PDEVICE_OBJECT DeviceObject; PIO_STACK_LOCATION StackPtr; KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); @@ -1707,8 +1707,8 @@ LARGE_INTEGER CapturedByteOffset; ULONG CapturedKey = 0; BOOLEAN Synchronous = FALSE; + PMDL Mdl; PAGED_CODE(); - CapturedByteOffset.QuadPart = 0;
/* Validate User-Mode Buffers */ @@ -1716,32 +1716,37 @@ { _SEH_TRY { + /* Probe the status block */ ProbeForWrite(IoStatusBlock, sizeof(IO_STATUS_BLOCK), sizeof(ULONG)); - ProbeForWrite(Buffer, - Length, - 1); - + + /* Probe the read buffer */ + ProbeForWrite(Buffer, Length, 1); + + /* Check if we got a byte offset */ if (ByteOffset) { + /* Capture and probe it */ CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset); }
+ /* Capture and probe the key */ if (Key) CapturedKey = ProbeForReadUlong(Key); - - /* FIXME - probe other pointers and capture information */ } _SEH_HANDLE { + /* Get the exception code */ Status = _SEH_GetExceptionCode(); } _SEH_END;
- if(!NT_SUCCESS(Status)) return Status; + /* Check for probe failure */ + if (!NT_SUCCESS(Status)) return Status; } else { + /* Kernel mode: capture directly */ if (ByteOffset) CapturedByteOffset = *ByteOffset; if (Key) CapturedKey = *Key; } @@ -1755,25 +1760,6 @@ NULL); if (!NT_SUCCESS(Status)) return Status;
- /* Check if we should use Sync IO or not */ - if (FileObject->Flags & FO_SYNCHRONOUS_IO) - { - if (ByteOffset == NULL || - (CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION && - CapturedByteOffset.u.HighPart == -1)) - { - /* Use the Current Byte OFfset */ - CapturedByteOffset = FileObject->CurrentByteOffset; - } - - Synchronous = TRUE; - } - else if (ByteOffset == NULL && !(FileObject->Flags & FO_NAMED_PIPE)) - { - ObDereferenceObject(FileObject); - return STATUS_INVALID_PARAMETER; - } - /* Check for event */ if (Event) { @@ -1786,89 +1772,133 @@ NULL); if (!NT_SUCCESS(Status)) { + /* Fail */ ObDereferenceObject(FileObject); return Status; } + + /* Otherwise reset the event */ KeClearEvent(EventObject); }
- /* 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) + { + /* Lock the file object */ + IopLockFileObject(FileObject); + + /* Check if we don't have a byte offset avilable */ + if (!(ByteOffset) || + ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) && + (CapturedByteOffset.u.HighPart == -1))) + { + /* Use the Current Byte Offset instead */ + CapturedByteOffset = FileObject->CurrentByteOffset; + } + + /* Rememer we are sync */ + Synchronous = TRUE; + } + else if (!(ByteOffset) && + !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) + { + /* Otherwise, this was async I/O without a byte offset, so fail */ + if (EventObject) ObDereferenceObject(EventObject); + ObDereferenceObject(FileObject); + return STATUS_INVALID_PARAMETER; + } + + /* Get the device object */ + DeviceObject = IoGetRelatedDeviceObject(FileObject); + + /* Clear the File Object's event */ KeClearEvent(&FileObject->Event);
- /* Create the IRP */ - _SEH_TRY - { - Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, - DeviceObject, - Buffer, - Length, - &CapturedByteOffset, - EventObject, - IoStatusBlock); - - if (Irp == NULL) - { - Status = STATUS_INSUFFICIENT_RESOURCES; - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - /* Cleanup if IRP Allocation Failed */ - if (!NT_SUCCESS(Status)) - { - if (Event) ObDereferenceObject(EventObject); - ObDereferenceObject(FileObject); - return Status; - } - - /* Set up IRP Data */ + /* Allocate the IRP */ + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if (!Irp) return IopCleanupFailedIrp(FileObject, NULL); + + /* Set the IRP */ Irp->Tail.Overlay.OriginalFileObject = FileObject; - Irp->RequestorMode = PreviousMode; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); + Irp->RequestorMode = KernelMode; Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; - Irp->Flags |= IRP_READ_OPERATION; -#if 0 - /* FIXME: - * Vfat doesn't handle non cached files correctly. - */ - if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE; -#endif - - /* Setup Stack Data */ + Irp->UserIosb = IoStatusBlock; + Irp->UserEvent = EventObject; + Irp->PendingReturned = FALSE; + Irp->Cancel = FALSE; + Irp->CancelRoutine = NULL; + Irp->AssociatedIrp.SystemBuffer = NULL; + Irp->MdlAddress = NULL; + + /* Set the Stack Data */ StackPtr = IoGetNextIrpStackLocation(Irp); + StackPtr->MajorFunction = IRP_MJ_READ; StackPtr->FileObject = FileObject; StackPtr->Parameters.Read.Key = CapturedKey; - - /* Call the Driver */ - Status = IoCallDriver(DeviceObject, Irp); - if (Status == STATUS_PENDING) - { - if (Synchronous) - { - KeWaitForSingleObject(&FileObject->Event, - Executive, - PreviousMode, - FileObject->Flags & FO_ALERTABLE_IO, - NULL); - Status = FileObject->FinalStatus; - } - } - - /* Return the Status */ - return Status; + StackPtr->Parameters.Read.Length = Length; + StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset; + + /* Check if this is buffered I/O */ + if (DeviceObject->Flags & DO_BUFFERED_IO) + { + /* Check if we have a buffer length */ + if (Length) + { + /* Allocate a buffer */ + Irp->AssociatedIrp.SystemBuffer = + ExAllocatePoolWithTag(NonPagedPool, + Length, + TAG_SYSB); + + /* Set the buffer and flags */ + Irp->UserBuffer = Buffer; + Irp->Flags = (IRP_BUFFERED_IO | + IRP_DEALLOCATE_BUFFER | + IRP_INPUT_OPERATION); + } + else + { + /* Not reading anything */ + Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION; + } + } + else if (DeviceObject->Flags & DO_DIRECT_IO) + { + /* Check if we have a buffer length */ + if (Length) + { + /* Allocate an MDL */ + Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp); + MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess); + } + + /* No allocation flags */ + Irp->Flags = 0; + } + else + { + /* No allocation flags, and use the buffer directly */ + Irp->Flags = 0; + Irp->UserBuffer = Buffer; + } + + /* Now set the deferred read flags */ + Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION); +#if 0 + /* FIXME: VFAT SUCKS */ + if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE; +#endif + + /* Perform the call */ + return IopPerformSynchronousRequest(DeviceObject, + Irp, + FileObject, + TRUE, + PreviousMode, + Synchronous, + IopReadTransfer); }
NTSTATUS