Author: ion Date: Mon Nov 13 01:31:45 2006 New Revision: 24730
URL: http://svn.reactos.org/svn/reactos?rev=24730&view=rev Log: - Cleanup fastio.c - Implement FsRtlMdlReadDev (this function is not called, no risk of regressions). - Move FsRtlAcquireFileExclusive and FsRtlReleaseFileExclusive from filelock.c to fastio.c. - Bugfix these functions to actually call FsRtlEnter/ExitFileSystem. - Huge cleanusp of filelock.c, but no code changes, except the usage of some simpler macros provided by NTIFS.H (with equivalent code).
Modified: trunk/reactos/ntoskrnl/fs/fastio.c trunk/reactos/ntoskrnl/fs/filelock.c
Modified: trunk/reactos/ntoskrnl/fs/fastio.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/fs/fastio.c?rev=24... ============================================================================== --- trunk/reactos/ntoskrnl/fs/fastio.c (original) +++ trunk/reactos/ntoskrnl/fs/fastio.c Mon Nov 13 01:31:45 2006 @@ -1,13 +1,12 @@ /* - * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/fs/fastio.c * PURPOSE: File System Routines which support Fast I/O or Cc Access. - * - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - */ - -/* INCLUDES ****************************************************************/ + * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) +*/ + +/* INCLUDES ******************************************************************/
#include <ntoskrnl.h> #define NDEBUG @@ -19,6 +18,7 @@ extern ULONG CcFastReadResourceMiss; extern ULONG CcFastReadWait; extern ULONG CcFastReadNoWait; +ULONG CcFastMdlReadNotPossible;
/* FUNCTIONS *****************************************************************/
@@ -26,8 +26,8 @@ * @implemented */ VOID -STDCALL -FsRtlIncrementCcFastReadResourceMiss( VOID ) +NTAPI +FsRtlIncrementCcFastReadResourceMiss(VOID) { CcFastReadResourceMiss++; } @@ -36,8 +36,8 @@ * @implemented */ VOID -STDCALL -FsRtlIncrementCcFastReadNotPossible( VOID ) +NTAPI +FsRtlIncrementCcFastReadNotPossible(VOID) { CcFastReadNotPossible++; } @@ -46,8 +46,8 @@ * @implemented */ VOID -STDCALL -FsRtlIncrementCcFastReadWait( VOID ) +NTAPI +FsRtlIncrementCcFastReadWait(VOID) { CcFastReadWait++; } @@ -56,86 +56,53 @@ * @implemented */ VOID -STDCALL -FsRtlIncrementCcFastReadNoWait( VOID ) +NTAPI +FsRtlIncrementCcFastReadNoWait(VOID) { CcFastReadNoWait++; }
/* - * NAME EXPORTED - * FsRtlCopyRead@32 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * NOTE - * From Bo Branten's ntifs.h v12. - * * @unimplemented */ BOOLEAN -STDCALL -FsRtlCopyRead(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN BOOLEAN Wait, - IN ULONG LockKey, +NTAPI +FsRtlCopyRead(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) + IN PDEVICE_OBJECT DeviceObject) { UNIMPLEMENTED; return FALSE; }
/* - * NAME EXPORTED - * FsRtlCopyWrite@32 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * NOTE - * From Bo Branten's ntifs.h v12. - * * @unimplemented */ BOOLEAN -STDCALL -FsRtlCopyWrite(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN BOOLEAN Wait, - IN ULONG LockKey, +NTAPI +FsRtlCopyWrite(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) + IN PDEVICE_OBJECT DeviceObject) { UNIMPLEMENTED; return FALSE; }
/* - * NAME EXPORTED - * FsRtlGetFileSize@8 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * * @implemented */ NTSTATUS -STDCALL +NTAPI FsRtlGetFileSize(IN PFILE_OBJECT FileObject, IN OUT PLARGE_INTEGER FileSize) { @@ -182,19 +149,10 @@ }
/* - * NAME EXPORTED - * FsRtlMdlRead@24 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * @implemented - */ -BOOLEAN -STDCALL + * @implemented + */ +BOOLEAN +NTAPI FsRtlMdlRead(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, @@ -244,19 +202,10 @@ }
/* - * NAME EXPORTED - * FsRtlMdlReadComplete@8 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * @implemented - */ -BOOLEAN -STDCALL + * @implemented + */ +BOOLEAN +NTAPI FsRtlMdlReadComplete(IN PFILE_OBJECT FileObject, IN OUT PMDL MdlChain) { @@ -291,25 +240,11 @@ return FsRtlMdlReadCompleteDev(FileObject, MdlChain, DeviceObject); }
- -/* - * NAME EXPORTED - * FsRtlMdlReadCompleteDev@12 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * NOTE - * From Bo Branten's ntifs.h v13. - * (CcMdlReadCompleteDev declared in internal/cc.h) - * - * @implemented - */ -BOOLEAN -STDCALL +/* + * @implemented + */ +BOOLEAN +NTAPI FsRtlMdlReadCompleteDev(IN PFILE_OBJECT FileObject, IN PMDL MdlChain, IN PDEVICE_OBJECT DeviceObject) @@ -320,19 +255,10 @@ }
/* - * NAME EXPORTED - * FsRtlMdlReadDev@28 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * @unimplemented - */ -BOOLEAN -STDCALL + * @implemented + */ +BOOLEAN +NTAPI FsRtlMdlReadDev(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, @@ -341,25 +267,115 @@ OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject) { - UNIMPLEMENTED; - return FALSE; -} - - -/* - * NAME EXPORTED - * FsRtlMdlWriteComplete@12 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * @implemented - */ -BOOLEAN -STDCALL + PFSRTL_COMMON_FCB_HEADER FcbHeader; + BOOLEAN Result = TRUE; + LARGE_INTEGER Offset; + PFAST_IO_DISPATCH FastIoDispatch; + PDEVICE_OBJECT Device; + PAGED_CODE(); + + /* No actual read */ + if (!Length) + { + /* Return success */ + IoStatus->Status = STATUS_SUCCESS; + IoStatus->Information = 0; + return TRUE; + } + + /* Sanity check */ + ASSERT(MAXLONGLONG - FileOffset->QuadPart >= (LONGLONG)Length); + + /* Get the offset and FCB header */ + Offset.QuadPart = FileOffset->QuadPart + Length; + FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; + + /* Enter the FS */ + FsRtlEnterFileSystem(); + CcFastMdlReadWait++; + + /* Lock the FCB */ + ExAcquireResourceShared(FcbHeader->Resource, TRUE); + + /* Check if this is a fast I/O cached file */ + if (!(FileObject->PrivateCacheMap) || + (FcbHeader->IsFastIoPossible == FastIoIsNotPossible)) + { + /* It's not, so fail */ + CcFastMdlReadNotPossible += 1; + Result = FALSE; + goto Cleanup; + } + + /* Check if we need to find out if fast I/O is available */ + if (FcbHeader->IsFastIoPossible == FastIoIsQuestionable) + { + /* Sanity check */ + ASSERT(!KeIsExecutingDpc()); + + /* Get the Fast I/O table */ + Device = IoGetRelatedDeviceObject(FileObject); + FastIoDispatch = Device->DriverObject->FastIoDispatch; + + /* Sanity check */ + ASSERT(FastIoDispatch != NULL); + ASSERT(FastIoDispatch->FastIoCheckIfPossible != NULL); + + /* Ask the driver if we can do it */ + if (!FastIoDispatch->FastIoCheckIfPossible(FileObject, + FileOffset, + Length, + TRUE, + LockKey, + TRUE, + IoStatus, + Device)) + { + /* It's not, fail */ + CcFastMdlReadNotPossible += 1; + Result = FALSE; + goto Cleanup; + } + } + + /* Check if we read too much */ + if (Offset.QuadPart > FcbHeader->FileSize.QuadPart) + { + /* We did, check if the file offset is past the end */ + if (FileOffset->QuadPart >= FcbHeader->FileSize.QuadPart) + { + /* Set end of file */ + IoStatus->Status = STATUS_END_OF_FILE; + IoStatus->Information = 0; + goto Cleanup; + } + + /* Otherwise, just normalize the length */ + Length = (ULONG)(FcbHeader->FileSize.QuadPart - FileOffset->QuadPart); + } + + /* Set this as top-level IRP */ + PsGetCurrentThread()->TopLevelIrp = FSRTL_FAST_IO_TOP_LEVEL_IRP; + + /* Attempt a read */ + CcMdlRead(FileObject, FileOffset, Length, MdlChain, IoStatus); + FileObject->Flags |= FO_FILE_FAST_IO_READ; + + /* Remove the top-level IRP flag */ + PsGetCurrentThread()->TopLevelIrp = 0; + + /* Return to caller */ +Cleanup: + ExReleaseResourceLite(FcbHeader->Resource); + FsRtlExitFileSystem(); + return Result; +} + +/* + * @implemented + */ +BOOLEAN +NTAPI FsRtlMdlWriteComplete(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PMDL MdlChain) @@ -400,19 +416,10 @@ }
/* - * NAME EXPORTED - * FsRtlMdlWriteCompleteDev@16 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * @implemented - */ -BOOLEAN -STDCALL + * @implemented + */ +BOOLEAN +NTAPI FsRtlMdlWriteCompleteDev(IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PMDL MdlChain, @@ -423,25 +430,15 @@ return TRUE; }
- -/* - * NAME EXPORTED - * FsRtlPrepareMdlWrite@24 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * @implemented - */ -BOOLEAN -STDCALL -FsRtlPrepareMdlWrite(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN ULONG LockKey, +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlPrepareMdlWrite(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, OUT PMDL *MdlChain, OUT PIO_STATUS_BLOCK IoStatus) { @@ -487,23 +484,14 @@ }
/* - * NAME EXPORTED - * FsRtlPrepareMdlWriteDev@28 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * * @unimplemented */ BOOLEAN -STDCALL -FsRtlPrepareMdlWriteDev(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN ULONG LockKey, +NTAPI +FsRtlPrepareMdlWriteDev(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) @@ -512,4 +500,79 @@ return FALSE; }
+/* +* @implemented +*/ +VOID +NTAPI +FsRtlAcquireFileExclusive(IN PFILE_OBJECT FileObject) +{ + PFAST_IO_DISPATCH FastDispatch; + PDEVICE_OBJECT DeviceObject; + PFSRTL_COMMON_FCB_HEADER FcbHeader; + + /* Get the Device Object and fast dispatch */ + DeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); + FastDispatch = DeviceObject->DriverObject->FastIoDispatch; + + /* Check if we have to do a Fast I/O Dispatch */ + if ((FastDispatch) && (FastDispatch->AcquireFileForNtCreateSection)) + { + /* Enter the file system and call it */ + FsRtlEnterFileSystem(); + FastDispatch->AcquireFileForNtCreateSection(FileObject); + return; + } + + /* Get the FCB Header */ + FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; + if (FcbHeader->Resource) + { + /* Use a Resource Acquire */ + FsRtlEnterFileSystem(); + ExAcquireResourceExclusive(FcbHeader->Resource, TRUE); + } + + /* All done, return */ + return; +} + +/* +* @implemented +*/ +VOID +NTAPI +FsRtlReleaseFile(IN PFILE_OBJECT FileObject) +{ + PFAST_IO_DISPATCH FastDispatch; + PDEVICE_OBJECT DeviceObject; + PFSRTL_COMMON_FCB_HEADER FcbHeader; + + /* Get the Device Object */ + DeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); + + FastDispatch = DeviceObject->DriverObject->FastIoDispatch; + + /* Check if we have to do a Fast I/O Dispatch */ + if ((FastDispatch) && (FastDispatch->ReleaseFileForNtCreateSection)) + { + /* Call the release function and exit the file system */ + FastDispatch->ReleaseFileForNtCreateSection(FileObject); + FsRtlExitFileSystem(); + return; + } + + /* Get the FCB Header */ + FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext; + if (FcbHeader->Resource) + { + /* Use a Resource release */ + ExReleaseResourceLite(FcbHeader->Resource); + FsRtlExitFileSystem(); + } + + /* All done, return */ + return; +} + /* EOF */
Modified: trunk/reactos/ntoskrnl/fs/filelock.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/fs/filelock.c?rev=... ============================================================================== --- trunk/reactos/ntoskrnl/fs/filelock.c (original) +++ trunk/reactos/ntoskrnl/fs/filelock.c Mon Nov 13 01:31:45 2006 @@ -25,14 +25,10 @@ NPAGED_LOOKASIDE_LIST LockTocLookaside; PAGED_LOOKASIDE_LIST LockLookaside;
- - __inline BOOLEAN -IsOverlappingLock( - PFILE_LOCK_INFO Lock, - PLARGE_INTEGER StartOffset, - PLARGE_INTEGER EndOffset - ) +IsOverlappingLock(PFILE_LOCK_INFO Lock, + PLARGE_INTEGER StartOffset, + PLARGE_INTEGER EndOffset) { if ((ULONGLONG)StartOffset->QuadPart > (ULONGLONG)Lock->EndingByte.QuadPart) { @@ -47,13 +43,10 @@ return TRUE; }
- __inline BOOLEAN -IsSurroundingLock( - PFILE_LOCK_INFO Lock, - PLARGE_INTEGER StartOffset, - PLARGE_INTEGER EndOffset - ) +IsSurroundingLock(PFILE_LOCK_INFO Lock, + PLARGE_INTEGER StartOffset, + PLARGE_INTEGER EndOffset) { if ((ULONGLONG)StartOffset->QuadPart >= (ULONGLONG)Lock->StartingByte.QuadPart && (ULONGLONG)EndOffset->QuadPart <= (ULONGLONG)Lock->EndingByte.QuadPart) @@ -64,58 +57,72 @@ return FALSE; }
- -/********************************************************************** - * NAME PRIVATE - * FsRtlpInitFileLockingImplementation - * - */ VOID -STDCALL INIT_FUNCTION +NTAPI FsRtlInitSystem(VOID) { - ExInitializeNPagedLookasideList( &LockTocLookaside, + /* Initialize the list for all lock information structures */ + ExInitializeNPagedLookasideList(&LockTocLookaside, NULL, NULL, 0, sizeof(FILE_LOCK_TOC), IFS_POOL_TAG, - 0 - ); - - ExInitializeNPagedLookasideList( &GrantedLookaside, + 0); + + /* Initialize the list for granted locks */ + ExInitializeNPagedLookasideList(&GrantedLookaside, NULL, NULL, 0, sizeof(FILE_LOCK_GRANTED), IFS_POOL_TAG, - 0 - ); - - ExInitializePagedLookasideList( &LockLookaside, + 0); + + /* Initialize the list for lock allocations */ + ExInitializePagedLookasideList(&LockLookaside, NULL, NULL, 0, sizeof(FILE_LOCK), IFS_POOL_TAG, - 0 - ); - - ExInitializeFastMutex(&LockTocMutex); - -} - -/********************************************************************** - * NAME PRIVATE - * FsRtlpFileLockCancelRoutine - * - */ + 0); + + /* Initialize the lock information mutex */ + ExInitializeFastMutex(&LockTocMutex); +} + +VOID +NTAPI +FsRtlCompleteLockIrpReal(IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteRoutine, + IN PVOID Context, + IN PIRP Irp, + IN NTSTATUS Status, + OUT PNTSTATUS NewStatus, + IN PFILE_OBJECT FileObject OPTIONAL) +{ + /* Check if we have a complete routine */ + if (CompleteRoutine) + { + /* Check if we have a file object */ + if (FileObject) FileObject->LastLock = NULL; + + /* Set the I/O Status and do completion */ + Irp->IoStatus.Status = Status; + *NewStatus = CompleteRoutine(Context, Irp); + } + else + { + /* Otherwise do a normal I/O complete request */ + FsRtlCompleteRequest(Irp, Status); + *NewStatus = Status; + } +} + VOID STDCALL -FsRtlpFileLockCancelRoutine( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp - ) +FsRtlpFileLockCancelRoutine(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) { KIRQL oldIrql; PKSPIN_LOCK SpinLock; @@ -135,28 +142,17 @@ Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT); - -} - -/********************************************************************** - * NAME PRIVATE - * FsRtlpCheckLockForReadOrWriteAccess - * - * Return: - * TRUE: can read/write - * FALSE: can't read/write - */ +} + BOOLEAN FASTCALL -FsRtlpCheckLockForReadOrWriteAccess( - IN PFILE_LOCK FileLock, - IN PLARGE_INTEGER FileOffset, - IN PLARGE_INTEGER Length, - IN ULONG Key, - IN PFILE_OBJECT FileObject, - IN PEPROCESS Process, - IN BOOLEAN Read - ) +FsRtlpCheckLockForReadOrWriteAccess(IN PFILE_LOCK FileLock, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + IN ULONG Key, + IN PFILE_OBJECT FileObject, + IN PEPROCESS Process, + IN BOOLEAN Read) { KIRQL oldirql; PFILE_LOCK_TOC LockToc; @@ -212,1163 +208,920 @@ return TRUE; }
- -/********************************************************************** - * NAME EXPORTED - * FsRtlCheckLockForReadAccess - * - * @implemented - */ -BOOLEAN -STDCALL -FsRtlCheckLockForReadAccess ( - IN PFILE_LOCK FileLock, - IN PIRP Irp - ) -{ - PIO_STACK_LOCATION Stack; - LARGE_INTEGER LocalLength; - - Stack = IoGetCurrentIrpStackLocation(Irp); - - LocalLength.u.LowPart = Stack->Parameters.Read.Length; - LocalLength.u.HighPart = 0; - - return FsRtlpCheckLockForReadOrWriteAccess( FileLock, - &Stack->Parameters.Read.ByteOffset, - &LocalLength, - Stack->Parameters.Read.Key, - Stack->FileObject, - IoGetRequestorProcess(Irp), - TRUE /* Read */ - ); -} - - -/********************************************************************** - * NAME EXPORTED - * FsRtlCheckLockForWriteAccess - * - * @implemented - */ -BOOLEAN -STDCALL -FsRtlCheckLockForWriteAccess ( - IN PFILE_LOCK FileLock, - IN PIRP Irp - ) -{ - PIO_STACK_LOCATION Stack; - LARGE_INTEGER LocalLength; - - Stack = IoGetCurrentIrpStackLocation(Irp); - - LocalLength.u.LowPart = Stack->Parameters.Read.Length; - LocalLength.u.HighPart = 0; - - return FsRtlpCheckLockForReadOrWriteAccess( FileLock, - &Stack->Parameters.Write.ByteOffset, - &LocalLength, - Stack->Parameters.Write.Key, - Stack->FileObject, - IoGetRequestorProcess(Irp), - FALSE /* Read */ - ); - -} - - - - -/********************************************************************** - * NAME EXPORTED - * FsRtlFastCheckLockForRead - * - * @implemented - */ -BOOLEAN -STDCALL -FsRtlFastCheckLockForRead ( - IN PFILE_LOCK FileLock, - IN PLARGE_INTEGER FileOffset, - IN PLARGE_INTEGER Length, - IN ULONG Key, - IN PFILE_OBJECT FileObject, - IN PEPROCESS Process - ) -{ - return FsRtlpCheckLockForReadOrWriteAccess( FileLock, - FileOffset, - Length, - Key, - FileObject, - Process, - TRUE /* Read */ - ); -} - - -/********************************************************************** - * NAME EXPORTED - * FsRtlFastCheckLockForWrite - * - * @implemented - */ -BOOLEAN -STDCALL -FsRtlFastCheckLockForWrite ( - IN PFILE_LOCK FileLock, - IN PLARGE_INTEGER FileOffset, - IN PLARGE_INTEGER Length, - IN ULONG Key, - IN PFILE_OBJECT FileObject, - IN PEPROCESS Process - ) -{ - return FsRtlpCheckLockForReadOrWriteAccess( FileLock, - FileOffset, - Length, - Key, - FileObject, - Process, - FALSE /* Read */ - ); -} - - - -/********************************************************************** - * NAME PRIVATE - * FsRtlpFastUnlockAllByKey - * - */ NTSTATUS FASTCALL -FsRtlpFastUnlockAllByKey( - IN PFILE_LOCK FileLock, - IN PFILE_OBJECT FileObject, - IN PEPROCESS Process, - IN ULONG Key, - IN BOOLEAN UseKey, - IN PVOID Context OPTIONAL - ) -{ - KIRQL oldirql; - PFILE_LOCK_TOC LockToc; - PFILE_LOCK_GRANTED Granted, tmp; - BOOLEAN Unlock = FALSE; - //must make local copy since FILE_LOCK struct is allowed to be paged - BOOLEAN GotUnlockRoutine; - LIST_ENTRY UnlockedListHead; - PLIST_ENTRY EnumEntry; - - ASSERT(FileLock); - LockToc = FileLock->LockInformation; - - if (LockToc == NULL) - { - return STATUS_RANGE_NOT_LOCKED; - } - - InitializeListHead(&UnlockedListHead); - GotUnlockRoutine = FileLock->UnlockRoutine != NULL; - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); - - LIST_FOR_EACH_SAFE(Granted, tmp, &LockToc->GrantedListHead, FILE_LOCK_GRANTED, ListEntry) - { - - if (Granted->Lock.ProcessId == Process && - Granted->Lock.FileObject == FileObject && - (!UseKey || (UseKey && Granted->Lock.Key == Key)) ) - { - RemoveEntryList(&Granted->ListEntry); - Unlock = TRUE; - - if (GotUnlockRoutine) - { - /* - Put on unlocked list and call unlock routine for them afterwards. - This way we don't have to restart enum after each call - */ - InsertHeadList(&UnlockedListHead,&Granted->ListEntry); - } - else - { +FsRtlpFastUnlockAllByKey(IN PFILE_LOCK FileLock, + IN PFILE_OBJECT FileObject, + IN PEPROCESS Process, + IN ULONG Key, + IN BOOLEAN UseKey, + IN PVOID Context OPTIONAL) +{ + KIRQL oldirql; + PFILE_LOCK_TOC LockToc; + PFILE_LOCK_GRANTED Granted, tmp; + BOOLEAN Unlock = FALSE; + //must make local copy since FILE_LOCK struct is allowed to be paged + BOOLEAN GotUnlockRoutine; + LIST_ENTRY UnlockedListHead; + PLIST_ENTRY EnumEntry; + + ASSERT(FileLock); + LockToc = FileLock->LockInformation; + + if (LockToc == NULL) + { + return STATUS_RANGE_NOT_LOCKED; + } + + InitializeListHead(&UnlockedListHead); + GotUnlockRoutine = FileLock->UnlockRoutine != NULL; + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + + LIST_FOR_EACH_SAFE(Granted, tmp, &LockToc->GrantedListHead, FILE_LOCK_GRANTED, ListEntry) + { + + if (Granted->Lock.ProcessId == Process && + Granted->Lock.FileObject == FileObject && + (!UseKey || (UseKey && Granted->Lock.Key == Key)) ) + { + RemoveEntryList(&Granted->ListEntry); + Unlock = TRUE; + + if (GotUnlockRoutine) + { + /* + Put on unlocked list and call unlock routine for them afterwards. + This way we don't have to restart enum after each call + */ + InsertHeadList(&UnlockedListHead,&Granted->ListEntry); + } + else + { + ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); + } + } + } + + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + + if (Unlock) + { + //call unlock routine for each unlocked lock (if any) + while (!IsListEmpty(&UnlockedListHead)) + { + EnumEntry = RemoveTailList(&UnlockedListHead); + Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry); + + FileLock->UnlockRoutine(Granted->UnlockContext, &Granted->Lock); ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); - } - } - } - - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - - if (Unlock) - { - //call unlock routine for each unlocked lock (if any) - while (!IsListEmpty(&UnlockedListHead)) - { - EnumEntry = RemoveTailList(&UnlockedListHead); - Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry); - - FileLock->UnlockRoutine(Granted->UnlockContext, &Granted->Lock); - ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); - } - - //NOTE: holding spinlock while calling this - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); - FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql, Context); - - if (IsListEmpty(&LockToc->GrantedListHead)) - { - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; - } - else - { - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - } - - return STATUS_SUCCESS; - } - - return STATUS_RANGE_NOT_LOCKED; -} - -/********************************************************************** - * NAME EXPORTED - * FsRtlFastUnlockAll - * - * @implemented - */ -NTSTATUS -STDCALL -FsRtlFastUnlockAll /*ByProcess*/ ( - IN PFILE_LOCK FileLock, - IN PFILE_OBJECT FileObject, - IN PEPROCESS Process, - IN PVOID Context OPTIONAL - ) -{ - return FsRtlpFastUnlockAllByKey( FileLock, - FileObject, - Process, - 0, /* Key is ignored */ - FALSE, /* Do NOT use Key */ - Context - ); -} - -/********************************************************************** - * NAME EXPORTED - * FsRtlFastUnlockAllByKey - * - * @implemented - */ -NTSTATUS -STDCALL -FsRtlFastUnlockAllByKey ( - IN PFILE_LOCK FileLock, - IN PFILE_OBJECT FileObject, - IN PEPROCESS Process, - IN ULONG Key, - IN PVOID Context OPTIONAL - ) -{ - return FsRtlpFastUnlockAllByKey( FileLock, - FileObject, - Process, - Key, - TRUE, /* Use Key */ - Context - ); -} - - -/********************************************************************** - * NAME PRIVATE - * FsRtlpAddLock - * - * NOTE - * Spinlock held at entry !! - */ + } + + //NOTE: holding spinlock while calling this + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql, Context); + + if (IsListEmpty(&LockToc->GrantedListHead)) + { + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; + } + else + { + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + } + + return STATUS_SUCCESS; + } + + return STATUS_RANGE_NOT_LOCKED; +} + BOOLEAN FASTCALL -FsRtlpAddLock( - IN PFILE_LOCK_TOC LockToc, - IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN PLARGE_INTEGER Length, - IN PEPROCESS Process, - IN ULONG Key, - IN BOOLEAN ExclusiveLock, - IN PVOID Context - ) -{ - PFILE_LOCK_GRANTED Granted; - LARGE_INTEGER EndOffset; - - EndOffset.QuadPart = FileOffset->QuadPart + Length->QuadPart - 1; - - //loop and try to find conflicking locks - LIST_FOR_EACH(Granted, &LockToc->GrantedListHead, FILE_LOCK_GRANTED, ListEntry) - { - if (IsOverlappingLock(&Granted->Lock, FileOffset, &EndOffset)) - { - //we found a locks that overlap with the new lock - - //if both locks are shared, we might have a fast path outa here... - if (!Granted->Lock.ExclusiveLock && !ExclusiveLock) - { - //if existing lock surround new lock, we know that no other exclusive lock - //may overlap with our new lock;-D - if (IsSurroundingLock(&Granted->Lock, FileOffset, &EndOffset)) +FsRtlpAddLock(IN PFILE_LOCK_TOC LockToc, + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + IN PEPROCESS Process, + IN ULONG Key, + IN BOOLEAN ExclusiveLock, + IN PVOID Context) +{ + PFILE_LOCK_GRANTED Granted; + LARGE_INTEGER EndOffset; + + EndOffset.QuadPart = FileOffset->QuadPart + Length->QuadPart - 1; + + //loop and try to find conflicking locks + LIST_FOR_EACH(Granted, &LockToc->GrantedListHead, FILE_LOCK_GRANTED, ListEntry) + { + if (IsOverlappingLock(&Granted->Lock, FileOffset, &EndOffset)) + { + //we found a locks that overlap with the new lock + + //if both locks are shared, we might have a fast path outa here... + if (!Granted->Lock.ExclusiveLock && !ExclusiveLock) { - break; + //if existing lock surround new lock, we know that no other exclusive lock + //may overlap with our new lock;-D + if (IsSurroundingLock(&Granted->Lock, FileOffset, &EndOffset)) + { + break; + } + + //else keep locking for conflicts + continue; }
- //else keep locking for conflicts - continue; - } - - //we found a conflict: - //we want shared access to an excl. lock OR exlc. access to a shared lock - return FALSE; - } - } - - Granted = ExAllocateFromNPagedLookasideList(&GrantedLookaside); - - //starting offset - Granted->Lock.StartingByte = *FileOffset; - Granted->Lock.Length = *Length; - Granted->Lock.ExclusiveLock = ExclusiveLock; - Granted->Lock.Key = Key; - Granted->Lock.FileObject = FileObject; - Granted->Lock.ProcessId = Process; - //ending offset - Granted->Lock.EndingByte = EndOffset; - Granted->UnlockContext = Context; - - InsertHeadList(&LockToc->GrantedListHead,&Granted->ListEntry); - return TRUE; -} - - - -/********************************************************************** - * NAME PRIVATE - * FsRtlpCompletePendingLocks - * - * NOTE - * Spinlock held at entry !! - */ + //we found a conflict: + //we want shared access to an excl. lock OR exlc. access to a shared lock + return FALSE; + } + } + + Granted = ExAllocateFromNPagedLookasideList(&GrantedLookaside); + + //starting offset + Granted->Lock.StartingByte = *FileOffset; + Granted->Lock.Length = *Length; + Granted->Lock.ExclusiveLock = ExclusiveLock; + Granted->Lock.Key = Key; + Granted->Lock.FileObject = FileObject; + Granted->Lock.ProcessId = Process; + //ending offset + Granted->Lock.EndingByte = EndOffset; + Granted->UnlockContext = Context; + + InsertHeadList(&LockToc->GrantedListHead,&Granted->ListEntry); + return TRUE; +} + VOID FASTCALL -FsRtlpCompletePendingLocks( - IN PFILE_LOCK FileLock, - IN PFILE_LOCK_TOC LockToc, - IN OUT PKIRQL oldirql, - IN PVOID Context - ) -{ - //walk pending list, FIFO order, try 2 complete locks - PLIST_ENTRY EnumEntry; - PIRP Irp, tmp; - PIO_STACK_LOCATION Stack; - LIST_ENTRY CompletedListHead; - - InitializeListHead(&CompletedListHead); - - LIST_FOR_EACH_SAFE(Irp, tmp, &LockToc->PendingListHead, IRP, Tail.Overlay.ListEntry) - { - Stack = IoGetCurrentIrpStackLocation(Irp); - if (FsRtlpAddLock(LockToc, - Stack->FileObject, - &Stack->Parameters.LockControl.ByteOffset, - Stack->Parameters.LockControl.Length, - IoGetRequestorProcess(Irp), - Stack->Parameters.LockControl.Key, - Stack->Flags & SL_EXCLUSIVE_LOCK, - Irp->Tail.Overlay.DriverContext[2] //Context - ) ) - { - RemoveEntryList(&Irp->Tail.Overlay.ListEntry); - - if (!IoSetCancelRoutine(Irp, NULL)) - { - //irp is canceled and cancelroutine will run when we release the lock - InitializeListHead(&Irp->Tail.Overlay.ListEntry); - continue; - } - - /* - Put on completed list and complete them all afterwards. - This way we don't have to restart enum after each completion. - */ - InsertHeadList(&CompletedListHead, &Irp->Tail.Overlay.ListEntry); - } - } - - KeReleaseSpinLock(&LockToc->SpinLock, *oldirql); - - //complete irp's (if any) - while (!IsListEmpty(&CompletedListHead)) - { - EnumEntry = RemoveTailList(&CompletedListHead); - - Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry); - - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = 0; - - if (FileLock->CompleteLockIrpRoutine) - { - if (FileLock->CompleteLockIrpRoutine(Context, Irp)!=STATUS_SUCCESS) - { - Stack = IoGetCurrentIrpStackLocation(Irp); - - //revert - FsRtlpUnlockSingle ( FileLock, - Stack->FileObject, - &Stack->Parameters.LockControl.ByteOffset, - Stack->Parameters.LockControl.Length, - IoGetRequestorProcess(Irp), - Stack->Parameters.LockControl.Key, - NULL, /* unused context */ - FALSE /* don't call unlock copletion rout.*/ - ); - } - } - else - { - IoCompleteRequest(Irp, IO_NO_INCREMENT); - } - - } - - KeAcquireSpinLock(&LockToc->SpinLock, oldirql); -} - - - -/********************************************************************** - * NAME PRIVATE - * FsRtlpUnlockSingle - * - */ +FsRtlpCompletePendingLocks(IN PFILE_LOCK FileLock, + IN PFILE_LOCK_TOC LockToc, + IN OUT PKIRQL oldirql, + IN PVOID Context) +{ + //walk pending list, FIFO order, try 2 complete locks + PLIST_ENTRY EnumEntry; + PIRP Irp, tmp; + PIO_STACK_LOCATION Stack; + LIST_ENTRY CompletedListHead; + + InitializeListHead(&CompletedListHead); + + LIST_FOR_EACH_SAFE(Irp, tmp, &LockToc->PendingListHead, IRP, Tail.Overlay.ListEntry) + { + Stack = IoGetCurrentIrpStackLocation(Irp); + if (FsRtlpAddLock(LockToc, + Stack->FileObject, + &Stack->Parameters.LockControl.ByteOffset, + Stack->Parameters.LockControl.Length, + IoGetRequestorProcess(Irp), + Stack->Parameters.LockControl.Key, + Stack->Flags & SL_EXCLUSIVE_LOCK, + Irp->Tail.Overlay.DriverContext[2] //Context + ) ) + { + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); + + if (!IoSetCancelRoutine(Irp, NULL)) + { + //irp is canceled and cancelroutine will run when we release the lock + InitializeListHead(&Irp->Tail.Overlay.ListEntry); + continue; + } + + /* + Put on completed list and complete them all afterwards. + This way we don't have to restart enum after each completion. + */ + InsertHeadList(&CompletedListHead, &Irp->Tail.Overlay.ListEntry); + } + } + + KeReleaseSpinLock(&LockToc->SpinLock, *oldirql); + + //complete irp's (if any) + while (!IsListEmpty(&CompletedListHead)) + { + EnumEntry = RemoveTailList(&CompletedListHead); + + Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + if (FileLock->CompleteLockIrpRoutine) + { + if (FileLock->CompleteLockIrpRoutine(Context, Irp)!=STATUS_SUCCESS) + { + Stack = IoGetCurrentIrpStackLocation(Irp); + + //revert + FsRtlpUnlockSingle ( FileLock, + Stack->FileObject, + &Stack->Parameters.LockControl.ByteOffset, + Stack->Parameters.LockControl.Length, + IoGetRequestorProcess(Irp), + Stack->Parameters.LockControl.Key, + NULL, /* unused context */ + FALSE /* don't call unlock copletion rout.*/ + ); + } + } + else + { + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + } + + KeAcquireSpinLock(&LockToc->SpinLock, oldirql); +} + NTSTATUS FASTCALL -FsRtlpUnlockSingle( - IN PFILE_LOCK FileLock, - IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN PLARGE_INTEGER Length, - IN PEPROCESS Process, - IN ULONG Key, - IN PVOID Context OPTIONAL, - IN BOOLEAN CallUnlockRoutine - ) -{ - KIRQL oldirql; - PFILE_LOCK_TOC LockToc; - PFILE_LOCK_GRANTED Granted, tmp; - - ASSERT(FileLock); - LockToc = FileLock->LockInformation; - - if (LockToc == NULL) - { - return STATUS_RANGE_NOT_LOCKED; - } - - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql ); - - LIST_FOR_EACH_SAFE(Granted, tmp, &LockToc->GrantedListHead, FILE_LOCK_GRANTED,ListEntry) - { - - //must be exact match - if (FileOffset->QuadPart == Granted->Lock.StartingByte.QuadPart && - Length->QuadPart == Granted->Lock.Length.QuadPart && - Granted->Lock.ProcessId == Process && - Granted->Lock.FileObject == FileObject && - Granted->Lock.Key == Key) - { - RemoveEntryList(&Granted->ListEntry); - FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql, Context); - - if (IsListEmpty(&LockToc->GrantedListHead)) - { +FsRtlpUnlockSingle(IN PFILE_LOCK FileLock, + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + IN PEPROCESS Process, + IN ULONG Key, + IN PVOID Context OPTIONAL, + IN BOOLEAN CallUnlockRoutine) +{ + KIRQL oldirql; + PFILE_LOCK_TOC LockToc; + PFILE_LOCK_GRANTED Granted, tmp; + + ASSERT(FileLock); + LockToc = FileLock->LockInformation; + + if (LockToc == NULL) + { + return STATUS_RANGE_NOT_LOCKED; + } + + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql ); + + LIST_FOR_EACH_SAFE(Granted, tmp, &LockToc->GrantedListHead, FILE_LOCK_GRANTED,ListEntry) + { + + //must be exact match + if (FileOffset->QuadPart == Granted->Lock.StartingByte.QuadPart && + Length->QuadPart == Granted->Lock.Length.QuadPart && + Granted->Lock.ProcessId == Process && + Granted->Lock.FileObject == FileObject && + Granted->Lock.Key == Key) + { + RemoveEntryList(&Granted->ListEntry); + FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql, Context); + + if (IsListEmpty(&LockToc->GrantedListHead)) + { + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + + FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; //paged data + } + else + { + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + } + + if (FileLock->UnlockRoutine && CallUnlockRoutine) + { + FileLock->UnlockRoutine(Granted->UnlockContext, &Granted->Lock); + } + + ExFreeToNPagedLookasideList(&GrantedLookaside, Granted); + + return STATUS_SUCCESS; + } + } + + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + + return STATUS_RANGE_NOT_LOCKED; + +} + +/* PUBLIC FUNCTIONS **********************************************************/ + +/* + * @implemented + */ +PFILE_LOCK_INFO +NTAPI +FsRtlGetNextFileLock(IN PFILE_LOCK FileLock, + IN BOOLEAN Restart) +{ + /* + Messy enumeration of granted locks. + What our last ptr. in LastReturnedLock points at, might have been freed between + calls, so we have to scan thru the list every time, searching for our last lock. + If it's not there anymore, restart the enumeration... + */ + KIRQL oldirql; + PLIST_ENTRY EnumEntry; + PFILE_LOCK_GRANTED Granted; + PFILE_LOCK_TOC LockToc; + BOOLEAN FoundPrevious = FALSE; + //must make local copy since FILE_LOCK struct is allowed to be in paged mem + FILE_LOCK_INFO LocalLastReturnedLockInfo; + PVOID LocalLastReturnedLock; + + ASSERT(FileLock); + LockToc = FileLock->LockInformation; + if (LockToc == NULL) + { + return NULL; + } + + LocalLastReturnedLock = FileLock->LastReturnedLock; + + KeAcquireSpinLock(&LockToc->SpinLock,&oldirql); + +restart:; + + EnumEntry = LockToc->GrantedListHead.Flink; + + if (Restart) + { + if (EnumEntry != &LockToc->GrantedListHead) + { + Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry); + LocalLastReturnedLockInfo = Granted->Lock; + KeReleaseSpinLock(&LockToc->SpinLock,oldirql); + + FileLock->LastReturnedLockInfo = LocalLastReturnedLockInfo; + FileLock->LastReturnedLock = EnumEntry; + return &FileLock->LastReturnedLockInfo; + } + else + { + KeReleaseSpinLock(&LockToc->SpinLock,oldirql); + return NULL; + } + } + + //else: continue enum + while (EnumEntry != &LockToc->GrantedListHead) + { + //found previous lock? + if (EnumEntry == LocalLastReturnedLock) + { + FoundPrevious = TRUE; + //get next + EnumEntry = EnumEntry->Flink; + if (EnumEntry != &LockToc->GrantedListHead) + { + Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry); + LocalLastReturnedLockInfo = Granted->Lock; + KeReleaseSpinLock(&LockToc->SpinLock,oldirql); + + FileLock->LastReturnedLockInfo = LocalLastReturnedLockInfo; + FileLock->LastReturnedLock = EnumEntry; + return &FileLock->LastReturnedLockInfo; + } + break; + } + EnumEntry = EnumEntry->Flink; + } + + if (!FoundPrevious) + { + //got here? uh no, didn't find our last lock..must have been freed...restart + Restart = TRUE; + goto restart; + } + + KeReleaseSpinLock(&LockToc->SpinLock,oldirql); + + return NULL;//no (more) locks +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlPrivateLock(IN PFILE_LOCK FileLock, + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + IN PEPROCESS Process, + IN ULONG Key, + IN BOOLEAN FailImmediately, //seems meaningless for fast io + IN BOOLEAN ExclusiveLock, + OUT PIO_STATUS_BLOCK IoStatus, + IN PIRP Irp OPTIONAL, + IN PVOID Context OPTIONAL, + IN BOOLEAN AlreadySynchronized) +{ + PFILE_LOCK_TOC LockToc; + KIRQL oldirql; + + ASSERT(FileLock); + if (FileLock->LockInformation == NULL) + { + ExAcquireFastMutex(&LockTocMutex); + //still NULL? + if (FileLock->LockInformation == NULL) + { + FileLock->LockInformation = ExAllocateFromNPagedLookasideList(&LockTocLookaside); + LockToc = FileLock->LockInformation; + KeInitializeSpinLock(&LockToc->SpinLock); + InitializeListHead(&LockToc->GrantedListHead); + InitializeListHead(&LockToc->PendingListHead); + } + ExReleaseFastMutex(&LockTocMutex); + } + + LockToc = FileLock->LockInformation; + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + + //try add new lock (while holding spin lock) + if (FsRtlpAddLock(LockToc, + FileObject, + FileOffset, + Length, + Process, + Key, + ExclusiveLock, + Context + ) ) + { + IoStatus->Status = STATUS_SUCCESS; + } + else if (Irp && !FailImmediately) + { + //failed + irp + no fail = make. pending + + Irp->Tail.Overlay.DriverContext[3] = &LockToc->SpinLock; + Irp->Tail.Overlay.DriverContext[2] = Context; + + (void)IoSetCancelRoutine(Irp, FsRtlpFileLockCancelRoutine); + if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL)) + { + //irp was canceled KeReleaseSpinLock(&LockToc->SpinLock, oldirql);
- FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; //paged data - } - else - { - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - } - - if (FileLock->UnlockRoutine && CallUnlockRoutine) - { - FileLock->UnlockRoutine(Granted->UnlockContext, &Granted->Lock); - } - - ExFreeToNPagedLookasideList(&GrantedLookaside, Granted); - - return STATUS_SUCCESS; - } - } - - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - - return STATUS_RANGE_NOT_LOCKED; - -} - - - -/********************************************************************** - * NAME EXPORTED - * FsRtlFastUnlockSingle - * + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return TRUE; + } + + IoMarkIrpPending(Irp); + Irp->IoStatus.Status = IoStatus->Status = STATUS_PENDING; + Irp->IoStatus.Information = 0; + InsertHeadList(&LockToc->PendingListHead,&Irp->Tail.Overlay.ListEntry); + + } + else + { + IoStatus->Status = STATUS_LOCK_NOT_GRANTED; + } + + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); //fires cancel routine + + //never pending if no irp;-) + ASSERT(!(IoStatus->Status == STATUS_PENDING && !Irp)); + + if (IoStatus->Status != STATUS_PENDING) + { + if (IoStatus->Status == STATUS_SUCCESS) + { + FsRtlAreThereCurrentFileLocks(FileLock) = TRUE; + } + + if (Irp) + { + Irp->IoStatus.Status = IoStatus->Status; + Irp->IoStatus.Information = 0; + if (FileLock->CompleteLockIrpRoutine) + { + if (FileLock->CompleteLockIrpRoutine(Context,Irp)!=STATUS_SUCCESS) + { + //CompleteLockIrpRoutine complain: revert changes + FsRtlpUnlockSingle( FileLock, + FileObject, + FileOffset, + Length, + Process, + Key, + NULL, /* context */ + FALSE /* don't call unlock copletion routine */ + ); + } + } + else + { + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + } + } + + //NOTE: only fast io seems to care about this return value + return (IoStatus->Status == STATUS_SUCCESS || FailImmediately); +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlCheckLockForReadAccess(IN PFILE_LOCK FileLock, + IN PIRP Irp) +{ + PIO_STACK_LOCATION Stack; + LARGE_INTEGER LocalLength; + + /* Get the I/O Stack location and length */ + Stack = IoGetCurrentIrpStackLocation(Irp); + LocalLength.QuadPart = Stack->Parameters.Read.Length; + + /* Call the internal API */ + return FsRtlpCheckLockForReadOrWriteAccess(FileLock, + &Stack->Parameters. + Read.ByteOffset, + &LocalLength, + Stack->Parameters.Read.Key, + Stack->FileObject, + IoGetRequestorProcess(Irp), + TRUE); +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlCheckLockForWriteAccess(IN PFILE_LOCK FileLock, + IN PIRP Irp) +{ + PIO_STACK_LOCATION Stack; + LARGE_INTEGER LocalLength; + + /* Get the I/O Stack location and length */ + Stack = IoGetCurrentIrpStackLocation(Irp); + LocalLength.QuadPart = Stack->Parameters.Read.Length; + + /* Call the internal API */ + return FsRtlpCheckLockForReadOrWriteAccess(FileLock, + &Stack->Parameters. + Read.ByteOffset, + &LocalLength, + Stack->Parameters.Read.Key, + Stack->FileObject, + IoGetRequestorProcess(Irp), + FALSE); +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlFastCheckLockForRead(IN PFILE_LOCK FileLock, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + IN ULONG Key, + IN PFILE_OBJECT FileObject, + IN PEPROCESS Process) +{ + /* Call the internal API */ + return FsRtlpCheckLockForReadOrWriteAccess(FileLock, + FileOffset, + Length, + Key, + FileObject, + Process, + TRUE); +} + +/* + * @implemented + */ +BOOLEAN +NTAPI +FsRtlFastCheckLockForWrite(IN PFILE_LOCK FileLock, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + IN ULONG Key, + IN PFILE_OBJECT FileObject, + IN PEPROCESS Process) +{ + /* Call the internal API */ + return FsRtlpCheckLockForReadOrWriteAccess(FileLock, + FileOffset, + Length, + Key, + FileObject, + Process, + FALSE); +} + +/* * @implemented */ NTSTATUS -STDCALL -FsRtlFastUnlockSingle ( - IN PFILE_LOCK FileLock, - IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN PLARGE_INTEGER Length, - IN PEPROCESS Process, - IN ULONG Key, - IN PVOID Context OPTIONAL, - IN BOOLEAN AlreadySynchronized - ) -{ - return FsRtlpUnlockSingle( FileLock, +NTAPI +FsRtlFastUnlockSingle(IN PFILE_LOCK FileLock, + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + IN PEPROCESS Process, + IN ULONG Key, + IN PVOID Context OPTIONAL, + IN BOOLEAN AlreadySynchronized) +{ + /* Call the internal API */ + return FsRtlpUnlockSingle(FileLock, FileObject, FileOffset, Length, Process, Key, Context, - TRUE /* call unlock copletion routine */ - ); -} - -/********************************************************************** - * NAME EXPORTED - * FsRtlpDumpFileLocks - * - * NOTE: used for testing and debugging - */ -VOID -FASTCALL -FsRtlpDumpFileLocks( - IN PFILE_LOCK FileLock - ) -{ - KIRQL oldirql; - PFILE_LOCK_TOC LockToc; - PFILE_LOCK_GRANTED Granted; - PIRP Irp; - PIO_STACK_LOCATION Stack; - - ASSERT(FileLock); - LockToc = FileLock->LockInformation; - - if (LockToc == NULL) - { - DPRINT1("No file locks\n"); - return; - } - - DPRINT1("Dumping granted file locks, FIFO order\n"); - - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); - - LIST_FOR_EACH(Granted, &LockToc->GrantedListHead, FILE_LOCK_GRANTED , ListEntry) - { - DPRINT1("%s, start: %I64x, len: %I64x, end: %I64x, key: %i, proc: 0x%p, fob: 0x%p\n", - Granted->Lock.ExclusiveLock ? "EXCL" : "SHRD", - Granted->Lock.StartingByte.QuadPart, - Granted->Lock.Length.QuadPart, - Granted->Lock.EndingByte.QuadPart, - Granted->Lock.Key, - Granted->Lock.ProcessId, - Granted->Lock.FileObject - ); - - } - - DPRINT1("Dumping pending file locks, FIFO order\n"); - - LIST_FOR_EACH(Irp, &LockToc->PendingListHead, IRP , Tail.Overlay.ListEntry) - { - Stack = IoGetCurrentIrpStackLocation(Irp); - - DPRINT1("%s, start: %I64x, len: %I64x, end: %I64x, key: %i, proc: 0x%p, fob: 0x%p\n", - (Stack->Flags & SL_EXCLUSIVE_LOCK) ? "EXCL" : "SHRD", - Stack->Parameters.LockControl.ByteOffset.QuadPart, - Stack->Parameters.LockControl.Length->QuadPart, - Stack->Parameters.LockControl.ByteOffset.QuadPart + Stack->Parameters.LockControl.Length->QuadPart - 1, - Stack->Parameters.LockControl.Key, - IoGetRequestorProcess(Irp), - Stack->FileObject - ); - - } - - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); -} - - - -/********************************************************************** - * NAME EXPORTED - * FsRtlGetNextFileLock - * - * RETURN VALUE - * NULL if no more locks. - * - * @implemented - */ -PFILE_LOCK_INFO -STDCALL -FsRtlGetNextFileLock ( - IN PFILE_LOCK FileLock, - IN BOOLEAN Restart - ) -{ - /* - Messy enumeration of granted locks. - What our last ptr. in LastReturnedLock points at, might have been freed between - calls, so we have to scan thru the list every time, searching for our last lock. - If it's not there anymore, restart the enumeration... - */ - KIRQL oldirql; - PLIST_ENTRY EnumEntry; - PFILE_LOCK_GRANTED Granted; - PFILE_LOCK_TOC LockToc; - BOOLEAN FoundPrevious = FALSE; - //must make local copy since FILE_LOCK struct is allowed to be in paged mem - FILE_LOCK_INFO LocalLastReturnedLockInfo; - PVOID LocalLastReturnedLock; - - ASSERT(FileLock); - LockToc = FileLock->LockInformation; - if (LockToc == NULL) - { - return NULL; - } - - LocalLastReturnedLock = FileLock->LastReturnedLock; - - KeAcquireSpinLock(&LockToc->SpinLock,&oldirql); - -restart:; - - EnumEntry = LockToc->GrantedListHead.Flink; - - if (Restart) - { - if (EnumEntry != &LockToc->GrantedListHead) - { - Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry); - LocalLastReturnedLockInfo = Granted->Lock; - KeReleaseSpinLock(&LockToc->SpinLock,oldirql); - - FileLock->LastReturnedLockInfo = LocalLastReturnedLockInfo; - FileLock->LastReturnedLock = EnumEntry; - return &FileLock->LastReturnedLockInfo; - } - else - { - KeReleaseSpinLock(&LockToc->SpinLock,oldirql); - return NULL; - } - } - - //else: continue enum - while (EnumEntry != &LockToc->GrantedListHead) - { - //found previous lock? - if (EnumEntry == LocalLastReturnedLock) - { - FoundPrevious = TRUE; - //get next - EnumEntry = EnumEntry->Flink; - if (EnumEntry != &LockToc->GrantedListHead) - { - Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry); - LocalLastReturnedLockInfo = Granted->Lock; - KeReleaseSpinLock(&LockToc->SpinLock,oldirql); - - FileLock->LastReturnedLockInfo = LocalLastReturnedLockInfo; - FileLock->LastReturnedLock = EnumEntry; - return &FileLock->LastReturnedLockInfo; - } - break; - } - EnumEntry = EnumEntry->Flink; - } - - if (!FoundPrevious) - { - //got here? uh no, didn't find our last lock..must have been freed...restart - Restart = TRUE; - goto restart; - } - - KeReleaseSpinLock(&LockToc->SpinLock,oldirql); - - return NULL;//no (more) locks -} - - -/********************************************************************** - * NAME EXPORTED - * FsRtlInitializeFileLock - * - * NOTE - * Called when creating/allocating/initializing FCB - * - * @implemented - */ -VOID -STDCALL -FsRtlInitializeFileLock ( - IN PFILE_LOCK FileLock, - IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL, - IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL - ) -{ - - FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; - FileLock->CompleteLockIrpRoutine = CompleteLockIrpRoutine; - FileLock->UnlockRoutine = UnlockRoutine; - FileLock->LockInformation = NULL; - -} - - -/********************************************************************** - * NAME EXPORTED - * FsRtlPrivateLock - * - * @implemented - */ -BOOLEAN -STDCALL -FsRtlPrivateLock ( - IN PFILE_LOCK FileLock, - IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN PLARGE_INTEGER Length, - IN PEPROCESS Process, - IN ULONG Key, - IN BOOLEAN FailImmediately, //seems meaningless for fast io - IN BOOLEAN ExclusiveLock, - OUT PIO_STATUS_BLOCK IoStatus, - IN PIRP Irp OPTIONAL, - IN PVOID Context OPTIONAL, - IN BOOLEAN AlreadySynchronized - ) -{ - PFILE_LOCK_TOC LockToc; - KIRQL oldirql; - - ASSERT(FileLock); - if (FileLock->LockInformation == NULL) - { - ExAcquireFastMutex(&LockTocMutex); - //still NULL? - if (FileLock->LockInformation == NULL) - { - FileLock->LockInformation = ExAllocateFromNPagedLookasideList(&LockTocLookaside); - LockToc = FileLock->LockInformation; - KeInitializeSpinLock(&LockToc->SpinLock); - InitializeListHead(&LockToc->GrantedListHead); - InitializeListHead(&LockToc->PendingListHead); - } - ExReleaseFastMutex(&LockTocMutex); - } - - LockToc = FileLock->LockInformation; - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); - - //try add new lock (while holding spin lock) - if (FsRtlpAddLock(LockToc, - FileObject, - FileOffset, - Length, - Process, - Key, - ExclusiveLock, - Context - ) ) - { - IoStatus->Status = STATUS_SUCCESS; - } - else if (Irp && !FailImmediately) - { - //failed + irp + no fail = make. pending - - Irp->Tail.Overlay.DriverContext[3] = &LockToc->SpinLock; - Irp->Tail.Overlay.DriverContext[2] = Context; - - (void)IoSetCancelRoutine(Irp, FsRtlpFileLockCancelRoutine); - if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL)) - { - //irp was canceled - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - - Irp->IoStatus.Status = STATUS_CANCELLED; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - - return TRUE; - } - - IoMarkIrpPending(Irp); - Irp->IoStatus.Status = IoStatus->Status = STATUS_PENDING; - Irp->IoStatus.Information = 0; - InsertHeadList(&LockToc->PendingListHead,&Irp->Tail.Overlay.ListEntry); - - } - else - { - IoStatus->Status = STATUS_LOCK_NOT_GRANTED; - } - - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); //fires cancel routine - - //never pending if no irp;-) - ASSERT(!(IoStatus->Status == STATUS_PENDING && !Irp)); - - if (IoStatus->Status != STATUS_PENDING) - { - if (IoStatus->Status == STATUS_SUCCESS) - { - FsRtlAreThereCurrentFileLocks(FileLock) = TRUE; - } - - if (Irp) - { - Irp->IoStatus.Status = IoStatus->Status; - Irp->IoStatus.Information = 0; - if (FileLock->CompleteLockIrpRoutine) - { - if (FileLock->CompleteLockIrpRoutine(Context,Irp)!=STATUS_SUCCESS) - { - //CompleteLockIrpRoutine complain: revert changes - FsRtlpUnlockSingle( FileLock, + TRUE); +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +FsRtlFastUnlockAll(IN PFILE_LOCK FileLock, + IN PFILE_OBJECT FileObject, + IN PEPROCESS Process, + IN PVOID Context OPTIONAL) +{ + /* Call the generic function by process */ + return FsRtlpFastUnlockAllByKey(FileLock, FileObject, - FileOffset, - Length, + Process, + 0, + FALSE, + Context); +} + +/* + * @implemented + */ +NTSTATUS +NTAPI +FsRtlFastUnlockAllByKey(IN PFILE_LOCK FileLock, + IN PFILE_OBJECT FileObject, + IN PEPROCESS Process, + IN ULONG Key, + IN PVOID Context OPTIONAL) +{ + /* Call the generic function by key */ + return FsRtlpFastUnlockAllByKey(FileLock, + FileObject, Process, Key, - NULL, /* context */ - FALSE /* don't call unlock copletion routine */ - ); - } - } - else - { - IoCompleteRequest(Irp, IO_NO_INCREMENT); - } - } - } - - //NOTE: only fast io seems to care about this return value - return (IoStatus->Status == STATUS_SUCCESS || FailImmediately); - -} - - - -/********************************************************************** - * NAME EXPORTED - * FsRtlProcessFileLock - * + TRUE, + Context); +} + +/* * @implemented */ NTSTATUS -STDCALL -FsRtlProcessFileLock ( - IN PFILE_LOCK FileLock, - IN PIRP Irp, - IN PVOID Context OPTIONAL - ) -{ - PIO_STACK_LOCATION Stack; - NTSTATUS Status; - IO_STATUS_BLOCK LocalIoStatus; - - ASSERT(FileLock); - Stack = IoGetCurrentIrpStackLocation(Irp); - Irp->IoStatus.Information = 0; - - switch(Stack->MinorFunction) - { - case IRP_MN_LOCK: - //ret: BOOLEAN - FsRtlPrivateLock( FileLock, - Stack->FileObject, - &Stack->Parameters.LockControl.ByteOffset, //not pointer! - Stack->Parameters.LockControl.Length, - IoGetRequestorProcess(Irp), - Stack->Parameters.LockControl.Key, - Stack->Flags & SL_FAIL_IMMEDIATELY, - Stack->Flags & SL_EXCLUSIVE_LOCK, - &LocalIoStatus, - Irp, - Context, - FALSE); - - return LocalIoStatus.Status; - - case IRP_MN_UNLOCK_SINGLE: - Status = FsRtlFastUnlockSingle ( FileLock, - Stack->FileObject, - &Stack->Parameters.LockControl.ByteOffset, - Stack->Parameters.LockControl.Length, - IoGetRequestorProcess(Irp), - Stack->Parameters.LockControl.Key, - Context, - FALSE); - break; - - case IRP_MN_UNLOCK_ALL: - Status = FsRtlFastUnlockAll( FileLock, - Stack->FileObject, - IoGetRequestorProcess(Irp), - Context ); - break; - - case IRP_MN_UNLOCK_ALL_BY_KEY: - Status = FsRtlFastUnlockAllByKey ( FileLock, - Stack->FileObject, - IoGetRequestorProcess(Irp), - Stack->Parameters.LockControl.Key, - Context ); - - break; - - default: - Irp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; - } - - - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = 0; - - IoCompleteRequest(Irp,IO_NO_INCREMENT); - - return Status; -} - - -/********************************************************************** - * NAME EXPORTED - * FsRtlUninitializeFileLock - * +NTAPI +FsRtlProcessFileLock(IN PFILE_LOCK FileLock, + IN PIRP Irp, + IN PVOID Context OPTIONAL) +{ + PIO_STACK_LOCATION IoStackLocation; + NTSTATUS Status; + IO_STATUS_BLOCK IoStatusBlock; + + /* Get the I/O Stack location */ + IoStackLocation = IoGetCurrentIrpStackLocation(Irp); + ASSERT(IoStackLocation->MajorFunction == IRP_MJ_LOCK_CONTROL); + + /* Clear the I/O status block and check what function this is */ + IoStatusBlock.Information = 0; + switch(IoStackLocation->MinorFunction) + { + /* A lock */ + case IRP_MN_LOCK: + + /* Call the private lock routine */ + FsRtlPrivateLock(FileLock, + IoStackLocation->FileObject, + &IoStackLocation-> + Parameters.LockControl.ByteOffset, + IoStackLocation->Parameters.LockControl.Length, + IoGetRequestorProcess(Irp), + IoStackLocation->Parameters.LockControl.Key, + IoStackLocation->Flags & SL_FAIL_IMMEDIATELY, + IoStackLocation->Flags & SL_EXCLUSIVE_LOCK, + &IoStatusBlock, + Irp, + Context, + FALSE); + break; + + /* A single unlock */ + case IRP_MN_UNLOCK_SINGLE: + + /* Call fast unlock */ + IoStatusBlock.Status = + FsRtlFastUnlockSingle(FileLock, + IoStackLocation->FileObject, + &IoStackLocation->Parameters.LockControl. + ByteOffset, + IoStackLocation->Parameters.LockControl. + Length, + IoGetRequestorProcess(Irp), + IoStackLocation->Parameters.LockControl. + Key, + Context, + FALSE); + + /* Complete the IRP */ + FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine, + Context, + Irp, + IoStatusBlock.Status, + &Status, + NULL); + break; + + /* Total unlock */ + case IRP_MN_UNLOCK_ALL: + + /* Do a fast unlock */ + IoStatusBlock.Status = FsRtlFastUnlockAll(FileLock, + IoStackLocation-> + FileObject, + IoGetRequestorProcess(Irp), + Context); + + /* Complete the IRP */ + FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine, + Context, + Irp, + IoStatusBlock.Status, + &Status, + NULL); + break; + + /* Unlock by key */ + case IRP_MN_UNLOCK_ALL_BY_KEY: + + /* Do it */ + IoStatusBlock.Status = + FsRtlFastUnlockAllByKey(FileLock, + IoStackLocation->FileObject, + IoGetRequestorProcess(Irp), + IoStackLocation->Parameters. + LockControl.Key, + Context); + + /* Complete the IRP */ + FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine, + Context, + Irp, + IoStatusBlock.Status, + &Status, + NULL); + break; + + /* Invalid request */ + default: + + /* Complete it */ + FsRtlCompleteRequest(Irp, STATUS_INVALID_DEVICE_REQUEST); + IoStatusBlock.Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + /* Return the status */ + return IoStatusBlock.Status; +} + +/* * @implemented */ VOID -STDCALL -FsRtlUninitializeFileLock ( - IN PFILE_LOCK FileLock - ) -{ - PFILE_LOCK_TOC LockToc; - PIRP Irp; - PFILE_LOCK_GRANTED Granted; - PLIST_ENTRY EnumEntry; - KIRQL oldirql; - - ASSERT(FileLock); - if (FileLock->LockInformation == NULL) - { - return; - } - - LockToc = FileLock->LockInformation; - - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); - - //remove and free granted locks - while (!IsListEmpty(&LockToc->GrantedListHead)) - { - EnumEntry = RemoveTailList(&LockToc->GrantedListHead); - Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED, ListEntry); - ExFreeToNPagedLookasideList(&GrantedLookaside, Granted); - } - - //remove, complete and free all pending locks - while (!IsListEmpty(&LockToc->PendingListHead)) - { - EnumEntry = RemoveTailList(&LockToc->PendingListHead); - Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry); - - if (!IoSetCancelRoutine(Irp, NULL)) - { - //The cancel routine will be called. When we release the lock it will complete the irp. - InitializeListHead(&Irp->Tail.Overlay.ListEntry); - continue; - } - - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - - Irp->IoStatus.Status = STATUS_RANGE_NOT_LOCKED; - Irp->IoStatus.Information = 0; - IoCompleteRequest(Irp, IO_NO_INCREMENT); - - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); - - } - - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - - ExFreeToNPagedLookasideList(&LockTocLookaside, LockToc); - - FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; - FileLock->LockInformation = NULL; - -} - - -/********************************************************************** - * NAME EXPORTED - * FsRtlAllocateFileLock - * - * NOTE - * Only present in NT 5.0 or later. - * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool! - * +NTAPI +FsRtlInitializeFileLock (IN PFILE_LOCK FileLock, + IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL, + IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL) +{ + /* Setup the lock */ + FileLock->FastIoIsQuestionable = FALSE; + FileLock->CompleteLockIrpRoutine = CompleteLockIrpRoutine; + FileLock->UnlockRoutine = UnlockRoutine; + FileLock->LockInformation = NULL; +} + +/* + * @implemented + */ +VOID +NTAPI +FsRtlUninitializeFileLock(IN PFILE_LOCK FileLock) +{ + PFILE_LOCK_TOC LockToc; + PIRP Irp; + PFILE_LOCK_GRANTED Granted; + PLIST_ENTRY EnumEntry; + KIRQL OldIrql; + + /* Get the lock information */ + LockToc = FileLock->LockInformation; + if (!FileLock->LockInformation) return; + + /* Acquire the lock queue */ + KeAcquireSpinLock(&LockToc->SpinLock, &OldIrql); + + /* Loop the lock tree */ + while (!IsListEmpty(&LockToc->GrantedListHead)) + { + /* Get the entry */ + EnumEntry = RemoveTailList(&LockToc->GrantedListHead); + + /* Get the granted lock and free it */ + Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED, ListEntry); + ExFreeToNPagedLookasideList(&GrantedLookaside, Granted); + } + + /* Loop the waiting locks */ + while (!IsListEmpty(&LockToc->PendingListHead)) + { + /* Get the entry and IRP */ + EnumEntry = RemoveTailList(&LockToc->PendingListHead); + Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry); + + /* Release the lock */ + KeReleaseSpinLock(&LockToc->SpinLock, OldIrql); + + /* Acquire cancel spinlock and clear the cancel routine */ + IoAcquireCancelSpinLock(&Irp->CancelIrql); + IoSetCancelRoutine(Irp, NULL); + IoReleaseCancelSpinLock(Irp->CancelIrql); + + /* Complete the IRP */ + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_RANGE_NOT_LOCKED; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + /* Acquire the lock again */ + KeAcquireSpinLock(&LockToc->SpinLock, &OldIrql); + } + + /* Release the lock and free it */ + KeReleaseSpinLock(&LockToc->SpinLock, OldIrql); + ExFreeToNPagedLookasideList(&LockTocLookaside, LockToc); + + /* Remove the lock information pointer */ + FileLock->LockInformation = NULL; +} + +/* * @implemented */ PFILE_LOCK -STDCALL -FsRtlAllocateFileLock( - IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL, - IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL - ) -{ - PFILE_LOCK FileLock; - - FileLock = ExAllocateFromPagedLookasideList(&LockLookaside); - - FsRtlInitializeFileLock(FileLock, - CompleteLockIrpRoutine, - UnlockRoutine - ); - - return FileLock; -} - -/********************************************************************** - * NAME EXPORTED - * FsRtlFreeFileLock - * - * NOTE - * Only present in NT 5.0 or later. - * FCB FILE_LOCK struct should/is acording to DDK allocated from paged pool! - * +NTAPI +FsRtlAllocateFileLock(IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL, + IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL) +{ + PFILE_LOCK FileLock; + + /* Try to allocate it */ + FileLock = ExAllocateFromPagedLookasideList(&LockLookaside); + if (FileLock) + { + /* Initialize it */ + FsRtlInitializeFileLock(FileLock, + CompleteLockIrpRoutine, + UnlockRoutine); + } + + /* Return the lock */ + return FileLock; +} + +/* * @implemented */ VOID -STDCALL -FsRtlFreeFileLock( - IN PFILE_LOCK FileLock - ) -{ - ASSERT(FileLock); - - FsRtlUninitializeFileLock(FileLock); - ExFreeToPagedLookasideList(&LockLookaside, FileLock); -} - -/* - * @implemented - */ -VOID -STDCALL -FsRtlAcquireFileExclusive( - IN PFILE_OBJECT FileObject - ) -{ - PFAST_IO_DISPATCH FastDispatch; - PDEVICE_OBJECT DeviceObject; - PFSRTL_COMMON_FCB_HEADER FcbHeader; - - /* Get the Device Object */ - DeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); - - /* Check if we have to do a Fast I/O Dispatch */ - if ((FastDispatch = DeviceObject->DriverObject->FastIoDispatch)) { - - /* Call the Fast I/O Routine */ - if (FastDispatch->AcquireFileForNtCreateSection) { - FastDispatch->AcquireFileForNtCreateSection(FileObject); - } - - return; - } - - /* Do a normal acquire */ - if ((FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)) { - - /* Use a Resource Acquire */ - ExAcquireResourceExclusive(FcbHeader->Resource, TRUE); - - return; - } - - /* Return...is there some kind of failure we should raise?? */ - return; -} - -/* - * @implemented - */ -VOID -STDCALL -FsRtlReleaseFile( - IN PFILE_OBJECT FileObject - ) -{ - PFAST_IO_DISPATCH FastDispatch; - PDEVICE_OBJECT DeviceObject; - PFSRTL_COMMON_FCB_HEADER FcbHeader; - - /* Get the Device Object */ - DeviceObject = IoGetBaseFileSystemDeviceObject(FileObject); - - /* Check if we have to do a Fast I/O Dispatch */ - if ((FastDispatch = DeviceObject->DriverObject->FastIoDispatch)) { - - /* Use Fast I/O */ - if (FastDispatch->ReleaseFileForNtCreateSection) { - FastDispatch->ReleaseFileForNtCreateSection(FileObject); - } - - return; - } - - /* Do a normal acquire */ - if ((FcbHeader = (PFSRTL_COMMON_FCB_HEADER)FileObject->FsContext)) { - - /* Use a Resource Release */ - ExReleaseResourceLite(FcbHeader->Resource); - - return; - } - - /* Return...is there some kind of failure we should raise?? */ - return; -} - +NTAPI +FsRtlFreeFileLock(IN PFILE_LOCK FileLock) +{ + /* Uninitialize and free the lock */ + FsRtlUninitializeFileLock(FileLock); + ExFreeToPagedLookasideList(&LockLookaside, FileLock); +}
/* EOF */