示例#1
0
BOOLEAN
LfsFindClientNextLsn (
    IN PLFCB Lfcb,
    IN PLfsLCB Lcb,
    OUT PLSN Lsn
    )

/*++

Routine Description:

    This routine will attempt to find the next Lsn to return to a client
    based on the context mode.

Arguments:

    Lfcb - File control block for this log file.

    Lcb - Pointer to the context block for this query operation.

    Lsn - Pointer to store the Lsn found (if any)

Return Value:

    BOOLEAN - TRUE if an Lsn is found, FALSE otherwise.

--*/

{
    LSN NextLsn;
    BOOLEAN NextLsnFound;

    PLFS_CLIENT_RECORD ClientRecord;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsFindClientNextLsn:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Lcb  -> %08lx\n", Lcb );

    ClientRecord = Lfcb->ClientArray + Lcb->ClientId.ClientIndex;

    //
    //  The context block has the last Lsn returned.  If the user wanted
    //  one of the Lsn's in that log header then our job is simple.
    //

    switch (Lcb->ContextMode) {

    case LfsContextUndoNext:
    case LfsContextPrevious:

        NextLsn = (Lcb->ContextMode == LfsContextUndoNext
                   ? Lcb->RecordHeader->ClientUndoNextLsn
                   : Lcb->RecordHeader->ClientPreviousLsn);

        if ( NextLsn.QuadPart == 0 ) {                                                                                 //**** xxEqlZero( NextLsn )

            NextLsnFound = FALSE;

        } else if (LfsVerifyClientLsnInRange( Lfcb, ClientRecord, NextLsn )) {

            BOOLEAN UsaError;

            LfsPinOrMapLogRecordHeader( Lfcb,
                                        NextLsn,
                                        FALSE,
                                        FALSE,
                                        &UsaError,
                                        &Lcb->RecordHeader,
                                        &Lcb->RecordHeaderBcb );

            NextLsnFound = TRUE;

        } else {

            NextLsnFound = FALSE;
        }

        break;

    case LfsContextForward:

        //
        //  We search forward for the next log record for this client.
        //

        NextLsnFound = LfsSearchForwardByClient( Lfcb, Lcb, &NextLsn );
        break;

    default:

        NextLsnFound = FALSE;
        break;
    }

    if (NextLsnFound) {

        *Lsn = NextLsn;
    }

    LfsDebugTrace(  0, Dbg, "NextLsn (Low)     -> %08lx\n", NextLsn.LowPart );
    LfsDebugTrace(  0, Dbg, "NextLsn (High)    -> %08lx\n", NextLsn.HighPart );
    LfsDebugTrace( -1, Dbg, "LfsFindClientNextLsn:  Exit -> %08x\n", NextLsnFound );

    return NextLsnFound;
}
示例#2
0
LSN
LfsQueryLastLsn (
    IN LFS_LOG_HANDLE LogHandle
    )

/*++

Routine Description:

    This routine will return the most recent Lsn for this log record.

Arguments:

    LogHandle - Pointer to private Lfs structure used to identify this
                client.

Return Value:

    LSN - This is the last Lsn assigned in this log file.

--*/

{
    PLCH Lch;

    PLFCB Lfcb;

    LSN LastLsn;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsQueryLastLsn:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Log Handle    -> %08lx\n", LogHandle );

    Lch = (PLCH) LogHandle;

    //
    //  Check that the structure is a valid log handle structure.
    //

    LfsValidateLch( Lch );

    //
    //  Use a try-finally to facilitate cleanup.
    //

    try {

        //
        //  Acquire the log file control block for this log file.
        //

        LfsAcquireLch( Lch );
        Lfcb = Lch->Lfcb;

        //
        //  If the Log file has been closed then refuse access.
        //

        if (Lfcb == NULL) {

            ExRaiseStatus( STATUS_ACCESS_DENIED );
        }

        //
        //  Check that the client Id is valid.
        //

        LfsValidateClientId( Lfcb, Lch );

        //
        //  Copy the last Lsn out of the Lfcb.  If the last Lsn is
        //  does not correspond to a log record, we will return the
        //  zero Lsn.
        //

        if (FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN )) {

            LastLsn = LfsZeroLsn;

        } else {

            LastLsn = Lfcb->RestartArea->CurrentLsn;
        }

    } finally {

        DebugUnwind( LfsQueryLastLsn );

        //
        //  Release the Lfcb if acquired.
        //

        LfsReleaseLch( Lch );

        LfsDebugTrace(  0, Dbg, "Last Lsn (Low)    -> %08lx\n", LastLsn.LowPart );
        LfsDebugTrace(  0, Dbg, "Last Lsn (High)   -> %08lx\n", LastLsn.HighPart );
        LfsDebugTrace( -1, Dbg, "LfsQueryLastLsn:  Exit\n", 0 );
    }

    return LastLsn;
}
示例#3
0
VOID
LfsFindLogRecord (
    IN PLFCB Lfcb,
    IN OUT PLfsLCB Lcb,
    IN LSN Lsn,
    OUT PLFS_RECORD_TYPE RecordType,
    OUT TRANSACTION_ID *TransactionId,
    OUT PLSN UndoNextLsn,
    OUT PLSN PreviousLsn,
    OUT PULONG BufferLength,
    OUT PVOID *Buffer
    )

/*++

Routine Description:

    This routine is called recover a log record for a client.

Arguments:

    Lfcb - Log file control block for this file.

    Lcb - Pointer to the context block to update.

    Lsn - This is the Lsn for the log record.

    RecordType - Supplies the address to store the record type of this
                 log record.

    TransactionId - Supplies the address to store the transaction Id of
                    this log record.

    UndoNextLsn - Supplies the address to store the Undo Next Lsn for this
                  log record.

    PreviousLsn - Supplies the address to store the Previous Lsn for this
                  log record.

    BufferLength - Pointer to address to store the length in bytes of the
                   log record.

    Buffer - Pointer to store the address where the log record data begins.

Return Value:

    None

--*/

