Author: ion Date: Tue Jul 4 20:50:56 2006 New Revision: 22837
URL: http://svn.reactos.org/svn/reactos?rev=22837&view=rev Log: - Fix NtSetInformationFile 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 except for Completion Ports, like the previous code).
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 20:50:56 2006 @@ -24,12 +24,6 @@ /// // // TODO: -// - Update to new semantics: -// - Lock/Unlock <= DONE -// - Query/Set Volume Info <= DONE -// - Read/Write file <= DONE -// - QueryDirectoryFile <= DONE -// - 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 @@ -2014,311 +2008,311 @@ */ NTSTATUS NTAPI -NtSetInformationFile(HANDLE FileHandle, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass) +NtSetInformationFile(IN HANDLE FileHandle, + IN PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass) { - OBJECT_HANDLE_INFORMATION HandleInformation; + PFILE_OBJECT FileObject; + NTSTATUS Status = STATUS_SUCCESS; + PIRP Irp; + PDEVICE_OBJECT DeviceObject; PIO_STACK_LOCATION StackPtr; - PFILE_OBJECT FileObject; - PDEVICE_OBJECT DeviceObject; - PIRP Irp; - KEVENT Event; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + PKEVENT Event = NULL; BOOLEAN LocalEvent = FALSE; - NTSTATUS Status = STATUS_SUCCESS; - KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); - BOOLEAN Failed = FALSE; - + PKNORMAL_ROUTINE NormalRoutine; + PVOID NormalContext; + KIRQL OldIrql; + IO_STATUS_BLOCK KernelIosb; + PVOID Queue; + PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation; + PIO_COMPLETION_CONTEXT Context; + + /* Check if we're called from user mode */ if (PreviousMode != KernelMode) { + /* Enter SEH for probing */ _SEH_TRY { - if (IoStatusBlock) - { - ProbeForWrite(IoStatusBlock, - sizeof(IO_STATUS_BLOCK), - sizeof(ULONG)); - } - + /* Probe the I/O Status block */ + ProbeForWrite(IoStatusBlock, + sizeof(IO_STATUS_BLOCK), + sizeof(ULONG)); + + /* Probe the information */ if (Length) ProbeForRead(FileInformation, Length, 1); } _SEH_HANDLE { + /* Get the exception code */ Status = _SEH_GetExceptionCode(); } _SEH_END; - - if (!NT_SUCCESS(Status)) - { - return Status; - } - } - - /* Get the file object from the file handle */ + + /* Check if probing failed */ + if (!NT_SUCCESS(Status)) return Status; + } + + /* Reference the Handle */ Status = ObReferenceObjectByHandle(FileHandle, - 0, + 0, // FIXME IoFileObjectType, PreviousMode, (PVOID *)&FileObject, - &HandleInformation); + NULL); if (!NT_SUCCESS(Status)) return Status;
- /* Check information class specific access rights */ - switch (FileInformationClass) - { - case FileBasicInformation: - if (!(HandleInformation.GrantedAccess & FILE_WRITE_ATTRIBUTES)) - Failed = TRUE; - break; - - case FileDispositionInformation: - if (!(HandleInformation.GrantedAccess & DELETE)) - Failed = TRUE; - break; - - case FilePositionInformation: - if (!(HandleInformation.GrantedAccess & (FILE_READ_DATA | FILE_WRITE_DATA)) || - !(FileObject->Flags & FO_SYNCHRONOUS_IO)) - Failed = TRUE; - break; - - case FileEndOfFileInformation: - if (!(HandleInformation.GrantedAccess & FILE_WRITE_DATA)) - 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 - { - FileObject->CurrentByteOffset = ((PFILE_POSITION_INFORMATION)FileInformation)->CurrentByteOffset; - IoStatusBlock->Information = 0; - 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); + } + + /* Check if this is a file that was opened for Synch I/O */ + if (FileObject->Flags & FO_SYNCHRONOUS_IO) + { + /* Lock it */ + IopLockFileObject(FileObject); + + /* Check if the caller just wants the position */ + if (FileInformationClass == FilePositionInformation) + { + /* Protect write in SEH */ + _SEH_TRY + { + /* Write the offset */ + FileObject->CurrentByteOffset = + ((PFILE_POSITION_INFORMATION)FileInformation)-> + CurrentByteOffset; + + /* Fill out the I/O Status Block */ + IoStatusBlock->Information = 0; + 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 */ + Event = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_IO); + KeInitializeEvent(Event, SynchronizationEvent, FALSE); + LocalEvent = TRUE; + } + + /* Clear the File Object event */ + KeClearEvent(&FileObject->Event); + + /* Allocate the IRP */ + Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); + if (!Irp) return IopCleanupFailedIrp(FileObject, NULL); + + /* Set the IRP */ + Irp->Tail.Overlay.OriginalFileObject = FileObject; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); + Irp->RequestorMode = PreviousMode; + 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; + + /* Set the Stack Data */ + StackPtr = IoGetNextIrpStackLocation(Irp); + StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION; + StackPtr->FileObject = FileObject; + + /* Allocate a buffer */ + Irp->AssociatedIrp.SystemBuffer = + ExAllocatePoolWithTag(NonPagedPool, + Length, + TAG_SYSB); + + /* Copy the data into it */ + RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FileInformation, Length); + + /* Set the flags */ + Irp->Flags = (IRP_BUFFERED_IO | + IRP_DEALLOCATE_BUFFER | + IRP_DEFER_IO_COMPLETION); + + /* Set the Parameters */ + StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass; + StackPtr->Parameters.SetFile.Length = Length; + + /* Queue the IRP */ + //IopQueueIrpToThread(Irp); + + /* Update operation counts */ + IopUpdateOperationCount(IopOtherTransfer);
/* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */ /* Handle IO Completion Port quickly */ if (FileInformationClass == FileCompletionInformation) { - PVOID Queue; - PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation; - PIO_COMPLETION_CONTEXT Context; - - if (FileObject->Flags & FO_SYNCHRONOUS_IO || FileObject->CompletionContext != NULL) - { + /* Check if the file object already has a completion port */ + if ((FileObject->Flags & FO_SYNCHRONOUS_IO) || + (FileObject->CompletionContext)) + { + /* Fail */ Status = STATUS_INVALID_PARAMETER; } else { - if (Length < sizeof(FILE_COMPLETION_INFORMATION)) + /* Reference the Port */ + CompletionInfo = Irp->AssociatedIrp.SystemBuffer; + Status = ObReferenceObjectByHandle(CompletionInfo->Port, + IO_COMPLETION_MODIFY_STATE, + IoCompletionType, + PreviousMode, + (PVOID*)&Queue, + NULL); + if (NT_SUCCESS(Status)) { - Status = STATUS_INFO_LENGTH_MISMATCH; - } - else - { - /* Reference the Port */ - Status = ObReferenceObjectByHandle(CompletionInfo->Port, /* FIXME - protect with SEH! */ - IO_COMPLETION_MODIFY_STATE, - IoCompletionType, - PreviousMode, - (PVOID*)&Queue, - NULL); - if (NT_SUCCESS(Status)) + /* Allocate the Context */ + Context = ExAllocatePoolWithTag(PagedPool, + sizeof(IO_COMPLETION_CONTEXT), + IOC_TAG); + if (Context) { - /* Allocate the Context */ - Context = ExAllocatePoolWithTag(PagedPool, - sizeof(IO_COMPLETION_CONTEXT), - TAG('I', 'o', 'C', 'p')); - - if (Context != NULL) + /* Set the Data */ + Context->Key = CompletionInfo->Key; + Context->Port = Queue; + if (InterlockedCompareExchangePointer(&FileObject-> + CompletionContext, + Context, + NULL)) { - /* Set the Data */ - Context->Key = CompletionInfo->Key; /* FIXME - protect with SEH! */ - Context->Port = Queue; - - if (InterlockedCompareExchangePointer(&FileObject->CompletionContext, - Context, - NULL) != NULL) - { - /* someone else set the completion port in the - meanwhile, fail */ - ExFreePool(Context); - ObDereferenceObject(Queue); - Status = STATUS_INVALID_PARAMETER; - } - } - else - { - /* Dereference the Port now */ + /* + * Someone else set the completion port in the + * meanwhile, so dereference the port and fail. + */ + ExFreePool(Context); ObDereferenceObject(Queue); - Status = STATUS_INSUFFICIENT_RESOURCES; + Status = STATUS_INVALID_PARAMETER; } } + else + { + /* Dereference the Port now */ + ObDereferenceObject(Queue); + Status = STATUS_INSUFFICIENT_RESOURCES; + } } }
- /* Complete the I/O */ - ObDereferenceObject(FileObject); - return Status; - } - - /* Check if this is a direct open or not */ - if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN) - { - DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject); + /* Set the IRP Status */ + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; } else { - DeviceObject = IoGetRelatedDeviceObject(FileObject); - } - - /* Check if we should use Sync IO or not */ - if (FileObject->Flags & FO_SYNCHRONOUS_IO) - { - /* Use File Object event */ - KeClearEvent(&FileObject->Event); - } - else - { - /* Use local event */ - KeInitializeEvent(&Event, SynchronizationEvent, FALSE); - LocalEvent = TRUE; - } - - /* 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) - { - Status = STATUS_INSUFFICIENT_RESOURCES; - goto failfreeirp; - } - - /* Copy the data inside */ - if (PreviousMode != KernelMode) - { - _SEH_TRY - { - /* no need to probe again */ - RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, - FileInformation, - Length); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if (!NT_SUCCESS(Status)) - { - ExFreePoolWithTag(Irp->AssociatedIrp.SystemBuffer, - TAG_SYSB); - Irp->AssociatedIrp.SystemBuffer = NULL; -failfreeirp: - IoFreeIrp(Irp); - ObDereferenceObject(FileObject); - return Status; - } - } - else - { - RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, - FileInformation, - Length); - } - - /* Set up the IRP */ - Irp->Tail.Overlay.OriginalFileObject = FileObject; - Irp->RequestorMode = PreviousMode; - Irp->UserIosb = IoStatusBlock; - Irp->UserEvent = (LocalEvent) ? &Event : NULL; - Irp->Tail.Overlay.Thread = PsGetCurrentThread(); - Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; - Irp->Flags |= (LocalEvent) ? IRP_SYNCHRONOUS_API : 0; - - /* Set up Stack Data */ - StackPtr = IoGetNextIrpStackLocation(Irp); - StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION; - StackPtr->FileObject = FileObject; - - /* Set the Parameters */ - StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass; - StackPtr->Parameters.SetFile.Length = Length; - - /* Call the Driver */ - Status = IoCallDriver(DeviceObject, Irp); + /* Call the Driver */ + Status = IoCallDriver(DeviceObject, Irp); + } + + /* Check if we're waiting for the IRP to complete */ if (Status == STATUS_PENDING) { + /* Check if this was async I/O */ if (LocalEvent) { - KeWaitForSingleObject(&Event, - Executive, - PreviousMode, - FileObject->Flags & FO_ALERTABLE_IO, - NULL); + /* 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 { - Status = IoStatusBlock->Status; + /* 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); - _SEH_TRY + /* Wait for the IRP */ + Status = KeWaitForSingleObject(&FileObject->Event, + Executive, + PreviousMode, + FileObject->Flags & FO_ALERTABLE_IO, + NULL); + if ((Status == STATUS_USER_APC) || (Status == STATUS_ALERTED)) { - Status = FileObject->FinalStatus; + /* Abort the request */ + IopAbortInterruptedIrp(&FileObject->Event, Irp); } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } + + /* 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 */