- Increase Hive dirty counter when marking cells as dirty
 - Clear the counter accordingly when flushing the hive
[NTOSKRNL]
 - Lazy flush the registry when unlocking it
 - Correctly update hive lazy flush count when actully flushing it
 - Respect the force flush parameter
CORE-6762 #comment Should be fixed with r61783, let's see what testbot says.

svn path=/trunk/; revision=61783
This commit is contained in:
Jérôme Gardou 2014-01-23 21:06:48 +00:00
parent 3cdb13b7e3
commit 9f87212d66
4 changed files with 43 additions and 17 deletions

View file

@ -120,6 +120,7 @@ HvMarkCellDirty(
RtlSetBits(&RegistryHive->DirtyVector, RtlSetBits(&RegistryHive->DirtyVector,
CellBlock, CellLastBlock - CellBlock); CellBlock, CellLastBlock - CellBlock);
RegistryHive->DirtyCount++;
return TRUE; return TRUE;
} }

View file

@ -265,6 +265,7 @@ HvSyncHive(
/* Clear dirty bitmap. */ /* Clear dirty bitmap. */
RtlClearAllBits(&RegistryHive->DirtyVector); RtlClearAllBits(&RegistryHive->DirtyVector);
RegistryHive->DirtyCount = 0;
return TRUE; return TRUE;
} }

View file

