Index: ntoskrnl/fsrtl/filelock.c =================================================================== --- ntoskrnl/fsrtl/filelock.c (revision 56828) +++ ntoskrnl/fsrtl/filelock.c (working copy) @@ -9,7 +9,7 @@ /* INCLUDES ******************************************************************/ #include -#define NDEBUG +//#define NDEBUG #include /* GLOBALS *******************************************************************/ @@ -272,20 +272,7 @@ { 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) @@ -305,8 +292,8 @@ ASSERT(RemovedOld); Conflict = RtlInsertElementGenericTable (&LockInfo->RangeTable, - ToInsert, - sizeof(*ToInsert), + &NewElement, + sizeof(NewElement), &InsertedNew); ASSERT(InsertedNew && Conflict); return Conflict; @@ -336,18 +323,25 @@ PLOCK_INFORMATION LockInfo; BOOLEAN InsertedNew; - DPRINT("FsRtlPrivateLock(%wZ, Offset %08x%08x, Length %08x%08x, Key %x, FailImmediately %d, Exclusive %d)\n", + DPRINT("FsRtlPrivateLock(%wZ, Offset %08x%08x (%d), Length %08x%08x (%d), Key %x, FailImmediately %d, Exclusive %d)\n", &FileObject->FileName, FileOffset->HighPart, FileOffset->LowPart, + (int)FileOffset->QuadPart, Length->HighPart, Length->LowPart, + (int)Length->QuadPart, Key, FailImmediately, ExclusiveLock); - if (FileOffset->QuadPart < 0ll || - FileOffset->QuadPart + Length->QuadPart < FileOffset->QuadPart) + ULARGE_INTEGER UnsignedStart; + ULARGE_INTEGER UnsignedEnd; + + UnsignedStart.QuadPart = FileOffset->QuadPart; + UnsignedEnd.QuadPart = FileOffset->QuadPart + Length->QuadPart; + + if (UnsignedEnd.QuadPart < UnsignedStart.QuadPart) { DPRINT("File offset out of range\n"); IoStatus->Status = STATUS_INVALID_PARAMETER; @@ -416,11 +410,20 @@ { if (Conflict->Exclusive.FileLock.ExclusiveLock || ExclusiveLock) { + DPRINT("Conflict %08x%08x:%08x%08x Exc %d (Want Exc %d)\n", + Conflict->Exclusive.FileLock.StartingByte.HighPart, + Conflict->Exclusive.FileLock.StartingByte.LowPart, + Conflict->Exclusive.FileLock.EndingByte.HighPart, + Conflict->Exclusive.FileLock.EndingByte.LowPart, + Conflict->Exclusive.FileLock.ExclusiveLock, + ExclusiveLock); if (FailImmediately) { + DPRINT("STATUS_FILE_LOCK_CONFLICT\n"); IoStatus->Status = STATUS_FILE_LOCK_CONFLICT; if (Irp) { + DPRINT("STATUS_FILE_LOCK_CONFLICT: Complete\n"); FsRtlCompleteLockIrpReal (FileLock->CompleteLockIrpRoutine, Context, @@ -463,8 +466,10 @@ if (FailImmediately) { IoStatus->Status = STATUS_FILE_LOCK_CONFLICT; + DPRINT("STATUS_FILE_LOCK_CONFLICT\n"); if (Irp) { + DPRINT("STATUS_FILE_LOCK_CONFLICT: Complete\n"); FsRtlCompleteLockIrpReal (FileLock->CompleteLockIrpRoutine, Context, @@ -805,12 +810,14 @@ PCOMBINED_LOCK_ELEMENT Entry; PIRP NextMatchingLockIrp; PLOCK_INFORMATION InternalInfo = FileLock->LockInformation; - DPRINT("FsRtlFastUnlockSingle(%wZ, Offset %08x%08x, Length %08x%08x, Key %x)\n", + DPRINT("FsRtlFastUnlockSingle(%wZ, Offset %08x%08x (%d), Length %08x%08x (%d), Key %x)\n", &FileObject->FileName, FileOffset->HighPart, FileOffset->LowPart, + (int)FileOffset->QuadPart, Length->HighPart, Length->LowPart, + (int)Length->QuadPart, Key); // The region to unlock must correspond exactly to a previously locked region // -- msdn @@ -819,6 +826,7 @@ Find.Exclusive.FileLock.StartingByte = *FileOffset; Find.Exclusive.FileLock.EndingByte.QuadPart = FileOffset->QuadPart + Length->QuadPart; + ASSERT(InternalInfo); Entry = RtlLookupElementGenericTable(&InternalInfo->RangeTable, &Find); if (!Entry) { DPRINT("Range not locked %wZ\n", &FileObject->FileName); @@ -879,11 +887,77 @@ } if (FoundShared) { + BOOLEAN RemadeRange = FALSE; + PLIST_ENTRY SharedRangeEntry; + PLOCK_SHARED_RANGE WatchSharedRange; + COMBINED_LOCK_ELEMENT RemadeElement; + PCOMBINED_LOCK_ELEMENT RemadeElementInserted = NULL; Find.Exclusive.FileLock.StartingByte = SharedRange->Start; Find.Exclusive.FileLock.EndingByte = SharedRange->End; SharedEntry = SharedRange->Entry.Flink; RemoveEntryList(&SharedRange->Entry); ExFreePool(SharedRange); + /* We need to rebuild the list of shared ranges. */ + DPRINT("Removing the lock entry %wZ (%08x%08x:%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); + /* Copy */ + RemadeElement = *Entry; + RtlDeleteElementGenericTable(&InternalInfo->RangeTable, Entry); + /* Put shared locks back in place */ + for (SharedRangeEntry = InternalInfo->SharedLocks.Flink; + SharedRangeEntry != &InternalInfo->SharedLocks; + SharedRangeEntry = SharedRangeEntry->Flink) + { + COMBINED_LOCK_ELEMENT Find; + WatchSharedRange = CONTAINING_RECORD(SharedRangeEntry, LOCK_SHARED_RANGE, Entry); + Find.Exclusive.FileLock.StartingByte = WatchSharedRange->Start; + Find.Exclusive.FileLock.EndingByte = WatchSharedRange->End; + if (LockCompare(&InternalInfo->RangeTable, &RemadeElement, &Find) != GenericEqual) + { + DPRINT("Skipping range %08x%08x:%08x%08x\n", + Find.Exclusive.FileLock.StartingByte.HighPart, + Find.Exclusive.FileLock.StartingByte.LowPart, + Find.Exclusive.FileLock.EndingByte.HighPart, + Find.Exclusive.FileLock.EndingByte.LowPart); + continue; + } + if (!RemadeRange) + { + DPRINT("Re-creating range %08x%08x:%08x%08x\n", + Find.Exclusive.FileLock.StartingByte.HighPart, + Find.Exclusive.FileLock.StartingByte.LowPart, + Find.Exclusive.FileLock.EndingByte.HighPart, + Find.Exclusive.FileLock.EndingByte.LowPart); + RemadeElement.Exclusive.FileLock.StartingByte = WatchSharedRange->Start; + RemadeElement.Exclusive.FileLock.EndingByte = WatchSharedRange->End; + RemadeElementInserted = + RtlInsertElementGenericTable + (&InternalInfo->RangeTable, + &RemadeElement, + sizeof(RemadeElement), + &RemadeRange); + ASSERT(RemadeElementInserted); + ASSERT(RemadeRange); + } + else + { + DPRINT("Re-adding range %08x%08x:%08x%08x\n", + WatchSharedRange->Start.HighPart, + WatchSharedRange->Start.LowPart, + WatchSharedRange->End.HighPart, + WatchSharedRange->End.LowPart); + RemadeElementInserted = + FsRtlpSubsumeSharedLock + (FileLock, + InternalInfo, + RemadeElementInserted, + RemadeElementInserted); + } + } } else { @@ -891,29 +965,19 @@ } } - if (IsListEmpty(&InternalInfo->SharedLocks)) { - DPRINT("Removing the lock entry %wZ (%08x%08x:%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); - 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); - } + 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 @@ -943,17 +1007,37 @@ IN PEPROCESS Process, IN PVOID Context OPTIONAL) { + PLIST_ENTRY ListEntry; PCOMBINED_LOCK_ELEMENT Entry; - PRTL_GENERIC_TABLE InternalInfo = FileLock->LockInformation; + PLOCK_INFORMATION InternalInfo = FileLock->LockInformation; DPRINT("FsRtlFastUnlockAll(%wZ)\n", &FileObject->FileName); // XXX Synchronize somehow if (!FileLock->LockInformation) { DPRINT("Not locked %wZ\n", &FileObject->FileName); return STATUS_RANGE_NOT_LOCKED; // no locks } - for (Entry = RtlEnumerateGenericTable(InternalInfo, TRUE); + for (ListEntry = InternalInfo->SharedLocks.Flink; + ListEntry != &InternalInfo->SharedLocks;) + { + LARGE_INTEGER Length; + PLOCK_SHARED_RANGE Range = CONTAINING_RECORD(ListEntry, LOCK_SHARED_RANGE, Entry); + Length.QuadPart = Range->End.QuadPart - Range->Start.QuadPart; + ListEntry = ListEntry->Flink; + if (Range->ProcessId != Process->UniqueProcessId) + continue; + FsRtlFastUnlockSingle + (FileLock, + FileObject, + &Range->Start, + &Length, + Range->ProcessId, + Range->Key, + Context, + TRUE); + } + for (Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, TRUE); Entry; - Entry = RtlEnumerateGenericTable(InternalInfo, FALSE)) + Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, FALSE)) { LARGE_INTEGER Length; // We'll take the first one to be the list head, and free the others first... @@ -985,6 +1069,7 @@ IN ULONG Key, IN PVOID Context OPTIONAL) { + PLIST_ENTRY ListEntry; PCOMBINED_LOCK_ELEMENT Entry; PLOCK_INFORMATION InternalInfo = FileLock->LockInformation; @@ -992,6 +1077,26 @@ // XXX Synchronize somehow if (!FileLock->LockInformation) return STATUS_RANGE_NOT_LOCKED; // no locks + for (ListEntry = InternalInfo->SharedLocks.Flink; + ListEntry != &InternalInfo->SharedLocks;) + { + PLOCK_SHARED_RANGE Range = CONTAINING_RECORD(ListEntry, LOCK_SHARED_RANGE, Entry); + LARGE_INTEGER Length; + Length.QuadPart = Range->End.QuadPart - Range->Start.QuadPart; + ListEntry = ListEntry->Flink; + if (Range->ProcessId != Process->UniqueProcessId || + Range->Key != Key) + continue; + FsRtlFastUnlockSingle + (FileLock, + FileObject, + &Range->Start, + &Length, + Range->ProcessId, + Range->Key, + Context, + TRUE); + } for (Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, TRUE); Entry; Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, FALSE))