/* * @implemented */ VOID NTAPI FsRtlUninitializeFileLock(IN PFILE_LOCK FileLock) { if (FileLock->LockInformation) { 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(&SharedRange->Entry); ExFreePoolWithTag(SharedRange, TAG_RANGE); } while ((Entry = RtlGetElementGenericTable(&InternalInfo->RangeTable, 0)) != NULL) { RtlDeleteElementGenericTable(&InternalInfo->RangeTable, Entry); } while ((Irp = IoCsqRemoveNextIrp(&InternalInfo->Csq, NULL)) != NULL) { FsRtlProcessFileLock(FileLock, Irp, NULL); } ExFreePoolWithTag(InternalInfo, TAG_FLOCK); FileLock->LockInformation = NULL; } }
/* * @implemented */ VOID NTAPI FsRtlResetBaseMcb(IN PBASE_MCB OpaqueMcb) { PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb; PLARGE_MCB_MAPPING_ENTRY Element; while (RtlNumberGenericTableElements(&Mcb->Mapping->Table) && (Element = (PLARGE_MCB_MAPPING_ENTRY)RtlGetElementGenericTable(&Mcb->Mapping->Table, 0))) { RtlDeleteElementGenericTable(&Mcb->Mapping->Table, Element); } Mcb->PairCount = 0; Mcb->MaximumPairCount = 0; }
static void RtlSplayTreeTest() { ULONG i, del; PCHAR Ch; CHAR Text[] = "the quick_brown!fOx-jUmp3d/0vER+THe^lazy.D@g"; CHAR NewE[] = "11111111111111111111111111111111110111111111"; RTL_GENERIC_TABLE Table; RtlInitializeGenericTable (&Table, CompareCharTable, AllocRoutine, FreeRoutine, NULL); for (i = 0; Text[i]; i++) { BOOLEAN WasNew; Ch = (PCHAR)RtlInsertElementGenericTable (&Table, &Text[i], sizeof(Text[i]), &WasNew); ok(Ch && *Ch == Text[i], "Copy character into node\n"); ok(WasNew == (NewE[i] == '1'), "Character newness didn't match for char %u: '%c'\n", i, Text[i]); } for (Ch = (PCHAR)RtlEnumerateGenericTable(&Table, TRUE), i = 0; Ch; Ch = (PCHAR)RtlEnumerateGenericTable(&Table, FALSE), i++) { ok(strchr(Text, *Ch) != NULL, "Nonexistent character\n"); } ok(RtlNumberGenericTableElements(&Table) == strlen(Text) - 1, "Not the right number of elements\n"); ok(RtlLookupElementGenericTable(&Table, "q") != NULL, "Could not lookup q\n"); ok(!RtlLookupElementGenericTable(&Table, "#"), "Found a character that shouldn't appear\n"); ok(strlen(Text) == i + 1, "Didn't enumerate enough characters\n"); del = 0; for (i = 0; Text[i]; i++) { if (NewE[i] == '1') { BOOLEAN WasDeleted; WasDeleted = RtlDeleteElementGenericTable(&Table, &Text[i]); del += WasDeleted; } } ok(!RtlNumberGenericTableElements(&Table), "Not zero elements\n"); ok(!RtlGetElementGenericTable(&Table, 0), "Elements left when we removed them all\n"); ok(strlen(Text) == del + 1, "Deleted too many times\n"); ok(IsListEmpty(&Allocations), "Didn't free all memory\n"); }
ULONG NTAPI MiCacheEvictPages(PMM_SECTION_SEGMENT Segment, ULONG Target) { ULONG_PTR Entry; ULONG Result = 0, i, j; NTSTATUS Status; PFN_NUMBER Page; LARGE_INTEGER Offset; MmLockSectionSegment(Segment); for (i = 0; i < RtlNumberGenericTableElements(&Segment->PageTable); i++) { PCACHE_SECTION_PAGE_TABLE Element = RtlGetElementGenericTable(&Segment->PageTable, i); ASSERT(Element); Offset = Element->FileOffset; for (j = 0; j < ENTRIES_PER_ELEMENT; j++, Offset.QuadPart += PAGE_SIZE) { Entry = MmGetPageEntrySectionSegment(Segment, &Offset); if (Entry && !IS_SWAP_FROM_SSE(Entry)) { Page = PFN_FROM_SSE(Entry); MmUnlockSectionSegment(Segment); Status = MmpPageOutPhysicalAddress(Page); if (NT_SUCCESS(Status)) Result++; MmLockSectionSegment(Segment); } } } MmUnlockSectionSegment(Segment); return Result; }
VOID NTAPI MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment, FREE_SECTION_PAGE_FUN FreePage) { PCACHE_SECTION_PAGE_TABLE Element; DPRINT("MiFreePageTablesSectionSegment(%p)\n", &Segment->PageTable); while ((Element = RtlGetElementGenericTable(&Segment->PageTable, 0))) { DPRINT("Delete table for <%wZ> %p -> %I64x\n", Segment->FileObject ? &Segment->FileObject->FileName : NULL, Segment, Element->FileOffset.QuadPart); if (FreePage) { ULONG i; for (i = 0; i < ENTRIES_PER_ELEMENT; i++) { ULONG_PTR Entry; LARGE_INTEGER Offset; Offset.QuadPart = Element->FileOffset.QuadPart + i * PAGE_SIZE; Entry = Element->PageEntries[i]; if (Entry && !IS_SWAP_FROM_SSE(Entry)) { DPRINT("Freeing page %p:%Ix @ %I64x\n", Segment, Entry, Offset.QuadPart); FreePage(Segment, &Offset); } } } DPRINT("Remove memory\n"); RtlDeleteElementGenericTable(&Segment->PageTable, Element); } DPRINT("Done\n"); }
/* * @implemented */ BOOLEAN NTAPI FsRtlPrivateLock(IN PFILE_LOCK FileLock, IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, IN PEPROCESS Process, IN ULONG Key, IN BOOLEAN FailImmediately, IN BOOLEAN ExclusiveLock, OUT PIO_STATUS_BLOCK IoStatus, IN PIRP Irp OPTIONAL, IN PVOID Context OPTIONAL, IN BOOLEAN AlreadySynchronized) { NTSTATUS Status; COMBINED_LOCK_ELEMENT ToInsert; PCOMBINED_LOCK_ELEMENT Conflict; PLOCK_INFORMATION LockInfo; PLOCK_SHARED_RANGE NewSharedRange; BOOLEAN InsertedNew; ULARGE_INTEGER UnsignedStart; ULARGE_INTEGER UnsignedEnd; DPRINT("FsRtlPrivateLock(%wZ, Offset %08x%08x (%d), Length %08x%08x (%d), Key %x, FailImmediately %u, Exclusive %u)\n", &FileObject->FileName, FileOffset->HighPart, FileOffset->LowPart, (int)FileOffset->QuadPart, Length->HighPart, Length->LowPart, (int)Length->QuadPart, Key, FailImmediately, ExclusiveLock); 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; 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), TAG_FLOCK); if (!LockInfo) { IoStatus->Status = STATUS_NO_MEMORY; return FALSE; } FileLock->LockInformation = LockInfo; LockInfo->BelongsTo = FileLock; InitializeListHead(&LockInfo->SharedLocks); RtlInitializeGenericTable (&LockInfo->RangeTable, LockCompare, LockAllocate, LockFree, NULL); KeInitializeSpinLock(&LockInfo->CsqLock); InitializeListHead(&LockInfo->CsqList); IoCsqInitializeEx (&LockInfo->Csq, LockInsertIrpEx, LockRemoveIrp, LockPeekNextIrp, LockAcquireQueueLock, LockReleaseQueueLock, LockCompleteCanceledIrp); } LockInfo = FileLock->LockInformation; ToInsert.Exclusive.FileLock.FileObject = FileObject; ToInsert.Exclusive.FileLock.StartingByte = *FileOffset; ToInsert.Exclusive.FileLock.EndingByte.QuadPart = FileOffset->QuadPart + Length->QuadPart; 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) { DPRINT("Conflict %08x%08x:%08x%08x Exc %u (Want Exc %u)\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, Irp, IoStatus->Status, &Status, FileObject); } return FALSE; } else { IoStatus->Status = STATUS_PENDING; if (Irp) { Irp->IoStatus.Information = LockInfo->Generation; IoMarkIrpPending(Irp); IoCsqInsertIrpEx (&LockInfo->Csq, Irp, NULL, NULL); } } return FALSE; } else { 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 (Conflict && (LockCompare(&LockInfo->RangeTable, Conflict, &ToInsert) == GenericEqual)) { if (Conflict->Exclusive.FileLock.ExclusiveLock) { /* Found an exclusive match */ 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, Irp, IoStatus->Status, &Status, FileObject); } } else { IoStatus->Status = STATUS_PENDING; if (Irp) { IoMarkIrpPending(Irp); IoCsqInsertIrpEx (&LockInfo->Csq, Irp, NULL, NULL); } } return FALSE; } } } 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 = FsRtlpRebuildSharedLockRange(FileLock, LockInfo, &ToInsert); if (!Conflict) { IoStatus->Status = STATUS_NO_MEMORY; if (Irp) { FsRtlCompleteLockIrpReal (FileLock->CompleteLockIrpRoutine, Context, Irp, IoStatus->Status, &Status, FileObject); } } /* We got here because there were only overlapping shared locks */ /* A shared lock is both a range *and* a list entry. Insert the entry here. */ DPRINT("Adding shared lock %wZ\n", &FileObject->FileName); NewSharedRange = ExAllocatePoolWithTag(NonPagedPool, sizeof(*NewSharedRange), TAG_RANGE); 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 = *FileOffset; NewSharedRange->End.QuadPart = FileOffset->QuadPart + Length->QuadPart; 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; if (Irp) { FsRtlCompleteLockIrpReal (FileLock->CompleteLockIrpRoutine, Context, Irp, IoStatus->Status, &Status, FileObject); } return TRUE; } } else if (!Conflict) { /* 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 %u\n", &FileObject->FileName, Conflict->Exclusive.FileLock.StartingByte.HighPart, Conflict->Exclusive.FileLock.StartingByte.LowPart, Conflict->Exclusive.FileLock.EndingByte.HighPart, Conflict->Exclusive.FileLock.EndingByte.LowPart, Conflict->Exclusive.FileLock.ExclusiveLock); if (!ExclusiveLock) { NewSharedRange = ExAllocatePoolWithTag(NonPagedPool, sizeof(*NewSharedRange), TAG_RANGE); 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 = *FileOffset; NewSharedRange->End.QuadPart = FileOffset->QuadPart + Length->QuadPart; NewSharedRange->Key = Key; NewSharedRange->ProcessId = Process->UniqueProcessId; InsertTailList(&LockInfo->SharedLocks, &NewSharedRange->Entry); } /* Assume all is cool, and lock is set */ IoStatus->Status = STATUS_SUCCESS; if (Irp) { /* Complete the request */ FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine, Context, Irp, IoStatus->Status, &Status, FileObject); /* Update the status */ IoStatus->Status = Status; } } return TRUE; }