2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmapi.c
5 * PURPOSE: Configuration Manager - Internal Registry APIs
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 KTIMER CmpLazyFlushTimer
;
19 WORK_QUEUE_ITEM CmpLazyWorkItem
;
20 KTIMER CmpEnableLazyFlushTimer
;
21 KDPC CmpEnableLazyFlushDpc
;
22 BOOLEAN CmpLazyFlushPending
;
23 BOOLEAN CmpForceForceFlush
;
24 BOOLEAN CmpHoldLazyFlush
= TRUE
;
25 ULONG CmpLazyFlushIntervalInSeconds
= 5;
26 ULONG CmpLazyFlushHiveCount
= 7;
27 ULONG CmpLazyFlushCount
= 1;
28 LONG CmpFlushStarveWriters
;
30 /* FUNCTIONS ******************************************************************/
34 CmpDoFlushNextHive(IN BOOLEAN ForceFlush
,
36 OUT PULONG DirtyCount
)
39 PLIST_ENTRY NextEntry
;
42 ULONG HiveCount
= CmpLazyFlushHiveCount
;
48 /* Don't do anything if we're not supposed to */
49 if (CmpNoWrite
) return TRUE
;
51 /* Make sure we have to flush at least one hive */
52 if (!HiveCount
) HiveCount
= 1;
54 /* Don't force flush */
55 CmpForceForceFlush
= FALSE
;
57 /* Acquire the list lock and loop */
58 ExAcquirePushLockShared(&CmpHiveListHeadLock
);
59 NextEntry
= CmpHiveListHead
.Flink
;
60 while (NextEntry
!= &CmpHiveListHead
)
62 /* Get the hive and check if we should flush it */
63 CmHive
= CONTAINING_RECORD(NextEntry
, CMHIVE
, HiveList
);
64 if (!(CmHive
->Hive
.HiveFlags
& HIVE_NOLAZYFLUSH
) &&
65 (CmHive
->FlushCount
!= CmpLazyFlushCount
))
70 /* Ignore clean or volatile hves */
71 if (!(CmHive
->Hive
.DirtyCount
) ||
72 (CmHive
->Hive
.HiveFlags
& HIVE_VOLATILE
))
74 /* Don't do anything but do update the count */
75 CmHive
->FlushCount
= CmpLazyFlushCount
;
80 DPRINT1("Flushing: %wZ\n", CmHive
->FileFullPath
);
81 DPRINT1("Handle: %lx\n", CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
]);
82 Status
= HvSyncHive(&CmHive
->Hive
);
83 if(!NT_SUCCESS(Status
))
85 /* Let them know we failed */
91 else if ((CmHive
->Hive
.DirtyCount
) &&
92 (!(CmHive
->Hive
.HiveFlags
& HIVE_VOLATILE
)) &&
93 (!(CmHive
->Hive
.HiveFlags
& HIVE_NOLAZYFLUSH
)))
95 /* Use another lazy flusher for this hive */
96 ASSERT(CmHive
->FlushCount
== CmpLazyFlushCount
);
97 *DirtyCount
+= CmHive
->Hive
.DirtyCount
;
100 /* Try the next one */
101 NextEntry
= NextEntry
->Flink
;
104 /* Check if we've flushed everything */
105 if (NextEntry
== &CmpHiveListHead
)
107 /* We have, tell the caller we're done */
112 /* We need to be called again */
116 /* Unlock the list and return the result */
117 ExReleasePushLock(&CmpHiveListHeadLock
);
123 CmpEnableLazyFlushDpcRoutine(IN PKDPC Dpc
,
124 IN PVOID DeferredContext
,
125 IN PVOID SystemArgument1
,
126 IN PVOID SystemArgument2
)
128 /* Don't stop lazy flushing from happening anymore */
129 CmpHoldLazyFlush
= FALSE
;
134 CmpLazyFlushDpcRoutine(IN PKDPC Dpc
,
135 IN PVOID DeferredContext
,
136 IN PVOID SystemArgument1
,
137 IN PVOID SystemArgument2
)
139 /* Check if we should queue the lazy flush worker */
140 if ((!CmpLazyFlushPending
) && (!CmpHoldLazyFlush
))
142 CmpLazyFlushPending
= TRUE
;
143 ExQueueWorkItem(&CmpLazyWorkItem
, DelayedWorkQueue
);
151 LARGE_INTEGER DueTime
;
154 /* Check if we should set the lazy flush timer */
155 if ((!CmpNoWrite
) && (!CmpHoldLazyFlush
))
158 DueTime
.QuadPart
= Int32x32To64(CmpLazyFlushIntervalInSeconds
,
160 KeSetTimer(&CmpLazyFlushTimer
, DueTime
, &CmpLazyFlushDpc
);
166 CmpLazyFlushWorker(IN PVOID Parameter
)
168 BOOLEAN ForceFlush
, Result
, MoreWork
= FALSE
;
169 ULONG DirtyCount
= 0;
172 /* Don't do anything if lazy flushing isn't enabled yet */
173 if (CmpHoldLazyFlush
) return;
175 /* Check if we are forcing a flush */
176 ForceFlush
= CmpForceForceFlush
;
179 /* Lock the registry exclusively */
180 CmpLockRegistryExclusive();
184 /* Do a normal lock */
186 InterlockedIncrement(&CmpFlushStarveWriters
);
189 /* Flush the next hive */
190 MoreWork
= CmpDoFlushNextHive(ForceFlush
, &Result
, &DirtyCount
);
194 InterlockedIncrement((PLONG
)&CmpLazyFlushCount
);
197 /* Check if we have starved writers */
198 if (!ForceFlush
) InterlockedDecrement(&CmpFlushStarveWriters
);
200 /* Not pending anymore, release the registry lock */
201 CmpLazyFlushPending
= FALSE
;
204 /* Check if we need to flush another hive */
205 if ((MoreWork
) || (DirtyCount
)) CmpLazyFlush();
210 CmpCmdInit(IN BOOLEAN SetupBoot
)
212 LARGE_INTEGER DueTime
;
215 /* Setup the lazy DPC */
216 KeInitializeDpc(&CmpLazyFlushDpc
, CmpLazyFlushDpcRoutine
, NULL
);
218 /* Setup the lazy timer */
219 KeInitializeTimer(&CmpLazyFlushTimer
);
221 /* Setup the lazy worker */
222 ExInitializeWorkItem(&CmpLazyWorkItem
, CmpLazyFlushWorker
, NULL
);
224 /* Setup the forced-lazy DPC and timer */
225 KeInitializeDpc(&CmpEnableLazyFlushDpc
,
226 CmpEnableLazyFlushDpcRoutine
,
228 KeInitializeTimer(&CmpEnableLazyFlushTimer
);
230 /* Enable lazy flushing after 10 minutes */
231 DueTime
.QuadPart
= Int32x32To64(600, -10 * 1000 * 1000);
232 KeSetTimer(&CmpEnableLazyFlushTimer
, DueTime
, &CmpEnableLazyFlushDpc
);
234 /* Setup flush variables */
235 CmpNoWrite
= CmpMiniNTBoot
;
236 CmpWasSetupBoot
= SetupBoot
;
238 /* Testing: Force Lazy Flushing */
239 CmpHoldLazyFlush
= FALSE
;
241 /* Setup the hive list */
242 CmpInitializeHiveList(SetupBoot
);
247 CmpCmdHiveOpen(IN POBJECT_ATTRIBUTES FileAttributes
,
248 IN PSECURITY_CLIENT_CONTEXT ImpersonationContext
,
249 IN OUT PBOOLEAN Allocate
,
250 OUT PCMHIVE
*NewHive
,
253 PUNICODE_STRING FileName
;
257 /* Open the file in the current security context */
258 FileName
= FileAttributes
->ObjectName
;
259 Status
= CmpInitHiveFromFile(FileName
,
264 if (((Status
== STATUS_ACCESS_DENIED
) ||
265 (Status
== STATUS_NO_SUCH_USER
) ||
266 (Status
== STATUS_WRONG_PASSWORD
) ||
267 (Status
== STATUS_ACCOUNT_EXPIRED
) ||
268 (Status
== STATUS_ACCOUNT_DISABLED
) ||
269 (Status
== STATUS_ACCOUNT_RESTRICTION
)) &&
270 (ImpersonationContext
))
272 /* We failed due to an account/security error, impersonate SYSTEM */
273 Status
= SeImpersonateClientEx(ImpersonationContext
, NULL
);
274 if (NT_SUCCESS(Status
))
277 Status
= CmpInitHiveFromFile(FileName
,
283 /* Restore impersonation token */
288 /* Return status of open attempt */
294 CmpShutdownWorkers(VOID
)
296 /* Stop lazy flushing */
298 KeCancelTimer(&CmpLazyFlushTimer
);
303 CmSetLazyFlushState(IN BOOLEAN Enable
)
305 /* Set state for lazy flusher */
306 CmpHoldLazyFlush
= !Enable
;