{
    PCHAR NewBuffer;
    BOOLEAN UsaError;
    LONGLONG LogRecordLength;
    ULONG PageOffset;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsFindLogRecord:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Lfcb          -> %08lx\n", Lfcb );
    LfsDebugTrace(  0, Dbg, "Context Block -> %08lx\n", Lcb );
    LfsDebugTrace(  0, Dbg, "Lsn (Low)     -> %08lx\n", Lsn.LowPart );

    NewBuffer = NULL;

    //
    //  Use a try-finally to facilitate cleanup.
    //

    try {

        //
        //  Map the record header for this Lsn if we haven't already.
        //

        if (Lcb->RecordHeader == NULL) {

            LfsPinOrMapLogRecordHeader( Lfcb,
                                        Lsn,
                                        FALSE,
                                        FALSE,
                                        &UsaError,
                                        &Lcb->RecordHeader,
                                        &Lcb->RecordHeaderBcb );
        }

        //
        //  We now have the log record desired.  If the Lsn in the
        //  log record doesn't match the desired Lsn then the disk is
        //  corrupt.
        //

        if ( Lsn.QuadPart != Lcb->RecordHeader->ThisLsn.QuadPart ) {                                                   //**** xxNeq( Lsn, Lcb->RecordHeader->ThisLsn )

            ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
        }

        //
        //  Check that the length field isn't greater than the total available space
        //  in the log file.
        //

        LogRecordLength = Lcb->RecordHeader->ClientDataLength + Lfcb->RecordHeaderLength;                              //**** xxFromUlong( Lcb->RecordHeader->ClientDataLength + Lfcb->RecordHeaderLength );

        if ( LogRecordLength >= Lfcb->TotalAvailable ) {                                                               //**** xxGeq( LogRecordLength, Lfcb->TotalAvailable )

            ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
        }

        //
        //  If the entire log record is on this log page, put a pointer to
        //  the log record in the context block.
        //

        if (!FlagOn( Lcb->RecordHeader->Flags, LOG_RECORD_MULTI_PAGE )) {

            //
            //  If client size indicates that we have to go beyond the end of the current
            //  page, we raise an error.
            //

            PageOffset = LfsLsnToPageOffset( Lfcb, Lsn );

            if ((PageOffset + Lcb->RecordHeader->ClientDataLength + Lfcb->RecordHeaderLength)
                > (ULONG)Lfcb->LogPageSize) {

                ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
            }

            Lcb->CurrentLogRecord = LfsAdd2Ptr( Lcb->RecordHeader, LFS_RECORD_HEADER_SIZE, PVOID );
            Lcb->AuxilaryBuffer = FALSE;

        //
        //  Else we copy the data and remember that we allocated a buffer.
        //

        } else {

            NewBuffer = FsRtlAllocatePool( PagedPool, Lcb->RecordHeader->ClientDataLength );

            LfsCopyReadLogRecord( Lfcb,
                                  Lcb->RecordHeader,
                                  NewBuffer );

            Lcb->CurrentLogRecord = NewBuffer;

            Lcb->AuxilaryBuffer = TRUE;

            NewBuffer = NULL;
        }

        //
        //  We need to update the caller's parameters and the context block.
        //

        *RecordType = Lcb->RecordHeader->RecordType;
        *TransactionId = Lcb->RecordHeader->TransactionId;

        *UndoNextLsn = Lcb->RecordHeader->ClientUndoNextLsn;
        *PreviousLsn = Lcb->RecordHeader->ClientPreviousLsn;

        *Buffer = Lcb->CurrentLogRecord;
        *BufferLength = Lcb->RecordHeader->ClientDataLength;

    } finally {

        DebugUnwind( LfsFindLogRecord );

        //
        //  If an error occurred we unpin the record header and the log
        //  We also free the buffer if allocated by us.
        //

        if (NewBuffer != NULL) {

            ExFreePool( NewBuffer );
        }

        LfsDebugTrace(  0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
        LfsDebugTrace(  0, Dbg, "Buffer        -> %08lx\n", *Buffer );
        LfsDebugTrace( -1, Dbg, "LfsFindLogRecord:  Exit\n", 0 );
    }

    return;
}
示例#4
0
VOID
LfsTerminateLogQuery (
    IN LFS_LOG_HANDLE LogHandle,
    IN LFS_LOG_CONTEXT Context
    )

/*++

Routine Description:

    This routine is called when a client has completed his query operation
    and wishes to deallocate any resources acquired by the Lfs to
    perform the log file query.

Arguments:

    LogHandle - Pointer to private Lfs structure used to identify this
                client.

    Context - Supplies the address to store a pointer to the Lfs created
              context structure.

Return Value:

    None

--*/

{
    PLCH Lch;
    PLfsLCB Lcb;

    PLFCB Lfcb;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsTerminateLogQuery:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Log Handle    -> %08lx\n", LogHandle );
    LfsDebugTrace(  0, Dbg, "Context       -> %08lx\n", Context );

    Lch = (PLCH) LogHandle;
    Lcb = (PLfsLCB) Context;

    //
    //  Check that the structure is a valid log handle structure.
    //

    LfsValidateLch( Lch );

    //
    //  Use a try-finally to facilitate cleanup.
    //

    try {

        //
        //  Acquire the log file control block for this log file.
        //

        LfsAcquireLch( Lch );
        Lfcb = Lch->Lfcb;

        //
        //  If the Log file has been closed then refuse access.
        //

        if (Lfcb == NULL) {

            try_return( NOTHING );
        }

        //
        //  Check that the client Id is valid.
        //

        LfsValidateClientId( Lfcb, Lch );

        //
        //  Check that the context structure is valid.
        //

        LfsValidateLcb( Lcb, Lch );

        //
        //  Deallocate the context block.
        //

        LfsDeallocateLcb( Lcb );

    try_exit:  NOTHING;
    } finally {

        DebugUnwind( LfsTerminateLogQuery );

        //
        //  Release the Lfcb if acquired.
        //

        LfsReleaseLch( Lch );

        LfsDebugTrace( -1, Dbg, "LfsTerminateLogQuery:  Exit\n", 0 );
    }

    return;
}
示例#5
0
VOID
LfsReadLogRecord (
    IN LFS_LOG_HANDLE LogHandle,
    IN LSN FirstLsn,
    IN LFS_CONTEXT_MODE ContextMode,
    OUT PLFS_LOG_CONTEXT Context,
    OUT PLFS_RECORD_TYPE RecordType,
    OUT TRANSACTION_ID *TransactionId,
    OUT PLSN UndoNextLsn,
    OUT PLSN PreviousLsn,
    OUT PULONG BufferLength,
    OUT PVOID *Buffer
    )

/*++

Routine Description:

    This routine initiates the query operation.  It returns the log record
    in question and a context structure used by the Lfs to return related
    log records.  The caller specifies what mode of query to use.  He may
    walk backwards through the file by Undo records or all records for
    this client linked through the previous Lsn fields.  He may also look
    forwards through the file for all records for the issuing client.

Arguments:

    LogHandle - Pointer to private Lfs structure used to identify this
                client.

    FirstLsn - Starting record for this query operation.

    ContextMode - Method of query.

    Context - Supplies the address to store a pointer to the Lfs created
              context structure.

    RecordType - Supplies the address to store the record type of this
                 log record.

    TransactionId - Supplies the address to store the transaction Id of
                    this log record.

    UndoNextLsn - Supplies the address to store the Undo Next Lsn for this
                  log record.

    PreviousLsn - Supplies the address to store the Previous Lsn for this
                  log record.

    BufferLength - This is the length of the log data.

    Buffer - This is a pointer to the start of the log data.

Return Value:

    None

--*/

{
    volatile NTSTATUS Status = STATUS_SUCCESS;

    PLFS_CLIENT_RECORD ClientRecord;

    PLCH Lch;

    PLFCB Lfcb;

    PLfsLCB Lcb = NULL;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsReadLogRecord:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Log Handle        -> %08lx\n", LogHandle );
    LfsDebugTrace(  0, Dbg, "First Lsn (Low)   -> %08lx\n", FirstLsn.LowPart );
    LfsDebugTrace(  0, Dbg, "First Lsn (High)  -> %08lx\n", FirstLsn.HighPart );
    LfsDebugTrace(  0, Dbg, "Context Mode      -> %08lx\n", ContextMode );

    Lch = (PLCH) LogHandle;

    //
    //  Check that the context mode is valid.
    //

    switch (ContextMode) {

    case LfsContextUndoNext :
    case LfsContextPrevious :
    case LfsContextForward :

        break;

    default:

        LfsDebugTrace( 0, Dbg, "Invalid context mode -> %08x\n", ContextMode );
        ExRaiseStatus( STATUS_INVALID_PARAMETER );
    }

    //
    //  Check that the structure is a valid log handle structure.
    //

    LfsValidateLch( Lch );

    //
    //  Use a try-except to catch errors.
    //

    try {

        //
        //  Use a try-finally to facilitate cleanup.
        //

        try {

            //
            //  Acquire the log file control block for this log file.
            //

            LfsAcquireLch( Lch );
            Lfcb = Lch->Lfcb;

            //
            //  If the Log file has been closed then refuse access.
            //

            if (Lfcb == NULL) {

                ExRaiseStatus( STATUS_ACCESS_DENIED );
            }

            //
            //  Check that the client Id is valid.
            //

            LfsValidateClientId( Lfcb, Lch );

            //
            //  Check that the given Lsn is in the legal range for this client.
            //

            ClientRecord = LfsAdd2Ptr( Lfcb->ClientArray,
                                    Lch->ClientArrayByteOffset,
                                    PLFS_CLIENT_RECORD );

            if (!LfsVerifyClientLsnInRange( Lfcb, ClientRecord, FirstLsn )) {

                ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
            }

            //
            //  We can give up the Lfcb as we know the Lsn is within the file.
            //

            LfsReleaseLch( Lch );

            //
            //  Allocate and initialize a context structure.
            //

            LfsAllocateLcb( &Lcb );

            LfsInitializeLcb( Lcb,
                              Lch->ClientId,
                              ContextMode );

            //
            //  Find the log record indicated by the given Lsn.
            //

            LfsFindLogRecord( Lfcb,
                              Lcb,
                              FirstLsn,
                              RecordType,
                              TransactionId,
                              UndoNextLsn,
                              PreviousLsn,
                              BufferLength,
                              Buffer );

            //
            //  Update the client's arguments.
            //

            *Context = Lcb;
            Lcb = NULL;

        } finally {

            DebugUnwind( LfsReadLogRecord );

            //
            //  Release the log file control block if held.
            //

            LfsReleaseLch( Lch );

            //
            //  Deallocate the context block if an error occurred.
            //

            if (Lcb != NULL) {

                LfsDeallocateLcb( Lcb );
            }

            LfsDebugTrace(  0, Dbg, "Context       -> %08lx\n", *Context );
            LfsDebugTrace(  0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
            LfsDebugTrace(  0, Dbg, "Buffer        -> %08lx\n", *Buffer );
            LfsDebugTrace( -1, Dbg, "LfsReadLogRecord:  Exit\n", 0 );
        }

    } except (LfsExceptionFilter( GetExceptionInformation() )) {

        Status = GetExceptionCode();
    }

    if (Status != STATUS_SUCCESS) {

        ExRaiseStatus( Status );
    }

    return;
}
示例#6
0
BOOLEAN
LfsSearchForwardByClient (
    IN PLFCB Lfcb,
    IN OUT PLfsLCB Lcb,
    OUT PLSN Lsn
    )

/*++

Routine Description:

    This routine will attempt to find the next Lsn for this client by searching
    forward in the file, looking for a match.

Arguments:

    Lfcb - Pointer to the file control block for this log file.

    Lcb - Pointer to the context block for this query operation.

    Lsn - Points to the location to store the next Lsn if found.

Return Value:

    BOOLEAN - TRUE if another Lsn for this client is found.  FALSE otherwise.

--*/

{
    PLFS_RECORD_HEADER CurrentRecordHeader;
    PBCB CurrentBcb;

    BOOLEAN FoundNextLsn;

    LSN CurrentLsn;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsSearchForwardByClient:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Lcb  -> %08lx\n", Lcb );

    //
    //  The log record header is in the log context
    //  block.  We set the current Bcb to NULL so that we don't
    //  unpin the log record in the context block until we're sure
    //  of success.
    //

    CurrentRecordHeader = Lcb->RecordHeader;

    CurrentBcb = NULL;

    //
    //  We use a try-finally to facilitate cleanup.
    //

    try {

        //
        //  We assume we won't find another Lsn.
        //

        FoundNextLsn = FALSE;

        //
        //  Loop as long as another Lsn can be found.
        //

        while (LfsFindNextLsn( Lfcb, CurrentRecordHeader, &CurrentLsn )) {

            BOOLEAN UsaError;

            //
            //  Unpin the previous log record header.
            //

            if (CurrentBcb != NULL) {

                CcUnpinData( CurrentBcb );
                CurrentBcb = NULL;
            }

            //
            //  Pin the log record header for this Lsn.
            //

            LfsPinOrMapLogRecordHeader( Lfcb,
                                        CurrentLsn,
                                        FALSE,
                                        FALSE,
                                        &UsaError,
                                        &CurrentRecordHeader,
                                        &CurrentBcb );

            //
            //  If the client values match, then we update the
            //  context block and exit.
            //

            if (LfsClientIdMatch( &CurrentRecordHeader->ClientId,
                                  &Lcb->ClientId )
                && CurrentRecordHeader->RecordType == LfsClientRecord) {

                //
                //  We remember this one.
                //

                Lcb->RecordHeader = CurrentRecordHeader;
                Lcb->RecordHeaderBcb = CurrentBcb;

                CurrentBcb = NULL;
                FoundNextLsn = TRUE;

                *Lsn = CurrentLsn;
                break;
            }
        }

    } finally {

        DebugUnwind( LfsSearchForwardByClient );

        //
        //  Unpin any log record headers still pinned for no reason.
        //

        if (CurrentBcb != NULL) {

            CcUnpinData( CurrentBcb );
        }

        LfsDebugTrace(  0, Dbg, "NextLsn (Low)     -> %08lx\n", Lsn->LowPart );
        LfsDebugTrace(  0, Dbg, "NextLsn (High)    -> %08lx\n", Lsn->HighPart );
        LfsDebugTrace( -1, Dbg, "LfsSearchForwardByClient:  Exit -> %08x\n", FoundNextLsn );
    }

    return FoundNextLsn;
}
示例#7
0
BOOLEAN
LfsReadNextLogRecord (
    IN LFS_LOG_HANDLE LogHandle,
    IN OUT LFS_LOG_CONTEXT Context,
    OUT PLFS_RECORD_TYPE RecordType,
    OUT TRANSACTION_ID *TransactionId,
    OUT PLSN UndoNextLsn,
    OUT PLSN PreviousLsn,
    OUT PLSN Lsn,
    OUT PULONG BufferLength,
    OUT PVOID *Buffer
    )

/*++

Routine Description:

    This routine is called to continue a query operation.  The Lfs uses
    private information stored in the context structure to determine the
    next log record to return to the caller.

Arguments:

    LogHandle - Pointer to private Lfs structure used to identify this
                client.

    Context - Supplies the address to store a pointer to the Lfs created
              context structure.

    Lsn - Lsn for this log record.

    RecordType - Supplies the address to store the record type of this
                 log record.

    TransactionId - Supplies the address to store the transaction Id of
                    this log record.

    UndoNextLsn - Supplies the address to store the Undo Next Lsn for this
                  log record.

    PreviousLsn - Supplies the address to store the Previous Lsn for this
                  log record.

    BufferLength - This is the length of the log data.

    Buffer - This is a pointer to the start of the log data.

Return Value:

    None

--*/

{
    volatile NTSTATUS Status = STATUS_SUCCESS;

    PLCH Lch;

    PLFCB Lfcb;

    PLfsLCB Lcb;

    BOOLEAN FoundNextLsn;

    BOOLEAN UnwindRememberLcbFields;
    PBCB UnwindRecordHeaderBcb;
    PLFS_RECORD_HEADER UnwindRecordHeader;
    PVOID UnwindCurrentLogRecord;
    BOOLEAN UnwindAuxilaryBuffer;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsReadNextLogRecord:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Log Handle    -> %08lx\n", LogHandle );
    LfsDebugTrace(  0, Dbg, "Context       -> %08lx\n", Context );

    FoundNextLsn = FALSE;

    UnwindRememberLcbFields = FALSE;

    Lch = (PLCH) LogHandle;
    Lcb = (PLfsLCB) Context;

    //
    //  Check that the structure is a valid log handle structure.
    //

    LfsValidateLch( Lch );

    //
    //  Use a try-except to catch errors.
    //

    try {

        //
        //  Use a try-finally to facilitate cleanup.
        //

        try {

            //
            //  Acquire the log file control block for this log file.
            //

            LfsAcquireLch( Lch );
            Lfcb = Lch->Lfcb;

            //
            //  If the Log file has been closed then refuse access.
            //

            if (Lfcb == NULL) {

                ExRaiseStatus( STATUS_ACCESS_DENIED );
            }

            //
            //  Check that the client Id is valid.
            //

            LfsValidateClientId( Lfcb, Lch );

            //
            //  Check that the context structure is valid.
            //

            LfsValidateLcb( Lcb, Lch );

            //
            //  Remember any context fields to be overwritten.
            //

            UnwindRememberLcbFields = TRUE;

            UnwindRecordHeaderBcb = Lcb->RecordHeaderBcb;
            Lcb->RecordHeaderBcb = NULL;

            UnwindRecordHeader = Lcb->RecordHeader;
            UnwindCurrentLogRecord = Lcb->CurrentLogRecord;

            UnwindAuxilaryBuffer = Lcb->AuxilaryBuffer;
            Lcb->AuxilaryBuffer = FALSE;

            //
            //  Find the next Lsn number based on the current Lsn number in
            //  the context block.
            //

            if (LfsFindClientNextLsn( Lfcb, Lcb, Lsn )) {

                //
                //  We can give up the Lfcb as we know the Lsn is within the file.
                //

                LfsReleaseLfcb( Lfcb );

                //
                //  Cleanup the context block so we can do the next search.
                //

                Lcb->CurrentLogRecord = NULL;
                Lcb->AuxilaryBuffer = FALSE;

                //
                //  Perform the work of getting the log record.
                //

                LfsFindLogRecord( Lfcb,
                                  Lcb,
                                  *Lsn,
                                  RecordType,
                                  TransactionId,
                                  UndoNextLsn,
                                  PreviousLsn,
                                  BufferLength,
                                  Buffer );

                FoundNextLsn = TRUE;
            }

        } finally {

            DebugUnwind( LfsReadNextLogRecord );

            //
            //  If we exited due to an error, we have to restore the context
            //  block.
            //

            if (UnwindRememberLcbFields) {

                if (AbnormalTermination()) {

                    //
                    //  If the record header in the context block is not
                    //  the same as we started with.  Then we unpin that
                    //  data.
                    //

                    if (Lcb->RecordHeaderBcb != NULL) {

                        CcUnpinData( Lcb->RecordHeaderBcb );

                    }

                    if (Lcb->CurrentLogRecord != NULL
                        && Lcb->AuxilaryBuffer == TRUE) {

                        ExFreePool( Lcb->CurrentLogRecord );
                    }

                    Lcb->RecordHeaderBcb = UnwindRecordHeaderBcb;
                    Lcb->RecordHeader = UnwindRecordHeader;
                    Lcb->CurrentLogRecord = UnwindCurrentLogRecord;
                    Lcb->AuxilaryBuffer = UnwindAuxilaryBuffer;

                //
                //  Otherwise, if we have successfully found the next Lsn,
                //  we free up any resources being held from the previous search.
                //

                } else if (FoundNextLsn ) {

                    if (UnwindRecordHeaderBcb != NULL) {

                        CcUnpinData( UnwindRecordHeaderBcb );
                    }

                    if (UnwindCurrentLogRecord != NULL
                        && UnwindAuxilaryBuffer == TRUE) {

                        ExFreePool( UnwindCurrentLogRecord );
                    }

                //
                //  Restore the Bcb and auxilary buffer field for the final
                //  cleanup.
                //

                } else {

                    if (UnwindRecordHeaderBcb != NULL) {

                        if (Lcb->RecordHeaderBcb != NULL) {

                            CcUnpinData( UnwindRecordHeaderBcb );

                        } else {

                            Lcb->RecordHeaderBcb = UnwindRecordHeaderBcb;
                        }
                    }

                    if (UnwindAuxilaryBuffer) {

                        if (Lcb->CurrentLogRecord == UnwindCurrentLogRecord) {

                            Lcb->AuxilaryBuffer = TRUE;

                        } else {

                            ExFreePool( UnwindCurrentLogRecord );
                        }
                    }
                }
            }

            //
            //  Release the log file control block if held.
            //

            LfsReleaseLch( Lch );

            LfsDebugTrace(  0, Dbg, "Lsn (Low)     -> %08lx\n", Lsn->LowPart );
            LfsDebugTrace(  0, Dbg, "Lsn (High)    -> %08lx\n", Lsn->HighPart );
            LfsDebugTrace(  0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
            LfsDebugTrace(  0, Dbg, "Buffer        -> %08lx\n", *Buffer );
            LfsDebugTrace( -1, Dbg, "LfsReadNextLogRecord:  Exit\n", 0 );
        }

    } except (LfsExceptionFilter( GetExceptionInformation() )) {

        Status = GetExceptionCode();
    }

    if (Status != STATUS_SUCCESS) {

        ExRaiseStatus( Status );
    }

    return FoundNextLsn;
}
示例#8
0
VOID
LfsFindOldestClientLsn (
    IN PLFS_RESTART_AREA RestartArea,
    IN PLFS_CLIENT_RECORD ClientArray,
    OUT PLSN OldestLsn
    )

/*++

Routine Description:

    This routine walks through the active clients to determine the oldest
    Lsn the system must maintain.

Arguments:

    RestartArea - This is the Restart Area to examine.

    ClientArray - This is the start of the client data array.

    OldestLsn - We store the oldest Lsn we find in this value.  It is
        initialized with a starting value, we won't return a more recent
        Lsn.

Return Value:

    None.

--*/

{
    USHORT NextClient;

    PLFS_CLIENT_RECORD ClientBlock;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsFindOldestClientLsn:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "RestartArea       -> %08lx\n", RestartArea );
    LfsDebugTrace(  0, Dbg, "Base Lsn (Low)    -> %08lx\n", BaseLsn.LowPart );
    LfsDebugTrace(  0, Dbg, "Base Lsn (High)   -> %08lx\n", BaseLsn.HighPart );

    //
    //  Take the first client off the in use list.
    //

    NextClient = RestartArea->ClientInUseList;

    //
    //  While there are more clients, compare their oldest Lsn with the
    //  current oldest.
    //

    while (NextClient != LFS_NO_CLIENT) {

        ClientBlock = ClientArray + NextClient;

        //
        //  We ignore this block if it's oldest Lsn is 0.
        //

        if (( ClientBlock->OldestLsn.QuadPart != 0 )
            && ( ClientBlock->OldestLsn.QuadPart < OldestLsn->QuadPart )) {

            *OldestLsn = ClientBlock->OldestLsn;
        }

        //
        //  Try the next client block.
        //

        NextClient = ClientBlock->NextClient;
    }

    LfsDebugTrace(  0, Dbg, "OldestLsn (Low)   -> %08lx\n", BaseLsn.LowPart );
    LfsDebugTrace(  0, Dbg, "OldestLsn (High)  -> %08lx\n", BaseLsn.HighPart );
    LfsDebugTrace( -1, Dbg, "LfsFindOldestClientLsn:  Exit\n", 0 );

    return;
}
示例#9
0
VOID
LfsWriteLfsRestart (
    IN PLFCB Lfcb,
    IN ULONG ThisRestartSize,
    IN BOOLEAN WaitForIo
    )

/*++

Routine Description:

    This routine puts the Lfs restart area on the queue of operations to
    write to the file.  We do this by allocating a second restart area
    and attaching it to the Lfcb.  We also allocate a buffer control
    block to use for this write.  We look at the WaitForIo boolean to
    determine whether this thread can perform the I/O.  This also indicates
    whether this thread gives up the Lfcb.

Arguments:

    Lfcb - A pointer to the log file control block for this operation.

    ThisRestartSize - This is the size to use for the restart area.

    WaitForIo - Indicates if this thread is to perform the work.

Return Value:

    None.

--*/

{
    PLBCB NewLbcb = NULL;
    PLFS_RESTART_AREA NewRestart = NULL;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsWriteLfsRestart:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Lfcb          -> %08lx\n", Lfcb );
    LfsDebugTrace(  0, Dbg, "Write Chkdsk  -> %04x\n", WriteChkdsk );
    LfsDebugTrace(  0, Dbg, "Restart Size  -> %08lx\n", ThisRestartSize );
    LfsDebugTrace(  0, Dbg, "WaitForIo     -> %08lx\n", WaitForIo );

    //
    //  Use a try-finally to facilitate cleanup.
    //

    __try {

        PLBCB ActiveLbcb;

        //
        //  We allocate another restart area and
        //  copy the current area into it.  Attach the new area to the Lfcb.
        //

        LfsAllocateRestartArea( &NewRestart, ThisRestartSize );

        //
        //  We allocate a Lbcb structure and update the values to
        //  reflect this restart area.
        //

        LfsAllocateLbcb( Lfcb, &NewLbcb );
        SetFlag( NewLbcb->LbcbFlags, LBCB_RESTART_LBCB );

        //
        //  If this is the second page, then add a system page to the offset.
        //

        if (!Lfcb->InitialRestartArea) {

            NewLbcb->FileOffset = Lfcb->SystemPageSize + NewLbcb->FileOffset;
        }

        (ULONG)NewLbcb->Length = ThisRestartSize;

        NewLbcb->PageHeader = (PVOID) Lfcb->RestartArea;

        //
        //  Lets put the current lsn in the Lbcb.
        //

        NewLbcb->LastEndLsn = NewLbcb->LastLsn = Lfcb->NextRestartLsn;
        Lfcb->NextRestartLsn.QuadPart = 1 + Lfcb->NextRestartLsn.QuadPart;

        //
        //  Copy the existing restart area into the new area.
        //

        RtlCopyMemory( NewRestart, Lfcb->RestartArea, ThisRestartSize );
        Lfcb->RestartArea = NewRestart;

        Lfcb->ClientArray = LfsAdd2Ptr( NewRestart, Lfcb->ClientArrayOffset, PLFS_CLIENT_RECORD );

        NewRestart = NULL;

        //
        //  Update the Lfcb to indicate that the other restart area
        //  on the disk is to be used.
        //

        Lfcb->InitialRestartArea = !Lfcb->InitialRestartArea;

        //
        //  Add this Lbcb to the end of the workque and flush to that point.
        //

        InsertTailList( &Lfcb->LbcbWorkque, &NewLbcb->WorkqueLinks );

        //
        //  If we don't support a packed log file then we need to make
        //  sure that all file records written out ahead of this
        //  restart area make it out to disk and we don't add anything
        //  to this page.
        //

        if (!FlagOn( Lfcb->Flags, LFCB_PACK_LOG )
            && !IsListEmpty( &Lfcb->LbcbActive )) {

            ActiveLbcb = CONTAINING_RECORD( Lfcb->LbcbActive.Flink,
                                            LBCB,
                                            ActiveLinks );

            if (FlagOn( ActiveLbcb->LbcbFlags, LBCB_NOT_EMPTY )) {

                RemoveEntryList( &ActiveLbcb->ActiveLinks );
                ClearFlag( ActiveLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE );
            }
        }

        if (WaitForIo) {

            LfsFlushLbcb( Lfcb, NewLbcb );
        }

    } __finally {

        DebugUnwind( LfsWriteLfsRestart );

        if (NewRestart != NULL) {

            ExFreePool( NewRestart );
        }

        LfsDebugTrace( -1, Dbg, "LfsWriteLfsRestart:  Exit\n", 0 );
    }

    return;
}
示例#10
0
PLBCB
LfsGetLbcb (
    IN PLFCB Lfcb
    )

/*++

Routine Description:

    This routine is called to add a Lbcb to the active queue.

Arguments:

    Lfcb - This is the file control block for the log file.

Return Value:

    PLBCB - Pointer to the Lbcb allocated.

--*/

{
    PLBCB Lbcb = NULL;
    PVOID PageHeader;
    PBCB PageHeaderBcb = NULL;

    BOOLEAN WrappedOrUsaError;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsGetLbcb:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Lfcb      -> %08lx\n", Lfcb );

    //
    //  Use a try-finally to facilitate cleanup.
    //

    try {

        //
        //  Pin the desired record page.
        //

        LfsPreparePinWriteData( Lfcb,
                                Lfcb->NextLogPage,
                                (ULONG)Lfcb->LogPageSize,
                                &PageHeader,
                                &PageHeaderBcb );

        //
        //  Put our signature into the page so we won't fail if we
        //  see a previous 'BAAD' signature.
        //

        *((PULONG) PageHeader) = LFS_SIGNATURE_RECORD_PAGE_ULONG;

        //
        //  Now allocate an Lbcb.
        //

        LfsAllocateLbcb( Lfcb, &Lbcb );

        //
        //  If we are at the beginning of the file we test that the
        //  sequence number won't wrap to 0.
        //

        if (!FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN | LFCB_REUSE_TAIL )
            && ( Lfcb->NextLogPage == Lfcb->FirstLogPage )) {

            Lfcb->SeqNumber = Lfcb->SeqNumber + 1;

            //
            //  If the sequence number is going from 0 to 1, then
            //  this is the first time the log file has wrapped.  We want
            //  to remember this because it means that we can now do
            //  large spiral writes.
            //

            if (Int64ShllMod32( Lfcb->SeqNumber, Lfcb->FileDataBits ) == 0) {

                LfsDebugTrace( 0, Dbg, "Log sequence number about to wrap:  Lfcb -> %08lx\n", Lfcb );
                KeBugCheck( FILE_SYSTEM );
            }

            //
            //  If this number is greater or equal to  the wrap sequence number in
            //  the Lfcb, set the wrap flag in the Lbcb.
            //

            if (!FlagOn( Lfcb->Flags, LFCB_LOG_WRAPPED )
                && ( Lfcb->SeqNumber >= Lfcb->SeqNumberForWrap )) {

                SetFlag( Lbcb->LbcbFlags, LBCB_LOG_WRAPPED );
                SetFlag( Lfcb->Flags, LFCB_LOG_WRAPPED );
            }
        }

        //
        //  Now initialize the rest of the Lbcb fields.
        //

        Lbcb->FileOffset = Lfcb->NextLogPage;
        Lbcb->SeqNumber = Lfcb->SeqNumber;
        Lbcb->BufferOffset = Lfcb->LogPageDataOffset;

        //
        //  Store the next page in the Lfcb.
        //

        LfsNextLogPageOffset( Lfcb,
                              Lfcb->NextLogPage,
                              &Lfcb->NextLogPage,
                              &WrappedOrUsaError );

        Lbcb->Length = Lfcb->LogPageSize;
        Lbcb->PageHeader = PageHeader;
        Lbcb->LogPageBcb = PageHeaderBcb;

        Lbcb->ResourceThread = ExGetCurrentResourceThread();

        //
        //  If we are reusing a previous page then set a flag in
        //  the Lbcb to indicate that we should flush a copy
        //  first.
        //

        if (FlagOn( Lfcb->Flags, LFCB_REUSE_TAIL )) {

            SetFlag( Lbcb->LbcbFlags, LBCB_FLUSH_COPY );
            ClearFlag( Lfcb->Flags, LFCB_REUSE_TAIL );

            (ULONG)Lbcb->BufferOffset = Lfcb->ReusePageOffset;

            Lbcb->Flags = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Flags;
            Lbcb->LastLsn = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Copy.LastLsn;
            Lbcb->LastEndLsn = ((PLFS_RECORD_PAGE_HEADER) PageHeader)->Header.Packed.LastEndLsn;
        }

        //
        //  Put the Lbcb on the active queue
        //

        InsertTailList( &Lfcb->LbcbActive, &Lbcb->ActiveLinks );

        SetFlag( Lbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE );

    } finally {

        DebugUnwind( LfsGetLbcb );

        //
        //  If an error occurred, we need to clean up any blocks which
        //  have not been added to the active queue.
        //

        if (AbnormalTermination()) {

            if (Lbcb != NULL) {

                LfsDeallocateLbcb( Lfcb, Lbcb );
                Lbcb = NULL;
            }

            //
            //  Unpin the system page if pinned.
            //

            if (PageHeaderBcb != NULL) {

                CcUnpinData( PageHeaderBcb );
            }
        }

        LfsDebugTrace( -1, Dbg, "LfsGetLbcb:  Exit\n", 0 );
    }

    return Lbcb;
}
示例#11
0
VOID
LfsFlushLbcb (
    IN PLFCB Lfcb,
    IN PLBCB Lbcb
    )

/*++

Routine Description:

    This routine is called to make sure the data within an Lbcb makes it out
    to disk.  The Lbcb must either already be in the workque or it must be
    a restart Lbcb.

Arguments:

    Lfcb - This is the file control block for the log file.

    Lbcb - This is the Lbcb to flush.

Return Value:

    None.

--*/

{
    LSN LastLsn;
    PLSN FlushedLsn;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsFlushLbcb:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Lfcb      -> %08lx\n", Lfcb );
    LfsDebugTrace(  0, Dbg, "Lbcb      -> %08lx\n", Lbcb );

    LastLsn = Lbcb->LastEndLsn;

    //
    //  If this is a restart area we use the restart counter in the
    //  Lfcb.  Otherwise we can use the LastFlushedLsn value in the
    //  Lfcb.  This way we can determine that the Lbcb that interests
    //  us has made it out to disk.
    //

    if (LfsLbcbIsRestart( Lbcb )) {

        FlushedLsn = &Lfcb->LastFlushedRestartLsn;

    } else {

        FlushedLsn = &Lfcb->LastFlushedLsn;
    }

    //
    //  We loop here until the desired Lsn has made it to disk.
    //  If we are able to do the I/O, we will perform it.
    //

    do {

        //
        //
        //  If we can do the Io, call down to flush the Lfcb.
        //

        if (Lfcb->LfsIoState == LfsNoIoInProgress) {

            LfsFlushLfcb( Lfcb, Lbcb );

            break;
        }

        //
        //  Otherwise we release the Lfcb and immediately wait on the event.
        //

        LfsReleaseLfcb( Lfcb );

        KeWaitForSingleObject( &Lfcb->Sync->Event,
                               Executive,
                               KernelMode,
                               FALSE,
                               NULL );

        LfsAcquireLfcb( Lfcb );

    } while ( LastLsn.QuadPart > FlushedLsn->QuadPart );

    LfsDebugTrace( -1, Dbg, "LfsFlushLbcb:  Exit\n", 0 );
    return;
}
示例#12
0
VOID
LfsFlushToLsnPriv (
    IN PLFCB Lfcb,
    IN LSN Lsn
    )

/*++

Routine Description:

    This routine is the worker routine which performs the work of flushing
    a particular Lsn to disk.  This routine is always called with the
    Lfcb acquired.  This routines makes no guarantee about whether the Lfcb
    is acquired on exit.

Arguments:

    Lfcb - This is the file control block for the log file.

    Lsn - This is the Lsn to flush to disk.

Return Value:

    None.

--*/

{
    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsFlushToLsnPriv:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Lfcb          -> %08lx\n", Lfcb );
    LfsDebugTrace(  0, Dbg, "Lsn (Low)     -> %08lx\n", Lsn.LowPart );
    LfsDebugTrace(  0, Dbg, "Lsn (High)    -> %08lx\n", Lsn.HighPart );

    //
    //  We check if the Lsn is in the valid range.  Raising an
    //  exception if not.
    //

    if ( Lsn.QuadPart > Lfcb->RestartArea->CurrentLsn.QuadPart ) {

        LfsDebugTrace( 0, Dbg, "Lsn is not in the file\n", 0 );
        ExRaiseStatus( STATUS_INVALID_PARAMETER );
    }

    //
    //  If the Lsn has already been flushed we are done.
    //  Otherwise we need to look through the workqueues and the
    //  active queue.
    //

    if ( Lsn.QuadPart > Lfcb->LastFlushedLsn.QuadPart ) {

        PLIST_ENTRY ThisEntry;
        PLBCB ThisLbcb;

        //
        //  Check the workqueue first.  We are looking for the last
        //  buffer block of a log page block which contains this
        //  Lsn.
        //

        ThisEntry = Lfcb->LbcbWorkque.Flink;

        //
        //  We keep looping.
        //

        while (TRUE) {

            ThisLbcb = CONTAINING_RECORD( ThisEntry,
                                          LBCB,
                                          WorkqueLinks );

            //
            //  We pass over any restart areas.  We also skip any
            //  Lbcb's which do not contain the end of a log record.
            //

            if (!LfsLbcbIsRestart( ThisLbcb )
                && FlagOn( ThisLbcb->Flags, LOG_PAGE_LOG_RECORD_END )) {

                //
                //  If the last complete Lsn in this Lbcb is greater or equal
                //  to the desired Lsn, we exit the loop.
                //

                if ( ThisLbcb->LastEndLsn.QuadPart >= Lsn.QuadPart ) {

                    break;
                }
            }

            //
            //  Otherwise move to the next Lbcb.
            //

            ThisEntry = ThisEntry->Flink;

            ASSERT( ThisEntry != &Lfcb->LbcbWorkque );
        }

        //
        //  If we are not supporting a packed log file and this Lbcb is from
        //  the active queue, we need to check that losing the tail of the
        //  will not swallow up any of our reserved space.
        //

        if (!FlagOn( Lfcb->Flags, LFCB_PACK_LOG )
            && FlagOn( ThisLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE )) {

            LONGLONG CurrentAvail;
            LONGLONG UnusedBytes;

            //
            //  Find the unused bytes.
            //

            UnusedBytes = 0;

            LfsCurrentAvailSpace( Lfcb,
                                  &CurrentAvail,
                                  (PULONG)&UnusedBytes );

            CurrentAvail = CurrentAvail - Lfcb->TotalUndoCommitment;

            if ( UnusedBytes > CurrentAvail ) {

                LfsDebugTrace( -1, Dbg, "Have to preserve these bytes for possible aborts\n", 0 );

                ExRaiseStatus( STATUS_LOG_FILE_FULL );
            }

            //
            //  We want to make sure we don't write any more data into this
            //  page.  Remove this from the active queue.
            //

            RemoveEntryList( &ThisLbcb->ActiveLinks );
            ClearFlag( ThisLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE );
        }

        //
        //  We now have the Lbcb we want to flush to disk.
        //

        LfsFlushLbcb( Lfcb, ThisLbcb );
    }

    LfsDebugTrace( -1, Dbg, "LfsFlushToLsnPriv:  Exit\n", 0 );

    return;
}
示例#13
0
VOID
LfsSetBaseLsnPriv (
    IN PLFCB Lfcb,
    IN PLFS_CLIENT_RECORD ClientRecord,
    IN LSN BaseLsn
    )

/*++

Routine Description:

    This worker routine is called internally by Lfs to modify the
    oldest Lsn a client expects to need during restart.  The Lfs is allowed to
    reuse any part of the circular log file which logically precedes
    this Lsn.  A client may only specify a Lsn which follows the previous
    Lsn specified by this client.

Arguments:

    Lfcb - Log context block for this file.

    ClientRecord - For the client whose base Lsn is being modified.

    BaseLsn - This is the oldest Lsn the client may require during a
              restart.

Return Value:

    None.

--*/

{
    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsSetBaseLsn:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Lfcb              -> %08lx\n", Lfcb );
    LfsDebugTrace(  0, Dbg, "Base Lsn (Low)    -> %08lx\n", BaseLsn.LowPart );
    LfsDebugTrace(  0, Dbg, "Base Lsn (High)   -> %08lx\n", BaseLsn.HighPart );

    //
    //  We only proceed if the client is moving forward in the file.
    //

    if ( BaseLsn.QuadPart > Lfcb->OldestLsn.QuadPart ) {                                                               //**** xxGtr( BaseLsn, Lfcb->OldestLsn )

        if ( BaseLsn.QuadPart > ClientRecord->OldestLsn.QuadPart ) {                                                   //**** xxGtr( BaseLsn, ClientRecord->OldestLsn )

            ClientRecord->OldestLsn = BaseLsn;
        }

        Lfcb->OldestLsn = BaseLsn;

        //
        //  We walk through all the active clients and find the new
        //  oldest Lsn for the log file.
        //

        LfsFindOldestClientLsn( Lfcb->RestartArea,
                                Lfcb->ClientArray,
                                &Lfcb->OldestLsn );

        Lfcb->OldestLsnOffset = LfsLsnToFileOffset( Lfcb, Lfcb->OldestLsn );
        ClearFlag( Lfcb->Flags, LFCB_NO_OLDEST_LSN );

        LfsFindCurrentAvail( Lfcb );
    }

    LfsDebugTrace( -1, Dbg, "LfsSetBaseLsnPriv:  Exit\n", 0 );

    return;
}
示例#14
0
VOID
LfsReadRestartArea (
    IN LFS_LOG_HANDLE LogHandle,
    IN OUT PULONG BufferLength,
    IN PVOID Buffer,
    OUT PLSN Lsn
    )

/*++

Routine Description:

    This routine is called by the client when he wishes to read his restart
    area in the log file.

Arguments:

    LogHandle - Pointer to private Lfs structure used to identify this
                client.

    BufferLength - On entry it is the length of the user buffer.  On exit
                   it is the size of the data stored in the buffer.

    Buffer - Pointer to the buffer where the client restart data is to be
             copied.

    Lsn - This is the Lsn for client restart area.

Return Value:

    None

--*/

{
    volatile NTSTATUS Status = STATUS_SUCCESS;

    BOOLEAN UsaError;

    PLCH Lch;

    PLFS_CLIENT_RECORD ClientRecord;

    PLFS_RECORD_HEADER RecordHeader;
    PBCB RecordHeaderBcb;

    PLFCB Lfcb;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsReadRestartArea:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Log Handle    -> %08lx\n", LogHandle );
    LfsDebugTrace(  0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
    LfsDebugTrace(  0, Dbg, "Buffer        -> %08lx\n", Buffer );

    RecordHeaderBcb = NULL;

    Lch = (PLCH) LogHandle;

    //
    //  Check that the structure is a valid log handle structure.
    //

    LfsValidateLch( Lch );

    //
    //  Use a try-except to catch errors.
    //

    try {

        //
        //  Use a try-finally to facilitate cleanup.
        //

        try {

            //
            //  Acquire the log file control block for this log file.
            //

            LfsAcquireLch( Lch );
            Lfcb = Lch->Lfcb;

            //
            //  If the Log file has been closed then refuse access.
            //

            if (Lfcb == NULL) {

                ExRaiseStatus( STATUS_ACCESS_DENIED );
            }

            //
            //  Check that the client Id is valid.
            //

            LfsValidateClientId( Lfcb, Lch );

            ClientRecord = LfsAdd2Ptr( Lfcb->ClientArray,
                                    Lch->ClientArrayByteOffset,
                                    PLFS_CLIENT_RECORD );

            //
            //  If the client doesn't have a restart area, go ahead and exit
            //  now.
            //

            if ( ClientRecord->ClientRestartLsn.QuadPart == 0 ) {                                                      //**** xxEqlZero( ClientRecord->ClientRestartLsn )

                //
                //  We show there is no restart area by returning a length
                //  of zero.  We also set the Lsn value to zero so that
                //  we can catch it if the user tries to use the Lsn.
                //

                LfsDebugTrace( 0, Dbg, "No client restart area exists\n", 0 );

                *BufferLength = 0;
                *Lsn = LfsZeroLsn;

                try_return( NOTHING );
            }

            //
            //  Release the Lfcb as we won't be modifying any fields in it.
            //

            LfsReleaseLfcb( Lfcb );

            //
            //  Pin the log record for this Lsn.
            //

            LfsPinOrMapLogRecordHeader( Lfcb,
                                        ClientRecord->ClientRestartLsn,
                                        FALSE,
                                        FALSE,
                                        &UsaError,
                                        &RecordHeader,
                                        &RecordHeaderBcb );

            //
            //  If the Lsn values don't match, then the disk is corrupt.
            //

            if ( ClientRecord->ClientRestartLsn.QuadPart != RecordHeader->ThisLsn.QuadPart ) {                         //**** xxNeq( ClientRecord->ClientRestartLsn, RecordHeader->ThisLsn )

                ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR );
            }


            //
            //  Check that the user's buffer is big enough to hold the restart
            //  data.  We raise an error status for this error.
            //

            if (RecordHeader->ClientDataLength > *BufferLength) {

                LfsDebugTrace( 0, Dbg, "Client buffer is too small\n", 0 );
                *BufferLength = 0;
                *Lsn = LfsZeroLsn;
                ExRaiseStatus( STATUS_BUFFER_OVERFLOW );
            }


            //
            //  Use the cache manager to copy the data into the user's buffer.
            //

            LfsCopyReadLogRecord( Lfcb,
                                  RecordHeader,
                                  Buffer );

            //
            //  Pass the length and the Lsn of the restart area back to the
            //  caller.
            //

            *BufferLength = RecordHeader->ClientDataLength;
            *Lsn = RecordHeader->ThisLsn;

        try_exit: NOTHING;
        } finally {

            DebugUnwind( LfsReadRestartArea );

            //
            //  Release the log file control block if held.
            //

            LfsReleaseLch( Lch );

            //
            //  Unpin the log record header for the client restart if pinned.
            //

            if (RecordHeaderBcb != NULL) {

                CcUnpinData( RecordHeaderBcb );
            }

            LfsDebugTrace(  0, Dbg, "Lsn (Low)     -> %08lx\n", Lsn->LowPart );
            LfsDebugTrace(  0, Dbg, "Lsn (High)    -> %08lx\n", Lsn->HighPart );
            LfsDebugTrace(  0, Dbg, "Buffer Length -> %08lx\n", *BufferLength );
            LfsDebugTrace( -1, Dbg, "LfsReadRestartArea:  Exit\n", 0 );
        }

    } except (LfsExceptionFilter( GetExceptionInformation() )) {

        Status = GetExceptionCode();
    }

    if (Status != STATUS_SUCCESS) {

        ExRaiseStatus( Status );
    }

    return;
}
示例#15
0
VOID
LfsSetBaseLsn (
    IN LFS_LOG_HANDLE LogHandle,
    IN LSN BaseLsn
    )

/*++

Routine Description:

    This routine is called by the client to notify the log service of the
    oldest Lsn he expects to need during restart.  The Lfs is allowed to
    reuse any part of the circular log file which logically precedes
    this Lsn.  A client may only specify a Lsn which follows the previous
    Lsn specified by this client.

Arguments:

    LogHandle - Pointer to private Lfs structure used to identify this
                client.

    BaseLsn - This is the oldest Lsn the client may require during a
              restart.

Return Value:

    None

--*/

{
    volatile NTSTATUS Status = STATUS_SUCCESS;

    PLCH Lch;

    PLFCB Lfcb;

    PLFS_CLIENT_RECORD ClientRecord;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsSetBaseLsn:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Log Handle        -> %08lx\n", LogHandle );
    LfsDebugTrace(  0, Dbg, "Base Lsn (Low)    -> %08lx\n", BaseLsn.LowPart );
    LfsDebugTrace(  0, Dbg, "Base Lsn (High)   -> %08lx\n", BaseLsn.HighPart );

    Lch = (PLCH) LogHandle;

    //
    //  Check that the structure is a valid log handle structure.
    //

    LfsValidateLch( Lch );

    //
    //  Use a try-except to catch errors.
    //

    try {

        //
        //  Use a try-finally to facilitate cleanup.
        //

        try {

            //
            //  Acquire the log file control block for this log file.
            //

            LfsAcquireLch( Lch );
            Lfcb = Lch->Lfcb;

            //
            //  If the Log file has been closed then refuse access.
            //

            if (Lfcb == NULL) {

                ExRaiseStatus( STATUS_ACCESS_DENIED );
            }

            //
            //  Check that the client Id is valid.
            //

            LfsValidateClientId( Lfcb, Lch );

            ClientRecord = LfsAdd2Ptr( Lfcb->ClientArray,
                                    Lch->ClientArrayByteOffset,
                                    PLFS_CLIENT_RECORD );

            //
            //  We simply call the worker routine to advance the base lsn.
            //  If we moved forward in the file, we will put our restart area in the
            //  queue.
            //

            LfsSetBaseLsnPriv( Lfcb,
                               ClientRecord,
                               BaseLsn );

            LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, FALSE );

        } finally {

            DebugUnwind( LfsSetBaseLsn );

            //
            //  Release the log file control block if held.
            //

            LfsReleaseLch( Lch );

            LfsDebugTrace( -1, Dbg, "LfsSetBaseLsn:  Exit\n", 0 );
        }

    } except (LfsExceptionFilter( GetExceptionInformation() )) {

        Status = GetExceptionCode();
    }

    if (Status != STATUS_SUCCESS) {

        ExRaiseStatus( Status );
    }

    return;
}
示例#16
0
VOID
LfsWriteRestartArea (
    IN LFS_LOG_HANDLE LogHandle,
    IN ULONG BufferLength,
    IN PVOID Buffer,
    OUT PLSN Lsn
    )

