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