diff --git a/reactos/ntoskrnl/fs/filelock.c b/reactos/ntoskrnl/fs/filelock.c index 75f9ad80720..9b3972c6e54 100644 --- a/reactos/ntoskrnl/fs/filelock.c +++ b/reactos/ntoskrnl/fs/filelock.c @@ -1,4 +1,4 @@ -/* $Id: filelock.c,v 1.6 2002/11/13 06:01:11 robd Exp $ +/* $Id: filelock.c,v 1.7 2003/01/25 15:52:43 hbirr Exp $ * * reactos/ntoskrnl/fs/filelock.c * @@ -10,25 +10,22 @@ #define NDEBUG #include -//#define TAG_LOCK TAG('F','l','c','k') - /* -NOTE: -I'm not using resource syncronization here, since -FsRtlFastCheckLockForRead/FsRtlFastCheckLockForWrite -can be running at any IRQL. Therefore I also have used -nonpaged memory for the lists. +NOTE: +I'm not using resource syncronization here, since FsRtlFastCheckLockForRead/Write +are allowed to be called at DISPATCH_LEVEL. Must therefore use nonpaged memory for +the lists. */ -#define LOCK_START_OFF(Lock) ((Lock).StartingByte.QuadPart) -#define LOCK_END_OFF(Lock) (((Lock).StartingByte.QuadPart) + ((Lock).Length.QuadPart) - 1) -#define REQUEST_START_OFF (FileOffset->QuadPart) -#define REQUEST_END_OFF ((FileOffset->QuadPart) + (Length->QuadPart) - 1) +#define LOCK_START_OFF(Lock) ((Lock).StartingByte.QuadPart) +#define LOCK_END_OFF(Lock) (((Lock).StartingByte.QuadPart) + ((Lock).Length.QuadPart) - 1) +#define REQUEST_START_OFF (FileOffset->QuadPart) +#define REQUEST_END_OFF ((FileOffset->QuadPart) + (Length->QuadPart) - 1) -FAST_MUTEX LockTocMutex; -NPAGED_LOOKASIDE_LIST PendingLookaside; -NPAGED_LOOKASIDE_LIST GrantedLookaside; -NPAGED_LOOKASIDE_LIST LockTocLookaside; +FAST_MUTEX LockTocMutex; +NPAGED_LOOKASIDE_LIST GrantedLookaside; +NPAGED_LOOKASIDE_LIST LockTocLookaside; +PAGED_LOOKASIDE_LIST LockLookaside; /********************************************************************** * NAME PRIVATE @@ -39,166 +36,148 @@ VOID STDCALL FsRtlpInitFileLockingImplementation(VOID) { - ExInitializeNPagedLookasideList( &LockTocLookaside, - NULL, - NULL, - 0, - sizeof(FILE_LOCK_TOC), - IFS_POOL_TAG, - 0 - ); + ExInitializeNPagedLookasideList( &LockTocLookaside, + NULL, + NULL, + 0, + sizeof(FILE_LOCK_TOC), + IFS_POOL_TAG, + 0 + ); - ExInitializeNPagedLookasideList( &GrantedLookaside, - NULL, - NULL, - 0, - sizeof(FILE_LOCK_GRANTED), - IFS_POOL_TAG, - 0 - ); + ExInitializeNPagedLookasideList( &GrantedLookaside, + NULL, + NULL, + 0, + sizeof(FILE_LOCK_GRANTED), + IFS_POOL_TAG, + 0 + ); - ExInitializeNPagedLookasideList( &PendingLookaside, - NULL, - NULL, - 0, - sizeof(FILE_LOCK_PENDING), - IFS_POOL_TAG, - 0 - ); + ExInitializePagedLookasideList( &LockLookaside, + NULL, + NULL, + 0, + sizeof(FILE_LOCK), + IFS_POOL_TAG, + 0 + ); - ExInitializeFastMutex(&LockTocMutex); + ExInitializeFastMutex(&LockTocMutex); } - /********************************************************************** * NAME PRIVATE - * FsRtlpPendingFileLockCancelRoutine + * FsRtlpFileLockCancelRoutine * */ -VOID -STDCALL -FsRtlpPendingFileLockCancelRoutine( - IN PDEVICE_OBJECT DeviceObject, - IN PIRP Irp - ) +VOID +STDCALL +FsRtlpFileLockCancelRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) { - KIRQL oldIrql; - PFILE_LOCK FileLock; - PFILE_LOCK_TOC LockToc; - PFILE_LOCK_PENDING Pending; - PLIST_ENTRY EnumEntry; + KIRQL oldIrql; + PKSPIN_LOCK SpinLock; + PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine; - IoReleaseCancelSpinLock(Irp->CancelIrql); //don't need this for private queue cancelation + //don't need this since we have our own sync. protecting irp cancellation + IoReleaseCancelSpinLock(Irp->CancelIrql); - FileLock = (PVOID)Irp->IoStatus.Information; - assert(FileLock); - LockToc = FileLock->LockInformation; - if (LockToc == NULL) - return; + SpinLock = &((PFILE_LOCK_TOC)Irp->Tail.Overlay.DriverContext[1])->SpinLock; - KeAcquireSpinLock(&LockToc->SpinLock, &oldIrql); + KeAcquireSpinLock(SpinLock, &oldIrql); + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); + KeReleaseSpinLock(SpinLock, oldIrql); - EnumEntry = LockToc->PendingListHead.Flink; - while (EnumEntry != &LockToc->PendingListHead) { - Pending = CONTAINING_RECORD(EnumEntry, FILE_LOCK_PENDING , ListEntry ); - - if (Pending->Irp == Irp){ - RemoveEntryList(&Pending->ListEntry); - KeReleaseSpinLock(&LockToc->SpinLock, oldIrql); - Irp->IoStatus.Status = STATUS_CANCELLED; - - if (FileLock->CompleteLockIrpRoutine ) - FileLock->CompleteLockIrpRoutine(Pending->Context,Irp); - else - IofCompleteRequest(Irp,IO_NO_INCREMENT); - - ExFreeToNPagedLookasideList(&PendingLookaside,Pending); - return; - } - EnumEntry = EnumEntry->Flink; - } - - /* - didn't find irp in list, so someone else must have completed it - while we were waiting for the spinlock - */ - KeReleaseSpinLock(&LockToc->SpinLock, oldIrql); + Irp->IoStatus.Status = STATUS_CANCELLED; + CompleteLockIrpRoutine = ((PFILE_LOCK)Irp->Tail.Overlay.DriverContext[0])->CompleteLockIrpRoutine; + if (CompleteLockIrpRoutine) + { + CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp); + } + else + { + IofCompleteRequest(Irp, IO_NO_INCREMENT); + } + } - - - - /********************************************************************** * NAME PRIVATE * FsRtlpCheckLockForReadOrWriteAccess * */ BOOLEAN -STDCALL +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 - ) -{ - KIRQL oldirql; - PFILE_LOCK_TOC LockToc; - PFILE_LOCK_GRANTED Granted; - PLIST_ENTRY EnumEntry; + 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; + PFILE_LOCK_GRANTED Granted; + PLIST_ENTRY EnumEntry; - assert(FileLock); - LockToc = FileLock->LockInformation; + assert(FileLock); + LockToc = FileLock->LockInformation; - if (LockToc == NULL || Length->QuadPart == 0) { - return TRUE; - } + if (LockToc == NULL || Length->QuadPart == 0) + { + return TRUE; + } - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); - EnumEntry = LockToc->GrantedListHead.Flink; - while ( EnumEntry != &LockToc->GrantedListHead){ + EnumEntry = LockToc->GrantedListHead.Flink; + while ( EnumEntry != &LockToc->GrantedListHead) + { + Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED , ListEntry ); + //if overlapping + if(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) || + REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock))) + { + //No read conflict if (shared lock) OR (exclusive + our lock) + //No write conflict if exclusive lock AND our lock + if ((Read && !Granted->Lock.ExclusiveLock) || + (Granted->Lock.ExclusiveLock && + Granted->Lock.Process == Process && + Granted->Lock.FileObject == FileObject && + Granted->Lock.Key == Key ) ) + { + //AND if lock surround request region, stop searching and grant + if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) && + REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock)) + { + EnumEntry = &LockToc->GrantedListHead;//indicate no conflict + break; + } + //else continue searching for conflicts + } + else //conflict + { + break; + } + } + EnumEntry = EnumEntry->Flink; + } - Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED , ListEntry ); - //if overlapping - if(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) || - REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock))) { + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - //No read conflict if (shared lock) OR (exclusive + our lock) - //No write conflict if exclusive lock AND our lock - if ((Read && !Granted->Lock.ExclusiveLock) || - (Granted->Lock.ExclusiveLock && - Granted->Lock.Process == Process && - Granted->Lock.FileObject == FileObject && - Granted->Lock.Key == Key ) ) { + if (EnumEntry == &LockToc->GrantedListHead) + { //no conflict + return TRUE; + } - //AND if lock surround read region, stop searching and grant - if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) && - REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock)){ - - EnumEntry = &LockToc->GrantedListHead;//success - break; - } - //else continue searching for conflicts - } - else //conflict - break; - } - EnumEntry = EnumEntry->Flink; - } - - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - - if (EnumEntry == &LockToc->GrantedListHead) { //no conflict - return TRUE; - } - - return FALSE; + return FALSE; } @@ -210,26 +189,26 @@ FsRtlpCheckLockForReadOrWriteAccess( BOOLEAN STDCALL FsRtlCheckLockForReadAccess ( - IN PFILE_LOCK FileLock, - IN PIRP Irp - ) + IN PFILE_LOCK FileLock, + IN PIRP Irp + ) { - PIO_STACK_LOCATION Stack; - LARGE_INTEGER LocalLength; + PIO_STACK_LOCATION Stack; + LARGE_INTEGER LocalLength; - Stack = IoGetCurrentIrpStackLocation(Irp); + Stack = IoGetCurrentIrpStackLocation(Irp); - LocalLength.u.LowPart = Stack->Parameters.Read.Length; - LocalLength.u.HighPart = 0; + 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? - ); + return FsRtlpCheckLockForReadOrWriteAccess( FileLock, + &Stack->Parameters.Read.ByteOffset, + &LocalLength, + Stack->Parameters.Read.Key, + Stack->FileObject, + IoGetRequestorProcess(Irp), + TRUE//Read? + ); } @@ -241,26 +220,26 @@ FsRtlCheckLockForReadAccess ( BOOLEAN STDCALL FsRtlCheckLockForWriteAccess ( - IN PFILE_LOCK FileLock, - IN PIRP Irp - ) + IN PFILE_LOCK FileLock, + IN PIRP Irp + ) { - PIO_STACK_LOCATION Stack; - LARGE_INTEGER LocalLength; + PIO_STACK_LOCATION Stack; + LARGE_INTEGER LocalLength; - Stack = IoGetCurrentIrpStackLocation(Irp); + Stack = IoGetCurrentIrpStackLocation(Irp); - LocalLength.u.LowPart = Stack->Parameters.Read.Length; - LocalLength.u.HighPart = 0; + 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? - ); + return FsRtlpCheckLockForReadOrWriteAccess( FileLock, + &Stack->Parameters.Write.ByteOffset, + &LocalLength, + Stack->Parameters.Write.Key, + Stack->FileObject, + IoGetRequestorProcess(Irp), + FALSE//Read? + ); } @@ -275,22 +254,22 @@ FsRtlCheckLockForWriteAccess ( 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 - ) + 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? - ); + return FsRtlpCheckLockForReadOrWriteAccess( FileLock, + FileOffset, + Length, + Key, + FileObject, + Process, + TRUE//Read? + ); } @@ -302,22 +281,22 @@ FsRtlFastCheckLockForRead ( 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 - ) + 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? - ); + return FsRtlpCheckLockForReadOrWriteAccess( FileLock, + FileOffset, + Length, + Key, + FileObject, + Process, + FALSE//Read? + ); } @@ -328,73 +307,93 @@ FsRtlFastCheckLockForWrite ( * */ NTSTATUS -STDCALL +FASTCALL FsRtlpFastUnlockAllByKey( - IN PFILE_LOCK FileLock, - IN PFILE_OBJECT FileObject, - IN PEPROCESS Process, - IN DWORD Key, /* FIXME: guess */ - IN BOOLEAN UseKey, /* FIXME: guess */ - IN PVOID Context OPTIONAL - ) + IN PFILE_LOCK FileLock, + IN PFILE_OBJECT FileObject, + IN PEPROCESS Process, + IN DWORD Key, /* FIXME: guess */ + IN BOOLEAN UseKey, /* FIXME: guess */ + IN PVOID Context OPTIONAL + ) { - KIRQL oldirql; - PFILE_LOCK_TOC LockToc; - PLIST_ENTRY EnumEntry; - PFILE_LOCK_GRANTED Granted; - BOOLEAN Unlock = FALSE; - //must make local copy since FILE_LOCK struct is allowed to be paged - BOOLEAN GotUnlockRoutine; + KIRQL oldirql; + PFILE_LOCK_TOC LockToc; + PLIST_ENTRY EnumEntry; + PFILE_LOCK_GRANTED Granted; + BOOLEAN Unlock = FALSE; + //must make local copy since FILE_LOCK struct is allowed to be paged + PUNLOCK_ROUTINE GotUnlockRoutine; - assert(FileLock); - LockToc = FileLock->LockInformation; + assert(FileLock); + LockToc = FileLock->LockInformation; - if (LockToc == NULL) - return STATUS_RANGE_NOT_LOCKED; + if (LockToc == NULL) + { + return STATUS_RANGE_NOT_LOCKED; + } - GotUnlockRoutine = FileLock->UnlockRoutine ? TRUE : FALSE; - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + GotUnlockRoutine = FileLock->UnlockRoutine; + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); - EnumEntry = LockToc->GrantedListHead.Flink; - while ( EnumEntry != &LockToc->GrantedListHead ) { + EnumEntry = LockToc->GrantedListHead.Flink; + while (EnumEntry != &LockToc->GrantedListHead ) + { + Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry); + EnumEntry = EnumEntry->Flink; - Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry); - EnumEntry = EnumEntry->Flink; + if (Granted->Lock.Process == Process && + Granted->Lock.FileObject == FileObject && + (!UseKey || (UseKey && Granted->Lock.Key == Key)) ) + { + RemoveEntryList(&Granted->ListEntry); + Unlock = TRUE; - if (Granted->Lock.Process == Process && - Granted->Lock.FileObject == FileObject && - (!UseKey || (UseKey && Granted->Lock.Key == Key)) ){ + 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(&LockToc->UnlockedListHead,&Granted->ListEntry); + } + else + { + ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); + } + } + } - RemoveEntryList(&Granted->ListEntry); - Unlock = TRUE; + if (Unlock) + { + //call unlock routine for each unlocked lock (if any) + while (!IsListEmpty(&LockToc->UnlockedListHead)) + { + EnumEntry = RemoveTailList(&LockToc->UnlockedListHead); + Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry); + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + FileLock->UnlockRoutine(Context,&Granted->Lock); + ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + } - if (GotUnlockRoutine) { - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - FileLock->UnlockRoutine(Context,&Granted->Lock); - ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); - EnumEntry = LockToc->GrantedListHead.Flink; //restart - continue; - } + //NOTE: holding spinlock while calling this + FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql); - ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); - } - } + if (IsListEmpty(&LockToc->GrantedListHead)) + { + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; + } + else + { + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + } + return STATUS_SUCCESS; + } - if (Unlock){ - FsRtlpTryCompletePendingLocks(FileLock,LockToc,NULL); - } - - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - - if (Unlock) { - if (IsListEmpty(&LockToc->GrantedListHead)) - FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; - - return STATUS_SUCCESS; - } - - return STATUS_RANGE_NOT_LOCKED; + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + return STATUS_RANGE_NOT_LOCKED; } /********************************************************************** @@ -405,19 +404,19 @@ FsRtlpFastUnlockAllByKey( NTSTATUS STDCALL FsRtlFastUnlockAll /*ByProcess*/ ( - IN PFILE_LOCK FileLock, - IN PFILE_OBJECT FileObject, - IN PEPROCESS Process, - IN PVOID Context OPTIONAL - ) + IN PFILE_LOCK FileLock, + IN PFILE_OBJECT FileObject, + IN PEPROCESS Process, + IN PVOID Context OPTIONAL + ) { - return FsRtlpFastUnlockAllByKey ( FileLock, - FileObject, - Process, - 0, /* Key */ - FALSE, /* Do NOT use Key */ - Context - ); + return FsRtlpFastUnlockAllByKey( FileLock, + FileObject, + Process, + 0, /* Key */ + FALSE, /* Do NOT use Key */ + Context + ); } /********************************************************************** @@ -428,20 +427,20 @@ FsRtlFastUnlockAll /*ByProcess*/ ( NTSTATUS STDCALL FsRtlFastUnlockAllByKey ( - IN PFILE_LOCK FileLock, - IN PFILE_OBJECT FileObject, - IN PEPROCESS Process, - IN ULONG Key, - IN PVOID Context OPTIONAL - ) + 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 - ); + return FsRtlpFastUnlockAllByKey( FileLock, + FileObject, + Process, + Key, + TRUE, /* Use Key */ + Context + ); } @@ -453,65 +452,65 @@ FsRtlFastUnlockAllByKey ( * Spinlock held at entry !! */ NTSTATUS -STDCALL +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 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 + ) { - PLIST_ENTRY EnumEntry; - PFILE_LOCK_GRANTED Granted; - - EnumEntry = LockToc->GrantedListHead.Flink; - while (EnumEntry != &LockToc->GrantedListHead) { + PLIST_ENTRY EnumEntry; + PFILE_LOCK_GRANTED Granted; - Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry); - //if overlapping - if(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) || - REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock))) { + EnumEntry = LockToc->GrantedListHead.Flink; + while (EnumEntry != &LockToc->GrantedListHead) + { + Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry); + //if overlapping + if(!(REQUEST_START_OFF > LOCK_END_OFF(Granted->Lock) || + REQUEST_END_OFF < LOCK_START_OFF(Granted->Lock))) + { + //never conflict if shared lock and we want to add a shared lock + if (!Granted->Lock.ExclusiveLock && !ExclusiveLock) + { + //AND if lock surround region, stop searching and insert lock + if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) && + REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock)) + { + EnumEntry = &LockToc->GrantedListHead; + break; + } + //else keep locking for conflicts + } + else + {//conflict if we want share access to excl. lock OR exlc. access to shared lock + break;//FAIL + } + } + EnumEntry = EnumEntry->Flink; + } - //never conflict if shared lock and we want to add a shared lock - if (!Granted->Lock.ExclusiveLock && - !ExclusiveLock) { + if (EnumEntry == &LockToc->GrantedListHead) + {//no conflict + Granted = ExAllocateFromNPagedLookasideList(&GrantedLookaside); - //AND if lock surround region, stop searching and insert lock - if (REQUEST_START_OFF >= LOCK_START_OFF(Granted->Lock) && - REQUEST_END_OFF <= LOCK_END_OFF(Granted->Lock)){ + Granted->Lock.StartingByte = *FileOffset; + Granted->Lock.Length = *Length; + Granted->Lock.ExclusiveLock = ExclusiveLock; + Granted->Lock.Key = Key; + Granted->Lock.FileObject = FileObject; + Granted->Lock.Process = Process; + Granted->Lock.EndingByte.QuadPart = REQUEST_END_OFF; - EnumEntry = &LockToc->GrantedListHead; - break; - } - //else keep locking for conflicts - } - else //conflict if we want share access to excl. lock OR exlc. access to shared lock - break;//FAIL - } + InsertHeadList(&LockToc->GrantedListHead,&Granted->ListEntry); + return TRUE; + } - EnumEntry = EnumEntry->Flink; - } - - if (EnumEntry == &LockToc->GrantedListHead) {//no conflict - - Granted = ExAllocateFromNPagedLookasideList(&GrantedLookaside); - - Granted->Lock.StartingByte = *FileOffset; - Granted->Lock.Length = *Length; - Granted->Lock.ExclusiveLock = ExclusiveLock; - Granted->Lock.Key = Key; - Granted->Lock.FileObject = FileObject; - Granted->Lock.Process = Process; - Granted->Lock.EndingByte.QuadPart = REQUEST_END_OFF; - - InsertHeadList(&LockToc->GrantedListHead,&Granted->ListEntry); - return TRUE; - } - - return FALSE; + return FALSE; } @@ -519,64 +518,85 @@ FsRtlpAddLock( /********************************************************************** * NAME PRIVATE - * FsRtlpTryCompletePendingLocks + * FsRtlpCompletePendingLocks * * NOTE * Spinlock held at entry !! */ VOID -STDCALL -FsRtlpTryCompletePendingLocks( - IN PFILE_LOCK FileLock, - IN PFILE_LOCK_TOC LockToc, - IN OUT PKIRQL oldirql - ) +FASTCALL +FsRtlpCompletePendingLocks( + IN PFILE_LOCK FileLock, + IN PFILE_LOCK_TOC LockToc, + IN OUT PKIRQL oldirql + ) { - //walk pending list, FIFO order, try 2 complete locks - PLIST_ENTRY EnumEntry; - PFILE_LOCK_PENDING Pending; - PIO_STACK_LOCATION Stack; + //walk pending list, FIFO order, try 2 complete locks + PLIST_ENTRY EnumEntry; + PIRP Irp; + PIO_STACK_LOCATION Stack; - EnumEntry = LockToc->PendingListHead.Blink; - while (EnumEntry != &LockToc->PendingListHead) { + EnumEntry = LockToc->PendingListHead.Blink; + while (EnumEntry != &LockToc->PendingListHead) + { + Irp = CONTAINING_RECORD(EnumEntry,IRP, Tail.Overlay.ListEntry); - Pending = CONTAINING_RECORD(EnumEntry, FILE_LOCK_PENDING,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 + ) ) + { + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); - Stack = IoGetCurrentIrpStackLocation(Pending->Irp); - - if (FsRtlpAddLock( LockToc, - Stack->FileObject,//correct? - &Stack->Parameters.LockControl.ByteOffset, - Stack->Parameters.LockControl.Length, - IoGetRequestorProcess(Pending->Irp), - Stack->Parameters.LockControl.Key, - Stack->Flags & SL_EXCLUSIVE_LOCK - ) ) { + if (!IoSetCancelRoutine(Irp, NULL)) + { + /* + Cancel routine WILL be called after we release the spinlock. It will try to remove + the irp from the list and cancel/complete this irp. Since we allready removed it, + make its ListEntry point to itself. + */ + InitializeListHead(&Irp->Tail.Overlay.ListEntry); + } + else + { + /* + Cancel routine will NOT be called, canceled or not. - RemoveEntryList(&Pending->ListEntry); + Put on completed list and complete them all afterwards. + This way we don't have to restart enum after each completion. + */ + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + InsertHeadList(&LockToc->CompletedListHead,&Irp->Tail.Overlay.ListEntry); + } + } + EnumEntry = EnumEntry->Blink; + } - IoSetCancelRoutine(Pending->Irp, NULL); - /* - Irp could be cancelled and the cancel routine may or may not have been called, - waiting there for our spinlock. - But it doesn't matter because it will not find the IRP in the list. - */ - KeReleaseSpinLock(&LockToc->SpinLock, *oldirql);//fires cancel routine - Pending->Irp->IoStatus.Status = STATUS_SUCCESS; + //complete irp's (if any) + while (!IsListEmpty(&LockToc->CompletedListHead)) + { + EnumEntry = RemoveTailList(&LockToc->CompletedListHead); + KeReleaseSpinLock(&LockToc->SpinLock, *oldirql);//fires cancel routine + Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry); - if (FileLock->CompleteLockIrpRoutine) - FileLock->CompleteLockIrpRoutine(Pending->Context,Pending->Irp); - else - IofCompleteRequest(Pending->Irp, IO_NO_INCREMENT); + if (FileLock->CompleteLockIrpRoutine) + { + FileLock->CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp); + } + else + { + IofCompleteRequest(Irp, IO_NO_INCREMENT); + } + + KeAcquireSpinLock(&LockToc->SpinLock, oldirql); + } - ExFreeToNPagedLookasideList(&PendingLookaside,Pending); - KeAcquireSpinLock(&LockToc->SpinLock, oldirql); - //restart, something migth have happend to our list - EnumEntry = LockToc->PendingListHead.Blink; - continue; - } - EnumEntry = EnumEntry->Blink; - } } @@ -587,67 +607,74 @@ FsRtlpTryCompletePendingLocks( * */ NTSTATUS -STDCALL +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 AlreadySynchronized, - IN BOOLEAN CallUnlockRoutine - ) + 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, + IN BOOLEAN CallUnlockRoutine + ) { - KIRQL oldirql; - PFILE_LOCK_TOC LockToc; - PFILE_LOCK_GRANTED Granted; - PLIST_ENTRY EnumEntry; + KIRQL oldirql; + PFILE_LOCK_TOC LockToc; + PFILE_LOCK_GRANTED Granted; + PLIST_ENTRY EnumEntry; - assert(FileLock); - LockToc = FileLock->LockInformation; + assert(FileLock); + LockToc = FileLock->LockInformation; - if (LockToc == NULL) - return STATUS_RANGE_NOT_LOCKED; + if (LockToc == NULL || Length->QuadPart == 0) + { + return STATUS_RANGE_NOT_LOCKED; + } - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql ); + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql ); - EnumEntry = LockToc->GrantedListHead.Flink; - while (EnumEntry != &LockToc->GrantedListHead) { + EnumEntry = LockToc->GrantedListHead.Flink; + while (EnumEntry != &LockToc->GrantedListHead) + { + Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry); - Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry); + //must be exact match + if (FileOffset->QuadPart == Granted->Lock.StartingByte.QuadPart && + Length->QuadPart == Granted->Lock.Length.QuadPart && + Granted->Lock.Process == Process && + Granted->Lock.FileObject == FileObject && + Granted->Lock.Key == Key) + { + RemoveEntryList(&Granted->ListEntry); + FsRtlpCompletePendingLocks(FileLock, LockToc, &oldirql); - //must be exact match - if (FileOffset->QuadPart == Granted->Lock.StartingByte.QuadPart && - Length->QuadPart == Granted->Lock.Length.QuadPart && - Granted->Lock.Process == Process && - Granted->Lock.FileObject == FileObject && - Granted->Lock.Key == Key) { + if (IsListEmpty(&LockToc->GrantedListHead)) + { + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; + } + else + { + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + } - RemoveEntryList(&Granted->ListEntry); + if (FileLock->UnlockRoutine && CallUnlockRoutine) + { + FileLock->UnlockRoutine(Context,&Granted->Lock); + } - FsRtlpTryCompletePendingLocks(FileLock, LockToc,NULL); - - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); - if (FileLock->UnlockRoutine && CallUnlockRoutine) - FileLock->UnlockRoutine(Context,&Granted->Lock); + return STATUS_SUCCESS; + } + EnumEntry = EnumEntry->Flink; + } - ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - if (IsListEmpty(&LockToc->GrantedListHead)) - FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; - - return STATUS_SUCCESS; - - } - EnumEntry = EnumEntry->Flink; - } - - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - - return STATUS_RANGE_NOT_LOCKED; + return STATUS_RANGE_NOT_LOCKED; } @@ -661,100 +688,101 @@ FsRtlpUnlockSingle( 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 - ) + 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, - FileObject, - FileOffset, - Length, - Process, - Key, - Context, - AlreadySynchronized, - TRUE//CallUnlockRoutine - ); + return FsRtlpUnlockSingle( FileLock, + FileObject, + FileOffset, + Length, + Process, + Key, + Context, + AlreadySynchronized, + TRUE//CallUnlockRoutine + ); } /********************************************************************** * NAME EXPORTED * FsRtlpDumpFileLocks * + * NOTE: used for testing and debugging */ VOID -STDCALL +FASTCALL FsRtlpDumpFileLocks( - IN PFILE_LOCK FileLock - ) + IN PFILE_LOCK FileLock + ) { - //100% OK - KIRQL oldirql; - PFILE_LOCK_TOC LockToc; - PFILE_LOCK_GRANTED Granted; - PFILE_LOCK_PENDING Pending; - PLIST_ENTRY EnumEntry; - PIO_STACK_LOCATION Stack; + KIRQL oldirql; + PFILE_LOCK_TOC LockToc; + PFILE_LOCK_GRANTED Granted; + PIRP Irp; + PLIST_ENTRY EnumEntry; + PIO_STACK_LOCATION Stack; - assert(FileLock); - LockToc = FileLock->LockInformation; + assert(FileLock); + LockToc = FileLock->LockInformation; - if (LockToc == NULL) { - DPRINT1("No file locks\n"); - return; - } + if (LockToc == NULL) + { + DPRINT1("No file locks\n"); + return; + } - DPRINT1("Dumping granted file locks, FIFO order\n"); + DPRINT1("Dumping granted file locks, FIFO order\n"); - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); - EnumEntry = LockToc->GrantedListHead.Blink; - while ( EnumEntry != &LockToc->GrantedListHead){ + EnumEntry = LockToc->GrantedListHead.Blink; + while ( EnumEntry != &LockToc->GrantedListHead) + { + Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED , ListEntry ); - Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED , ListEntry ); - - DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n", - Granted->Lock.ExclusiveLock ? "EXCL" : "SHRD", - Granted->Lock.StartingByte.QuadPart, - Granted->Lock.Length.QuadPart, - Granted->Lock.EndingByte.QuadPart, - Granted->Lock.Key, - Granted->Lock.Process, - Granted->Lock.FileObject - ); + DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\n", + Granted->Lock.ExclusiveLock ? "EXCL" : "SHRD", + Granted->Lock.StartingByte.QuadPart, + Granted->Lock.Length.QuadPart, + Granted->Lock.EndingByte.QuadPart, + Granted->Lock.Key, + Granted->Lock.Process, + Granted->Lock.FileObject + ); - EnumEntry = EnumEntry->Blink; - } + EnumEntry = EnumEntry->Blink; + } - DPRINT1("Dumping pending file locks, FIFO order\n"); + DPRINT1("Dumping pending file locks, FIFO order\n"); - EnumEntry = LockToc->PendingListHead.Blink; - while ( EnumEntry != &LockToc->PendingListHead){ + EnumEntry = LockToc->PendingListHead.Blink; + while ( EnumEntry != &LockToc->PendingListHead) + { + Irp = CONTAINING_RECORD(EnumEntry, IRP , Tail.Overlay.ListEntry ); - Pending = CONTAINING_RECORD(EnumEntry, FILE_LOCK_PENDING , ListEntry ); - - Stack = IoGetCurrentIrpStackLocation(Pending->Irp); + Stack = IoGetCurrentIrpStackLocation(Irp); - DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\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(Pending->Irp), - Stack->FileObject - ); + DPRINT1("%s, start: %i, len: %i, end: %i, key: %i, proc: 0x%X, fob: 0x%X\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 + ); - EnumEntry = EnumEntry->Blink; - } + EnumEntry = EnumEntry->Blink; + } - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); } @@ -770,85 +798,93 @@ FsRtlpDumpFileLocks( 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 free 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; + 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; + assert(FileLock); + LockToc = FileLock->LockInformation; + if (LockToc == NULL) + { + return NULL; + } - LocalLastReturnedLock = FileLock->LastReturnedLock; + LocalLastReturnedLock = FileLock->LastReturnedLock; - KeAcquireSpinLock(&LockToc->SpinLock,&oldirql); + KeAcquireSpinLock(&LockToc->SpinLock,&oldirql); restart:; - EnumEntry = LockToc->GrantedListHead.Flink; + 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; - } - } + if (Restart) + { + if (EnumEntry != &LockToc->GrantedListHead) + { + Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED,ListEntry); + LocalLastReturnedLockInfo = Granted->Lock; + KeReleaseSpinLock(&LockToc->SpinLock,oldirql); - //else: continue enum - while (EnumEntry != &LockToc->GrantedListHead) { + FileLock->LastReturnedLockInfo = LocalLastReturnedLockInfo; + FileLock->LastReturnedLock = EnumEntry; + return &FileLock->LastReturnedLockInfo; + } + else + { + KeReleaseSpinLock(&LockToc->SpinLock,oldirql); + return NULL; + } + } - //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); + //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; - } + 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; - } + 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); + KeReleaseSpinLock(&LockToc->SpinLock,oldirql); - return NULL;//no (more) locks + return NULL;//no (more) locks } @@ -863,16 +899,16 @@ restart:; VOID STDCALL FsRtlInitializeFileLock ( - IN PFILE_LOCK FileLock, - IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL, - IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL - ) + 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; + FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; + FileLock->CompleteLockIrpRoutine = CompleteLockIrpRoutine; + FileLock->UnlockRoutine = UnlockRoutine; + FileLock->LockInformation = NULL; } @@ -885,118 +921,139 @@ FsRtlInitializeFileLock ( 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, //meaningless for fast io - IN BOOLEAN ExclusiveLock, - OUT PIO_STATUS_BLOCK IoStatus, - IN PIRP Irp OPTIONAL, - IN PVOID Context, - IN BOOLEAN AlreadySynchronized - ) + 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, + IN BOOLEAN AlreadySynchronized + ) { - PFILE_LOCK_TOC LockToc; - KIRQL oldirql; - PFILE_LOCK_PENDING Pending; + 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->PendingListHead); - InitializeListHead(&LockToc->GrantedListHead); - } - ExReleaseFastMutex(&LockTocMutex); - } + 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); + InitializeListHead(&LockToc->CompletedListHead); + InitializeListHead(&LockToc->UnlockedListHead); + } + ExReleaseFastMutex(&LockTocMutex); + } - LockToc = FileLock->LockInformation; - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + LockToc = FileLock->LockInformation; + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); - //try add new lock - if (FsRtlpAddLock( LockToc, - FileObject, - FileOffset, - Length, - Process, - Key, - ExclusiveLock - ) ) { + //try add new lock (while holding spin lock) + if (FsRtlpAddLock(LockToc, + FileObject, + FileOffset, + Length, + Process, + Key, + ExclusiveLock + ) ) + { + IoStatus->Status = STATUS_SUCCESS; + } + else if (Irp && !FailImmediately) + { //failed + irp + no fail = mk. pending + //for our cancel routine + Irp->Tail.Overlay.DriverContext[0] = (PVOID)FileLock; + Irp->Tail.Overlay.DriverContext[1] = (PVOID)LockToc; + Irp->Tail.Overlay.DriverContext[2] = Context; - IoStatus->Status = STATUS_SUCCESS; - } - else if (Irp && !FailImmediately) { //failed + irp + no fail = mk. pending + IoSetCancelRoutine(Irp, FsRtlpFileLockCancelRoutine); - Irp->IoStatus.Information = (DWORD)FileLock;//for our cancel routine - IoSetCancelRoutine(Irp, FsRtlpPendingFileLockCancelRoutine); + if (Irp->Cancel) + { + //irp canceled even before we got to queue it + if (IoSetCancelRoutine(Irp, NULL)) + { //Cancel routine will NOT be called: cancel it here + IoStatus->Status = STATUS_CANCELLED; + } + else + { //Cancel routine WILL be called. When we release the lock it will complete the irp + //Return pending since we are not completing the irp here + Irp->IoStatus.Status = IoStatus->Status = STATUS_PENDING; + Irp->IoStatus.Information = 0; + InitializeListHead(&Irp->Tail.Overlay.ListEntry); + } + + } + else + { //not cancelled: queue irp + IoMarkIrpPending(Irp); + Irp->IoStatus.Status = IoStatus->Status = STATUS_PENDING; + Irp->IoStatus.Information = 0; + InsertHeadList(&LockToc->PendingListHead,&Irp->Tail.Overlay.ListEntry); + } - if (Irp->Cancel) { - IoSetCancelRoutine(Irp, NULL); - /* - Irp was canceled and the cancel routine may or may not have been called, - waiting there for our spinlock. - But it doesn't matter since it will not find the IRP in the list. - */ - IoStatus->Status = STATUS_CANCELLED; - } - else { //not cancelled: queue irp - IoMarkIrpPending(Irp); - Pending = ExAllocateFromNPagedLookasideList(&PendingLookaside); - Pending->Context = Context; - Pending->Irp = Irp; - IoStatus->Status = STATUS_PENDING; - InsertHeadList(&LockToc->PendingListHead,&Pending->ListEntry); - } + } + else + { + IoStatus->Status = STATUS_LOCK_NOT_GRANTED; + } - } - else { - IoStatus->Status = STATUS_LOCK_NOT_GRANTED; - } + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); //fires cancel routine - KeReleaseSpinLock(&LockToc->SpinLock, oldirql); //fires cancel routine + //never pending if no irp;-) + assert(!(IoStatus->Status == STATUS_PENDING && !Irp)); - assert(!(IoStatus->Status == STATUS_PENDING && !Irp)); + if (IoStatus->Status != STATUS_PENDING) + { + if (IoStatus->Status == STATUS_SUCCESS) + { + FsRtlAreThereCurrentFileLocks(FileLock) = TRUE; + } - if (IoStatus->Status == STATUS_SUCCESS) - FsRtlAreThereCurrentFileLocks(FileLock) = TRUE; + if (Irp) + { + Irp->IoStatus.Status = IoStatus->Status; + Irp->IoStatus.Information = 0; - Irp->IoStatus.Status = IoStatus->Status; + if (FileLock->CompleteLockIrpRoutine) + { //complete irp routine - if (Irp && (IoStatus->Status != STATUS_PENDING)) { + if (!NT_SUCCESS(FileLock->CompleteLockIrpRoutine(Context,Irp))) + { + //CompleteLockIrpRoutine complain: revert changes + FsRtlpUnlockSingle( FileLock, + FileObject, + FileOffset, + Length, + Process, + Key, + Context, + AlreadySynchronized, + FALSE//CallUnlockRoutine + ); + } + } + else + {//std irp completion + IofCompleteRequest(Irp, IO_NO_INCREMENT); + } + } + } - if (FileLock->CompleteLockIrpRoutine) { //complete irp routine - - if (!NT_SUCCESS(FileLock->CompleteLockIrpRoutine(Context,Irp))) { - //CompleteLockIrpRoutine complain: revert changes - FsRtlpUnlockSingle( FileLock, - FileObject, - FileOffset, - Length, - Process, - Key, - Context, - AlreadySynchronized, - FALSE//CallUnlockRoutine - ); - } - } - else {//std irp completion - IofCompleteRequest(Irp, IO_NO_INCREMENT); - } - } - - //NOTE: only fast io care about this return value - if (IoStatus->Status == STATUS_SUCCESS || FailImmediately) - return TRUE; - - return FALSE; + //NOTE: only fast io seems to care about this return value + return (IoStatus->Status == STATUS_SUCCESS || FailImmediately); } @@ -1010,78 +1067,83 @@ FsRtlPrivateLock ( NTSTATUS STDCALL FsRtlProcessFileLock ( - IN PFILE_LOCK FileLock, - IN PIRP Irp, - IN PVOID Context OPTIONAL - ) + IN PFILE_LOCK FileLock, + IN PIRP Irp, + IN PVOID Context OPTIONAL + ) { - PIO_STACK_LOCATION Stack; - NTSTATUS Status; - IO_STATUS_BLOCK LocalIoStatus; + PIO_STACK_LOCATION Stack; + NTSTATUS Status; + IO_STATUS_BLOCK LocalIoStatus; - assert(FileLock); - Stack = IoGetCurrentIrpStackLocation(Irp); + assert(FileLock); + Stack = IoGetCurrentIrpStackLocation(Irp); + Irp->IoStatus.Information = 0; - switch(Stack->MinorFunction){ + 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); - 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; - 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_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: - 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); - case IRP_MN_UNLOCK_ALL_BY_KEY: - Status = FsRtlFastUnlockAllByKey ( FileLock, - Stack->FileObject, - IoGetRequestorProcess(Irp), - Stack->Parameters.LockControl.Key, - Context); + break; - break; + default: + Irp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST; + IofCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; + } - default: - Irp->IoStatus.Status = Status = STATUS_INVALID_DEVICE_REQUEST; - IofCompleteRequest(Irp, IO_NO_INCREMENT); - return Status; - } + Irp->IoStatus.Status = Status; - Irp->IoStatus.Status = Status; + if (FileLock->CompleteLockIrpRoutine ) + { + FileLock->CompleteLockIrpRoutine(Context,Irp); + } + else + { + IofCompleteRequest(Irp,IO_NO_INCREMENT); + } - if (FileLock->CompleteLockIrpRoutine ) - FileLock->CompleteLockIrpRoutine(Context,Irp); - else - IofCompleteRequest(Irp,IO_NO_INCREMENT); - - return Status; + return Status; } @@ -1093,69 +1155,73 @@ FsRtlProcessFileLock ( VOID STDCALL FsRtlUninitializeFileLock ( - IN PFILE_LOCK FileLock - ) + IN PFILE_LOCK FileLock + ) { - PFILE_LOCK_TOC LockToc; - PFILE_LOCK_PENDING Pending; - PFILE_LOCK_GRANTED Granted; - PLIST_ENTRY EnumEntry; - KIRQL oldirql; + PFILE_LOCK_TOC LockToc; + PIRP Irp; + PFILE_LOCK_GRANTED Granted; + PLIST_ENTRY EnumEntry; + KIRQL oldirql; - assert(FileLock); - if (FileLock->LockInformation == NULL) - return; + assert(FileLock); + if (FileLock->LockInformation == NULL) + { + return; + } - LockToc = FileLock->LockInformation; + LockToc = FileLock->LockInformation; - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); - //unlock and free granted locks - EnumEntry = LockToc->GrantedListHead.Flink; - while (EnumEntry != &LockToc->GrantedListHead) { + //remove and free granted locks + while (!IsListEmpty(&LockToc->GrantedListHead)) + { + EnumEntry = RemoveTailList(&LockToc->GrantedListHead); + Granted = CONTAINING_RECORD(EnumEntry, FILE_LOCK_GRANTED, ListEntry); + ExFreeToNPagedLookasideList(&GrantedLookaside, Granted); + } - Granted = CONTAINING_RECORD(EnumEntry,FILE_LOCK_GRANTED, ListEntry); - EnumEntry = EnumEntry->Flink; + //remove, complete and free all pending locks + while (!IsListEmpty(&LockToc->PendingListHead)) + { + EnumEntry = RemoveTailList(&LockToc->PendingListHead); + Irp = CONTAINING_RECORD(EnumEntry, IRP, Tail.Overlay.ListEntry); - RemoveEntryList(&Granted->ListEntry); - ExFreeToNPagedLookasideList(&GrantedLookaside,Granted); - } - - //complete pending locks - EnumEntry = LockToc->PendingListHead.Flink; - while (EnumEntry != &LockToc->PendingListHead) { + 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); + } + else + { + /* + Cancel routine will NOT be called, even though the irp might have been canceled. + Don't care since we'l complete it faster than the cancel routine would have. + */ + KeReleaseSpinLock(&LockToc->SpinLock, oldirql);//fires cancel routine - Pending = CONTAINING_RECORD(EnumEntry,FILE_LOCK_PENDING, ListEntry); - RemoveEntryList(&Pending->ListEntry); + Irp->IoStatus.Status = STATUS_RANGE_NOT_LOCKED; + + if (FileLock->CompleteLockIrpRoutine) + { + FileLock->CompleteLockIrpRoutine(Irp->Tail.Overlay.DriverContext[2], Irp); + } + else + { + IofCompleteRequest(Irp, IO_NO_INCREMENT); + } - IoSetCancelRoutine(Pending->Irp, NULL); - /* - Irp could be cancelled and the cancel routine may or may not have been called, - waiting there for our spinlock. - But it doesn't matter because it will not find the IRP in the list. - */ - KeReleaseSpinLock(&LockToc->SpinLock, oldirql);//fires cancel routine + KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); + } + } - Pending->Irp->IoStatus.Status = STATUS_RANGE_NOT_LOCKED; + KeReleaseSpinLock(&LockToc->SpinLock, oldirql); - if (FileLock->CompleteLockIrpRoutine) - FileLock->CompleteLockIrpRoutine(Pending->Context,Pending->Irp); - else - IofCompleteRequest(Pending->Irp, IO_NO_INCREMENT); + ExFreeToNPagedLookasideList(&LockTocLookaside, LockToc); - ExFreeToNPagedLookasideList(&PendingLookaside,Pending); - - KeAcquireSpinLock(&LockToc->SpinLock, &oldirql); - //restart, something migth have happend to our list - EnumEntry = LockToc->PendingListHead.Flink; - } - - KeReleaseSpinLock(&LockToc->SpinLock, oldirql) ; - - FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; - FileLock->LockInformation = NULL; - - ExFreeToNPagedLookasideList(&LockTocLookaside, LockToc); + FsRtlAreThereCurrentFileLocks(FileLock) = FALSE; + FileLock->LockInformation = NULL; } @@ -1171,21 +1237,21 @@ FsRtlUninitializeFileLock ( */ PFILE_LOCK STDCALL -FsRtlAllocateFileLock ( - IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL, - IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL - ) +FsRtlAllocateFileLock( + IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL, + IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL + ) { - PFILE_LOCK FileLock; + PFILE_LOCK FileLock; - FileLock = ExAllocatePoolWithTag(PagedPool,sizeof(FILE_LOCK),IFS_POOL_TAG); + FileLock = ExAllocateFromPagedLookasideList(&LockLookaside); - FsRtlInitializeFileLock( FileLock, - CompleteLockIrpRoutine, - UnlockRoutine - ); + FsRtlInitializeFileLock(FileLock, + CompleteLockIrpRoutine, + UnlockRoutine + ); - return FileLock; + return FileLock; } /********************************************************************** @@ -1200,12 +1266,13 @@ FsRtlAllocateFileLock ( VOID STDCALL FsRtlFreeFileLock( - IN PFILE_LOCK FileLock - ) + IN PFILE_LOCK FileLock + ) { - assert(FileLock); - FsRtlUninitializeFileLock(FileLock); - ExFreePool(FileLock); + assert(FileLock); + + FsRtlUninitializeFileLock(FileLock); + ExFreeToPagedLookasideList(&LockLookaside, FileLock); } /* EOF */ diff --git a/reactos/ntoskrnl/include/internal/ifs.h b/reactos/ntoskrnl/include/internal/ifs.h index 6bb12dafe1f..134750c0b92 100644 --- a/reactos/ntoskrnl/include/internal/ifs.h +++ b/reactos/ntoskrnl/include/internal/ifs.h @@ -1,6 +1,6 @@ #ifndef __INCLUDE_INTERNAL_IFS_H #define __INCLUDE_INTERNAL_IFS_H -/* $Id: ifs.h,v 1.4 2002/11/13 06:01:11 robd Exp $ */ +/* $Id: ifs.h,v 1.5 2003/01/25 15:52:43 hbirr Exp $ */ #include @@ -11,12 +11,12 @@ VOID STDCALL FsRtlpInitFileLockingImplementation(VOID); VOID STDCALL -FsRtlpPendingFileLockCancelRoutine( +FsRtlpFileLockCancelRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); -BOOLEAN STDCALL +BOOLEAN FASTCALL FsRtlpCheckLockForReadOrWriteAccess( IN PFILE_LOCK FileLock, IN PLARGE_INTEGER FileOffset, @@ -27,7 +27,7 @@ FsRtlpCheckLockForReadOrWriteAccess( IN BOOLEAN Read ); -NTSTATUS STDCALL +NTSTATUS FASTCALL FsRtlpFastUnlockAllByKey( IN PFILE_LOCK FileLock, IN PFILE_OBJECT FileObject, @@ -37,7 +37,7 @@ FsRtlpFastUnlockAllByKey( IN PVOID Context OPTIONAL ); -NTSTATUS STDCALL +NTSTATUS FASTCALL FsRtlpAddLock( IN PFILE_LOCK_TOC LockToc, IN PFILE_OBJECT FileObject, @@ -48,14 +48,14 @@ FsRtlpAddLock( IN BOOLEAN ExclusiveLock ); -VOID STDCALL -FsRtlpTryCompletePendingLocks( +VOID FASTCALL +FsRtlpCompletePendingLocks( IN PFILE_LOCK FileLock, IN PFILE_LOCK_TOC LockToc, IN OUT PKIRQL oldirql ); -NTSTATUS STDCALL +NTSTATUS FASTCALL FsRtlpUnlockSingle( IN PFILE_LOCK FileLock, IN PFILE_OBJECT FileObject, @@ -68,7 +68,7 @@ FsRtlpUnlockSingle( IN BOOLEAN CallUnlockRoutine ); -VOID STDCALL +VOID FASTCALL FsRtlpDumpFileLocks( IN PFILE_LOCK FileLock );