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

📄 vmcbsup.c

📁 windows 2000中的UDF文件系统的驱动程序.只有读的功能,不支持未关闭的盘片.只支持UDF2.0以下版本,不支持VAT格式的UDF.
💻 C
📖 第 1 页 / 共 3 页
字号:
/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    VmcbSup.c

Abstract:

    Historical note: this package was originally written for HPFS (pinball)
    and is now resurrected for UDFS.  Since UDFS is readonly in initial
    versions we will snip by #ifdef the write support, leaving it visible
    for the future - this code has not been changed (nearly) whatsoever and
    is left named as Pb (pinball) code.

    The VMCB routines provide support for maintaining a mapping between
    LBNs and VBNs for a virtual volume file.  The volume file is all
    of the sectors that make up the on-disk structures.  A file system
    uses this package to map LBNs for on-disk structure to VBNs in a volume
    file.  This when used in conjunction with Memory Management and the
    Cache Manager will treat the volume file as a simple mapped file.  A
    variable of type VMCB is used to store the mapping information and one
    is needed for every mounted volume.

    The main idea behind this package is to allow the user to dynamically
    read in new disk structure sectors (e.g., File Entries).  The user assigns
    the new sector a VBN in the Volume file and has memory management fault
    the page containing the sector into memory.  To do this Memory management
    will call back into the file system to read the page from the volume file
    passing in the appropriate VBN.  Now the file system takes the VBN and
    maps it back to its LBN and does the read.

    The granularity of mapping is one a per page basis.  That is if
    a mapping for LBN 8 is added to the VMCB structure and the page size
    is 8 sectors then the VMCB routines will actually assign a mapping for
    LBNS 8 through 15, and they will be assigned to a page aligned set of
    VBNS.  This function is needed to allow us to work efficiently with
    memory management.  This means that some sectors in some pages might
    actually contain regular file data and not volume information, and so
    when writing the page out we must only write the sectors that are really
    in use by the volume file.  To help with this we provide a set
    of routines to keep track of dirty volume file sectors.
    That way, when the file system is called to write a page to the volume
    file, it will only write the sectors that are dirty.

    Concurrent access the VMCB structure is control by this package.

    The functions provided in this package are as follows:

      o  UdfInitializeVmcb - Initialize a new VMCB structure.

      o  UdfUninitializeVmcb - Uninitialize an existing VMCB structure.

      o  UdfSetMaximumLbnVmcb - Sets/Resets the maximum allowed LBN
         for the specified VMCB structure.

      o  UdfAddVmcbMapping - This routine takes an LBN and assigns to it
         a VBN.  If the LBN already was assigned to an VBN it simply returns
         the old VBN and does not do a new assignemnt.

      o  UdfRemoveVmcbMapping - This routine takes an LBN and removes its
         mapping from the VMCB structure.

      o  UdfVmcbVbnToLbn - This routine takes a VBN and returns the
         LBN it maps to.

      o  UdfVmcbLbnToVbn - This routine takes an LBN and returns the
         VBN its maps to.

#if VMCB_WRITE_SUPPORT

      o  PbSetDirtyVmcb - This routine is used to mark sectors dirty
         in the volume file.

      o  PbSetCleanVmcb - This routine is used to mark sectors clean
         in the volume file.

      o  PbGetDirtySectorsVmcb - This routine is used to retrieve the
         dirty sectors for a page in the volume file.

      o  PbGetAndCleanDirtyVmcb - This routine is used to retrieve the
         dirty sectors for a page in the volume file and atomically clear
         the dirty sectors.

#endif // VMCB_WRITE_SUPPORT

Authors:

    Gary Kimura     [GaryKi]    4-Apr-1990
    Dan Lovinger    [DanLo]     10-Sep-1996

Revision History:

--*/

#include "UdfProcs.h"

//
//  The Bug check file id for this module
//

#define BugCheckFileId                   (UDFS_BUG_CHECK_VMCBSUP)

//
//  The local debug trace level
//

#define Dbg                              (UDFS_DEBUG_LEVEL_VMCBSUP)

