⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mm.c

📁 winddk src目录下的文件系统驱动源码压缩!
💻 C
📖 第 1 页 / 共 2 页
字号:
/*++

Copyright (c) 1989 - 1999  Microsoft Corporation

Module Name:

    mm.c

Abstract:

    This module implements the memory managment routines for the SMB mini
    redirector

Notes:

    The SMB mini redirector manipulates entities which have very different usage
    patterns. They range from very static entities ( which are allocated and freed
    with a very low frequency ) to very dynamic entities.

    The entities manipulated in the SMB mini redirector are SMBCE_SERVER, SMBCE_NET_ROOT,
    SMBCE_VC, SMBCE_SESSION. These represent a connection to a server, a share on
    a particular server, a virtual circuit used in the connection and a session
    for a particular user.

    These are not very dynamic, i.e., the allocation/deallocation is very infrequent.
    The SMB_EXCHANGE and SMBCE_REQUEST map to the SMB's that are sent along that
    a connection. Every file operation in turn maps to a certain number of calls
    for allocationg/freeing exchanges and requests. Therefore it is imperative
    that some form of scavenging/caching of recently freed entries be maintained
    to satisfy requests quickly.

    In the current implementation the exchanges and requests are implemented
    using the zone allocation primitives.

    The exchange allocation and free routines are currently implemented as wrappers
    around the RxAllocate and RxFree routines. It would be far more efficient if
    a look aside cache of some exchange instances are maintained.

--*/

#include "precomp.h"
#pragma hdrstop

#include <vcsndrcv.h>

#ifdef  ALLOC_PRAGMA
#pragma alloc_text(PAGE, SmbMmAllocateSessionEntry)
#pragma alloc_text(PAGE, SmbMmFreeSessionEntry)
#pragma alloc_text(PAGE, SmbMmAllocateServerTransport)
#pragma alloc_text(PAGE, SmbMmFreeServerTransport)
#pragma alloc_text(PAGE, SmbMmInit)
#pragma alloc_text(PAGE, SmbMmTearDown)
#endif

#define SMBMM_ZONE_ALLOCATION 0x10

// The memory management package addresses a number of concerns w.r.t debugging
// and performance. By centralizing all the allocation/deallocation routines to
// thsi one module it is possible to build up profiles regarding various data
// structures used by the connection engine. In addition debugging support is
// provided by thereading together all allocated objects of a particular type
// are threaded together in a linked list according to type.
//
// At any stage by inspecting these lists the currently active instances of a
// particular type can be enumerated.
//
// Each type handled by this module is provided with two routines, e.g., for
// server entries there are SmbMmInitializeEntry and SmbMmUninitializeEntry. The
// first routine is called before handing over a pointer of a newly created
// instance. This will ensure that the instance is in a wll known initial state.
// Similarly the second routine is called just before deallocating the pool
// associated with the instance. This helps enforce the necessary integrity
// constraints, e.g., all enclosed pointers must be NULL etc.
//
// The pool allocation/deallocation is handled by the following routines
//
//    SmbMmAllocateObjectPool/SmbMmFreeObjectPool
//
//    SmbMmAllocateExchange/SmbMmFreeExchange
//
// The Object allocation routines are split up into two parts so as to be able to
// handle the session allocationson par with other objects even though they are
// further subtyped.
//
// On debug builds additional pool is allocated and the appropriate linking is
// done into the corresponding list. On retail builds these map to the regular
// pool allocation wrappers.
//

// Zone allocation to speed up memory management of RxCe entities.
//

ULONG       SmbMmRequestZoneEntrySize;
ZONE_HEADER SmbMmRequestZone;
PVOID       SmbMmRequestZoneSegmentPtr;

//
// Pool allocation resources and spin locks
//

KSPIN_LOCK  SmbMmSpinLock;

ULONG SmbMmExchangeId;

//
// List of the various objects/exchanges allocated.
//

LIST_ENTRY SmbMmExchangesInUse[SENTINEL_EXCHANGE];
LIST_ENTRY SmbMmObjectsInUse[SMBCEDB_OT_SENTINEL];

ULONG  ObjectSizeInBytes[SMBCEDB_OT_SENTINEL];
ULONG  ExchangeSizeInBytes[SENTINEL_EXCHANGE];

//
// Lookaside lists for Exchange allocation
//

