Author: ion Date: Sat Jul 8 22:17:26 2006 New Revision: 22928
URL: http://svn.reactos.org/svn/reactos?rev=22928&view=rev Log: - Uber-optimize IopQueryAttributesFile by using the OPEN_PACKET mechanism to query file attributes, instead of doing lots of slow native calls. - Modify IopParseDevice to detect when OPEN_PACKET optimizations are in use (query or deletion (deletion not yet implemented)) and have some codepaths be slightly different and use DUMMY_FILE_OBJECT. - Implement QueryOnly case in IopParseDevice to handle attribute queries. - Add a missing dereference, and remove an extra DO reference.
Modified: trunk/reactos/ntoskrnl/io/iomgr/file.c
Modified: trunk/reactos/ntoskrnl/io/iomgr/file.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/file.c?re... ============================================================================== --- trunk/reactos/ntoskrnl/io/iomgr/file.c (original) +++ trunk/reactos/ntoskrnl/io/iomgr/file.c Sat Jul 8 22:17:26 2006 @@ -38,18 +38,12 @@ PEXTENDED_IO_STACK_LOCATION StackLoc; IO_SECURITY_CONTEXT SecurityContext; IO_STATUS_BLOCK IoStatusBlock; - BOOLEAN DirectOpen = FALSE; + BOOLEAN DirectOpen = FALSE, OpenCancelled, UseDummyFile; OBJECT_ATTRIBUTES ObjectAttributes; - BOOLEAN OpenCancelled; KIRQL OldIrql; - DPRINT("IopParseDevice:\n" - "DeviceObject : %p\n" - "RelatedFileObject : %p\n" - "CompleteName : %wZ, RemainingName : %wZ\n", - ParseObject, - Context, - CompleteName, - RemainingName); + PDUMMY_FILE_OBJECT DummyFileObject; + PFILE_BASIC_INFORMATION FileBasicInfo; + ULONG ReturnLength;
/* Assume failure */ *Object = NULL; @@ -76,8 +70,13 @@ SeSetAccessStateGenericMapping(AccessState, &IoFileObjectType->TypeInfo.GenericMapping);
+ /* Check if we can simply use a dummy file */ + UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly)); + /* Check if this is a direct open */ - if (!(RemainingName->Length) && !(OpenPacket->RelatedFileObject)) + if (!(RemainingName->Length) && + !(OpenPacket->RelatedFileObject) && + !(UseDummyFile)) { /* Remember this for later */ DirectOpen = TRUE; @@ -127,74 +126,86 @@ } }
- /* Create the actual file object */ - InitializeObjectAttributes(&ObjectAttributes, - NULL, - Attributes, - NULL, - NULL); - Status = ObCreateObject(KernelMode, - IoFileObjectType, - &ObjectAttributes, - AccessMode, - NULL, - sizeof(FILE_OBJECT), - 0, - 0, - (PVOID*)&FileObject); - RtlZeroMemory(FileObject, sizeof(FILE_OBJECT)); - - /* Set the device object and reference it */ - Status = IopReferenceDeviceObject(DeviceObject); - FileObject->DeviceObject = DeviceObject; + /* Check if we really need to create an object */ + if (!UseDummyFile) + { + /* Create the actual file object */ + InitializeObjectAttributes(&ObjectAttributes, + NULL, + Attributes, + NULL, + NULL); + Status = ObCreateObject(KernelMode, + IoFileObjectType, + &ObjectAttributes, + AccessMode, + NULL, + sizeof(FILE_OBJECT), + 0, + 0, + (PVOID*)&FileObject); + RtlZeroMemory(FileObject, sizeof(FILE_OBJECT)); + + /* Check if this is Synch I/O */ + if (OpenPacket->CreateOptions & + (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) + { + /* Set the synch flag */ + FileObject->Flags |= FO_SYNCHRONOUS_IO; + + /* Check if it's also alertable */ + if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) + { + /* It is, set the alertable flag */ + FileObject->Flags |= FO_ALERTABLE_IO; + } + } + + /* Check if the caller requested no intermediate buffering */ + if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) + { + /* Set the correct flag for the FSD to read */ + FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING; + } + + /* Check if the caller requested write through support */ + if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH) + { + /* Set the correct flag for the FSD to read */ + FileObject->Flags |= FO_WRITE_THROUGH; + } + + /* Check if the caller says the file will be only read sequentially */ + if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY) + { + /* Set the correct flag for the FSD to read */ + FileObject->Flags |= FO_SEQUENTIAL_ONLY; + } + + /* Check if the caller believes the file will be only read randomly */ + if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS) + { + /* Set the correct flag for the FSD to read */ + FileObject->Flags |= FO_RANDOM_ACCESS; + } + } + else + { + /* Use the dummy object instead */ + DummyFileObject = OpenPacket->DummyFileObject; + RtlZeroMemory(DummyFileObject, sizeof(DUMMY_FILE_OBJECT)); + + /* Set it up */ + FileObject = (PFILE_OBJECT)&DummyFileObject->ObjectHeader.Body; + DummyFileObject->ObjectHeader.Type = IoFileObjectType; + DummyFileObject->ObjectHeader.PointerCount = 1; + }
/* Setup the file header */ FileObject->Type = IO_TYPE_FILE; FileObject->Size = sizeof(FILE_OBJECT); FileObject->RelatedFileObject = OpenPacket->RelatedFileObject; - - /* Check if this is Synch I/O */ - if (OpenPacket->CreateOptions & - (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) - { - /* Set the synch flag */ - FileObject->Flags |= FO_SYNCHRONOUS_IO; - - /* Check if it's also alertable */ - if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) - { - /* It is, set the alertable flag */ - FileObject->Flags |= FO_ALERTABLE_IO; - } - } - - /* Check if the caller requested no intermediate buffering */ - if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) - { - /* Set the correct flag for the FSD to read */ - FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING; - } - - /* Check if the caller requested write through support */ - if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH) - { - /* Set the correct flag for the FSD to read */ - FileObject->Flags |= FO_WRITE_THROUGH; - } - - /* Check if the caller believes the file will be only read sequentially */ - if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY) - { - /* Set the correct flag for the FSD to read */ - FileObject->Flags |= FO_SEQUENTIAL_ONLY; - } - - /* Check if the caller believes the file will be only read randomly */ - if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS) - { - /* Set the correct flag for the FSD to read */ - FileObject->Flags |= FO_RANDOM_ACCESS; - } + FileObject->DeviceObject = DeviceObject;
/* Check if this is a direct device open */ if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN; @@ -315,8 +326,11 @@ IopDereferenceDeviceObject(DeviceObject, FALSE); if (Vpb) IopDereferenceVpb(Vpb);
- /* Clear the FO */ + /* Clear the FO and dereference it */ FileObject->DeviceObject = NULL; + if (!UseDummyFile) ObDereferenceObject(FileObject); + + /* Fail */ return STATUS_INSUFFICIENT_RESOURCES; } } @@ -324,7 +338,7 @@ /* Copy the name */ RtlCopyUnicodeString(&FileObject->FileName, RemainingName);
- /* Reference the file object and call the driver */ + /* Reference the file object */ ObReferenceObject(FileObject);
/* Initialize the File Object event and set the FO */ @@ -402,7 +416,7 @@ OpenPacket->FileObject = NULL;
/* Dereference the file object */ - ObDereferenceObject(FileObject); + if (!UseDummyFile) ObDereferenceObject(FileObject);
/* Unless the driver canelled the open, dereference the VPB */ if (!(OpenCancelled) && (Vpb)) IopDereferenceVpb(Vpb); @@ -417,14 +431,77 @@ KEBUGCHECK(0); }
- /* Otherwise, we were successful. Reference the object, set status */ - ObReferenceObject(FileObject); - OpenPacket->FinalStatus = IoStatusBlock.Status; - OpenPacket->ParseCheck = TRUE; - - /* Return the object and status */ - *Object = FileObject; - return OpenPacket->FinalStatus; + /* Make sure we are not using a dummy */ + if (!UseDummyFile) + { + /* Reference the object and set the parse check */ + ObReferenceObject(FileObject); + *Object = FileObject; + OpenPacket->FinalStatus = IoStatusBlock.Status; + OpenPacket->ParseCheck = TRUE; + return OpenPacket->FinalStatus; + } + else + { + /* Check if this was a query */ + if (OpenPacket->QueryOnly) + { + /* Check if the caller wants basic info only */ + if (!OpenPacket->FullAttributes) + { + /* Allocate the buffer */ + FileBasicInfo = ExAllocatePoolWithTag(NonPagedPool, + sizeof(*FileBasicInfo), + TAG_IO); + if (FileBasicInfo) + { + /* Do the query */ + Status = IoQueryFileInformation(FileObject, + FileBasicInformation, + sizeof(*FileBasicInfo), + FileBasicInfo, + &ReturnLength); + if (NT_SUCCESS(Status)) + { + /* Copy the data */ + RtlCopyMemory(OpenPacket->BasicInformation, + FileBasicInfo, + ReturnLength); + } + + /* Free our buffer */ + ExFreePool(FileBasicInfo); + } + else + { + /* Fail */ + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + else + { + /* This is a full query */ + Status = IoQueryFileInformation( + FileObject, + FileNetworkOpenInformation, + sizeof(FILE_NETWORK_OPEN_INFORMATION), + OpenPacket->NetworkInformation, + &ReturnLength); + if (!NT_SUCCESS(Status)) ASSERT(Status != STATUS_NOT_IMPLEMENTED); + } + } + + /* Delete the file object */ + IopDeleteFile(FileObject); + + /* Clear out the file */ + OpenPacket->FileObject = NULL; + + /* Set and return status */ + OpenPacket->FinalStatus = Status; + OpenPacket->ParseCheck = TRUE; + return Status; + } }
NTSTATUS @@ -957,112 +1034,119 @@ NTAPI IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes, IN FILE_INFORMATION_CLASS FileInformationClass, + IN ULONG FileInformationSize, OUT PVOID FileInformation) { - IO_STATUS_BLOCK IoStatusBlock; - HANDLE FileHandle; - NTSTATUS Status; - KPROCESSOR_MODE AccessMode; - UNICODE_STRING ObjectName; - OBJECT_CREATE_INFORMATION ObjectCreateInfo; - OBJECT_ATTRIBUTES LocalObjectAttributes; - ULONG BufferSize; - union - { - FILE_BASIC_INFORMATION BasicInformation; - FILE_NETWORK_OPEN_INFORMATION NetworkOpenInformation; - }LocalFileInformation; - - if (FileInformationClass == FileBasicInformation) - { - BufferSize = sizeof(FILE_BASIC_INFORMATION); - } - else if (FileInformationClass == FileNetworkOpenInformation) - { - BufferSize = sizeof(FILE_NETWORK_OPEN_INFORMATION); + NTSTATUS Status = STATUS_SUCCESS; + KPROCESSOR_MODE AccessMode = ExGetPreviousMode(); + DUMMY_FILE_OBJECT DummyFileObject; + FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo; + HANDLE Handle; + OPEN_PACKET OpenPacket; + BOOLEAN IsBasic; + PAGED_CODE(); + + /* Check if the caller was user mode */ + if (AccessMode != KernelMode) + { + /* Protect probe in SEH */ + _SEH_TRY + { + /* Probe the buffer */ + ProbeForWrite(FileInformation, FileInformationSize, sizeof(ULONG)); + } + _SEH_HANDLE + { + /* Get the exception code */ + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + /* Fail on exception */ + if (!NT_SUCCESS(Status))return Status; + } + + /* Check if this is a basic or full request */ + IsBasic = (FileInformationSize == sizeof(FILE_BASIC_INFORMATION)); + + /* Setup the Open Packet */ + OpenPacket.Type = IO_TYPE_OPEN_PACKET; + OpenPacket.Size = sizeof(OPEN_PACKET); + OpenPacket.FileObject = NULL; + OpenPacket.FinalStatus = STATUS_SUCCESS; + OpenPacket.Information = 0; + OpenPacket.ParseCheck = 0; + OpenPacket.RelatedFileObject = NULL; + OpenPacket.AllocationSize.QuadPart = 0; + OpenPacket.CreateOptions = FILE_OPEN_REPARSE_POINT; + OpenPacket.FileAttributes = 0; + OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + OpenPacket.EaBuffer = NULL; + OpenPacket.EaLength = 0; + OpenPacket.Options = 0; + OpenPacket.Disposition = FILE_OPEN; + OpenPacket.BasicInformation = IsBasic ? FileInformation : NULL; + OpenPacket.NetworkInformation = IsBasic ? &NetworkOpenInfo : + (AccessMode != KernelMode) ? + &NetworkOpenInfo : FileInformation; + OpenPacket.CreateFileType = 0; + OpenPacket.MailslotOrPipeParameters = NULL; + OpenPacket.Override = FALSE; + OpenPacket.QueryOnly = TRUE; + OpenPacket.DeleteOnly = FALSE; + OpenPacket.FullAttributes = IsBasic ? FALSE : TRUE; + OpenPacket.DummyFileObject = &DummyFileObject; + OpenPacket.InternalFlags = 0; + + /* Update the operation count */ + IopUpdateOperationCount(IopOtherTransfer); + + /* + * Attempt opening the file. This will call the I/O Parse Routine for + * the File Object (IopParseDevice) which will use the dummy file obejct + * send the IRP to its device object. Note that we have two statuses + * to worry about: the Object Manager's status (in Status) and the I/O + * status, which is in the Open Packet's Final Status, and determined + * by the Parse Check member. + */ + Status = ObOpenObjectByName(ObjectAttributes, + NULL, + AccessMode, + NULL, + FILE_READ_ATTRIBUTES, + &OpenPacket, + &Handle); + if (OpenPacket.ParseCheck != TRUE) + { + /* Parse failed */ + return Status; } else { - return STATUS_INVALID_PARAMETER; - } - - AccessMode = ExGetPreviousMode(); - - if (AccessMode != KernelMode) - { - Status = STATUS_SUCCESS; + /* Use the Io status */ + Status = OpenPacket.FinalStatus; + } + + /* Check if we were succesful and this was user mode and a full query */ + if ((NT_SUCCESS(Status)) && (AccessMode != KernelMode) && !(IsBasic)) + { + /* Enter SEH for copy */ _SEH_TRY { - ProbeForWrite(FileInformation, - BufferSize, - sizeof(ULONG)); + /* Copy the buffer back */ + RtlMoveMemory(FileInformation, + &NetworkOpenInfo, + FileInformationSize); } _SEH_HANDLE { + /* Get exception code */ Status = _SEH_GetExceptionCode(); } _SEH_END; - if (NT_SUCCESS(Status)) - { - Status = ObpCaptureObjectAttributes(ObjectAttributes, - AccessMode, - FALSE, - &ObjectCreateInfo, - &ObjectName); - } - if (!NT_SUCCESS(Status)) - { - return Status; - } - InitializeObjectAttributes(&LocalObjectAttributes, - &ObjectName, - ObjectCreateInfo.Attributes, - ObjectCreateInfo.RootDirectory, - ObjectCreateInfo.SecurityDescriptor); - } - - /* Open the file */ - Status = ZwOpenFile(&FileHandle, - SYNCHRONIZE | FILE_READ_ATTRIBUTES, - AccessMode == KernelMode ? ObjectAttributes : &LocalObjectAttributes, - &IoStatusBlock, - 0, - FILE_SYNCHRONOUS_IO_NONALERT); - if (AccessMode != KernelMode) - { - ObpReleaseCapturedAttributes(&ObjectCreateInfo); - if (ObjectName.Buffer) ObpReleaseCapturedName(&ObjectName); - } - if (!NT_SUCCESS (Status)) - { - DPRINT ("ZwOpenFile() failed (Status %lx)\n", Status); - return Status; - } - - /* Get file attributes */ - Status = ZwQueryInformationFile(FileHandle, - &IoStatusBlock, - AccessMode == KernelMode ? FileInformation : &LocalFileInformation, - BufferSize, - FileInformationClass); - if (!NT_SUCCESS (Status)) - { - DPRINT ("ZwQueryInformationFile() failed (Status %lx)\n", Status); - } - ZwClose(FileHandle); - - if (NT_SUCCESS(Status) && AccessMode != KernelMode) - { - _SEH_TRY - { - memcpy(FileInformation, &LocalFileInformation, BufferSize); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } + } + + /* Return status */ return Status; }
@@ -1228,6 +1312,9 @@ OpenPacket.DummyFileObject = NULL; OpenPacket.InternalFlags = 0;
+ /* Update the operation count */ + IopUpdateOperationCount(IopOtherTransfer); + /* * Attempt opening the file. This will call the I/O Parse Routine for * the File Object (IopParseDevice) which will create the object and @@ -1386,7 +1473,7 @@ sizeof(FILE_OBJECT), 0, (PVOID*)&CreatedFileObject); - if (!NT_SUCCESS(Status)) return (NULL); + if (!NT_SUCCESS(Status)) return NULL;
/* Choose Device Object */ if (FileObject) DeviceObject = FileObject->DeviceObject; @@ -1764,8 +1851,10 @@ NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PFILE_BASIC_INFORMATION FileInformation) { + /* Call the internal helper API */ return IopQueryAttributesFile(ObjectAttributes, FileBasicInformation, + sizeof(FILE_BASIC_INFORMATION), FileInformation); }
@@ -1774,9 +1863,11 @@ NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation) { - return IopQueryAttributesFile(ObjectAttributes, - FileNetworkOpenInformation, - FileInformation); + /* Call the internal helper API */ + return IopQueryAttributesFile(ObjectAttributes, + FileNetworkOpenInformation, + sizeof(FILE_NETWORK_OPEN_INFORMATION), + FileInformation); }
/**