/*++

Routine Description:

    This routine is called by the client to write a restart area to the
    disk.  This routine will not return to the caller until the client
    restart area and all prior Lsn's have been flushed and the Lfs
    restart area on the disk has been updated.

    On return, all log records up to and including 'Lsn' have been flushed
    to the disk.

Arguments:

    LogHandle - Pointer to private Lfs structure used to identify this
                client.

    BufferLength - On entry it is the length of the user buffer.

    Buffer - Pointer to the buffer where the client restart data resides.

    Lsn - This is the Lsn for this write operation.  On input, this will be the
          new Base Lsn for this client.

          ****  This was used to prevent adding an interface change to
                the Beta release.

Return Value:

    None

--*/

{
    volatile NTSTATUS Status = STATUS_SUCCESS;

    PLCH Lch;

    PLFCB Lfcb;

    PLFS_CLIENT_RECORD ClientRecord;

    LFS_WRITE_ENTRY WriteEntry;

    PAGED_CODE();

    LfsDebugTrace( +1, Dbg, "LfsWriteRestartArea:  Entered\n", 0 );
    LfsDebugTrace(  0, Dbg, "Log Handle    -> %08lx\n", LogHandle );
    LfsDebugTrace(  0, Dbg, "Buffer Length -> %08lx\n", BufferLength );
    LfsDebugTrace(  0, Dbg, "Buffer        -> %08lx\n", Buffer );

    Lch = (PLCH) LogHandle;

    //
    //  Check that the structure is a valid log handle structure.
    //

    LfsValidateLch( Lch );

    //
    //  Use a try-except to catch errors.
    //

    try {

        //
        //  Use a try-finally to facilitate cleanup.
        //

        try {

            //
            //  Acquire the log file control block for this log file.
            //

            LfsAcquireLch( Lch );
            Lfcb = Lch->Lfcb;

            //
            //  If the Log file has been closed then refuse access.
            //

            if (Lfcb == NULL) {

                ExRaiseStatus( STATUS_ACCESS_DENIED );
            }

            //
            //  Check that the client Id is valid.
            //

            LfsValidateClientId( Lfcb, Lch );

            ClientRecord = LfsAdd2Ptr( Lfcb->ClientArray,
                                    Lch->ClientArrayByteOffset,
                                    PLFS_CLIENT_RECORD );

            //
            //  Go ahead and update the Base Lsn in the client area if the value
            //  given is not zero.
            //

            if ( Lsn->QuadPart != 0 ) {                                                                                //**** xxNeqZero( *Lsn )

                LfsSetBaseLsnPriv( Lfcb,
                                   ClientRecord,
                                   *Lsn );
            }

            //
            //  Write this restart area as a log record into a log page.
            //

            WriteEntry.Buffer = Buffer;
            WriteEntry.ByteLength = BufferLength;

            LfsWriteLogRecordIntoLogPage( Lfcb,
                                          Lch,
                                          1,
                                          &WriteEntry,
                                          LfsClientRestart,
                                          NULL,
                                          LfsZeroLsn,
                                          LfsZeroLsn,
                                          0,
                                          TRUE,
                                          Lsn );

            //
            //  Update the restart area for the client.
            //

            ClientRecord->ClientRestartLsn = *Lsn;

            //
            //  Write the restart area to the disk.
            //

            LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, TRUE );

        } finally {

            DebugUnwind( LfsWriteRestartArea );

            //
            //  Release the log file control block if still held.
            //

            LfsReleaseLch( Lch );

            LfsDebugTrace(  0, Dbg, "Lsn (Low)     -> %08lx\n", Lsn->LowPart );
            LfsDebugTrace(  0, Dbg, "Log (High)    -> %08lx\n", Lsn->HighPart );
            LfsDebugTrace( -1, Dbg, "LfsWriteRestartArea:  Exit\n", 0 );
        }

    } except (LfsExceptionFilter( GetExceptionInformation() )) {

        Status = GetExceptionCode();
    }

    if (Status != STATUS_SUCCESS) {

        ExRaiseStatus( Status );
    }

    return;
}