1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/cc/pin.c 5 * PURPOSE: Implements cache managers pinning interface 6 * 7 * PROGRAMMERS: ? 8 Pierre Schweitzer (pierre@reactos.org) 9 */ 10 11 /* INCLUDES ******************************************************************/ 12 13 #include <ntoskrnl.h> 14 #define NDEBUG 15 #include <debug.h> 16 17 /* GLOBALS *******************************************************************/ 18 19 extern NPAGED_LOOKASIDE_LIST iBcbLookasideList; 20 21 /* Counters: 22 * - Number of calls to CcMapData that could wait 23 * - Number of calls to CcMapData that couldn't wait 24 * - Number of calls to CcPinRead that could wait 25 * - Number of calls to CcPinRead that couldn't wait 26 */ 27 ULONG CcMapDataWait = 0; 28 ULONG CcMapDataNoWait = 0; 29 ULONG CcPinReadWait = 0; 30 ULONG CcPinReadNoWait = 0; 31 32 /* FUNCTIONS *****************************************************************/ 33 34 static 35 BOOLEAN 36 NTAPI 37 CcpMapData( 38 IN PFILE_OBJECT FileObject, 39 IN PLARGE_INTEGER FileOffset, 40 IN ULONG Length, 41 IN ULONG Flags, 42 OUT PVOID *pBcb, 43 OUT PVOID *pBuffer) 44 { 45 LONGLONG ReadOffset; 46 BOOLEAN Valid; 47 PROS_SHARED_CACHE_MAP SharedCacheMap; 48 PROS_VACB Vacb; 49 NTSTATUS Status; 50 PINTERNAL_BCB iBcb; 51 LONGLONG ROffset; 52 KIRQL OldIrql; 53 54 ReadOffset = FileOffset->QuadPart; 55 56 ASSERT(FileObject); 57 ASSERT(FileObject->SectionObjectPointer); 58 ASSERT(FileObject->SectionObjectPointer->SharedCacheMap); 59 60 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 61 ASSERT(SharedCacheMap); 62 63 DPRINT("SectionSize %I64x, FileSize %I64x\n", 64 SharedCacheMap->SectionSize.QuadPart, 65 SharedCacheMap->FileSize.QuadPart); 66 67 if (ReadOffset % VACB_MAPPING_GRANULARITY + Length > VACB_MAPPING_GRANULARITY) 68 { 69 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", 70 FileObject, FileOffset, Length, Flags); 71 return FALSE; 72 } 73 74 if (!BooleanFlagOn(Flags, MAP_NO_READ)) 75 { 76 static int Warned = 0; 77 78 SetFlag(Flags, MAP_NO_READ); 79 if (!Warned) 80 { 81 DPRINT1("Mapping/pinning with no read not implemented. Forcing read, might fail if wait not allowed\n"); 82 Warned++; 83 } 84 } 85 86 ROffset = ROUND_DOWN(ReadOffset, VACB_MAPPING_GRANULARITY); 87 Status = CcRosRequestVacb(SharedCacheMap, 88 ROffset, 89 pBuffer, 90 &Valid, 91 &Vacb); 92 if (!NT_SUCCESS(Status)) 93 { 94 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", 95 FileObject, FileOffset, Length, Flags); 96 ExRaiseStatus(Status); 97 return FALSE; 98 } 99 100 if (!Valid && BooleanFlagOn(Flags, MAP_NO_READ)) 101 { 102 if (!BooleanFlagOn(Flags, MAP_WAIT)) 103 { 104 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); 105 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", 106 FileObject, FileOffset, Length, Flags); 107 return FALSE; 108 } 109 110 Status = CcReadVirtualAddress(Vacb); 111 if (!NT_SUCCESS(Status)) 112 { 113 CcRosReleaseVacb(SharedCacheMap, Vacb, FALSE, FALSE, FALSE); 114 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", 115 FileObject, FileOffset, Length, Flags); 116 ExRaiseStatus(Status); 117 return FALSE; 118 } 119 } 120 121 *pBuffer = (PUCHAR)*pBuffer + ReadOffset % VACB_MAPPING_GRANULARITY; 122 iBcb = ExAllocateFromNPagedLookasideList(&iBcbLookasideList); 123 if (iBcb == NULL) 124 { 125 CcRosReleaseVacb(SharedCacheMap, Vacb, TRUE, FALSE, FALSE); 126 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> FALSE\n", 127 FileObject, FileOffset, Length, Flags); 128 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 129 return FALSE; 130 } 131 132 RtlZeroMemory(iBcb, sizeof(*iBcb)); 133 iBcb->PFCB.NodeTypeCode = 0xDE45; /* Undocumented (CAPTIVE_PUBLIC_BCB_NODETYPECODE) */ 134 iBcb->PFCB.NodeByteSize = sizeof(PUBLIC_BCB); 135 iBcb->PFCB.MappedLength = Length; 136 iBcb->PFCB.MappedFileOffset = *FileOffset; 137 iBcb->Vacb = Vacb; 138 iBcb->Dirty = FALSE; 139 iBcb->Pinned = FALSE; 140 iBcb->RefCount = 1; 141 ExInitializeResourceLite(&iBcb->Lock); 142 *pBcb = (PVOID)iBcb; 143 144 KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql); 145 InsertTailList(&SharedCacheMap->BcbList, &iBcb->BcbEntry); 146 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); 147 148 return TRUE; 149 } 150 151 /* 152 * @implemented 153 */ 154 BOOLEAN 155 NTAPI 156 CcMapData ( 157 IN PFILE_OBJECT FileObject, 158 IN PLARGE_INTEGER FileOffset, 159 IN ULONG Length, 160 IN ULONG Flags, 161 OUT PVOID *pBcb, 162 OUT PVOID *pBuffer) 163 { 164 BOOLEAN Ret; 165 166 DPRINT("CcMapData(FileObject 0x%p, FileOffset %I64x, Length %lu, Flags 0x%lx," 167 " pBcb 0x%p, pBuffer 0x%p)\n", FileObject, FileOffset->QuadPart, 168 Length, Flags, pBcb, pBuffer); 169 170 if (Flags & MAP_WAIT) 171 { 172 ++CcMapDataWait; 173 } 174 else 175 { 176 ++CcMapDataNoWait; 177 } 178 179 Ret = CcpMapData(FileObject, FileOffset, Length, Flags, pBcb, pBuffer); 180 181 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx -> %d Bcb=%p\n", 182 FileObject, FileOffset, Length, Flags, Ret, *pBcb); 183 return Ret; 184 } 185 186 /* 187 * @unimplemented 188 */ 189 BOOLEAN 190 NTAPI 191 CcPinMappedData ( 192 IN PFILE_OBJECT FileObject, 193 IN PLARGE_INTEGER FileOffset, 194 IN ULONG Length, 195 IN ULONG Flags, 196 OUT PVOID * Bcb) 197 { 198 BOOLEAN Result; 199 PINTERNAL_BCB iBcb; 200 PROS_SHARED_CACHE_MAP SharedCacheMap; 201 202 CCTRACE(CC_API_DEBUG, "FileObject=%p FileOffset=%p Length=%lu Flags=0x%lx\n", 203 FileObject, FileOffset, Length, Flags); 204 205 ASSERT(FileObject); 206 ASSERT(FileObject->SectionObjectPointer); 207 ASSERT(FileObject->SectionObjectPointer->SharedCacheMap); 208 209 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 210 ASSERT(SharedCacheMap); 211 if (!SharedCacheMap->PinAccess) 212 { 213 DPRINT1("FIXME: Pinning a file with no pin access!\n"); 214 return FALSE; 215 } 216 217 iBcb = *Bcb; 218 ASSERT(iBcb->Pinned == FALSE); 219 220 iBcb->Pinned = TRUE; 221 iBcb->Vacb->PinCount++; 222 223 if (BooleanFlagOn(Flags, PIN_EXCLUSIVE)) 224 { 225 Result = ExAcquireResourceExclusiveLite(&iBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT)); 226 } 227 else 228 { 229 Result = ExAcquireSharedStarveExclusive(&iBcb->Lock, BooleanFlagOn(Flags, PIN_WAIT)); 230 } 231 232 if (!Result) 233 { 234 iBcb->Pinned = FALSE; 235 iBcb->Vacb->PinCount--; 236 } 237 238 return Result; 239 } 240 241 /* 242 * @unimplemented 243 */ 244 BOOLEAN 245 NTAPI 246 CcPinRead ( 247 IN PFILE_OBJECT FileObject, 248 IN PLARGE_INTEGER FileOffset, 249 IN ULONG Length, 250 IN ULONG Flags, 251 OUT PVOID * Bcb, 252 OUT PVOID * Buffer) 253 { 254 CCTRACE(CC_API_DEBUG, "FileOffset=%p FileOffset=%p Length=%lu Flags=0x%lx\n", 255 FileObject, FileOffset, Length, Flags); 256 257 if (Flags & PIN_WAIT) 258 { 259 ++CcPinReadWait; 260 } 261 else 262 { 263 ++CcPinReadNoWait; 264 } 265 266 /* Map first */ 267 if (!CcpMapData(FileObject, FileOffset, Length, Flags, Bcb, Buffer)) 268 { 269 return FALSE; 270 } 271 272 /* Pin then */ 273 if (!CcPinMappedData(FileObject, FileOffset, Length, Flags, Bcb)) 274 { 275 CcUnpinData(*Bcb); 276 return FALSE; 277 } 278 279 return TRUE; 280 } 281 282 /* 283 * @unimplemented 284 */ 285 BOOLEAN 286 NTAPI 287 CcPreparePinWrite ( 288 IN PFILE_OBJECT FileObject, 289 IN PLARGE_INTEGER FileOffset, 290 IN ULONG Length, 291 IN BOOLEAN Zero, 292 IN ULONG Flags, 293 OUT PVOID * Bcb, 294 OUT PVOID * Buffer) 295 { 296 CCTRACE(CC_API_DEBUG, "FileOffset=%p FileOffset=%p Length=%lu Zero=%d Flags=0x%lx\n", 297 FileObject, FileOffset, Length, Zero, Flags); 298 299 /* 300 * FIXME: This is function is similar to CcPinRead, but doesn't 301 * read the data if they're not present. Instead it should just 302 * prepare the VACBs and zero them out if Zero != FALSE. 303 * 304 * For now calling CcPinRead is better than returning error or 305 * just having UNIMPLEMENTED here. 306 */ 307 return CcPinRead(FileObject, FileOffset, Length, Flags, Bcb, Buffer); 308 } 309 310 /* 311 * @implemented 312 */ 313 VOID NTAPI 314 CcSetDirtyPinnedData ( 315 IN PVOID Bcb, 316 IN PLARGE_INTEGER Lsn) 317 { 318 PINTERNAL_BCB iBcb = Bcb; 319 320 CCTRACE(CC_API_DEBUG, "Bcb=%p Lsn=%p\n", 321 Bcb, Lsn); 322 323 iBcb->Dirty = TRUE; 324 if (!iBcb->Vacb->Dirty) 325 { 326 CcRosMarkDirtyVacb(iBcb->Vacb); 327 } 328 } 329 330 331 /* 332 * @implemented 333 */ 334 VOID NTAPI 335 CcUnpinData ( 336 IN PVOID Bcb) 337 { 338 CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb); 339 340 CcUnpinDataForThread(Bcb, (ERESOURCE_THREAD)PsGetCurrentThread()); 341 } 342 343 /* 344 * @unimplemented 345 */ 346 VOID 347 NTAPI 348 CcUnpinDataForThread ( 349 IN PVOID Bcb, 350 IN ERESOURCE_THREAD ResourceThreadId) 351 { 352 PINTERNAL_BCB iBcb = Bcb; 353 354 CCTRACE(CC_API_DEBUG, "Bcb=%p ResourceThreadId=%lu\n", Bcb, ResourceThreadId); 355 356 if (iBcb->Pinned) 357 { 358 ExReleaseResourceForThreadLite(&iBcb->Lock, ResourceThreadId); 359 iBcb->Pinned = FALSE; 360 iBcb->Vacb->PinCount--; 361 } 362 363 if (--iBcb->RefCount == 0) 364 { 365 KIRQL OldIrql; 366 PROS_SHARED_CACHE_MAP SharedCacheMap; 367 368 SharedCacheMap = iBcb->Vacb->SharedCacheMap; 369 CcRosReleaseVacb(SharedCacheMap, 370 iBcb->Vacb, 371 TRUE, 372 iBcb->Dirty, 373 FALSE); 374 375 KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql); 376 RemoveEntryList(&iBcb->BcbEntry); 377 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); 378 379 ExDeleteResourceLite(&iBcb->Lock); 380 ExFreeToNPagedLookasideList(&iBcbLookasideList, iBcb); 381 } 382 } 383 384 /* 385 * @implemented 386 */ 387 VOID 388 NTAPI 389 CcRepinBcb ( 390 IN PVOID Bcb) 391 { 392 PINTERNAL_BCB iBcb = Bcb; 393 394 CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb); 395 396 iBcb->RefCount++; 397 } 398 399 /* 400 * @unimplemented 401 */ 402 VOID 403 NTAPI 404 CcUnpinRepinnedBcb ( 405 IN PVOID Bcb, 406 IN BOOLEAN WriteThrough, 407 IN PIO_STATUS_BLOCK IoStatus) 408 { 409 PINTERNAL_BCB iBcb = Bcb; 410 KIRQL OldIrql; 411 PROS_SHARED_CACHE_MAP SharedCacheMap; 412 413 CCTRACE(CC_API_DEBUG, "Bcb=%p WriteThrough=%d\n", Bcb, WriteThrough); 414 415 IoStatus->Status = STATUS_SUCCESS; 416 if (--iBcb->RefCount == 0) 417 { 418 IoStatus->Information = 0; 419 if (WriteThrough) 420 { 421 if (iBcb->Vacb->Dirty) 422 { 423 IoStatus->Status = CcRosFlushVacb(iBcb->Vacb); 424 } 425 else 426 { 427 IoStatus->Status = STATUS_SUCCESS; 428 } 429 } 430 else 431 { 432 IoStatus->Status = STATUS_SUCCESS; 433 } 434 435 if (iBcb->Pinned) 436 { 437 ExReleaseResourceLite(&iBcb->Lock); 438 iBcb->Pinned = FALSE; 439 iBcb->Vacb->PinCount--; 440 ASSERT(iBcb->Vacb->PinCount == 0); 441 } 442 443 SharedCacheMap = iBcb->Vacb->SharedCacheMap; 444 CcRosReleaseVacb(iBcb->Vacb->SharedCacheMap, 445 iBcb->Vacb, 446 TRUE, 447 iBcb->Dirty, 448 FALSE); 449 450 KeAcquireSpinLock(&SharedCacheMap->BcbSpinLock, &OldIrql); 451 RemoveEntryList(&iBcb->BcbEntry); 452 KeReleaseSpinLock(&SharedCacheMap->BcbSpinLock, OldIrql); 453 454 ExDeleteResourceLite(&iBcb->Lock); 455 ExFreeToNPagedLookasideList(&iBcbLookasideList, iBcb); 456 } 457 } 458