NT4/private/ntos/lfs/write.c
2020-09-30 17:12:29 +02:00

476 lines
12 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
Write.c
Abstract:
This module implements the user routines which write log records into
or flush portions of the log file.
Author:
Brian Andrew [BrianAn] 20-June-1991
Revision History:
--*/
#include "lfsprocs.h"
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_WRITE)
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, LfsFlushToLsn)
#pragma alloc_text(PAGE, LfsForceWrite)
#pragma alloc_text(PAGE, LfsWrite)
#endif
BOOLEAN
LfsWrite (
IN LFS_LOG_HANDLE LogHandle,
IN ULONG NumberOfWriteEntries,
IN PLFS_WRITE_ENTRY WriteEntries,
IN LFS_RECORD_TYPE RecordType,
IN TRANSACTION_ID *TransactionId OPTIONAL,
IN LSN UndoNextLsn,
IN LSN PreviousLsn,
IN LONG UndoRequirement,
OUT PLSN Lsn
)
/*++
Routine Description:
This routine is called by a client to write a log record to the log file.
The log record is lazy written and is not guaranteed to be on the disk
until a subsequent LfsForceWrie or LfsWriteRestartArea or until
an LfsFlushtoLsn is issued withan Lsn greater-than or equal to the Lsn
returned from this service.
Arguments:
LogHandle - Pointer to private Lfs structure used to identify this
client.
NumberOfWriteEntries - Number of components of the log record.
WriteEntries - Pointer to an array of write entries.
RecordType - Lfs defined type for this log record.
TransactionId - Id value used to group log records by complete transaction.
UndoNextLsn - Lsn of a previous log record which needs to be undone in
the event of a client restart.
PreviousLsn - Lsn of the immediately previous log record for this client.
Lsn - Lsn to be associated with this log record.
Return Value:
BOOLEAN - Advisory, TRUE indicates that less than 1/4 of the log file is
available.
--*/
{
volatile NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN LogFileFull = FALSE;
PLCH Lch;
PLFCB Lfcb;
PAGED_CODE();
DebugTrace( +1, Dbg, "LfsWrite: Entered\n", 0 );
DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
DebugTrace( 0, Dbg, "NumberOfWriteEntries -> %08lx\n", NumberOfWriteEntries );
DebugTrace( 0, Dbg, "WriteEntries -> %08lx\n", WriteEntries );
DebugTrace( 0, Dbg, "Record Type -> %08lx\n", RecordType );
DebugTrace( 0, Dbg, "Transaction Id -> %08lx\n", TransactionId );
DebugTrace( 0, Dbg, "UndoNextLsn (Low) -> %08lx\n", UndoNextLsn.LowPart );
DebugTrace( 0, Dbg, "UndoNextLsn (High) -> %08lx\n", UndoNextLsn.HighPart );
DebugTrace( 0, Dbg, "PreviousLsn (Low) -> %08lx\n", PreviousLsn.LowPart );
DebugTrace( 0, Dbg, "PreviousLsn (High) -> %08lx\n", PreviousLsn.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 );
//
// Write the log record.
//
LogFileFull = LfsWriteLogRecordIntoLogPage( Lfcb,
Lch,
NumberOfWriteEntries,
WriteEntries,
RecordType,
TransactionId,
UndoNextLsn,
PreviousLsn,
UndoRequirement,
FALSE,
Lsn );
} finally {
DebugUnwind( LfsWrite );
//
// Release the log file control block if held.
//
LfsReleaseLch( Lch );
DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart );
DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart );
DebugTrace( -1, Dbg, "LfsWrite: Exit\n", 0 );
}
} except (LfsExceptionFilter( GetExceptionInformation() )) {
Status = GetExceptionCode();
}
if (Status != STATUS_SUCCESS) {
ExRaiseStatus( Status );
}
return LogFileFull;
}
BOOLEAN
LfsForceWrite (
IN LFS_LOG_HANDLE LogHandle,
IN ULONG NumberOfWriteEntries,
IN PLFS_WRITE_ENTRY WriteEntries,
IN LFS_RECORD_TYPE RecordType,
IN TRANSACTION_ID *TransactionId,
IN LSN UndoNextLsn,
IN LSN PreviousLsn,
IN LONG UndoRequirement,
OUT PLSN Lsn
)
/*++
Routine Description:
This routine is called by a client to write a log record to the log file.
This is idendical to LfsWrite except that on return the log record is
guaranteed to be on disk.
Arguments:
LogHandle - Pointer to private Lfs structure used to identify this
client.
NumberOfWriteEntries - Number of components of the log record.
WriteEntries - Pointer to an array of write entries.
RecordType - Lfs defined type for this log record.
TransactionId - Id value used to group log records by complete transaction.
UndoNextLsn - Lsn of a previous log record which needs to be undone in
the event of a client restart.
PreviousLsn - Lsn of the immediately previous log record for this client.
Lsn - Lsn to be associated with this log record.
Return Value:
BOOLEAN - Advisory, TRUE indicates that less than 1/4 of the log file is
available.
--*/
{
volatile NTSTATUS Status = STATUS_SUCCESS;
PLCH Lch;
PLFCB Lfcb;
BOOLEAN LogFileFull = FALSE;
PAGED_CODE();
DebugTrace( +1, Dbg, "LfsForceWrite: Entered\n", 0 );
DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
DebugTrace( 0, Dbg, "NumberOfWriteEntries -> %08lx\n", NumberOfWriteEntries );
DebugTrace( 0, Dbg, "WriteEntries -> %08lx\n", WriteEntries );
DebugTrace( 0, Dbg, "Record Type -> %08lx\n", RecordType );
DebugTrace( 0, Dbg, "Transaction Id -> %08lx\n", TransactionId );
DebugTrace( 0, Dbg, "UndoNextLsn (Low) -> %08lx\n", UndoNextLsn.LowPart );
DebugTrace( 0, Dbg, "UndoNextLsn (High) -> %08lx\n", UndoNextLsn.HighPart );
DebugTrace( 0, Dbg, "PreviousLsn (Low) -> %08lx\n", PreviousLsn.LowPart );
DebugTrace( 0, Dbg, "PreviousLsn (High) -> %08lx\n", PreviousLsn.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 );
//
// Write the log record.
//
LogFileFull = LfsWriteLogRecordIntoLogPage( Lfcb,
Lch,
NumberOfWriteEntries,
WriteEntries,
RecordType,
TransactionId,
UndoNextLsn,
PreviousLsn,
UndoRequirement,
TRUE,
Lsn );
//
// The call to add this lbcb to the workque is guaranteed to release
// the Lfcb if this thread may do the Io.
//
LfsFlushToLsnPriv( Lfcb, *Lsn );
} finally {
DebugUnwind( LfsForceWrite );
//
// Release the log file control block if held.
//
LfsReleaseLch( Lch );
DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart );
DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart );
DebugTrace( -1, Dbg, "LfsForceWrite: Exit\n", 0 );
}
} except (LfsExceptionFilter( GetExceptionInformation() )) {
Status = GetExceptionCode();
}
if (Status != STATUS_SUCCESS) {
ExRaiseStatus( Status );
}
return LogFileFull;
}
VOID
LfsFlushToLsn (
IN LFS_LOG_HANDLE LogHandle,
IN LSN Lsn
)
/*++
Routine Description:
This routine is called by a client to insure that all log records
to a certain point have been flushed to the file. This is done by
checking if the desired Lsn has even been written at all. If so we
check if it has been flushed to the file. If not, we simply write
the current restart area to the disk.
Arguments:
LogHandle - Pointer to private Lfs structure used to identify this
client.
Lsn - This is the Lsn that must be on the disk on return from this
routine.
Return Value:
None
--*/
{
volatile NTSTATUS Status = STATUS_SUCCESS;
PLCH Lch;
PLFCB Lfcb;
PAGED_CODE();
DebugTrace( +1, Dbg, "LfsFlushToLsn: Entered\n", 0 );
DebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle );
DebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn.LowPart );
DebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn.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 we will assume the Lsn has been flushed.
//
if (Lfcb != NULL) {
//
// Check that the client Id is valid.
//
LfsValidateClientId( Lfcb, Lch );
//
// Call our common routine to perform the work.
//
LfsFlushToLsnPriv( Lfcb, Lsn );
}
} finally {
DebugUnwind( LfsFlushToLsn );
//
// Release the log file control block if held.
//
LfsReleaseLch( Lch );
DebugTrace( -1, Dbg, "LfsFlushToLsn: Exit\n", 0 );
}
} except (LfsExceptionFilter( GetExceptionInformation() )) {
Status = GetExceptionCode();
}
if (Status != STATUS_SUCCESS) {
ExRaiseStatus( Status );
}
return;
}