Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1353 lines
35 KiB

/*++
Copyright (c) 1998-2002 Microsoft Corporation
Module Name:
filecache.c
Abstract:
This module implements the open file handle cache.
Author:
Keith Moore (keithmo) 21-Aug-1998
Revision History:
--*/
#include "precomp.h"
//
// Private constants.
//
//
// Private types.
//
//
// Private prototypes.
//
NTSTATUS
UlpRestartReadFileEntry(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp,
IN PVOID pContext
);
NTSTATUS
UlpRestartReadCompleteFileEntry(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp,
IN PVOID pContext
);
//
// Private globals.
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text( INIT, InitializeFileCache )
#pragma alloc_text( PAGE, TerminateFileCache )
#pragma alloc_text( PAGE, UlCreateFileEntry )
#pragma alloc_text( PAGE, UlFailMdlReadDev )
#pragma alloc_text( PAGE, UlFailMdlReadCompleteDev )
#pragma alloc_text( PAGE, UlReadFileEntry )
#pragma alloc_text( PAGE, UlReadFileEntryFast )
#pragma alloc_text( PAGE, UlReadCompleteFileEntry )
#pragma alloc_text( PAGE, UlReadCompleteFileEntryFast )
#endif // ALLOC_PRAGMA
#if 0
NOT PAGEABLE -- UlpRestartReadFileEntry
NOT PAGEABLE -- UlpRestartReadCompleteFileEntry
#endif
//
// Public functions.
//
/***************************************************************************++
Routine Description:
Performs global initialization of the open file cache.
Arguments:
None.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
InitializeFileCache(
VOID
)
{
return STATUS_SUCCESS; // NYI
} // InitializeFileCache
/***************************************************************************++
Routine Description:
Performs global termination of the open file cache.
Arguments:
None.
Return Value:
None.
--***************************************************************************/
VOID
TerminateFileCache(
VOID
)
{
} // TerminateFileCache
/***************************************************************************++
Routine Description:
Creates a new file entry for the specified file.
Arguments:
FileHandle - The file handle.
pFileCacheEntry - Receives the newly created file cache entry if
successful.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlCreateFileEntry(
IN HANDLE FileHandle,
IN OUT PUL_FILE_CACHE_ENTRY pFileCacheEntry
)
{
NTSTATUS Status;
PFILE_OBJECT pFileObject;
IO_STATUS_BLOCK IoStatusBlock;
PFAST_IO_DISPATCH pFastIoDispatch;
FILE_STANDARD_INFORMATION FileInfo;
FILE_FS_SIZE_INFORMATION SizeInfo;
//
// Sanity check.
//
PAGED_CODE();
//
// Setup locals so we know how to cleanup on exit.
//
pFileObject = NULL;
Status = STATUS_SUCCESS;
RtlZeroMemory( pFileCacheEntry, sizeof(*pFileCacheEntry) );
pFileCacheEntry->Signature = UL_FILE_CACHE_ENTRY_SIGNATURE;
UlTrace(FILE_CACHE, (
"UlCreateFileEntry: handle %p\n",
(PVOID) FileHandle
));
//
// Get a referenced pointer to the file object.
//
Status = ObReferenceObjectByHandle(
FileHandle, // Handle
FILE_READ_ACCESS, // DesiredAccess
*IoFileObjectType, // ObjectType
UserMode, // AccessMode
(PVOID *) &pFileObject, // Object
NULL // HandleInformation
);
if (NT_SUCCESS(Status) == FALSE)
goto end;
pFileCacheEntry->pFileObject = pFileObject;
//
// Snag the device object from the file object, then fill in the
// fast I/O routines. The code here was shamelessly stolen from
// the NT SMB server.
//
pFileCacheEntry->pDeviceObject = IoGetRelatedDeviceObject( pFileObject );
//
// Assume no fast I/O, and then query the fast I/O dispath routines.
//
pFileCacheEntry->pMdlRead = &UlFailMdlReadDev;
pFileCacheEntry->pMdlReadComplete = &UlFailMdlReadCompleteDev;
pFastIoDispatch =
pFileCacheEntry->pDeviceObject->DriverObject->FastIoDispatch;
//
// Query MdlRead.
//
if (pFastIoDispatch != NULL &&
pFastIoDispatch->SizeOfFastIoDispatch >
FIELD_OFFSET(FAST_IO_DISPATCH, MdlRead) &&
pFastIoDispatch->MdlRead != NULL)
{
//
// Fill in MdlRead call if the file system's vector is large
// enough. We still need to check if the routines is specified.
//
pFileCacheEntry->pMdlRead = pFastIoDispatch->MdlRead;
}
//
// Query MdlReadComplete.
//
if (pFastIoDispatch != NULL &&
pFastIoDispatch->SizeOfFastIoDispatch >
FIELD_OFFSET(FAST_IO_DISPATCH, MdlReadComplete) &&
pFastIoDispatch->MdlReadComplete != NULL)
{
//
// Fill in MdlReadComplete call if the file system's vector is large
// enough. We still need to check if the routines is specified.
//
pFileCacheEntry->pMdlReadComplete = pFastIoDispatch->MdlReadComplete;
}
//
// Get the file size, etc from the file. Note that, since we *may*
// be running in the context of a user-mode thread, we need to
// use the Zw form of the API rather than the Nt form.
//
if (!pFastIoDispatch ||
pFastIoDispatch->SizeOfFastIoDispatch <=
FIELD_OFFSET(FAST_IO_DISPATCH, FastIoQueryStandardInfo) ||
!pFastIoDispatch->FastIoQueryStandardInfo ||
!pFastIoDispatch->FastIoQueryStandardInfo(
pFileObject,
TRUE,
&FileInfo,
&IoStatusBlock,
pFileCacheEntry->pDeviceObject
))
{
Status = ZwQueryInformationFile(
FileHandle, // FileHandle
&IoStatusBlock, // IoStatusBlock,
&FileInfo, // FileInformation,
sizeof(FileInfo), // Length
FileStandardInformation // FileInformationClass
);
if (NT_SUCCESS(Status) == FALSE)
goto end;
}
pFileCacheEntry->EndOfFile = FileInfo.EndOfFile;
//
// Get the file size information for the SectorSize.
//
if (!(pFileObject->Flags & FO_CACHE_SUPPORTED))
{
if (pFileCacheEntry->pDeviceObject->SectorSize)
{
pFileCacheEntry->BytesPerSector =
pFileCacheEntry->pDeviceObject->SectorSize;
}
else
{
Status = ZwQueryVolumeInformationFile(
FileHandle,
&IoStatusBlock,
&SizeInfo,
sizeof(SizeInfo),
FileFsSizeInformation
);
if (NT_SUCCESS(Status) == FALSE)
goto end;
pFileCacheEntry->BytesPerSector = SizeInfo.BytesPerSector;
}
}
//
// Success!
//
UlTrace(FILE_CACHE, (
"UlCreateFileEntry: entry %p, handle %lx [%p]\n",
pFileCacheEntry,
FileHandle,
pFileObject
));
end:
if (NT_SUCCESS(Status) == FALSE)
{
//
// If we made it to this point, then the open has failed.
//
UlTrace(FILE_CACHE, (
"UlCreateFileEntry: handle %p, failure %08lx\n",
FileHandle,
Status
));
UlDestroyFileCacheEntry( pFileCacheEntry );
}
return Status;
} // UlCreateFileEntry
/***************************************************************************++
Routine Description:
Reads data from a file. Does a MDL read for filesystems that support
MDL reads. If the fs doesn't support MDL reads, this function
allocates a buffer to hold the data.
Arguments:
pFileBuffer - Contains all the info about the read, and the data
once that's been read.
pIrp - This IRP is used to issue the read.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlReadFileEntry(
IN OUT PUL_FILE_BUFFER pFileBuffer,
IN PIRP pIrp
)
{
NTSTATUS Status;
PIO_STACK_LOCATION pIrpSp;
PUL_FILE_CACHE_ENTRY pFile;
PUCHAR pFileData;
PMDL pMdl;
ULONG ReadLength;
ULONG SectorSize;
ULONG RelativeOffset;
ULONGLONG ReadOffset;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( pFileBuffer );
ASSERT( IS_FILE_BUFFER_IN_USE( pFileBuffer ) );
ASSERT( IS_VALID_FILE_CACHE_ENTRY( pFileBuffer->pFileCacheEntry ) );
ASSERT( IS_VALID_IRP( pIrp ) );
pFile = pFileBuffer->pFileCacheEntry;
if (pFile->pFileObject->Flags & FO_CACHE_SUPPORTED)
{
UlTrace(FILE_CACHE, (
"UlReadFileEntry(Buffer = %p, pFile = %p, pIrp = %p) MDL Read\n",
pFileBuffer,
pFile,
pIrp
));
//
// Caching file system. Do a MDL read.
//
pIrpSp = IoGetNextIrpStackLocation( pIrp );
pIrpSp->MajorFunction = IRP_MJ_READ;
pIrpSp->MinorFunction = IRP_MN_MDL;
pIrpSp->FileObject = pFile->pFileObject;
pIrpSp->DeviceObject = pFile->pDeviceObject;
//
// Initialize the IRP.
//
pIrp->MdlAddress = NULL;
pIrp->Tail.Overlay.Thread = UlQueryIrpThread();
//
// Indicate to the file system that this operation can be handled
// synchronously. Basically, this means that the file system can
// use our thread to fault pages in, etc. This avoids
// having to context switch to a file system thread.
//
pIrp->Flags = IRP_SYNCHRONOUS_API;
//
// Set the number of bytes to read and the offset.
//
pIrpSp->Parameters.Read.Length = pFileBuffer->Length;
pIrpSp->Parameters.Read.ByteOffset.QuadPart =
pFileBuffer->FileOffset.QuadPart;
ASSERT( pIrpSp->Parameters.Read.Key == 0 );
//
// Set up the completion routine.
//
IoSetCompletionRoutine(
pIrp, // Irp
UlpRestartReadFileEntry, // CompletionRoutine
pFileBuffer, // Context
TRUE, // InvokeOnSuccess
TRUE, // InvokeOnError
TRUE // InvokeOnCancel
);
//
// Call the driver. Note that we always set status to
// STATUS_PENDING, since we set the IRP completion routine
// to *always* be called.
//
UlCallDriver( pFile->pDeviceObject, pIrp );
Status = STATUS_PENDING;
}
else
{
UlTrace(FILE_CACHE, (
"UlReadFileEntry(Buffer = %p, pFile = %p, pIrp = %p) NoCache Read\n",
pFileBuffer,
pFile,
pIrp
));
//
// Non-caching file system. Allocate a buffer and issue a
// normal read. The buffer needs to be aligned on the sector
// size to make the read truely async.
//
SectorSize = pFile->BytesPerSector;
ASSERT( SectorSize > 0 );
ASSERT( 0 == (SectorSize & (SectorSize - 1)) );
ReadLength = (pFileBuffer->Length + SectorSize - 1) & ~(SectorSize - 1);
//
// Align down the offset as well on SectorSize - this is required
// for NOCACHE read.
//
ReadOffset = pFileBuffer->FileOffset.QuadPart;
ReadOffset &= ~((ULONGLONG) SectorSize - 1);
ASSERT( ReadOffset <= pFileBuffer->FileOffset.QuadPart );
RelativeOffset = pFileBuffer->RelativeOffset =
(ULONG) (pFileBuffer->FileOffset.QuadPart - ReadOffset);
//
// We may have to allocate an extra SectorSize of bytes.
//
if ((pFileBuffer->Length + RelativeOffset) > ReadLength)
{
ReadLength += SectorSize;
}
pFileData = (PUCHAR) UL_ALLOCATE_POOL(
NonPagedPool,
ReadLength,
UL_NONCACHED_FILE_DATA_POOL_TAG
);
if (!pFileData)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
//
// Get a MDL for our buffer.
//
pMdl = UlAllocateMdl(
pFileData,
ReadLength,
FALSE,
FALSE,
NULL
);
if (!pMdl)
{
UL_FREE_POOL(
pFileData,
UL_NONCACHED_FILE_DATA_POOL_TAG
);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
MmBuildMdlForNonPagedPool( pMdl );
pFileBuffer->pMdl = pMdl;
//
// Remember where the data is.
//
pFileBuffer->pFileData = pFileData;
//
// Set up the read information.
//
pIrpSp = IoGetNextIrpStackLocation( pIrp );
pIrpSp->MajorFunction = IRP_MJ_READ;
pIrpSp->MinorFunction = IRP_MN_NORMAL;
pIrpSp->FileObject = pFile->pFileObject;
pIrpSp->DeviceObject = pFile->pDeviceObject;
//
// Initialize the IRP.
//
pIrp->MdlAddress = NULL;
pIrp->Tail.Overlay.Thread = UlQueryIrpThread();
//
// Indicate to the file system that this operation can be handled
// synchronously. Basically, this means that the file system can
// use the server's thread to fault pages in, etc. This avoids
// having to context switch to a file system thread.
//
pIrp->Flags = IRP_NOCACHE;
//
// Set the number of bytes to read and the offset.
//
pIrpSp->Parameters.Read.Length = ReadLength;
pIrpSp->Parameters.Read.ByteOffset.QuadPart = ReadOffset;
ASSERT( pIrpSp->Parameters.Read.Key == 0 );
//
// If the target device does buffered I/O, load the address of the
// caller's buffer as the "system buffered I/O buffer". If the
// target device does direct I/O, load the MDL address. If it does
// neither, load both the user buffer address and the MDL address.
// (This is necessary to support file systems, such as HPFS, that
// sometimes treat the I/O as buffered and sometimes treat it as
// direct.)
//
if (pFileBuffer->pFileCacheEntry->pDeviceObject->Flags & DO_BUFFERED_IO)
{
pIrp->AssociatedIrp.SystemBuffer = pFileData;
pIrp->Flags |= IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
}
else
if (pFileBuffer->pFileCacheEntry->pDeviceObject->Flags & DO_DIRECT_IO)
{
pIrp->MdlAddress = pMdl;
}
else
{
pIrp->UserBuffer = pFileData;
pIrp->MdlAddress = pMdl;
}
//
// Set up the completion routine.
//
IoSetCompletionRoutine(
pIrp, // Irp
UlpRestartReadFileEntry, // CompletionRoutine
pFileBuffer, // Context
TRUE, // InvokeOnSuccess
TRUE, // InvokeOnError
TRUE // InvokeOnCancel
);
//
// Call the driver. Note that we always set status to
// STATUS_PENDING, since we set the IRP completion routine
// to *always* be called.
//
UlCallDriver( pFile->pDeviceObject, pIrp );
Status = STATUS_PENDING;
}
end:
return Status;
} // UlReadFileEntry
/***************************************************************************++
Routine Description:
Reads data from a file. Does a MDL read for filesystems that support
MDL reads and Fast I/O. If the FS doesn't support fast i/o and MDL
reads, the function returns with a failure status.
Arguments:
pFileBuffer - Contains all the info about the read, and the data
once that's been read.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlReadFileEntryFast(
IN OUT PUL_FILE_BUFFER pFileBuffer
)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatus;
PUL_FILE_CACHE_ENTRY pFile;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( pFileBuffer );
ASSERT( IS_FILE_BUFFER_IN_USE( pFileBuffer ) );
ASSERT( IS_VALID_FILE_CACHE_ENTRY( pFileBuffer->pFileCacheEntry ) );
pFile = pFileBuffer->pFileCacheEntry;
if (pFile->pFileObject->Flags & FO_CACHE_SUPPORTED)
{
UlTrace(FILE_CACHE, (
"UlReadFileEntryFast(Buffer = %p, pFile = %p) MDL Read\n",
pFileBuffer,
pFile
));
//
// Cached filesystem. Try to use the fast path for the MDL read
// complete.
//
if (pFileBuffer->pFileCacheEntry->pMdlRead(
pFileBuffer->pFileCacheEntry->pFileObject,
(PLARGE_INTEGER) &pFileBuffer->FileOffset,
pFileBuffer->Length,
0,
&pFileBuffer->pMdl,
&IoStatus,
pFileBuffer->pFileCacheEntry->pDeviceObject
))
{
Status = STATUS_SUCCESS;
}
else
{
//
// It didn't work. The caller must now use the IRP path
// by calling UlReadFileEntry.
//
Status = STATUS_UNSUCCESSFUL;
}
}
else
{
UlTrace(FILE_CACHE, (
"UlReadFileEntryFast(Buffer = %p, pFile = %p) NoCache Read\n",
pFileBuffer,
pFile
));
//
// Non-caching file system. No fast i/o. The caller should
// use the IRP path by calling UlReadFileEntry.
//
Status = STATUS_UNSUCCESSFUL;
}
return Status;
} // UlReadFileEntryFast
/***************************************************************************++
Routine Description:
Frees up resources allocated by UlReadFileEntry (or UlReadFileEntryFast).
Should be called when the file data read is no longer in use.
Arguments:
pFileBuffer - Contains all the info about the read, and the data
that was read.
pIrp - This IRP is used to issue the read completion.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlReadCompleteFileEntry(
IN PUL_FILE_BUFFER pFileBuffer,
IN PIRP pIrp
)
{
NTSTATUS Status;
PIO_STACK_LOCATION pIrpSp;
PUL_FILE_CACHE_ENTRY pFile;
UL_STATUS_BLOCK UlStatus;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( pFileBuffer );
ASSERT( IS_FILE_BUFFER_IN_USE( pFileBuffer ) );
ASSERT( IS_VALID_FILE_CACHE_ENTRY( pFileBuffer->pFileCacheEntry ) );
ASSERT( IS_VALID_IRP( pIrp ) );
pFile = pFileBuffer->pFileCacheEntry;
if (pFile->pFileObject->Flags & FO_CACHE_SUPPORTED)
{
UlTrace(FILE_CACHE, (
"UlReadCompleteFileEntry(Buffer = %p, pFile = %p, pIrp = %p) MDL Read\n",
pFileBuffer,
pFile,
pIrp
));
//
// Caching file system. Do a MDL read completion.
//
pIrpSp = IoGetNextIrpStackLocation( pIrp );
pIrpSp->MajorFunction = IRP_MJ_READ;
pIrpSp->MinorFunction = IRP_MN_MDL | IRP_MN_COMPLETE;
pIrpSp->FileObject = pFile->pFileObject;
pIrpSp->DeviceObject = pFile->pDeviceObject;
//
// Initialize the IRP.
//
pIrp->MdlAddress = pFileBuffer->pMdl;
pIrp->Tail.Overlay.Thread = UlQueryIrpThread();
pFileBuffer->pMdl = NULL;
//
// MDL functions are inherently synchronous.
//
pIrp->Flags = IRP_SYNCHRONOUS_API;
//
// Set the number of bytes to read and the offset.
//
pIrpSp->Parameters.Read.Length = pFileBuffer->Length;
pIrpSp->Parameters.Read.ByteOffset.QuadPart =
pFileBuffer->FileOffset.QuadPart;
ASSERT(pIrpSp->Parameters.Read.Key == 0);
if (pFileBuffer->pCompletionRoutine)
{
//
// Set up the completion routine. We don't need to do anything
// on the completion, so we'll just have the I/O manager call
// our callers routine directly.
//
IoSetCompletionRoutine(
pIrp, // Irp
pFileBuffer->pCompletionRoutine, // CompletionRoutine
pFileBuffer->pContext, // Context
TRUE, // InvokeOnSuccess
TRUE, // InvokeOnError
TRUE // InvokeOnCancel
);
//
// Call the driver. Note that we always set status to
// STATUS_PENDING, since we set the IRP completion routine
// to *always* be called.
//
UlCallDriver( pFile->pDeviceObject, pIrp );
Status = STATUS_PENDING;
}
else
{
//
// Caller has asked us to perform a synchronous operation by
// passing in a NULL completion routine. Initialize the UlStatus
// and wait for it to get signaled after calling UlCallDriver.
//
UlInitializeStatusBlock( &UlStatus );
IoSetCompletionRoutine(
pIrp, // Irp
UlpRestartReadCompleteFileEntry, // CompletionRoutine
&UlStatus, // Context
TRUE, // InvokeOnSuccess
TRUE, // InvokeOnError
TRUE // InvokeOnCancel
);
Status = UlCallDriver( pFile->pDeviceObject, pIrp );
if (STATUS_PENDING == Status)
{
//
// Wait for it to finish.
//
UlWaitForStatusBlockEvent( &UlStatus );
//
// Retrieve the updated status.
//
Status = UlStatus.IoStatus.Status;
}
}
}
else
{
UlTrace(FILE_CACHE, (
"UlReadCompleteFileEntry(Buffer = %p, pFile = %p) NoCache Read\n",
pFileBuffer,
pFile
));
//
// Non-caching file system. We allocated this buffer. Just
// free it and call the completion routine.
//
ASSERT( pFileBuffer->pMdl );
UlFreeMdl( pFileBuffer->pMdl );
pFileBuffer->pMdl = NULL;
ASSERT( pFileBuffer->pFileData );
UL_FREE_POOL(
pFileBuffer->pFileData,
UL_NONCACHED_FILE_DATA_POOL_TAG
);
pFileBuffer->pFileData = NULL;
//
// Fake the completion here.
//
if (pFileBuffer->pCompletionRoutine)
{
pFileBuffer->pCompletionRoutine(
pFileBuffer->pFileCacheEntry->pDeviceObject,
pIrp,
pFileBuffer->pContext
);
//
// Return pending, since we called their completion routine.
//
Status = STATUS_PENDING;
}
else
{
Status = STATUS_SUCCESS;
}
}
if (!NT_SUCCESS(Status))
{
UlTrace(FILE_CACHE, (
"UlReadCompleteFileEntry(Buffer = %p, pFile = %p) FAILED! %x\n",
pFileBuffer,
pFile,
Status
));
}
return Status;
} // UlReadCompleteFileEntry
/***************************************************************************++
Routine Description:
Frees up resources allocated by UlReadFileEntry (or UlReadFileEntryFast).
Should be called when the file data read is no longer in use.
Arguments:
pFileBuffer - Contains all the info about the read, and the data
that was read.
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlReadCompleteFileEntryFast(
IN PUL_FILE_BUFFER pFileBuffer
)
{
NTSTATUS Status;
PUL_FILE_CACHE_ENTRY pFile;
//
// Sanity check.
//
PAGED_CODE();
ASSERT( pFileBuffer );
ASSERT( IS_FILE_BUFFER_IN_USE( pFileBuffer ) );
ASSERT( IS_VALID_FILE_CACHE_ENTRY( pFileBuffer->pFileCacheEntry ) );
pFile = pFileBuffer->pFileCacheEntry;
if (pFile->pFileObject->Flags & FO_CACHE_SUPPORTED)
{
UlTrace(FILE_CACHE, (
"UlReadCompleteFileEntryFast(Buffer = %p, pFile = %p) MDL Read\n",
pFileBuffer,
pFile
));
//
// Cached filesystem. Try to use the fast path for the MDL read
// complete.
//
if (pFileBuffer->pFileCacheEntry->pMdlReadComplete(
pFileBuffer->pFileCacheEntry->pFileObject,
pFileBuffer->pMdl,
pFileBuffer->pFileCacheEntry->pDeviceObject
))
{
pFileBuffer->pMdl = NULL;
Status = STATUS_SUCCESS;
}
else
{
//
// It didn't work. The caller must now use the IRP path
// by calling UlReadCompleteFileEntry.
//
Status = STATUS_UNSUCCESSFUL;
}
}
else
{
UlTrace(FILE_CACHE, (
"UlReadCompleteFileEntryFast(Buffer = %p, pFile = %p) NoCache Read\n",
pFileBuffer,
pFile
));
//
// Non-caching file system. We allocated this buffer. Just
// free it.
//
ASSERT( pFileBuffer->pMdl );
UlFreeMdl( pFileBuffer->pMdl );
pFileBuffer->pMdl = NULL;
ASSERT( pFileBuffer->pFileData );
UL_FREE_POOL(
pFileBuffer->pFileData,
UL_NONCACHED_FILE_DATA_POOL_TAG
);
pFileBuffer->pFileData = NULL;
Status = STATUS_SUCCESS;
}
return Status;
} // UlReadCompleteFileEntryFast
/***************************************************************************++
Routine Description:
Helper function to destroy a file cache entry.
Arguments:
pWorkItem - Supplies a pointer to the work item queued. This should
point to the WORK_ITEM structure embedded in a UL_FILE_CACHE_ENTRY.
Return Value:
None.
--***************************************************************************/
VOID
UlDestroyFileCacheEntry(
PUL_FILE_CACHE_ENTRY pFileCacheEntry
)
{
//
// Sanity check.
//
PAGED_CODE();
UlTrace(FILE_CACHE, (
"UlDestroyFileCacheEntry: entry %p\n",
pFileCacheEntry
));
ASSERT( IS_VALID_FILE_CACHE_ENTRY( pFileCacheEntry ) );
//
// Cleanup the file system stuff.
//
if (pFileCacheEntry->pFileObject != NULL)
{
ObDereferenceObject( pFileCacheEntry->pFileObject );
pFileCacheEntry->pFileObject = NULL;
}
//
// Now release the entry's resources.
//
pFileCacheEntry->Signature = UL_FILE_CACHE_ENTRY_SIGNATURE_X;
} // UlDestroyFileCacheEntry
/***************************************************************************++
Routine Description:
Dummy function to fail MDL reads.
Arguments:
Same as FsRtlMdlReadDev().
Return Value:
BOOLEAN - Always FALSE (failure).
--***************************************************************************/
BOOLEAN
UlFailMdlReadDev(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN ULONG Length,
IN ULONG LockKey,
OUT PMDL *MdlChain,
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject
)
{
UNREFERENCED_PARAMETER( FileObject );
UNREFERENCED_PARAMETER( FileOffset );
UNREFERENCED_PARAMETER( Length );
UNREFERENCED_PARAMETER( LockKey );
UNREFERENCED_PARAMETER( MdlChain );
UNREFERENCED_PARAMETER( IoStatus );
UNREFERENCED_PARAMETER( DeviceObject );
PAGED_CODE();
return FALSE;
} // UlFailMdlReadDev
/***************************************************************************++
Routine Description:
Dummy function to fail MDL read completes.
Arguments:
Same as FsRtlMdlReadCompleteDev().
Return Value:
BOOLEAN - Always FALSE (failure).
--***************************************************************************/
BOOLEAN
UlFailMdlReadCompleteDev(
IN PFILE_OBJECT FileObject,
IN PMDL MdlChain,
IN PDEVICE_OBJECT DeviceObject
)
{
UNREFERENCED_PARAMETER( FileObject );
UNREFERENCED_PARAMETER( MdlChain );
UNREFERENCED_PARAMETER( DeviceObject );
PAGED_CODE();
return FALSE;
} // UlFailMdlReadCompleteDev
//
// Private functions.
//
/***************************************************************************++
Routine Description:
Completion routine for UlReadFileEntry. Sets the data fields in
the UL_FILE_BUFFER and calls the completion routine passed to
UlReadFileEntry.
Arguments:
pDeviceObject - the file system device object (not used)
pIrp - the IRP used to do the read
pContext - pointer to the UL_FILE_BUFFER
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlpRestartReadFileEntry(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp,
IN PVOID pContext
)
{
NTSTATUS Status;
PUL_FILE_BUFFER pFileBuffer = (PUL_FILE_BUFFER)pContext;
PUL_FILE_CACHE_ENTRY pFile;
PUCHAR pFileData;
ULONGLONG EffetiveLength;
//
// Sanity check.
//
ASSERT( pFileBuffer );
ASSERT( IS_FILE_BUFFER_IN_USE( pFileBuffer ) );
ASSERT( IS_VALID_FILE_CACHE_ENTRY( pFileBuffer->pFileCacheEntry ) );
pFile = pFileBuffer->pFileCacheEntry;
if (pFile->pFileObject->Flags & FO_CACHE_SUPPORTED)
{
//
// This was a MDL read.
//
if (NT_SUCCESS(pIrp->IoStatus.Status))
{
pFileBuffer->pMdl = pIrp->MdlAddress;
}
}
else
{
//
// This was a NoCache Read. pFileBuffer->pMdl
// was already set by UlReadFileEntry.
//
ASSERT( pFileBuffer->pMdl );
if (NT_SUCCESS(pIrp->IoStatus.Status))
{
//
// Set the byte count of the MDL to the true bytes we asked for
// and adjust the offset to skip the possible extra bytes we
// have read.
//
EffetiveLength =
pIrp->IoStatus.Information - pFileBuffer->RelativeOffset;
//
// Re-initialize the MDL if we have read at least what we have
// requested, otherwise, fail the read.
//
if (pIrp->IoStatus.Information >= pFileBuffer->RelativeOffset &&
EffetiveLength >= pFileBuffer->Length)
{
pFileData = pFileBuffer->pFileData +
pFileBuffer->RelativeOffset;
MmInitializeMdl(
pFileBuffer->pMdl,
pFileData,
pFileBuffer->Length
);
MmBuildMdlForNonPagedPool( pFileBuffer->pMdl );
pIrp->IoStatus.Information = pFileBuffer->Length;
}
else
{
pIrp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
pIrp->IoStatus.Information = 0;
}
}
}
if (pFileBuffer->pCompletionRoutine)
{
Status = (pFileBuffer->pCompletionRoutine)(
pDeviceObject,
pIrp,
pFileBuffer->pContext
);
}
else
{
Status = STATUS_MORE_PROCESSING_REQUIRED;
}
return Status;
} // UlpRestartReadFileEntry
/***************************************************************************++
Routine Description:
Completion routine for UlReadCompleteFileEntry. Simply call
UlSignalStatusBlock to unblock the waiting thread.
Arguments:
pDeviceObject - the file system device object (not used)
pIrp - the IRP used to do the read completion
pContext - pointer to the UL_STATUS_BLOCK
Return Value:
NTSTATUS - Completion status.
--***************************************************************************/
NTSTATUS
UlpRestartReadCompleteFileEntry(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp,
IN PVOID pContext
)
{
PUL_STATUS_BLOCK pStatus = (PUL_STATUS_BLOCK) pContext;
UNREFERENCED_PARAMETER( pDeviceObject );
//
// Signal the read completion has been completed.
//
UlSignalStatusBlock(
pStatus,
pIrp->IoStatus.Status,
pIrp->IoStatus.Information
);
return STATUS_MORE_PROCESSING_REQUIRED;
} // UlpRestartReadCompleteFileEntry