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
);
121 _Function_class_(KDEFERRED_ROUTINE
)
124 CmpEnableLazyFlushDpcRoutine(IN PKDPC Dpc
,
125 IN PVOID DeferredContext
,
126 IN PVOID SystemArgument1
,
127 IN PVOID SystemArgument2
)
129 /* Don't stop lazy flushing from happening anymore */
130 CmpHoldLazyFlush
= FALSE
;
133 _Function_class_(KDEFERRED_ROUTINE
)
136 CmpLazyFlushDpcRoutine(IN PKDPC Dpc
,
137 IN PVOID DeferredContext
,
138 IN PVOID SystemArgument1
,
139 IN PVOID SystemArgument2
)
141 /* Check if we should queue the lazy flush worker */
142 if ((!CmpLazyFlushPending
) && (!CmpHoldLazyFlush
))
144 CmpLazyFlushPending
= TRUE
;
145 ExQueueWorkItem(&CmpLazyWorkItem
, DelayedWorkQueue
);
153 LARGE_INTEGER DueTime
;
156 /* Check if we should set the lazy flush timer */
157 if ((!CmpNoWrite
) && (!CmpHoldLazyFlush
))
160 DueTime
.QuadPart
= Int32x32To64(CmpLazyFlushIntervalInSeconds
,
162 KeSetTimer(&CmpLazyFlushTimer
, DueTime
, &CmpLazyFlushDpc
);
166 _Function_class_(WORKER_THREAD_ROUTINE
)
169 CmpLazyFlushWorker(IN PVOID Parameter
)
171 BOOLEAN ForceFlush
, Result
, MoreWork
= FALSE
;
172 ULONG DirtyCount
= 0;
175 /* Don't do anything if lazy flushing isn't enabled yet */
176 if (CmpHoldLazyFlush
) return;
178 /* Check if we are forcing a flush */
179 ForceFlush
= CmpForceForceFlush
;
182 /* Lock the registry exclusively */
183 CmpLockRegistryExclusive();
187 /* Do a normal lock */
189 InterlockedIncrement(&CmpFlushStarveWriters
);
192 /* Flush the next hive */
193 MoreWork
= CmpDoFlushNextHive(ForceFlush
, &Result
, &DirtyCount
);
197 InterlockedIncrement((PLONG
)&CmpLazyFlushCount
);
200 /* Check if we have starved writers */
201 if (!ForceFlush
) InterlockedDecrement(&CmpFlushStarveWriters
);
203 /* Not pending anymore, release the registry lock */
204 CmpLazyFlushPending
= FALSE
;
207 /* Check if we need to flush another hive */
208 if ((MoreWork
) || (DirtyCount
)) CmpLazyFlush();
213 CmpCmdInit(IN BOOLEAN SetupBoot
)
215 LARGE_INTEGER DueTime
;
218 /* Setup the lazy DPC */
219 KeInitializeDpc(&CmpLazyFlushDpc
, CmpLazyFlushDpcRoutine
, NULL
);
221 /* Setup the lazy timer */
222 KeInitializeTimer(&CmpLazyFlushTimer
);
224 /* Setup the lazy worker */
225 ExInitializeWorkItem(&CmpLazyWorkItem
, CmpLazyFlushWorker
, NULL
);
227 /* Setup the forced-lazy DPC and timer */
228 KeInitializeDpc(&CmpEnableLazyFlushDpc
,
229 CmpEnableLazyFlushDpcRoutine
,
231 KeInitializeTimer(&CmpEnableLazyFlushTimer
);
233 /* Enable lazy flushing after 10 minutes */
234 DueTime
.QuadPart
= Int32x32To64(600, -10 * 1000 * 1000);
235 KeSetTimer(&CmpEnableLazyFlushTimer
, DueTime
, &CmpEnableLazyFlushDpc
);
237 /* Setup flush variables */
238 CmpNoWrite
= CmpMiniNTBoot
;
239 CmpWasSetupBoot
= SetupBoot
;
241 /* Testing: Force Lazy Flushing */
242 CmpHoldLazyFlush
= FALSE
;
244 /* Setup the hive list */
245 CmpInitializeHiveList(SetupBoot
);
250 CmpCmdHiveOpen(IN POBJECT_ATTRIBUTES FileAttributes
,
251 IN PSECURITY_CLIENT_CONTEXT ImpersonationContext
,
252 IN OUT PBOOLEAN Allocate
,
253 OUT PCMHIVE
*NewHive
,
256 PUNICODE_STRING FileName
;
260 /* Open the file in the current security context */
261 FileName
= FileAttributes
->ObjectName
;
262 Status
= CmpInitHiveFromFile(FileName
,
267 if (((Status
== STATUS_ACCESS_DENIED
) ||
268 (Status
== STATUS_NO_SUCH_USER
) ||
269 (Status
== STATUS_WRONG_PASSWORD
) ||
270 (Status
== STATUS_ACCOUNT_EXPIRED
) ||
271 (Status
== STATUS_ACCOUNT_DISABLED
) ||
272 (Status
== STATUS_ACCOUNT_RESTRICTION
)) &&
273 (ImpersonationContext
))
275 /* We failed due to an account/security error, impersonate SYSTEM */
276 Status
= SeImpersonateClientEx(ImpersonationContext
, NULL
);
277 if (NT_SUCCESS(Status
))
280 Status
= CmpInitHiveFromFile(FileName
,
286 /* Restore impersonation token */
291 /* Return status of open attempt */
297 CmpShutdownWorkers(VOID
)
299 /* Stop lazy flushing */
301 KeCancelTimer(&CmpLazyFlushTimer
);
306 CmSetLazyFlushState(IN BOOLEAN Enable
)
308 /* Set state for lazy flusher */
309 CmpHoldLazyFlush
= !Enable
;