//
//  Turn off write/dirty/clean sector support
//

#define VMCB_WRITE_SUPPORT 0


//
//  The following macro is used to calculate the number of pages (in terms of
//  sectors) needed to contain a given sector count.  For example,
//
//      PageAlign( 0 Sectors ) = 0 Pages = 0 Sectors
//      PageAlign( 1 Sectors ) = 1 Page  = 8 Sectors
//      PageAlign( 2 Sectors ) = 1 Page  = 8 Sectors
//

#define PageAlign(V, L) ((((L)+((PAGE_SIZE/(V)->SectorSize)-1))/(PAGE_SIZE/(V)->SectorSize))*(PAGE_SIZE/(V)->SectorSize))


#if VMCB_WRITE_SUPPORT

//
//  The following constant is a bit mask, with one bit set for each sector
//  that'll fit in a page (4K page, 8 bits; 8K page, 16 bits, etc)
//

#define SECTOR_MASK ((1 << (PAGE_SIZE / sizeof (SECTOR))) - 1)

//
//  The Dirty Page structure are elements in the dirty table generic table.
//  This is followed by the procedure prototypes for the local generic table
//  routines
//

typedef struct _DIRTY_PAGE {
    ULONG LbnPageNumber;
    ULONG DirtyMask;
} DIRTY_PAGE;
typedef DIRTY_PAGE *PDIRTY_PAGE;

RTL_GENERIC_COMPARE_RESULTS
PbCompareDirtyVmcb (
    IN PRTL_GENERIC_TABLE DirtyTable,
    IN PVOID FirstStruct,
    IN PVOID SecondStruct
    );

PVOID
PbAllocateDirtyVmcb (
    IN PRTL_GENERIC_TABLE DirtyTable,
    IN CLONG ByteSize
    );

VOID
PbDeallocateDirtyVmcb (
    IN PRTL_GENERIC_TABLE DirtyTable,
    IN PVOID Buffer
    );

ULONG
PbDumpDirtyVmcb (
    IN PVMCB Vmcb
    );

#endif // VMCB_WRITE_SUPPORT

//
//  Local Routines.
//

BOOLEAN
UdfVmcbLookupMcbEntry (
    IN PMCB Mcb,
    IN VBN Vbn,
    OUT PLBN Lbn,
    OUT PULONG SectorCount OPTIONAL,
    OUT PULONG Index OPTIONAL
    );


#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, UdfAddVmcbMapping)

#if VMCB_WRITE_SUPPORT
#pragma alloc_text(PAGE, PbAllocateDirtyVmcb)
#pragma alloc_text(PAGE, PbDeallocateDirtyVmcb)
#pragma alloc_text(PAGE, PbDumpDirtyVmcb)
#pragma alloc_text(PAGE, PbGetAndCleanDirtyVmcb)
#endif // VMCB_WRITE_SUPPORT

#pragma alloc_text(PAGE, UdfInitializeVmcb)
#pragma alloc_text(PAGE, UdfRemoveVmcbMapping)
#pragma alloc_text(PAGE, UdfResetVmcb)

#if VMCB_WRITE_SUPPORT
#pragma alloc_text(PAGE, PbSetCleanVmcb)
#pragma alloc_text(PAGE, PbSetDirtyVmcb)
#endif // VMCB_WRITE_SUPPORT

#pragma alloc_text(PAGE, UdfSetMaximumLbnVmcb)
#pragma alloc_text(PAGE, UdfUninitializeVmcb)
#pragma alloc_text(PAGE, UdfVmcbLbnToVbn)
#pragma alloc_text(PAGE, UdfVmcbLookupMcbEntry)
#pragma alloc_text(PAGE, UdfVmcbVbnToLbn)
#endif


VOID
UdfInitializeVmcb (
    IN PVMCB Vmcb,
    IN POOL_TYPE PoolType,
    IN ULONG MaximumLbn,
    IN ULONG SectorSize
    )

