Invalidating kernel-cached data when isDataCacheInhibited is true

I'm working on an FSKit module for EdenFS, a source control virtual filesystem.

A teammate of mine asked about FSKit here a couple of years ago before its first public release. Since then, FSKit's feature development has made it feasible for our use case, so we're looking at FSKit again as a replacement for our current NFSv3 solution.

The cache coherency API makes FSKit especially appealing to us, since we need a way to invalidate the kernel's caches after a checkout/goto operation. In another thread, an Apple engineer described it as "designed to manage cache coherency for network file systems and other kinds of file systems where an outside actor might modify the data outside of the kernel's normal data flow," which fits this case.

As I understand it, there are two caching modes we could use:

  1. Negotiated caching, where FSKit calls the volume's open with the requested cache mode on every open of a file that isn't already open, and the volume replies with the coherency type it grants. FSKit then calls close once all references are released. That results in two extra round trips per file access, which is measurable on a workload that touches many thousands of files.
  2. Unilateral caching, where the volume sets isDataCacheInhibited = true, and FSKit stops calling the protocol's methods. The kernel then caches on its own, meaning those extra round trips are eliminated.

As far as I can tell, setCacheState(for:cacheMode:coherencyType:action: .revoke) is the only invalidation mechanism FSKit gives a volume. With isDataCacheInhibited = true, that call returns ENOTSUP (NSPOSIXErrorDomain code 45) and the kernel keeps serving the old contents. I reproduced this on a minimal in-memory module and filed it as FB24996000 with the example attached, tested on macOS 27.2 (26B5091g).

Is this ENOTSUP intended? The setCacheState documentation says it returns ENOTSUP for volumes that don't conform to FSVolume.DataCacheHandler, and my sample does conform. However, the isDataCacheInhibited documentation says it "instructs FSKit not to call this protocol's methods, even if the volume conforms to it". Is FSKit intentionally treating an inhibited volume as if it doesn't conform? If so, is there any other way to tell the kernel that cached data is stale in this mode? The documentation also states that the property is only read at loadResource, so we can't switch to negotiated caching just to serve a goto command either.

For a source control filesystem like ours, we'd at least need to invalidate the kernel cache at specific points (after a goto) for correctness. If per-item invalidation is unsupported in this mode on purpose, would Apple consider a way to invalidate a whole volume's cache at once? Linux FUSE added FUSE_NOTIFY_INC_EPOCH (https://lists.openwall.net/linux-kernel/2025/02/20/1523) for a similar reason, so a server can invalidate every cached lookup in one call instead of one entry at a time. Negotiated caching does work (setCacheState(.revoke) succeeds in that mode) but unilateral caching is ideal for us due to the performance improvement and simpler implementation.

Invalidating kernel-cached data when isDataCacheInhibited is true
 
 
Q