[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / cache / section / io.c
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/mm/section.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 /* INCLUDES *****************************************************************/
46
47 #include <ntoskrnl.h>
48 #include "newmm.h"
49 #define NDEBUG
50 #include <debug.h>
51 #include <reactos/exeformat.h>
52
53 #if defined (ALLOC_PRAGMA)
54 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
55 #pragma alloc_text(INIT, MmInitSectionImplementation)
56 #endif
57
58 KEVENT CcpLazyWriteEvent;
59
60 PDEVICE_OBJECT
61 NTAPI
62 MmGetDeviceObjectForFile(IN PFILE_OBJECT FileObject)
63 {
64 return IoGetRelatedDeviceObject(FileObject);
65 }
66
67 /*
68
69 Note:
70 This completion function is really required. Paging io completion does almost
71 nothing, including freeing the mdls.
72
73 */
74 _Function_class_(IO_COMPLETION_ROUTINE)
75 NTSTATUS
76 NTAPI
77 MiSimpleReadComplete(PDEVICE_OBJECT DeviceObject,
78 PIRP Irp,
79 PVOID Context)
80 {
81 PMDL Mdl = Irp->MdlAddress;
82
83 /* Unlock MDL Pages, page 167. */
84 DPRINT("MiSimpleReadComplete %p\n", Irp);
85 while (Mdl)
86 {
87 DPRINT("MDL Unlock %p\n", Mdl);
88 MmUnlockPages(Mdl);
89 Mdl = Mdl->Next;
90 }
91
92 /* Check if there's an MDL */
93 while ((Mdl = Irp->MdlAddress))
94 {
95 /* Clear all of them */
96 Irp->MdlAddress = Mdl->Next;
97 IoFreeMdl(Mdl);
98 }
99
100 return STATUS_SUCCESS;
101 }
102
103 /*
104
105 MiSimpleRead is a convenience function that provides either paging or non
106 paging reads. The caching and mm systems use this in paging mode, where
107 a completion function is required as above. The Paging BOOLEAN determines
108 whether the read is issued as a paging read or as an ordinary buffered read.
109
110 */
111
112 NTSTATUS
113 NTAPI
114 MiSimpleRead(PFILE_OBJECT FileObject,
115 PLARGE_INTEGER FileOffset,
116 PVOID Buffer,
117 ULONG Length,
118 BOOLEAN Paging,
119 PIO_STATUS_BLOCK ReadStatus)
120 {
121 NTSTATUS Status;
122 PIRP Irp = NULL;
123 KEVENT ReadWait;
124 PDEVICE_OBJECT DeviceObject;
125 PIO_STACK_LOCATION IrpSp;
126
127 ASSERT(FileObject);
128 ASSERT(FileOffset);
129 ASSERT(Buffer);
130 ASSERT(ReadStatus);
131
132 DeviceObject = MmGetDeviceObjectForFile(FileObject);
133 ReadStatus->Status = STATUS_INTERNAL_ERROR;
134 ReadStatus->Information = 0;
135
136 ASSERT(DeviceObject);
137
138 DPRINT("PAGING READ: FileObject %p <%wZ> Offset %08x%08x Length %d\n",
139 FileObject,
140 &FileObject->FileName,
141 FileOffset->HighPart,
142 FileOffset->LowPart,
143 Length);
144
145 KeInitializeEvent(&ReadWait, NotificationEvent, FALSE);
146
147 Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
148 DeviceObject,
149 Buffer,
150 Length,
151 FileOffset,
152 ReadStatus);
153
154 if (!Irp)
155 {
156 return STATUS_NO_MEMORY;
157 }
158
159 Irp->Flags |= (Paging ? IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO | IRP_NOCACHE : 0) | IRP_SYNCHRONOUS_API;
160
161 Irp->UserEvent = &ReadWait;
162 Irp->Tail.Overlay.OriginalFileObject = FileObject;
163 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
164 IrpSp = IoGetNextIrpStackLocation(Irp);
165 IrpSp->Control |= SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
166 IrpSp->FileObject = FileObject;
167 IrpSp->CompletionRoutine = MiSimpleReadComplete;
168
169 /* Non paging case, the FileObject will be dereferenced at completion */
170 if (!Paging)
171 ObReferenceObject(FileObject);
172
173 Status = IoCallDriver(DeviceObject, Irp);
174 if (Status == STATUS_PENDING)
175 {
176 DPRINT("KeWaitForSingleObject(&ReadWait)\n");
177 if (!NT_SUCCESS(KeWaitForSingleObject(&ReadWait,
178 Suspended,
179 KernelMode,
180 FALSE,
181 NULL)))
182 {
183 DPRINT1("Warning: Failed to wait for synchronous IRP\n");
184 ASSERT(FALSE);
185 return Status;
186 }
187 }
188
189 DPRINT("Paging IO Done: %08x\n", ReadStatus->Status);
190 Status = ReadStatus->Status == STATUS_END_OF_FILE ? STATUS_SUCCESS : ReadStatus->Status;
191 return Status;
192 }
193
194 /*
195
196 Convenience function for writing from kernel space. This issues a paging
197 write in all cases.
198
199 */
200
201 NTSTATUS
202 NTAPI
203 _MiSimpleWrite(PFILE_OBJECT FileObject,
204 PLARGE_INTEGER FileOffset,
205 PVOID Buffer,
206 ULONG Length,
207 PIO_STATUS_BLOCK ReadStatus,
208 const char *File,
209 int Line)
210 {
211 NTSTATUS Status;
212 PIRP Irp = NULL;
213 KEVENT ReadWait;
214 PDEVICE_OBJECT DeviceObject;
215 PIO_STACK_LOCATION IrpSp;
216
217 ASSERT(FileObject);
218 ASSERT(FileOffset);
219 ASSERT(Buffer);
220 ASSERT(ReadStatus);
221
222 DeviceObject = MmGetDeviceObjectForFile(FileObject);
223 ASSERT(DeviceObject);
224
225 DPRINT("PAGING WRITE: FileObject %x <%wZ> Offset %x Length %d (%s:%d)\n",
226 FileObject,
227 &FileObject->FileName,
228 FileOffset->LowPart,
229 Length,
230 File,
231 Line);
232
233 KeInitializeEvent(&ReadWait, NotificationEvent, FALSE);
234
235 Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
236 DeviceObject,
237 Buffer,
238 Length,
239 FileOffset,
240 ReadStatus);
241
242 if (!Irp)
243 {
244 return STATUS_NO_MEMORY;
245 }
246
247 Irp->Flags = IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_API;
248
249 Irp->UserEvent = &ReadWait;
250 Irp->Tail.Overlay.OriginalFileObject = FileObject;
251 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
252 IrpSp = IoGetNextIrpStackLocation(Irp);
253 IrpSp->Control |= SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
254 IrpSp->FileObject = FileObject;
255 IrpSp->CompletionRoutine = MiSimpleReadComplete;
256
257 DPRINT("Call Driver\n");
258 Status = IoCallDriver(DeviceObject, Irp);
259 DPRINT("Status %x\n", Status);
260
261 if (Status == STATUS_PENDING)
262 {
263 DPRINT("KeWaitForSingleObject(&ReadWait)\n");
264 if (!NT_SUCCESS(KeWaitForSingleObject(&ReadWait,
265 Suspended,
266 KernelMode,
267 FALSE,
268 NULL)))
269 {
270 DPRINT1("Warning: Failed to wait for synchronous IRP\n");
271 ASSERT(FALSE);
272 return Status;
273 }
274 }
275
276 DPRINT("Paging IO Done: %08x\n", ReadStatus->Status);
277 return ReadStatus->Status;
278 }
279
280 extern KEVENT MpwThreadEvent;
281 FAST_MUTEX MiWriteMutex;
282
283 /*
284
285 Function which uses MiSimpleWrite to write back a single page to a file.
286 The page in question does not need to be mapped. This function could be
287 made a bit more efficient by avoiding the copy and making a system space
288 mdl.
289
290 */
291
292 NTSTATUS
293 NTAPI
294 _MiWriteBackPage(PFILE_OBJECT FileObject,
295 PLARGE_INTEGER FileOffset,
296 ULONG Length,
297 PFN_NUMBER Page,
298 const char *File,
299 int Line)
300 {
301 NTSTATUS Status;
302 PVOID Hyperspace;
303 IO_STATUS_BLOCK Iosb;
304 KIRQL OldIrql;
305 PVOID PageBuffer = ExAllocatePool(NonPagedPool, PAGE_SIZE);
306
307 if (!PageBuffer) return STATUS_NO_MEMORY;
308
309 Hyperspace = MiMapPageInHyperSpace(PsGetCurrentProcess(), Page, &OldIrql);
310 if (!Hyperspace)
311 {
312 ExFreePool(PageBuffer);
313 return STATUS_NO_MEMORY;
314 }
315 RtlCopyMemory(PageBuffer, Hyperspace, PAGE_SIZE);
316 MiUnmapPageInHyperSpace(PsGetCurrentProcess(), Hyperspace, OldIrql);
317
318 DPRINT("MiWriteBackPage(%wZ,%08x%08x,%s:%d)\n",
319 &FileObject->FileName,
320 FileOffset->u.HighPart,
321 FileOffset->u.LowPart,
322 File,
323 Line);
324
325 Status = MiSimpleWrite(FileObject,
326 FileOffset,
327 PageBuffer,
328 Length,
329 &Iosb);
330
331 ExFreePool(PageBuffer);
332
333 if (!NT_SUCCESS(Status))
334 {
335 DPRINT1("MiSimpleWrite failed (%x)\n", Status);
336 }
337
338 return Status;
339 }