Beispiel #1
0
/*
 * @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;
    }
}
Beispiel #2
0
/* 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
FsRtlpRebuildSharedLockRange
(PFILE_LOCK FileLock,
 PLOCK_INFORMATION LockInfo,
 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;
    COMBINED_LOCK_ELEMENT NewElement = *Conflict;
    PCOMBINED_LOCK_ELEMENT Entry;
    while ((Entry = RtlLookupElementGenericTable
            (FileLock->LockInformation, &NewElement)))
    {
        FsRtlpExpandLockElement(&NewElement, Entry);
        RemovedOld = RtlDeleteElementGenericTable
            (&LockInfo->RangeTable,
             Entry);
        ASSERT(RemovedOld);
    }
    Conflict = RtlInsertElementGenericTable
        (&LockInfo->RangeTable,
         &NewElement,
         sizeof(NewElement),
         &InsertedNew);
    ASSERT(InsertedNew);
    return Conflict;
}
Beispiel #3
0
BOOLEAN
NTAPI
NpDeleteEventTableEntry(IN PRTL_GENERIC_TABLE Table,
                        IN PVOID Buffer)
{
    if (!Buffer) return FALSE;

    ObDereferenceObject(((PNP_EVENT_BUFFER)Buffer)->Event);
    return RtlDeleteElementGenericTable(Table, Buffer);
}
Beispiel #4
0
BOOLEAN
RadixDeleteElement(
    IN PRTL_GENERIC_TABLE   Table,
    IN ULONG                Key
    )
{
    RADIX_TABLE_ELEMENT element;
    element.Key = Key;
    return RtlDeleteElementGenericTable(Table, &element);
}
BOOLEAN
xixfs_FCBTLBDeleteEntry(
	PXIXFS_FCB pFCB
)
{
	FCB_TABLE_ENTRY Entry;
	PAGED_CODE();
	DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_CREATE|DEBUG_TARGET_CLOSE| DEBUG_TARGET_FCB),
		("Enter xixfs_FCBTLBDeleteEntry \n" ));  

	Entry.FileId = pFCB->XixcoreFcb.LotNumber;
	return (RtlDeleteElementGenericTable(&pFCB->PtrVCB->FCBTable, &Entry));
}
Beispiel #6
0
BOOLEAN
XixFsdFCBTableDeleteFCB(
	PXIFS_FCB pFCB
)
{
	FCB_TABLE_ENTRY Entry;
	PAGED_CODE();
	DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_CREATE|DEBUG_TARGET_CLOSE| DEBUG_TARGET_FCB),
		("Enter XixFsdFCBTableDeleteFCB \n" ));  

	Entry.FileId = pFCB->LotNumber;
	return (RtlDeleteElementGenericTable(&pFCB->PtrVCB->FCBTable, &Entry));
}
Beispiel #7
0
/*
 * @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;
}
Beispiel #8
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");
}
Beispiel #9
0
/*
 * @implemented
 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
 * %NULL value is forbidden.
 * @Vbn: Starting virtual block number to specify the range to delete.
 * @SectorCount: Length of the range to delete.
 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
 *
 * Deletes any possible @Mcb mappings in the given range @Vbn ... @Vbn+@SectorCount-1.
 * This call has no problems if no mappings exist there yet.
 */
BOOLEAN
NTAPI
FsRtlRemoveBaseMcbEntry(IN PBASE_MCB OpaqueMcb,
                        IN LONGLONG Vbn,
                        IN LONGLONG SectorCount)
{
    PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb;
    LARGE_MCB_MAPPING_ENTRY NeedleRun;
    PLARGE_MCB_MAPPING_ENTRY HaystackRun;

    if (Vbn < 0 || SectorCount <= 0) return FALSE;
    if (Vbn + SectorCount <= Vbn) return FALSE;

    NeedleRun.RunStartVbn.QuadPart = Vbn;
    NeedleRun.RunEndVbn.QuadPart = Vbn + SectorCount;
    NeedleRun.StartingLbn.QuadPart = ~0ULL;

    /* adjust/destroy all intersecting ranges */
    Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare;
    while ((HaystackRun = RtlLookupElementGenericTable(&Mcb->Mapping->Table, &NeedleRun)))
    {
        if (HaystackRun->RunStartVbn.QuadPart < NeedleRun.RunStartVbn.QuadPart)
        {
            ASSERT(HaystackRun->RunEndVbn.QuadPart > NeedleRun.RunStartVbn.QuadPart);
            HaystackRun->RunEndVbn.QuadPart = NeedleRun.RunStartVbn.QuadPart;
        }
        else if (HaystackRun->RunEndVbn.QuadPart > NeedleRun.RunEndVbn.QuadPart)
        {
            ASSERT(HaystackRun->RunStartVbn.QuadPart < NeedleRun.RunEndVbn.QuadPart);
            HaystackRun->RunStartVbn.QuadPart = NeedleRun.RunEndVbn.QuadPart;
        }
        else
        {
            ASSERT(NeedleRun.RunStartVbn.QuadPart >= HaystackRun->RunStartVbn.QuadPart);
            //ASSERT(NeedleRun.RunEndVbn.QuadPart <= HaystackRun->RunEndVbn.QuadPart);
            Mcb->Mapping->Table.CompareRoutine = McbMappingCompare;
            RtlDeleteElementGenericTable(&Mcb->Mapping->Table, HaystackRun);
            Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare;
        }
    }
    Mcb->Mapping->Table.CompareRoutine = McbMappingCompare;

    return TRUE;
}
Beispiel #10
0
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");
}
Beispiel #11
0
/*
 * @implemented
 */
