Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

cmworker.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1992 Microsoft Corporation 00004 00005 Module Name: 00006 00007 cmworker.c 00008 00009 Abstract: 00010 00011 This module contains support for the worker thread of the registry. 00012 The worker thread (actually an executive worker thread is used) is 00013 required for operations that must take place in the context of the 00014 system process. (particularly file I/O) 00015 00016 Author: 00017 00018 John Vert (jvert) 21-Oct-1992 00019 00020 Revision History: 00021 00022 --*/ 00023 00024 #include "cmp.h" 00025 00026 extern LIST_ENTRY CmpHiveListHead; 00027 00028 VOID 00029 CmpInitializeHiveList( 00030 VOID 00031 ); 00032 00033 // 00034 // ----- LAZY FLUSH CONTROL ----- 00035 // 00036 // LAZY_FLUSH_INTERVAL_IN_SECONDS controls how many seconds will elapse 00037 // between when the hive is marked dirty and when the lazy flush worker 00038 // thread is queued to write the data to disk. 00039 // 00040 #define LAZY_FLUSH_INTERVAL_IN_SECONDS 5 00041 00042 // 00043 // LAZY_FLUSH_TIMEOUT_IN_SECONDS controls how long the lazy flush worker 00044 // thread will wait for the registry lock before giving up and queueing 00045 // the lazy flush timer again. 00046 // 00047 #define LAZY_FLUSH_TIMEOUT_IN_SECONDS 1 00048 00049 #define SECOND_MULT 10*1000*1000 // 10->mic, 1000->mil, 1000->second 00050 00051 PKPROCESS CmpSystemProcess; 00052 KTIMER CmpLazyFlushTimer; 00053 KDPC CmpLazyFlushDpc; 00054 WORK_QUEUE_ITEM CmpLazyWorkItem; 00055 00056 BOOLEAN CmpLazyFlushPending = FALSE; 00057 00058 extern BOOLEAN CmpNoWrite; 00059 extern BOOLEAN CmpWasSetupBoot; 00060 extern BOOLEAN HvShutdownComplete; 00061 extern BOOLEAN CmpProfileLoaded; 00062 00063 // 00064 // Indicate whether the "disk full" popup has been triggered yet or not. 00065 // 00066 extern BOOLEAN CmpDiskFullWorkerPopupDisplayed; 00067 00068 // 00069 // set to true if disk full when trying to save the changes made between system hive loading and registry initalization 00070 // 00071 extern BOOLEAN CmpCannotWriteConfiguration; 00072 00073 #if DBG 00074 PKTHREAD CmpCallerThread = NULL; 00075 #endif 00076 00077 // 00078 // Local function prototypes 00079 // 00080 00081 VOID 00082 CmpLazyFlushWorker( 00083 IN PVOID Parameter 00084 ); 00085 00086 VOID 00087 CmpLazyFlushDpcRoutine( 00088 IN PKDPC Dpc, 00089 IN PVOID DeferredContext, 00090 IN PVOID SystemArgument1, 00091 IN PVOID SystemArgument2 00092 ); 00093 00094 VOID 00095 CmpDiskFullWarningWorker( 00096 IN PVOID WorkItem 00097 ); 00098 00099 VOID 00100 CmpDiskFullWarning( 00101 VOID 00102 ); 00103 00104 #ifdef ALLOC_PRAGMA 00105 #pragma alloc_text(PAGE,CmpWorker) 00106 #pragma alloc_text(PAGE,CmpLazyFlush) 00107 #pragma alloc_text(PAGE,CmpLazyFlushWorker) 00108 #pragma alloc_text(PAGE,CmpDiskFullWarningWorker) 00109 #pragma alloc_text(PAGE,CmpDiskFullWarning) 00110 #endif 00111 00112 00113 00114 VOID 00115 CmpWorker( 00116 IN PREGISTRY_COMMAND CommandArea 00117 ) 00118 /*++ 00119 00120 Routine Description: 00121 00122 Actually execute the command specified in CommandArea, and 00123 report its completion. 00124 00125 Arguments: 00126 00127 Parameter - supplies a pointer to the REGISTRY_COMMAND structure to 00128 be executed. 00129 00130 Return Value: 00131 00132 --*/ 00133 { 00134 NTSTATUS Status; 00135 PCMHIVE CmHive; 00136 IO_STATUS_BLOCK IoStatusBlock; 00137 PUNICODE_STRING FileName; 00138 ULONG i; 00139 HANDLE Handle; 00140 PFILE_RENAME_INFORMATION RenameInfo; 00141 PLIST_ENTRY p; 00142 BOOLEAN result; 00143 HANDLE NullHandle; 00144 00145 PAGED_CODE(); 00146 00147 switch (CommandArea->Command) { 00148 00149 case REG_CMD_INIT: 00150 // 00151 // Initialize lazy flush timer and DPC 00152 // 00153 KeInitializeDpc(&CmpLazyFlushDpc, 00154 CmpLazyFlushDpcRoutine, 00155 NULL); 00156 00157 KeInitializeTimer(&CmpLazyFlushTimer); 00158 00159 ExInitializeWorkItem(&CmpLazyWorkItem, CmpLazyFlushWorker, NULL); 00160 00161 CmpNoWrite = FALSE; 00162 00163 CmpWasSetupBoot = CommandArea->SetupBoot; 00164 if (CommandArea->SetupBoot == FALSE) { 00165 CmpInitializeHiveList(); 00166 } 00167 00168 // 00169 // flush dirty data to disk 00170 // 00171 CmpDoFlushAll(); 00172 break; 00173 00174 case REG_CMD_FLUSH_KEY: 00175 CommandArea->Status = 00176 CmFlushKey(CommandArea->Hive, CommandArea->Cell); 00177 break; 00178 00179 case REG_CMD_REFRESH_HIVE: 00180 // 00181 // Refresh hive to match last flushed version 00182 // 00183 HvRefreshHive(CommandArea->Hive); 00184 break; 00185 00186 case REG_CMD_FILE_SET_SIZE: 00187 CommandArea->Status = CmpDoFileSetSize( 00188 CommandArea->Hive, 00189 CommandArea->FileType, 00190 CommandArea->FileSize 00191 ); 00192 break; 00193 00194 case REG_CMD_HIVE_OPEN: 00195 00196 // 00197 // Open the file. 00198 // 00199 FileName = CommandArea->FileAttributes->ObjectName; 00200 00201 CommandArea->Status = CmpInitHiveFromFile(FileName, 00202 0, 00203 &CommandArea->CmHive, 00204 &CommandArea->Allocate, 00205 &CommandArea->RegistryLockAquired); 00206 // 00207 // NT Servers will return STATUS_ACCESS_DENIED. Netware 3.1x 00208 // servers could return any of the other error codes if the GUEST 00209 // account is disabled. 00210 // 00211 if (((CommandArea->Status == STATUS_ACCESS_DENIED) || 00212 (CommandArea->Status == STATUS_NO_SUCH_USER) || 00213 (CommandArea->Status == STATUS_WRONG_PASSWORD) || 00214 (CommandArea->Status == STATUS_ACCOUNT_EXPIRED) || 00215 (CommandArea->Status == STATUS_ACCOUNT_DISABLED) || 00216 (CommandArea->Status == STATUS_ACCOUNT_RESTRICTION)) && 00217 (CommandArea->ImpersonationContext != NULL)) { 00218 // 00219 // Impersonate the caller and try it again. This 00220 // lets us open hives on a remote machine. 00221 // 00222 Status = SeImpersonateClientEx( 00223 CommandArea->ImpersonationContext, 00224 NULL); 00225 00226 if ( NT_SUCCESS( Status ) ) { 00227 00228 CommandArea->Status = CmpInitHiveFromFile(FileName, 00229 0, 00230 &CommandArea->CmHive, 00231 &CommandArea->Allocate, 00232 &CommandArea->RegistryLockAquired); 00233 NullHandle = NULL; 00234 00235 PsRevertToSelf(); 00236 } 00237 } 00238 00239 break; 00240 00241 case REG_CMD_HIVE_CLOSE: 00242 00243 // 00244 // Close the files associated with this hive. 00245 // 00246 CmHive = CommandArea->CmHive; 00247 00248 for (i=0; i<HFILE_TYPE_MAX; i++) { 00249 if (CmHive->FileHandles[i] != NULL) { 00250 ZwClose(CmHive->FileHandles[i]); 00251 CmHive->FileHandles[i] = NULL; 00252 } 00253 } 00254 CommandArea->Status = STATUS_SUCCESS; 00255 break; 00256 00257 case REG_CMD_HIVE_READ: 00258 00259 // 00260 // Used by special case of savekey, just do a read 00261 // 00262 result = CmpFileRead( 00263 (PHHIVE)CommandArea->CmHive, 00264 CommandArea->FileType, 00265 CommandArea->Offset, 00266 CommandArea->Buffer, 00267 CommandArea->FileSize // read length 00268 ); 00269 if (result) { 00270 CommandArea->Status = STATUS_SUCCESS; 00271 } else { 00272 CommandArea->Status = STATUS_REGISTRY_IO_FAILED; 00273 } 00274 break; 00275 00276 case REG_CMD_SHUTDOWN: 00277 00278 // 00279 // shut down the registry 00280 // 00281 CmpDoFlushAll(); 00282 00283 // 00284 // close all the hive files 00285 // 00286 p=CmpHiveListHead.Flink; 00287 while (p!=&CmpHiveListHead) { 00288 CmHive = CONTAINING_RECORD(p, CMHIVE, HiveList); 00289 for (i=0; i<HFILE_TYPE_MAX; i++) { 00290 if (CmHive->FileHandles[i] != NULL) { 00291 ZwClose(CmHive->FileHandles[i]); 00292 CmHive->FileHandles[i] = NULL; 00293 } 00294 } 00295 p=p->Flink; 00296 } 00297 00298 break; 00299 00300 case REG_CMD_RENAME_HIVE: 00301 // 00302 // Rename a CmHive's primary handle 00303 // 00304 Handle = CommandArea->CmHive->FileHandles[HFILE_TYPE_PRIMARY]; 00305 if (CommandArea->OldName != NULL) { 00306 ASSERT_PASSIVE_LEVEL(); 00307 Status = ZwQueryObject(Handle, 00308 ObjectNameInformation, 00309 CommandArea->OldName, 00310 CommandArea->NameInfoLength, 00311 &CommandArea->NameInfoLength); 00312 if (!NT_SUCCESS(Status)) { 00313 CommandArea->Status = Status; 00314 break; 00315 } 00316 } 00317 00318 RenameInfo = ExAllocatePool(PagedPool, 00319 sizeof(FILE_RENAME_INFORMATION) + 00320 CommandArea->NewName->Length); 00321 if (RenameInfo == NULL) { 00322 CommandArea->Status = STATUS_INSUFFICIENT_RESOURCES; 00323 break; 00324 } 00325 RenameInfo->ReplaceIfExists = FALSE; 00326 RenameInfo->RootDirectory = NULL; 00327 RenameInfo->FileNameLength = CommandArea->NewName->Length; 00328 RtlMoveMemory(RenameInfo->FileName, 00329 CommandArea->NewName->Buffer, 00330 CommandArea->NewName->Length); 00331 00332 Status = ZwSetInformationFile(Handle, 00333 &IoStatusBlock, 00334 (PVOID)RenameInfo, 00335 sizeof(FILE_RENAME_INFORMATION) + 00336 CommandArea->NewName->Length, 00337 FileRenameInformation); 00338 ExFreePool(RenameInfo); 00339 CommandArea->Status = Status; 00340 break; 00341 00342 case REG_CMD_ADD_HIVE_LIST: 00343 // 00344 // Add a hive to the hive file list 00345 // 00346 Status = CmpAddToHiveFileList(CommandArea->CmHive); 00347 CommandArea->Status = Status; 00348 break; 00349 00350 case REG_CMD_REMOVE_HIVE_LIST: 00351 // 00352 // Remove a hive from the hive file list 00353 // 00354 CmpRemoveFromHiveFileList(CommandArea->CmHive); 00355 CommandArea->Status = STATUS_SUCCESS; 00356 break; 00357 00358 default: 00359 KeBugCheckEx(REGISTRY_ERROR,6,1,0,0); 00360 00361 } // switch 00362 00363 return; 00364 } 00365 00366 00367 VOID 00368 CmpLazyFlush( 00369 VOID 00370 ) 00371 00372 /*++ 00373 00374 Routine Description: 00375 00376 This routine resets the registry timer to go off at a specified interval 00377 in the future (LAZY_FLUSH_INTERVAL_IN_SECONDS). 00378 00379 Arguments: 00380 00381 None 00382 00383 Return Value: 00384 00385 None. 00386 00387 --*/ 00388 00389 { 00390 LARGE_INTEGER DueTime; 00391 00392 PAGED_CODE(); 00393 CMLOG(CML_FLOW, CMS_IO) { 00394 KdPrint(("CmpLazyFlush: setting lazy flush timer\n")); 00395 } 00396 if (!CmpNoWrite) { 00397 00398 DueTime.QuadPart = Int32x32To64(LAZY_FLUSH_INTERVAL_IN_SECONDS, 00399 - SECOND_MULT); 00400 00401 // 00402 // Indicate relative time 00403 // 00404 00405 KeSetTimer(&CmpLazyFlushTimer, 00406 DueTime, 00407 &CmpLazyFlushDpc); 00408 00409 } 00410 00411 00412 } 00413 00414 00415 VOID 00416 CmpLazyFlushDpcRoutine( 00417 IN PKDPC Dpc, 00418 IN PVOID DeferredContext, 00419 IN PVOID SystemArgument1, 00420 IN PVOID SystemArgument2 00421 ) 00422 00423 /*++ 00424 00425 Routine Description: 00426 00427 This is the DPC routine triggered by the lazy flush timer. All it does 00428 is queue a work item to an executive worker thread. The work item will 00429 do the actual lazy flush to disk. 00430 00431 Arguments: 00432 00433 Dpc - Supplies a pointer to the DPC object. 00434 00435 DeferredContext - not used 00436 00437 SystemArgument1 - not used 00438 00439 SystemArgument2 - not used 00440 00441 Return Value: 00442 00443 None. 00444 00445 --*/ 00446 00447 { 00448 CMLOG(CML_FLOW, CMS_IO) { 00449 KdPrint(("CmpLazyFlushDpc: queuing lazy flush work item\n")); 00450 } 00451 00452 if (!CmpLazyFlushPending) { 00453 CmpLazyFlushPending = TRUE; 00454 ExQueueWorkItem(&CmpLazyWorkItem, DelayedWorkQueue); 00455 } 00456 00457 } 00458 00459 00460 VOID 00461 CmpLazyFlushWorker( 00462 IN PVOID Parameter 00463 ) 00464 00465 /*++ 00466 00467 Routine Description: 00468 00469 Worker routine called to do a lazy flush. Called by an executive worker 00470 thread in the system process. 00471 00472 Arguments: 00473 00474 Parameter - not used. 00475 00476 Return Value: 00477 00478 None. 00479 00480 --*/ 00481 00482 { 00483 BOOLEAN Result = TRUE; 00484 00485 PAGED_CODE(); 00486 00487 CMLOG(CML_FLOW, CMS_IO) { 00488 KdPrint(("CmpLazyFlushWorker: flushing hives\n")); 00489 } 00490 00491 CmpLockRegistry(); 00492 if (!HvShutdownComplete) { 00493 Result = CmpDoFlushAll(); 00494 } 00495 CmpLazyFlushPending = FALSE; 00496 CmpUnlockRegistry(); 00497 00498 if( CmpCannotWriteConfiguration ) { 00499 // 00500 // Disk full; system hive haven't been save at initialization 00501 // 00502 if(Result) { 00503 // 00504 // All hives were saved; No need for disk full warning anymore 00505 // 00506 CmpCannotWriteConfiguration = FALSE; 00507 } else { 00508 // 00509 // Issue another hard error (if not already displayed) and postpone a lazy flush operation 00510 // 00511 CmpDiskFullWarning(); 00512 CmpLazyFlush(); 00513 } 00514 } 00515 } 00516 00517 VOID 00518 CmpDiskFullWarningWorker( 00519 IN PVOID WorkItem 00520 ) 00521 00522 /*++ 00523 00524 Routine Description: 00525 00526 Displays hard error popup that indicates the disk is full. 00527 00528 Arguments: 00529 00530 WorkItem - Supplies pointer to the work item. This routine will 00531 free the work item. 00532 00533 Return Value: 00534 00535 None. 00536 00537 --*/ 00538 00539 { 00540 NTSTATUS Status; 00541 ULONG Response; 00542 00543 ExFreePool(WorkItem); 00544 00545 Status = ExRaiseHardError(STATUS_DISK_FULL, 00546 0, 00547 0, 00548 NULL, 00549 OptionOk, 00550 &Response); 00551 } 00552 00553 00554 00555 VOID 00556 CmpDiskFullWarning( 00557 VOID 00558 ) 00559 /*++ 00560 00561 Routine Description: 00562 00563 Raises a hard error of type STATUS_DISK_FULL if wasn't already raised 00564 00565 Arguments: 00566 00567 None 00568 00569 Return Value: 00570 00571 None 00572 00573 --*/ 00574 { 00575 PWORK_QUEUE_ITEM WorkItem; 00576 00577 if( (!CmpDiskFullWorkerPopupDisplayed) && (CmpCannotWriteConfiguration) && (ExReadyForErrors) && (CmpProfileLoaded) ) { 00578 00579 // 00580 // Queue work item to display popup 00581 // 00582 WorkItem = ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM)); 00583 if (WorkItem != NULL) { 00584 00585 CmpDiskFullWorkerPopupDisplayed = TRUE; 00586 ExInitializeWorkItem(WorkItem, 00587 CmpDiskFullWarningWorker, 00588 WorkItem); 00589 ExQueueWorkItem(WorkItem, DelayedWorkQueue); 00590 } 00591 } 00592 }

Generated on Sat May 15 19:39:29 2004 for test by doxygen 1.3.7