Reactos
at master 338 lines 9.9 kB view raw
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