NTSTATUS
NTAPI
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)
{
    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 (%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
    // But Windows 2003 doesn't assert on it and simply ignores that parameter
    // ASSERT(AlreadySynchronized);
    Find.Exclusive.FileLock.StartingByte = *FileOffset;
    Find.Exclusive.FileLock.EndingByte.QuadPart = 
        FileOffset->QuadPart + Length->QuadPart;
    if (!InternalInfo) {
        DPRINT("File not previously locked (ever)\n");
        return STATUS_RANGE_NOT_LOCKED;
    }
    Entry = RtlLookupElementGenericTable(&InternalInfo->RangeTable, &Find);
    if (!Entry) {
        DPRINT("Range not locked %wZ\n", &FileObject->FileName);
        return STATUS_RANGE_NOT_LOCKED;
    }

    DPRINT("Found lock entry: Exclusive %u %08x%08x:%08x%08x %wZ\n",
           Entry->Exclusive.FileLock.ExclusiveLock,
           Entry->Exclusive.FileLock.StartingByte.HighPart,
           Entry->Exclusive.FileLock.StartingByte.LowPart,
           Entry->Exclusive.FileLock.EndingByte.HighPart,
           Entry->Exclusive.FileLock.EndingByte.LowPart,
           &FileObject->FileName);
    
    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));
        // Remove the old exclusive lock region
        RtlDeleteElementGenericTable(&InternalInfo->RangeTable, Entry);
    }
    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)
        {
            /* Remove the found range from the shared range lists */
            RemoveEntryList(&SharedRange->Entry);
            ExFreePoolWithTag(SharedRange, TAG_RANGE);
            /* 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);
               
            /* Remember what was in there and remove it from the table */
            Find = *Entry;
            RtlDeleteElementGenericTable(&InternalInfo->RangeTable, &Find);
            /* Put shared locks back in place */
            for (SharedEntry = InternalInfo->SharedLocks.Flink;
                 SharedEntry != &InternalInfo->SharedLocks;
                 SharedEntry = SharedEntry->Flink)
            {
                COMBINED_LOCK_ELEMENT LockElement;
                SharedRange = CONTAINING_RECORD(SharedEntry, LOCK_SHARED_RANGE, Entry);
                LockElement.Exclusive.FileLock.FileObject = FileObject;
                LockElement.Exclusive.FileLock.StartingByte = SharedRange->Start;
                LockElement.Exclusive.FileLock.EndingByte = SharedRange->End;
                LockElement.Exclusive.FileLock.ProcessId = SharedRange->ProcessId;
                LockElement.Exclusive.FileLock.Key = SharedRange->Key;
                LockElement.Exclusive.FileLock.ExclusiveLock = FALSE;
                
                if (LockCompare(&InternalInfo->RangeTable, &Find, &LockElement) != GenericEqual)
                {
                    DPRINT("Skipping range %08x%08x:%08x%08x\n",
                           LockElement.Exclusive.FileLock.StartingByte.HighPart,
                           LockElement.Exclusive.FileLock.StartingByte.LowPart,
                           LockElement.Exclusive.FileLock.EndingByte.HighPart,
                           LockElement.Exclusive.FileLock.EndingByte.LowPart);
                    continue;
                }
                DPRINT("Re-creating range %08x%08x:%08x%08x\n",
                       LockElement.Exclusive.FileLock.StartingByte.HighPart,
                       LockElement.Exclusive.FileLock.StartingByte.LowPart,
                       LockElement.Exclusive.FileLock.EndingByte.HighPart,
                       LockElement.Exclusive.FileLock.EndingByte.LowPart);
                FsRtlpRebuildSharedLockRange(FileLock, InternalInfo, &LockElement);
            }
        }
        else
        {
            return STATUS_RANGE_NOT_LOCKED;
        }
    }

#ifndef NDEBUG    
    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);
    }
