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