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 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS *****************************************************************/ 17 18 extern KGUARDED_MUTEX ViewLock; 19 20 NTSTATUS CcRosInternalFreeVacb(PROS_VACB Vacb); 21 22 /* FUNCTIONS *****************************************************************/ 23 24 /* 25 * @unimplemented 26 */ 27 LARGE_INTEGER 28 NTAPI 29 CcGetDirtyPages ( 30 IN PVOID LogHandle, 31 IN PDIRTY_PAGE_ROUTINE DirtyPageRoutine, 32 IN PVOID Context1, 33 IN PVOID Context2) 34 { 35 LARGE_INTEGER i; 36 37 CCTRACE(CC_API_DEBUG, "LogHandle=%p DirtyPageRoutine=%p Context1=%p Context2=%p\n", 38 LogHandle, DirtyPageRoutine, Context1, Context2); 39 40 UNIMPLEMENTED; 41 i.QuadPart = 0; 42 return i; 43 } 44 45 /* 46 * @implemented 47 */ 48 PFILE_OBJECT 49 NTAPI 50 CcGetFileObjectFromBcb ( 51 IN PVOID Bcb) 52 { 53 PINTERNAL_BCB iBcb = (PINTERNAL_BCB)Bcb; 54 55 CCTRACE(CC_API_DEBUG, "Bcb=%p\n", Bcb); 56 57 return iBcb->Vacb->SharedCacheMap->FileObject; 58 } 59 60 /* 61 * @unimplemented 62 */ 63 LARGE_INTEGER 64 NTAPI 65 CcGetLsnForFileObject ( 66 IN PFILE_OBJECT FileObject, 67 OUT PLARGE_INTEGER OldestLsn OPTIONAL) 68 { 69 LARGE_INTEGER i; 70 71 CCTRACE(CC_API_DEBUG, "FileObject=%p\n", FileObject); 72 73 UNIMPLEMENTED; 74 i.QuadPart = 0; 75 return i; 76 } 77 78 /* 79 * @unimplemented 80 */ 81 VOID 82 NTAPI 83 CcInitializeCacheMap ( 84 IN PFILE_OBJECT FileObject, 85 IN PCC_FILE_SIZES FileSizes, 86 IN BOOLEAN PinAccess, 87 IN PCACHE_MANAGER_CALLBACKS CallBacks, 88 IN PVOID LazyWriterContext) 89 { 90 NTSTATUS Status; 91 92 ASSERT(FileObject); 93 ASSERT(FileSizes); 94 95 CCTRACE(CC_API_DEBUG, "FileObject=%p FileSizes=%p PinAccess=%d CallBacks=%p LazyWriterContext=%p\n", 96 FileObject, FileSizes, PinAccess, CallBacks, LazyWriterContext); 97 98 /* Call old ROS cache init function */ 99 Status = CcRosInitializeFileCache(FileObject, 100 FileSizes, 101 PinAccess, 102 CallBacks, 103 LazyWriterContext); 104 if (!NT_SUCCESS(Status)) 105 ExRaiseStatus(Status); 106 } 107 108 /* 109 * @implemented 110 */ 111 BOOLEAN 112 NTAPI 113 CcIsThereDirtyData ( 114 IN PVPB Vpb) 115 { 116 PROS_VACB Vacb; 117 PLIST_ENTRY Entry; 118 /* Assume no dirty data */ 119 BOOLEAN Dirty = FALSE; 120 121 CCTRACE(CC_API_DEBUG, "Vpb=%p\n", Vpb); 122 123 KeAcquireGuardedMutex(&ViewLock); 124 125 /* Browse dirty VACBs */ 126 for (Entry = DirtyVacbListHead.Flink; Entry != &DirtyVacbListHead; Entry = Entry->Flink) 127 { 128 Vacb = CONTAINING_RECORD(Entry, ROS_VACB, DirtyVacbListEntry); 129 /* Look for these associated with our volume */ 130 if (Vacb->SharedCacheMap->FileObject->Vpb != Vpb) 131 { 132 continue; 133 } 134 135 /* From now on, we are associated with our VPB */ 136 137 /* Temporary files are not counted as dirty */ 138 if (BooleanFlagOn(Vacb->SharedCacheMap->FileObject->Flags, FO_TEMPORARY_FILE)) 139 { 140 continue; 141 } 142 143 /* A single dirty VACB is enough to have dirty data */ 144 if (Vacb->Dirty) 145 { 146 Dirty = TRUE; 147 break; 148 } 149 } 150 151 KeReleaseGuardedMutex(&ViewLock); 152 153 return Dirty; 154 } 155 156 /* 157 * @unimplemented 158 */ 159 BOOLEAN 160 NTAPI 161 CcPurgeCacheSection ( 162 IN PSECTION_OBJECT_POINTERS SectionObjectPointer, 163 IN PLARGE_INTEGER FileOffset OPTIONAL, 164 IN ULONG Length, 165 IN BOOLEAN UninitializeCacheMaps) 166 { 167 PROS_SHARED_CACHE_MAP SharedCacheMap; 168 LONGLONG StartOffset; 169 LONGLONG EndOffset; 170 LIST_ENTRY FreeList; 171 KIRQL OldIrql; 172 PLIST_ENTRY ListEntry; 173 PROS_VACB Vacb; 174 LONGLONG ViewEnd; 175 BOOLEAN Success; 176 177 CCTRACE(CC_API_DEBUG, "SectionObjectPointer=%p\n FileOffset=%p Length=%lu UninitializeCacheMaps=%d", 178 SectionObjectPointer, FileOffset, Length, UninitializeCacheMaps); 179 180 if (UninitializeCacheMaps) 181 { 182 DPRINT1("FIXME: CcPurgeCacheSection not uninitializing private cache maps\n"); 183 } 184 185 SharedCacheMap = SectionObjectPointer->SharedCacheMap; 186 if (!SharedCacheMap) 187 return FALSE; 188 189 StartOffset = FileOffset != NULL ? FileOffset->QuadPart : 0; 190 if (Length == 0 || FileOffset == NULL) 191 { 192 EndOffset = MAXLONGLONG; 193 } 194 else 195 { 196 EndOffset = StartOffset + Length; 197 ASSERT(EndOffset > StartOffset); 198 } 199 200 InitializeListHead(&FreeList); 201 202 /* Assume success */ 203 Success = TRUE; 204 205 KeAcquireGuardedMutex(&ViewLock); 206 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql); 207 ListEntry = SharedCacheMap->CacheMapVacbListHead.Flink; 208 while (ListEntry != &SharedCacheMap->CacheMapVacbListHead) 209 { 210 Vacb = CONTAINING_RECORD(ListEntry, ROS_VACB, CacheMapVacbListEntry); 211 ListEntry = ListEntry->Flink; 212 213 /* Skip VACBs outside the range, or only partially in range */ 214 if (Vacb->FileOffset.QuadPart < StartOffset) 215 { 216 continue; 217 } 218 ViewEnd = min(Vacb->FileOffset.QuadPart + VACB_MAPPING_GRANULARITY, 219 SharedCacheMap->SectionSize.QuadPart); 220 if (ViewEnd >= EndOffset) 221 { 222 break; 223 } 224 225 /* Still in use, it cannot be purged, fail */ 226 if (Vacb->ReferenceCount != 0 && !Vacb->Dirty) 227 { 228 Success = FALSE; 229 break; 230 } 231 232 /* This VACB is in range, so unlink it and mark for free */ 233 RemoveEntryList(&Vacb->VacbLruListEntry); 234 if (Vacb->Dirty) 235 { 236 RemoveEntryList(&Vacb->DirtyVacbListEntry); 237 CcTotalDirtyPages -= VACB_MAPPING_GRANULARITY / PAGE_SIZE; 238 } 239 RemoveEntryList(&Vacb->CacheMapVacbListEntry); 240 InsertHeadList(&FreeList, &Vacb->CacheMapVacbListEntry); 241 } 242 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); 243 KeReleaseGuardedMutex(&ViewLock); 244 245 while (!IsListEmpty(&FreeList)) 246 { 247 Vacb = CONTAINING_RECORD(RemoveHeadList(&FreeList), 248 ROS_VACB, 249 CacheMapVacbListEntry); 250 CcRosInternalFreeVacb(Vacb); 251 } 252 253 return Success; 254 } 255 256 257 /* 258 * @implemented 259 */ 260 VOID NTAPI 261 CcSetFileSizes ( 262 IN PFILE_OBJECT FileObject, 263 IN PCC_FILE_SIZES FileSizes) 264 { 265 KIRQL oldirql; 266 PROS_SHARED_CACHE_MAP SharedCacheMap; 267 268 CCTRACE(CC_API_DEBUG, "FileObject=%p FileSizes=%p\n", 269 FileObject, FileSizes); 270 271 DPRINT("CcSetFileSizes(FileObject 0x%p, FileSizes 0x%p)\n", 272 FileObject, FileSizes); 273 DPRINT("AllocationSize %I64d, FileSize %I64d, ValidDataLength %I64d\n", 274 FileSizes->AllocationSize.QuadPart, 275 FileSizes->FileSize.QuadPart, 276 FileSizes->ValidDataLength.QuadPart); 277 278 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 279 280 /* 281 * It is valid to call this function on file objects that weren't 282 * initialized for caching. In this case it's simple no-op. 283 */ 284 if (SharedCacheMap == NULL) 285 return; 286 287 if (FileSizes->AllocationSize.QuadPart < SharedCacheMap->SectionSize.QuadPart) 288 { 289 CcPurgeCacheSection(FileObject->SectionObjectPointer, 290 &FileSizes->AllocationSize, 291 0, 292 FALSE); 293 } 294 295 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql); 296 SharedCacheMap->SectionSize = FileSizes->AllocationSize; 297 SharedCacheMap->FileSize = FileSizes->FileSize; 298 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql); 299 } 300 301 /* 302 * @unimplemented 303 */ 304 VOID 305 NTAPI 306 CcSetLogHandleForFile ( 307 IN PFILE_OBJECT FileObject, 308 IN PVOID LogHandle, 309 IN PFLUSH_TO_LSN FlushToLsnRoutine) 310 { 311 CCTRACE(CC_API_DEBUG, "FileObject=%p LogHandle=%p FlushToLsnRoutine=%p\n", 312 FileObject, LogHandle, FlushToLsnRoutine); 313 314 UNIMPLEMENTED; 315 } 316 317 /* 318 * @unimplemented 319 */ 320 BOOLEAN 321 NTAPI 322 CcUninitializeCacheMap ( 323 IN PFILE_OBJECT FileObject, 324 IN PLARGE_INTEGER TruncateSize OPTIONAL, 325 IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL) 326 { 327 NTSTATUS Status; 328 PROS_SHARED_CACHE_MAP SharedCacheMap; 329 KIRQL OldIrql; 330 331 CCTRACE(CC_API_DEBUG, "FileObject=%p TruncateSize=%p UninitializeCompleteEvent=%p\n", 332 FileObject, TruncateSize, UninitializeCompleteEvent); 333 334 if (TruncateSize != NULL && 335 FileObject->SectionObjectPointer->SharedCacheMap != NULL) 336 { 337 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 338 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql); 339 if (SharedCacheMap->FileSize.QuadPart > TruncateSize->QuadPart) 340 { 341 SharedCacheMap->FileSize = *TruncateSize; 342 } 343 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); 344 CcPurgeCacheSection(FileObject->SectionObjectPointer, 345 TruncateSize, 346 0, 347 FALSE); 348 } 349 350 Status = CcRosReleaseFileCache(FileObject); 351 if (UninitializeCompleteEvent) 352 { 353 KeSetEvent(&UninitializeCompleteEvent->Event, IO_NO_INCREMENT, FALSE); 354 } 355 return NT_SUCCESS(Status); 356 } 357 358 BOOLEAN 359 NTAPI 360 CcGetFileSizes ( 361 IN PFILE_OBJECT FileObject, 362 IN PCC_FILE_SIZES FileSizes) 363 { 364 PROS_SHARED_CACHE_MAP SharedCacheMap; 365 366 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 367 368 if (!SharedCacheMap) 369 return FALSE; 370 371 FileSizes->AllocationSize = SharedCacheMap->SectionSize; 372 FileSizes->FileSize = FileSizes->ValidDataLength = SharedCacheMap->FileSize; 373 return TRUE; 374 } 375