#endif
    
    // this is definitely the thing we want
    InternalInfo->Generation++;
    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
        // 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;
}
Beispiel #12
0
/*
 * @implemented
 * @Mcb: #PLARGE_MCB initialized by FsRtlInitializeLargeMcb().
 * %NULL value is forbidden.
 * @Vbn: Starting virtual block number of the wished range.
 * @Lbn: Starting logical block number of the wished range.
 * @SectorCount: Length of the wished range.
 * Value less or equal to %0 is forbidden; FIXME: Is the reject of %0 W32 compliant?
 *
 * Adds the specified range @Vbn ... @Vbn+@SectorCount-1 to @Mcb.
 * Any mappings previously in this range are deleted first.
 *
 * Returns: %TRUE if successful.
 */
BOOLEAN
NTAPI
FsRtlAddBaseMcbEntry(IN PBASE_MCB OpaqueMcb,
                     IN LONGLONG Vbn,
                     IN LONGLONG Lbn,
                     IN LONGLONG SectorCount)
{
    PBASE_MCB_INTERNAL Mcb = (PBASE_MCB_INTERNAL)OpaqueMcb;
    LARGE_MCB_MAPPING_ENTRY Node, NeedleRun;
    PLARGE_MCB_MAPPING_ENTRY LowerRun, HigherRun;
    BOOLEAN NewElement;

    if (Vbn < 0) return FALSE;
    if (SectorCount <= 0) return FALSE;

    /* clean any possible previous entries in our range */
    FsRtlRemoveBaseMcbEntry(OpaqueMcb, Vbn, SectorCount);

    // We need to map [Vbn, Vbn+SectorCount) to [Lbn, Lbn+SectorCount),
    // taking in account the fact that we need to merge these runs if
    // they are adjacent or overlap, but fail if new run fully fits into another run

    /* initially we think we will be inserted as a separate run */
    Node.RunStartVbn.QuadPart = Vbn;
    Node.RunEndVbn.QuadPart = Vbn + SectorCount;
    Node.StartingLbn.QuadPart = Lbn;

    /* optionally merge with lower run */
    NeedleRun.RunStartVbn.QuadPart = Node.RunStartVbn.QuadPart - 1;
    NeedleRun.RunEndVbn.QuadPart = NeedleRun.RunStartVbn.QuadPart + 1;
    NeedleRun.StartingLbn.QuadPart = ~0ULL;
    Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare;
    if ((LowerRun = RtlLookupElementGenericTable(&Mcb->Mapping->Table, &NeedleRun)))
    {
        ASSERT(LowerRun->RunEndVbn.QuadPart == Node.RunStartVbn.QuadPart);
        Node.RunStartVbn.QuadPart = LowerRun->RunStartVbn.QuadPart;
        Node.StartingLbn.QuadPart = LowerRun->StartingLbn.QuadPart;
        Mcb->Mapping->Table.CompareRoutine = McbMappingCompare;
        RtlDeleteElementGenericTable(&Mcb->Mapping->Table, LowerRun);
        DPRINT("Intersecting lower run found (%I64d,%I64d) Lbn: %I64d\n", LowerRun->RunStartVbn.QuadPart, LowerRun->RunEndVbn.QuadPart, LowerRun->StartingLbn.QuadPart);
    }

    /* optionally merge with higher run */
    NeedleRun.RunStartVbn.QuadPart = Node.RunEndVbn.QuadPart;
    NeedleRun.RunEndVbn.QuadPart = NeedleRun.RunStartVbn.QuadPart + 1;
    Mcb->Mapping->Table.CompareRoutine = McbMappingIntersectCompare;
    if ((HigherRun = RtlLookupElementGenericTable(&Mcb->Mapping->Table, &NeedleRun)))
    {
        ASSERT(HigherRun->RunStartVbn.QuadPart == Node.RunEndVbn.QuadPart);
        Node.RunEndVbn.QuadPart = HigherRun->RunEndVbn.QuadPart;
        Mcb->Mapping->Table.CompareRoutine = McbMappingCompare;
        RtlDeleteElementGenericTable(&Mcb->Mapping->Table, HigherRun);
        DPRINT("Intersecting higher run found (%I64d,%I64d) Lbn: %I64d\n", HigherRun->RunStartVbn.QuadPart, HigherRun->RunEndVbn.QuadPart, HigherRun->StartingLbn.QuadPart);
    }
    Mcb->Mapping->Table.CompareRoutine = McbMappingCompare;

    /* finally insert the resulting run */
    RtlInsertElementGenericTable(&Mcb->Mapping->Table, &Node, sizeof(Node), &NewElement);
    ASSERT(NewElement);
    Node.RunStartVbn.QuadPart = Vbn;
    Node.RunEndVbn.QuadPart = Vbn + SectorCount;
    Node.StartingLbn.QuadPart = Lbn;

    // NB: Two consecutive runs can only be merged, if actual LBNs also match!

    /* 1.
            Existing->RunStartVbn
            |
            |///////|
                |/////////////|
                |
                Node->RunStartVbn

        2.
            Existing->RunStartVbn
            |
            |///////|
        |//////|
        |
        Node->RunStartVbn

        3.
            Existing->RunStartVbn
            |
            |///////|
                |///|
                |
                Node->RunStartVbn

        4.
            Existing->RunStartVbn
            |
            |///////|
        |///////////////|
        |
        Node->RunStartVbn


    Situation with holes:
    1. Holes at both ends
    2. Hole at the right, new run merged with the previous run
    3. Hole at the right, new run is not merged with the previous run
    4. Hole at the left, new run merged with the next run
    5. Hole at the left, new run is not merged with the next run
    6. No holes, exact fit to merge with both previous and next runs
    7. No holes, merges only with the next run
    8. No holes, merges only with the previous run
    9. No holes, does not merge with next or prev runs


    Overwriting existing mapping is not possible and results in FALSE being returned
    */
    return TRUE;
}
Beispiel #13
0
/*++////////////////////////////////////////////////////////////////////////////

ClassReleaseRemoveLock()

Routine Description:

    This routine is called to release the remove lock on the device object.  It
    must be called when finished using a previously locked reference to the
    device object.  If an Tag was specified when acquiring the lock then the
    same Tag must be specified when releasing the lock.

    When the lock count reduces to zero, this routine will signal the waiting
    remove Tag to delete the device object.  As a result the DeviceObject
    pointer should not be used again once the lock has been released.

Arguments:

    DeviceObject - the device object to lock

    Tag - The irp (if any) specified when acquiring the lock.  This is used
          for lock tracking purposes

Return Value:

    none

--*/
VOID
ClassReleaseRemoveLock(
    _In_ PDEVICE_OBJECT DeviceObject,
         PIRP Tag
    )
