ReactOS  0.4.14-dev-50-g13bb5e2
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 
32 BOOLEAN
33 NTAPI
36  _Out_ PULONG DirtyCount)
37 {
39  PLIST_ENTRY NextEntry;
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);
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) ||
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]);
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) &&
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)
128 VOID
129 NTAPI
130 CmpEnableLazyFlushDpcRoutine(IN PKDPC Dpc,
134 {
135  /* Don't stop lazy flushing from happening anymore */
137 }
138 
139 _Function_class_(KDEFERRED_ROUTINE)
140 VOID
141 NTAPI
142 CmpLazyFlushDpcRoutine(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 
156 VOID
157 NTAPI
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)
174 VOID
175 NTAPI
176 CmpLazyFlushWorker(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 */
183  if (CmpHoldLazyFlush)
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 */
203  CmpLockRegistry();
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 
232 VOID
233 NTAPI
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 
270 NTSTATUS
271 NTAPI
273  IN PSECURITY_CLIENT_CONTEXT ImpersonationContext,
275  OUT PCMHIVE *NewHive,
276  IN ULONG CheckFlags)
277 {
281  ULONG Length;
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 */
336  Length -= sizeof(OBJECT_NAME_INFORMATION);
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;
343  if (Length > MAXUSHORT)
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 */
418  PsRevertToSelf();
419  }
420  }
421 
422  if (FileAttributes->RootDirectory)
423  {
425  }
426 
427  /* Return status of open attempt */
428  return Status;
429 }
430 
431 VOID
432 NTAPI
434 {
435  /* Stop lazy flushing */
436  PAGED_CODE();
438 }
439 
440 VOID
441 NTAPI
443 {
444  /* Set state for lazy flusher */
446 }
447 
448 /* EOF */
VOID NTAPI CmpInitializeHiveList(VOID)
Definition: cmsysini.c:1358
#define STATUS_WRONG_PASSWORD
Definition: ntstatus.h:328
#define IN
Definition: typedefs.h:38
VOID NTAPI CmpShutdownWorkers(VOID)
Definition: cmlazy.c:433
#define TRUE
Definition: types.h:120
VOID NTAPI ExQueueWorkItem(IN PWORK_QUEUE_ITEM WorkItem, IN WORK_QUEUE_TYPE QueueType)
Definition: work.c:717
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:281
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
KTIMER CmpLazyFlushTimer
Definition: cmlazy.c:17
LIST_ENTRY CmpHiveListHead
Definition: cmsysini.c:18
_In_ LARGE_INTEGER DueTime
Definition: kefuncs.h:524
NTKERNELAPI VOID NTAPI PsRevertToSelf(VOID)
Definition: security.c:556
#define HIVE_VOLATILE
Definition: hivedata.h:23
BOOLEAN NTAPI CmpDoFlushNextHive(_In_ BOOLEAN ForceFlush, _Out_ PBOOLEAN Error, _Out_ PULONG DirtyCount)
Definition: cmlazy.c:34
LONG NTSTATUS
Definition: precomp.h:26
_In_ ULONGLONG _In_ ULONGLONG _In_ BOOLEAN Enable
Definition: ntddpcm.h:140
KTIMER CmpEnableLazyFlushTimer
Definition: cmlazy.c:20
ULONG FlushCount
Definition: cm.h:432
uint16_t * PWCHAR
Definition: typedefs.h:54
UNICODE_STRING Name
Definition: nt_native.h:1270
_In_ PVOID Parameter
Definition: ldrtypes.h:241
BOOLEAN CmpHoldLazyFlush
Definition: cmlazy.c:24
ULONG DirtyCount
Definition: hivedata.h:305
_In_opt_ PALLOCATE_FUNCTION Allocate
Definition: exfuncs.h:656
#define PAGED_CODE()
Definition: video.h:57
#define STATUS_ACCOUNT_EXPIRED
Definition: ntstatus.h:622
NTSYSAPI VOID NTAPI RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString)
PCWSTR FilePath
#define STATUS_ACCOUNT_RESTRICTION
Definition: ntstatus.h:332
LONG CmpFlushStarveWriters
Definition: cmlazy.c:28
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define UNICODE_NULL
long LONG
Definition: pedump.c:60
#define OBJ_NAME_PATH_SEPARATOR
Definition: arcname_tests.c:25
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
HANDLE FileHandles[HFILE_TYPE_MAX]
Definition: cm.h:394
WORK_QUEUE_ITEM CmpLazyWorkItem
Definition: cmlazy.c:19
unsigned char BOOLEAN
struct _OBJECT_NAME_INFORMATION OBJECT_NAME_INFORMATION
KDPC CmpLazyFlushDpc
Definition: cmlazy.c:18
UNICODE_STRING FileFullPath
Definition: cm.h:409
smooth NULL
Definition: ftsmooth.c:416
_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 _Out_
Definition: no_sal2.h:323
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
HHIVE Hive
Definition: cm.h:393
void DPRINT(...)
Definition: polytest.cpp:61
VOID NTAPI CmpLockRegistryExclusive(VOID)
Definition: cmsysini.c:1894
ULONG CmpLazyFlushIntervalInSeconds
Definition: cmlazy.c:25
_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:1230
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:675
#define STATUS_NO_SUCH_USER
Definition: ntstatus.h:322
#define STATUS_ACCOUNT_DISABLED
Definition: ntstatus.h:336
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
_In_ LARGE_INTEGER _In_opt_ PKDPC Dpc
Definition: kefuncs.h:524
BOOLEAN NTAPI KeCancelTimer(IN OUT PKTIMER Timer)
Definition: timerobj.c:206
#define ExInitializeWorkItem(Item, Routine, Context)
Definition: exfuncs.h:265
BOOLEAN CmpLazyFlushPending
Definition: cmlazy.c:22
BOOLEAN CmpNoWrite
Definition: cmsysini.c:29
if(!(yy_init))
Definition: macro.lex.yy.c:714
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
VOID NTAPI CmSetLazyFlushState(IN BOOLEAN Enable)
Definition: cmlazy.c:442
VOID NTAPI CmpUnlockRegistry(VOID)
Definition: cmsysini.c:1993
BOOL Error
Definition: chkdsk.c:66
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
BOOLEAN CMAPI HvSyncHive(PHHIVE RegistryHive)
Definition: hivewrt.c:243
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
BOOLEAN CmpMiniNTBoot
Definition: cmdata.c:60
#define TAG_CM
Definition: cmlib.h:203
char * PBOOLEAN
Definition: retypes.h:11
#define InterlockedDecrement
Definition: armddk.h:52
Definition: ketypes.h:687
NTSTATUS NTAPI CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName, IN ULONG HiveFlags, OUT PCMHIVE *Hive, IN OUT PBOOLEAN New, IN ULONG CheckFlags)
Definition: cmsysini.c:286
Definition: typedefs.h:117
NTSTATUS NTAPI SeImpersonateClientEx(IN PSECURITY_CLIENT_CONTEXT ClientContext, IN PETHREAD ServerThread OPTIONAL)
Definition: access.c:589
Status
Definition: gdiplustypes.h:24
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:675
FORCEINLINE VOID ExReleasePushLock(PEX_PUSH_LOCK PushLock)
Definition: ex.h:1282
#define _In_
Definition: no_sal2.h:204
FORCEINLINE VOID ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock)
Definition: ex.h:1091
struct _FileName FileName
Definition: fatprocs.h:884
EX_PUSH_LOCK CmpHiveListHeadLock
Definition: cmdata.c:39
#define InterlockedIncrement
Definition: armddk.h:53
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:61
BOOLEAN CmpForceForceFlush
Definition: cmlazy.c:23
BOOLEAN CmpWasSetupBoot
Definition: cmsysini.c:30
#define HFILE_TYPE_PRIMARY
Definition: hivedata.h:33
ULONG HiveFlags
Definition: hivedata.h:321
NTSYSAPI NTSTATUS NTAPI RtlAppendUnicodeStringToString(PUNICODE_STRING Destination, PUNICODE_STRING Source)
static PCMHIVE CmHive
Definition: registry.c:28
static ULONG CmpLazyFlushHiveCount
Definition: cmlazy.c:26
unsigned int * PULONG
Definition: retypes.h:1
#define STATUS_OBJECT_PATH_INVALID
Definition: ntstatus.h:279
#define HIVE_NOLAZYFLUSH
Definition: hivedata.h:24
#define MAXUSHORT
Definition: typedefs.h:81
#define DPRINT1
Definition: precomp.h:8
#define OUT
Definition: typedefs.h:39
unsigned int ULONG
Definition: retypes.h:1
_Function_class_(KDEFERRED_ROUTINE)
Definition: cmlazy.c:127
VOID NTAPI CmpLazyFlush(VOID)
Definition: cmlazy.c:158
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define STATUS_OBJECT_PATH_SYNTAX_BAD
Definition: ntstatus.h:281
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:711
VOID NTAPI CmpCmdInit(IN BOOLEAN SetupBoot)
Definition: cmlazy.c:234
signed int * PLONG
Definition: retypes.h:5
VOID NTAPI CmpLockRegistry(VOID)
Definition: cmsysini.c:1907
ULONG CmpLazyFlushCount
Definition: cmlazy.c:27
#define Int32x32To64(a, b)
Definition: cm.h:391
LONGLONG QuadPart
Definition: typedefs.h:112
KDPC CmpEnableLazyFlushDpc
Definition: cmlazy.c:21
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:675