ReactOS 0.4.15-dev-7693-gd0e2924
cmlazy.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * PURPOSE: Configuration Manager - Internal Registry APIs
5 * PROGRAMMERS: Alex Ionescu <alex.ionescu@reactos.org>
6 */
7
8/* INCLUDES *******************************************************************/
9
10#include "ntoskrnl.h"
11#define NDEBUG
12#include "debug.h"
13
14/* GLOBALS ********************************************************************/
15
28
29/* FUNCTIONS ******************************************************************/
30
35 _Out_ PULONG DirtyCount)
36{
38 PLIST_ENTRY NextEntry;
39 PCMHIVE CmHive;
41 ULONG HiveCount = CmpLazyFlushHiveCount;
42
43 /* Set Defaults */
44 *Error = FALSE;
45 *DirtyCount = 0;
46
47 /* Don't do anything if we're not supposed to */
48 if (CmpNoWrite) return TRUE;
49
50 /* Make sure we have to flush at least one hive */
51 if (!HiveCount) HiveCount = 1;
52
53 /* Acquire the list lock and loop */
55 NextEntry = CmpHiveListHead.Flink;
56 while ((NextEntry != &CmpHiveListHead) && HiveCount)
57 {
58 /* Get the hive and check if we should flush it */
59 CmHive = CONTAINING_RECORD(NextEntry, CMHIVE, HiveList);
60 if (!(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH) &&
61 (CmHive->FlushCount != CmpLazyFlushCount))
62 {
63 /* Great sucess! */
64 Result = TRUE;
65
66 /* One less to flush */
67 HiveCount--;
68
69 /* Ignore clean or volatile hives */
70 if ((!CmHive->Hive.DirtyCount && !ForceFlush) ||
71 (CmHive->Hive.HiveFlags & HIVE_VOLATILE))
72 {
73 /* Don't do anything but do update the count */
75 DPRINT("Hive %wZ is clean.\n", &CmHive->FileFullPath);
76 }
77 else
78 {
79 /* Do the sync */
80 DPRINT("Flushing: %wZ\n", &CmHive->FileFullPath);
81 DPRINT("Handle: %p\n", CmHive->FileHandles[HFILE_TYPE_PRIMARY]);
82 Status = HvSyncHive(&CmHive->Hive);
83 if(!NT_SUCCESS(Status))
84 {
85 /* Let them know we failed */
86 DPRINT1("Failed to flush %wZ on handle %p (status 0x%08lx)\n",
88 *Error = TRUE;
89 Result = FALSE;
90 break;
91 }
93 }
94 }
95 else if (CmHive->Hive.DirtyCount &&
96 !(CmHive->Hive.HiveFlags & HIVE_VOLATILE) &&
97 !(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH))
98 {
99 /* Use another lazy flusher for this hive */
101 *DirtyCount += CmHive->Hive.DirtyCount;
102 DPRINT("CmHive %wZ already uptodate.\n", &CmHive->FileFullPath);
103 }
104
105 /* Try the next one */
106 NextEntry = NextEntry->Flink;
107 }
108
109 /* Check if we've flushed everything */
110 if (NextEntry == &CmpHiveListHead)
111 {
112 /* We have, tell the caller we're done */
113 Result = FALSE;
114 }
115 else
116 {
117 /* We need to be called again */
118 Result = TRUE;
119 }
120
121 /* Unlock the list and return the result */
123 return Result;
124}
125
126_Function_class_(KDEFERRED_ROUTINE)
127VOID
128NTAPI
129CmpEnableLazyFlushDpcRoutine(IN PKDPC Dpc,
133{
134 /* Don't stop lazy flushing from happening anymore */
136}
137
138_Function_class_(KDEFERRED_ROUTINE)
139VOID
140NTAPI
141CmpLazyFlushDpcRoutine(IN PKDPC Dpc,
145{
146 /* Check if we should queue the lazy flush worker */
147 DPRINT("Flush pending: %s, Holding lazy flush: %s.\n", CmpLazyFlushPending ? "yes" : "no", CmpHoldLazyFlush ? "yes" : "no");
149 {
152 }
153}
154
155VOID
156NTAPI
158{
160 PAGED_CODE();
161
162 /* Check if we should set the lazy flush timer */
164 {
165 /* Do it */
167 -10 * 1000 * 1000);
169 }
170}
171
172_Function_class_(WORKER_THREAD_ROUTINE)
173VOID
174NTAPI
175CmpLazyFlushWorker(IN PVOID Parameter)
176{
177 BOOLEAN ForceFlush, Result, MoreWork = FALSE;
178 ULONG DirtyCount = 0;
179 PAGED_CODE();
180
181 /* Don't do anything if lazy flushing isn't enabled yet */
183 {
184 DPRINT1("Lazy flush held. Bye bye.\n");
186 return;
187 }
188
189 /* Check if we are forcing a flush */
190 ForceFlush = CmpForceForceFlush;
191 if (ForceFlush)
192 {
193 DPRINT("Forcing flush.\n");
194 /* Lock the registry exclusively */
196 }
197 else
198 {
199 DPRINT("Not forcing flush.\n");
200 /* Starve writers before locking */
203 }
204
205 /* Flush the next hive */
206 MoreWork = CmpDoFlushNextHive(ForceFlush, &Result, &DirtyCount);
207 if (!MoreWork)
208 {
209 /* We're done */
211 }
212
213 /* Check if we have starved writers */
214 if (!ForceFlush)
216
217 /* Not pending anymore, release the registry lock */
220
221 DPRINT("Lazy flush done. More work to be done: %s. Entries still dirty: %u.\n",
222 MoreWork ? "Yes" : "No", DirtyCount);
223
224 if (MoreWork)
225 {
226 /* Relaunch the flush timer, so the remaining hives get flushed */
227 CmpLazyFlush();
228 }
229}
230
231VOID
232NTAPI
234{
236 PAGED_CODE();
237
238 /* Setup the lazy DPC */
239 KeInitializeDpc(&CmpLazyFlushDpc, CmpLazyFlushDpcRoutine, NULL);
240
241 /* Setup the lazy timer */
243
244 /* Setup the lazy worker */
245 ExInitializeWorkItem(&CmpLazyWorkItem, CmpLazyFlushWorker, NULL);
246
247 /* Setup the forced-lazy DPC and timer */
249 CmpEnableLazyFlushDpcRoutine,
250 NULL);
252
253 /* Enable lazy flushing after 10 minutes */
254 DueTime.QuadPart = Int32x32To64(600, -10 * 1000 * 1000);
256
257 /* Setup flush variables */
259 CmpWasSetupBoot = SetupBoot;
260
261 /* Testing: Force Lazy Flushing */
263
264 /* Setup the system hives list if this is not a Setup boot */
265 if (!SetupBoot)
267
268 /* Now that the system hives are loaded, if we are in PE mode,
269 * all other hives will be loaded with full access */
270 if (CmpMiniNTBoot)
272}
273
275NTAPI
277 IN PSECURITY_CLIENT_CONTEXT ImpersonationContext,
279 OUT PCMHIVE *NewHive,
280 IN ULONG CheckFlags)
281{
286 OBJECT_NAME_INFORMATION DummyNameInfo;
287 POBJECT_NAME_INFORMATION FileNameInfo;
288
289 PAGED_CODE();
290
291 if (FileAttributes->RootDirectory)
292 {
293 /*
294 * Validity check: The ObjectName is relative to RootDirectory,
295 * therefore it must not start with a path separator.
296 */
297 if (FileAttributes->ObjectName && FileAttributes->ObjectName->Buffer &&
298 FileAttributes->ObjectName->Length >= sizeof(WCHAR) &&
299 *FileAttributes->ObjectName->Buffer == OBJ_NAME_PATH_SEPARATOR)
300 {
302 }
303
304 /* Determine the right buffer size and allocate */
305 Status = ZwQueryObject(FileAttributes->RootDirectory,
307 &DummyNameInfo,
308 sizeof(DummyNameInfo),
309 &Length);
311 {
312 DPRINT1("CmpCmdHiveOpen(): Root directory handle object name size query failed, Status = 0x%08lx\n", Status);
313 return Status;
314 }
315
316 FileNameInfo = ExAllocatePoolWithTag(PagedPool,
317 Length + sizeof(UNICODE_NULL),
318 TAG_CM);
319 if (FileNameInfo == NULL)
320 {
321 DPRINT1("CmpCmdHiveOpen(): Unable to allocate memory\n");
323 }
324
325 /* Try to get the value */
326 Status = ZwQueryObject(FileAttributes->RootDirectory,
328 FileNameInfo,
329 Length,
330 &Length);
331 if (!NT_SUCCESS(Status))
332 {
333 /* Fail */
334 DPRINT1("CmpCmdHiveOpen(): Root directory handle object name query failed, Status = 0x%08lx\n", Status);
335 ExFreePoolWithTag(FileNameInfo, TAG_CM);
336 return Status;
337 }
338
339 /* Null-terminate and add the length of the terminator */
341 FilePath = FileNameInfo->Name.Buffer;
342 FilePath[Length / sizeof(WCHAR)] = UNICODE_NULL;
343 Length += sizeof(UNICODE_NULL);
344
345 /* Compute the size of the full path; Length already counts the terminating NULL */
346 Length = Length + sizeof(WCHAR) + FileAttributes->ObjectName->Length;
348 {
349 /* Name size too long, bail out */
350 ExFreePoolWithTag(FileNameInfo, TAG_CM);
352 }
353
354 /* Build the full path */
355 RtlInitEmptyUnicodeString(&FileName, NULL, 0);
357 if (!FileName.Buffer)
358 {
359 /* Fail */
360 DPRINT1("CmpCmdHiveOpen(): Unable to allocate memory\n");
361 ExFreePoolWithTag(FileNameInfo, TAG_CM);
363 }
364 FileName.MaximumLength = Length;
365 RtlCopyUnicodeString(&FileName, &FileNameInfo->Name);
366 ExFreePoolWithTag(FileNameInfo, TAG_CM);
367
368 /*
369 * Append a path terminator if needed (we have already accounted
370 * for a possible extra one when allocating the buffer).
371 */
372 if (/* FileAttributes->ObjectName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR && */ // We excluded ObjectName starting with a path separator above.
373 FileName.Length > 0 && FileName.Buffer[FileName.Length / sizeof(WCHAR) - 1] != OBJ_NAME_PATH_SEPARATOR)
374 {
375 /* ObjectName does not start with '\' and PathBuffer does not end with '\' */
376 FileName.Buffer[FileName.Length / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
377 FileName.Length += sizeof(WCHAR);
378 FileName.Buffer[FileName.Length / sizeof(WCHAR)] = UNICODE_NULL;
379 }
380
381 /* Append the object name */
383 if (!NT_SUCCESS(Status))
384 {
385 /* Fail */
386 DPRINT1("CmpCmdHiveOpen(): RtlAppendUnicodeStringToString() failed, Status = 0x%08lx\n", Status);
388 return Status;
389 }
390 }
391 else
392 {
393 FileName = *FileAttributes->ObjectName;
394 }
395
396 /* Open the file in the current security context */
398 0,
399 NewHive,
400 Allocate,
401 CheckFlags);
402 if (((Status == STATUS_ACCESS_DENIED) ||
408 ImpersonationContext)
409 {
410 /* We failed due to an account/security error, impersonate SYSTEM */
411 Status = SeImpersonateClientEx(ImpersonationContext, NULL);
412 if (NT_SUCCESS(Status))
413 {
414 /* Now try again */
416 0,
417 NewHive,
418 Allocate,
419 CheckFlags);
420
421 /* Restore impersonation token */
423 }
424 }
425
426 if (FileAttributes->RootDirectory)
427 {
429 }
430
431 /* Return status of open attempt */
432 return Status;
433}
434
435VOID
436NTAPI
438{
439 /* Stop lazy flushing */
440 PAGED_CODE();
442}
443
444VOID
445NTAPI
447{
448 /* Set state for lazy flusher */
450}
451
452/* EOF */
#define PAGED_CODE()
@ ObjectNameInformation
Definition: DriverTester.h:55
PCWSTR FilePath
unsigned char BOOLEAN
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:25
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
BOOL Error
Definition: chkdsk.c:66
EX_PUSH_LOCK CmpHiveListHeadLock
Definition: cmdata.c:39
BOOLEAN CmpMiniNTBoot
Definition: cmdata.c:60
BOOLEAN CmpShareSystemHives
Definition: cmdata.c:58
VOID NTAPI CmpLazyFlush(VOID)
Definition: cmlazy.c:157
KDPC CmpEnableLazyFlushDpc
Definition: cmlazy.c:20
static ULONG CmpLazyFlushHiveCount
Definition: cmlazy.c:25
ULONG CmpLazyFlushCount
Definition: cmlazy.c:26
LONG CmpFlushStarveWriters
Definition: cmlazy.c:27
ULONG CmpLazyFlushIntervalInSeconds
Definition: cmlazy.c:24
VOID NTAPI CmpCmdInit(IN BOOLEAN SetupBoot)
Definition: cmlazy.c:233
BOOLEAN NTAPI CmpDoFlushNextHive(_In_ BOOLEAN ForceFlush, _Out_ PBOOLEAN Error, _Out_ PULONG DirtyCount)
Definition: cmlazy.c:33
VOID NTAPI CmpShutdownWorkers(VOID)
Definition: cmlazy.c:437
KTIMER CmpEnableLazyFlushTimer
Definition: cmlazy.c:19
KDPC CmpLazyFlushDpc
Definition: cmlazy.c:17
WORK_QUEUE_ITEM CmpLazyWorkItem
Definition: cmlazy.c:18
NTSTATUS NTAPI CmpCmdHiveOpen(IN POBJECT_ATTRIBUTES FileAttributes, IN PSECURITY_CLIENT_CONTEXT ImpersonationContext, IN OUT PBOOLEAN Allocate, OUT PCMHIVE *NewHive, IN ULONG CheckFlags)
Definition: cmlazy.c:276
VOID NTAPI CmSetLazyFlushState(IN BOOLEAN Enable)
Definition: cmlazy.c:446
BOOLEAN CmpForceForceFlush
Definition: cmlazy.c:22
BOOLEAN CmpHoldLazyFlush
Definition: cmlazy.c:23
KTIMER CmpLazyFlushTimer
Definition: cmlazy.c:16
BOOLEAN CmpLazyFlushPending
Definition: cmlazy.c:21
BOOLEAN CMAPI HvSyncHive(PHHIVE RegistryHive)
#define TAG_CM
Definition: cmlib.h:212
VOID NTAPI CmpLockRegistryExclusive(VOID)
Definition: cmsysini.c:1954
VOID NTAPI CmpUnlockRegistry(VOID)
Definition: cmsysini.c:2053
VOID NTAPI CmpLockRegistry(VOID)
Definition: cmsysini.c:1967
VOID NTAPI CmpInitializeHiveList(VOID)
Definition: cmsysini.c:1464
LIST_ENTRY CmpHiveListHead
Definition: cmsysini.c:17
BOOLEAN CmpWasSetupBoot
Definition: cmsysini.c:32
BOOLEAN CmpNoWrite
Definition: cmsysini.c:30
NTSTATUS NTAPI CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName, IN ULONG HiveFlags, OUT PCMHIVE *Hive, IN OUT PBOOLEAN New, IN ULONG CheckFlags)
Definition: cmsysini.c:289
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:712
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define PagedPool
Definition: env_spec_w32.h:308
FORCEINLINE VOID ExReleasePushLock(PEX_PUSH_LOCK PushLock)
Definition: ex.h:1296
FORCEINLINE VOID ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock)
Definition: ex.h:1105
struct _FileName FileName
Definition: fatprocs.h:896
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE _In_ ACCESS_MASK _In_ POBJECT_ATTRIBUTES _Out_ PIO_STATUS_BLOCK _In_opt_ PLARGE_INTEGER _In_ ULONG FileAttributes
Definition: fltkernel.h:1236
Status
Definition: gdiplustypes.h:25
#define HIVE_VOLATILE
Definition: hivedata.h:23
#define HFILE_TYPE_PRIMARY
Definition: hivedata.h:33
#define HIVE_NOLAZYFLUSH
Definition: hivedata.h:24
if(dx< 0)
Definition: linetemp.h:194
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
NTKERNELAPI VOID NTAPI PsRevertToSelf(VOID)
Definition: security.c:556
#define _Function_class_(x)
Definition: ms_sal.h:2946
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
struct _OBJECT_NAME_INFORMATION OBJECT_NAME_INFORMATION
#define Int32x32To64(a, b)
#define UNICODE_NULL
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
_In_ ULONGLONG _In_ ULONGLONG _In_ BOOLEAN Enable
Definition: ntddpcm.h:142
NTSTATUS NTAPI SeImpersonateClientEx(_In_ PSECURITY_CLIENT_CONTEXT ClientContext, _In_opt_ PETHREAD ServerThread)
Extended function that impersonates a client.
Definition: client.c:276
#define STATUS_WRONG_PASSWORD
Definition: ntstatus.h:342
#define STATUS_ACCOUNT_DISABLED
Definition: ntstatus.h:350
#define STATUS_OBJECT_PATH_SYNTAX_BAD
Definition: ntstatus.h:295
#define STATUS_NO_SUCH_USER
Definition: ntstatus.h:336
#define STATUS_ACCOUNT_EXPIRED
Definition: ntstatus.h:636
#define STATUS_OBJECT_PATH_INVALID
Definition: ntstatus.h:293
#define STATUS_ACCOUNT_RESTRICTION
Definition: ntstatus.h:346
long LONG
Definition: pedump.c:60
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
#define DPRINT
Definition: sndvol32.h:71
Definition: cmlib.h:316
ULONG FlushCount
Definition: cmlib.h:356
HHIVE Hive
Definition: cmlib.h:317
HANDLE FileHandles[HFILE_TYPE_MAX]
Definition: cmlib.h:318
UNICODE_STRING FileFullPath
Definition: cmlib.h:333
ULONG HiveFlags
Definition: hivedata.h:347
ULONG DirtyCount
Definition: hivedata.h:330
Definition: ketypes.h:699
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
UNICODE_STRING Name
Definition: nt_native.h:1270
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:281
BOOLEAN NTAPI KeCancelTimer(IN OUT PKTIMER Timer)
Definition: timerobj.c:206
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
uint32_t * PULONG
Definition: typedefs.h:59
unsigned char * PBOOLEAN
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
#define MAXUSHORT
Definition: typedefs.h:83
#define IN
Definition: typedefs.h:39
int32_t * PLONG
Definition: typedefs.h:58
uint16_t * PWCHAR
Definition: typedefs.h:56
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:112
_In_ WDFTIMER _In_ LONGLONG DueTime
Definition: wdftimer.h:190
VOID NTAPI ExQueueWorkItem(IN PWORK_QUEUE_ITEM WorkItem, IN WORK_QUEUE_TYPE QueueType)
Definition: work.c:723
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
#define ExInitializeWorkItem(Item, Routine, Context)
Definition: exfuncs.h:265
_In_opt_ PALLOCATE_FUNCTION Allocate
Definition: exfuncs.h:814
@ DelayedWorkQueue
Definition: extypes.h:190
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:688
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:687
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:689
_Inout_opt_ PVOID Parameter
Definition: rtltypes.h:323
__wchar_t WCHAR
Definition: xmlstorage.h:180