/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/io/iofunc.c
+ * FILE: ntoskrnl/io/iomgr/iofunc.c
* PURPOSE: Generic I/O Functions that build IRPs for various operations
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Gunnar Dalsnes
* Filip Navara (navaraf@reactos.org)
+ * Pierre Schweitzer (pierre@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <debug.h>
#include "internal/io_i.h"
+volatile LONG IoPageReadIrpAllocationFailure = 0;
+volatile LONG IoPageReadNonPagefileIrpAllocationFailure = 0;
+
/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
IopCleanupAfterException(IN PFILE_OBJECT FileObject,
- IN PIRP Irp,
+ IN PIRP Irp OPTIONAL,
IN PKEVENT Event OPTIONAL,
IN PKEVENT LocalEvent OPTIONAL)
{
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "IRP: %p. FO: %p \n", Irp, FileObject);
- /* Check if we had a buffer */
- if (Irp->AssociatedIrp.SystemBuffer)
+ if (Irp)
{
- /* Free it */
- ExFreePool(Irp->AssociatedIrp.SystemBuffer);
- }
+ /* Check if we had a buffer */
+ if (Irp->AssociatedIrp.SystemBuffer)
+ {
+ /* Free it */
+ ExFreePool(Irp->AssociatedIrp.SystemBuffer);
+ }
- /* Free the mdl */
- if (Irp->MdlAddress) IoFreeMdl(Irp->MdlAddress);
+ /* Free the mdl */
+ if (Irp->MdlAddress) IoFreeMdl(Irp->MdlAddress);
- /* Free the IRP */
- IoFreeIrp(Irp);
+ /* Free the IRP */
+ IoFreeIrp(Irp);
+ }
/* Check if we had a file lock */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
ACCESS_MASK DesiredAccess;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
ULONG BufferLength;
+ POOL_TYPE PoolType;
+
+ PAGED_CODE();
+
IOTRACE(IO_CTL_DEBUG, "Handle: %p. CTL: %lx. Type: %lx \n",
DeviceHandle, IoControlCode, IsDevIoCtl);
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
- IopLockFileObject(FileObject);
+ Status = IopLockFileObject(FileObject, PreviousMode);
+ if (Status != STATUS_SUCCESS)
+ {
+ if (EventObject) ObDereferenceObject(EventObject);
+ ObDereferenceObject(FileObject);
+ return Status;
+ }
/* Remember to unlock later */
LockedForSynch = TRUE;
DeviceObject = IoGetRelatedDeviceObject(FileObject);
}
+ /* If this is a device I/O, try to do it with FastIO path */
+ if (IsDevIoCtl)
+ {
+ PFAST_IO_DISPATCH FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+
+ /* Check whether FSD is FastIO aware and provide an appropriate routine */
+ if (FastIoDispatch != NULL && FastIoDispatch->FastIoDeviceControl != NULL)
+ {
+ IO_STATUS_BLOCK KernelIosb;
+
+ /* If we have an output buffer coming from usermode */
+ if (PreviousMode != KernelMode && OutputBuffer != NULL)
+ {
+ /* Probe it according to its usage */
+ _SEH2_TRY
+ {
+ if (AccessType == METHOD_IN_DIRECT)
+ {
+ ProbeForRead(OutputBuffer, OutputBufferLength, sizeof(CHAR));
+ }
+ else if (AccessType == METHOD_OUT_DIRECT)
+ {
+ ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(CHAR));
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Cleanup after exception and return */
+ IopCleanupAfterException(FileObject, NULL, EventObject, NULL);
+
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+ }
+
+ /* If we are dismounting a volume, increase the dismount count */
+ if (IoControlCode == FSCTL_DISMOUNT_VOLUME)
+ {
+ InterlockedIncrement((PLONG)&SharedUserData->DismountCount);
+ }
+
+ /* Call the FSD */
+ if (FastIoDispatch->FastIoDeviceControl(FileObject,
+ TRUE,
+ InputBuffer,
+ InputBufferLength,
+ OutputBuffer,
+ OutputBufferLength,
+ IoControlCode,
+ &KernelIosb,
+ DeviceObject))
+ {
+ IO_COMPLETION_CONTEXT CompletionInfo = { NULL, NULL };
+
+ /* Write the IOSB back */
+ _SEH2_TRY
+ {
+ *IoStatusBlock = KernelIosb;
+
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ KernelIosb.Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Backup our complete context in case it exists */
+ if (FileObject->CompletionContext)
+ {
+ CompletionInfo = *(FileObject->CompletionContext);
+ }
+
+ /* If we had an event, signal it */
+ if (Event)
+ {
+ KeSetEvent(EventObject, IO_NO_INCREMENT, FALSE);
+ ObDereferenceObject(EventObject);
+ }
+
+ /* If FO was locked, unlock it */
+ if (LockedForSynch)
+ {
+ IopUnlockFileObject(FileObject);
+ }
+
+ /* Set completion if required */
+ if (CompletionInfo.Port != NULL && UserApcContext != NULL)
+ {
+ if (!NT_SUCCESS(IoSetIoCompletion(CompletionInfo.Port,
+ CompletionInfo.Key,
+ UserApcContext,
+ KernelIosb.Status,
+ KernelIosb.Information,
+ TRUE)))
+ {
+ KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ /* We're done with FastIO! */
+ ObDereferenceObject(FileObject);
+ return KernelIosb.Status;
+ }
+ }
+ }
+
/* Clear the event */
KeClearEvent(&FileObject->Event);
/* Allocate IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
- if (!Irp) return IopCleanupFailedIrp(FileObject, Event, NULL);
+ if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
/* Setup the IRP */
Irp->UserIosb = IoStatusBlock;
StackPtr->Parameters.DeviceIoControl.OutputBufferLength =
OutputBufferLength;
+ PoolType = IsDevIoCtl ? NonPagedPoolCacheAligned : NonPagedPool;
+
/* Handle the Methods */
switch (AccessType)
{
{
/* Allocate the System Buffer */
Irp->AssociatedIrp.SystemBuffer =
- ExAllocatePoolWithTag(NonPagedPool,
- BufferLength,
- TAG_SYS_BUF);
+ ExAllocatePoolWithQuotaTag(PoolType,
+ BufferLength,
+ TAG_SYS_BUF);
/* Check if we got a buffer */
if (InputBuffer)
{
/* Allocate the System Buffer */
Irp->AssociatedIrp.SystemBuffer =
- ExAllocatePoolWithTag(NonPagedPool,
- InputBufferLength,
- TAG_SYS_BUF);
+ ExAllocatePoolWithQuotaTag(PoolType,
+ InputBufferLength,
+ TAG_SYS_BUF);
/* Copy into the System Buffer */
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
}
/* Check if we got an output buffer */
- if (OutputBuffer)
+ if (OutputBufferLength)
{
/* Allocate the System Buffer */
Irp->MdlAddress = IoAllocateMdl(OutputBuffer,
}
/* Use deferred completion for FS I/O */
- Irp->Flags |= (!IsDevIoCtl) ? IRP_DEFER_IO_COMPLETION : 0;
+ if (!IsDevIoCtl)
+ {
+ Irp->Flags |= IRP_DEFER_IO_COMPLETION;
+ }
+
+ /* If we are dismounting a volume, increaase the dismount count */
+ if (IoControlCode == FSCTL_DISMOUNT_VOLUME)
+ {
+ InterlockedIncrement((PLONG)&SharedUserData->DismountCount);
+ }
/* Perform the call */
return IopPerformSynchronousRequest(DeviceObject,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
- IopLockFileObject(FileObject);
+ (void)IopLockFileObject(FileObject, KernelMode);
/* Use File Object event */
KeClearEvent(&FileObject->Event);
/* Check if this was synch I/O */
if (!LocalEvent)
{
- /* Check if the requet is pending */
+ /* Check if the request is pending */
if (Status == STATUS_PENDING)
{
/* Wait on the file object */
RenameInfo->RootDirectory,
NULL);
- /* And open its parent directory */
+ /* And open its parent directory
+ * Use hint if specified
+ */
if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
{
+ PFILE_OBJECT_EXTENSION FileObjectExtension;
+
ASSERT(!(FileObject->Flags & FO_DIRECT_DEVICE_OPEN));
-#if 0
- /* Commented out - we don't support FO extension yet
- * FIXME: Corrected last arg when it's supported
- */
+
+ FileObjectExtension = FileObject->FileObjectExtension;
Status = IoCreateFileSpecifyDeviceObjectHint(&TargetHandle,
DesiredAccess | SYNCHRONIZE,
&ObjectAttributes,
CreateFileTypeNone,
NULL,
IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY | IO_NO_PARAMETER_CHECKING,
- FileObject->DeviceObject);
-#else
- ASSERT(FALSE);
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-#endif
+ FileObjectExtension->TopDeviceObjectHint);
}
else
{
return STATUS_SUCCESS;
}
+static
+ULONG
+IopGetFileMode(IN PFILE_OBJECT FileObject)
+{
+ ULONG Mode = 0;
+
+ if (FileObject->Flags & FO_WRITE_THROUGH)
+ Mode |= FILE_WRITE_THROUGH;
+
+ if (FileObject->Flags & FO_SEQUENTIAL_ONLY)
+ Mode |= FILE_SEQUENTIAL_ONLY;
+
+ if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
+ Mode |= FILE_NO_INTERMEDIATE_BUFFERING;
+
+ if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+ {
+ if (FileObject->Flags & FO_ALERTABLE_IO)
+ Mode |= FILE_SYNCHRONOUS_IO_ALERT;
+ else
+ Mode |= FILE_SYNCHRONOUS_IO_NONALERT;
+ }
+
+ if (FileObject->Flags & FO_DELETE_ON_CLOSE)
+ Mode |= FILE_DELETE_ON_CLOSE;
+
+ return Mode;
+}
+
/* PUBLIC FUNCTIONS **********************************************************/
/*
IOTRACE(IO_API_DEBUG, "FileObject: %p. Mdl: %p. Offset: %p \n",
FileObject, Mdl, Offset);
+ /* Is the write originating from Cc? */
+ if (FileObject->SectionObjectPointer != NULL &&
+ FileObject->SectionObjectPointer->SharedCacheMap != NULL)
+ {
+ ++CcDataFlushes;
+ CcDataPages += BYTES_TO_PAGES(MmGetMdlByteCount(Mdl));
+ }
+
/* Get the Device Object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* Allocate IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
- if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
+ /* If allocation failed, try to see whether we can use
+ * the reserve IRP
+ */
+ if (Irp == NULL)
+ {
+ /* We will use it only for paging file */
+ if (MmIsFileObjectAPagingFile(FileObject))
+ {
+ InterlockedExchangeAdd(&IoPageReadIrpAllocationFailure, 1);
+ Irp = IopAllocateReserveIrp(DeviceObject->StackSize);
+ }
+ else
+ {
+ InterlockedExchangeAdd(&IoPageReadNonPagefileIrpAllocationFailure, 1);
+ }
+
+ /* If allocation failed (not a paging file or too big stack size)
+ * Fail for real
+ */
+ if (Irp == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
/* Get the Stack */
StackPtr = IoGetNextIrpStackLocation(Irp);
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
- IopLockFileObject(FileObject);
+ (void)IopLockFileObject(FileObject, KernelMode);
/* Use File Object event */
KeClearEvent(&FileObject->Event);
/* Check if this was synch I/O */
if (!LocalEvent)
{
- /* Check if the requet is pending */
+ /* Check if the request is pending */
if (Status == STATUS_PENDING)
{
/* Wait on the file object */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
- IopLockFileObject(FileObject);
+ Status = IopLockFileObject(FileObject, PreviousMode);
+ if (Status != STATUS_SUCCESS)
+ {
+ ObDereferenceObject(FileObject);
+ return Status;
+ }
}
else
{
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
- IopLockFileObject(FileObject);
+ Status = IopLockFileObject(FileObject, PreviousMode);
+ if (Status != STATUS_SUCCESS)
+ {
+ if (Event) ObDereferenceObject(Event);
+ ObDereferenceObject(FileObject);
+ return Status;
+ }
LockedForSync = TRUE;
}
LARGE_INTEGER CapturedByteOffset, CapturedLength;
NTSTATUS Status;
OBJECT_HANDLE_INFORMATION HandleInformation;
+ PFAST_IO_DISPATCH FastIoDispatch;
PAGED_CODE();
CapturedByteOffset.QuadPart = 0;
CapturedLength.QuadPart = 0;
/* Get the device object */
DeviceObject = IoGetRelatedDeviceObject(FileObject);
+ /* Try to do it the FastIO way if possible */
+ FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+ if (FastIoDispatch != NULL && FastIoDispatch->FastIoLock != NULL)
+ {
+ IO_STATUS_BLOCK KernelIosb;
+
+ if (FastIoDispatch->FastIoLock(FileObject,
+ &CapturedByteOffset,
+ &CapturedLength,
+ PsGetCurrentProcess(),
+ Key,
+ FailImmediately,
+ ExclusiveLock,
+ &KernelIosb,
+ DeviceObject))
+ {
+ /* Write the IOSB back */
+ _SEH2_TRY
+ {
+ *IoStatusBlock = KernelIosb;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ KernelIosb.Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* If we had an event, signal it */
+ if (EventHandle)
+ {
+ KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+ ObDereferenceObject(Event);
+ }
+
+ /* Set completion if required */
+ if (FileObject->CompletionContext != NULL && ApcContext != NULL)
+ {
+ if (!NT_SUCCESS(IoSetIoCompletion(FileObject->CompletionContext->Port,
+ FileObject->CompletionContext->Key,
+ ApcContext,
+ KernelIosb.Status,
+ KernelIosb.Information,
+ TRUE)))
+ {
+ KernelIosb.Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ FileObject->LockOperation = TRUE;
+
+ /* We're done with FastIO! */
+ ObDereferenceObject(FileObject);
+ return KernelIosb.Status;
+ }
+ }
+
/* Check if we should use Sync IO or not */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
- IopLockFileObject(FileObject);
+ Status = IopLockFileObject(FileObject, PreviousMode);
+ if (Status != STATUS_SUCCESS)
+ {
+ if (Event) ObDereferenceObject(Event);
+ ObDereferenceObject(FileObject);
+ return Status;
+ }
LockedForSync = TRUE;
}
return Status;
}
+ /* Are there two associated completion routines? */
+ if (FileObject->CompletionContext != NULL && ApcRoutine != NULL)
+ {
+ ObDereferenceObject(FileObject);
+ if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
+ return STATUS_INVALID_PARAMETER;
+ }
+
/* Check if we have an even handle */
if (EventHandle)
{
if (!NT_SUCCESS(Status))
{
/* Fail */
+ if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
ObDereferenceObject(FileObject);
return Status;
}
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
- IopLockFileObject(FileObject);
+ Status = IopLockFileObject(FileObject, PreviousMode);
+ if (Status != STATUS_SUCCESS)
+ {
+ if (Event) ObDereferenceObject(Event);
+ ObDereferenceObject(FileObject);
+ if (AuxBuffer) ExFreePoolWithTag(AuxBuffer, TAG_SYSB);
+ return Status;
+ }
/* Remember to unlock later */
LockedForSynch = TRUE;
PVOID NormalContext;
KIRQL OldIrql;
IO_STATUS_BLOCK KernelIosb;
+ BOOLEAN CallDriver = TRUE;
+ PFILE_ACCESS_INFORMATION AccessBuffer;
+ PFILE_MODE_INFORMATION ModeBuffer;
+ PFILE_ALIGNMENT_INFORMATION AlignmentBuffer;
+ PFILE_ALL_INFORMATION AllBuffer;
+ PFAST_IO_DISPATCH FastIoDispatch;
PAGED_CODE();
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
}
_SEH2_END;
}
+#if DBG
else
{
/* Validate the information class */
return STATUS_INFO_LENGTH_MISMATCH;
}
}
+#endif
/* Reference the Handle */
Status = ObReferenceObjectByHandle(FileHandle,
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
- IopLockFileObject(FileObject);
+ Status = IopLockFileObject(FileObject, PreviousMode);
+ if (Status != STATUS_SUCCESS)
+ {
+ ObDereferenceObject(FileObject);
+ return Status;
+ }
/* Check if the caller just wants the position */
if (FileInformationClass == FilePositionInformation)
LocalEvent = TRUE;
}
+ /* Check if FastIO is possible for the two available information classes */
+ FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+ if (FastIoDispatch != NULL &&
+ ((FileInformationClass == FileBasicInformation && FastIoDispatch->FastIoQueryBasicInfo != NULL) ||
+ (FileInformationClass == FileStandardInformation && FastIoDispatch->FastIoQueryStandardInfo != NULL)))
+ {
+ BOOLEAN Success = FALSE;
+
+ if (FileInformationClass == FileBasicInformation)
+ {
+ Success = FastIoDispatch->FastIoQueryBasicInfo(FileObject, TRUE,
+ FileInformation,
+ &KernelIosb,
+ DeviceObject);
+ }
+ else
+ {
+ Success = FastIoDispatch->FastIoQueryStandardInfo(FileObject, TRUE,
+ FileInformation,
+ &KernelIosb,
+ DeviceObject);
+ }
+
+ /* If call succeed */
+ if (Success)
+ {
+ /* Write the IOSB back */
+ _SEH2_TRY
+ {
+ *IoStatusBlock = KernelIosb;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ KernelIosb.Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Free the event if we had one */
+ if (LocalEvent)
+ {
+ ExFreePoolWithTag(Event, TAG_IO);
+ }
+
+ /* If FO was locked, unlock it */
+ if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+ {
+ IopUnlockFileObject(FileObject);
+ }
+
+ /* We're done with FastIO! */
+ ObDereferenceObject(FileObject);
+ return KernelIosb.Status;
+ }
+ }
+
/* Clear the File Object event */
KeClearEvent(&FileObject->Event);
/* Update operation counts */
IopUpdateOperationCount(IopOtherTransfer);
+ /* Fill in file information before calling the driver.
+ See 'File System Internals' page 485.*/
+ if (FileInformationClass == FileAccessInformation)
+ {
+ AccessBuffer = Irp->AssociatedIrp.SystemBuffer;
+ AccessBuffer->AccessFlags = HandleInformation.GrantedAccess;
+ Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION);
+ CallDriver = FALSE;
+ }
+ else if (FileInformationClass == FileModeInformation)
+ {
+ ModeBuffer = Irp->AssociatedIrp.SystemBuffer;
+ ModeBuffer->Mode = IopGetFileMode(FileObject);
+ Irp->IoStatus.Information = sizeof(FILE_MODE_INFORMATION);
+ CallDriver = FALSE;
+ }
+ else if (FileInformationClass == FileAlignmentInformation)
+ {
+ AlignmentBuffer = Irp->AssociatedIrp.SystemBuffer;
+ AlignmentBuffer->AlignmentRequirement = DeviceObject->AlignmentRequirement;
+ Irp->IoStatus.Information = sizeof(FILE_ALIGNMENT_INFORMATION);
+ CallDriver = FALSE;
+ }
+ else if (FileInformationClass == FileAllInformation)
+ {
+ AllBuffer = Irp->AssociatedIrp.SystemBuffer;
+ AllBuffer->AccessInformation.AccessFlags = HandleInformation.GrantedAccess;
+ AllBuffer->ModeInformation.Mode = IopGetFileMode(FileObject);
+ AllBuffer->AlignmentInformation.AlignmentRequirement = DeviceObject->AlignmentRequirement;
+ Irp->IoStatus.Information = sizeof(FILE_ACCESS_INFORMATION) +
+ sizeof(FILE_MODE_INFORMATION) +
+ sizeof(FILE_ALIGNMENT_INFORMATION);
+ }
+
/* Call the Driver */
- Status = IoCallDriver(DeviceObject, Irp);
+ if (CallDriver)
+ {
+ Status = IoCallDriver(DeviceObject, Irp);
+ }
+ else
+ {
+ Status = STATUS_SUCCESS;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+
if (Status == STATUS_PENDING)
{
/* Check if this was async I/O */
ULONG CapturedKey = 0;
BOOLEAN Synchronous = FALSE;
PMDL Mdl;
+ PFAST_IO_DISPATCH FastIoDispatch;
+ IO_STATUS_BLOCK KernelIosb;
+ BOOLEAN Success;
+
PAGED_CODE();
CapturedByteOffset.QuadPart = 0;
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
+ /* Get File Object */
+ Status = ObReferenceObjectByHandle(FileHandle,
+ FILE_READ_DATA,
+ IoFileObjectType,
+ PreviousMode,
+ (PVOID*)&FileObject,
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Get the device object */
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
/* Validate User-Mode Buffers */
if (PreviousMode != KernelMode)
{
CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
}
+ /* Perform additional checks for non-cached file access */
+ if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
+ {
+ /* Fail if Length is not sector size aligned
+ * Perform a quick check for 2^ sector sizes
+ * If it fails, try a more standard way
+ */
+ if ((DeviceObject->SectorSize != 0) &&
+ ((DeviceObject->SectorSize - 1) & Length) != 0)
+ {
+ if (Length % DeviceObject->SectorSize != 0)
+ {
+ /* Release the file object and and fail */
+ ObDereferenceObject(FileObject);
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ /* Fail if buffer doesn't match alignment requirements */
+ if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0)
+ {
+ /* Release the file object and and fail */
+ ObDereferenceObject(FileObject);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (ByteOffset)
+ {
+ /* Fail if ByteOffset is not sector size aligned */
+ if ((DeviceObject->SectorSize != 0) &&
+ (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0))
+ {
+ /* Release the file object and and fail */
+ ObDereferenceObject(FileObject);
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+
/* Capture and probe the key */
if (Key) CapturedKey = ProbeForReadUlong(Key);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- /* Return the exception code */
+ /* Release the file object and return the exception code */
+ ObDereferenceObject(FileObject);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
if (Key) CapturedKey = *Key;
}
- /* Get File Object */
- Status = ObReferenceObjectByHandle(FileHandle,
- FILE_READ_DATA,
- IoFileObjectType,
- PreviousMode,
- (PVOID*)&FileObject,
- NULL);
- if (!NT_SUCCESS(Status)) return Status;
-
/* Check for event */
if (Event)
{
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock the file object */
- IopLockFileObject(FileObject);
+ Status = IopLockFileObject(FileObject, PreviousMode);
+ if (Status != STATUS_SUCCESS)
+ {
+ if (EventObject) ObDereferenceObject(EventObject);
+ ObDereferenceObject(FileObject);
+ return Status;
+ }
- /* Check if we don't have a byte offset avilable */
+ /* Check if we don't have a byte offset available */
if (!(ByteOffset) ||
((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
(CapturedByteOffset.u.HighPart == -1)))
CapturedByteOffset = FileObject->CurrentByteOffset;
}
+ /* If the file is cached, try fast I/O */
+ if (FileObject->PrivateCacheMap)
+ {
+ /* Perform fast read */
+ FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+ ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL);
+
+ Success = FastIoDispatch->FastIoRead(FileObject,
+ &CapturedByteOffset,
+ Length,
+ TRUE,
+ CapturedKey,
+ Buffer,
+ &KernelIosb,
+ DeviceObject);
+
+ /* Only accept the result if we got a straightforward status */
+ if (Success &&
+ (KernelIosb.Status == STATUS_SUCCESS ||
+ KernelIosb.Status == STATUS_BUFFER_OVERFLOW ||
+ KernelIosb.Status == STATUS_END_OF_FILE))
+ {
+ /* Fast path -- update transfer & operation counts */
+ IopUpdateOperationCount(IopReadTransfer);
+ IopUpdateTransferCount(IopReadTransfer,
+ (ULONG)KernelIosb.Information);
+
+ /* Enter SEH to write the IOSB back */
+ _SEH2_TRY
+ {
+ /* Write it back to the caller */
+ *IoStatusBlock = KernelIosb;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* The caller's IOSB was invalid, so fail */
+ if (EventObject) ObDereferenceObject(EventObject);
+ IopUnlockFileObject(FileObject);
+ ObDereferenceObject(FileObject);
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ /* Signal the completion event */
+ if (EventObject)
+ {
+ KeSetEvent(EventObject, 0, FALSE);
+ ObDereferenceObject(EventObject);
+ }
+
+ /* Clean up */
+ IopUnlockFileObject(FileObject);
+ ObDereferenceObject(FileObject);
+ return KernelIosb.Status;
+ }
+ }
+
/* Remember we are sync */
Synchronous = TRUE;
}
return STATUS_INVALID_PARAMETER;
}
- /* Get the device object */
- DeviceObject = IoGetRelatedDeviceObject(FileObject);
-
/* Clear the File Object's event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
- if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
+ if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
/* Set the IRP */
Irp->Tail.Overlay.OriginalFileObject = FileObject;
DeviceObject = IoGetRelatedDeviceObject(FileObject);
}
+ DPRINT("Will call: %p\n", DeviceObject);
+ DPRINT("Associated driver: %p (%wZ)\n", DeviceObject->DriverObject, &DeviceObject->DriverObject->DriverName);
+
/* Check if this is a file that was opened for Synch I/O */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
- IopLockFileObject(FileObject);
+ Status = IopLockFileObject(FileObject, PreviousMode);
+ if (Status != STATUS_SUCCESS)
+ {
+ ObDereferenceObject(FileObject);
+ return Status;
+ }
/* Check if the caller just wants the position */
if (FileInformationClass == FilePositionInformation)
NTSTATUS Status;
OBJECT_HANDLE_INFORMATION HandleInformation;
IO_STATUS_BLOCK KernelIosb;
+ PFAST_IO_DISPATCH FastIoDispatch;
PAGED_CODE();
CapturedByteOffset.QuadPart = 0;
CapturedLength.QuadPart = 0;
DeviceObject = IoGetRelatedDeviceObject(FileObject);
}
+ /* Try to do it the FastIO way if possible */
+ FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+ if (FastIoDispatch != NULL && FastIoDispatch->FastIoUnlockSingle != NULL)
+ {
+ if (FastIoDispatch->FastIoUnlockSingle(FileObject,
+ &CapturedByteOffset,
+ &CapturedLength,
+ PsGetCurrentProcess(),
+ Key,
+ &KernelIosb,
+ DeviceObject))
+ {
+ /* Write the IOSB back */
+ _SEH2_TRY
+ {
+ *IoStatusBlock = KernelIosb;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ KernelIosb.Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* We're done with FastIO! */
+ ObDereferenceObject(FileObject);
+ return KernelIosb.Status;
+ }
+ }
+
/* Check if we should use Sync IO or not */
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
- IopLockFileObject(FileObject);
+ Status = IopLockFileObject(FileObject, PreviousMode);
+ if (Status != STATUS_SUCCESS)
+ {
+ ObDereferenceObject(FileObject);
+ return Status;
+ }
}
else
{
BOOLEAN Synchronous = FALSE;
PMDL Mdl;
OBJECT_HANDLE_INFORMATION ObjectHandleInfo;
+ PFAST_IO_DISPATCH FastIoDispatch;
+ IO_STATUS_BLOCK KernelIosb;
+ BOOLEAN Success;
+
PAGED_CODE();
CapturedByteOffset.QuadPart = 0;
IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
- /* Get File Object */
- Status = ObReferenceObjectByHandle(FileHandle,
- 0,
- IoFileObjectType,
- PreviousMode,
- (PVOID*)&FileObject,
- &ObjectHandleInfo);
+ /* Get File Object for write */
+ Status = ObReferenceFileObjectForWrite(FileHandle,
+ PreviousMode,
+ &FileObject,
+ &ObjectHandleInfo);
if (!NT_SUCCESS(Status)) return Status;
+ /* Get the device object */
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+
/* Validate User-Mode Buffers */
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
- /*
- * Check if the handle has either FILE_WRITE_DATA or
- * FILE_APPEND_DATA 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);
- _SEH2_YIELD(return STATUS_ACCESS_DENIED);
- }
-
/* Probe the status block */
ProbeForWriteIoStatusBlock(IoStatusBlock);
CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
}
+ /* Perform additional checks for non-cached file access */
+ if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
+ {
+ /* Fail if Length is not sector size aligned
+ * Perform a quick check for 2^ sector sizes
+ * If it fails, try a more standard way
+ */
+ if ((DeviceObject->SectorSize != 0) &&
+ ((DeviceObject->SectorSize - 1) & Length) != 0)
+ {
+ if (Length % DeviceObject->SectorSize != 0)
+ {
+ /* Release the file object and and fail */
+ ObDereferenceObject(FileObject);
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ /* Fail if buffer doesn't match alignment requirements */
+ if (((ULONG_PTR)Buffer & DeviceObject->AlignmentRequirement) != 0)
+ {
+ /* Release the file object and and fail */
+ ObDereferenceObject(FileObject);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (ByteOffset)
+ {
+ /* Fail if ByteOffset is not sector size aligned */
+ if ((DeviceObject->SectorSize != 0) &&
+ (CapturedByteOffset.QuadPart % DeviceObject->SectorSize != 0))
+ {
+ /* Only if that's not specific values for synchronous IO */
+ if ((CapturedByteOffset.QuadPart != FILE_WRITE_TO_END_OF_FILE) &&
+ (CapturedByteOffset.QuadPart != FILE_USE_FILE_POINTER_POSITION ||
+ !BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO)))
+ {
+ /* Release the file object and and fail */
+ ObDereferenceObject(FileObject);
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+ }
+
/* Capture and probe the key */
if (Key) CapturedKey = ProbeForReadUlong(Key);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- /* Return the exception code */
+ /* Release the file object and return the exception code */
+ ObDereferenceObject(FileObject);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock the file object */
- IopLockFileObject(FileObject);
+ Status = IopLockFileObject(FileObject, PreviousMode);
+ if (Status != STATUS_SUCCESS)
+ {
+ if (EventObject) ObDereferenceObject(EventObject);
+ ObDereferenceObject(FileObject);
+ return Status;
+ }
- /* Check if we don't have a byte offset avilable */
+ /* Check if we don't have a byte offset available */
if (!(ByteOffset) ||
((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&
(CapturedByteOffset.u.HighPart == -1)))
CapturedByteOffset = FileObject->CurrentByteOffset;
}
+ /* If the file is cached, try fast I/O */
+ if (FileObject->PrivateCacheMap)
+ {
+ /* Perform fast write */
+ FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+ ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoWrite != NULL);
+
+ Success = FastIoDispatch->FastIoWrite(FileObject,
+ &CapturedByteOffset,
+ Length,
+ TRUE,
+ CapturedKey,
+ Buffer,
+ &KernelIosb,
+ DeviceObject);
+
+ /* Only accept the result if it was successful */
+ if (Success &&
+ KernelIosb.Status == STATUS_SUCCESS)
+ {
+ /* Fast path -- update transfer & operation counts */
+ IopUpdateOperationCount(IopWriteTransfer);
+ IopUpdateTransferCount(IopWriteTransfer,
+ (ULONG)KernelIosb.Information);
+
+ /* Enter SEH to write the IOSB back */
+ _SEH2_TRY
+ {
+ /* Write it back to the caller */
+ *IoStatusBlock = KernelIosb;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* The caller's IOSB was invalid, so fail */
+ if (EventObject) ObDereferenceObject(EventObject);
+ IopUnlockFileObject(FileObject);
+ ObDereferenceObject(FileObject);
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ /* Signal the completion event */
+ if (EventObject)
+ {
+ KeSetEvent(EventObject, 0, FALSE);
+ ObDereferenceObject(EventObject);
+ }
+
+ /* Clean up */
+ IopUnlockFileObject(FileObject);
+ ObDereferenceObject(FileObject);
+ return KernelIosb.Status;
+ }
+ }
+
/* Remember we are sync */
Synchronous = TRUE;
}
return STATUS_INVALID_PARAMETER;
}
- /* Get the device object */
- DeviceObject = IoGetRelatedDeviceObject(FileObject);
-
/* Clear the File Object's event */
KeClearEvent(&FileObject->Event);
/* Allocate the IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
- if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
+ if (!Irp) return IopCleanupFailedIrp(FileObject, EventObject, NULL);
/* Set the IRP */
Irp->Tail.Overlay.OriginalFileObject = FileObject;
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
- IopLockFileObject(FileObject);
+ Status = IopLockFileObject(FileObject, PreviousMode);
+ if (Status != STATUS_SUCCESS)
+ {
+ ObDereferenceObject(FileObject);
+ return Status;
+ }
}
else
{
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock it */
- IopLockFileObject(FileObject);
+ Status = IopLockFileObject(FileObject, PreviousMode);
+ if (Status != STATUS_SUCCESS)
+ {
+ ObDereferenceObject(FileObject);
+ if (TargetDeviceObject) ObDereferenceObject(TargetDeviceObject);
+ return Status;
+ }
}
else
{