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

forksup.c File Reference

#include "mi.h"

Go to the source code of this file.

Defines

#define MM_FORK_SUCCEEDED   0
#define MM_FORK_FAILED   1

Functions

VOID MiUpPfnReferenceCount (IN PFN_NUMBER Page, IN USHORT Count)
VOID MiDownPfnReferenceCount (IN PFN_NUMBER Page, IN USHORT Count)
VOID MiUpControlAreaRefs (IN PCONTROL_AREA ControlArea)
ULONG MiDoneWithThisPageGetAnother (IN PPFN_NUMBER PageFrameIndex, IN PMMPTE PointerPde, IN PEPROCESS CurrentProcess)
VOID MiUpForkPageShareCount (IN PMMPFN PfnForkPtePage)
VOID MiUpCloneProcessRefCount (IN PMMCLONE_DESCRIPTOR Clone)
VOID MiUpCloneProtoRefCount (IN PMMCLONE_BLOCK CloneProto, IN PEPROCESS CurrentProcess)
ULONG MiHandleForkTransitionPte (IN PMMPTE PointerPte, IN PMMPTE PointerNewPte, IN PMMCLONE_BLOCK ForkProtoPte)
VOID MiDownShareCountFlushEntireTb (IN PFN_NUMBER PageFrameIndex)
VOID MiBuildForkPageTable (IN PFN_NUMBER PageFrameIndex, IN PMMPTE PointerPde, IN PMMPTE PointerNewPde, IN PFN_NUMBER PdePhysicalPage, IN PMMPFN PfnPdPage)
VOID MiRetrievePageDirectoryFrames (IN PFN_NUMBER RootPhysicalPage, OUT PPFN_NUMBER PageDirectoryFrames)
NTSTATUS MiCloneProcessAddressSpace (IN PEPROCESS ProcessToClone, IN PEPROCESS ProcessToInitialize, IN PFN_NUMBER RootPhysicalPage, IN PFN_NUMBER HyperPhysicalPage)
ULONG MiDecrementCloneBlockReference (IN PMMCLONE_DESCRIPTOR CloneDescriptor, IN PMMCLONE_BLOCK CloneBlock, IN PEPROCESS CurrentProcess)
VOID MiWaitForForkToComplete (IN PEPROCESS CurrentProcess)


Define Documentation

#define MM_FORK_FAILED   1
 

Definition at line 92 of file forksup.c.

Referenced by MiCloneProcessAddressSpace().

#define MM_FORK_SUCCEEDED   0
 

Definition at line 91 of file forksup.c.

Referenced by MiCloneProcessAddressSpace(), and MiDecrementCloneBlockReference().


Function Documentation

VOID MiBuildForkPageTable IN PFN_NUMBER  PageFrameIndex,
IN PMMPTE  PointerPde,
IN PMMPTE  PointerNewPde,
IN PFN_NUMBER  PdePhysicalPage,
IN PMMPFN  PfnPdPage
 

Definition at line 2380 of file forksup.c.

References ActiveAndValid, DemandZeroPde, LOCK_PFN, MI_PFN_ELEMENT, MI_SET_OWNER_IN_PTE, MI_WRITE_INVALID_PTE, _MMPFN::OriginalPte, _MMPFN::PteAddress, _MMPFN::PteFrame, TransitionPde, _MMPFN::u2, _MMPFN::u3, UNLOCK_PFN, and UserMode.

Referenced by MiCloneProcessAddressSpace().

