ReactOS  0.4.12-dev-916-gffc4e30
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  UCHAR Buffer[sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
282  ULONG Length = sizeof(Buffer);
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  /* Try to get the value */
301  Status = ZwQueryObject(FileAttributes->RootDirectory,
303  FileNameInfo,
304  Length,
305  &Length);
306  if (!NT_SUCCESS(Status))
307  {
308  /* Fail */
309  DPRINT1("CmpCmdHiveOpen(): Root directory handle object name query failed, Status = 0x%08lx\n", Status);
310  return Status;
311  }
312 
313  /* Null-terminate and add the length of the terminator */
314  Length -= sizeof(OBJECT_NAME_INFORMATION);
315  FilePath = FileNameInfo->Name.Buffer;
316  FilePath[Length / sizeof(WCHAR)] = UNICODE_NULL;
317  Length += sizeof(UNICODE_NULL);
318 
319  /* Compute the size of the full path; Length already counts the terminating NULL */
320  Length = Length + sizeof(WCHAR) + FileAttributes->ObjectName->Length;
321  if (Length > MAXUSHORT)
322  {
323  /* Name size too long, bail out */
325  }
326 
327  /* Build the full path */
328  RtlInitEmptyUnicodeString(&FileName, NULL, 0);
330  if (!FileName.Buffer)
331  {
332  /* Fail */
333  DPRINT1("CmpCmdHiveOpen(): Unable to allocate memory\n");
335  }
336  FileName.MaximumLength = Length;
337  RtlCopyUnicodeString(&FileName, &FileNameInfo->Name);
338 
339  /*
340  * Append a path terminator if needed (we have already accounted
341  * for a possible extra one when allocating the buffer).
342  */
343  if (/* FileAttributes->ObjectName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR && */ // We excluded ObjectName starting with a path separator above.
344  FileName.Length > 0 && FileName.Buffer[FileName.Length / sizeof(WCHAR) - 1] != OBJ_NAME_PATH_SEPARATOR)
345  {
346  /* ObjectName does not start with '\' and PathBuffer does not end with '\' */
347  FileName.Buffer[FileName.Length / sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
348  FileName.Length += sizeof(WCHAR);
349  FileName.Buffer[FileName.Length / sizeof(WCHAR)] = UNICODE_NULL;
350  }
351 
352  /* Append the object name */
354  if (!NT_SUCCESS(Status))
355  {
356  /* Fail */
357  DPRINT1("CmpCmdHiveOpen(): RtlAppendUnicodeStringToString() failed, Status = 0x%08lx\n", Status);
359  return Status;
360  }
361  }
362  else
363  {
364  FileName = *FileAttributes->ObjectName;
365  }
366 
367  /* Open the file in the current security context */
369  0,
370  NewHive,
371  Allocate,
372  CheckFlags);
373  if (((Status == STATUS_ACCESS_DENIED) ||
379  (ImpersonationContext))
380  {
381  /* We failed due to an account/security error, impersonate SYSTEM */
382  Status = SeImpersonateClientEx(ImpersonationContext, NULL);
383  if (NT_SUCCESS(Status))
384  {
385  /* Now try again */
387  0,
388  NewHive,
389  Allocate,
390  CheckFlags);
391 
392  /* Restore impersonation token */
393  PsRevertToSelf();
394  }
395  }
396 
397  if (FileAttributes->RootDirectory)
398  {
400  }
401 
402  /* Return status of open attempt */
403  return Status;
404 }
405 
406 VOID
407 NTAPI
409 {
410  /* Stop lazy flushing */
411  PAGED_CODE();
413 }
414 
415 VOID
416 NTAPI
418 {
419  /* Set state for lazy flusher */
421 }
422 
423 /* EOF */
VOID NTAPI CmpInitializeHiveList(VOID)
Definition: cmsysini.c:1365
#define STATUS_WRONG_PASSWORD
Definition: ntstatus.h:328
#define IN
Definition: typedefs.h:38
VOID NTAPI CmpShutdownWorkers(VOID)
Definition: cmlazy.c:408
#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:548
#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:240
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:1900
Definition: bufpool.h:45
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:417
VOID NTAPI CmpUnlockRegistry(VOID)
Definition: cmsysini.c:1999
#define MAX_PATH
Definition: compat.h:26
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
unsigned char UCHAR
Definition: xmlstorage.h:181
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
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
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
VOID NTAPI CmpCmdInit(IN BOOLEAN SetupBoot)
Definition: cmlazy.c:234
signed int * PLONG
Definition: retypes.h:5
VOID NTAPI CmpLockRegistry(VOID)
Definition: cmsysini.c:1913
ULONG CmpLazyFlushCount
Definition: cmlazy.c:27
#define Int32x32To64(a, b)
Definition: cm.h:391
LONGLONG QuadPart
Definition: typedefs.h:112
struct _OBJECT_NAME_INFORMATION * POBJECT_NAME_INFORMATION
KDPC CmpEnableLazyFlushDpc
Definition: cmlazy.c:21
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:675