NPAGED_LOOKASIDE_LIST SmbMmExchangesLookasideList[SENTINEL_EXCHANGE];

INLINE PSMBCE_OBJECT_HEADER
SmbMmAllocateObjectPool(
    SMBCEDB_OBJECT_TYPE  ObjectType,
    ULONG                PoolType,
    ULONG                PoolSize)
{
    KIRQL SavedIrql;
    PVOID pv = NULL;
    UCHAR Flags = 0;

    PSMBCE_OBJECT_HEADER pHeader = NULL;

    ASSERT((ObjectType >= 0) && (ObjectType < SMBCEDB_OT_SENTINEL));

    if (ObjectType == SMBCEDB_OT_REQUEST) {
        // Acquire the resource lock.
        KeAcquireSpinLock( &SmbMmSpinLock, &SavedIrql );

        if (!ExIsFullZone( &SmbMmRequestZone )) {
            pv = ExAllocateFromZone( &SmbMmRequestZone );
            Flags = SMBMM_ZONE_ALLOCATION;
        }

        // Release the resource lock.
        KeReleaseSpinLock( &SmbMmSpinLock, SavedIrql );
    }

    if (pv == NULL) {
        PLIST_ENTRY pListEntry;

        __assume_bound( PoolSize );
        pv = RxAllocatePoolWithTag(
                 PoolType,
                 PoolSize + sizeof(LIST_ENTRY),
                 MRXSMB_MM_POOLTAG);

        if (pv != NULL) {
            pListEntry = (PLIST_ENTRY)pv;
            pHeader    = (PSMBCE_OBJECT_HEADER)(pListEntry + 1);

            ExInterlockedInsertTailList(
                &SmbMmObjectsInUse[ObjectType],
                pListEntry,
                &SmbMmSpinLock);
        }
    } else {
        pHeader = (PSMBCE_OBJECT_HEADER)pv;
    }

    if (pHeader != NULL) {
        // Zero the memory.
        RtlZeroMemory( pHeader, PoolSize);

        pHeader->Flags = Flags;
    }

    return pHeader;
}

INLINE VOID
SmbMmFreeObjectPool(
    PSMBCE_OBJECT_HEADER  pHeader)
{
    KIRQL               SavedIrql;
    BOOLEAN             ZoneAllocation = FALSE;
    PLIST_ENTRY         pListEntry;

    ASSERT((pHeader->ObjectType >= 0) && (pHeader->ObjectType < SMBCEDB_OT_SENTINEL));

    // Acquire the resource lock.
    KeAcquireSpinLock( &SmbMmSpinLock, &SavedIrql );

    // Check if it was a zone allocation
    if (pHeader->Flags & SMBMM_ZONE_ALLOCATION) {
        ZoneAllocation = TRUE;
        ExFreeToZone(&SmbMmRequestZone,pHeader);
    } else {
        pListEntry = (PLIST_ENTRY)((PCHAR)pHeader - sizeof(LIST_ENTRY));
        RemoveEntryList(pListEntry);
    }

    // Release the resource lock.
    KeReleaseSpinLock( &SmbMmSpinLock, SavedIrql );

    if (!ZoneAllocation) {
        RxFreePool(pListEntry);
    }
}

// Construction and destruction of various SMB connection engine objects
//

#define SmbMmInitializeServerEntry(pServerEntry)                                \
         InitializeListHead(&(pServerEntry)->OutstandingRequests.ListHead);   \
         InitializeListHead(&(pServerEntry)->MidAssignmentRequests.ListHead); \
         InitializeListHead(&(pServerEntry)->Sessions.ListHead);              \
         InitializeListHead(&(pServerEntry)->NetRoots.ListHead);              \
         InitializeListHead(&(pServerEntry)->VNetRootContexts.ListHead);      \
         InitializeListHead(&(pServerEntry)->ActiveExchanges);                \
         InitializeListHead(&(pServerEntry)->ExpiredExchanges);                \
         InitializeListHead(&(pServerEntry)->Sessions.DefaultSessionList);     \
         (pServerEntry)->pTransport                = NULL;                      \
         (pServerEntry)->pMidAtlas                 = NULL

#define SmbMmInitializeSessionEntry(pSessionEntry)  \
         InitializeListHead(&(pSessionEntry)->Requests.ListHead); \
         InitializeListHead(&(pSessionEntry)->SerializationList); \
         (pSessionEntry)->DefaultSessionLink.Flink = NULL;        \
         (pSessionEntry)->DefaultSessionLink.Blink = NULL