02387 { 02388 KIRQL OldIrql; 02389 PMMPFN Pfn1; 02390 02391 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 02392 02393 // 02394 // The PFN lock must be held while initializing the 02395 // frame to prevent those scanning the database for 02396 // free frames from taking it after we fill in the 02397 // u2 field. 02398 // 02399 02400 LOCK_PFN (OldIrql); 02401 02402 Pfn1->OriginalPte = DemandZeroPde; 02403 Pfn1->u2.ShareCount = 1; 02404 Pfn1->u3.e2.ReferenceCount = 1; 02405 Pfn1->PteAddress = PointerPde; 02406 Pfn1->u3.e1.Modified = 1; 02407 Pfn1->u3.e1.PageLocation = ActiveAndValid; 02408 Pfn1->PteFrame = PdePhysicalPage; 02409 02410 // 02411 // Increment the share count for the page containing 02412 // this PTE as the PTE is in transition. 02413 // 02414 02415 PfnPdPage->u2.ShareCount += 1; 02416 02417 // 02418 // Put the PDE into the transition state as it is not 02419 // really mapped and decrement share count does not 02420 // put private pages into transition, only prototypes. 02421 // 02422 02423 MI_WRITE_INVALID_PTE (PointerNewPde, TransitionPde); 02424 02425 // 02426 // Make the PTE owned by user mode. 02427 // 02428 02429 #ifndef _ALPHA_ 02430 MI_SET_OWNER_IN_PTE (PointerNewPde, UserMode); 02431 #endif //_ALPHA_ 02432 PointerNewPde->u.Trans.PageFrameNumber = PageFrameIndex; 02433 02434 UNLOCK_PFN (OldIrql); 02435 }

NTSTATUS MiCloneProcessAddressSpace IN PEPROCESS  ProcessToClone,
IN PEPROCESS  ProcessToInitialize,
IN PFN_NUMBER  RootPhysicalPage,
IN PFN_NUMBER  HyperPhysicalPage
 

Definition at line 100 of file forksup.c.

References _EPROCESS::AddressSpaceDeleted, ASSERT, BYTE_OFFSET, _MMCLONE_DESCRIPTOR::CloneHeader, _MMCLONE_HEADER::ClonePtes, _MMVAD::ControlArea, DbgPrint, _MMCLONE_DESCRIPTOR::EndingVpn, _MMVAD::EndingVpn, ExAllocatePoolWithTag, EXCEPTION_EXECUTE_HANDLER, ExFreePool(), FALSE, _EPROCESS::ForkInProgress, _EPROCESS::ForkWasSuccessful, HighPagePriority, IS_PTE_NOT_DEMAND_ZERO, KeAttachProcess(), KeBugCheckEx(), KeDelayExecutionThread(), KeDetachProcess(), KernelMode, LOCK_ADDRESS_SPACE, LOCK_WS, MDL_PAGES_LOCKED, _MDL::MdlFlags, MI_GET_PAGE_FRAME_FROM_PTE, MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE, MI_GET_PROTECTION_FROM_SOFT_PTE, MI_GET_PROTECTION_FROM_WSLE, MI_INCREMENT_USED_PTES_BY_HANDLE, MI_MAKE_PROTECT_WRITE_COPY, MI_MAKE_VALID_PTE_WRITE_COPY, MI_PFN_ELEMENT, MI_PTE_LOOKUP_NEEDED, MI_VPN_TO_VA, MI_WRITE_INVALID_PTE, MiBuildForkPageTable(), MiCheckPdeForPagedPool(), MiDoesPdeExistAndMakeValid(), MiDoesPpeExistAndMakeValid, MiDoneWithThisPageGetAnother(), MiDownPfnReferenceCount(), MiDownShareCountFlushEntireTb(), MiGetFirstClone, MiGetFirstVad, MiGetNextClone, MiGetNextVad, MiGetPdeAddress, MiGetPdeOffset, MiGetPpePdeOffset, MiGetPteAddress, MiGetPteOffset, MiGetVirtualAddressMappedByPte, MiHandleForkTransitionPte(), MiInsertClone, MiInsertVad(), MiIsPteOnPdeBoundary, MiLocateCloneAddress, MiLocateWsle(), MiLockPagedAddress(), MiMakeSystemAddressValid(), MiMapSinglePage(), MiProtoAddressForPte, MiPteToProto, MiRemoveClone, MiRetrievePageDirectoryFrames(), MiUnlockPagedAddress(), MiUnmapSinglePage(), MiUpCloneProcessRefCount(), MiUpCloneProtoRefCount(), MiUpControlAreaRefs(), MiUpForkPageShareCount(), MiUpPfnReferenceCount(), MM_DBG_FORK, MM_DECOMMIT, MM_FORK_FAILED, MM_FORK_SUCCEEDED, MM_MAX_COMMIT, MM_VIEW_SHARE, MmCached, MMCLONE_BLOCK, MMCLONE_DESCRIPTOR, MMCLONE_HEADER, MmInitializeMdl, MmMapLockedPagesSpecifyCache(), MmShortTime, MmUnmapLockedPages(), MmWorkingSetList, MmWsle, NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, _EPROCESS::NumberOfPrivatePages, _MMCLONE_HEADER::NumberOfProcessReferences, _MMCLONE_HEADER::NumberOfPtes, _MMCLONE_DESCRIPTOR::NumberOfPtes, _MMCLONE_DESCRIPTOR::NumberOfReferences, _MMPFN::OriginalPte, PAGE_ALIGN, PAGE_SHIFT, PAGE_SIZE, PAGED_CODE, PagedPool, _MMCLONE_DESCRIPTOR::PagedPoolQuotaCharge, _MMVAD::Parent, _MMCLONE_DESCRIPTOR::Parent, _EPROCESS::PeakVirtualSize, _EPROCESS::PhysicalVadList, PMMCLONE_HEADER, PMMVAD_SHORT, PsChargePoolQuota(), PsGetCurrentProcess, PsGetCurrentThread, PsReturnPoolQuota(), _MMPFN::PteAddress, _MMPFN::PteFrame, _MMCLONE_DESCRIPTOR::StartingVpn, _MMVAD::StartingVpn, TRUE, _MMSUPPORT::u, _MMVAD::u, _MMPTE::u, _MMPFN::u1, _MMWSLE::u1, _MMVAD::u2, _MMVAD::u3, _MMPFN::u3, UNLOCK_ADDRESS_SPACE, UNLOCK_WS, _MMWSL::UsedPageTableEntries, _MI_PHYSICAL_VIEW::Vad, _EPROCESS::VirtualSize, _EPROCESS::Vm, WSLE_NULL_INDEX, and WSLE_NUMBER.

Referenced by MmInitializeProcessAddressSpace().

00109 : 00110 00111 This routine stands on its head to produce a copy of the specified 00112 process's address space in the process to initialize. This 00113 is done by examining each virtual address descriptor's inherit 00114 attributes. If the pages described by the VAD should be inherited, 00115 each PTE is examined and copied into the new address space. 00116 00117 For private pages, fork prototype PTEs are constructed and the pages 00118 become shared, copy-on-write, between the two processes. 00119 00120 00121 Arguments: 00122 00123 ProcessToClone - Supplies the process whose address space should be 00124 cloned. 00125 00126 ProcessToInitialize - Supplies the process whose address space is to 00127 be created. 00128 00129 RootPhysicalPage - Supplies the physical page number of the top level 00130 page (parent on 64-bit systems) directory 00131 of the process to initialize. 00132 00133 HyperPhysicalPage - Supplies the physical page number of the page table 00134 page which maps hyperspace for the process to 00135 initialize. This is only needed for 32-bit systems. 00136 00137 Return Value: 00138 00139 None. 00140 00141 Environment: 00142 00143 Kernel mode, APCs disabled. 00144 00145 --*/ 00146 00147 { 00148 PFN_NUMBER PpePhysicalPage; 00149 PFN_NUMBER PdePhysicalPage; 00150 PEPROCESS CurrentProcess; 00151 PMMPTE PdeBase; 00152 PMMCLONE_HEADER CloneHeader; 00153 PMMCLONE_BLOCK CloneProtos; 00154 PMMCLONE_DESCRIPTOR CloneDescriptor; 00155 PMMVAD NewVad; 00156 PMMVAD Vad; 00157 PMMVAD NextVad; 00158 PMMVAD *VadList; 00159 PMMVAD FirstNewVad; 00160 PMMCLONE_DESCRIPTOR *CloneList; 00161 PMMCLONE_DESCRIPTOR FirstNewClone; 00162 PMMCLONE_DESCRIPTOR Clone; 00163 PMMCLONE_DESCRIPTOR NextClone; 00164 PMMCLONE_DESCRIPTOR NewClone; 00165 ULONG Attached; 00166 ULONG CloneFailed; 00167 ULONG VadInsertFailed; 00168 WSLE_NUMBER WorkingSetIndex; 00169 PVOID VirtualAddress; 00170 NTSTATUS status; 00171 PMMPFN Pfn2; 00172 PMMPFN PfnPdPage; 00173 MMPTE TempPte; 00174 MMPTE PteContents; 00175 #if defined (_X86PAE_) 00176 PMDL MdlPageDirectory; 00177 PPFN_NUMBER MdlPageFrames; 00178 PFN_NUMBER PageDirectoryFrames[PD_PER_SYSTEM]; 00179 PFN_NUMBER MdlHackPageDirectory[(sizeof(MDL)/sizeof(PFN_NUMBER)) + PD_PER_SYSTEM]; 00180 #endif 00181 PFN_NUMBER MdlPage; 00182 PFN_NUMBER MdlDirPage; 00183 PMMPTE PointerPte; 00184 PMMPTE PointerPde; 00185 PMMPTE PointerPpe; 00186 PMMPTE LastPte; 00187 PMMPTE PointerNewPte; 00188 PMMPTE NewPteMappedAddress; 00189 PMMPTE PointerNewPde; 00190 PLIST_ENTRY NextEntry; 00191 PMI_PHYSICAL_VIEW PhysicalView; 00192 PFN_NUMBER PageFrameIndex; 00193 PFN_NUMBER PageDirFrameIndex; 00194 PMMCLONE_BLOCK ForkProtoPte; 00195 PMMCLONE_BLOCK CloneProto; 00196 PMMCLONE_BLOCK LockedForkPte; 00197 PMMPTE ContainingPte; 00198 ULONG NumberOfForkPtes; 00199 PFN_NUMBER NumberOfPrivatePages; 00200 PFN_NUMBER PageTablePage; 00201 SIZE_T TotalPagedPoolCharge; 00202 SIZE_T TotalNonPagedPoolCharge; 00203 PMMPFN PfnForkPtePage; 00204 PVOID UsedPageTableEntries; 00205 ULONG ReleasedWorkingSetMutex; 00206 ULONG FirstTime; 00207 ULONG Waited; 00208 ULONG i; 00209 ULONG PpePdeOffset; 00210 #if defined (_WIN64) 00211 PVOID UsedPageDirectoryEntries; 00212 PMMPTE PointerNewPpe; 00213 PMMPTE PpeBase; 00214 PMMPFN PfnPpPage; 00215 #else 00216 PMMWSL HyperBase; 00217 #endif 00218 00219 PageTablePage = 2; 00220 NumberOfForkPtes = 0; 00221 Attached = FALSE; 00222 PageFrameIndex = (PFN_NUMBER)-1; 00223 PageDirFrameIndex = (PFN_NUMBER)-1; 00224 00225 #if DBG 00226 if (MmDebug & MM_DBG_FORK) { 00227 DbgPrint("beginning clone operation process to clone = %lx\n", 00228 ProcessToClone); 00229 } 00230 #endif //DBG 00231 00232 PAGED_CODE(); 00233 00234 if (ProcessToClone != PsGetCurrentProcess()) { 00235 Attached = TRUE; 00236 KeAttachProcess (&ProcessToClone->Pcb); 00237 } 00238 00239 #if defined (_X86PAE_) 00240 MiRetrievePageDirectoryFrames (RootPhysicalPage, PageDirectoryFrames); 00241 #endif 00242 00243 CurrentProcess = ProcessToClone; 00244 00245 // 00246 // Get the working set mutex and the address creation mutex 00247 // of the process to clone. This prevents page faults while we 00248 // are examining the address map and prevents virtual address space 00249 // from being created or deleted. 00250 // 00251 00252 LOCK_ADDRESS_SPACE (CurrentProcess); 00253 00254 // 00255 // Write-watch VAD bitmaps are not currently duplicated 00256 // so fork is not allowed. 00257 // 00258 00259 if (CurrentProcess->Vm.u.Flags.WriteWatch == 1) { 00260 status = STATUS_INVALID_PAGE_PROTECTION; 00261 goto ErrorReturn1; 00262 } 00263 00264 // 00265 // Check for AWE regions as they are not duplicated so fork is not allowed. 00266 // Note that since this is a readonly list walk, the address space mutex 00267 // is sufficient to synchronize properly. 00268 // 00269 00270 NextEntry = CurrentProcess->PhysicalVadList.Flink; 00271 while (NextEntry != &CurrentProcess->PhysicalVadList) { 00272 00273 PhysicalView = CONTAINING_RECORD(NextEntry, 00274 MI_PHYSICAL_VIEW, 00275 ListEntry); 00276 00277 if (PhysicalView->Vad->u.VadFlags.UserPhysicalPages == 1) { 00278 status = STATUS_INVALID_PAGE_PROTECTION; 00279 goto ErrorReturn1; 00280 } 00281 00282 NextEntry = NextEntry->Flink; 00283 } 00284 00285 // 00286 // Make sure the address space was not deleted, if so, return an error. 00287 // 00288 00289 if (CurrentProcess->AddressSpaceDeleted != 0) { 00290 status = STATUS_PROCESS_IS_TERMINATING; 00291 goto ErrorReturn1; 00292 } 00293 00294 // 00295 // Attempt to acquire the needed pool before starting the 00296 // clone operation, this allows an easier failure path in 00297 // the case of insufficient system resources. 00298 // 00299 00300 NumberOfPrivatePages = CurrentProcess->NumberOfPrivatePages; 00301 00302 CloneProtos = ExAllocatePoolWithTag (PagedPool, sizeof(MMCLONE_BLOCK) * 00303 NumberOfPrivatePages, 00304 'lCmM'); 00305 if (CloneProtos == NULL) { 00306 status = STATUS_INSUFFICIENT_RESOURCES; 00307 goto ErrorReturn1; 00308 } 00309 00310 CloneHeader = ExAllocatePoolWithTag (NonPagedPool, 00311 sizeof(MMCLONE_HEADER), 00312 ' mM'); 00313 if (CloneHeader == NULL) { 00314 status = STATUS_INSUFFICIENT_RESOURCES; 00315 goto ErrorReturn2; 00316 } 00317 00318 CloneDescriptor = ExAllocatePoolWithTag (NonPagedPool, 00319 sizeof(MMCLONE_DESCRIPTOR), 00320 ' mM'); 00321 if (CloneDescriptor == NULL) { 00322 status = STATUS_INSUFFICIENT_RESOURCES; 00323 goto ErrorReturn3; 00324 } 00325 00326 Vad = MiGetFirstVad (CurrentProcess); 00327 VadList = &FirstNewVad; 00328 00329 while (Vad != (PMMVAD)NULL) { 00330 00331 // 00332 // If the VAD does not go to the child, ignore it. 00333 // 00334 00335 if ((Vad->u.VadFlags.UserPhysicalPages == 0) && 00336 00337 ((Vad->u.VadFlags.PrivateMemory == 1) || 00338 (Vad->u2.VadFlags2.Inherit == MM_VIEW_SHARE))) { 00339 00340 NewVad = ExAllocatePoolWithTag (NonPagedPool, sizeof(MMVAD), ' daV'); 00341 00342 if (NewVad == NULL) { 00343 00344 // 00345 // Unable to allocate pool for all the VADs. Deallocate 00346 // all VADs and other pool obtained so far. 00347 // 00348 00349 *VadList = (PMMVAD)NULL; 00350 status = STATUS_INSUFFICIENT_RESOURCES; 00351 goto ErrorReturn4; 00352 } 00353 *VadList = NewVad; 00354 VadList = &NewVad->Parent; 00355 } 00356 Vad = MiGetNextVad (Vad); 00357 } 00358 00359 // 00360 // Terminate list of VADs for new process. 00361 // 00362 00363 *VadList = (PMMVAD)NULL; 00364 00365 // 00366 // Charge the current process the quota for the paged and nonpaged 00367 // global structures. This consists of the array of clone blocks 00368 // in paged pool and the clone header in non-paged pool. 00369 // 00370 00371 try { 00372 PsChargePoolQuota (CurrentProcess, PagedPool, sizeof(MMCLONE_BLOCK) * 00373 NumberOfPrivatePages); 00374 PageTablePage = 1; 00375 PsChargePoolQuota (CurrentProcess, NonPagedPool, sizeof(MMCLONE_HEADER)); 00376 PageTablePage = 0; 00377 00378 } except (EXCEPTION_EXECUTE_HANDLER) { 00379 00380 // 00381 // Unable to charge quota for the clone blocks. 00382 // 00383 00384 status = GetExceptionCode(); 00385 goto ErrorReturn4; 00386 } 00387 00388 LOCK_WS (CurrentProcess); 00389 00390 ASSERT (CurrentProcess->ForkInProgress == NULL); 00391 00392 // 00393 // Indicate to the pager that the current process is being 00394 // forked. This blocks other threads in that process from 00395 // modifying clone blocks counts and contents. 00396 // 00397 00398 CurrentProcess->ForkInProgress = PsGetCurrentThread(); 00399 00400 #if defined (_WIN64) 00401 00402 // 00403 // Increment the reference count for the pages which are being "locked" 00404 // in MDLs. This prevents the page from being reused while it is 00405 // being double mapped. Note we have a count of 3 below because in addition 00406 // to the PPE, we also set up a initial dummy PDE and PTE. 00407 // 00408 00409 MiUpPfnReferenceCount (RootPhysicalPage, 3); 00410 00411 // 00412 // Map the page directory parent page into the system address 00413 // space. This is accomplished by building an MDL to describe the 00414 // Page directory parent page. 00415 // 00416 00417 PpeBase = (PMMPTE)MiMapSinglePage (NULL, 00418 RootPhysicalPage, 00419 MmCached, 00420 HighPagePriority); 00421 00422 if (PpeBase == NULL) { 00423 MiDownPfnReferenceCount (RootPhysicalPage, 3); 00424 CurrentProcess->ForkInProgress = NULL; 00425 UNLOCK_WS (CurrentProcess); 00426 status = STATUS_INSUFFICIENT_RESOURCES; 00427 goto ErrorReturn4; 00428 } 00429 00430 PfnPpPage = MI_PFN_ELEMENT (RootPhysicalPage); 00431 00432 #else 00433 00434 #if !defined (_X86PAE_) 00435 MiUpPfnReferenceCount (RootPhysicalPage, 1); 00436 #endif 00437 00438 #endif 00439 00440 // 00441 // Initialize a page directory map so it can be 00442 // unlocked in the loop and the end of the loop without 00443 // any testing to see if has a valid value the first time through. 00444 // Note this is a dummy map for 64-bit systems and a real one for 32-bit. 00445 // 00446 00447 #if !defined (_X86PAE_) 00448 00449 MdlDirPage = RootPhysicalPage; 00450 00451 PdePhysicalPage = RootPhysicalPage; 00452 00453 PdeBase = (PMMPTE)MiMapSinglePage (NULL, 00454 MdlDirPage, 00455 MmCached, 00456 HighPagePriority); 00457 00458 if (PdeBase == NULL) { 00459 #if defined (_WIN64) 00460 MiDownPfnReferenceCount (RootPhysicalPage, 3); 00461 MiUnmapSinglePage (PpeBase); 00462 #else 00463 MiDownPfnReferenceCount (RootPhysicalPage, 1); 00464 #endif 00465 CurrentProcess->ForkInProgress = NULL; 00466 UNLOCK_WS (CurrentProcess); 00467 status = STATUS_INSUFFICIENT_RESOURCES; 00468 goto ErrorReturn4; 00469 } 00470 00471 #else 00472 00473 // 00474 // All 4 page directory pages need to be mapped for PAE so the heavyweight 00475 // mapping must be used. 00476 // 00477 00478 MdlPageDirectory = (PMDL)&MdlHackPageDirectory[0]; 00479 00480 MmInitializeMdl(MdlPageDirectory, (PVOID)PDE_BASE, PD_PER_SYSTEM * PAGE_SIZE); 00481 MdlPageDirectory->MdlFlags |= MDL_PAGES_LOCKED; 00482 00483 MdlPageFrames = (PPFN_NUMBER)(MdlPageDirectory + 1); 00484 00485 for (i = 0; i < PD_PER_SYSTEM; i += 1) { 00486 *(MdlPageFrames + i) = PageDirectoryFrames[i]; 00487 MiUpPfnReferenceCount (PageDirectoryFrames[i], 1); 00488 } 00489 00490 PdePhysicalPage = RootPhysicalPage; 00491 00492 PdeBase = (PMMPTE)MmMapLockedPagesSpecifyCache (MdlPageDirectory, 00493 KernelMode, 00494 MmCached, 00495 NULL, 00496 FALSE, 00497 HighPagePriority); 00498 00499 if (PdeBase == NULL) { 00500 for (i = 0; i < PD_PER_SYSTEM; i += 1) { 00501 MiDownPfnReferenceCount (PageDirectoryFrames[i], 1); 00502 } 00503 CurrentProcess->ForkInProgress = NULL; 00504 UNLOCK_WS (CurrentProcess); 00505 status = STATUS_INSUFFICIENT_RESOURCES; 00506 goto ErrorReturn4; 00507 } 00508 00509 #endif 00510 00511 PfnPdPage = MI_PFN_ELEMENT (RootPhysicalPage); 00512 00513 #if !defined (_WIN64) 00514 00515 // 00516 // Map hyperspace so target UsedPageTable entries can be incremented. 00517 // 00518 00519 MiUpPfnReferenceCount (HyperPhysicalPage, 2); 00520 00521 HyperBase = (PMMWSL)MiMapSinglePage (NULL, 00522 HyperPhysicalPage, 00523 MmCached, 00524 HighPagePriority); 00525 00526 if (HyperBase == NULL) { 00527 MiDownPfnReferenceCount (HyperPhysicalPage, 2); 00528 #if !defined (_X86PAE_) 00529 MiDownPfnReferenceCount (RootPhysicalPage, 1); 00530 MiUnmapSinglePage (PdeBase); 00531 #else 00532 for (i = 0; i < PD_PER_SYSTEM; i += 1) { 00533 MiDownPfnReferenceCount (PageDirectoryFrames[i], 1); 00534 } 00535 MmUnmapLockedPages (PdeBase, MdlPageDirectory); 00536 #endif 00537 CurrentProcess->ForkInProgress = NULL; 00538 UNLOCK_WS (CurrentProcess); 00539 status = STATUS_INSUFFICIENT_RESOURCES; 00540 goto ErrorReturn4; 00541 } 00542 #endif 00543 00544 // 00545 // Initialize a page table MDL to lock and map the hyperspace page so it 00546 // can be unlocked in the loop and the end of the loop without 00547 // any testing to see if has a valid value the first time through. 00548 // 00549 00550 #if defined (_WIN64) 00551 MdlPage = RootPhysicalPage; 00552 #else 00553 MdlPage = HyperPhysicalPage; 00554 #endif 00555 00556 NewPteMappedAddress = (PMMPTE)MiMapSinglePage (NULL, 00557 MdlPage, 00558 MmCached, 00559 HighPagePriority); 00560 00561 if (NewPteMappedAddress == NULL) { 00562 00563 #if defined (_WIN64) 00564 00565 MiDownPfnReferenceCount (RootPhysicalPage, 3); 00566 MiUnmapSinglePage (PpeBase); 00567 MiUnmapSinglePage (PdeBase); 00568 00569 #else 00570 MiDownPfnReferenceCount (HyperPhysicalPage, 2); 00571 MiUnmapSinglePage (HyperBase); 00572 #if !defined (_X86PAE_) 00573 MiDownPfnReferenceCount (RootPhysicalPage, 1); 00574 MiUnmapSinglePage (PdeBase); 00575 #else 00576 for (i = 0; i < PD_PER_SYSTEM; i += 1) { 00577 MiDownPfnReferenceCount (PageDirectoryFrames[i], 1); 00578 } 00579 MmUnmapLockedPages (PdeBase, MdlPageDirectory); 00580 #endif 00581 00582 #endif 00583 00584 CurrentProcess->ForkInProgress = NULL; 00585 UNLOCK_WS (CurrentProcess); 00586 status = STATUS_INSUFFICIENT_RESOURCES; 00587 goto ErrorReturn4; 00588 } 00589 00590 PointerNewPte = NewPteMappedAddress; 00591 00592 // 00593 // Build new clone prototype PTE block and descriptor, note that 00594 // each prototype PTE has a reference count following it. 00595 // 00596 00597 ForkProtoPte = CloneProtos; 00598 00599 LockedForkPte = ForkProtoPte; 00600 MiLockPagedAddress (LockedForkPte, FALSE); 00601 00602 CloneHeader->NumberOfPtes = (ULONG)NumberOfPrivatePages; 00603 CloneHeader->NumberOfProcessReferences = 1; 00604 CloneHeader->ClonePtes = CloneProtos; 00605 00606 00607 00608 CloneDescriptor->StartingVpn = (ULONG_PTR)CloneProtos; 00609 CloneDescriptor->EndingVpn = (ULONG_PTR)((ULONG_PTR)CloneProtos + 00610 NumberOfPrivatePages * 00611 sizeof(MMCLONE_BLOCK)); 00612 CloneDescriptor->NumberOfReferences = 0; 00613 CloneDescriptor->NumberOfPtes = (ULONG)NumberOfPrivatePages; 00614 CloneDescriptor->CloneHeader = CloneHeader; 00615 CloneDescriptor->PagedPoolQuotaCharge = sizeof(MMCLONE_BLOCK) * 00616 NumberOfPrivatePages; 00617 00618 // 00619 // Insert the clone descriptor for this fork operation into the 00620 // process which was cloned. 00621 // 00622 00623 MiInsertClone (CloneDescriptor); 00624 00625 // 00626 // Examine each virtual address descriptor and create the 00627 // proper structures for the new process. 00628 // 00629 00630 Vad = MiGetFirstVad (CurrentProcess); 00631 NewVad = FirstNewVad; 00632 00633 while (Vad != (PMMVAD)NULL) { 00634 00635 // 00636 // Examine the VAD to determine its type and inheritance 00637 // attribute. 00638 // 00639 00640 if ((Vad->u.VadFlags.UserPhysicalPages == 0) && 00641 00642 ((Vad->u.VadFlags.PrivateMemory == 1) || 00643 (Vad->u2.VadFlags2.Inherit == MM_VIEW_SHARE))) { 00644 00645 // 00646 // The virtual address descriptor should be shared in the 00647 // forked process. 00648 // 00649 00650 // 00651 // Make a copy of the VAD for the new process, the new VADs 00652 // are preallocated and linked together through the parent 00653 // field. 00654 // 00655 00656 NextVad = NewVad->Parent; 00657 00658 00659 if (Vad->u.VadFlags.PrivateMemory == 1) { 00660 *(PMMVAD_SHORT)NewVad = *(PMMVAD_SHORT)Vad; 00661 NewVad->u.VadFlags.NoChange = 0; 00662 } else { 00663 *NewVad = *Vad; 00664 } 00665 00666 if (NewVad->u.VadFlags.NoChange) { 00667 if ((NewVad->u2.VadFlags2.OneSecured) || 00668 (NewVad->u2.VadFlags2.MultipleSecured)) { 00669 00670 // 00671 // Eliminate these as the memory was secured 00672 // only in this process, not in the new one. 00673 // 00674 00675 NewVad->u2.VadFlags2.OneSecured = 0; 00676 NewVad->u2.VadFlags2.MultipleSecured = 0; 00677 NewVad->u2.VadFlags2.StoredInVad = 0; 00678 NewVad->u3.List.Flink = NULL; 00679 NewVad->u3.List.Blink = NULL; 00680 } 00681 if (NewVad->u2.VadFlags2.SecNoChange == 0) { 00682 NewVad->u.VadFlags.NoChange = 0; 00683 } 00684 } 00685 NewVad->Parent = NextVad; 00686 00687 // 00688 // If the VAD refers to a section, up the view count for that 00689 // section. This requires the PFN mutex to be held. 00690 // 00691 00692 if ((Vad->u.VadFlags.PrivateMemory == 0) && 00693 (Vad->ControlArea != (PCONTROL_AREA)NULL)) { 00694 00695 // 00696 // Increment the count of the number of views for the 00697 // section object. This requires the PFN mutex to be held. 00698 // 00699 00700 MiUpControlAreaRefs (Vad->ControlArea); 00701 } 00702 00703 // 00704 // Examine each PTE and create the appropriate PTE for the 00705 // new process. 00706 // 00707 00708 PointerPde = MiGetPdeAddress (MI_VPN_TO_VA (Vad->StartingVpn)); 00709 PointerPte = (volatile PMMPTE) MiGetPteAddress ( 00710 MI_VPN_TO_VA (Vad->StartingVpn)); 00711 LastPte = MiGetPteAddress (MI_VPN_TO_VA (Vad->EndingVpn)); 00712 FirstTime = TRUE; 00713 00714 while ((PMMPTE)PointerPte <= LastPte) { 00715 00716 // 00717 // For each PTE contained in the VAD check the page table 00718 // page, and if non-zero, make the appropriate modifications 00719 // to copy the PTE to the new process. 00720 // 00721 00722 if ((FirstTime) || MiIsPteOnPdeBoundary (PointerPte)) { 00723 00724 PointerPpe = MiGetPdeAddress (PointerPte); 00725 PointerPde = MiGetPteAddress (PointerPte); 00726 00727 do { 00728 00729 while (!MiDoesPpeExistAndMakeValid (PointerPpe, 00730 CurrentProcess, 00731 FALSE, 00732 &Waited)) { 00733 00734 // 00735 // Page directory parent is empty, go to the next one. 00736 // 00737 00738 PointerPpe += 1; 00739 PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe); 00740 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00741 00742 if ((PMMPTE)PointerPte > LastPte) { 00743 00744 // 00745 // All done with this VAD, exit loop. 00746 // 00747 00748 goto AllDone; 00749 } 00750 } 00751 00752 Waited = 0; 00753 00754 while (!MiDoesPdeExistAndMakeValid (PointerPde, 00755 CurrentProcess, 00756 FALSE, 00757 &Waited)) { 00758 00759 // 00760 // This page directory is empty, go to the next one. 00761 // 00762 00763 PointerPde += 1; 00764 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 00765 00766 if ((PMMPTE)PointerPte > LastPte) { 00767 00768 // 00769 // All done with this VAD, exit loop. 00770 // 00771 00772 goto AllDone; 00773 } 00774 #if defined (_WIN64) 00775 if (MiIsPteOnPdeBoundary (PointerPde)) { 00776 PointerPpe = MiGetPteAddress (PointerPde); 00777 Waited = 1; 00778 break; 00779 } 00780 #endif 00781 } 00782 00783 } while (Waited != 0); 00784 00785 FirstTime = FALSE; 00786 00787 #if defined (_WIN64) 00788 // 00789 // Calculate the address of the PPE in the new process's 00790 // page directory parent page. 00791 // 00792 00793 PointerNewPpe = &PpeBase[MiGetPdeOffset(PointerPte)]; 00794 00795 if (PointerNewPpe->u.Long == 0) { 00796 00797 // 00798 // No physical page has been allocated yet, get a page 00799 // and map it in as a transition page. This will 00800 // become a page table page for the new process. 00801 // 00802 00803 ReleasedWorkingSetMutex = 00804 MiDoneWithThisPageGetAnother (&PageDirFrameIndex, 00805 PointerPpe, 00806 CurrentProcess); 00807 00808 MI_ZERO_USED_PAGETABLE_ENTRIES (MI_PFN_ELEMENT(PageDirFrameIndex)); 00809 00810 if (ReleasedWorkingSetMutex) { 00811 00812 do { 00813 00814 MiDoesPpeExistAndMakeValid (PointerPpe, 00815 CurrentProcess, 00816 FALSE, 00817 &Waited); 00818 00819 Waited = 0; 00820 00821 MiDoesPdeExistAndMakeValid (PointerPde, 00822 CurrentProcess, 00823 FALSE, 00824 &Waited); 00825 } while (Waited != 0); 00826 } 00827 00828 // 00829 // Hand initialize this PFN as normal initialization 00830 // would do it for the process whose context we are 00831 // attached to. 00832 // 00833 // The PFN lock must be held while initializing the 00834 // frame to prevent those scanning the database for 00835 // free frames from taking it after we fill in the 00836 // u2 field. 00837 // 00838 00839 MiBuildForkPageTable (PageDirFrameIndex, 00840 PointerPpe, 00841 PointerNewPpe, 00842 RootPhysicalPage, 00843 PfnPpPage); 00844 00845 // 00846 // Map the new page directory page into the system 00847 // portion of the address space. Note that hyperspace 00848 // cannot be used as other operations (allocating 00849 // nonpaged pool at DPC level) could cause the 00850 // hyperspace page being used to be reused. 00851 // 00852 00853 MiDownPfnReferenceCount (MdlDirPage, 1); 00854 00855 MdlDirPage = PageDirFrameIndex; 00856 00857 ASSERT (PdeBase != NULL); 00858 00859 PdeBase = (PMMPTE)MiMapSinglePage (PdeBase, 00860 MdlDirPage, 00861 MmCached, 00862 HighPagePriority); 00863 00864 MiUpPfnReferenceCount (MdlDirPage, 1); 00865 00866 PointerNewPde = PdeBase; 00867 } 00868 else { 00869 ASSERT (PointerNewPpe->u.Hard.Valid == 1 || 00870 PointerNewPpe->u.Soft.Transition == 1); 00871 00872 if (PointerNewPpe->u.Hard.Valid == 1) { 00873 PageDirFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerNewPpe); 00874 } 00875 else { 00876 PageDirFrameIndex = MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (PointerNewPpe); 00877 } 00878 } 00879 00880 // 00881 // Calculate the address of the new PDE to build. 00882 // Note that FirstTime could be true, yet the page 00883 // directory page might already be built. 00884 // 00885 00886 PointerNewPde = (PMMPTE)((ULONG_PTR)PAGE_ALIGN(PointerNewPde) | 00887 BYTE_OFFSET (PointerPde)); 00888 00889 PdePhysicalPage = PageDirFrameIndex; 00890 00891 PfnPdPage = MI_PFN_ELEMENT (PdePhysicalPage); 00892 00893 UsedPageDirectoryEntries = (PVOID)PfnPdPage; 00894 #endif 00895 00896 // 00897 // Calculate the address of the PDE in the new process's 00898 // page directory page. 00899 // 00900 00901 PpePdeOffset = MiGetPpePdeOffset(MiGetVirtualAddressMappedByPte(PointerPte)); 00902 PointerNewPde = &PdeBase[PpePdeOffset]; 00903 00904 if (PointerNewPde->u.Long == 0) { 00905 00906 // 00907 // No physical page has been allocated yet, get a page 00908 // and map it in as a transition page. This will 00909 // become a page table page for the new process. 00910 // 00911 00912 ReleasedWorkingSetMutex = 00913 MiDoneWithThisPageGetAnother (&PageFrameIndex, 00914 PointerPde, 00915 CurrentProcess); 00916 00917 if (ReleasedWorkingSetMutex) { 00918 00919 do { 00920 00921 MiDoesPpeExistAndMakeValid (PointerPpe, 00922 CurrentProcess, 00923 FALSE, 00924 &Waited); 00925 00926 Waited = 0; 00927 00928 MiDoesPdeExistAndMakeValid (PointerPde, 00929 CurrentProcess, 00930 FALSE, 00931 &Waited); 00932 } while (Waited != 0); 00933 } 00934 00935 // 00936 // Hand initialize this PFN as normal initialization 00937 // would do it for the process whose context we are 00938 // attached to. 00939 // 00940 // The PFN lock must be held while initializing the 00941 // frame to prevent those scanning the database for 00942 // free frames from taking it after we fill in the 00943 // u2 field. 00944 // 00945 00946 #if defined (_X86PAE_) 00947 PdePhysicalPage = PageDirectoryFrames[MiGetPdPteOffset(MiGetVirtualAddressMappedByPte(PointerPte))]; 00948 PfnPdPage = MI_PFN_ELEMENT (PdePhysicalPage); 00949 #endif 00950 00951 MiBuildForkPageTable (PageFrameIndex, 00952 PointerPde, 00953 PointerNewPde, 00954 PdePhysicalPage, 00955 PfnPdPage); 00956 00957 #if defined (_WIN64) 00958 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryEntries); 00959 #endif 00960 00961 // 00962 // Map the new page table page into the system portion 00963 // of the address space. Note that hyperspace 00964 // cannot be used as other operations (allocating 00965 // nonpaged pool at DPC level) could cause the 00966 // hyperspace page being used to be reused. 00967 // 00968 00969 ASSERT (NewPteMappedAddress != NULL); 00970 00971 MiDownPfnReferenceCount (MdlPage, 1); 00972 00973 MdlPage = PageFrameIndex; 00974 00975 PointerNewPte = (PMMPTE)MiMapSinglePage (NewPteMappedAddress, 00976 MdlPage, 00977 MmCached, 00978 HighPagePriority); 00979 00980 ASSERT (PointerNewPte != NULL); 00981 00982 MiUpPfnReferenceCount (MdlPage, 1); 00983 } 00984 00985 // 00986 // Calculate the address of the new PTE to build. 00987 // Note that FirstTime could be true, yet the page 00988 // table page already built. 00989 // 00990 00991 PointerNewPte = (PMMPTE)((ULONG_PTR)PAGE_ALIGN(PointerNewPte) | 00992 BYTE_OFFSET (PointerPte)); 00993 00994 #ifdef _WIN64 00995 UsedPageTableEntries = (PVOID)MI_PFN_ELEMENT((PFN_NUMBER)PointerNewPde->u.Hard.PageFrameNumber); 00996 #else 00997 #if !defined (_X86PAE_) 00998 UsedPageTableEntries = (PVOID)&HyperBase->UsedPageTableEntries 00999 [MiGetPteOffset( PointerPte )]; 01000 #else 01001 UsedPageTableEntries = (PVOID)&HyperBase->UsedPageTableEntries 01002 [MiGetPpePdeOffset(MiGetVirtualAddressMappedByPte(PointerPte))]; 01003 #endif 01004 #endif 01005 01006 } 01007 01008 // 01009 // Make the fork prototype PTE location resident. 01010 // 01011 01012 if (PAGE_ALIGN (ForkProtoPte) != PAGE_ALIGN (LockedForkPte)) { 01013 MiUnlockPagedAddress (LockedForkPte, FALSE); 01014 LockedForkPte = ForkProtoPte; 01015 MiLockPagedAddress (LockedForkPte, FALSE); 01016 } 01017 01018 MiMakeSystemAddressValid (PointerPte, CurrentProcess); 01019 01020 PteContents = *PointerPte; 01021 01022 // 01023 // Check each PTE. 01024 // 01025 01026 if (PteContents.u.Long == 0) { 01027 NOTHING; 01028 01029 } else if (PteContents.u.Hard.Valid == 1) { 01030 01031 // 01032 // Valid. 01033 // 01034 01035 Pfn2 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 01036 VirtualAddress = MiGetVirtualAddressMappedByPte (PointerPte); 01037 WorkingSetIndex = MiLocateWsle (VirtualAddress, 01038 MmWorkingSetList, 01039 Pfn2->u1.WsIndex); 01040 01041 ASSERT (WorkingSetIndex != WSLE_NULL_INDEX); 01042 01043 if (Pfn2->u3.e1.PrototypePte == 1) { 01044 01045 // 01046 // This PTE is already in prototype PTE format. 01047 // 01048 01049 // 01050 // This is a prototype PTE. The PFN database does 01051 // not contain the contents of this PTE it contains 01052 // the contents of the prototype PTE. This PTE must 01053 // be reconstructed to contain a pointer to the 01054 // prototype PTE. 01055 // 01056 // The working set list entry contains information about 01057 // how to reconstruct the PTE. 01058 // 01059 01060 if (MmWsle[WorkingSetIndex].u1.e1.SameProtectAsProto 01061 == 0) { 01062 01063 // 01064 // The protection for the prototype PTE is in the 01065 // WSLE. 01066 // 01067 01068 TempPte.u.Long = 0; 01069 TempPte.u.Soft.Protection = 01070 MI_GET_PROTECTION_FROM_WSLE(&MmWsle[WorkingSetIndex]); 01071 TempPte.u.Soft.PageFileHigh = MI_PTE_LOOKUP_NEEDED; 01072 01073 } else { 01074 01075 // 01076 // The protection is in the prototype PTE. 01077 // 01078 01079 TempPte.u.Long = MiProtoAddressForPte ( 01080 Pfn2->PteAddress); 01081 // TempPte.u.Proto.ForkType = 01082 // MmWsle[WorkingSetIndex].u1.e1.ForkType; 01083 } 01084 01085 TempPte.u.Proto.Prototype = 1; 01086 MI_WRITE_INVALID_PTE (PointerNewPte, TempPte); 01087 01088 // 01089 // A PTE is now non-zero, increment the used page 01090 // table entries counter. 01091 // 01092 01093 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries); 01094 01095 // 01096 // Check to see if this is a fork prototype PTE, 01097 // and if it is increment the reference count 01098 // which is in the longword following the PTE. 01099 // 01100 01101 if (MiLocateCloneAddress ((PVOID)Pfn2->PteAddress) != 01102 (PMMCLONE_DESCRIPTOR)NULL) { 01103 01104 // 01105 // The reference count field, or the prototype PTE 01106 // for that matter may not be in the working set. 01107 // 01108 01109 CloneProto = (PMMCLONE_BLOCK)Pfn2->PteAddress; 01110 01111 MiUpCloneProtoRefCount (CloneProto, 01112 CurrentProcess); 01113 01114 if (PAGE_ALIGN (ForkProtoPte) != 01115 PAGE_ALIGN (LockedForkPte)) { 01116 MiUnlockPagedAddress (LockedForkPte, FALSE); 01117 LockedForkPte = ForkProtoPte; 01118 MiLockPagedAddress (LockedForkPte, FALSE); 01119 } 01120 01121 MiMakeSystemAddressValid (PointerPte, 01122 CurrentProcess); 01123 } 01124 01125 } else { 01126 01127 // 01128 // This is a private page, create a fork prototype PTE 01129 // which becomes the "prototype" PTE for this page. 01130 // The protection is the same as that in the prototype' 01131 // PTE so the WSLE does not need to be updated. 01132 // 01133 01134 MI_MAKE_VALID_PTE_WRITE_COPY (PointerPte); 01135 01136 ForkProtoPte->ProtoPte = *PointerPte; 01137 ForkProtoPte->CloneRefCount = 2; 01138 01139 // 01140 // Transform the PFN element to reference this new fork 01141 // prototype PTE. 01142 // 01143 01144 Pfn2->PteAddress = &ForkProtoPte->ProtoPte; 01145 Pfn2->u3.e1.PrototypePte = 1; 01146 01147 ContainingPte = MiGetPteAddress(&ForkProtoPte->ProtoPte); 01148 if (ContainingPte->u.Hard.Valid == 0) { 01149 #if !defined (_WIN64) 01150 if (!NT_SUCCESS(MiCheckPdeForPagedPool (&ForkProtoPte->ProtoPte))) { 01151 #endif 01152 KeBugCheckEx (MEMORY_MANAGEMENT, 01153 0x61940, 01154 (ULONG_PTR)&ForkProtoPte->ProtoPte, 01155 (ULONG_PTR)ContainingPte->u.Long, 01156 (ULONG_PTR)MiGetVirtualAddressMappedByPte(&ForkProtoPte->ProtoPte)); 01157 #if !defined (_WIN64) 01158 } 01159 #endif 01160 } 01161 Pfn2->PteFrame = MI_GET_PAGE_FRAME_FROM_PTE (ContainingPte); 01162 01163 01164 // 01165 // Increment the share count for the page containing the 01166 // fork prototype PTEs as we have just placed a valid 01167 // PTE into the page. 01168 // 01169 01170 PfnForkPtePage = MI_PFN_ELEMENT ( 01171 ContainingPte->u.Hard.PageFrameNumber ); 01172 01173 MiUpForkPageShareCount (PfnForkPtePage); 01174 01175 // 01176 // Change the protection in the PFN database to COPY 01177 // on write, if writable. 01178 // 01179 01180 MI_MAKE_PROTECT_WRITE_COPY (Pfn2->OriginalPte); 01181 01182 // 01183 // Put the protection into the WSLE and mark the WSLE 01184 // to indicate that the protection field for the PTE 01185 // is the same as the prototype PTE. 01186 // 01187 01188 MmWsle[WorkingSetIndex].u1.e1.Protection = 01189 MI_GET_PROTECTION_FROM_SOFT_PTE(&Pfn2->OriginalPte); 01190 01191 MmWsle[WorkingSetIndex].u1.e1.SameProtectAsProto = 1; 01192 01193 TempPte.u.Long = MiProtoAddressForPte (Pfn2->PteAddress); 01194 TempPte.u.Proto.Prototype = 1; 01195 MI_WRITE_INVALID_PTE (PointerNewPte, TempPte); 01196 01197 // 01198 // A PTE is now non-zero, increment the used page 01199 // table entries counter. 01200 // 01201 01202 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries); 01203 01204 // 01205 // One less private page (it's now shared). 01206 // 01207 01208 CurrentProcess->NumberOfPrivatePages -= 1; 01209 01210 ForkProtoPte += 1; 01211 NumberOfForkPtes += 1; 01212 01213 } 01214 01215 } else if (PteContents.u.Soft.Prototype == 1) { 01216 01217 // 01218 // Prototype PTE, check to see if this is a fork 01219 // prototype PTE already. Note that if COW is set, 01220 // the PTE can just be copied (fork compatible format). 01221 // 01222 01223 MI_WRITE_INVALID_PTE (PointerNewPte, PteContents); 01224 01225 // 01226 // A PTE is now non-zero, increment the used page 01227 // table entries counter. 01228 // 01229 01230 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries); 01231 01232 // 01233 // Check to see if this is a fork prototype PTE, 01234 // and if it is increment the reference count 01235 // which is in the longword following the PTE. 01236 // 01237 01238 CloneProto = (PMMCLONE_BLOCK)(MiPteToProto(PointerPte)); 01239 01240 if (MiLocateCloneAddress ((PVOID)CloneProto) != 01241 (PMMCLONE_DESCRIPTOR)NULL) { 01242 01243 // 01244 // The reference count field, or the prototype PTE 01245 // for that matter may not be in the working set. 01246 // 01247 01248 MiUpCloneProtoRefCount (CloneProto, 01249 CurrentProcess); 01250 01251 if (PAGE_ALIGN (ForkProtoPte) != 01252 PAGE_ALIGN (LockedForkPte)) { 01253 MiUnlockPagedAddress (LockedForkPte, FALSE); 01254 LockedForkPte = ForkProtoPte; 01255 MiLockPagedAddress (LockedForkPte, FALSE); 01256 } 01257 01258 MiMakeSystemAddressValid (PointerPte, 01259 CurrentProcess); 01260 } 01261 01262 } else if (PteContents.u.Soft.Transition == 1) { 01263 01264 // 01265 // Transition. 01266 // 01267 01268 if (MiHandleForkTransitionPte (PointerPte, 01269 PointerNewPte, 01270 ForkProtoPte)) { 01271 // 01272 // PTE is no longer transition, try again. 01273 // 01274 01275 continue; 01276 } 01277 01278 // 01279 // A PTE is now non-zero, increment the used page 01280 // table entries counter. 01281 // 01282 01283 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries); 01284 01285 // 01286 // One less private page (it's now shared). 01287 // 01288 01289 CurrentProcess->NumberOfPrivatePages -= 1; 01290 01291 ForkProtoPte += 1; 01292 NumberOfForkPtes += 1; 01293 01294 } else { 01295 01296 // 01297 // Page file format (may be demand zero). 01298 // 01299 01300 if (IS_PTE_NOT_DEMAND_ZERO (PteContents)) { 01301 01302 if (PteContents.u.Soft.Protection == MM_DECOMMIT) { 01303 01304 // 01305 // This is a decommitted PTE, just move it 01306 // over to the new process. Don't increment 01307 // the count of private pages. 01308 // 01309 01310 MI_WRITE_INVALID_PTE (PointerNewPte, PteContents); 01311 } else { 01312 01313 // 01314 // The PTE is not demand zero, move the PTE to 01315 // a fork prototype PTE and make this PTE and 01316 // the new processes PTE refer to the fork 01317 // prototype PTE. 01318 // 01319 01320 ForkProtoPte->ProtoPte = PteContents; 01321 01322 // 01323 // Make the protection write-copy if writable. 01324 // 01325 01326 MI_MAKE_PROTECT_WRITE_COPY (ForkProtoPte->ProtoPte); 01327 01328 ForkProtoPte->CloneRefCount = 2; 01329 01330 TempPte.u.Long = 01331 MiProtoAddressForPte (&ForkProtoPte->ProtoPte); 01332 01333 TempPte.u.Proto.Prototype = 1; 01334 01335 MI_WRITE_INVALID_PTE (PointerPte, TempPte); 01336 MI_WRITE_INVALID_PTE (PointerNewPte, TempPte); 01337 01338 // 01339 // One less private page (it's now shared). 01340 // 01341 01342 CurrentProcess->NumberOfPrivatePages -= 1; 01343 01344 ForkProtoPte += 1; 01345 NumberOfForkPtes += 1; 01346 } 01347 } else { 01348 01349 // 01350 // The page is demand zero, make the new process's 01351 // page demand zero. 01352 // 01353 01354 MI_WRITE_INVALID_PTE (PointerNewPte, PteContents); 01355 } 01356 01357 // 01358 // A PTE is now non-zero, increment the used page 01359 // table entries counter. 01360 // 01361 01362 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableEntries); 01363 } 01364 01365 PointerPte += 1; 01366 PointerNewPte += 1; 01367 01368 } // end while for PTEs 01369 AllDone: 01370 NewVad = NewVad->Parent; 01371 } 01372 Vad = MiGetNextVad (Vad); 01373 01374 } // end while for VADs 01375 01376 // 01377 // Unlock paged pool page. 01378 // 01379 01380 MiUnlockPagedAddress (LockedForkPte, FALSE); 01381 01382 // 01383 // Unmap the PD Page and hyper space page. 01384 // 01385 01386 #if defined (_WIN64) 01387 MiUnmapSinglePage (PpeBase); 01388 #endif 01389 01390 #if !defined (_X86PAE_) 01391 MiUnmapSinglePage (PdeBase); 01392 #else 01393 MmUnmapLockedPages (PdeBase, MdlPageDirectory); 01394 #endif 01395 01396 #if !defined (_WIN64) 01397 MiUnmapSinglePage (HyperBase); 01398 #endif 01399 01400 MiUnmapSinglePage (NewPteMappedAddress); 01401 01402 #if defined (_WIN64) 01403 MiDownPfnReferenceCount (RootPhysicalPage, 1); 01404 #endif 01405 01406 #if defined (_X86PAE_) 01407 for (i = 0; i < PD_PER_SYSTEM; i += 1) { 01408 MiDownPfnReferenceCount (PageDirectoryFrames[i], 1); 01409 } 01410 #else 01411 MiDownPfnReferenceCount (MdlDirPage, 1); 01412 #endif 01413 01414 #if !defined (_WIN64) 01415 MiDownPfnReferenceCount (HyperPhysicalPage, 1); 01416 #endif 01417 01418 MiDownPfnReferenceCount (MdlPage, 1); 01419 01420 // 01421 // Make the count of private pages match between the two processes. 01422 // 01423 01424 ASSERT ((SPFN_NUMBER)CurrentProcess->NumberOfPrivatePages >= 0); 01425 01426 ProcessToInitialize->NumberOfPrivatePages = 01427 CurrentProcess->NumberOfPrivatePages; 01428 01429 ASSERT (NumberOfForkPtes <= CloneDescriptor->NumberOfPtes); 01430 01431 if (NumberOfForkPtes != 0) { 01432 01433 // 01434 // The number of fork PTEs is non-zero, set the values 01435 // into the structures. 01436 // 01437 01438 CloneHeader->NumberOfPtes = NumberOfForkPtes; 01439 CloneDescriptor->NumberOfReferences = NumberOfForkPtes; 01440 CloneDescriptor->NumberOfPtes = NumberOfForkPtes; 01441 01442 } else { 01443 01444 // 01445 // There were no fork PTEs created. Remove the clone descriptor 01446 // from this process and clean up the related structures. 01447 // Note - must be holding the working set mutex and not holding 01448 // the PFN lock. 01449 // 01450 01451 MiRemoveClone (CloneDescriptor); 01452 01453 UNLOCK_WS (CurrentProcess); 01454 01455 ExFreePool (CloneDescriptor->CloneHeader->ClonePtes); 01456 01457 ExFreePool (CloneDescriptor->CloneHeader); 01458 01459 // 01460 // Return the pool for the global structures referenced by the 01461 // clone descriptor. 01462 // 01463 01464 PsReturnPoolQuota (CurrentProcess, 01465 PagedPool, 01466 CloneDescriptor->PagedPoolQuotaCharge); 01467 01468 PsReturnPoolQuota (CurrentProcess, NonPagedPool, sizeof(MMCLONE_HEADER)); 01469 01470 ExFreePool (CloneDescriptor); 01471 01472 LOCK_WS (CurrentProcess); 01473 } 01474 01475 MiDownShareCountFlushEntireTb (PageFrameIndex); 01476 01477 #if defined (_WIN64) 01478 MiDownShareCountFlushEntireTb (PageDirFrameIndex); 01479 #endif 01480 01481 PageFrameIndex = (PFN_NUMBER)-1; 01482 PageDirFrameIndex = (PFN_NUMBER)-1; 01483 01484 // 01485 // Copy the clone descriptors from this process to the new process. 01486 // 01487 01488 Clone = MiGetFirstClone (); 01489 CloneList = &FirstNewClone; 01490 CloneFailed = FALSE; 01491 01492 while (Clone != (PMMCLONE_DESCRIPTOR)NULL) { 01493 01494 // 01495 // Increment the count of processes referencing this clone block. 01496 // 01497 01498 MiUpCloneProcessRefCount (Clone); 01499 01500 do { 01501 NewClone = ExAllocatePoolWithTag (NonPagedPool, 01502 sizeof( MMCLONE_DESCRIPTOR), 01503 ' mM'); 01504 01505 if (NewClone != NULL) { 01506 break; 01507 } 01508 01509 // 01510 // There are insufficient resources to continue this operation, 01511 // however, to properly clean up at this point, all the 01512 // clone headers must be allocated, so when the cloned process 01513 // is deleted, the clone headers will be found. if the pool 01514 // is not readily available, loop periodically trying for it. 01515 // Force the clone operation to fail so the pool will soon be 01516 // released. 01517 // 01518 01519 CloneFailed = TRUE; 01520 status = STATUS_INSUFFICIENT_RESOURCES; 01521 01522 KeDelayExecutionThread (KernelMode, 01523 FALSE, 01524 (PLARGE_INTEGER)&MmShortTime); 01525 continue; 01526 } while (TRUE); 01527 01528 *NewClone = *Clone; 01529 01530 *CloneList = NewClone; 01531 CloneList = &NewClone->Parent; 01532 Clone = MiGetNextClone (Clone); 01533 } 01534 01535 *CloneList = (PMMCLONE_DESCRIPTOR)NULL; 01536 01537 // 01538 // Release the working set mutex and the address creation mutex from 01539 // the current process as all the necessary information is now 01540 // captured. 01541 // 01542 01543 UNLOCK_WS (CurrentProcess); 01544 01545 CurrentProcess->ForkInProgress = NULL; 01546 01547 UNLOCK_ADDRESS_SPACE (CurrentProcess); 01548 01549 // 01550 // As we have updated many PTEs to clear dirty bits, flush the 01551 // TB cache. Note that this was not done every time we changed 01552 // a valid PTE so other threads could be modifying the address 01553 // space without causing copy on writes. (Too bad). 01554 // 01555 01556 01557 // 01558 // Attach to the process to initialize and insert the vad and clone 01559 // descriptors into the tree. 01560 // 01561 01562 if (Attached) { 01563 KeDetachProcess (); 01564 Attached = FALSE; 01565 } 01566 01567 if (PsGetCurrentProcess() != ProcessToInitialize) { 01568 Attached = TRUE; 01569 KeAttachProcess (&ProcessToInitialize->Pcb); 01570 } 01571 01572 CurrentProcess = ProcessToInitialize; 01573 01574 // 01575 // We are now in the context of the new process, build the 01576 // VAD list and the clone list. 01577 // 01578 01579 Vad = FirstNewVad; 01580 VadInsertFailed = FALSE; 01581 01582 LOCK_WS (CurrentProcess); 01583 01584 while (Vad != (PMMVAD)NULL) { 01585 01586 NextVad = Vad->Parent; 01587 01588 try { 01589 01590 if (VadInsertFailed) { 01591 Vad->u.VadFlags.CommitCharge = MM_MAX_COMMIT; 01592 } 01593 01594 MiInsertVad (Vad); 01595 01596 } except (EXCEPTION_EXECUTE_HANDLER) { 01597 01598 // 01599 // Charging quota for the VAD failed, set the 01600 // remaining quota fields in this VAD and all 01601 // subsequent VADs to zero so the VADs can be 01602 // inserted and later deleted. 01603 // 01604 01605 VadInsertFailed = TRUE; 01606 status = GetExceptionCode(); 01607 01608 // 01609 // Do the loop again for this VAD. 01610 // 01611 01612 continue; 01613 } 01614 01615 // 01616 // Update the current virtual size. 01617 // 01618 01619 CurrentProcess->VirtualSize += PAGE_SIZE + 01620 ((Vad->EndingVpn - Vad->StartingVpn) >> PAGE_SHIFT); 01621 01622 Vad = NextVad; 01623 } 01624 01625 UNLOCK_WS (CurrentProcess); 01626 //MmUnlockCode (MiCloneProcessAddressSpace, 5000); 01627 01628 // 01629 // Update the peak virtual size. 01630 // 01631 01632 CurrentProcess->PeakVirtualSize = CurrentProcess->VirtualSize; 01633 01634 Clone = FirstNewClone; 01635 TotalPagedPoolCharge = 0; 01636 TotalNonPagedPoolCharge = 0; 01637 01638 while (Clone != (PMMCLONE_DESCRIPTOR)NULL) { 01639 01640 NextClone = Clone->Parent; 01641 MiInsertClone (Clone); 01642 01643 // 01644 // Calculate the page pool and non-paged pool to charge for these 01645 // operations. 01646 // 01647 01648 TotalPagedPoolCharge += Clone->PagedPoolQuotaCharge; 01649 TotalNonPagedPoolCharge += sizeof(MMCLONE_HEADER); 01650 01651 Clone = NextClone; 01652 } 01653 01654 if (CloneFailed || VadInsertFailed) { 01655 01656 CurrentProcess->ForkWasSuccessful = MM_FORK_FAILED; 01657 01658 if (Attached) { 01659 KeDetachProcess (); 01660 } 01661 KdPrint(("MMFORK: vad insert failed\n")); 01662 01663 return status; 01664 } 01665 01666 try { 01667 01668 PageTablePage = 1; 01669 PsChargePoolQuota (CurrentProcess, PagedPool, TotalPagedPoolCharge); 01670 PageTablePage = 0; 01671 PsChargePoolQuota (CurrentProcess, NonPagedPool, TotalNonPagedPoolCharge); 01672 01673 } except (EXCEPTION_EXECUTE_HANDLER) { 01674 01675 if (PageTablePage == 0) { 01676 PsReturnPoolQuota (CurrentProcess, PagedPool, TotalPagedPoolCharge); 01677 } 01678 KdPrint(("MMFORK: pool quota failed\n")); 01679 01680 CurrentProcess->ForkWasSuccessful = MM_FORK_FAILED; 01681 01682 if (Attached) { 01683 KeDetachProcess (); 01684 } 01685 return GetExceptionCode(); 01686 } 01687 01688 ASSERT (ProcessToClone->ForkWasSuccessful == MM_FORK_SUCCEEDED); 01689 ASSERT (CurrentProcess->ForkWasSuccessful == MM_FORK_SUCCEEDED); 01690 01691 if (Attached) { 01692 KeDetachProcess (); 01693 } 01694 01695 #if DBG 01696 if (MmDebug & MM_DBG_FORK) { 01697 DbgPrint("ending clone operation process to clone = %lx\n", 01698 ProcessToClone); 01699 } 01700 #endif //DBG 01701 01702 return STATUS_SUCCESS; 01703 01704 // 01705 // Error returns. 01706 // 01707 01708 ErrorReturn4: 01709 if (PageTablePage == 2) { 01710 NOTHING; 01711 } 01712 else if (PageTablePage == 1) { 01713 PsReturnPoolQuota (CurrentProcess, PagedPool, sizeof(MMCLONE_BLOCK) * 01714 NumberOfPrivatePages); 01715 } 01716 else { 01717 ASSERT (PageTablePage == 0); 01718 PsReturnPoolQuota (CurrentProcess, PagedPool, sizeof(MMCLONE_BLOCK) * 01719 NumberOfPrivatePages); 01720 PsReturnPoolQuota (CurrentProcess, NonPagedPool, sizeof(MMCLONE_HEADER)); 01721 } 01722 01723 NewVad = FirstNewVad; 01724 while (NewVad != NULL) { 01725 Vad = NewVad->Parent; 01726 ExFreePool (NewVad); 01727 NewVad = Vad; 01728 } 01729 01730 ExFreePool (CloneDescriptor); 01731 ErrorReturn3: 01732 ExFreePool (CloneHeader); 01733 ErrorReturn2: 01734 ExFreePool (CloneProtos); 01735 ErrorReturn1: 01736 UNLOCK_ADDRESS_SPACE (CurrentProcess); 01737 ASSERT (CurrentProcess->ForkWasSuccessful == MM_FORK_SUCCEEDED); 01738 if (Attached) { 01739 KeDetachProcess (); 01740 } 01741 return status; 01742 }

ULONG MiDecrementCloneBlockReference IN PMMCLONE_DESCRIPTOR  CloneDescriptor,
IN PMMCLONE_BLOCK  CloneBlock,
IN PEPROCESS  CurrentProcess
 

Definition at line 1745 of file forksup.c.

References APC_LEVEL, ASSERT, _MMCLONE_BLOCK::CloneRefCount, DbgPrint, ExFreePool(), FALSE, FreePageList, IS_PTE_NOT_DEMAND_ZERO, KeBugCheckEx(), LOCK_PFN, LOCK_WS_REGARDLESS, MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE, MI_PFN_ELEMENT, MI_SET_PFN_DELETED, MiDecrementShareCount(), MiInsertPageInList(), MiMakeSystemAddressValidPfnWs(), MiReleasePageFileSpace(), MiRemoveClone, MiUnlinkPageFromList(), MiWaitForForkToComplete(), MM_DBG_FORK, MM_FORK_SUCCEEDED, MmPageLocationList, NonPagedPool, _MMPFN::OriginalPte, PagedPool, PsReturnPoolQuota(), _MMPFN::PteFrame, TRUE, _MMPTE::u, _MMPFN::u3, UNLOCK_PFN, UNLOCK_WS_REGARDLESS, and ZeroPte.

Referenced by MiCopyOnWrite(), MiDeletePte(), and MiDeleteValidAddress().

01753 : 01754 01755 This routine decrements the reference count field of a "fork prototype 01756 PTE" (clone-block). If the reference count becomes zero, the reference 01757 count for the clone-descriptor is decremented and if that becomes zero, 01758 it is deallocated and the number of process count for the clone header is 01759 decremented. If the number of process count becomes zero, the clone 01760 header is deallocated. 01761 01762 Arguments: 01763 01764 CloneDescriptor - Supplies the clone descriptor which describes the 01765 clone block. 01766 01767 CloneBlock - Supplies the clone block to decrement the reference count of. 01768 01769 CurrentProcess - Supplies the current process. 01770 01771 Return Value: 01772 01773 TRUE if the working set mutex was released, FALSE if it was not. 01774 01775 Environment: 01776 01777 Kernel mode, APCs disabled, working set mutex and PFN mutex held. 01778 01779 --*/ 01780 01781 { 01782 01783 ULONG MutexReleased; 01784 MMPTE CloneContents; 01785 PMMPFN Pfn3; 01786 KIRQL OldIrql; 01787 LONG NewCount; 01788 LOGICAL WsHeldSafe; 01789 01790 MutexReleased = FALSE; 01791 OldIrql = APC_LEVEL; 01792 01793 MutexReleased = MiMakeSystemAddressValidPfnWs (CloneBlock, CurrentProcess); 01794 01795 while (CurrentProcess->ForkInProgress) { 01796 MiWaitForForkToComplete (CurrentProcess); 01797 MiMakeSystemAddressValidPfnWs (CloneBlock, CurrentProcess); 01798 MutexReleased = TRUE; 01799 } 01800 01801 CloneBlock->CloneRefCount -= 1; 01802 NewCount = CloneBlock->CloneRefCount; 01803 01804 ASSERT (NewCount >= 0); 01805 01806 if (NewCount == 0) { 01807 CloneContents = CloneBlock->ProtoPte; 01808 } else { 01809 CloneContents = ZeroPte; 01810 } 01811 01812 if ((NewCount == 0) && (CloneContents.u.Long != 0)) { 01813 01814 // 01815 // The last reference to a fork prototype PTE 01816 // has been removed. Deallocate any page file 01817 // space and the transition page, if any. 01818 // 01819 01820 01821 // 01822 // Assert that the page is no longer valid. 01823 // 01824 01825 ASSERT (CloneContents.u.Hard.Valid == 0); 01826 01827 // 01828 // Assert that the PTE is not in subsection format (doesn't point 01829 // to a file). 01830 // 01831 01832 ASSERT (CloneContents.u.Soft.Prototype == 0); 01833 01834 if (CloneContents.u.Soft.Transition == 1) { 01835 01836 // 01837 // Prototype PTE in transition, put the page 01838 // on the free list. 01839 // 01840 01841 Pfn3 = MI_PFN_ELEMENT (CloneContents.u.Trans.PageFrameNumber); 01842 MI_SET_PFN_DELETED (Pfn3); 01843 01844 MiDecrementShareCount (Pfn3->PteFrame); 01845 01846 // 01847 // Check the reference count for the page, if the reference 01848 // count is zero and the page is not on the freelist, 01849 // move the page to the free list, if the reference 01850 // count is not zero, ignore this page. 01851 // When the reference count goes to zero, it will be placed on the 01852 // free list. 01853 // 01854 01855 if ((Pfn3->u3.e2.ReferenceCount == 0) && 01856 (Pfn3->u3.e1.PageLocation != FreePageList)) { 01857 01858 MiUnlinkPageFromList (Pfn3); 01859 MiReleasePageFileSpace (Pfn3->OriginalPte); 01860 MiInsertPageInList (MmPageLocationList[FreePageList], 01861 MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE(&CloneContents)); 01862 } 01863 } else { 01864 01865 if (IS_PTE_NOT_DEMAND_ZERO (CloneContents)) { 01866 MiReleasePageFileSpace (CloneContents); 01867 } 01868 } 01869 } 01870 01871 // 01872 // Decrement the number of references to the 01873 // clone descriptor. 01874 // 01875 01876 CloneDescriptor->NumberOfReferences -= 1; 01877 01878 if (CloneDescriptor->NumberOfReferences == 0) { 01879 01880 // 01881 // There are no longer any PTEs in this process which refer 01882 // to the fork prototype PTEs for this clone descriptor. 01883 // Remove the CloneDescriptor and decrement the CloneHeader 01884 // number of process's reference count. 01885 // 01886 01887 CloneDescriptor->CloneHeader->NumberOfProcessReferences -= 1; 01888 01889 MiRemoveClone (CloneDescriptor); 01890 01891 if (CloneDescriptor->CloneHeader->NumberOfProcessReferences == 0) { 01892 01893 // 01894 // There are no more processes pointing to this fork header 01895 // blow it away. 01896 // 01897 01898 UNLOCK_PFN (OldIrql); 01899 01900 // 01901 // The working set lock may have been acquired safely or unsafely 01902 // by our caller. Handle both cases here and below. 01903 // 01904 01905 UNLOCK_WS_REGARDLESS (CurrentProcess, WsHeldSafe); 01906 01907 MutexReleased = TRUE; 01908 01909 01910 #if DBG 01911 { 01912 01913 ULONG i; 01914 PMMCLONE_BLOCK OldCloneBlock; 01915 01916 OldCloneBlock = CloneDescriptor->CloneHeader->ClonePtes; 01917 for (i = 0; i < CloneDescriptor->CloneHeader->NumberOfPtes; i += 1) { 01918 if (OldCloneBlock->CloneRefCount != 0) { 01919 DbgPrint("fork block with non zero ref count %lx %lx %lx\n", 01920 OldCloneBlock, CloneDescriptor, 01921 CloneDescriptor->CloneHeader); 01922 KeBugCheckEx (MEMORY_MANAGEMENT, 1, 0, 0, 0); 01923 } 01924 } 01925 01926 if (MmDebug & MM_DBG_FORK) { 01927 DbgPrint("removing clone header at address %lx\n", 01928 CloneDescriptor->CloneHeader); 01929 } 01930 01931 } 01932 #endif //DBG 01933 01934 ExFreePool (CloneDescriptor->CloneHeader->ClonePtes); 01935 01936 ExFreePool (CloneDescriptor->CloneHeader); 01937 01938 // 01939 // The working set lock may have been acquired safely or unsafely 01940 // by our caller. Reacquire it in the same manner our caller did. 01941 // 01942 01943 LOCK_WS_REGARDLESS (CurrentProcess, WsHeldSafe); 01944 01945 LOCK_PFN (OldIrql); 01946 } 01947 01948 #if DBG 01949 if (MmDebug & MM_DBG_FORK) { 01950 DbgPrint("removing clone descriptor at address %lx\n",CloneDescriptor); 01951 } 01952 #endif //DBG 01953 01954 // 01955 // Return the pool for the global structures referenced by the 01956 // clone descriptor. 01957 // 01958 01959 UNLOCK_PFN (OldIrql); 01960 01961 if (CurrentProcess->ForkWasSuccessful == MM_FORK_SUCCEEDED) { 01962 01963 PsReturnPoolQuota (CurrentProcess, 01964 PagedPool, 01965 CloneDescriptor->PagedPoolQuotaCharge); 01966 01967 PsReturnPoolQuota (CurrentProcess, 01968 NonPagedPool, 01969 sizeof(MMCLONE_HEADER)); 01970 } 01971 01972 ExFreePool (CloneDescriptor); 01973 LOCK_PFN (OldIrql); 01974 } 01975 01976 return MutexReleased; 01977 }

ULONG MiDoneWithThisPageGetAnother IN PPFN_NUMBER  PageFrameIndex,
IN PMMPTE  PointerPde,
IN PEPROCESS  CurrentProcess
 

Definition at line 2133 of file forksup.c.

References LOCK_PFN, MI_PAGE_COLOR_PTE_PROCESS, MiDecrementShareCountOnly, MiEnsureAvailablePageOrWait(), MiRemoveZeroPage(), NULL, and UNLOCK_PFN.

Referenced by MiCloneProcessAddressSpace().

02139 { 02140 KIRQL OldIrql; 02141 ULONG ReleasedMutex; 02142 02143 LOCK_PFN (OldIrql); 02144 02145 if (*PageFrameIndex != (PFN_NUMBER)-1) { 02146 02147 // 02148 // Decrement the share count of the last page which 02149 // we operated on. 02150 // 02151 02152 MiDecrementShareCountOnly (*PageFrameIndex); 02153 } 02154 02155 ReleasedMutex = 02156 MiEnsureAvailablePageOrWait ( 02157 CurrentProcess, 02158 NULL); 02159 02160 *PageFrameIndex = MiRemoveZeroPage ( 02161 MI_PAGE_COLOR_PTE_PROCESS (PointerPde, 02162 &CurrentProcess->NextPageColor)); 02163 02164 UNLOCK_PFN (OldIrql); 02165 return ReleasedMutex; 02166 }

VOID MiDownPfnReferenceCount IN PFN_NUMBER  Page,
IN USHORT  Count
 

Definition at line 2095 of file forksup.c.

References Count, LOCK_PFN, MiDecrementReferenceCount(), UNLOCK_PFN, and USHORT.

Referenced by MiCloneProcessAddressSpace().

02102 { 02103 USHORT i; 02104 KIRQL OldIrql; 02105 02106 LOCK_PFN (OldIrql); 02107 for (i = 0; i < Count; i += 1) { 02108 MiDecrementReferenceCount (Page); 02109 } 02110 UNLOCK_PFN (OldIrql); 02111 return; 02112 }

VOID MiDownShareCountFlushEntireTb IN PFN_NUMBER  PageFrameIndex  ) 
 

Definition at line 2341 of file forksup.c.

References FALSE, KeFlushEntireTb(), LOCK_PFN, MiDecrementShareCountOnly, and UNLOCK_PFN.

Referenced by MiCloneProcessAddressSpace().

02345 { 02346 KIRQL OldIrql; 02347 02348 LOCK_PFN (OldIrql); 02349 02350 if (PageFrameIndex != (PFN_NUMBER)-1) { 02351 02352 // 02353 // Decrement the share count of the last page which 02354 // we operated on. 02355 // 02356 02357 MiDecrementShareCountOnly (PageFrameIndex); 02358 } 02359 02360 KeFlushEntireTb (FALSE, FALSE); 02361 UNLOCK_PFN (OldIrql); 02362 return; 02363 }

ULONG MiHandleForkTransitionPte IN PMMPTE  PointerPte,
IN PMMPTE  PointerNewPte,
IN PMMCLONE_BLOCK  ForkProtoPte
 

Definition at line 2204 of file forksup.c.

References ASSERT, FALSE, KeBugCheckEx(), LOCK_PFN, MI_GET_PAGE_FRAME_FROM_PTE, MI_MAKE_PROTECT_WRITE_COPY, MI_PFN_ELEMENT, MI_WRITE_INVALID_PTE, MiCheckPdeForPagedPool(), MiDecrementShareCount(), MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiProtoAddressForPte, NT_SUCCESS, _MMPFN::OriginalPte, _MMPFN::PteAddress, _MMPFN::PteFrame, TRUE, _MMPTE::u, _MMPFN::u2, _MMPFN::u3, and UNLOCK_PFN.

Referenced by MiCloneProcessAddressSpace().

02210 { 02211 KIRQL OldIrql; 02212 PMMPFN Pfn2; 02213 MMPTE PteContents; 02214 PMMPTE ContainingPte; 02215 PFN_NUMBER PageTablePage; 02216 MMPTE TempPte; 02217 PMMPFN PfnForkPtePage; 02218 02219 02220 LOCK_PFN (OldIrql); 02221 02222 // 02223 // Now that we have the PFN mutex which prevents pages from 02224 // leaving the transition state, examine the PTE again to 02225 // ensure that it is still transition. 02226 // 02227 02228 PteContents = *(volatile PMMPTE)PointerPte; 02229 02230 if ((PteContents.u.Soft.Transition == 0) || 02231 (PteContents.u.Soft.Prototype == 1)) { 02232 02233 // 02234 // The PTE is no longer in transition... do this 02235 // loop again. 02236 // 02237 02238 UNLOCK_PFN (OldIrql); 02239 return TRUE; 02240 02241 } else { 02242 02243 // 02244 // The PTE is still in transition, handle like a 02245 // valid PTE. 02246 // 02247 02248 Pfn2 = MI_PFN_ELEMENT (PteContents.u.Trans.PageFrameNumber); 02249 02250 // 02251 // Assertion that PTE is not in prototype PTE format. 02252 // 02253 02254 ASSERT (Pfn2->u3.e1.PrototypePte != 1); 02255 02256 // 02257 // This is a private page in transition state, 02258 // create a fork prototype PTE 02259 // which becomes the "prototype" PTE for this page. 02260 // 02261 02262 ForkProtoPte->ProtoPte = PteContents; 02263 02264 // 02265 // Make the protection write-copy if writable. 02266 // 02267 02268 MI_MAKE_PROTECT_WRITE_COPY (ForkProtoPte->ProtoPte); 02269 02270 ForkProtoPte->CloneRefCount = 2; 02271 02272 // 02273 // Transform the PFN element to reference this new fork 02274 // prototype PTE. 02275 // 02276 02277 // 02278 // Decrement the share count for the page table 02279 // page which contains the PTE as it is no longer 02280 // valid or in transition. 02281 // 02282 Pfn2->PteAddress = &ForkProtoPte->ProtoPte; 02283 Pfn2->u3.e1.PrototypePte = 1; 02284 02285 // 02286 // Make original PTE copy on write. 02287 // 02288 02289 MI_MAKE_PROTECT_WRITE_COPY (Pfn2->OriginalPte); 02290 02291 ContainingPte = MiGetPteAddress(&ForkProtoPte->ProtoPte); 02292 02293 if (ContainingPte->u.Hard.Valid == 0) { 02294 #if !defined (_WIN64) 02295 if (!NT_SUCCESS(MiCheckPdeForPagedPool (&ForkProtoPte->ProtoPte))) { 02296 #endif 02297 KeBugCheckEx (MEMORY_MANAGEMENT, 02298 0x61940, 02299 (ULONG_PTR)&ForkProtoPte->ProtoPte, 02300 (ULONG_PTR)ContainingPte->u.Long, 02301 (ULONG_PTR)MiGetVirtualAddressMappedByPte(&ForkProtoPte->ProtoPte)); 02302 #if !defined (_WIN64) 02303 } 02304 #endif 02305 } 02306 02307 PageTablePage = Pfn2->PteFrame; 02308 02309 Pfn2->PteFrame = MI_GET_PAGE_FRAME_FROM_PTE (ContainingPte); 02310 02311 // 02312 // Increment the share count for the page containing 02313 // the fork prototype PTEs as we have just placed 02314 // a transition PTE into the page. 02315 // 02316 02317 PfnForkPtePage = MI_PFN_ELEMENT ( 02318 ContainingPte->u.Hard.PageFrameNumber ); 02319 02320 PfnForkPtePage->u2.ShareCount += 1; 02321 02322 TempPte.u.Long = 02323 MiProtoAddressForPte (Pfn2->PteAddress); 02324 TempPte.u.Proto.Prototype = 1; 02325 MI_WRITE_INVALID_PTE (PointerPte, TempPte); 02326 MI_WRITE_INVALID_PTE (PointerNewPte, TempPte); 02327 02328 // 02329 // Decrement the share count for the page table 02330 // page which contains the PTE as it is no longer 02331 // valid or in transition. 02332 // 02333 02334 MiDecrementShareCount (PageTablePage); 02335 } 02336 UNLOCK_PFN (OldIrql); 02337 return FALSE; 02338 }

VOID MiRetrievePageDirectoryFrames IN PFN_NUMBER  RootPhysicalPage,
OUT PPFN_NUMBER  PageDirectoryFrames
 

Referenced by MiCloneProcessAddressSpace().

VOID MiUpCloneProcessRefCount IN PMMCLONE_DESCRIPTOR  Clone  ) 
 

Definition at line 2169 of file forksup.c.

References LOCK_PFN, and UNLOCK_PFN.

Referenced by MiCloneProcessAddressSpace().

02172 { 02173 KIRQL OldIrql; 02174 02175 LOCK_PFN (OldIrql); 02176 02177 Clone->CloneHeader->NumberOfProcessReferences += 1; 02178 02179 UNLOCK_PFN (OldIrql); 02180 return; 02181 }

VOID MiUpCloneProtoRefCount IN PMMCLONE_BLOCK  CloneProto,
IN PEPROCESS  CurrentProcess
 

Definition at line 2184 of file forksup.c.

References LOCK_PFN, MiMakeSystemAddressValidPfnWs(), and UNLOCK_PFN.

Referenced by MiCloneProcessAddressSpace().

02189 { 02190 KIRQL OldIrql; 02191 02192 LOCK_PFN (OldIrql); 02193 02194 MiMakeSystemAddressValidPfnWs (CloneProto, 02195 CurrentProcess); 02196 02197 CloneProto->CloneRefCount += 1; 02198 02199 UNLOCK_PFN (OldIrql); 02200 return; 02201 }

VOID MiUpControlAreaRefs IN PCONTROL_AREA  ControlArea  ) 
 

Definition at line 2115 of file forksup.c.

References LOCK_PFN, and UNLOCK_PFN.

Referenced by MiCloneProcessAddressSpace().

02119 { 02120 KIRQL OldIrql; 02121 02122 LOCK_PFN (OldIrql); 02123 02124 ControlArea->NumberOfMappedViews += 1; 02125 ControlArea->NumberOfUserReferences += 1; 02126 02127 UNLOCK_PFN (OldIrql); 02128 return; 02129 }

VOID MiUpForkPageShareCount IN PMMPFN  PfnForkPtePage  ) 
 

Definition at line 2366 of file forksup.c.

References LOCK_PFN, and UNLOCK_PFN.

Referenced by MiCloneProcessAddressSpace().

02369 { 02370 KIRQL OldIrql; 02371 02372 LOCK_PFN (OldIrql); 02373 PfnForkPtePage->u2.ShareCount += 1; 02374 02375 UNLOCK_PFN (OldIrql); 02376 return; 02377 }

VOID MiUpPfnReferenceCount IN PFN_NUMBER  Page,
IN USHORT  Count
 

Definition at line 2076 of file forksup.c.

References Count, LOCK_PFN, MI_PFN_ELEMENT, _MMPFN::u3, and UNLOCK_PFN.

Referenced by MiCloneProcessAddressSpace().

02083 { 02084 KIRQL OldIrql; 02085 PMMPFN Pfn1; 02086 02087 Pfn1 = MI_PFN_ELEMENT (Page); 02088 LOCK_PFN (OldIrql); 02089 Pfn1->u3.e2.ReferenceCount += Count; 02090 UNLOCK_PFN (OldIrql); 02091 return; 02092 }

VOID MiWaitForForkToComplete IN PEPROCESS  CurrentProcess  ) 
 

Definition at line 1980 of file forksup.c.

References APC_LEVEL, LOCK_ADDRESS_SPACE, LOCK_PFN, LOCK_WS_REGARDLESS, UNLOCK_ADDRESS_SPACE, UNLOCK_PFN, and UNLOCK_WS_REGARDLESS.

Referenced by MiCopyOnWrite(), MiDecrementCloneBlockReference(), MiResolveDemandZeroFault(), and MmAccessFault().

01986 : 01987 01988 This routine waits for the current process to complete a fork 01989 operation. 01990 01991 Arguments: 01992 01993 CurrentProcess - Supplies the current process value. 01994 01995 Return Value: 01996 01997 None. 01998 01999 Environment: 02000 02001 Kernel mode, APCs disabled, working set mutex and PFN mutex held. 02002 02003 --*/ 02004 02005 { 02006 ULONG OldIrql; 02007 LOGICAL WsHeldSafe; 02008 02009 // 02010 // A fork operation is in progress and the count of clone-blocks 02011 // and other structures may not be changed. Release the mutexes 02012 // and wait for the address creation mutex which governs the 02013 // fork operation. 02014 // 02015 02016 UNLOCK_PFN (APC_LEVEL); 02017 02018 // 02019 // The working set mutex may have been acquired safely or unsafely 02020 // by our caller. Handle both cases here and below, carefully making sure 02021 // that the OldIrql left in the WS mutex on return is the same as on entry. 02022 // 02023 02024 OldIrql = CurrentProcess->WorkingSetLock.OldIrql; 02025 02026 UNLOCK_WS_REGARDLESS (CurrentProcess, WsHeldSafe); 02027 02028 // 02029 // Explicitly acquire the working set lock safely as it may be released and 02030 // reacquired by our caller. 02031 // 02032 02033 LOCK_ADDRESS_SPACE (CurrentProcess); 02034 02035 // 02036 // The working set lock may have been acquired safely or unsafely 02037 // by our caller. Reacquire it in the same manner our caller did. 02038 // 02039 02040 LOCK_WS_REGARDLESS (CurrentProcess, WsHeldSafe); 02041 02042 // 02043 // Release the address creation mutex, the working set mutex 02044 // must be held to set the ForkInProgress field. 02045 // 02046 02047 UNLOCK_ADDRESS_SPACE (CurrentProcess); 02048 02049 // 02050 // Ensure the previous IRQL is correctly set to its entry value. 02051 // 02052 02053 CurrentProcess->WorkingSetLock.OldIrql = OldIrql; 02054 02055 // 02056 // Get the PFN lock again. 02057 // 02058 02059 LOCK_PFN (OldIrql); 02060 return; 02061 } #if DBG


Generated on Sat May 15 19:43:45 2004 for test by doxygen 1.3.7