/*++

Routine Description:

    This routine initializes a new Vmcb Structure.  The caller must
    supply the memory for the structure.  This must precede all other calls
    that set/query the volume file mapping.

    If pool is not available this routine will raise a status value
    indicating insufficient resources.

Arguments:

    Vmcb - Supplies a pointer to the volume file structure to initialize.

    PoolType - Supplies the pool type to use when allocating additional
        internal structures.

    MaximumLbn - Supplies the maximum Lbn value that is valid for this
        volume.

    LbSize - Size of a sector on this volume

Return Value:

    None

--*/

{
    BOOLEAN VbnInitialized;
    BOOLEAN LbnInitialized;

    PAGED_CODE();

    DebugTrace(( +1, Dbg, "UdfInitializeVmcb, Vmcb = %08x\n", Vmcb ));

    VbnInitialized = FALSE;
    LbnInitialized = FALSE;

    try {

        //
        //  Initialize the fields in the vmcb structure
        //

        KeInitializeMutex( &Vmcb->Mutex, 0 );

        FsRtlInitializeMcb( &Vmcb->VbnIndexed, PoolType );
        VbnInitialized = TRUE;

        FsRtlInitializeMcb( &Vmcb->LbnIndexed, PoolType );
        LbnInitialized = TRUE;

        Vmcb->MaximumLbn = MaximumLbn;

        Vmcb->SectorSize = SectorSize;

#if VMCB_WRITE_SUPPORT

        //
        //  For the dirty table we store in the table context field the pool
        //  type to use for allocating additional structures
        //

        RtlInitializeGenericTable( &Vmcb->DirtyTable,
                                   PbCompareDirtyVmcb,
                                   PbAllocateDirtyVmcb,
                                   PbDeallocateDirtyVmcb,
                                   (PVOID)PoolType );

#endif // VMCB_WRITE_SUPPORT

    } finally {

        //
        //  If this is an abnormal termination then check if we need to
        //  uninitialize the mcb structures
        //

        if (AbnormalTermination()) {

            if (VbnInitialized) { FsRtlUninitializeMcb( &Vmcb->VbnIndexed ); }
            if (LbnInitialized) { FsRtlUninitializeMcb( &Vmcb->LbnIndexed ); }
        }

        DebugUnwind("UdfInitializeVmcb");
        DebugTrace(( -1, Dbg, "UdfInitializeVmcb -> VOID\n" ));
    }

    //
    //  And return to our caller
    //

    return;
}


VOID
UdfUninitializeVmcb (
    IN PVMCB Vmcb
    )

/*++

Routine Description:

    This routine uninitializes an existing VMCB structure.  After calling
    this routine the input VMCB structure must be re-initialized before
    being used again.

Arguments:

    Vmcb - Supplies a pointer to the VMCB structure to uninitialize.

Return Value:

    None.

--*/

{
    PAGED_CODE();

    DebugTrace(( +1, Dbg, "UdfUninitializeVmcb, Vmcb = %08x\n", Vmcb ));

    //
    //  Unitialize the fields in the Vmcb structure
    //

    FsRtlUninitializeMcb( &Vmcb->VbnIndexed );
    FsRtlUninitializeMcb( &Vmcb->LbnIndexed );

    //
    //  And return to our caller
    //

    DebugTrace(( -1, Dbg, "UdfUninitializeVmcb -> VOID\n" ));

    return;
}


VOID
UdfResetVmcb (
    IN PVMCB Vmcb
    )

/*++

Routine Description:

    This routine resets the mappings in an existing VMCB structure.

Arguments:

    Vmcb - Supplies a pointer to the VMCB structure to reset.

Return Value:

    None.

--*/

{
    PAGED_CODE();

    DebugTrace(( +1, Dbg, "UdfResetVmcb, Vmcb = %08x\n", Vmcb ));

    //
    //  Unitialize the fields in the Vmcb structure
    //

    FsRtlResetLargeMcb( (PLARGE_MCB) &Vmcb->VbnIndexed, TRUE );
    FsRtlResetLargeMcb( (PLARGE_MCB) &Vmcb->LbnIndexed, TRUE );

    //
    //  And return to our caller
    //

    DebugTrace(( -1, Dbg, "UdfResetVmcb -> VOID\n" ));

    return;
}