#define SmbMmInitializeNetRootEntry(pNetRootEntry)  \
         InitializeListHead(&(pNetRootEntry)->Requests.ListHead)

#define SmbMmUninitializeServerEntry(pServerEntry)                                 \
         ASSERT(IsListEmpty(&(pServerEntry)->OutstandingRequests.ListHead) &&   \
                IsListEmpty(&(pServerEntry)->MidAssignmentRequests.ListHead) && \
                IsListEmpty(&(pServerEntry)->Sessions.ListHead) &&              \
                IsListEmpty(&(pServerEntry)->NetRoots.ListHead) &&              \
                ((pServerEntry)->pMidAtlas == NULL))

#define SmbMmUninitializeSessionEntry(pSessionEntry)  \
         ASSERT(IsListEmpty(&(pSessionEntry)->Requests.ListHead) && \
                ((pSessionEntry)->DefaultSessionLink.Flink == NULL))

#define SmbMmUninitializeNetRootEntry(pNetRootEntry)  \
         ASSERT(IsListEmpty(&(pNetRootEntry)->Requests.ListHead))

#define SmbMmInitializeRequestEntry(pRequestEntry)

#define SmbMmUninitializeRequestEntry(pRequestEntry)

PVOID
SmbMmAllocateObject(
    SMBCEDB_OBJECT_TYPE ObjectType)
{
    PSMBCE_OBJECT_HEADER pHeader;

    ASSERT((ObjectType >= 0) && (ObjectType < SMBCEDB_OT_SENTINEL));

    pHeader = SmbMmAllocateObjectPool(
                  ObjectType,
                  NonPagedPool,
                  ObjectSizeInBytes[ObjectType]);

    if (pHeader != NULL) {
        pHeader->NodeType = SMB_CONNECTION_ENGINE_NTC(ObjectType);
        pHeader->State = SMBCEDB_START_CONSTRUCTION;

        switch (ObjectType) {
        case SMBCEDB_OT_SERVER :
            SmbMmInitializeServerEntry((PSMBCEDB_SERVER_ENTRY)pHeader);
            break;

        case SMBCEDB_OT_NETROOT :
            SmbMmInitializeNetRootEntry((PSMBCEDB_NET_ROOT_ENTRY)pHeader);
            break;

        case SMBCEDB_OT_REQUEST :
            SmbMmInitializeRequestEntry((PSMBCEDB_REQUEST_ENTRY)pHeader);
            break;

        default:
            ASSERT(!"Valid Type for SmbMmAllocateObject");
            break;
        }
    }

    return pHeader;
}

VOID
SmbMmFreeObject(
    PVOID pv)
{
    PSMBCE_OBJECT_HEADER pHeader = (PSMBCE_OBJECT_HEADER)pv;

    switch (pHeader->ObjectType) {
    case SMBCEDB_OT_SERVER :
        SmbMmUninitializeServerEntry((PSMBCEDB_SERVER_ENTRY)pHeader);
        break;

    case SMBCEDB_OT_NETROOT :
        SmbMmUninitializeNetRootEntry((PSMBCEDB_NET_ROOT_ENTRY)pHeader);
        break;

    case SMBCEDB_OT_REQUEST :
        SmbMmUninitializeRequestEntry((PSMBCEDB_REQUEST_ENTRY)pHeader);
        break;

    default:
        ASSERT(!"Valid Type for SmbMmFreeObject");
        break;
    }

    SmbMmFreeObjectPool(pHeader);
}

PSMBCEDB_SESSION_ENTRY
SmbMmAllocateSessionEntry(
    PSMBCEDB_SERVER_ENTRY pServerEntry)
{
    PSMBCEDB_SESSION_ENTRY pSessionEntry;
    SESSION_TYPE           SessionType;
    ULONG                  SessionSize;

    PAGED_CODE();

    SessionSize = sizeof(SMBCEDB_SESSION_ENTRY);
    SessionType = LANMAN_SESSION;

    pSessionEntry = (PSMBCEDB_SESSION_ENTRY)
                    SmbMmAllocateObjectPool(
                        SMBCEDB_OT_SESSION,
                        NonPagedPool,
                        SessionSize);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -