mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-26 19:33:31 +00:00
Root cause: CcRosDeleteFileCache's first loop ran under the spinlock and removed VACBs from the LRU and dirty lists, but left them in CacheMapVacbListHead. It also set Vacb->Dirty = TRUE as a flush hint (after CcRosUnmarkDirtyVacb cleared it), creating an inconsistent VACB state: Dirty=TRUE but not in the dirty list, with only the cache-map-list refcount (1). After releasing the lock, the second loop removed VACBs from CacheMapVacbListHead without holding any lock. This created a race with CcFlushCache: a caller that already held a SharedCacheMap pointer could call CcRosLookupVacb between the two loops, find the VACB (refcount → 2), see Dirty=TRUE (the hack), and call CcRosFlushVacb. Meanwhile the second loop could set Dirty=FALSE, drop the cmap ref (→1, print "Leaking VACB"), and then the early-return in CcRosUnmarkDirtyVacb would skip the decrement. CcRosReleaseVacb then drops 1→0 → ASSERT(Refs > 0) fires. Before the previous fix, the same race caused ASSERT(Vacb->Dirty) in the old CcRosUnmarkDirtyVacb — the previous fix just changed which assert fired. The fix: - CcRosDeleteFileCache: VACBs are now removed from CacheMapVacbListHead in the first loop, under the spinlock, and moved to a private LocalVacbList. After the lock is released, CcRosLookupVacb can no longer find these VACBs, preventing new lookup references from being created. - CcRosReleaseVacb: Removed the overly strict ASSERT(Refs > 0). When CcRosDeleteFileCache drops the cmap ref while a lookup is outstanding, CcRosReleaseVacb legitimately releases the last reference and CcRosVacbDecRefCount correctly frees the VACB. Callers (e.g., CcFlushCache) don't access the VACB pointer afterward. Signed-off-by: Timo Kreuzer <[email protected]>