1 /* 2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section) 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 * 18 * 19 * PROJECT: ReactOS kernel 20 * FILE: ntoskrnl/cache/section/reqtools.c 21 * PURPOSE: Implements section objects 22 * 23 * PROGRAMMERS: Rex Jolliff 24 * David Welch 25 * Eric Kohl 26 * Emanuele Aliberti 27 * Eugene Ingerman 28 * Casper Hornstrup 29 * KJK::Hyperion 30 * Guido de Jong 31 * Ge van Geldorp 32 * Royce Mitchell III 33 * Filip Navara 34 * Aleksey Bragin 35 * Jason Filby 36 * Thomas Weidenmueller 37 * Gunnar Andre' Dalsnes 38 * Mike Nordell 39 * Alex Ionescu 40 * Gregor Anich 41 * Steven Edwards 42 * Herve Poussineau 43 */ 44 45 /* 46 This file contains functions used by fault.c to do blocking resource 47 acquisition. To call one of these functions, fill out your 48 MM_REQUIRED_RESOURCES with a pointer to the desired function and configure 49 the other members as below. 50 */ 51 52 /* INCLUDES *****************************************************************/ 53 54 #include <ntoskrnl.h> 55 #include "newmm.h" 56 #define NDEBUG 57 #include <debug.h> 58 59 #define DPRINTC DPRINT 60 61 VOID 62 NTAPI 63 MmBuildMdlFromPages(PMDL Mdl, PPFN_NUMBER Pages); 64 65 /* 66 67 Blocking function to acquire zeroed pages from the balancer. 68 69 Upon entry: 70 71 Required->Amount: Number of pages to acquire 72 Required->Consumer: consumer to charge the page to 73 74 Upon return: 75 76 Required->Pages[0..Amount]: Allocated pages. 77 78 The function fails unless all requested pages can be allocated. 79 80 */ 81 NTSTATUS 82 NTAPI 83 MiGetOnePage(PMMSUPPORT AddressSpace, 84 PMEMORY_AREA MemoryArea, 85 PMM_REQUIRED_RESOURCES Required) 86 { 87 ULONG i; 88 NTSTATUS Status = STATUS_SUCCESS; 89 90 for (i = 0; i < Required->Amount; i++) 91 { 92 DPRINTC("MiGetOnePage(%s:%d)\n", Required->File, Required->Line); 93 Status = MmRequestPageMemoryConsumer(Required->Consumer, 94 TRUE, 95 &Required->Page[i]); 96 if (!NT_SUCCESS(Status)) 97 { 98 while (i > 0) 99 { 100 MmReleasePageMemoryConsumer(Required->Consumer, 101 Required->Page[i-1]); 102 i--; 103 } 104 return Status; 105 } 106 } 107 108 return Status; 109 } 110 111 /* 112 113 Blocking function to read (part of) a page from a file. 114 115 Upon entry: 116 117 Required->Context: a FILE_OBJECT to read 118 Required->Consumer: consumer to charge the page to 119 Required->FileOffset: Offset to read at 120 Required->Amount: Number of bytes to read (0 -> 4096) 121 122 Upon return: 123 124 Required->Page[Required->Offset]: The allocated and read in page 125 126 The indicated page is filled to Required->Amount with file data and zeroed 127 afterward. 128 129 */ 130 131 NTSTATUS 132 NTAPI 133 MiReadFilePage(PMMSUPPORT AddressSpace, 134 PMEMORY_AREA MemoryArea, 135 PMM_REQUIRED_RESOURCES RequiredResources) 136 { 137 PFILE_OBJECT FileObject = RequiredResources->Context; 138 PPFN_NUMBER Page = &RequiredResources->Page[RequiredResources->Offset]; 139 PLARGE_INTEGER FileOffset = &RequiredResources->FileOffset; 140 NTSTATUS Status; 141 PVOID PageBuf = NULL; 142 KEVENT Event; 143 IO_STATUS_BLOCK IOSB; 144 UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)]; 145 PMDL Mdl = (PMDL)MdlBase; 146 KIRQL OldIrql; 147 148 DPRINTC("Pulling page %I64x from %wZ to %Ix\n", 149 FileOffset->QuadPart, 150 &FileObject->FileName, 151 *Page); 152 153 Status = MmRequestPageMemoryConsumer(RequiredResources->Consumer, 154 TRUE, 155 Page); 156 157 if (!NT_SUCCESS(Status)) 158 { 159 DPRINT1("Status: %x\n", Status); 160 return Status; 161 } 162 163 MmInitializeMdl(Mdl, NULL, PAGE_SIZE); 164 MmBuildMdlFromPages(Mdl, Page); 165 Mdl->MdlFlags |= MDL_PAGES_LOCKED; 166 167 KeInitializeEvent(&Event, NotificationEvent, FALSE); 168 Status = IoPageRead(FileObject, Mdl, FileOffset, &Event, &IOSB); 169 if (Status == STATUS_PENDING) 170 { 171 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 172 Status = IOSB.Status; 173 } 174 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) 175 { 176 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 177 } 178 179 PageBuf = MiMapPageInHyperSpace(PsGetCurrentProcess(), *Page, &OldIrql); 180 if (!PageBuf) 181 { 182 MmReleasePageMemoryConsumer(RequiredResources->Consumer, *Page); 183 return STATUS_NO_MEMORY; 184 } 185 186 RtlZeroMemory((PCHAR)PageBuf+RequiredResources->Amount, 187 PAGE_SIZE-RequiredResources->Amount); 188 189 MiUnmapPageInHyperSpace(PsGetCurrentProcess(), PageBuf, OldIrql); 190 191 DPRINT("Read Status %x (Page %x)\n", Status, *Page); 192 193 if (!NT_SUCCESS(Status)) 194 { 195 MmReleasePageMemoryConsumer(RequiredResources->Consumer, *Page); 196 DPRINT("Status: %x\n", Status); 197 return Status; 198 } 199 200 return STATUS_SUCCESS; 201 } 202 203 /* 204 205 Blocking function to read a swap page into a memory page. 206 207 Upon entry: 208 209 Required->Consumer: consumer to charge the page to 210 Required->SwapEntry: swap entry to use 211 212 Upon return: 213 214 Required->Page[Required->Offset]: Populated page 215 216 */ 217 218 NTSTATUS 219 NTAPI 220 MiSwapInPage(PMMSUPPORT AddressSpace, 221 PMEMORY_AREA MemoryArea, 222 PMM_REQUIRED_RESOURCES Resources) 223 { 224 NTSTATUS Status; 225 226 Status = MmRequestPageMemoryConsumer(Resources->Consumer, 227 TRUE, 228 &Resources->Page[Resources->Offset]); 229 if (!NT_SUCCESS(Status)) 230 { 231 DPRINT1("MmRequestPageMemoryConsumer failed, status = %x\n", Status); 232 return Status; 233 } 234 235 Status = MmReadFromSwapPage(Resources->SwapEntry, 236 Resources->Page[Resources->Offset]); 237 if (!NT_SUCCESS(Status)) 238 { 239 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status); 240 return Status; 241 } 242 243 MmSetSavedSwapEntryPage(Resources->Page[Resources->Offset], 244 Resources->SwapEntry); 245 246 DPRINT1("MiSwapInPage(%x,%x)\n", 247 Resources->Page[Resources->Offset], 248 Resources->SwapEntry); 249 250 return Status; 251 } 252 253 /* 254 255 A way to write a page without a lock acquired using the same blocking mechanism 256 as resource acquisition. 257 258 Upon entry: 259 260 Required->Page[Required->Offset]: Page to write 261 Required->Context: FILE_OBJECT to write to 262 Required->FileOffset: offset to write at 263 264 This always does a paging write with whole page size. Note that paging IO 265 doesn't change the valid data length of a file. 266 267 */ 268 269 NTSTATUS 270 NTAPI 271 MiWriteFilePage(PMMSUPPORT AddressSpace, 272 PMEMORY_AREA MemoryArea, 273 PMM_REQUIRED_RESOURCES Required) 274 { 275 DPRINT1("MiWriteFilePage(%x,%x)\n", 276 Required->Page[Required->Offset], 277 Required->FileOffset.LowPart); 278 279 return MiWriteBackPage(Required->Context, 280 &Required->FileOffset, 281 PAGE_SIZE, 282 Required->Page[Required->Offset]); 283 } 284