[NTOSKRNL] Add a raw implementation of !irpfind in kdbg
[reactos.git] / 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/cache/section/io.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 %ul\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 /* When "ReadStatus->Information > 0" is false and "ReadStatus->Status == STATUS_END_OF_FILE" is true
191 * it means that read pointer is out of file, so we must fail */
192 Status = ReadStatus->Status == STATUS_END_OF_FILE && ReadStatus->Information > 0 ? STATUS_SUCCESS : ReadStatus->Status;
193 return Status;
194 }
195
196 /*
197
198 Convenience function for writing from kernel space. This issues a paging
199 write in all cases.
200
201 */
202
203 NTSTATUS
204 NTAPI
205 _MiSimpleWrite(PFILE_OBJECT FileObject,
206 PLARGE_INTEGER FileOffset,
207 PVOID Buffer,
208 ULONG Length,
209 PIO_STATUS_BLOCK ReadStatus,
210 const char *File,
211 int Line)
212 {
213 NTSTATUS Status;
214 PIRP Irp = NULL;
215 KEVENT ReadWait;
216 PDEVICE_OBJECT DeviceObject;
217 PIO_STACK_LOCATION IrpSp;
218
219 ASSERT(FileObject);
220 ASSERT(FileOffset);
221 ASSERT(Buffer);
222 ASSERT(ReadStatus);
223
224 DeviceObject = MmGetDeviceObjectForFile(FileObject);
225 ASSERT(DeviceObject);
226
227 DPRINT("PAGING WRITE: FileObject %p <%wZ> Offset 0x%I64x Length %lu (%s:%d)\n",
228 FileObject,
229 &FileObject->FileName,
230 FileOffset->QuadPart,
231 Length,
232 File,
233 Line);
234
235 KeInitializeEvent(&ReadWait, NotificationEvent, FALSE);
236
237 Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE,
238 DeviceObject,
239 Buffer,
240 Length,
241 FileOffset,
242 ReadStatus);
243
244 if (!Irp)
245 {
246 return STATUS_NO_MEMORY;
247 }
248
249 Irp->Flags = IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_API;
250
251 Irp->UserEvent = &ReadWait;
252 Irp->Tail.Overlay.OriginalFileObject = FileObject;
253 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
254 IrpSp = IoGetNextIrpStackLocation(Irp);
255 IrpSp->Control |= SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
256 IrpSp->FileObject = FileObject;
257 IrpSp->CompletionRoutine = MiSimpleReadComplete;
258
259 DPRINT("Call Driver\n");
260 Status = IoCallDriver(DeviceObject, Irp);
261 DPRINT("Status %x\n", Status);
262
263 if (Status == STATUS_PENDING)
264 {
265 DPRINT("KeWaitForSingleObject(&ReadWait)\n");
266 if (!NT_SUCCESS(KeWaitForSingleObject(&ReadWait,
267 Suspended,
268 KernelMode,
269 FALSE,
270 NULL)))
271 {
272 DPRINT1("Warning: Failed to wait for synchronous IRP\n");
273 ASSERT(FALSE);
274 return Status;
275 }
276 }
277
278 DPRINT("Paging IO Done: %08x\n", ReadStatus->Status);
279 return ReadStatus->Status;
280 }
281
282 extern KEVENT MpwThreadEvent;
283 FAST_MUTEX MiWriteMutex;
284
285 /*
286
287 Function which uses MiSimpleWrite to write back a single page to a file.
288 The page in question does not need to be mapped. This function could be
289 made a bit more efficient by avoiding the copy and making a system space
290 mdl.
291
292 */
293
294 NTSTATUS
295 NTAPI
296 _MiWriteBackPage(PFILE_OBJECT FileObject,
297 PLARGE_INTEGER FileOffset,
298 ULONG Length,
299 PFN_NUMBER Page,
300 const char *File,
301 int Line)
302 {
303 NTSTATUS Status;
304 PVOID Hyperspace;
305 IO_STATUS_BLOCK Iosb;
306 KIRQL OldIrql;
307 PVOID PageBuffer = ExAllocatePool(NonPagedPool, PAGE_SIZE);
308
309 if (!PageBuffer) return STATUS_NO_MEMORY;
310
311 Hyperspace = MiMapPageInHyperSpace(PsGetCurrentProcess(), Page, &OldIrql);
312 if (!Hyperspace)
313 {
314 ExFreePool(PageBuffer);
315 return STATUS_NO_MEMORY;
316 }
317 RtlCopyMemory(PageBuffer, Hyperspace, PAGE_SIZE);
318 MiUnmapPageInHyperSpace(PsGetCurrentProcess(), Hyperspace, OldIrql);
319
320 DPRINT("MiWriteBackPage(%wZ,%08x%08x,%s:%d)\n",
321 &FileObject->FileName,
322 FileOffset->u.HighPart,
323 FileOffset->u.LowPart,
324 File,
325 Line);
326
327 Status = MiSimpleWrite(FileObject,
328 FileOffset,
329 PageBuffer,
330 Length,
331 &Iosb);
332
333 ExFreePool(PageBuffer);
334
335 if (!NT_SUCCESS(Status))
336 {
337 DPRINT1("MiSimpleWrite failed (%x)\n", Status);
338 }
339
340 return Status;
341 }