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 ULONG Refs; 211 212 Vacb = CONTAINING_RECORD(ListEntry, ROS_VACB, CacheMapVacbListEntry); 213 ListEntry = ListEntry->Flink; 214 215 /* Skip VACBs outside the range, or only partially in range */ 216 if (Vacb->FileOffset.QuadPart < StartOffset) 217 { 218 continue; 219 } 220 ViewEnd = min(Vacb->FileOffset.QuadPart + VACB_MAPPING_GRANULARITY, 221 SharedCacheMap->SectionSize.QuadPart); 222 if (ViewEnd >= EndOffset) 223 { 224 break; 225 } 226 227 /* Still in use, it cannot be purged, fail 228 * Allow one ref: VACB is supposed to be always 1-referenced 229 */ 230 Refs = CcRosVacbGetRefCount(Vacb); 231 if ((Refs > 1 && !Vacb->Dirty) || 232 (Refs > 2 && Vacb->Dirty)) 233 { 234 Success = FALSE; 235 break; 236 } 237 238 /* This VACB is in range, so unlink it and mark for free */ 239 ASSERT(Refs == 1 || Vacb->Dirty); 240 RemoveEntryList(&Vacb->VacbLruListEntry); 241 if (Vacb->Dirty) 242 { 243 CcRosUnmarkDirtyVacb(Vacb, FALSE); 244 } 245 RemoveEntryList(&Vacb->CacheMapVacbListEntry); 246 InsertHeadList(&FreeList, &Vacb->CacheMapVacbListEntry); 247 } 248 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); 249 KeReleaseGuardedMutex(&ViewLock); 250 251 while (!IsListEmpty(&FreeList)) 252 { 253 Vacb = CONTAINING_RECORD(RemoveHeadList(&FreeList), 254 ROS_VACB, 255 CacheMapVacbListEntry); 256 CcRosVacbDecRefCount(Vacb); 257 CcRosInternalFreeVacb(Vacb); 258 } 259 260 return Success; 261 } 262 263 264 /* 265 * @implemented 266 */ 267 VOID NTAPI 268 CcSetFileSizes ( 269 IN PFILE_OBJECT FileObject, 270 IN PCC_FILE_SIZES FileSizes) 271 { 272 KIRQL oldirql; 273 PROS_SHARED_CACHE_MAP SharedCacheMap; 274 275 CCTRACE(CC_API_DEBUG, "FileObject=%p FileSizes=%p\n", 276 FileObject, FileSizes); 277 278 DPRINT("CcSetFileSizes(FileObject 0x%p, FileSizes 0x%p)\n", 279 FileObject, FileSizes); 280 DPRINT("AllocationSize %I64d, FileSize %I64d, ValidDataLength %I64d\n", 281 FileSizes->AllocationSize.QuadPart, 282 FileSizes->FileSize.QuadPart, 283 FileSizes->ValidDataLength.QuadPart); 284 285 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 286 287 /* 288 * It is valid to call this function on file objects that weren't 289 * initialized for caching. In this case it's simple no-op. 290 */ 291 if (SharedCacheMap == NULL) 292 return; 293 294 if (FileSizes->AllocationSize.QuadPart < SharedCacheMap->SectionSize.QuadPart) 295 { 296 CcPurgeCacheSection(FileObject->SectionObjectPointer, 297 &FileSizes->AllocationSize, 298 0, 299 FALSE); 300 } 301 302 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &oldirql); 303 SharedCacheMap->SectionSize = FileSizes->AllocationSize; 304 SharedCacheMap->FileSize = FileSizes->FileSize; 305 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, oldirql); 306 } 307 308 /* 309 * @unimplemented 310 */ 311 VOID 312 NTAPI 313 CcSetLogHandleForFile ( 314 IN PFILE_OBJECT FileObject, 315 IN PVOID LogHandle, 316 IN PFLUSH_TO_LSN FlushToLsnRoutine) 317 { 318 CCTRACE(CC_API_DEBUG, "FileObject=%p LogHandle=%p FlushToLsnRoutine=%p\n", 319 FileObject, LogHandle, FlushToLsnRoutine); 320 321 UNIMPLEMENTED; 322 } 323 324 /* 325 * @unimplemented 326 */ 327 BOOLEAN 328 NTAPI 329 CcUninitializeCacheMap ( 330 IN PFILE_OBJECT FileObject, 331 IN PLARGE_INTEGER TruncateSize OPTIONAL, 332 IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL) 333 { 334 NTSTATUS Status; 335 PROS_SHARED_CACHE_MAP SharedCacheMap; 336 KIRQL OldIrql; 337 338 CCTRACE(CC_API_DEBUG, "FileObject=%p TruncateSize=%p UninitializeCompleteEvent=%p\n", 339 FileObject, TruncateSize, UninitializeCompleteEvent); 340 341 if (TruncateSize != NULL && 342 FileObject->SectionObjectPointer->SharedCacheMap != NULL) 343 { 344 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 345 KeAcquireSpinLock(&SharedCacheMap->CacheMapLock, &OldIrql); 346 if (SharedCacheMap->FileSize.QuadPart > TruncateSize->QuadPart) 347 { 348 SharedCacheMap->FileSize = *TruncateSize; 349 } 350 KeReleaseSpinLock(&SharedCacheMap->CacheMapLock, OldIrql); 351 CcPurgeCacheSection(FileObject->SectionObjectPointer, 352 TruncateSize, 353 0, 354 FALSE); 355 } 356 357 Status = CcRosReleaseFileCache(FileObject); 358 if (UninitializeCompleteEvent) 359 { 360 KeSetEvent(&UninitializeCompleteEvent->Event, IO_NO_INCREMENT, FALSE); 361 } 362 return NT_SUCCESS(Status); 363 } 364 365 BOOLEAN 366 NTAPI 367 CcGetFileSizes ( 368 IN PFILE_OBJECT FileObject, 369 IN PCC_FILE_SIZES FileSizes) 370 { 371 PROS_SHARED_CACHE_MAP SharedCacheMap; 372 373 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap; 374 375 if (!SharedCacheMap) 376 return FALSE; 377 378 FileSizes->AllocationSize = SharedCacheMap->SectionSize; 379 FileSizes->FileSize = FileSizes->ValidDataLength = SharedCacheMap->FileSize; 380 return TRUE; 381 } 382