// This function implements the release of Tag
#pragma warning(suppress:28103)
{
    PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
    LONG lockValue;

    #if DBG
        PRTL_GENERIC_TABLE removeTrackingList = NULL;
        REMOVE_TRACKING_BLOCK searchDataBlock;

        BOOLEAN found = FALSE;

        BOOLEAN isRemoved = (commonExtension->IsRemoved == REMOVE_COMPLETE);

        KIRQL oldIrql;

        if(isRemoved) {
            TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK, "ClassReleaseRemoveLock: REMOVE_COMPLETE set; this should never happen"));
            InterlockedDecrement(&(commonExtension->RemoveLock));
            return;
        }

        KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
                          &oldIrql);

        removeTrackingList = commonExtension->RemoveTrackingList;

        if (removeTrackingList != NULL)
        {
            searchDataBlock.Tag = Tag;
            found = RtlDeleteElementGenericTable(removeTrackingList, &searchDataBlock);
        }

        if(!found) {
            if(commonExtension->RemoveTrackingUntrackedCount == 0) {
                TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassReleaseRemoveLock: "
                            "Couldn't find Tag %p in the lock tracking list\n", Tag));
                NT_ASSERT(FALSE);
            } else {
                TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassReleaseRemoveLock: "
                            "Couldn't find Tag %p in the lock tracking list - "
                            "may be one of the %d untracked requests still outstanding\n",
                            Tag, commonExtension->RemoveTrackingUntrackedCount));

                commonExtension->RemoveTrackingUntrackedCount--;
                NT_ASSERT(commonExtension->RemoveTrackingUntrackedCount >= 0);
            }
        }

        KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock,
                          oldIrql);

    #endif

    lockValue = InterlockedDecrement(&commonExtension->RemoveLock);

    TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK,  "ClassReleaseRemoveLock: "
                "Released for Object %p & irp %p - count is %d\n",
                DeviceObject, Tag, lockValue));

    NT_ASSERT(lockValue >= 0);

    NT_ASSERTMSG("RemoveLock decreased to meet LockLowWatermark",
              ((LockLowWatermark == 0) || !(lockValue == LockLowWatermark)));

    if(lockValue == 0) {

        NT_ASSERT(commonExtension->IsRemoved);

        //
        // The device needs to be removed.  Signal the remove event
        // that it's safe to go ahead.
        //

        TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK,  "ClassReleaseRemoveLock: "
                    "Release for object %p & irp %p caused lock to go to zero\n",
                    DeviceObject, Tag));

        KeSetEvent(&commonExtension->RemoveEvent,
                   IO_NO_INCREMENT,
                   FALSE);

    }
    return;
}