xref: /reactos/ntoskrnl/cache/section/reqtools.c (revision c2c66aff)
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