VOID
UdfSetMaximumLbnVmcb (
    IN PVMCB Vmcb,
    IN ULONG MaximumLbn
    )

/*++

Routine Description:

    This routine sets/resets the maximum allowed LBN for the specified
    Vmcb structure.  The Vmcb structure must already have been initialized
    by calling UdfInitializeVmcb.

Arguments:

    Vmcb - Supplies a pointer to the volume file structure to initialize.

    MaximumLbn - Supplies the maximum Lbn value that is valid for this
        volume.

Return Value:

    None

--*/

{
    PAGED_CODE();

    DebugTrace(( +1, Dbg, "UdfSetMaximumLbnVmcb, Vmcb = %08x\n", Vmcb ));

    //
    //  Set the field
    //

    Vmcb->MaximumLbn = MaximumLbn;

    //
    //  And return to our caller
    //

    DebugTrace(( -1, Dbg, "UdfSetMaximumLbnVmcb -> VOID\n" ));

    return;
}


BOOLEAN
UdfVmcbVbnToLbn (
    IN PVMCB Vmcb,
    IN VBN Vbn,
    IN PLBN Lbn,
    OUT PULONG SectorCount OPTIONAL
    )

/*++

Routine Description:

    This routine translates a VBN to an LBN.

Arguments:

    Vmcb - Supplies the VMCB structure being queried.

    Vbn - Supplies the VBN to translate from.

    Lbn - Receives the LBN mapped by the input Vbn.  This value is only valid
        if the function result is TRUE.

    SectorCount - Optionally receives the number of sectors corresponding
        to the run.

Return Value:

    BOOLEAN - TRUE if he Vbn has a valid mapping and FALSE otherwise.

--*/

{
    BOOLEAN Result;

    DebugTrace(( +1, Dbg, "UdfVmcbVbnToLbn, Vbn = %08x\n", Vbn ));

    //
    //  Now grab the mutex for the vmcb
    //

    (VOID)KeWaitForSingleObject( &Vmcb->Mutex,
                                 Executive,
                                 KernelMode,
                                 FALSE,
                                 (PLARGE_INTEGER) NULL );

    try {

        Result = UdfVmcbLookupMcbEntry( &Vmcb->VbnIndexed,
                                        Vbn,
                                        Lbn,
                                        SectorCount,
                                        NULL );

        DebugTrace(( 0, Dbg, "*Lbn = %08x\n", *Lbn ));

        //
        //  If the returned Lbn is greater than the maximum allowed Lbn
        //  then return FALSE
        //

        if (Result && (*Lbn > Vmcb->MaximumLbn)) {

            try_leave( Result = FALSE );
        }

        //
        //  If the last returned Lbn is greater than the maximum allowed Lbn
        //  then bring in the sector count
        //

        if (Result &&
            ARGUMENT_PRESENT(SectorCount) &&
            (*Lbn+*SectorCount-1 > Vmcb->MaximumLbn)) {

            *SectorCount = (Vmcb->MaximumLbn - *Lbn + 1);
        }

    } finally {

        (VOID) KeReleaseMutex( &Vmcb->Mutex, FALSE );

        DebugUnwind("UdfVmcbVbnToLbn");
        DebugTrace(( -1, Dbg, "UdfVmcbVbnToLbn -> Result = %08x\n", Result ));
    }


    return Result;
}


BOOLEAN
UdfVmcbLbnToVbn (
    IN PVMCB Vmcb,
    IN LBN Lbn,
    OUT PVBN Vbn,
    OUT PULONG SectorCount OPTIONAL
    )

/*++

Routine Description:

    This routine translates an LBN to a VBN.

Arguments:

    Vmcb - Supplies the VMCB structure being queried.

    Lbn - Supplies the LBN to translate from.

    Vbn - Recieves the VBN mapped by the input LBN.  This value is
        only valid if the function result is TRUE.

    SectorCount - Optionally receives the number of sectors corresponding
        to the run.

Return Value:

⌨️ 快捷键说明

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