Author: arty Date: Sat Mar 10 07:28:03 2012 New Revision: 56098
URL: http://svn.reactos.org/svn/reactos?rev=56098&view=rev Log: [FSRTL] Handle cases where multiple ranges overlap a new lock, including either exclusive or shared ranges. We expand a shared range when an overlap occurs and add another shared range to the shared ranges list. Also make sure to complete an IRP along every non-pending case. Reduces failures in kernel32_winetest except an expected successful unlock of ~0,1, which appears to contravene the documentation.
Modified: trunk/reactos/ntoskrnl/fsrtl/filelock.c
Modified: trunk/reactos/ntoskrnl/fsrtl/filelock.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/fsrtl/filelock.c?r... ============================================================================== --- trunk/reactos/ntoskrnl/fsrtl/filelock.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/fsrtl/filelock.c [iso-8859-1] Sat Mar 10 07:28:03 2012 @@ -9,7 +9,7 @@ /* INCLUDES ******************************************************************/
#include <ntoskrnl.h> -//#define NDEBUG +#define NDEBUG #include <debug.h>
/* GLOBALS *******************************************************************/ @@ -28,17 +28,27 @@ }; FILE_EXCLUSIVE_LOCK_ENTRY Exclusive; } -COMBINED_LOCK_ELEMENT, *PCOMBINED_LOCK_ELEMENT; + COMBINED_LOCK_ELEMENT, *PCOMBINED_LOCK_ELEMENT;
typedef struct _LOCK_INFORMATION { - RTL_GENERIC_TABLE RangeTable; - IO_CSQ Csq; - KSPIN_LOCK CsqLock; + RTL_GENERIC_TABLE RangeTable; + IO_CSQ Csq; + KSPIN_LOCK CsqLock; LIST_ENTRY CsqList; - PFILE_LOCK BelongsTo; -} -LOCK_INFORMATION, *PLOCK_INFORMATION; + PFILE_LOCK BelongsTo; + LIST_ENTRY SharedLocks; +} + LOCK_INFORMATION, *PLOCK_INFORMATION; + +typedef struct _LOCK_SHARED_RANGE +{ + LIST_ENTRY Entry; + LARGE_INTEGER Start, End; + ULONG Key; + PVOID ProcessId; +} + LOCK_SHARED_RANGE, *PLOCK_SHARED_RANGE;
/* PRIVATE FUNCTIONS *********************************************************/
@@ -72,13 +82,27 @@ { PCOMBINED_LOCK_ELEMENT A = PtrA, B = PtrB; RTL_GENERIC_COMPARE_RESULTS Result; - DPRINT("Starting to compare element %x to element %x\n", PtrA, PtrB); +#if 0 + DPRINT("Starting to compare element %x to element %x\n", PtrA, PtrB); +#endif + /* Match if we overlap */ + if (((A->Exclusive.FileLock.StartingByte.QuadPart < + B->Exclusive.FileLock.EndingByte.QuadPart) && + (A->Exclusive.FileLock.StartingByte.QuadPart >= + B->Exclusive.FileLock.StartingByte.QuadPart)) || + ((B->Exclusive.FileLock.StartingByte.QuadPart < + A->Exclusive.FileLock.EndingByte.QuadPart) && + (B->Exclusive.FileLock.StartingByte.QuadPart >= + A->Exclusive.FileLock.StartingByte.QuadPart))) + return GenericEqual; + /* Otherwise, key on the starting byte */ Result = (A->Exclusive.FileLock.StartingByte.QuadPart < B->Exclusive.FileLock.StartingByte.QuadPart) ? GenericLessThan : (A->Exclusive.FileLock.StartingByte.QuadPart > B->Exclusive.FileLock.StartingByte.QuadPart) ? GenericGreaterThan : GenericEqual; +#if 0 DPRINT("Compare(%x:%x) %x-%x to %x-%x => %d\n", A,B, A->Exclusive.FileLock.StartingByte.LowPart, @@ -86,6 +110,7 @@ B->Exclusive.FileLock.StartingByte.LowPart, B->Exclusive.FileLock.EndingByte.LowPart, Result); +#endif return Result; }
@@ -115,24 +140,24 @@ PCOMBINED_LOCK_ELEMENT WhereUnlock = PeekContext; PLOCK_INFORMATION LockInfo = CONTAINING_RECORD(Csq, LOCK_INFORMATION, Csq); PLIST_ENTRY Following; + DPRINT("PeekNextIrp(IRP %p, Context %p)\n", Irp, PeekContext); if (!Irp) { - Irp = CONTAINING_RECORD - (LockInfo->CsqList.Flink, - IRP, - Tail.Overlay.ListEntry); - Following = &Irp->Tail.Overlay.ListEntry; + Following = LockInfo->CsqList.Flink; } else Following = Irp->Tail.Overlay.ListEntry.Flink; - + + DPRINT("ListEntry %p Head %p\n", Following, &LockInfo->CsqList); for (; Following != &LockInfo->CsqList; Following = Following->Flink) { - PIRP Irp = CONTAINING_RECORD(Following, IRP, Tail.Overlay.ListEntry); - PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); + PIO_STACK_LOCATION IoStack; BOOLEAN Matching; + Irp = CONTAINING_RECORD(Following, IRP, Tail.Overlay.ListEntry); + DPRINT("Irp %p\n", Irp); + IoStack = IoGetCurrentIrpStackLocation(Irp); LockElement.Exclusive.FileLock.StartingByte = IoStack->Parameters.LockControl.ByteOffset; LockElement.Exclusive.FileLock.EndingByte.QuadPart = @@ -147,15 +172,16 @@ /* Else get any completable IRP */ else { - Matching = !!RtlLookupElementGenericTable - (&LockInfo->RangeTable, &LockElement); + Matching = FALSE; } if (!Matching) { // This IRP is fine... + DPRINT("Returning the IRP %p\n", Irp); return Irp; } } + DPRINT("Return NULL\n"); return NULL; }
@@ -178,6 +204,7 @@ { NTSTATUS Status; PLOCK_INFORMATION LockInfo = CONTAINING_RECORD(Csq, LOCK_INFORMATION, Csq); + DPRINT("Complete cancelled IRP %p Status %x\n", Irp, STATUS_CANCELLED); FsRtlCompleteLockIrpReal (LockInfo->BelongsTo->CompleteLockIrpRoutine, NULL, @@ -201,14 +228,16 @@ { /* Check if we have a file object */ if (FileObject) FileObject->LastLock = NULL; - + /* Set the I/O Status and do completion */ Irp->IoStatus.Status = Status; + DPRINT("Calling completion routine %p Status %x\n", Irp, Status); *NewStatus = CompleteRoutine(Context, Irp); } else { /* Otherwise do a normal I/O complete request */ + DPRINT("Completing IRP %p Status %x\n", Irp, Status); FsRtlCompleteRequest(Irp, Status); *NewStatus = Status; } @@ -229,6 +258,58 @@ Entry = RtlEnumerateGenericTable(FileLock->LockInformation, Restart); if (!Entry) return NULL; else return &Entry->Exclusive.FileLock; +} + +/* This function expands the conflicting range Conflict by removing and reinserting it, + then adds a shared range of the same size */ +PCOMBINED_LOCK_ELEMENT +NTAPI +FsRtlpSubsumeSharedLock +(PFILE_LOCK FileLock, + PLOCK_INFORMATION LockInfo, + PCOMBINED_LOCK_ELEMENT ToInsert, + PCOMBINED_LOCK_ELEMENT Conflict) +{ + BOOLEAN InsertedNew = FALSE, RemovedOld; + COMBINED_LOCK_ELEMENT NewElement; + PLOCK_SHARED_RANGE SharedRange = + ExAllocatePoolWithTag(NonPagedPool, sizeof(*SharedRange), 'FSRA'); + + if (!SharedRange) + return NULL; + + ASSERT(!Conflict->Exclusive.FileLock.ExclusiveLock); + ASSERT(!ToInsert->Exclusive.FileLock.ExclusiveLock); + SharedRange->Start = ToInsert->Exclusive.FileLock.StartingByte; + SharedRange->End = ToInsert->Exclusive.FileLock.EndingByte; + SharedRange->Key = ToInsert->Exclusive.FileLock.Key; + SharedRange->ProcessId = ToInsert->Exclusive.FileLock.ProcessId; + InsertTailList(&LockInfo->SharedLocks, &SharedRange->Entry); + + NewElement = *Conflict; + if (ToInsert->Exclusive.FileLock.StartingByte.QuadPart > + Conflict->Exclusive.FileLock.StartingByte.QuadPart) + { + NewElement.Exclusive.FileLock.StartingByte = + Conflict->Exclusive.FileLock.StartingByte; + } + if (ToInsert->Exclusive.FileLock.EndingByte.QuadPart < + Conflict->Exclusive.FileLock.EndingByte.QuadPart) + { + NewElement.Exclusive.FileLock.EndingByte = + Conflict->Exclusive.FileLock.EndingByte; + } + RemovedOld = RtlDeleteElementGenericTable + (&LockInfo->RangeTable, + Conflict); + ASSERT(RemovedOld); + Conflict = RtlInsertElementGenericTable + (&LockInfo->RangeTable, + ToInsert, + sizeof(*ToInsert), + &InsertedNew); + ASSERT(InsertedNew && Conflict); + return Conflict; }
/* @@ -254,32 +335,59 @@ PCOMBINED_LOCK_ELEMENT Conflict; PLOCK_INFORMATION LockInfo; BOOLEAN InsertedNew; - - DPRINT1("FsRtlPrivateLock() is stubplemented!\n"); - /* Windows 2003 ignores that parameter - ASSERT(AlreadySynchronized); - */ - + + DPRINT("FsRtlPrivateLock(%wZ, Offset %08x%08x, Length %08x%08x, Key %x, FailImmediately %d, Exclusive %d)\n", + &FileObject->FileName, + FileOffset->HighPart, + FileOffset->LowPart, + Length->HighPart, + Length->LowPart, + Key, + FailImmediately, + ExclusiveLock); + + if (FileOffset->QuadPart < 0ll || + FileOffset->QuadPart + Length->QuadPart < FileOffset->QuadPart) + { + DPRINT("File offset out of range\n"); + IoStatus->Status = STATUS_INVALID_PARAMETER; + if (Irp) + { + DPRINT("Complete lock %p Status %x\n", Irp, IoStatus->Status); + FsRtlCompleteLockIrpReal + (FileLock->CompleteLockIrpRoutine, + Context, + Irp, + IoStatus->Status, + &Status, + FileObject); + } + return FALSE; + } + /* Initialize the lock, if necessary */ if (!FileLock->LockInformation) { LockInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(LOCK_INFORMATION), 'FLCK'); FileLock->LockInformation = LockInfo; - if (!FileLock) + if (!FileLock) { + IoStatus->Status = STATUS_NO_MEMORY; return FALSE; - + } + LockInfo->BelongsTo = FileLock; - + InitializeListHead(&LockInfo->SharedLocks); + RtlInitializeGenericTable (&LockInfo->RangeTable, LockCompare, LockAllocate, LockFree, NULL); - + KeInitializeSpinLock(&LockInfo->CsqLock); InitializeListHead(&LockInfo->CsqList); - + IoCsqInitializeEx (&LockInfo->Csq, LockInsertIrpEx, @@ -289,7 +397,7 @@ LockReleaseQueueLock, LockCompleteCanceledIrp); } - + LockInfo = FileLock->LockInformation; ToInsert.Exclusive.FileLock.FileObject = FileObject; ToInsert.Exclusive.FileLock.StartingByte = *FileOffset; @@ -297,13 +405,13 @@ ToInsert.Exclusive.FileLock.ProcessId = Process->UniqueProcessId; ToInsert.Exclusive.FileLock.Key = Key; ToInsert.Exclusive.FileLock.ExclusiveLock = ExclusiveLock; - + Conflict = RtlInsertElementGenericTable (FileLock->LockInformation, &ToInsert, sizeof(ToInsert), &InsertedNew); - + if (Conflict && !InsertedNew) { if (Conflict->Exclusive.FileLock.ExclusiveLock || ExclusiveLock) @@ -340,18 +448,112 @@ } else { - IoStatus->Status = STATUS_SUCCESS; - if (Irp) + ULONG i; + /* We know of at least one lock in range that's shared. We need to + * find out if any more exist and any are exclusive. */ + for (i = 0; i < RtlNumberGenericTableElements(&LockInfo->RangeTable); i++) + { + Conflict = RtlGetElementGenericTable(&LockInfo->RangeTable, i); + /* The first argument will be inserted as a shared range */ + if (LockCompare(&LockInfo->RangeTable, Conflict, &ToInsert) == GenericEqual) + { + if (Conflict->Exclusive.FileLock.ExclusiveLock) + { + /* Found an exclusive match */ + if (FailImmediately) + { + IoStatus->Status = STATUS_FILE_LOCK_CONFLICT; + if (Irp) + { + FsRtlCompleteLockIrpReal + (FileLock->CompleteLockIrpRoutine, + Context, + Irp, + IoStatus->Status, + &Status, + FileObject); + } + } + else + { + IoStatus->Status = STATUS_PENDING; + if (Irp) + { + IoMarkIrpPending(Irp); + IoCsqInsertIrpEx + (&LockInfo->Csq, + Irp, + NULL, + NULL); + } + } + return FALSE; + } + else + { + /* We've made all overlapping shared ranges into one big range + * now we need to add a range entry for the new range */ + DPRINT("Overlapping shared lock %wZ %08x%08x %08x%08x\n", + &FileObject->FileName, + Conflict->Exclusive.FileLock.StartingByte.HighPart, + Conflict->Exclusive.FileLock.StartingByte.LowPart, + Conflict->Exclusive.FileLock.EndingByte.HighPart, + Conflict->Exclusive.FileLock.EndingByte.LowPart); + Conflict = FsRtlpSubsumeSharedLock + (FileLock, LockInfo, &ToInsert, Conflict); + if (!Conflict) + { + IoStatus->Status = STATUS_NO_MEMORY; + if (Irp) + { + FsRtlCompleteLockIrpReal + (FileLock->CompleteLockIrpRoutine, + Context, + Irp, + IoStatus->Status, + &Status, + FileObject); + } + return FALSE; + } + } + } + } + + /* We got here because there were only overlapping shared locks */ + DPRINT("Acquired shared lock %wZ %08x%08x %08x%08x\n", + &FileObject->FileName, + Conflict->Exclusive.FileLock.StartingByte.HighPart, + Conflict->Exclusive.FileLock.StartingByte.LowPart, + Conflict->Exclusive.FileLock.EndingByte.HighPart, + Conflict->Exclusive.FileLock.EndingByte.LowPart); + if (!FsRtlpSubsumeSharedLock(FileLock, LockInfo, &ToInsert, Conflict)) { - FsRtlCompleteLockIrpReal - (FileLock->CompleteLockIrpRoutine, - Context, - Irp, - IoStatus->Status, - &Status, - FileObject); + IoStatus->Status = STATUS_NO_MEMORY; + if (Irp) + { + FsRtlCompleteLockIrpReal + (FileLock->CompleteLockIrpRoutine, + Context, + Irp, + IoStatus->Status, + &Status, + FileObject); + } + return FALSE; } - return FALSE; + IoStatus->Status = STATUS_SUCCESS; + if (Irp) + { + FsRtlCompleteLockIrpReal + (FileLock->CompleteLockIrpRoutine, + Context, + Irp, + IoStatus->Status, + &Status, + FileObject); + } + return TRUE; } } else if (!Conflict) @@ -359,13 +561,58 @@ /* Conflict here is (or would be) the newly inserted element, but we ran * out of space probably. */ IoStatus->Status = STATUS_NO_MEMORY; + if (Irp) + { + FsRtlCompleteLockIrpReal + (FileLock->CompleteLockIrpRoutine, + Context, + Irp, + IoStatus->Status, + &Status, + FileObject); + } return FALSE; } else { + DPRINT("Inserted new lock %wZ %08x%08x %08x%08x exclusive %d\n", + &FileObject->FileName, + Conflict->Exclusive.FileLock.StartingByte.HighPart, + Conflict->Exclusive.FileLock.StartingByte.LowPart, + Conflict->Exclusive.FileLock.StartingByte.HighPart, + Conflict->Exclusive.FileLock.StartingByte.LowPart, + Conflict->Exclusive.FileLock.ExclusiveLock); + if (!ExclusiveLock) + { + PLOCK_SHARED_RANGE NewSharedRange; + NewSharedRange = + ExAllocatePoolWithTag(NonPagedPool, sizeof(*NewSharedRange), 'FSRA'); + if (!NewSharedRange) + { + IoStatus->Status = STATUS_NO_MEMORY; + if (Irp) + { + FsRtlCompleteLockIrpReal + (FileLock->CompleteLockIrpRoutine, + Context, + Irp, + IoStatus->Status, + &Status, + FileObject); + } + return FALSE; + } + DPRINT("Adding shared lock %wZ\n", &FileObject->FileName); + NewSharedRange->Start = ToInsert.Exclusive.FileLock.StartingByte; + NewSharedRange->End = ToInsert.Exclusive.FileLock.EndingByte; + NewSharedRange->Key = Key; + NewSharedRange->ProcessId = ToInsert.Exclusive.FileLock.ProcessId; + InsertTailList(&LockInfo->SharedLocks, &NewSharedRange->Entry); + } + /* Assume all is cool, and lock is set */ IoStatus->Status = STATUS_SUCCESS; - + if (Irp) { /* Complete the request */ @@ -375,12 +622,12 @@ IoStatus->Status, &Status, FileObject); - + /* Update the status */ IoStatus->Status = Status; } } - + return TRUE; }
@@ -392,10 +639,19 @@ FsRtlCheckLockForReadAccess(IN PFILE_LOCK FileLock, IN PIRP Irp) { + BOOLEAN Result; PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); COMBINED_LOCK_ELEMENT ToFind; PCOMBINED_LOCK_ELEMENT Found; - if (!FileLock->LockInformation) return TRUE; + DPRINT("CheckLockForReadAccess(%wZ, Offset %08x%08x, Length %x)\n", + &IoStack->FileObject->FileName, + IoStack->Parameters.Read.ByteOffset.HighPart, + IoStack->Parameters.Read.ByteOffset.LowPart, + IoStack->Parameters.Read.Length); + if (!FileLock->LockInformation) { + DPRINT("CheckLockForReadAccess(%wZ) => TRUE\n", &IoStack->FileObject->FileName); + return TRUE; + } ToFind.Exclusive.FileLock.StartingByte = IoStack->Parameters.Read.ByteOffset; ToFind.Exclusive.FileLock.EndingByte.QuadPart = ToFind.Exclusive.FileLock.StartingByte.QuadPart + @@ -403,9 +659,14 @@ Found = RtlLookupElementGenericTable (FileLock->LockInformation, &ToFind); - if (!Found) return TRUE; - return !Found->Exclusive.FileLock.ExclusiveLock || + if (!Found) { + DPRINT("CheckLockForReadAccess(%wZ) => TRUE\n", &IoStack->FileObject->FileName); + return TRUE; + } + Result = !Found->Exclusive.FileLock.ExclusiveLock || IoStack->Parameters.Read.Key == Found->Exclusive.FileLock.Key; + DPRINT("CheckLockForReadAccess(%wZ) => %s\n", &IoStack->FileObject->FileName, Result ? "TRUE" : "FALSE"); + return Result; }
/* @@ -416,11 +677,20 @@ FsRtlCheckLockForWriteAccess(IN PFILE_LOCK FileLock, IN PIRP Irp) { + BOOLEAN Result; PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); COMBINED_LOCK_ELEMENT ToFind; PCOMBINED_LOCK_ELEMENT Found; PEPROCESS Process = Irp->Tail.Overlay.Thread->ThreadsProcess; - if (!FileLock->LockInformation) return TRUE; + DPRINT("CheckLockForWriteAccess(%wZ, Offset %08x%08x, Length %x)\n", + &IoStack->FileObject->FileName, + IoStack->Parameters.Write.ByteOffset.HighPart, + IoStack->Parameters.Write.ByteOffset.LowPart, + IoStack->Parameters.Write.Length); + if (!FileLock->LockInformation) { + DPRINT("CheckLockForWriteAccess(%wZ) => TRUE\n", &IoStack->FileObject->FileName); + return TRUE; + } ToFind.Exclusive.FileLock.StartingByte = IoStack->Parameters.Write.ByteOffset; ToFind.Exclusive.FileLock.EndingByte.QuadPart = ToFind.Exclusive.FileLock.StartingByte.QuadPart + @@ -428,8 +698,13 @@ Found = RtlLookupElementGenericTable (FileLock->LockInformation, &ToFind); - if (!Found) return TRUE; - return Process->UniqueProcessId == Found->Exclusive.FileLock.ProcessId; + if (!Found) { + DPRINT("CheckLockForWriteAccess(%wZ) => TRUE\n", &IoStack->FileObject->FileName); + return TRUE; + } + Result = Process->UniqueProcessId == Found->Exclusive.FileLock.ProcessId; + DPRINT("CheckLockForWriteAccess(%wZ) => %s\n", &IoStack->FileObject->FileName, Result ? "TRUE" : "FALSE"); + return Result; }
/* @@ -447,6 +722,13 @@ PEPROCESS EProcess = Process; COMBINED_LOCK_ELEMENT ToFind; PCOMBINED_LOCK_ELEMENT Found; + DPRINT("FsRtlFastCheckLockForRead(%wZ, Offset %08x%08x, Length %08x%08x, Key %x)\n", + &FileObject->FileName, + FileOffset->HighPart, + FileOffset->LowPart, + Length->HighPart, + Length->LowPart, + Key); ToFind.Exclusive.FileLock.StartingByte = *FileOffset; ToFind.Exclusive.FileLock.EndingByte.QuadPart = FileOffset->QuadPart + Length->QuadPart; @@ -471,19 +753,35 @@ IN PFILE_OBJECT FileObject, IN PVOID Process) { + BOOLEAN Result; PEPROCESS EProcess = Process; COMBINED_LOCK_ELEMENT ToFind; PCOMBINED_LOCK_ELEMENT Found; + DPRINT("FsRtlFastCheckLockForWrite(%wZ, Offset %08x%08x, Length %08x%08x, Key %x)\n", + &FileObject->FileName, + FileOffset->HighPart, + FileOffset->LowPart, + Length->HighPart, + Length->LowPart, + Key); ToFind.Exclusive.FileLock.StartingByte = *FileOffset; ToFind.Exclusive.FileLock.EndingByte.QuadPart = FileOffset->QuadPart + Length->QuadPart; - if (!FileLock->LockInformation) return TRUE; + if (!FileLock->LockInformation) { + DPRINT("CheckForWrite(%wZ) => TRUE\n", &FileObject->FileName); + return TRUE; + } Found = RtlLookupElementGenericTable (FileLock->LockInformation, &ToFind); - if (!Found) return TRUE; - return Found->Exclusive.FileLock.Key == Key && + if (!Found) { + DPRINT("CheckForWrite(%wZ) => TRUE\n", &FileObject->FileName); + return TRUE; + } + Result = Found->Exclusive.FileLock.Key == Key && Found->Exclusive.FileLock.ProcessId == EProcess->UniqueProcessId; + DPRINT("CheckForWrite(%wZ) => %s\n", &FileObject->FileName, Result ? "TRUE" : "FALSE"); + return Result; }
/* @@ -500,10 +798,20 @@ IN PVOID Context OPTIONAL, IN BOOLEAN AlreadySynchronized) { + BOOLEAN FoundShared = FALSE; + PLIST_ENTRY SharedEntry; + PLOCK_SHARED_RANGE SharedRange = NULL; COMBINED_LOCK_ELEMENT Find; PCOMBINED_LOCK_ELEMENT Entry; PIRP NextMatchingLockIrp; PLOCK_INFORMATION InternalInfo = FileLock->LockInformation; + DPRINT("FsRtlFastUnlockSingle(%wZ, Offset %08x%08x, Length %08x%08x, Key %x)\n", + &FileObject->FileName, + FileOffset->HighPart, + FileOffset->LowPart, + Length->HighPart, + Length->LowPart, + Key); // The region to unlock must correspond exactly to a previously locked region // -- msdn // But Windows 2003 doesn't assert on it and simply ignores that parameter @@ -512,26 +820,101 @@ Find.Exclusive.FileLock.EndingByte.QuadPart = FileOffset->QuadPart + Length->QuadPart; Entry = RtlLookupElementGenericTable(&InternalInfo->RangeTable, &Find); - if (!Entry) return STATUS_RANGE_NOT_LOCKED; - if (Entry->Exclusive.FileLock.Key != Key || - Entry->Exclusive.FileLock.ProcessId != Process->UniqueProcessId) - return STATUS_RANGE_NOT_LOCKED; - if (Entry->Exclusive.FileLock.StartingByte.QuadPart != FileOffset->QuadPart || - Entry->Exclusive.FileLock.EndingByte.QuadPart != - FileOffset->QuadPart + Length->QuadPart) - return STATUS_RANGE_NOT_LOCKED; + if (!Entry) { + DPRINT("Range not locked %wZ\n", &FileObject->FileName); + return STATUS_RANGE_NOT_LOCKED; + } + + if (Entry->Exclusive.FileLock.ExclusiveLock) + { + if (Entry->Exclusive.FileLock.Key != Key || + Entry->Exclusive.FileLock.ProcessId != Process->UniqueProcessId || + Entry->Exclusive.FileLock.StartingByte.QuadPart != FileOffset->QuadPart || + Entry->Exclusive.FileLock.EndingByte.QuadPart != + FileOffset->QuadPart + Length->QuadPart) + { + DPRINT("Range not locked %wZ\n", &FileObject->FileName); + return STATUS_RANGE_NOT_LOCKED; + } + RtlCopyMemory(&Find, Entry, sizeof(Find)); + } + else + { + DPRINT("Shared lock %wZ Start %08x%08x End %08x%08x\n", + &FileObject->FileName, + Entry->Exclusive.FileLock.StartingByte.HighPart, + Entry->Exclusive.FileLock.StartingByte.LowPart, + Entry->Exclusive.FileLock.EndingByte.HighPart, + Entry->Exclusive.FileLock.EndingByte.LowPart); + for (SharedEntry = InternalInfo->SharedLocks.Flink; + SharedEntry != &InternalInfo->SharedLocks; + SharedEntry = SharedEntry->Flink) + { + SharedRange = CONTAINING_RECORD(SharedEntry, LOCK_SHARED_RANGE, Entry); + if (SharedRange->Start.QuadPart == FileOffset->QuadPart && + SharedRange->End.QuadPart == FileOffset->QuadPart + Length->QuadPart && + SharedRange->Key == Key && + SharedRange->ProcessId == Process->UniqueProcessId) + { + FoundShared = TRUE; + DPRINT("Found shared element to delete %wZ Start %08x%08x End %08x%08x Key %x\n", + &FileObject->FileName, + SharedRange->Start.HighPart, + SharedRange->Start.LowPart, + SharedRange->End.HighPart, + SharedRange->End.LowPart, + SharedRange->Key); + break; + } + } + if (FoundShared) + { + Find.Exclusive.FileLock.StartingByte = SharedRange->Start; + Find.Exclusive.FileLock.EndingByte = SharedRange->End; + SharedEntry = SharedRange->Entry.Flink; + RemoveEntryList(&SharedRange->Entry); + ExFreePool(SharedRange); + } + else + { + return STATUS_RANGE_NOT_LOCKED; + } + } + + if (IsListEmpty(&InternalInfo->SharedLocks)) { + DPRINT("Removing the lock entry %wZ\n", &FileObject->FileName); + RtlDeleteElementGenericTable(&InternalInfo->RangeTable, Entry); + } else { + DPRINT("Lock still has:\n"); + for (SharedEntry = InternalInfo->SharedLocks.Flink; + SharedEntry != &InternalInfo->SharedLocks; + SharedEntry = SharedEntry->Flink) + { + SharedRange = CONTAINING_RECORD(SharedEntry, LOCK_SHARED_RANGE, Entry); + DPRINT("Shared element %wZ Offset %08x%08x Length %08x%08x Key %x\n", + &FileObject->FileName, + SharedRange->Start.HighPart, + SharedRange->Start.LowPart, + SharedRange->End.HighPart, + SharedRange->End.LowPart, + SharedRange->Key); + } + } + // this is definitely the thing we want - RtlCopyMemory(&Find, Entry, sizeof(Find)); - NextMatchingLockIrp = IoCsqRemoveNextIrp(&InternalInfo->Csq, &Find); - RtlDeleteElementGenericTable(&InternalInfo->RangeTable, Entry); - while (NextMatchingLockIrp) - { - // Got a new lock irp... try to do the new lock operation - // Note that we pick an operation that would succeed at the time - // we looked, but can't guarantee that it won't just be re-queued - // because somebody else snatched part of the range in a new thread. - FsRtlProcessFileLock(InternalInfo->BelongsTo, NextMatchingLockIrp, NULL); - } + NextMatchingLockIrp = IoCsqRemoveNextIrp(&InternalInfo->Csq, &Find); + while (NextMatchingLockIrp) + { + // Got a new lock irp... try to do the new lock operation + // Note that we pick an operation that would succeed at the time + // we looked, but can't guarantee that it won't just be re-queued + // because somebody else snatched part of the range in a new thread. + DPRINT("Locking another IRP %p for %p %wZ\n", + &FileObject->FileName, FileLock, NextMatchingLockIrp); + FsRtlProcessFileLock(InternalInfo->BelongsTo, NextMatchingLockIrp, NULL); + } + + DPRINT("Success %wZ\n", &FileObject->FileName); return STATUS_SUCCESS; }
@@ -547,11 +930,14 @@ { PCOMBINED_LOCK_ELEMENT Entry; PRTL_GENERIC_TABLE InternalInfo = FileLock->LockInformation; - + DPRINT("FsRtlFastUnlockAll(%wZ)\n", &FileObject->FileName); // XXX Synchronize somehow - if (!FileLock->LockInformation) return STATUS_RANGE_NOT_LOCKED; // no locks + if (!FileLock->LockInformation) { + DPRINT("Not locked %wZ\n", &FileObject->FileName); + return STATUS_RANGE_NOT_LOCKED; // no locks + } for (Entry = RtlEnumerateGenericTable(InternalInfo, TRUE); - Entry; + Entry; Entry = RtlEnumerateGenericTable(InternalInfo, FALSE)) { LARGE_INTEGER Length; @@ -569,7 +955,7 @@ Context, TRUE); } - + DPRINT("Done %wZ\n", &FileObject->FileName); return STATUS_SUCCESS; }
@@ -586,11 +972,13 @@ { PCOMBINED_LOCK_ELEMENT Entry; PLOCK_INFORMATION InternalInfo = FileLock->LockInformation; - + + DPRINT("FsRtlFastUnlockAllByKey(%wZ,Key %x)\n", &FileObject->FileName, Key); + // XXX Synchronize somehow if (!FileLock->LockInformation) return STATUS_RANGE_NOT_LOCKED; // no locks for (Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, TRUE); - Entry; + Entry; Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, FALSE)) { LARGE_INTEGER Length; @@ -612,7 +1000,7 @@ TRUE); } } - + return STATUS_SUCCESS; }
@@ -628,110 +1016,99 @@ 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; + + DPRINT("FsRtlProcessFileLock(%wZ, MinorFunction %x)\n", + &IoStackLocation->FileObject->FileName, + IoStackLocation->MinorFunction); + 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; - + 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); + return IoStatusBlock.Status; + /* 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; - + 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); + 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; - + case IRP_MN_UNLOCK_ALL: + + /* Do a fast unlock */ + IoStatusBlock.Status = FsRtlFastUnlockAll(FileLock, + IoStackLocation-> + FileObject, + IoGetRequestorProcess(Irp), + Context); + 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; - + case IRP_MN_UNLOCK_ALL_BY_KEY: + + /* Do it */ + IoStatusBlock.Status = + FsRtlFastUnlockAllByKey(FileLock, + IoStackLocation->FileObject, + IoGetRequestorProcess(Irp), + IoStackLocation->Parameters. + LockControl.Key, + Context); + break; + /* Invalid request */ - default: - - /* Complete it */ - FsRtlCompleteRequest(Irp, STATUS_INVALID_DEVICE_REQUEST); - IoStatusBlock.Status = STATUS_INVALID_DEVICE_REQUEST; - break; - } - + default: + + /* Complete it */ + FsRtlCompleteRequest(Irp, STATUS_INVALID_DEVICE_REQUEST); + IoStatusBlock.Status = STATUS_INVALID_DEVICE_REQUEST; + return STATUS_INVALID_DEVICE_REQUEST; + } + /* Return the status */ + DPRINT("Lock IRP %p %x\n", Irp, IoStatusBlock.Status); + FsRtlCompleteLockIrpReal + (FileLock->CompleteLockIrpRoutine, + Context, + Irp, + IoStatusBlock.Status, + &Status, + NULL); return IoStatusBlock.Status; }
@@ -764,7 +1141,17 @@ PIRP Irp; PLOCK_INFORMATION InternalInfo = FileLock->LockInformation; PCOMBINED_LOCK_ELEMENT Entry; + PLIST_ENTRY SharedEntry; + PLOCK_SHARED_RANGE SharedRange; // MSDN: this completes any remaining lock IRPs + for (SharedEntry = InternalInfo->SharedLocks.Flink; + SharedEntry != &InternalInfo->SharedLocks;) + { + SharedRange = CONTAINING_RECORD(SharedEntry, LOCK_SHARED_RANGE, Entry); + SharedEntry = SharedEntry->Flink; + RemoveEntryList(SharedEntry); + ExFreePool(SharedRange); + } while ((Entry = RtlGetElementGenericTable(&InternalInfo->RangeTable, 0)) != NULL) { RtlDeleteElementGenericTable(&InternalInfo->RangeTable, Entry); @@ -787,7 +1174,7 @@ IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL) { PFILE_LOCK FileLock; - + /* Try to allocate it */ FileLock = ExAllocateFromPagedLookasideList(&FsRtlFileLockLookasideList); if (FileLock) @@ -797,7 +1184,7 @@ CompleteLockIrpRoutine, UnlockRoutine); } - + /* Return the lock */ return FileLock; }