Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1179 lines
35 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. extsect.c
  5. Abstract:
  6. This module contains the routines which implement the
  7. NtExtendSection service.
  8. Author:
  9. Lou Perazzoli (loup) 8-May-1990
  10. Landy Wang (landyw) 02-June-1997
  11. Revision History:
  12. --*/
  13. #include "mi.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE,NtExtendSection)
  16. #pragma alloc_text(PAGE,MmExtendSection)
  17. #endif
  18. extern SIZE_T MmAllocationFragment;
  19. ULONG MiExtendedSubsectionsConvertedToDynamic;
  20. #if DBG
  21. VOID
  22. MiSubsectionConsistent (
  23. IN PSUBSECTION Subsection
  24. )
  25. /*++
  26. Routine Description:
  27. This function checks to ensure the subsection is consistent.
  28. Arguments:
  29. Subsection - Supplies a pointer to the subsection to be checked.
  30. Return Value:
  31. None.
  32. --*/
  33. {
  34. ULONG Sectors;
  35. ULONG FullPtes;
  36. //
  37. // Compare the disk sectors (4K units) to the PTE allocation.
  38. //
  39. Sectors = Subsection->NumberOfFullSectors;
  40. if (Subsection->u.SubsectionFlags.SectorEndOffset) {
  41. Sectors += 1;
  42. }
  43. //
  44. // Calculate how many PTEs are needed to map this number of sectors.
  45. //
  46. FullPtes = Sectors >> (PAGE_SHIFT - MM4K_SHIFT);
  47. if (Sectors & ((1 << (PAGE_SHIFT - MM4K_SHIFT)) - 1)) {
  48. FullPtes += 1;
  49. }
  50. if (FullPtes != Subsection->PtesInSubsection) {
  51. DbgPrint("Mm: Subsection inconsistent (%x vs %x)\n",
  52. FullPtes,
  53. Subsection->PtesInSubsection);
  54. DbgBreakPoint();
  55. }
  56. }
  57. #endif
  58. NTSTATUS
  59. NtExtendSection (
  60. IN HANDLE SectionHandle,
  61. IN OUT PLARGE_INTEGER NewSectionSize
  62. )
  63. /*++
  64. Routine Description:
  65. This function extends the size of the specified section. If
  66. the current size of the section is greater than or equal to the
  67. specified section size, the size is not updated.
  68. Arguments:
  69. SectionHandle - Supplies an open handle to a section object.
  70. NewSectionSize - Supplies the new size for the section object.
  71. Return Value:
  72. NTSTATUS.
  73. --*/
  74. {
  75. KPROCESSOR_MODE PreviousMode;
  76. PVOID Section;
  77. NTSTATUS Status;
  78. LARGE_INTEGER CapturedNewSectionSize;
  79. PAGED_CODE();
  80. //
  81. // Check to make sure the new section size is accessible.
  82. //
  83. PreviousMode = KeGetPreviousMode();
  84. if (PreviousMode != KernelMode) {
  85. try {
  86. ProbeForWriteSmallStructure (NewSectionSize,
  87. sizeof(LARGE_INTEGER),
  88. PROBE_ALIGNMENT (LARGE_INTEGER));
  89. CapturedNewSectionSize = *NewSectionSize;
  90. } except (EXCEPTION_EXECUTE_HANDLER) {
  91. //
  92. // If an exception occurs during the probe or capture
  93. // of the initial values, then handle the exception and
  94. // return the exception code as the status value.
  95. //
  96. return GetExceptionCode ();
  97. }
  98. }
  99. else {
  100. CapturedNewSectionSize = *NewSectionSize;
  101. }
  102. //
  103. // Reference the section object.
  104. //
  105. Status = ObReferenceObjectByHandle (SectionHandle,
  106. SECTION_EXTEND_SIZE,
  107. MmSectionObjectType,
  108. PreviousMode,
  109. (PVOID *)&Section,
  110. NULL);
  111. if (!NT_SUCCESS(Status)) {
  112. return Status;
  113. }
  114. Status = MmExtendSection (Section, &CapturedNewSectionSize, FALSE);
  115. ObDereferenceObject (Section);
  116. //
  117. // Update the NewSectionSize field.
  118. //
  119. try {
  120. //
  121. // Return the captured section size.
  122. //
  123. *NewSectionSize = CapturedNewSectionSize;
  124. } except (EXCEPTION_EXECUTE_HANDLER) {
  125. NOTHING;
  126. }
  127. return Status;
  128. }
  129. LOGICAL
  130. MiAppendSubsectionChain (
  131. IN PMSUBSECTION LastSubsection,
  132. IN PMSUBSECTION ExtendedSubsectionHead
  133. )
  134. /*++
  135. Routine Description:
  136. This nonpagable wrapper function extends the specified subsection chain.
  137. Arguments:
  138. LastSubsection - Supplies the last subsection in the existing control area.
  139. ExtendedSubsectionHead - Supplies an anchor pointing to the first
  140. subsection in the chain to append.
  141. Return Value:
  142. TRUE if the chain was appended, FALSE if not.
  143. --*/
  144. {
  145. KIRQL OldIrql;
  146. PMSUBSECTION NewSubsection;
  147. ASSERT (ExtendedSubsectionHead->NextSubsection != NULL);
  148. ASSERT (ExtendedSubsectionHead->u.SubsectionFlags.SectorEndOffset == 0);
  149. NewSubsection = (PMSUBSECTION) ExtendedSubsectionHead->NextSubsection;
  150. LOCK_PFN (OldIrql);
  151. //
  152. // This subsection may be extending a range that is already
  153. // mapped by a VAD(s). There is no way to tell how many VADs
  154. // already map it so if any do, just leave all the new subsections
  155. // marked as not reclaimable until the control area is deleted.
  156. //
  157. // If however, there are no *USER* references to this control area,
  158. // then the subsections can be marked as dynamic now. Note other
  159. // portions of code (currently only prefetch) that issue "dereference
  160. // from this subsection to the end of file" are safe because these
  161. // portions create user sections first and so the first check below
  162. // will be FALSE.
  163. //
  164. if (LastSubsection->ControlArea->NumberOfUserReferences != 0) {
  165. //
  166. // The caller has not allocated prototype PTEs and they are required.
  167. // Return so the caller can allocate and retry.
  168. //
  169. if (NewSubsection->SubsectionBase == NULL) {
  170. ASSERT (NewSubsection->u.SubsectionFlags.SubsectionStatic == 0);
  171. UNLOCK_PFN (OldIrql);
  172. return FALSE;
  173. }
  174. #if DBG
  175. do {
  176. ASSERT (NewSubsection->u.SubsectionFlags.SubsectionStatic == 1);
  177. NewSubsection = (PMSUBSECTION) NewSubsection->NextSubsection;
  178. } while (NewSubsection != NULL);
  179. #endif
  180. }
  181. else if (NewSubsection->SubsectionBase != NULL) {
  182. //
  183. // The prototype PTEs are no longer required (user views went away)
  184. // even though they were when the caller first built the subsections.
  185. // Mark the subsections as dynamic now.
  186. //
  187. do {
  188. ASSERT (NewSubsection->u.SubsectionFlags.SubsectionStatic == 1);
  189. MI_SNAP_SUB (NewSubsection, 0x1);
  190. NewSubsection->u.SubsectionFlags.SubsectionStatic = 0;
  191. NewSubsection->u2.SubsectionFlags2.SubsectionConverted = 1;
  192. NewSubsection->NumberOfMappedViews = 1;
  193. MiRemoveViewsFromSection (NewSubsection,
  194. NewSubsection->PtesInSubsection);
  195. MiExtendedSubsectionsConvertedToDynamic += 1;
  196. MI_SNAP_SUB (NewSubsection, 0x2);
  197. NewSubsection = (PMSUBSECTION) NewSubsection->NextSubsection;
  198. } while (NewSubsection != NULL);
  199. }
  200. LastSubsection->u.SubsectionFlags.SectorEndOffset = 0;
  201. LastSubsection->NumberOfFullSectors = ExtendedSubsectionHead->NumberOfFullSectors;
  202. //
  203. // A memory barrier is needed to ensure the writes initializing the
  204. // subsection fields are visible prior to linking the subsection into
  205. // the chain. This is because some reads from these fields are done
  206. // lock free for improved performance.
  207. //
  208. KeMemoryBarrier ();
  209. LastSubsection->NextSubsection = ExtendedSubsectionHead->NextSubsection;
  210. UNLOCK_PFN (OldIrql);
  211. return TRUE;
  212. }
  213. NTSTATUS
  214. MmExtendSection (
  215. IN PVOID SectionToExtend,
  216. IN OUT PLARGE_INTEGER NewSectionSize,
  217. IN ULONG IgnoreFileSizeChecking
  218. )
  219. /*++
  220. Routine Description:
  221. This function extends the size of the specified section. If
  222. the current size of the section is greater than or equal to the
  223. specified section size, the size is not updated.
  224. Arguments:
  225. Section - Supplies a pointer to a referenced section object.
  226. NewSectionSize - Supplies the new size for the section object.
  227. IgnoreFileSizeChecking - Supplies the value TRUE is file size
  228. checking should be ignored (i.e., it
  229. is being called from a file system which
  230. has already done the checks). FALSE
  231. if the checks still need to be made.
  232. Return Value:
  233. NTSTATUS.
  234. --*/
  235. {
  236. LOGICAL Appended;
  237. PMMPTE ProtoPtes;
  238. MMPTE TempPte;
  239. PCONTROL_AREA ControlArea;
  240. PSEGMENT Segment;
  241. PSECTION Section;
  242. PSUBSECTION LastSubsection;
  243. PSUBSECTION Subsection;
  244. PMSUBSECTION ExtendedSubsection;
  245. MSUBSECTION ExtendedSubsectionHead;
  246. PMSUBSECTION LastExtendedSubsection;
  247. UINT64 RequiredPtes;
  248. UINT64 NumberOfPtes;
  249. UINT64 TotalNumberOfPtes;
  250. ULONG PtesUsed;
  251. ULONG UnusedPtes;
  252. UINT64 AllocationSize;
  253. UINT64 RunningSize;
  254. UINT64 EndOfFile;
  255. NTSTATUS Status;
  256. LARGE_INTEGER NumberOf4KsForEntireFile;
  257. LARGE_INTEGER Starting4K;
  258. LARGE_INTEGER NextSubsection4KStart;
  259. LARGE_INTEGER Last4KChunk;
  260. ULONG PartialSize;
  261. SIZE_T AllocationFragment;
  262. PKTHREAD CurrentThread;
  263. PAGED_CODE();
  264. Section = (PSECTION)SectionToExtend;
  265. //
  266. // Make sure the section is really extendable - physical and
  267. // image sections are not.
  268. //
  269. Segment = Section->Segment;
  270. ControlArea = Segment->ControlArea;
  271. if ((ControlArea->u.Flags.PhysicalMemory || ControlArea->u.Flags.Image) ||
  272. (ControlArea->FilePointer == NULL)) {
  273. return STATUS_SECTION_NOT_EXTENDED;
  274. }
  275. //
  276. // Acquire the section extension mutex, this blocks other threads from
  277. // updating the size at the same time.
  278. //
  279. CurrentThread = KeGetCurrentThread ();
  280. KeEnterCriticalRegionThread (CurrentThread);
  281. ExAcquireResourceExclusiveLite (&MmSectionExtendResource, TRUE);
  282. //
  283. // Calculate the number of prototype PTE chunks to build for this section.
  284. // A subsection is also allocated for each chunk as all the prototype PTEs
  285. // in any given chunk are initially encoded to point at the same subsection.
  286. //
  287. // The maximum total section size is 16PB (2^54). This is because the
  288. // StartingSector4132 field in each subsection, ie: 2^42-1 bits of file
  289. // offset where the offset is in 4K (not pagesize) units. Thus, a
  290. // subsection may describe a *BYTE* file start offset of maximum
  291. // 2^54 - 4K.
  292. //
  293. // Each subsection can span at most 16TB - 64K. This is because the
  294. // NumberOfFullSectors and various other fields in the subsection are
  295. // ULONGs. In reality, this is a nonissue as far as maximum section size
  296. // is concerned because any number of subsections can be chained together
  297. // and in fact, subsections are allocated to span less to facilitate
  298. // efficient dynamic prototype PTE trimming and reconstruction.
  299. //
  300. if (NewSectionSize->QuadPart > MI_MAXIMUM_SECTION_SIZE) {
  301. Status = STATUS_SECTION_TOO_BIG;
  302. goto ReleaseAndReturn;
  303. }
  304. NumberOfPtes = (NewSectionSize->QuadPart + PAGE_SIZE - 1) >> PAGE_SHIFT;
  305. if (ControlArea->u.Flags.WasPurged == 0) {
  306. if ((UINT64)NewSectionSize->QuadPart <= (UINT64)Section->SizeOfSection.QuadPart) {
  307. *NewSectionSize = Section->SizeOfSection;
  308. goto ReleaseAndReturnSuccess;
  309. }
  310. }
  311. //
  312. // If a file handle was specified, set the allocation size of the file.
  313. //
  314. if (IgnoreFileSizeChecking == FALSE) {
  315. //
  316. // Release the resource so we don't deadlock with the file
  317. // system trying to extend this section at the same time.
  318. //
  319. ExReleaseResourceLite (&MmSectionExtendResource);
  320. //
  321. // Get a different resource to single thread query/set operations.
  322. //
  323. ExAcquireResourceExclusiveLite (&MmSectionExtendSetResource, TRUE);
  324. //
  325. // Query the file size to see if this file really needs extending.
  326. //
  327. // If the specified size is less than the current size, return
  328. // the current size.
  329. //
  330. Status = FsRtlGetFileSize (ControlArea->FilePointer,
  331. (PLARGE_INTEGER)&EndOfFile);
  332. if (!NT_SUCCESS (Status)) {
  333. ExReleaseResourceLite (&MmSectionExtendSetResource);
  334. KeLeaveCriticalRegionThread (CurrentThread);
  335. return Status;
  336. }
  337. if ((UINT64)NewSectionSize->QuadPart > EndOfFile) {
  338. //
  339. // Don't allow section extension unless the section was originally
  340. // created with write access. The check couldn't be done at create
  341. // time without breaking existing binaries, so the caller gets the
  342. // error at this point instead.
  343. //
  344. if (((Section->InitialPageProtection & PAGE_READWRITE) |
  345. (Section->InitialPageProtection & PAGE_EXECUTE_READWRITE)) == 0) {
  346. #if DBG
  347. DbgPrint("Section extension failed %x\n", Section);
  348. #endif
  349. ExReleaseResourceLite (&MmSectionExtendSetResource);
  350. KeLeaveCriticalRegionThread (CurrentThread);
  351. return STATUS_SECTION_NOT_EXTENDED;
  352. }
  353. //
  354. // Current file is smaller, attempt to set a new end of file.
  355. //
  356. EndOfFile = *(PUINT64)NewSectionSize;
  357. Status = FsRtlSetFileSize (ControlArea->FilePointer,
  358. (PLARGE_INTEGER)&EndOfFile);
  359. if (!NT_SUCCESS (Status)) {
  360. ExReleaseResourceLite (&MmSectionExtendSetResource);
  361. KeLeaveCriticalRegionThread (CurrentThread);
  362. return Status;
  363. }
  364. }
  365. if (Segment->ExtendInfo) {
  366. KeAcquireGuardedMutex (&MmSectionBasedMutex);
  367. if (Segment->ExtendInfo) {
  368. Segment->ExtendInfo->CommittedSize = EndOfFile;
  369. }
  370. KeReleaseGuardedMutex (&MmSectionBasedMutex);
  371. }
  372. //
  373. // Release the query/set resource and reacquire the extend section
  374. // resource.
  375. //
  376. ExReleaseResourceLite (&MmSectionExtendSetResource);
  377. ExAcquireResourceExclusiveLite (&MmSectionExtendResource, TRUE);
  378. }
  379. //
  380. // Find the last subsection.
  381. //
  382. ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0);
  383. if (((PMAPPED_FILE_SEGMENT)Segment)->LastSubsectionHint != NULL) {
  384. LastSubsection = (PSUBSECTION) ((PMAPPED_FILE_SEGMENT)Segment)->LastSubsectionHint;
  385. }
  386. else {
  387. if (ControlArea->u.Flags.Rom == 1) {
  388. LastSubsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
  389. }
  390. else {
  391. LastSubsection = (PSUBSECTION)(ControlArea + 1);
  392. }
  393. }
  394. while (LastSubsection->NextSubsection != NULL) {
  395. ASSERT (LastSubsection->UnusedPtes == 0);
  396. LastSubsection = LastSubsection->NextSubsection;
  397. }
  398. MI_CHECK_SUBSECTION (LastSubsection);
  399. //
  400. // Does the structure need extending?
  401. //
  402. TotalNumberOfPtes = (((UINT64)Segment->SegmentFlags.TotalNumberOfPtes4132) << 32) | Segment->TotalNumberOfPtes;
  403. if (NumberOfPtes <= TotalNumberOfPtes) {
  404. //
  405. // The segment is already large enough, just update
  406. // the section size and return.
  407. //
  408. Section->SizeOfSection = *NewSectionSize;
  409. if (Segment->SizeOfSegment < (UINT64)NewSectionSize->QuadPart) {
  410. //
  411. // Only update if it is really bigger.
  412. //
  413. Segment->SizeOfSegment = *(PUINT64)NewSectionSize;
  414. Mi4KStartFromSubsection(&Starting4K, LastSubsection);
  415. Last4KChunk.QuadPart = (NewSectionSize->QuadPart >> MM4K_SHIFT) - Starting4K.QuadPart;
  416. ASSERT (Last4KChunk.HighPart == 0);
  417. LastSubsection->NumberOfFullSectors = Last4KChunk.LowPart;
  418. LastSubsection->u.SubsectionFlags.SectorEndOffset =
  419. NewSectionSize->LowPart & MM4K_MASK;
  420. MI_CHECK_SUBSECTION (LastSubsection);
  421. }
  422. goto ReleaseAndReturnSuccess;
  423. }
  424. //
  425. // Add new structures to the section - locate the last subsection
  426. // and add there.
  427. //
  428. RequiredPtes = NumberOfPtes - TotalNumberOfPtes;
  429. PtesUsed = 0;
  430. if (RequiredPtes < LastSubsection->UnusedPtes) {
  431. //
  432. // There are ample PTEs to extend the section already allocated.
  433. //
  434. PtesUsed = (ULONG) RequiredPtes;
  435. RequiredPtes = 0;
  436. }
  437. else {
  438. PtesUsed = LastSubsection->UnusedPtes;
  439. RequiredPtes -= PtesUsed;
  440. }
  441. LastSubsection->PtesInSubsection += PtesUsed;
  442. LastSubsection->UnusedPtes -= PtesUsed;
  443. Segment->SizeOfSegment += (UINT64)PtesUsed * PAGE_SIZE;
  444. TotalNumberOfPtes += PtesUsed;
  445. Segment->TotalNumberOfPtes = (ULONG) TotalNumberOfPtes;
  446. if (TotalNumberOfPtes >= 0x100000000) {
  447. Segment->SegmentFlags.TotalNumberOfPtes4132 = (ULONG_PTR)(TotalNumberOfPtes >> 32);
  448. }
  449. if (RequiredPtes == 0) {
  450. //
  451. // There is no extension necessary, update the high VBN.
  452. //
  453. Mi4KStartFromSubsection(&Starting4K, LastSubsection);
  454. Last4KChunk.QuadPart = (NewSectionSize->QuadPart >> MM4K_SHIFT) - Starting4K.QuadPart;
  455. ASSERT (Last4KChunk.HighPart == 0);
  456. LastSubsection->NumberOfFullSectors = Last4KChunk.LowPart;
  457. LastSubsection->u.SubsectionFlags.SectorEndOffset =
  458. NewSectionSize->LowPart & MM4K_MASK;
  459. MI_CHECK_SUBSECTION (LastSubsection);
  460. }
  461. else {
  462. //
  463. // An extension is required.
  464. //
  465. // Allocate the subsection(s) now.
  466. //
  467. // If there are any user views, then also allocate the prototype
  468. // PTEs now (because a user view may be for an extended VAD which
  469. // would already be encompassing this new extension). If there
  470. // are no user views, then don't allocate the prototype PTEs until
  471. // the views are actually mapped (system views never pre-extend past
  472. // the end of the file).
  473. //
  474. NumberOf4KsForEntireFile.QuadPart = Segment->SizeOfSegment >> MM4K_SHIFT;
  475. AllocationSize = MI_ROUND_TO_SIZE (RequiredPtes * sizeof(MMPTE), PAGE_SIZE);
  476. AllocationFragment = MmAllocationFragment;
  477. RunningSize = 0;
  478. ExtendedSubsectionHead = *(PMSUBSECTION)LastSubsection;
  479. LastExtendedSubsection = &ExtendedSubsectionHead;
  480. ASSERT (LastExtendedSubsection->NextSubsection == NULL);
  481. SATISFY_OVERZEALOUS_COMPILER (NextSubsection4KStart.QuadPart = 0);
  482. do {
  483. //
  484. // Bound the size of each prototype PTE allocation so both :
  485. // 1. it can succeed even in cases where the pool is fragmented.
  486. // 2. later on last control area dereference, each subsection
  487. // is converted to dynamic and can be pruned/recreated
  488. // individually without losing (or requiring) contiguous pool.
  489. //
  490. if (AllocationSize - RunningSize > AllocationFragment) {
  491. PartialSize = (ULONG) AllocationFragment;
  492. }
  493. else {
  494. PartialSize = (ULONG) (AllocationSize - RunningSize);
  495. }
  496. //
  497. // Allocate an extended subsection.
  498. //
  499. ExtendedSubsection = (PMSUBSECTION) ExAllocatePoolWithTag (NonPagedPool,
  500. sizeof(MSUBSECTION),
  501. 'dSmM');
  502. if (ExtendedSubsection == NULL) {
  503. goto ExtensionFailed;
  504. }
  505. ExtendedSubsection->SubsectionBase = NULL;
  506. ExtendedSubsection->NextSubsection = NULL;
  507. LastExtendedSubsection->NextSubsection = (PSUBSECTION) ExtendedSubsection;
  508. ASSERT (ControlArea->FilePointer != NULL);
  509. ExtendedSubsection->u.LongFlags = 0;
  510. ExtendedSubsection->ControlArea = ControlArea;
  511. ExtendedSubsection->PtesInSubsection = PartialSize / sizeof(MMPTE);
  512. ExtendedSubsection->UnusedPtes = 0;
  513. RunningSize += PartialSize;
  514. if (RunningSize > (RequiredPtes * sizeof(MMPTE))) {
  515. UnusedPtes = (ULONG)(RunningSize / sizeof(MMPTE) - RequiredPtes);
  516. ExtendedSubsection->PtesInSubsection -= UnusedPtes;
  517. ExtendedSubsection->UnusedPtes = UnusedPtes;
  518. }
  519. ExtendedSubsection->u.SubsectionFlags.Protection =
  520. (unsigned) Segment->SegmentPteTemplate.u.Soft.Protection;
  521. ExtendedSubsection->DereferenceList.Flink = NULL;
  522. ExtendedSubsection->DereferenceList.Blink = NULL;
  523. ExtendedSubsection->NumberOfMappedViews = 0;
  524. ExtendedSubsection->u2.LongFlags2 = 0;
  525. //
  526. // Adjust the previous subsection to account for the new length.
  527. // Note that since the next allocation in this loop may fail,
  528. // the very first previous subsection changes are not rippled
  529. // to the chained subsection until the loop completes successfully.
  530. //
  531. if (LastExtendedSubsection == &ExtendedSubsectionHead) {
  532. Mi4KStartFromSubsection (&Starting4K, LastExtendedSubsection);
  533. Last4KChunk.QuadPart = NumberOf4KsForEntireFile.QuadPart -
  534. Starting4K.QuadPart;
  535. if (LastExtendedSubsection->u.SubsectionFlags.SectorEndOffset) {
  536. Last4KChunk.QuadPart += 1;
  537. }
  538. ASSERT (Last4KChunk.HighPart == 0);
  539. LastExtendedSubsection->NumberOfFullSectors = Last4KChunk.LowPart;
  540. LastExtendedSubsection->u.SubsectionFlags.SectorEndOffset = 0;
  541. //
  542. // If the number of sectors doesn't completely fill the PTEs
  543. // (only possible when the page size is not MM4K), then
  544. // fill it now.
  545. //
  546. if (LastExtendedSubsection->NumberOfFullSectors & ((1 << (PAGE_SHIFT - MM4K_SHIFT)) - 1)) {
  547. LastExtendedSubsection->NumberOfFullSectors += 1;
  548. }
  549. MI_CHECK_SUBSECTION (LastExtendedSubsection);
  550. Starting4K.QuadPart += LastExtendedSubsection->NumberOfFullSectors;
  551. NextSubsection4KStart.QuadPart = Starting4K.QuadPart;
  552. }
  553. else {
  554. NextSubsection4KStart.QuadPart += LastExtendedSubsection->NumberOfFullSectors;
  555. }
  556. //
  557. // Initialize the newly allocated subsection.
  558. //
  559. Mi4KStartForSubsection (&NextSubsection4KStart, ExtendedSubsection);
  560. if (RunningSize < AllocationSize) {
  561. //
  562. // Not the final subsection so all quantities are full pages.
  563. //
  564. ExtendedSubsection->NumberOfFullSectors =
  565. (PartialSize / sizeof (MMPTE)) << (PAGE_SHIFT - MM4K_SHIFT);
  566. ExtendedSubsection->u.SubsectionFlags.SectorEndOffset = 0;
  567. }
  568. else {
  569. //
  570. // The final subsection so quantities are not always full pages.
  571. //
  572. Last4KChunk.QuadPart =
  573. (NewSectionSize->QuadPart >> MM4K_SHIFT) - NextSubsection4KStart.QuadPart;
  574. ASSERT (Last4KChunk.HighPart == 0);
  575. ExtendedSubsection->NumberOfFullSectors = Last4KChunk.LowPart;
  576. ExtendedSubsection->u.SubsectionFlags.SectorEndOffset =
  577. NewSectionSize->LowPart & MM4K_MASK;
  578. }
  579. MI_CHECK_SUBSECTION (ExtendedSubsection);
  580. //
  581. // This subsection may be extending a range that is already
  582. // mapped by a VAD(s). There is no way to tell how many VADs
  583. // already map it so just mark the entire subsection as not
  584. // reclaimable until the control area is deleted.
  585. //
  586. // This also saves other portions of code that issue "dereference
  587. // from this subsection to the end of file" as these subsections are
  588. // marked as static not dynamic (at least until segment dereference
  589. // time).
  590. //
  591. // When this chain is appended to the control area at the end of
  592. // this routine an attempt is made to convert the subsection chain
  593. // to dynamic if no user mapped views are active.
  594. //
  595. LastExtendedSubsection = ExtendedSubsection;
  596. } while (RunningSize < AllocationSize);
  597. if (ControlArea->NumberOfUserReferences == 0) {
  598. ASSERT (IgnoreFileSizeChecking == TRUE);
  599. }
  600. //
  601. // All the subsections have been allocated, try to append the
  602. // subsection chain without allocating prototype PTEs. If user
  603. // views are present, the append will fail, at which point we will
  604. // attempt to allocate prototype PTEs and retry.
  605. //
  606. Appended = MiAppendSubsectionChain ((PMSUBSECTION)LastSubsection,
  607. &ExtendedSubsectionHead);
  608. if (Appended == FALSE) {
  609. RunningSize = 0;
  610. Subsection = (PSUBSECTION) &ExtendedSubsectionHead;
  611. do {
  612. if (AllocationSize - RunningSize > AllocationFragment) {
  613. PartialSize = (ULONG) AllocationFragment;
  614. }
  615. else {
  616. PartialSize = (ULONG) (AllocationSize - RunningSize);
  617. }
  618. RunningSize += PartialSize;
  619. ProtoPtes = (PMMPTE)ExAllocatePoolWithTag (PagedPool | POOL_MM_ALLOCATION,
  620. PartialSize,
  621. MMSECT);
  622. if (ProtoPtes == NULL) {
  623. goto ExtensionFailed;
  624. }
  625. Subsection = Subsection->NextSubsection;
  626. Subsection->SubsectionBase = ProtoPtes;
  627. Subsection->u.SubsectionFlags.SubsectionStatic = 1;
  628. //
  629. // Fill in the prototype PTEs for this subsection.
  630. //
  631. // Set all the PTEs to the initial execute-read-write protection.
  632. // The section will control access to these and the segment
  633. // must provide a method to allow other users to map the file
  634. // for various protections.
  635. //
  636. TempPte.u.Long = MiGetSubsectionAddressForPte (Subsection);
  637. TempPte.u.Soft.Prototype = 1;
  638. TempPte.u.Soft.Protection = Segment->SegmentPteTemplate.u.Soft.Protection;
  639. MiFillMemoryPte (ProtoPtes, PartialSize / sizeof (MMPTE), TempPte.u.Long);
  640. } while (RunningSize < AllocationSize);
  641. ASSERT (ControlArea->DereferenceList.Flink == NULL);
  642. //
  643. // Link the newly created subsection chain into the existing list.
  644. // Note that any adjustments (NumberOfFullSectors, etc) made to
  645. // the temp copy of the last subsection in the existing control
  646. // area must be *CAREFULLY* copied to the real copy in the chain (the
  647. // entire structure cannot just be block copied) as other fields
  648. // in the real copy (ie: NumberOfMappedViews may be changed in
  649. // parallel by another thread).
  650. //
  651. Appended = MiAppendSubsectionChain ((PMSUBSECTION)LastSubsection,
  652. &ExtendedSubsectionHead);
  653. ASSERT (Appended == TRUE);
  654. }
  655. TotalNumberOfPtes += RequiredPtes;
  656. Segment->TotalNumberOfPtes = (ULONG) TotalNumberOfPtes;
  657. if (TotalNumberOfPtes >= 0x100000000) {
  658. Segment->SegmentFlags.TotalNumberOfPtes4132 = (ULONG_PTR)(TotalNumberOfPtes >> 32);
  659. }
  660. if (LastExtendedSubsection != &ExtendedSubsectionHead) {
  661. ((PMAPPED_FILE_SEGMENT)Segment)->LastSubsectionHint =
  662. LastExtendedSubsection;
  663. }
  664. }
  665. Segment->SizeOfSegment = *(PUINT64)NewSectionSize;
  666. Section->SizeOfSection = *NewSectionSize;
  667. ReleaseAndReturnSuccess:
  668. Status = STATUS_SUCCESS;
  669. ReleaseAndReturn:
  670. ExReleaseResourceLite (&MmSectionExtendResource);
  671. KeLeaveCriticalRegionThread (CurrentThread);
  672. return Status;
  673. ExtensionFailed:
  674. //
  675. // Required pool to extend the section could not be allocated.
  676. // Reset the subsection and control area fields to their
  677. // original values.
  678. //
  679. LastSubsection->PtesInSubsection -= PtesUsed;
  680. LastSubsection->UnusedPtes += PtesUsed;
  681. TotalNumberOfPtes -= PtesUsed;
  682. Segment->SegmentFlags.TotalNumberOfPtes4132 = 0;
  683. Segment->TotalNumberOfPtes = (ULONG) TotalNumberOfPtes;
  684. if (TotalNumberOfPtes >= 0x100000000) {
  685. Segment->SegmentFlags.TotalNumberOfPtes4132 = (ULONG_PTR)(TotalNumberOfPtes >> 32);
  686. }
  687. Segment->SizeOfSegment -= ((UINT64)PtesUsed * PAGE_SIZE);
  688. //
  689. // Free all the previous allocations and return an error.
  690. //
  691. LastSubsection = ExtendedSubsectionHead.NextSubsection;
  692. while (LastSubsection != NULL) {
  693. Subsection = LastSubsection->NextSubsection;
  694. if (LastSubsection->SubsectionBase != NULL) {
  695. ExFreePool (LastSubsection->SubsectionBase);
  696. }
  697. ExFreePool (LastSubsection);
  698. LastSubsection = Subsection;
  699. }
  700. Status = STATUS_INSUFFICIENT_RESOURCES;
  701. goto ReleaseAndReturn;
  702. }
  703. PMMPTE
  704. FASTCALL
  705. MiGetProtoPteAddressExtended (
  706. IN PMMVAD Vad,
  707. IN ULONG_PTR Vpn
  708. )
  709. /*++
  710. Routine Description:
  711. This function calculates the address of the prototype PTE
  712. for the corresponding virtual address.
  713. Arguments:
  714. Vad - Supplies a pointer to the virtual address descriptor which
  715. encompasses the virtual address.
  716. Vpn - Supplies the virtual page number to locate a prototype PTE for.
  717. Return Value:
  718. The corresponding prototype PTE address.
  719. --*/
  720. {
  721. PSUBSECTION Subsection;
  722. PCONTROL_AREA ControlArea;
  723. ULONG PteOffset;
  724. ControlArea = Vad->ControlArea;
  725. if (ControlArea->u.Flags.GlobalOnlyPerSession == 0) {
  726. Subsection = (PSUBSECTION)(ControlArea + 1);
  727. }
  728. else {
  729. Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
  730. }
  731. //
  732. // Locate the subsection which contains the First Prototype PTE
  733. // for this VAD.
  734. //
  735. while ((Subsection->SubsectionBase == NULL) ||
  736. (Vad->FirstPrototypePte < Subsection->SubsectionBase) ||
  737. (Vad->FirstPrototypePte >=
  738. &Subsection->SubsectionBase[Subsection->PtesInSubsection])) {
  739. //
  740. // Get the next subsection.
  741. //
  742. Subsection = Subsection->NextSubsection;
  743. if (Subsection == NULL) {
  744. return NULL;
  745. }
  746. }
  747. ASSERT (Subsection->SubsectionBase != NULL);
  748. //
  749. // How many PTEs beyond this subsection must we go?
  750. //
  751. PteOffset = (ULONG) (((Vpn - Vad->StartingVpn) +
  752. (ULONG)(Vad->FirstPrototypePte - Subsection->SubsectionBase)) -
  753. Subsection->PtesInSubsection);
  754. ASSERT (PteOffset < 0xF0000000);
  755. PteOffset += Subsection->PtesInSubsection;
  756. //
  757. // Locate the subsection which contains the prototype PTEs.
  758. //
  759. while (PteOffset >= Subsection->PtesInSubsection) {
  760. PteOffset -= Subsection->PtesInSubsection;
  761. Subsection = Subsection->NextSubsection;
  762. if (Subsection == NULL) {
  763. return NULL;
  764. }
  765. }
  766. //
  767. // The PTEs are in this subsection.
  768. //
  769. ASSERT (Subsection->SubsectionBase != NULL);
  770. ASSERT (PteOffset < Subsection->PtesInSubsection);
  771. return &Subsection->SubsectionBase[PteOffset];
  772. }
  773. PSUBSECTION
  774. FASTCALL
  775. MiLocateSubsection (
  776. IN PMMVAD Vad,
  777. IN ULONG_PTR Vpn
  778. )
  779. /*++
  780. Routine Description:
  781. This function calculates the address of the subsection
  782. for the corresponding virtual address.
  783. This function only works for mapped files NOT mapped images.
  784. Arguments:
  785. Vad - Supplies a pointer to the virtual address descriptor which
  786. encompasses the virtual address.
  787. Vpn - Supplies the virtual page number to locate a prototype PTE for.
  788. Return Value:
  789. The corresponding prototype subsection.
  790. --*/
  791. {
  792. PSUBSECTION Subsection;
  793. PCONTROL_AREA ControlArea;
  794. ULONG PteOffset;
  795. ControlArea = Vad->ControlArea;
  796. if (ControlArea->u.Flags.Rom == 0) {
  797. Subsection = (PSUBSECTION)(ControlArea + 1);
  798. }
  799. else {
  800. Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
  801. }
  802. if (ControlArea->u.Flags.Image) {
  803. if (ControlArea->u.Flags.GlobalOnlyPerSession == 1) {
  804. Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1);
  805. }
  806. //
  807. // There is only one subsection, don't look any further.
  808. //
  809. return Subsection;
  810. }
  811. ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0);
  812. //
  813. // Locate the subsection which contains the First Prototype PTE
  814. // for this VAD. Note all the SubsectionBase values must be non-NULL
  815. // for the subsection range spanned by the VAD because the VAD still
  816. // exists. Carefully skip over preceding subsections not mapped by
  817. // this VAD because if no other VADs map them either, their base
  818. // can be NULL.
  819. //
  820. while ((Subsection->SubsectionBase == NULL) ||
  821. (Vad->FirstPrototypePte < Subsection->SubsectionBase) ||
  822. (Vad->FirstPrototypePte >=
  823. &Subsection->SubsectionBase[Subsection->PtesInSubsection])) {
  824. //
  825. // Get the next subsection.
  826. //
  827. Subsection = Subsection->NextSubsection;
  828. if (Subsection == NULL) {
  829. return NULL;
  830. }
  831. }
  832. ASSERT (Subsection->SubsectionBase != NULL);
  833. //
  834. // How many PTEs beyond this subsection must we go?
  835. //
  836. PteOffset = (ULONG)((Vpn - Vad->StartingVpn) +
  837. (ULONG)(Vad->FirstPrototypePte - Subsection->SubsectionBase));
  838. ASSERT (PteOffset < 0xF0000000);
  839. //
  840. // Locate the subsection which contains the prototype PTEs.
  841. //
  842. while (PteOffset >= Subsection->PtesInSubsection) {
  843. PteOffset -= Subsection->PtesInSubsection;
  844. Subsection = Subsection->NextSubsection;
  845. if (Subsection == NULL) {
  846. return NULL;
  847. }
  848. ASSERT (Subsection->SubsectionBase != NULL);
  849. }
  850. //
  851. // The PTEs are in this subsection.
  852. //
  853. ASSERT (Subsection->SubsectionBase != NULL);
  854. return Subsection;
  855. }