@ -23,7 +23,7 @@ BOOLEAN CmpLazyFlushPending;
BOOLEAN CmpForceForceFlush; BOOLEAN CmpForceForceFlush;
BOOLEAN CmpHoldLazyFlush = TRUE; BOOLEAN CmpHoldLazyFlush = TRUE;
ULONG CmpLazyFlushIntervalInSeconds = 5; ULONG CmpLazyFlushIntervalInSeconds = 5;
ULONG CmpLazyFlushHiveCount = 7; static ULONG CmpLazyFlushHiveCount = 7;
ULONG CmpLazyFlushCount = 1; ULONG CmpLazyFlushCount = 1;
LONG CmpFlushStarveWriters; LONG CmpFlushStarveWriters;
@ -31,9 +31,9 @@ LONG CmpFlushStarveWriters;
BOOLEAN BOOLEAN
NTAPI NTAPI
CmpDoFlushNextHive(IN BOOLEAN ForceFlush, CmpDoFlushNextHive(_In_ BOOLEAN ForceFlush,
OUT PBOOLEAN Error, _Out_ PBOOLEAN Error,
OUT PULONG DirtyCount) _Out_ PULONG DirtyCount)
{ {
NTSTATUS Status; NTSTATUS Status;
PLIST_ENTRY NextEntry; PLIST_ENTRY NextEntry;
@ -51,13 +51,10 @@ CmpDoFlushNextHive(IN BOOLEAN ForceFlush,
/* Make sure we have to flush at least one hive */ /* Make sure we have to flush at least one hive */
if (!HiveCount) HiveCount = 1; if (!HiveCount) HiveCount = 1;
/* Don't force flush */
CmpForceForceFlush = FALSE;
/* Acquire the list lock and loop */ /* Acquire the list lock and loop */
ExAcquirePushLockShared(&CmpHiveListHeadLock); ExAcquirePushLockShared(&CmpHiveListHeadLock);
NextEntry = CmpHiveListHead.Flink; NextEntry = CmpHiveListHead.Flink;
while (NextEntry != &CmpHiveListHead) while ((NextEntry != &CmpHiveListHead) && HiveCount)
{ {
/* Get the hive and check if we should flush it */ /* Get the hive and check if we should flush it */
CmHive = CONTAINING_RECORD(NextEntry, CMHIVE, HiveList); CmHive = CONTAINING_RECORD(NextEntry, CMHIVE, HiveList);
@ -67,17 +64,21 @@ CmpDoFlushNextHive(IN BOOLEAN ForceFlush,
/* Great sucess! */ /* Great sucess! */
Result = TRUE; Result = TRUE;
/* Ignore clean or volatile hves */ /* One less to flush */
if (!(CmHive->Hive.DirtyCount) || HiveCount--;
/* Ignore clean or volatile hives */
if ((!CmHive->Hive.DirtyCount && !ForceFlush) ||
(CmHive->Hive.HiveFlags & HIVE_VOLATILE)) (CmHive->Hive.HiveFlags & HIVE_VOLATILE))
{ {
/* Don't do anything but do update the count */ /* Don't do anything but do update the count */
CmHive->FlushCount = CmpLazyFlushCount; CmHive->FlushCount = CmpLazyFlushCount;
DPRINT("Hive %wZ is clean.\n", &CmHive->FileFullPath);
} }
else else
{ {
/* Do the sync */ /* Do the sync */
DPRINT1("Flushing: %wZ\n", CmHive->FileFullPath); DPRINT1("Flushing: %wZ\n", &CmHive->FileFullPath);
DPRINT1("Handle: %p\n", CmHive->FileHandles[HFILE_TYPE_PRIMARY]); DPRINT1("Handle: %p\n", CmHive->FileHandles[HFILE_TYPE_PRIMARY]);
Status = HvSyncHive(&CmHive->Hive); Status = HvSyncHive(&CmHive->Hive);
if(!NT_SUCCESS(Status)) if(!NT_SUCCESS(Status))
@ -85,7 +86,9 @@ CmpDoFlushNextHive(IN BOOLEAN ForceFlush,
/* Let them know we failed */ /* Let them know we failed */
*Error = TRUE; *Error = TRUE;
Result = FALSE; Result = FALSE;
break;
} }
CmHive->FlushCount = CmpLazyFlushCount;
} }
} }
else if ((CmHive->Hive.DirtyCount) && else if ((CmHive->Hive.DirtyCount) &&
@ -95,6 +98,7 @@ CmpDoFlushNextHive(IN BOOLEAN ForceFlush,
/* Use another lazy flusher for this hive */ /* Use another lazy flusher for this hive */
ASSERT(CmHive->FlushCount == CmpLazyFlushCount); ASSERT(CmHive->FlushCount == CmpLazyFlushCount);
*DirtyCount += CmHive->Hive.DirtyCount; *DirtyCount += CmHive->Hive.DirtyCount;
DPRINT("CmHive %wZ already uptodate.\n", &CmHive->FileFullPath);
} }
/* Try the next one */ /* Try the next one */
@ -139,6 +143,7 @@ CmpLazyFlushDpcRoutine(IN PKDPC Dpc,
IN PVOID SystemArgument2) IN PVOID SystemArgument2)
{ {
/* Check if we should queue the lazy flush worker */ /* Check if we should queue the lazy flush worker */
DPRINT("Flush pending: %s, Holding lazy flush: %s.\n", CmpLazyFlushPending ? "yes" : "no", CmpHoldLazyFlush ? "yes" : "no");
if ((!CmpLazyFlushPending) && (!CmpHoldLazyFlush)) if ((!CmpLazyFlushPending) && (!CmpHoldLazyFlush))
{ {
CmpLazyFlushPending = TRUE; CmpLazyFlushPending = TRUE;
@ -173,20 +178,27 @@ CmpLazyFlushWorker(IN PVOID Parameter)
PAGED_CODE(); PAGED_CODE();
/* Don't do anything if lazy flushing isn't enabled yet */ /* Don't do anything if lazy flushing isn't enabled yet */
if (CmpHoldLazyFlush) return; if (CmpHoldLazyFlush)
{
DPRINT1("Lazy flush held. Bye bye.\n");
CmpLazyFlushPending = FALSE;
return;
}
/* Check if we are forcing a flush */ /* Check if we are forcing a flush */
ForceFlush = CmpForceForceFlush; ForceFlush = CmpForceForceFlush;
if (ForceFlush) if (ForceFlush)
{ {
DPRINT("Forcing flush.\n");
/* Lock the registry exclusively */ /* Lock the registry exclusively */
CmpLockRegistryExclusive(); CmpLockRegistryExclusive();
} }
else else
{ {
/* Do a normal lock */ DPRINT("Not forcing flush.\n");
CmpLockRegistry(); /* Starve writers before locking */
InterlockedIncrement(&CmpFlushStarveWriters); InterlockedIncrement(&CmpFlushStarveWriters);
CmpLockRegistry();
} }
/* Flush the next hive */ /* Flush the next hive */
@ -198,14 +210,21 @@ CmpLazyFlushWorker(IN PVOID Parameter)
} }
/* Check if we have starved writers */ /* Check if we have starved writers */
if (!ForceFlush) InterlockedDecrement(&CmpFlushStarveWriters); if (!ForceFlush)
InterlockedDecrement(&CmpFlushStarveWriters);
/* Not pending anymore, release the registry lock */ /* Not pending anymore, release the registry lock */
CmpLazyFlushPending = FALSE; CmpLazyFlushPending = FALSE;
CmpUnlockRegistry(); CmpUnlockRegistry();
/* Check if we need to flush another hive */ DPRINT("Lazy flush done. More work to be done: %s. Entries still dirty: %u.\n",
if ((MoreWork) || (DirtyCount)) CmpLazyFlush(); MoreWork ? "Yes" : "No", DirtyCount);
if (MoreWork)
{
/* Relaunch the flush timer, so the remaining hives get flushed */
CmpLazyFlush();
}
} }
VOID VOID

View file

@ -1949,6 +1949,11 @@ CmpUnlockRegistry(VOID)
CmpDoFlushAll(TRUE); CmpDoFlushAll(TRUE);
CmpFlushOnLockRelease = FALSE; CmpFlushOnLockRelease = FALSE;
} }
else
{
/* Lazy flush the registry */
CmpLazyFlush();
}
/* Release the lock and leave the critical region */ /* Release the lock and leave the critical region */
ExReleaseResourceLite(&CmpRegistryLock); ExReleaseResourceLite(&CmpRegistryLock);