Ntfs!NtfsCheckpointVolume函数分析之Lfcb->RestartArea的变更和什么时候RestartArea写回文件的关系
Ntfs!NtfsCheckpointVolume函数分析之Lfcb->RestartArea的变更
第一部分:
VOID
NtfsCheckpointVolume (
IN PIRP_CONTEXT IrpContext,
IN PVCB Vcb,
IN BOOLEAN OwnsCheckpoint,
IN BOOLEAN CleanVolume,
IN BOOLEAN FlushVolume,
IN ULONG LfsFlags,
IN LSN LastKnownLsn
)
{
This routine is called periodically to perform a checkpoint on the volume
with respect to the log file. The checkpoint dumps a bunch of log file
state information to the log file, and finally writes a summary of the
dumped information in its Restart Area.
This checkpoint dumps the following:
Open Attribute Table
(all of the attribute names for the Attribute Table)
Dirty Pages Table
Transaction Table
此例程会定期调用,以根据日志文件对卷执行检查点操作。检查点会将大量日志文件状态信息转储到日志文件中,并最终在其重启区域中写入转储信息的摘要。
//
// Finally, write our Restart Area to describe all of the above, and
// give Lfs our new BaseLsn.
//
LfsWriteRestartArea( Vcb->LogHandle,
sizeof( RESTART_AREA ),
&RestartArea,
LfsCleanShutdown,
&Vcb->LastRestartArea );
0: kd> kv
# ChildEBP RetAddr Args to Child
00 f78d6748 f71fe6bb e13417d8 08124479 00000000 Ntfs!LfsFlushLfcb+0x4c3 (FPO: [Non-Fpo]) (CONV: stdcall) [d:\srv03rtm\base\fs\lfs\cachesup.c @ 970]
01 f78d679c f71796f4 013417d8 08124479 00000000 Ntfs!LfsFlushToLsnPriv+0x1c9 (FPO: [Non-Fpo]) (CONV: stdcall) [d:\srv03rtm\base\fs\lfs\lbcbsup.c @ 163]
02 f78d67fc f71fdcd5 e13417d8 000000e0 00000001 Ntfs!LfsWriteLfsRestart+0x1fe (FPO: [Non-Fpo]) (CONV: stdcall) [d:\srv03rtm\base\fs\lfs\rstrtsup.c @ 179]
03 f78d6848 f71d9319 e12830e0 00000068 f78d6894 Ntfs!LfsWriteRestartArea+0x18d (FPO: [Non-Fpo]) (CONV: stdcall) [d:\srv03rtm\base\fs\lfs\restart.c @ 426]
04 f78d6ab4 f7192e4c 898118a0 895cf100 00000000 Ntfs!NtfsCheckpointVolume+0x13d1 (FPO: [Non-Fpo]) (CONV: stdcall) [d:\srv03rtm\base\fs\ntfs\logsup.c @ 2529]
05 f78d6cec f717c5aa 898118a0 899c5488 898118a0 Ntfs!NtfsMountVolume+0x1268 (FPO: [Non-Fpo]) (CONV: stdcall) [d:\srv03rtm\base\fs\ntfs\fsctrl.c @ 2418]
06 f78d6d04 f71484b0 898118a0 899c5488 8999d020 Ntfs!NtfsCommonFileSystemControl+0x8c (FPO: [Non-Fpo]) (CONV: stdcall) [d:\srv03rtm\base\fs\ntfs\fsctrl.c @ 837]
07 f78d6d80 80af2bb9 898118a0 00000000 8999d020 Ntfs!NtfsFspDispatch+0x1fe (FPO: [Non-Fpo]) (CONV: stdcall) [d:\srv03rtm\base\fs\ntfs\fspdisp.c @ 336]
08 f78d6dac 80d391f0 898118a0 00000000 00000000 nt!ExpWorkerThread+0x10f (FPO: [Non-Fpo]) (CONV: stdcall) [d:\srv03rtm\base\ntos\ex\worker.c @ 1153]
09 f78d6ddc 80b00d52 80af2aaa 00000000 00000000 nt!PspSystemThreadStartup+0x2e (FPO: [Non-Fpo]) (CONV: stdcall) [d:\srv03rtm\base\ntos\ps\create.c @ 2213]
0a 00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16 [d:\srv03rtm\base\ntos\ke\i386\threadbg.asm @ 81]
第二部分:
VOID
LfsWriteLfsRestart (
IN PLFCB Lfcb,
IN ULONG ThisRestartSize,
IN BOOLEAN WaitForIo
)
{
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 ); //关键代码
参考开始:
LfsFindFirstIo( Lfcb,
TargetLsn,
RestartLsn,
FirstLbcb,
&NextLbcb,
&FileOffset,
&ContainsLastEntry,
&LfsRestart,
&UseTailCopy,
&IoBlocks );
//
// Check if this is a restart block or if we are passing through the log
// file for the first time or if this Lbcb is still in the active queue.
// If not, then group as many of the Lbcb's as can be part of a single Io.
//
if (LfsLbcbIsRestart( FirstLbcb )) {
*LfsRestart = TRUE;
#define LfsLbcbIsRestart(LBCB) \
(FlagOn( (LBCB)->LbcbFlags, LBCB_RESTART_LBCB ))
参考结束:
(ULONG)NewLbcb->Length = ThisRestartSize;
NewLbcb->PageHeader = (PVOID) Lfcb->RestartArea;
//
// Copy the existing restart area into the new area.
//
RtlCopyMemory( NewRestart, Lfcb->RestartArea, ThisRestartSize );
Lfcb->RestartArea = NewRestart;
//
// Add this Lbcb to the end of the workque and flush to that point.
//
InsertTailList( &Lfcb->LbcbWorkque, &NewLbcb->WorkqueLinks );
参考开始:
0: kd> t
Ntfs!LfsWriteLfsRestart:
f71794f6 6a2c push 2Ch
0: kd> kc
#
00 Ntfs!LfsWriteLfsRestart
01 Ntfs!LfsWriteRestartArea
02 Ntfs!NtfsCheckpointVolume
03 Ntfs!NtfsMountVolume
04 Ntfs!NtfsCommonFileSystemControl
05 Ntfs!NtfsFspDispatch
06 nt!ExpWorkerThread
07 nt!PspSystemThreadStartup
08 nt!KiThreadStartup
0: kd> dv
Lfcb = 0xe13417d8
[+0x0a0] RestartArea : 0xe139d008
参考结束:
[+0x0a0] RestartArea : 0xe1364f20 [Type: _LFS_RESTART_AREA *]
0: kd> dx -r1 (*((Ntfs!_LIST_ENTRY *)0xe1341860))
(*((Ntfs!_LIST_ENTRY *)0xe1341860)) [Type: _LIST_ENTRY]
[+0x000] Flink : 0xe135ed2c [Type: _LIST_ENTRY *]
[+0x004] Blink : 0xe127bc34 [Type: _LIST_ENTRY *]
0: kd> dt lbcb 0xe127bc34-4
Ntfs!LBCB
+0x000 NodeTypeCode : 0n2050
+0x002 NodeByteSize : 0n96
+0x004 WorkqueLinks : _LIST_ENTRY [ 0xe1341860 - 0xe1350cec ]
+0x00c ActiveLinks : _LIST_ENTRY [ 0x0 - 0x0 ]
+0x018 FileOffset : 0n4096
+0x020 Length : 0n224
+0x028 SeqNumber : 0n0
+0x030 BufferOffset : 0n0
+0x038 PageHeader : 0xe139d008 Void
+0x03c LogPageBcb : (null)
+0x040 LastLsn : _LARGE_INTEGER 0x8124479
+0x048 LastEndLsn : _LARGE_INTEGER 0x8124479
+0x050 Flags : 0
+0x054 LbcbFlags : 0x20
+0x058 ResourceThread : 0
0: kd> dd 0xe139d008
e139d008 08124478 00000000 ffff0001 00000000
e139d018 00000028 004000e0 04000000 00000000
e139d028 00000068 00400030 85e12261 00000000
e139d038 00000000 00000000 00000000 00000000
e139d048 08124465 00000000 08124478 00000000
e139d058 ffffffff 00000000 00000000 00000008
e139d068 0054004e 00530046 00000000 00000000
e139d078 00000000 00000000 00000000 00000000
0: kd> dd 0xe1364f20
e1364f20 08124478 00000000 ffff0001 00000000
e1364f30 00000028 004000e0 04000000 00000000
e1364f40 00000068 00400030 85e12261 00000000
e1364f50 00000000 00000000 00000000 00000000
e1364f60 08124465 00000000 08124478 00000000
e1364f70 ffffffff 00000000 00000000 00000008
e1364f80 0054004e 00530046 00000000 00000000
e1364f90 00000000 00000000 00000000 00000000
第三部分:0x89897000页面写回文件
//
// Remember the first Lbcb in the list.
//
FirstLbcb = CONTAINING_RECORD( Lfcb->LbcbWorkque.Flink,
LBCB,
WorkqueLinks );
//
// Write the page header into the page and mark the page dirty.
//
RtlCopyMemory( Add2Ptr( RestartPage, Lfcb->RestartDataOffset, PVOID ),
FirstLbcb->PageHeader,
(ULONG)FirstLbcb->Length );
//
// Remember the range we are flushing and find the second half of a page
// if necessary.
//
Lfcb->UserWriteData->FileOffset = FileOffset;
Lfcb->UserWriteData->Length = Length;
0: kd> dv FileOffset
FileOffset = 0x1000
Status = IoSynchronousPageWrite( Lfcb->FileObject,
Lfcb->LogHeadPartialMdl,
(PLARGE_INTEGER)&FileOffset,
&Event,
&Iosb );
0: kd> dx -r1 ((Ntfs!_LFCB *)0xe13417d8)
((Ntfs!_LFCB *)0xe13417d8) : 0xe13417d8 [Type: _LFCB *]
[+0x14c] LogHeadMdl : 0x899c57a8 [Type: _MDL *]
[+0x150] LogHeadPartialMdl : 0x895ccb00 [Type: _MDL *]
[+0x154] LogHeadBuffer : 0x89896000 [Type: void *]
0: kd> dx -r1 ((Ntfs!_MDL *)0x895ccb00)
((Ntfs!_MDL *)0x895ccb00) : 0x895ccb00 [Type: _MDL *]
[+0x000] Next : 0x0 [Type: _MDL *]
[+0x004] Size : 32 [Type: short]
[+0x006] MdlFlags : 28 [Type: short]
[+0x008] Process : 0x0 [Type: _EPROCESS *]
[+0x00c] MappedSystemVa : 0x89897000 [Type: void *]
[+0x010] StartVa : 0x89897000 [Type: void *]
[+0x014] ByteCount : 0x1000 [Type: unsigned long]
[+0x018] ByteOffset : 0x0 [Type: unsigned long]