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