/*
* 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 *****************************************************************/
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;
+
+ PAGED_CODE();
+
IOTRACE(IO_CTL_DEBUG, "Handle: %p. CTL: %lx. Type: %lx \n",
DeviceHandle, IoControlCode, IsDevIoCtl);
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);
}
/* 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,
/* 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 */
/* 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 */
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)
{
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,
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;
+
+ /* Unlock FO */
+ IopUnlockFileObject(FileObject);
+
+ /* We're done with FastIO! */
+ ObDereferenceObject(FileObject);
+ return KernelIosb.Status;
+ }
+ }
+
/* Clear the File Object event */
KeClearEvent(&FileObject->Event);
/* If the file is cached, try fast I/O */
if (FileObject->PrivateCacheMap)
{
- /* Perform fast write */
+ /* Perform fast read */
FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+ ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoRead != NULL);
+
Success = FastIoDispatch->FastIoRead(FileObject,
&CapturedByteOffset,
Length,
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)
{
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)
{
/* If the file is cached, try fast I/O */
if (FileObject->PrivateCacheMap)
{
- /* Perform fast read */
+ /* Perform fast write */
FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
+ ASSERT(FastIoDispatch != NULL && FastIoDispatch->FastIoWrite != NULL);
+
Success = FastIoDispatch->FastIoWrite(FileObject,
&CapturedByteOffset,
Length,