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
MiGetOnePage(PMMSUPPORT AddressSpace,PMEMORY_AREA MemoryArea,PMM_REQUIRED_RESOURCES Required)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
MiReadFilePage(PMMSUPPORT AddressSpace,PMEMORY_AREA MemoryArea,PMM_REQUIRED_RESOURCES RequiredResources)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
MiSwapInPage(PMMSUPPORT AddressSpace,PMEMORY_AREA MemoryArea,PMM_REQUIRED_RESOURCES Resources)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
MiWriteFilePage(PMMSUPPORT AddressSpace,PMEMORY_AREA MemoryArea,PMM_REQUIRED_RESOURCES Required)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