ReactOS 0.4.15-dev-5863-g1fe3ab7
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 * FILE: ntoskrnl/config/cmlazy.c
5 * PURPOSE: Configuration Manager - Internal Registry APIs
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9/* INCLUDES *******************************************************************/
10
11#include "ntoskrnl.h"
12//#define NDEBUG
13#include "debug.h"
14
15/* GLOBALS ********************************************************************/
16
29
30/* FUNCTIONS ******************************************************************/
31
36 _Out_ PULONG DirtyCount)
37{
39 PLIST_ENTRY NextEntry;
40 PCMHIVE CmHive;
42 ULONG HiveCount = CmpLazyFlushHiveCount;
43
44 /* Set Defaults */
45 *Error = FALSE;
46 *DirtyCount = 0;
47
48 /* Don't do anything if we're not supposed to */
49 if (CmpNoWrite) return TRUE;
50
51 /* Make sure we have to flush at least one hive */
52 if (!HiveCount) HiveCount = 1;
53
54 /* Acquire the list lock and loop */
56 NextEntry = CmpHiveListHead.Flink;
57 while ((NextEntry != &CmpHiveListHead) && HiveCount)
58 {
59 /* Get the hive and check if we should flush it */
60 CmHive = CONTAINING_RECORD(NextEntry, CMHIVE, HiveList);
61 if (!(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH) &&
62 (CmHive->FlushCount != CmpLazyFlushCount))
63 {
64 /* Great sucess! */
65 Result = TRUE;
66
67 /* One less to flush */
68 HiveCount--;
69
70 /* Ignore clean or volatile hives */
71 if ((!CmHive->Hive.DirtyCount && !ForceFlush) ||
72 (CmHive->Hive.HiveFlags & HIVE_VOLATILE))
73 {
74 /* Don't do anything but do update the count */
76 DPRINT("Hive %wZ is clean.\n", &CmHive->FileFullPath);
77 }
78 else
79 {
80 /* Do the sync */
81 DPRINT("Flushing: %wZ\n", &CmHive->FileFullPath);
82 DPRINT("Handle: %p\n", CmHive->FileHandles[HFILE_TYPE_PRIMARY]);
83 Status = HvSyncHive(&CmHive->Hive);
84 if(!NT_SUCCESS(Status))
85 {
86 /* Let them know we failed */
87 DPRINT1("Failed to flush %wZ on handle %p (status 0x%08lx)\n",
89 *Error = TRUE;
90 Result = FALSE;
91 break;
92 }
94 }
95 }
96 else if ((CmHive->Hive.DirtyCount) &&
97 (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE)) &&
98 (!(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH)))
99 {
100 /* Use another lazy flusher for this hive */
102 *DirtyCount += CmHive->Hive.DirtyCount;
103 DPRINT("CmHive %wZ already uptodate.\n", &CmHive->FileFullPath);
104 }
105
106 /* Try the next one */
107 NextEntry = NextEntry->Flink;
108 }
109
110 /* Check if we've flushed everything */
111 if (NextEntry == &CmpHiveListHead)
112 {
113 /* We have, tell the caller we're done */
114 Result = FALSE;
115 }
116 else
117 {
118 /* We need to be called again */
119 Result = TRUE;
120 }
121
122 /* Unlock the list and return the result */
124 return Result;
125}
126
127_Function_class_(KDEFERRED_ROUTINE)
128VOID
129NTAPI
130CmpEnableLazyFlushDpcRoutine(IN PKDPC Dpc,
134{
135 /* Don't stop lazy flushing from happening anymore */
137}
138
139_Function_class_(KDEFERRED_ROUTINE)
140VOID
141NTAPI
142CmpLazyFlushDpcRoutine(IN PKDPC Dpc,
146{
147 /* Check if we should queue the lazy flush worker */
148 DPRINT("Flush pending: %s, Holding lazy flush: %s.\n", CmpLazyFlushPending ? "yes" : "no", CmpHoldLazyFlush ? "yes" : "no");
150 {
153 }
154}
155
156VOID
157NTAPI
159{
161 PAGED_CODE();
162
163 /* Check if we should set the lazy flush timer */
164 if ((!CmpNoWrite) && (!CmpHoldLazyFlush))
165 {
166 /* Do it */
168 -10 * 1000 * 1000);
170 }
171}
172
173_Function_class_(WORKER_THREAD_ROUTINE)
174VOID
175NTAPI
176CmpLazyFlushWorker(IN PVOID Parameter)
177{
178 BOOLEAN ForceFlush, Result, MoreWork = FALSE;
179 ULONG DirtyCount = 0;
180 PAGED_CODE();
181
182 /* Don't do anything if lazy flushing isn't enabled yet */
184 {
185 DPRINT1("Lazy flush held. Bye bye.\n");
187 return;
188 }
189
190 /* Check if we are forcing a flush */
191 ForceFlush = CmpForceForceFlush;
192 if (ForceFlush)
193 {
194 DPRINT("Forcing flush.\n");
195 /* Lock the registry exclusively */
197 }
198 else
199 {
200 DPRINT("Not forcing flush.\n");
201 /* Starve writers before locking */
204 }
205
206 /* Flush the next hive */
207 MoreWork = CmpDoFlushNextHive(ForceFlush, &Result, &DirtyCount);
208 if (!MoreWork)
209 {
210 /* We're done */
212 }
213
214 /* Check if we have starved writers */
215 if (!ForceFlush)
217
218 /* Not pending anymore, release the registry lock */
221
222 DPRINT("Lazy flush done. More work to be done: %s. Entries still dirty: %u.\n",
223 MoreWork ? "Yes" : "No", DirtyCount);
224
225 if (MoreWork)
226 {
227 /* Relaunch the flush timer, so the remaining hives get flushed */
228 CmpLazyFlush();
229 }
230}
231
232VOID
233NTAPI
235{
237 PAGED_CODE();
238
239 /* Setup the lazy DPC */
240 KeInitializeDpc(&CmpLazyFlushDpc, CmpLazyFlushDpcRoutine, NULL);
241
242 /* Setup the lazy timer */
244
245 /* Setup the lazy worker */
246 ExInitializeWorkItem(&CmpLazyWorkItem, CmpLazyFlushWorker, NULL);
247
248 /* Setup the forced-lazy DPC and timer */
250 CmpEnableLazyFlushDpcRoutine,
251 NULL);
253
254 /* Enable lazy flushing after 10 minutes */
255 DueTime.QuadPart = Int32x32To64(600, -10 * 1000 * 1000);
257
258 /* Setup flush variables */
260 CmpWasSetupBoot = SetupBoot;
261
262 /* Testing: Force Lazy Flushing */
264
265 /* Setup the hive list if this is not a Setup boot */
266 if (!SetupBoot)
268}
269
271NTAPI
273 IN PSECURITY_CLIENT_CONTEXT ImpersonationContext,
275 OUT PCMHIVE *NewHive,
276 IN ULONG CheckFlags)
277{
282 OBJECT_NAME_INFORMATION DummyNameInfo;
283 POBJECT_NAME_INFORMATION FileNameInfo;
284
285 PAGED_CODE();
286
287 if (FileAttributes->RootDirectory)
288 {
289 /*
290 * Validity check: The ObjectName is relative to RootDirectory,
291 * therefore it must not start with a path separator.
292 */
293 if (FileAttributes->ObjectName && FileAttributes->ObjectName->Buffer &&
294 FileAttributes->ObjectName->Length >= sizeof(WCHAR) &&
295 *FileAttributes->ObjectName->Buffer == OBJ_NAME_PATH_SEPARATOR)
296 {
298 }
299
300 /* Determine the right buffer size and allocate */
301 Status = ZwQueryObject(FileAttributes->RootDirectory,
303 &DummyNameInfo,
304 sizeof(DummyNameInfo),
305 &Length);
307 {
308 DPRINT1("CmpCmdHiveOpen(): Root directory handle object name size query failed, Status = 0x%08lx\n", Status);
309 return Status;
310 }
311
312 FileNameInfo = ExAllocatePoolWithTag(PagedPool,
313 Length + sizeof(UNICODE_NULL),
314 TAG_CM);
315 if (FileNameInfo == NULL)
316 {
317 DPRINT1("CmpCmdHiveOpen(): Unable to allocate memory\n");
319 }
320
321 /* Try to get the value */
322 Status = ZwQueryObject(FileAttributes->RootDirectory,
324 FileNameInfo,
325 Length,
326 &Length);
327 if (!NT_SUCCESS(Status))
328 {
329 /* Fail */
330 DPRINT1("CmpCmdHiveOpen(): Root directory handle object name query failed, Status = 0x%08lx\n", Status);
331 ExFreePoolWithTag(FileNameInfo, TAG_CM);
332 return Status;
333 }
334
335 /* Null-terminate and add the length of the terminator */
337 FilePath = FileNameInfo->Name.Buffer;
338 FilePath[Length / sizeof(WCHAR)] = UNICODE_NULL;
339 Length += sizeof(UNICODE_NULL);
340
341 /* Compute the size of the full path; Length already counts the terminating NULL */
342 Length = Length + sizeof(WCHAR) + FileAttributes->ObjectName->Length;
344 {
345 /* Name size too long, bail out */
346 ExFreePoolWithTag(FileNameInfo, TAG_CM);
348 }
349
350 /* Build the full path */
351 RtlInitEmptyUnicodeString(&FileName, NULL, 0);
353 if (!FileName.Buffer)
354 {
355 /* Fail */
356 DPRINT1("CmpCmdHiveOpen(): Unable to allocate memory\n");
357 ExFreePoolWithTag(FileNameInfo, TAG_CM);
359 }
360 FileName.MaximumLength = Length;
361 RtlCopyUnicodeString(&FileName, &FileNameInfo->Name);
362 ExFreePoolWithTag(FileNameInfo, TAG_CM);
363
364 /*
365 * Append a path terminator if needed (we have already accounted
366 * for a possible extra one when allocating the buffer).
367 */
368 if (/* FileAttributes->ObjectName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR && */ // We excluded ObjectName starting with a path separator above.
369 FileName.Length > 0 && FileName.Buffer[FileName.Length / sizeof(WCHAR) - 1] != OBJ_NAME_PATH_SEPARATOR)
370 {
371 /* ObjectName does not start with '\' and PathBuffer does not end with '\' */
372 FileName.Buffer[FileName.Length / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
373 FileName.Length += sizeof(WCHAR);
374 FileName.Buffer[FileName.Length / sizeof(WCHAR)] = UNICODE_NULL;
375 }
376
377 /* Append the object name */
379 if (!NT_SUCCESS(Status))
380 {
381 /* Fail */
382 DPRINT1("CmpCmdHiveOpen(): RtlAppendUnicodeStringToString() failed, Status = 0x%08lx\n", Status);
384 return Status;
385 }
386 }
387 else
388 {
389 FileName = *FileAttributes->ObjectName;
390 }
391
392 /* Open the file in the current security context */
394 0,
395 NewHive,
396 Allocate,
397 CheckFlags);
398 if (((Status == STATUS_ACCESS_DENIED) ||
404 (ImpersonationContext))
405 {
406 /* We failed due to an account/security error, impersonate SYSTEM */
407 Status = SeImpersonateClientEx(ImpersonationContext, NULL);
408 if (NT_SUCCESS(Status))
409 {
410 /* Now try again */
412 0,
413 NewHive,
414 Allocate,
415 CheckFlags);
416
417 /* Restore impersonation token */
419 }
420 }
421
422 if (FileAttributes->RootDirectory)
423 {
425 }
426
427 /* Return status of open attempt */
428 return Status;
429}
430
431VOID
432NTAPI
434{
435 /* Stop lazy flushing */
436 PAGED_CODE();
438}
439
440VOID
441NTAPI
443{
444 /* Set state for lazy flusher */
446}
447
448/* 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
VOID NTAPI CmpLazyFlush(VOID)
Definition: cmlazy.c:158
KDPC CmpEnableLazyFlushDpc
Definition: cmlazy.c:21
static ULONG CmpLazyFlushHiveCount
Definition: cmlazy.c:26
ULONG CmpLazyFlushCount
Definition: cmlazy.c:27
LONG CmpFlushStarveWriters
Definition: cmlazy.c:28
ULONG CmpLazyFlushIntervalInSeconds
Definition: cmlazy.c:25
VOID NTAPI CmpCmdInit(IN BOOLEAN SetupBoot)
Definition: cmlazy.c:234
BOOLEAN NTAPI CmpDoFlushNextHive(_In_ BOOLEAN ForceFlush, _Out_ PBOOLEAN Error, _Out_ PULONG DirtyCount)
Definition: cmlazy.c:34
VOID NTAPI CmpShutdownWorkers(VOID)
Definition: cmlazy.c:433
KTIMER CmpEnableLazyFlushTimer
Definition: cmlazy.c:20
KDPC CmpLazyFlushDpc
Definition: cmlazy.c:18
WORK_QUEUE_ITEM CmpLazyWorkItem
Definition: cmlazy.c:19
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:272
VOID NTAPI CmSetLazyFlushState(IN BOOLEAN Enable)
Definition: cmlazy.c:442
BOOLEAN CmpForceForceFlush
Definition: cmlazy.c:23
BOOLEAN CmpHoldLazyFlush
Definition: cmlazy.c:24
KTIMER CmpLazyFlushTimer
Definition: cmlazy.c:17
BOOLEAN CmpLazyFlushPending
Definition: cmlazy.c:22
BOOLEAN CMAPI HvSyncHive(PHHIVE RegistryHive)
Definition: hivewrt.c:243
#define TAG_CM
Definition: cmlib.h:205
VOID NTAPI CmpLockRegistryExclusive(VOID)
Definition: cmsysini.c:1845
VOID NTAPI CmpUnlockRegistry(VOID)
Definition: cmsysini.c:1944
VOID NTAPI CmpLockRegistry(VOID)
Definition: cmsysini.c:1858
VOID NTAPI CmpInitializeHiveList(VOID)
Definition: cmsysini.c:1358
LIST_ENTRY CmpHiveListHead
Definition: cmsysini.c:18
BOOLEAN CmpWasSetupBoot
Definition: cmsysini.c:30
BOOLEAN CmpNoWrite
Definition: cmsysini.c:29
NTSTATUS NTAPI CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName, IN ULONG HiveFlags, OUT PCMHIVE *Hive, IN OUT PBOOLEAN New, IN ULONG CheckFlags)
Definition: cmsysini.c:286
#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:1295
FORCEINLINE VOID ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock)
Definition: ex.h:1104
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
_In_ PVOID Parameter
Definition: ldrtypes.h:241
if(dx< 0)
Definition: linetemp.h:194
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
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:245
ULONG FlushCount
Definition: cmlib.h:285
HHIVE Hive
Definition: cmlib.h:246
HANDLE FileHandles[HFILE_TYPE_MAX]
Definition: cmlib.h:247
UNICODE_STRING FileFullPath
Definition: cmlib.h:262
ULONG HiveFlags
Definition: hivedata.h:321
ULONG DirtyCount
Definition: hivedata.h:305
Definition: ketypes.h:687
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:426
#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:676
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:675
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:677
__wchar_t WCHAR
Definition: xmlstorage.h:180