1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/cc/fs.c 5 * PURPOSE: Implements cache managers functions useful for File Systems 6 * 7 * PROGRAMMERS: Alex Ionescu 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include <ntoskrnl.h> 13 14 #define NDEBUG 15 #include <debug.h> 16 17 /* FUNCTIONS *****************************************************************/ 18 19 /* 20 * @unimplemented 21 */ 22 LARGE_INTEGER 23 NTAPI 24 CcGetDirtyPages ( 25 IN PVOID LogHandle, 26 IN PDIRTY_PAGE_ROUTINE DirtyPageRoutine, 27 IN PVOID Context1, 28 IN PVOID Context2) 29 { 30 LARGE_INTEGER i; 31 32 CCTRACE(CC_API_DEBUG, "LogHandle=%p DirtyPageRoutine=%p Context1=%p Context2=%p\n", 33 LogHandle, DirtyPageRoutine, Context1, Context2); 34 35 UNIMPLEMENTED; 36 i.QuadPart = 0; 37 return i; 38 } 39 40 /* 41 * @implemented 42 */ 43 PFILE_OBJECT 44 NTAPI 45 CcGetFileObjectFromBcb ( 46 IN PVOID Bcb) 47 { 48 PINTERNAL_BCB iBcb = CONTAINING_RECORD(Bcb, INTERNAL_BCB, PFCB); 49 50 CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb); 51 52 return iBcb->Vacb->SharedCacheMap->FileObject; 53 } 54 55 /* 56 * @unimplemented 57 */ 58 LARGE_INTEGER 59 NTAPI 60 CcGetLsnForFileObject ( 61 IN PFILE_OBJECT FileObject, 62 OUT PLARGE_INTEGER OldestLsn OPTIONAL) 63 { 64 LARGE_INTEGER i; 65 66 CCTRACE(CC_API_DEBUG, "FileObject=%p\n", FileObject); 67 68 UNIMPLEMENTED; 69 i.QuadPart = 0; 70 return i; 71 } 72 73 /* 74 * @unimplemented 75 */ 76 VOID 77 NTAPI 78 CcInitializeCacheMap ( 79 IN PFILE_OBJECT FileObject, 80 IN PCC_FILE_SIZES FileSizes, 81 IN BOOLEAN PinAccess, 82 IN PCACHE_MANAGER_CALLBACKS CallBacks, 83 IN PVOID LazyWriterContext) 84 { 85 NTSTATUS Status; 86 87 ASSERT(FileObject); 88 ASSERT(FileSizes); 89 90 CCTRACE(CC_API_DEBUG, "FileObject=%p FileSizes=%p PinAccess=%d CallBacks=%p LazyWriterContext=%p\n", 91 FileObject, FileSizes, PinAccess, CallBacks, LazyWriterContext); 92 93 /* Call old ROS cache init function */ 94 Status = CcRosInitializeFileCache(FileObject, 95 FileSizes, 96 PinAccess, 97 CallBacks, 98 LazyWriterContext); 99 if (!NT_SUCCESS(Status)) 100 ExRaiseStatus(Status); 101 } 102 103 /* 104 * @implemented 105 */ 106 BOOLEAN 107 NTAPI 108 CcIsThereDirtyData ( 109 IN PVPB Vpb) 110 { 111 PROS_VACB Vacb; 112 PLIST_ENTRY Entry; 113 KIRQL oldIrql; 114 /* Assume no dirty data */ 115 BOOLEAN Dirty = FALSE; 116 117 CCTRACE(CC_API_DEBUG, "Vpb=%p\n", Vpb); 118 119 oldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); 120 121 /* Browse dirty VACBs */ 122 for (Entry = DirtyVacbListHead.Flink; Entry != &DirtyVacbListHead; Entry = Entry->Flink) 123 { 124 Vacb = CONTAINING_RECORD(Entry, ROS_VACB, DirtyVacbListEntry); 125 /* Look for these associated with our volume */ 126 if (Vacb->SharedCacheMap->FileObject->Vpb != Vpb) 127 { 128 continue; 129 } 130 131 /* From now on, we are associated with our VPB */ 132 133 /* Temporary files are not counted as dirty */ 134 if (BooleanFlagOn(Vacb->SharedCacheMap->FileObject->Flags, FO_TEMPORARY_FILE)) 135 { 136 continue; 137 } 138 139 /* A single dirty VACB is enough to have dirty data */ 140 if (Vacb->Dirty) 141 { 142 Dirty = TRUE; 143 break; 144 } 145 } 146 147 KeReleaseQueuedSpinLock(LockQueueMasterLock, oldIrql); 148 149 return Dirty; 150 } 151 152 /* 153 * @unimplemented 154 */ 155 BOOLEAN 156 NTAPI 157 CcPurgeCacheSection ( 158 IN PSECTION_OBJECT_POINTERS SectionObjectPointer, 159 IN PLARGE_INTEGER FileOffset OPTIONAL, 160 IN ULONG Length, 161 IN BOOLEAN UninitializeCacheMaps) 162 { 163 PROS_SHARED_CACHE_MAP SharedCacheMap; 164 PPRIVATE_CACHE_MAP PrivateCacheMap; 165 LONGLONG StartOffset; 166 LONGLONG EndOffset; 167 LIST_ENTRY FreeList; 168 KIRQL OldIrql; 169 PLIST_ENTRY ListEntry; 170 PROS_VACB Vacb; 171 LONGLONG ViewEnd; 172 BOOLEAN Success; 173 174 CCTRACE(CC_API_DEBUG, "SectionObjectPointer=%p\n FileOffset=%p Length=%lu UninitializeCacheMaps=%d", 175 SectionObjectPointer, FileOffset, Length, UninitializeCacheMaps); 176 177 /* Obtain the shared cache from the section */ 178 SharedCacheMap = SectionObjectPointer->SharedCacheMap; 179 if (!SharedCacheMap) 180 { 181 Success = TRUE; 182 goto purgeMm; 183 } 184 185 if (UninitializeCacheMaps) 186 { 187 /* 188 * We have gotten the acknowledgement that 189 * the caller wants to unintialize the private 190 * cache maps so let's do this. Since we already 191 * have the shared cache map from above, iterate 192 * over that cache's private lists. 193 */ 194 while (!IsListEmpty(&SharedCacheMap->PrivateList)) 195 { 196 /* 197 * This list is not empty, grab the 198 * private cache map. 199 */ 200 PrivateCacheMap = CONTAINING_RECORD(SharedCacheMap->PrivateList.Flink, PRIVATE_CACHE_MAP, PrivateLinks); 201 202 /* Unintialize the private cache now */ 203 CcUninitializeCacheMap(PrivateCacheMap->FileObject, NULL, NULL); 204 } 205 } 206 207 StartOffset = FileOffset != NULL ? FileOffset->QuadPart : 0; 208 if (Length == 0 || FileOffset == NULL) 209 { 210 EndOffset = MAXLONGLONG; 211 } 212 else 213 { 214 EndOffset = StartOffset + Length; 215 ASSERT(EndOffset > StartOffset); 216 } 217 218 InitializeListHead(&FreeList); 219 220 /* Assume success */ 221 Success = TRUE; 222 223 OldIrql = KeAcquireQueuedSpinLock(LockQueueMasterLock); 224 KeAcquireSpinLockAtDpcLevel(&SharedCacheMap->CacheMapLock); 225 ListEntry = SharedCacheMap->CacheMapVacbListHead.Flink; 226 while (ListEntry != &SharedCacheMap->CacheMapVacbListHead) 227 { 228 ULONG Refs; 229 230 Vacb = CONTAINING_RECORD(ListEntry, ROS_VACB, CacheMapVacbListEntry); 231 ListEntry = ListEntry->Flink; 232 233 /* Skip VACBs outside the range, or only partially in range */ 234 if (Vacb->FileOffset.QuadPart < StartOffset) 235 { 236 continue; 237 } 238 ViewEnd = min(Vacb->FileOffset.QuadPart + VACB_MAPPING_GRANULARITY, 239 SharedCacheMap->SectionSize.QuadPart); 240 if (ViewEnd >= EndOffset) 241 { 242 break; 243 } 244 245 /* Still in use, it cannot be purged, fail 246 * Allow one ref: VACB is supposed to be always 1-referenced 247 */ 248 Refs = CcRosVacbGetRefCount(Vacb); 249 if ((Refs > 1 && !Vacb->Dirty) || 250 (Refs > 2 && Vacb->Dirty)) 251 { 252 Success = FALSE; 253 break; 254 } 255 256 /* This VACB is in range, so unlink it and mark for free */ 257 ASSERT(Refs == 1 || Vacb->Dirty); 258 RemoveEntryList(&Vacb->VacbLruListEntry); 259 InitializeListHead(&Vacb->VacbLruListEntry); 260 if (Vacb->Dirty) 261 { 262 CcRosUnmarkDirtyVacb(Vacb, FALSE); 263 } 264 RemoveEntryList(&Vacb->CacheMapVacbListEntry); 265 InsertHeadList(&FreeList, &Vacb->CacheMapVacbListEntry); 266 } 267 KeReleaseSpinLockFromDpcLevel(&SharedCacheMap->CacheMapLock); 268 KeReleaseQueuedSpinLock(LockQueueMasterLock, OldIrql); 269 270 while (!IsListEmpty(&FreeList)) 271 { 272 ULONG Refs; 273 274 Vacb = CONTAINING_RECORD(RemoveHeadList(&FreeList), 275 ROS_VACB, 276 CacheMapVacbListEntry); 277 InitializeListHead(&Vacb->CacheMapVacbListEntry); 278 Refs = CcRosVacbDecRefCount(Vacb); 279 ASSERT(Refs == 0); 280 } 281 282 /* Now make sure that Mm doesn't hold some pages here. */ 283 purgeMm: 284 if (Success) 285 Success = MmPurgeSegment(SectionObjectPointer, FileOffset, Length); 286 287 return Success; 288 } 289 290 291 /* 292 * @implemented 293 */ 294 VOID NTAPI 295 CcSetFileSizes ( 296 IN PFILE_OBJECT FileObject, 297 IN PCC_FILE_SIZES FileSizes) 298 { 299 KIRQL OldIrql; 300 PROS_SHARED_CACHE_MAP SharedCacheMap; 301 LARGE_INTEGER OldSectionSize; 302 303 CCTRACE(CC_API_DEBUG, "FileObject=%p FileSizes=%p\n", 304 FileObject, FileSizes); 305 306 DPRINT("CcSetFileSizes(FileObject 0x%p, FileSizes 0x%p)\n", 307 FileObject, FileSizes); 308 DPRINT("AllocationSize %I64d, FileSize %I64d, ValidDataLength %I64d\n", 309 FileSizes->AllocationSize.QuadPart, 310 FileSizes->FileSize.QuadPart, 311 FileSizes->ValidDataLength.QuadPart); 312 313 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 314 315 /* 316 * It is valid to call this function on file objects that weren't 317 * initialized for caching. In this case it's simple no-op. 318 */ 319 if (SharedCacheMap == NULL) 320 return; 321 322 /* Update the relevant fields */ 323 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql); 324 OldSectionSize = SharedCacheMap->SectionSize; 325 SharedCacheMap->SectionSize = FileSizes->AllocationSize; 326 SharedCacheMap->FileSize = FileSizes->FileSize; 327 SharedCacheMap->ValidDataLength = FileSizes->ValidDataLength; 328 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); 329 330 if (FileSizes->AllocationSize.QuadPart < OldSectionSize.QuadPart) 331 { 332 CcPurgeCacheSection(FileObject->SectionObjectPointer, 333 &FileSizes->AllocationSize, 334 0, 335 FALSE); 336 } 337 else 338 { 339 /* Extend our section object */ 340 MmExtendSection(SharedCacheMap->Section, &SharedCacheMap->SectionSize); 341 } 342 } 343 344 /* 345 * @unimplemented 346 */ 347 VOID 348 NTAPI 349 CcSetLogHandleForFile ( 350 IN PFILE_OBJECT FileObject, 351 IN PVOID LogHandle, 352 IN PFLUSH_TO_LSN FlushToLsnRoutine) 353 { 354 CCTRACE(CC_API_DEBUG, "FileObject=%p LogHandle=%p FlushToLsnRoutine=%p\n", 355 FileObject, LogHandle, FlushToLsnRoutine); 356 357 UNIMPLEMENTED; 358 } 359 360 /* 361 * @unimplemented 362 */ 363 BOOLEAN 364 NTAPI 365 CcUninitializeCacheMap ( 366 IN PFILE_OBJECT FileObject, 367 IN PLARGE_INTEGER TruncateSize OPTIONAL, 368 IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL) 369 { 370 NTSTATUS Status; 371 PROS_SHARED_CACHE_MAP SharedCacheMap; 372 KIRQL OldIrql; 373 374 CCTRACE(CC_API_DEBUG, "FileObject=%p TruncateSize=%p UninitializeCompleteEvent=%p\n", 375 FileObject, TruncateSize, UninitializeCompleteEvent); 376 377 if (TruncateSize != NULL && 378 FileObject->SectionObjectPointer->SharedCacheMap != NULL) 379 { 380 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 381 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql); 382 if (SharedCacheMap->FileSize.QuadPart > TruncateSize->QuadPart) 383 { 384 SharedCacheMap->FileSize = *TruncateSize; 385 } 386 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); 387 CcPurgeCacheSection(FileObject->SectionObjectPointer, 388 TruncateSize, 389 0, 390 FALSE); 391 } 392 393 Status = CcRosReleaseFileCache(FileObject); 394 if (UninitializeCompleteEvent) 395 { 396 KeSetEvent(&UninitializeCompleteEvent->Event, IO_NO_INCREMENT, FALSE); 397 } 398 return NT_SUCCESS(Status); 399 } 400 401 BOOLEAN 402 NTAPI 403 CcGetFileSizes ( 404 IN PFILE_OBJECT FileObject, 405 IN PCC_FILE_SIZES FileSizes) 406 { 407 PROS_SHARED_CACHE_MAP SharedCacheMap; 408 409 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 410 411 if (!SharedCacheMap) 412 return FALSE; 413 414 FileSizes->AllocationSize = SharedCacheMap->SectionSize; 415 FileSizes->FileSize = FileSizes->ValidDataLength = SharedCacheMap->FileSize; 416 return TRUE; 417 } 418