[NTOSKRNL]

Fix some problems with the lock implementation
- Add a 'generation' to the lock IRPs so we know if we've reprocessed them on any
  specific turn when we unlock something else.
- Simplify coalescing of lock regions to just rebuilding the region by going through
  the shared lock list and expanding a new region with any overlaps.
- Simplify coalescing new shared locks into larger regions in the same manner.

svn path=/trunk/; revision=56953
This commit is contained in:
Art Yerkes 2012-07-23 18:53:50 +00:00
parent 682ce04b5a
commit c487b06067

View file

@ -21,12 +21,12 @@ PAGED_LOOKASIDE_LIST FsRtlFileLockLookasideList;
*/ */
typedef union _COMBINED_LOCK_ELEMENT typedef union _COMBINED_LOCK_ELEMENT
{ {
struct struct
{ {
LIST_ENTRY dummy; LIST_ENTRY dummy;
FILE_SHARED_LOCK_ENTRY Shared; FILE_SHARED_LOCK_ENTRY Shared;
}; };
FILE_EXCLUSIVE_LOCK_ENTRY Exclusive; FILE_EXCLUSIVE_LOCK_ENTRY Exclusive;
} }
COMBINED_LOCK_ELEMENT, *PCOMBINED_LOCK_ELEMENT; COMBINED_LOCK_ELEMENT, *PCOMBINED_LOCK_ELEMENT;
@ -38,6 +38,7 @@ typedef struct _LOCK_INFORMATION
LIST_ENTRY CsqList; LIST_ENTRY CsqList;
PFILE_LOCK BelongsTo; PFILE_LOCK BelongsTo;
LIST_ENTRY SharedLocks; LIST_ENTRY SharedLocks;
ULONG Generation;
} }
LOCK_INFORMATION, *PLOCK_INFORMATION; LOCK_INFORMATION, *PLOCK_INFORMATION;
@ -224,6 +225,7 @@ FsRtlCompleteLockIrpReal(IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteRoutine,
IN PFILE_OBJECT FileObject OPTIONAL) IN PFILE_OBJECT FileObject OPTIONAL)
{ {
/* Check if we have a complete routine */ /* Check if we have a complete routine */
Irp->IoStatus.Information = 0;
if (CompleteRoutine) if (CompleteRoutine)
{ {
/* Check if we have a file object */ /* Check if we have a file object */
@ -260,55 +262,57 @@ FsRtlGetNextFileLock(IN PFILE_LOCK FileLock,
else return &Entry->Exclusive.FileLock; else return &Entry->Exclusive.FileLock;
} }
VOID
NTAPI
FsRtlpExpandLockElement
(PCOMBINED_LOCK_ELEMENT ToExpand,
PCOMBINED_LOCK_ELEMENT Conflict)
{
if (ToExpand->Exclusive.FileLock.StartingByte.QuadPart >
Conflict->Exclusive.FileLock.StartingByte.QuadPart)
{
ToExpand->Exclusive.FileLock.StartingByte =
Conflict->Exclusive.FileLock.StartingByte;
}
if (ToExpand->Exclusive.FileLock.EndingByte.QuadPart <
Conflict->Exclusive.FileLock.EndingByte.QuadPart)
{
ToExpand->Exclusive.FileLock.EndingByte =
Conflict->Exclusive.FileLock.EndingByte;
}
}
/* This function expands the conflicting range Conflict by removing and reinserting it, /* This function expands the conflicting range Conflict by removing and reinserting it,
then adds a shared range of the same size */ then adds a shared range of the same size */
PCOMBINED_LOCK_ELEMENT PCOMBINED_LOCK_ELEMENT
NTAPI NTAPI
FsRtlpSubsumeSharedLock FsRtlpRebuildSharedLockRange
(PFILE_LOCK FileLock, (PFILE_LOCK FileLock,
PLOCK_INFORMATION LockInfo, PLOCK_INFORMATION LockInfo,
PCOMBINED_LOCK_ELEMENT ToInsert,
PCOMBINED_LOCK_ELEMENT Conflict) PCOMBINED_LOCK_ELEMENT Conflict)
{ {
/* Starting at Conflict->StartingByte and going to Conflict->EndingByte
* capture and expand a shared range from the shared range list.
* Finish when we've incorporated all overlapping shared regions.
*/
BOOLEAN InsertedNew = FALSE, RemovedOld; BOOLEAN InsertedNew = FALSE, RemovedOld;
COMBINED_LOCK_ELEMENT NewElement; COMBINED_LOCK_ELEMENT NewElement = *Conflict;
PLOCK_SHARED_RANGE SharedRange = PCOMBINED_LOCK_ELEMENT Entry;
ExAllocatePoolWithTag(NonPagedPool, sizeof(*SharedRange), 'FSRA'); while ((Entry = RtlLookupElementGenericTable
(FileLock->LockInformation, &NewElement)))
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 = FsRtlpExpandLockElement(&NewElement, Entry);
Conflict->Exclusive.FileLock.StartingByte; RemovedOld = RtlDeleteElementGenericTable
(&LockInfo->RangeTable,
Entry);
ASSERT(RemovedOld);
} }
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 Conflict = RtlInsertElementGenericTable
(&LockInfo->RangeTable, (&LockInfo->RangeTable,
ToInsert, &NewElement,
sizeof(*ToInsert), sizeof(NewElement),
&InsertedNew); &InsertedNew);
ASSERT(InsertedNew && Conflict); ASSERT(InsertedNew);
return Conflict; return Conflict;
} }
@ -334,20 +338,27 @@ FsRtlPrivateLock(IN PFILE_LOCK FileLock,
COMBINED_LOCK_ELEMENT ToInsert; COMBINED_LOCK_ELEMENT ToInsert;
PCOMBINED_LOCK_ELEMENT Conflict; PCOMBINED_LOCK_ELEMENT Conflict;
PLOCK_INFORMATION LockInfo; PLOCK_INFORMATION LockInfo;
PLOCK_SHARED_RANGE NewSharedRange;
BOOLEAN InsertedNew; BOOLEAN InsertedNew;
ULARGE_INTEGER UnsignedStart;
ULARGE_INTEGER UnsignedEnd;
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, &FileObject->FileName,
FileOffset->HighPart, FileOffset->HighPart,
FileOffset->LowPart, FileOffset->LowPart,
(int)FileOffset->QuadPart,
Length->HighPart, Length->HighPart,
Length->LowPart, Length->LowPart,
(int)Length->QuadPart,
Key, Key,
FailImmediately, FailImmediately,
ExclusiveLock); ExclusiveLock);
if (FileOffset->QuadPart < 0ll || UnsignedStart.QuadPart = FileOffset->QuadPart;
FileOffset->QuadPart + Length->QuadPart < FileOffset->QuadPart) UnsignedEnd.QuadPart = FileOffset->QuadPart + Length->QuadPart;
if (UnsignedEnd.QuadPart < UnsignedStart.QuadPart)
{ {
DPRINT("File offset out of range\n"); DPRINT("File offset out of range\n");
IoStatus->Status = STATUS_INVALID_PARAMETER; IoStatus->Status = STATUS_INVALID_PARAMETER;
@ -416,11 +427,20 @@ FsRtlPrivateLock(IN PFILE_LOCK FileLock,
{ {
if (Conflict->Exclusive.FileLock.ExclusiveLock || ExclusiveLock) 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) if (FailImmediately)
{ {
DPRINT("STATUS_FILE_LOCK_CONFLICT\n");
IoStatus->Status = STATUS_FILE_LOCK_CONFLICT; IoStatus->Status = STATUS_FILE_LOCK_CONFLICT;
if (Irp) if (Irp)
{ {
DPRINT("STATUS_FILE_LOCK_CONFLICT: Complete\n");
FsRtlCompleteLockIrpReal FsRtlCompleteLockIrpReal
(FileLock->CompleteLockIrpRoutine, (FileLock->CompleteLockIrpRoutine,
Context, Context,
@ -436,6 +456,7 @@ FsRtlPrivateLock(IN PFILE_LOCK FileLock,
IoStatus->Status = STATUS_PENDING; IoStatus->Status = STATUS_PENDING;
if (Irp) if (Irp)
{ {
Irp->IoStatus.Information = LockInfo->Generation;
IoMarkIrpPending(Irp); IoMarkIrpPending(Irp);
IoCsqInsertIrpEx IoCsqInsertIrpEx
(&LockInfo->Csq, (&LockInfo->Csq,
@ -463,8 +484,10 @@ FsRtlPrivateLock(IN PFILE_LOCK FileLock,
if (FailImmediately) if (FailImmediately)
{ {
IoStatus->Status = STATUS_FILE_LOCK_CONFLICT; IoStatus->Status = STATUS_FILE_LOCK_CONFLICT;
DPRINT("STATUS_FILE_LOCK_CONFLICT\n");
if (Irp) if (Irp)
{ {
DPRINT("STATUS_FILE_LOCK_CONFLICT: Complete\n");
FsRtlCompleteLockIrpReal FsRtlCompleteLockIrpReal
(FileLock->CompleteLockIrpRoutine, (FileLock->CompleteLockIrpRoutine,
Context, Context,
@ -491,16 +514,14 @@ FsRtlPrivateLock(IN PFILE_LOCK FileLock,
} }
else 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", DPRINT("Overlapping shared lock %wZ %08x%08x %08x%08x\n",
&FileObject->FileName, &FileObject->FileName,
Conflict->Exclusive.FileLock.StartingByte.HighPart, Conflict->Exclusive.FileLock.StartingByte.HighPart,
Conflict->Exclusive.FileLock.StartingByte.LowPart, Conflict->Exclusive.FileLock.StartingByte.LowPart,
Conflict->Exclusive.FileLock.EndingByte.HighPart, Conflict->Exclusive.FileLock.EndingByte.HighPart,
Conflict->Exclusive.FileLock.EndingByte.LowPart); Conflict->Exclusive.FileLock.EndingByte.LowPart);
Conflict = FsRtlpSubsumeSharedLock Conflict = FsRtlpRebuildSharedLockRange
(FileLock, LockInfo, &ToInsert, Conflict); (FileLock, LockInfo, &ToInsert);
if (!Conflict) if (!Conflict)
{ {
IoStatus->Status = STATUS_NO_MEMORY; IoStatus->Status = STATUS_NO_MEMORY;
@ -514,20 +535,20 @@ FsRtlPrivateLock(IN PFILE_LOCK FileLock,
&Status, &Status,
FileObject); FileObject);
} }
return FALSE; break;
} }
} }
} }
} }
/* We got here because there were only overlapping shared locks */ /* We got here because there were only overlapping shared locks */
DPRINT("Acquired shared lock %wZ %08x%08x %08x%08x\n", /* A shared lock is both a range *and* a list entry. Insert the
&FileObject->FileName, entry here. */
Conflict->Exclusive.FileLock.StartingByte.HighPart,
Conflict->Exclusive.FileLock.StartingByte.LowPart, DPRINT("Adding shared lock %wZ\n", &FileObject->FileName);
Conflict->Exclusive.FileLock.EndingByte.HighPart, NewSharedRange =
Conflict->Exclusive.FileLock.EndingByte.LowPart); ExAllocatePoolWithTag(NonPagedPool, sizeof(*NewSharedRange), 'FSRA');
if (!FsRtlpSubsumeSharedLock(FileLock, LockInfo, &ToInsert, Conflict)) if (!NewSharedRange)
{ {
IoStatus->Status = STATUS_NO_MEMORY; IoStatus->Status = STATUS_NO_MEMORY;
if (Irp) if (Irp)
@ -542,6 +563,19 @@ FsRtlPrivateLock(IN PFILE_LOCK FileLock,
} }
return FALSE; 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);
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);
IoStatus->Status = STATUS_SUCCESS; IoStatus->Status = STATUS_SUCCESS;
if (Irp) if (Irp)
{ {
@ -584,7 +618,6 @@ FsRtlPrivateLock(IN PFILE_LOCK FileLock,
Conflict->Exclusive.FileLock.ExclusiveLock); Conflict->Exclusive.FileLock.ExclusiveLock);
if (!ExclusiveLock) if (!ExclusiveLock)
{ {
PLOCK_SHARED_RANGE NewSharedRange;
NewSharedRange = NewSharedRange =
ExAllocatePoolWithTag(NonPagedPool, sizeof(*NewSharedRange), 'FSRA'); ExAllocatePoolWithTag(NonPagedPool, sizeof(*NewSharedRange), 'FSRA');
if (!NewSharedRange) if (!NewSharedRange)
@ -805,12 +838,14 @@ FsRtlFastUnlockSingle(IN PFILE_LOCK FileLock,
PCOMBINED_LOCK_ELEMENT Entry; PCOMBINED_LOCK_ELEMENT Entry;
PIRP NextMatchingLockIrp; PIRP NextMatchingLockIrp;
PLOCK_INFORMATION InternalInfo = FileLock->LockInformation; 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, &FileObject->FileName,
FileOffset->HighPart, FileOffset->HighPart,
FileOffset->LowPart, FileOffset->LowPart,
(int)FileOffset->QuadPart,
Length->HighPart, Length->HighPart,
Length->LowPart, Length->LowPart,
(int)Length->QuadPart,
Key); Key);
// The region to unlock must correspond exactly to a previously locked region // The region to unlock must correspond exactly to a previously locked region
// -- msdn // -- msdn
@ -819,6 +854,7 @@ FsRtlFastUnlockSingle(IN PFILE_LOCK FileLock,
Find.Exclusive.FileLock.StartingByte = *FileOffset; Find.Exclusive.FileLock.StartingByte = *FileOffset;
Find.Exclusive.FileLock.EndingByte.QuadPart = Find.Exclusive.FileLock.EndingByte.QuadPart =
FileOffset->QuadPart + Length->QuadPart; FileOffset->QuadPart + Length->QuadPart;
ASSERT(InternalInfo);
Entry = RtlLookupElementGenericTable(&InternalInfo->RangeTable, &Find); Entry = RtlLookupElementGenericTable(&InternalInfo->RangeTable, &Find);
if (!Entry) { if (!Entry) {
DPRINT("Range not locked %wZ\n", &FileObject->FileName); DPRINT("Range not locked %wZ\n", &FileObject->FileName);
@ -879,11 +915,55 @@ FsRtlFastUnlockSingle(IN PFILE_LOCK FileLock,
} }
if (FoundShared) if (FoundShared)
{ {
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.StartingByte = SharedRange->Start;
Find.Exclusive.FileLock.EndingByte = SharedRange->End; Find.Exclusive.FileLock.EndingByte = SharedRange->End;
SharedEntry = SharedRange->Entry.Flink; SharedEntry = SharedRange->Entry.Flink;
RemoveEntryList(&SharedRange->Entry); RemoveEntryList(&SharedRange->Entry);
ExFreePool(SharedRange); 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;
}
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);
RtlZeroMemory(&RemadeElement, sizeof(RemadeElement));
RemadeElement.Exclusive.FileLock.StartingByte = WatchSharedRange->Start;
RemadeElement.Exclusive.FileLock.EndingByte = WatchSharedRange->End;
RemadeElementInserted =
FsRtlpRebuildSharedLockRange
(FileLock, InternalInfo, &RemadeElement);
}
} }
else else
{ {
@ -891,35 +971,36 @@ FsRtlFastUnlockSingle(IN PFILE_LOCK FileLock,
} }
} }
if (IsListEmpty(&InternalInfo->SharedLocks)) { DPRINT("Lock still has:\n");
DPRINT("Removing the lock entry %wZ (%08x%08x:%08x%08x)\n", for (SharedEntry = InternalInfo->SharedLocks.Flink;
&FileObject->FileName, SharedEntry != &InternalInfo->SharedLocks;
Entry->Exclusive.FileLock.StartingByte.HighPart, SharedEntry = SharedEntry->Flink)
Entry->Exclusive.FileLock.StartingByte.LowPart, {
Entry->Exclusive.FileLock.EndingByte.HighPart, SharedRange = CONTAINING_RECORD(SharedEntry, LOCK_SHARED_RANGE, Entry);
Entry->Exclusive.FileLock.EndingByte.LowPart); DPRINT("Shared element %wZ Offset %08x%08x Length %08x%08x Key %x\n",
RtlDeleteElementGenericTable(&InternalInfo->RangeTable, Entry); &FileObject->FileName,
} else { SharedRange->Start.HighPart,
DPRINT("Lock still has:\n"); SharedRange->Start.LowPart,
for (SharedEntry = InternalInfo->SharedLocks.Flink; SharedRange->End.HighPart,
SharedEntry != &InternalInfo->SharedLocks; SharedRange->End.LowPart,
SharedEntry = SharedEntry->Flink) SharedRange->Key);
{
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 // this is definitely the thing we want
NextMatchingLockIrp = IoCsqRemoveNextIrp(&InternalInfo->Csq, &Find); InternalInfo->Generation++;
while (NextMatchingLockIrp) while ((NextMatchingLockIrp = IoCsqRemoveNextIrp(&InternalInfo->Csq, &Find)))
{ {
if (NextMatchingLockIrp->IoStatus.Information == InternalInfo->Generation)
{
// We've already looked at this one, meaning that we looped.
// Put it back and exit.
IoCsqInsertIrpEx
(&InternalInfo->Csq,
NextMatchingLockIrp,
NULL,
NULL);
break;
}
// Got a new lock irp... try to do the new lock operation // Got a new lock irp... try to do the new lock operation
// Note that we pick an operation that would succeed at the time // 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 // we looked, but can't guarantee that it won't just be re-queued
@ -943,17 +1024,37 @@ FsRtlFastUnlockAll(IN PFILE_LOCK FileLock,
IN PEPROCESS Process, IN PEPROCESS Process,
IN PVOID Context OPTIONAL) IN PVOID Context OPTIONAL)
{ {
PLIST_ENTRY ListEntry;
PCOMBINED_LOCK_ELEMENT Entry; PCOMBINED_LOCK_ELEMENT Entry;
PRTL_GENERIC_TABLE InternalInfo = FileLock->LockInformation; PLOCK_INFORMATION InternalInfo = FileLock->LockInformation;
DPRINT("FsRtlFastUnlockAll(%wZ)\n", &FileObject->FileName); DPRINT("FsRtlFastUnlockAll(%wZ)\n", &FileObject->FileName);
// XXX Synchronize somehow // XXX Synchronize somehow
if (!FileLock->LockInformation) { if (!FileLock->LockInformation) {
DPRINT("Not locked %wZ\n", &FileObject->FileName); DPRINT("Not locked %wZ\n", &FileObject->FileName);
return STATUS_RANGE_NOT_LOCKED; // no locks 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;
Entry = RtlEnumerateGenericTable(InternalInfo, FALSE)) Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, FALSE))
{ {
LARGE_INTEGER Length; LARGE_INTEGER Length;
// We'll take the first one to be the list head, and free the others first... // We'll take the first one to be the list head, and free the others first...
@ -985,6 +1086,7 @@ FsRtlFastUnlockAllByKey(IN PFILE_LOCK FileLock,
IN ULONG Key, IN ULONG Key,
IN PVOID Context OPTIONAL) IN PVOID Context OPTIONAL)
{ {
PLIST_ENTRY ListEntry;
PCOMBINED_LOCK_ELEMENT Entry; PCOMBINED_LOCK_ELEMENT Entry;
PLOCK_INFORMATION InternalInfo = FileLock->LockInformation; PLOCK_INFORMATION InternalInfo = FileLock->LockInformation;
@ -992,6 +1094,26 @@ FsRtlFastUnlockAllByKey(IN PFILE_LOCK FileLock,
// XXX Synchronize somehow // XXX Synchronize somehow
if (!FileLock->LockInformation) return STATUS_RANGE_NOT_LOCKED; // no locks 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); for (Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, TRUE);
Entry; Entry;
Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, FALSE)) Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, FALSE))