Implement a file system that runs in user space using the FSKit framework.

Posts under FSKit tag

46 Posts

Post

Replies

Boosts

Views

Activity

Ten FSKit issues found building a network file system module (all filed with minimal repros)
While building an SMB 2/3 client as an FSKit file system module (FSUnaryFileSystem + FSVolume, the macOS 27 Handler protocols), I ran into a number of framework-level issues. I have filed each one with a title starting "FSKit:" so they are easy to find, and every report has a minimal reproduction attached: a small in-memory FSKit module (no network, no disk, no cache of its own), so none of them depend on SMB. All were measured on macOS 27.0 (26A5406e and 26A5416b) with Xcode 27.0 beta 5. Summaries below in case anyone else is hitting these. FB24419773: renameatx_np with RENAME_SWAP returns success but destroys the destination file. On any FSKit volume a RENAME_SWAP is performed as an ordinary clobbering rename: rc=0, but the destination's contents are silently lost instead of exchanged. The module cannot refuse it because renameItem receives no flags; a swap and a plain overwriting rename look identical. (RENAME_EXCL works correctly.) FB24419825: a negative lookup is cached permanently. Once anything gets ENOENT for a name on an FSKit volume, the kernel serves that ENOENT for the life of the vnode. If the file is created later (for example by another machine on a network volume), it stays unopenable by that name indefinitely, while ls of the same directory lists it. There is no API through which a module can report that a name now exists. FB24419858: a data-cache grant from openItem can be applied after the module has already invalidated. The grant in FSOpenItemResult is applied asynchronously after the module's reply, and an invalidation issued in that window succeeds (setCacheState returns no error) and is then overwritten by the stale grant. The result is a kernel cache no future event will invalidate; readers see stale data. FB24419870: synchronize(flags:) is never called on a URL-backed volume. fsync(2), fcntl(F_FULLFSYNC), fcntl(F_BARRIERFSYNC) and sync(8) all return success with zero calls reaching the module, so durability is reported and never established. A packet capture of the same SMB share shows five SMB2 FLUSH requests through Apple's smbfs and zero through an FSKit module. FB24419894: FSItemSetAttributesRequest.consumedAttributes is never observed, and wasAttributeConsumed(.changeTime) answers about the wrong attribute. Consuming everything and consuming nothing are indistinguishable to the caller (chmod returns 0 either way), even though the setAttributes documentation says the upper layers will detect unsupported attributes. Separately, wasAttributeConsumed answers YES for changeTime when only accessTime was consumed, and never answers correctly about changeTime itself; this part reproduces by constructing the request directly, no file system needed. FB24419911: restrictsOwnershipChanges = true does not reject non-superuser chown. The property is documented as "the volume rejects a chown(2) from anyone other than the superuser", but on an -o owners mount a non-root chgrp is delivered to the module's setAttributes anyway, so every module has to enforce the policy itself. FB24419932: a failed activate wedges the resource URL. After a module's activate throws once, every later mount of the same URL string fails with "Resource busy" (fskitd logs "Can't start new task, resource state is 5"), while the same volume under a different URL spelling mounts fine. For a network module the ordinary trigger is one wrong password. Recovery requires killing both fskitd and the extension process. FB24419964: enumeration cannot report extended-attribute presence. FSItem.Attributes has no per-item "has xattrs" field, so one cold ls -l of a 500-entry directory costs about 2,000 FSKit boundary crossings: an xattr call per entry plus a "._name" AppleDouble sidecar lookup per entry, and each of those ENOENTs is then pinned by FB24419825. Suggestion: a per-entry hasExtendedAttributes flag so getattrlistbulk can be satisfied from the enumeration. FB24419974: no byte-range lock operations. flock(2) and fcntl(2) locks on an FSKit mount stay kernel-local and never reach the module, so advisory locks cannot coordinate between clients of a network file system. Suggestion: an optional lock-operations handler. FB24419979: no ACL or security descriptor operations. ls -le, chmod +a, acl_get_file(3) and cp -p with ACLs cannot work on any FSKit volume; a network server's real ACLs are invisible behind synthesized mode bits. The nearest surface, FSVolumeAccessCheckHandler, can only be asked yes/no questions about a descriptor the module has no way to provide. Suggestion: an optional ACL-operations protocol. If any of these are biting you too, duplicate feedbacks referencing the FB numbers above genuinely help with prioritization.
0
0
74
2d
FileProvider & FSKit compatability
I've been trying to mount an FSKit volume at the location where FileProvider saves files: ~/Library/CloudStorage . I've discovered that FileProvider attempts to call setAttributes in order to assign a value for an access control list (ACL). This call fails, because FSKit does not support this attribute, and causes FileProvider to stop working. FileProvider refuses to continue beyond creating it's domain folder when this occurs. Do you believe this constitutes a valid enhancement request for FSKit and/or FileProvider?
1
0
247
1w
FSKit - Retrieve Process ID?
Does FSKit support the ability to get the process information, such as the pid, when a process accesses a resource? Being able have the process context is important for implementing certain access patterns and security logging in some contexts. For instance, we have a system that utilizes (pre-FSKit) a FUSE mount that, depending on the process has different "views" and "access" based on the process id.
3
0
794
3w
Failure to mount an FSKit volume *sometimes*
Hello, I'm working on a project for a file system using FSKit and I'm currently experiencing a strange issue on macOS 26 to which I updated recently. While testing, I'm doing incremental debug builds using Xcode. I'm very careful to make sure I only have a single instance of the built app (hosting the file system extension) anywhere on disk. I run the app, mount the file system, run some tests, unmount, kill the app, make changes, and repeat. Once in a while, however, mount would suddenly start failing with mount: Loading resource: The operation couldn’t be completed. (com.apple.extensionKit.errorDomain error 2.) mount: File system named MyFS not found This would consistently repeat until I clean the build folder, rebuild and run again. I would continue testing for a while, then at some point mount would start failing again. I looked at the system logs and found this message from extensionkitservice: Failed to initialize _EXExtensionIdentity: Error Domain=com.apple.extensionKit.errorDomain Code=5 "Failed to find extension: 24B7F729-5AD1-4486-92B4-1F57CACCA265" So I started going through the logs in more detail and found the following: lsd seems to unregister and register the file system extension occasionally, each time giving it a different UUID. I can see logs about "com.apple.LaunchServices.pluginsregistered" and "com.apple.LaunchServices.pluginsunregistered" notifications being sent with their data. What seems to be the problem is that sometimes after this happens, when I attempt to mount the file system, the extensionkitservice would fail to find the extension because it is referencing it using one of its previous UUIDs assigned by lsd, not its latest one, judging by the UUID in the log message. Am I doing something wrong here? I think I may be causing the constant unregister/register of the extension idirectly by rebuilding via Xcode. Or is it a problem with extensionkitservice? I've never had this happen on Sequoia. macOS 26.0.1 (25A362); Xcode 26.0.1 (17A400) Thank you
5
1
907
3w
FSKit and CI Automation for Filesystem Development
Hi everyone, First, I'd like to say that I'm really excited about the direction FSKit is taking. Having a modern, user-space filesystem framework on macOS is a huge improvement, and I'm currently working on porting an existing cross-platform FUSE-based filesystem to use it. One challenge I've run into is automated testing. Our project has Linux, Windows, and macOS CI. On Linux, we can perform real mount/unmount integration tests on every commit. On Windows, we can do the same using WinFsp. However, on GitHub-hosted macOS runners, it appears that filesystem extensions still require interactive approval or registration before they can be mounted. This makes it difficult to validate the actual mount lifecycle in ephemeral CI environments. We can still compile and unit test our filesystem logic, but we can't exercise the final "mount a filesystem and verify it behaves correctly" integration tests without a self-hosted Mac. I'm curious whether this is the expected long-term workflow, or whether Apple has plans to make this easier for developers. Some questions I have are: Is unattended registration of an FSKit filesystem extension in CI something that's being considered? Are there plans to support ephemeral CI environments such as GitHub Actions without requiring manual interaction? Is there a recommended approach for automated integration testing of FSKit filesystems today that I'm overlooking? More generally, what does Apple envision as the best practice for projects that want to continuously test real filesystem mounts? I completely understand the security motivations for requiring user approval on end-user systems. My question is specifically about trusted development and CI environments where the machine is temporary and exists solely for automated testing. Thanks for any guidance, and thanks to the FSKit team for the work that's gone into making user-space filesystems a first-class experience on macOS.
0
1
360
Jul ’26
FSKit removeItem Not Being Called
Environment macOS Version: 26.1 Xcode Version: 16.2 Description I'm developing a custom file system using FSKit and have encountered an issue where the removeItem(_:named:fromDirectory:) method in my FSVolume.Operations implementation is not being invoked when attempting to delete files or directories through Finder or the command line. Implementation My volume implements the required FSVolume.Operations protocol with the following removeItem implementation: func removeItem( _ item: FSItem, named name: FSFileName, fromDirectory directory: FSItem ) async throws { logger.info("remove: \(name)") if let item = item as? MyFSItem, let directory = directory as? MyFSItem { directory.removeItem(item) } else { throw fs_errorForPOSIXError(POSIXError.EIO.rawValue) } } Steps to Reproduce Mount the custom FSKit-based file system using: mount -F -t MyFS /dev/diskX /tmp/mountpoint Create files using Finder or terminal (works correctly - createItem is called) Attempt to delete a file using any of the following methods: Terminal command: rm -rf /path/to/mounted/file option + cmd + delete to remove the file in Finder Expected Behavior The removeItem(_:named:fromDirectory:) method should be called, logging "remove: [filename]" and removing the item from the directory's children collection. Actual Behavior The removeItem method is never invoked. No logs appear from this method in Console.app. The deletion operation either fails silently or returns an error, but the callback never occurs. Additional Context Working operations: Other operations work correctly including: createItem - files and directories can be created lookupItem - items can be looked up successfully enumerateDirectory - directory listing works read and write - file I/O operations work correctly Volume state: The volume is properly mounted and accessible Files can be created, read, and written successfully Volume capabilities configured: var supportedVolumeCapabilities: FSVolume.SupportedCapabilities { let capabilities = FSVolume.SupportedCapabilities() capabilities.supportsHardLinks = true capabilities.supportsSymbolicLinks = true capabilities.supportsPersistentObjectIDs = true capabilities.doesNotSupportVolumeSizes = true capabilities.supportsHiddenFiles = true capabilities.supports64BitObjectIDs = true capabilities.caseFormat = .insensitiveCasePreserving return capabilities } Questions Are there specific volume capabilities or entitlements required for removeItem to be invoked? Is there a specific way deletion operations need to be enabled in FSKit? Could this be related to how file permissions or attributes are set during createItem? Are there any known issues with deletion operations in the current FSKit implementation? Do I need to implement additional protocols or set specific flags to support item deletion? Any guidance would be greatly appreciated. Has anyone successfully implemented deletion operations in FSKit? Thank you!
4
2
743
Jul ’26
FSKit: two extension processes after mount, one survives unmount — expected behavior?
Hi, I'm developing an FSKit extension and noticed a consistent process lifecycle that also reproduces with Apple's official passthrough sample. Environment: macOS: [26.5.2] Xcode: [26.6] Observed behavior: After a successful mount, Activity Monitor shows two processes with the same executable path (the embedded .appex inside the host app). After umount, one process exits; one remains. A subsequent mount again results in two active processes (one lingering + one new mount-serving instance, depending on timing). What I've ruled out: Not caused by Instruments / lldb attach (reproduces after reboot, with no debugger attached). Not specific to our project: Apple's official passthrough FSKit demo shows the same pattern. Not duplicate pluginkit registrations at different paths — both processes report the same .appex executable path. Not requiring the host app to be running — reproduces with command-line mount only (UDrive app and Xcode quit). Questions: Is this the intended FSKit lifecycle? After umount, is it expected that one extension process remains idle rather than exiting completely? Thanks!
2
0
328
Jul ’26
Open Sourcing Legacy file systems (such as HFS)?
Hopefully this is an acceptable ask and place for this: With Apple abandoning support for certain legacy file systems, such as HFS, would this be something that could be made open source? The idea here is to make facilitate software preservation and access, and maybe even provide the opportunity to develop an FSKit implementation via the community? Also would Apple have any strong business reason to keep it closed source once essentially considered abandoned? Though maybe simply tryinging to port https://github.com/0x09/hfsfuse to FSKit would be more realistic in the HFS specific scenario?
3
1
366
Jul ’26
FSKit AppEx continious integration
Hi! I'm developing an FSKit module and experiencing some troubles with test harness automation: Registering an FSKit AppEx requires user intervention by clicking through a GUI. Re-deploying a new build signed with a local certificate involves the same roundabout to re-toggle the registered AppEx in the Settings. Are there any plans to improve developer experience in this regard?
3
0
372
Jun ’26
Notify file tree changes
Hi, I am very excited for the fskit changes. Now I finally had some time to actually read the docs. But I am not very sure how the new cache api is able to propagate external file tree changes to fskit. As far as I understand it only handels cached file data but not metadata? I really hope I am just misunderstanding and this is possible. Greetings Nils
2
0
321
Jun ’26
FSKit and Network File Systems?
Hi folks! I’ve been paying attention to FSKit for moment to develop a network file system designed for source control-use cases (à la Eden or Google’s CITC). The design goal is support instant clones, even of massive repositories, by lazily fetching files as needed. Based on this thread, it seems like macOS 27 has added some of the requisite APIs needed to support inode invalidation for network/shared file systems like the cache coherency APIs. For example, I’m thinking that for this file system, I’d want to bypass the kernel’s own caching and have my file system be entirely responsible for it, as it‘d have a better understanding/picture of what is up-to-date and what isn’t and there won’t need to be multiple layers of cache invalidation/coherency. Am I correctly reading the intent of these new APIs?
3
0
494
Jun ’26
OpenZFS on FSKit — Proof of Concept
Installing ZFSFSKit.appex ? /Library/ExtensionKit/Extensions/ Substituting real Mach-O (libtool wrapper ? .libs/ZFSFSKit) Installing zfs.fs ? /Library/Filesystems/ mount_zfs: Mach-O 64-bit executable arm64 Done. Signing (before pluginkit, so it sees a valid signature)... Re-signing /Library/ExtensionKit/Extensions/ZFSFSKit.appex ad-hoc (no identity). Note: requires amfi_get_out_of_my_way=1 in boot-args. Team ID: ADHOC /Library/ExtensionKit/Extensions/ZFSFSKit.appex: replacing existing signature Done. Signature: Identifier=org.openzfsonosx.filesystems.zfs.fsext Signature=adhoc TeamIdentifier=not set Entitlements: <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>com.apple.application-identifier</key><string>ADHOC.org.openzfsonosx.filesystems.zfs.fsext</string><key>com.apple.developer.fskit.fsmodule</key><true/><key>com.apple.developer.team-identifier</key><string>ADHOC</string><key>com.apple.security.app-sandbox</key><true/></dict></plist> Registering with pluginkit... pluginkit -a done. Restarting fskitd... # sudo pluginkit -v -m -p com.apple.fskit.fsmodule + org.openzfsonosx.filesystems.zfs.fsext((null)) 6A12A41280FB-4190-B957-FA94DC89BB1E 2026-05-29 01:17:58 +0000 /Library/ExtensionKit/Extensions/ZFSFSKit.appex # sudo mkdir /Volumes/tank # sudo mount -F -t zfs /dev/disk4 /Volumes/tank # ls -la /Volumes/tank total 3 drwxr-xr-x 3 lundman staff 4 May 29 09:21 . drwxr-xr-x 4 root wheel 128 May 29 10:18 .. -rw-r--r-- 1 lundman staff 11 May 29 09:21 file.txt drwxr-xr-x 2 lundman staff 2 May 29 09:21 HelloWorld # cat /Volumes/tank/file.txt HelloWorld Even though FSKit isn't quite ready, I built a proof-of-concept FSKit extension to understand what the migration path looks like. This post shares what we got working, specific technical findings that weren't documented, and the gaps we hit that would need Apple's attention for a production implementation. Luckily, OpenZFS already compiles in userland for the "zdb" utility so not much work was required on that side. There were certain amount of desperation applied when we came across hurdles, so possibly some assumptions we formed are not correct. (We didn't go back and confirm the problem after it started working).
6
0
581
Jun ’26
Is FSVolume.DataCacheHandler relevant for block device file systems?
I've been looking at the new kernel caching APIs in FSKit (FSVolume.DataCacheHandler), and they look like they'll be quite useful for network file systems. But are they recommended to be implemented for block device file systems? I see an "Important" note in the documentation that says If a file system doesn’t conform to this protocol, the kernel may still cache it. However, such a file system has no control over caching behavior; the kernel caches data as it sees fit. So I'm wondering in the case of a block device system, where I'm (mostly) using kernel offloaded IO, whether this has any relevance, or if I should instead skip this implementation and just let the kernel "do its thing."
2
0
352
Jun ’26
AppEx lifecycle improvements
Outside of a very narrow happy path, Filesystem Extensions can leave the system in a bad state that can be hard to get out of: For example, a hanging Volume call can leave any process attempting to read from it permanently stuck (no timeouts, process is unkillable, ps / pkill / pgrep themselves may start hanging). When it comes to installation, FS AppEx are registered with two subsystems afaict (LaunchServices and fskitd) — those two states can get out of sync, and typically cannot be repaired manually. In particular, the only way to reset fskit state seems to be to kill it (notably, disabling SIP is required to launchctl kickstart it, but sudo killall fskit works like a charm). AppEx installed/enabled state seems to be per-user. When mounting as root, fskit queries a different state (implying that a FS may be enabled for an admin user ie. John Doe, but not from the perspective of a root SMAppService — even when using launchctl asuser/bsexec to attempt to replicate the security context of John Doe's login session at their behest). The actual question here is hard to formulate... are there any plans to make FS AppEx behave more like the rest of the platform? More consistent/helpful/centralized logging (it is currently spread across multiple targets and as much as the "boom" and emojis are entertaining, on day 14 of debugging transient failures, it does get old). Making a .pkg installer with an FS AppEx inside prevents the AppEx from being installed through the prescribed happy path (simply having the user launch the containing .app) since it gets pre-registered via LaunchServices. In fact, building an AppEx through XCode automatically registers it with ls, making real-world testing of AppEx really difficult... The sheer breadth of subtle challenges in shipping a working, reliable FSKit-based filesystem on macOS has prevented me so far from filing tidy, individual bug reports, and for this I apologize, but: if you have a roadmap of "reliability improvements / behavior normalization / edge case resolutions" to share today, I'm sure many of us would be eager to read it.
6
0
348
Jun ’26
Is FSBlockDeviceResource (and other FSResources) thread-safe?
Is FSBlockDeviceResource thread-safe, or do I need to ensure that it’s not written across multiple threads simultaneously? I see that FSBlockDeviceResource is not marked as Sendable in Swift. (This question could also apply to the other FSResources as well if it's simple to answer for them too, but it's just that for my specific use case I'm using FSBlockDeviceResource.)
1
0
159
Jun ’26
volumeSupportsPersistentIDsKey semantics
What does volumeSupportsPersistentIDsKey represent and guarantee on macOS? Is it specifically about persistent filesystem object IDs such as fileIdentifierKey / inode / systemFileNumber, or can it refer to other kinds of persistent IDs? For which common volume/filesystem cases would this property be false, and what should I fall back to as file identity in those cases? Thanks!
1
0
141
Jun ’26
When to use the new FSExtentType.readOnly?
Is it necessary to switch to the new FSExtentType.readOnly when implementing kernel offloaded IO if my entire volume is read-only and marked as such via requestedMountOptions? (My assumption is "no" since I'd think all writes to the resource at that point should be prevented anyway, but wanted to ask just in case.)
1
0
157
Jun ’26
request for a kernel I/O passthrough API for file-backed volumes (FUSE_PASSTHROUGH / ProjFS equivalent)
What I'm building An FSUnaryFileSystem that projects a large, read-mostly tree of existing on-disk files into a sandbox namespace — a build sandbox that lays out an action's declared inputs and points outputs at host scratch. This is squarely the "replace a third-party kext (macFUSE-style) with FSKit" use case, and it's a projection/overlay filesystem: nearly every file the volume serves is just a view of a regular file that already exists on a local APFS volume. The problem For file content, the only available path for a file-backed (non-block-device) volume is FSVolumeReadWriteOperations — every read that misses UBC is an XPC round-trip into my extension, where I memcpy from the backing file into the kernel buffer. The kernel already has, or could trivially open, the backing file; instead each page-in becomes: pagein → IPC → extension read → copy → return. FSVolumeKernelOffloadedIOOperations looks like the intended fast path, but it's built around FSBlockDeviceResource — i.e. it assumes the volume is backed by a block device the kernel can do extent I/O against. A projection over regular files has no block device, so there's no way to say "this item is backed by host file X — kernel, please do I/O directly against X and skip my process." What I measured In one representative build action my volume serves ~440 files and the kernel issues ~630 read RPCs (cold). A real build runs thousands of such actions, so this is on the order of millions of round-trips and buffer copies per build, for data that is already sitting in the host page cache. UBC absorbs repeats, but cold reads, cache eviction under memory pressure, and large sequential reads all pay the full RPC+copy cost. It dominates the I/O profile. The ask A passthrough/offload API for file-backed volumes: let the extension associate an FSItem with a backing file descriptor (or vnode) and have the kernel perform reads — and optionally writes — directly against the backing file, bypassing the userspace round-trip. Per-item, opt-in, and read-only-only would already be a huge win for projection/overlay workloads. This is exactly the model that already exists on other platforms: Linux FUSE passthrough (FUSE_PASSTHROUGH, backing-id via FUSE_DEV_IOC_BACKING_OPEN, mainline since 6.9): a FUSE daemon registers a backing fd and the kernel routes I/O straight to it. Windows Projected File System (ProjFS): content is hydrated/served from a provider-supplied source without a per-read user-space hop. FSKit is positioned as the supported replacement for kext-based filesystems, and projection/overlay/caching filesystems are a primary motivation for it — yet those are precisely the volumes that need zero-copy passthrough to be viable at scale. The block-device offload path covers disk-image-style filesystems; the gap is the file-backed case.
6
0
260
Jun ’26
Ten FSKit issues found building a network file system module (all filed with minimal repros)
While building an SMB 2/3 client as an FSKit file system module (FSUnaryFileSystem + FSVolume, the macOS 27 Handler protocols), I ran into a number of framework-level issues. I have filed each one with a title starting "FSKit:" so they are easy to find, and every report has a minimal reproduction attached: a small in-memory FSKit module (no network, no disk, no cache of its own), so none of them depend on SMB. All were measured on macOS 27.0 (26A5406e and 26A5416b) with Xcode 27.0 beta 5. Summaries below in case anyone else is hitting these. FB24419773: renameatx_np with RENAME_SWAP returns success but destroys the destination file. On any FSKit volume a RENAME_SWAP is performed as an ordinary clobbering rename: rc=0, but the destination's contents are silently lost instead of exchanged. The module cannot refuse it because renameItem receives no flags; a swap and a plain overwriting rename look identical. (RENAME_EXCL works correctly.) FB24419825: a negative lookup is cached permanently. Once anything gets ENOENT for a name on an FSKit volume, the kernel serves that ENOENT for the life of the vnode. If the file is created later (for example by another machine on a network volume), it stays unopenable by that name indefinitely, while ls of the same directory lists it. There is no API through which a module can report that a name now exists. FB24419858: a data-cache grant from openItem can be applied after the module has already invalidated. The grant in FSOpenItemResult is applied asynchronously after the module's reply, and an invalidation issued in that window succeeds (setCacheState returns no error) and is then overwritten by the stale grant. The result is a kernel cache no future event will invalidate; readers see stale data. FB24419870: synchronize(flags:) is never called on a URL-backed volume. fsync(2), fcntl(F_FULLFSYNC), fcntl(F_BARRIERFSYNC) and sync(8) all return success with zero calls reaching the module, so durability is reported and never established. A packet capture of the same SMB share shows five SMB2 FLUSH requests through Apple's smbfs and zero through an FSKit module. FB24419894: FSItemSetAttributesRequest.consumedAttributes is never observed, and wasAttributeConsumed(.changeTime) answers about the wrong attribute. Consuming everything and consuming nothing are indistinguishable to the caller (chmod returns 0 either way), even though the setAttributes documentation says the upper layers will detect unsupported attributes. Separately, wasAttributeConsumed answers YES for changeTime when only accessTime was consumed, and never answers correctly about changeTime itself; this part reproduces by constructing the request directly, no file system needed. FB24419911: restrictsOwnershipChanges = true does not reject non-superuser chown. The property is documented as "the volume rejects a chown(2) from anyone other than the superuser", but on an -o owners mount a non-root chgrp is delivered to the module's setAttributes anyway, so every module has to enforce the policy itself. FB24419932: a failed activate wedges the resource URL. After a module's activate throws once, every later mount of the same URL string fails with "Resource busy" (fskitd logs "Can't start new task, resource state is 5"), while the same volume under a different URL spelling mounts fine. For a network module the ordinary trigger is one wrong password. Recovery requires killing both fskitd and the extension process. FB24419964: enumeration cannot report extended-attribute presence. FSItem.Attributes has no per-item "has xattrs" field, so one cold ls -l of a 500-entry directory costs about 2,000 FSKit boundary crossings: an xattr call per entry plus a "._name" AppleDouble sidecar lookup per entry, and each of those ENOENTs is then pinned by FB24419825. Suggestion: a per-entry hasExtendedAttributes flag so getattrlistbulk can be satisfied from the enumeration. FB24419974: no byte-range lock operations. flock(2) and fcntl(2) locks on an FSKit mount stay kernel-local and never reach the module, so advisory locks cannot coordinate between clients of a network file system. Suggestion: an optional lock-operations handler. FB24419979: no ACL or security descriptor operations. ls -le, chmod +a, acl_get_file(3) and cp -p with ACLs cannot work on any FSKit volume; a network server's real ACLs are invisible behind synthesized mode bits. The nearest surface, FSVolumeAccessCheckHandler, can only be asked yes/no questions about a descriptor the module has no way to provide. Suggestion: an optional ACL-operations protocol. If any of these are biting you too, duplicate feedbacks referencing the FB numbers above genuinely help with prioritization.
Replies
0
Boosts
0
Views
74
Activity
2d
FileProvider & FSKit compatability
I've been trying to mount an FSKit volume at the location where FileProvider saves files: ~/Library/CloudStorage . I've discovered that FileProvider attempts to call setAttributes in order to assign a value for an access control list (ACL). This call fails, because FSKit does not support this attribute, and causes FileProvider to stop working. FileProvider refuses to continue beyond creating it's domain folder when this occurs. Do you believe this constitutes a valid enhancement request for FSKit and/or FileProvider?
Replies
1
Boosts
0
Views
247
Activity
1w
FSKit - Retrieve Process ID?
Does FSKit support the ability to get the process information, such as the pid, when a process accesses a resource? Being able have the process context is important for implementing certain access patterns and security logging in some contexts. For instance, we have a system that utilizes (pre-FSKit) a FUSE mount that, depending on the process has different "views" and "access" based on the process id.
Replies
3
Boosts
0
Views
794
Activity
3w
Failure to mount an FSKit volume *sometimes*
Hello, I'm working on a project for a file system using FSKit and I'm currently experiencing a strange issue on macOS 26 to which I updated recently. While testing, I'm doing incremental debug builds using Xcode. I'm very careful to make sure I only have a single instance of the built app (hosting the file system extension) anywhere on disk. I run the app, mount the file system, run some tests, unmount, kill the app, make changes, and repeat. Once in a while, however, mount would suddenly start failing with mount: Loading resource: The operation couldn’t be completed. (com.apple.extensionKit.errorDomain error 2.) mount: File system named MyFS not found This would consistently repeat until I clean the build folder, rebuild and run again. I would continue testing for a while, then at some point mount would start failing again. I looked at the system logs and found this message from extensionkitservice: Failed to initialize _EXExtensionIdentity: Error Domain=com.apple.extensionKit.errorDomain Code=5 "Failed to find extension: 24B7F729-5AD1-4486-92B4-1F57CACCA265" So I started going through the logs in more detail and found the following: lsd seems to unregister and register the file system extension occasionally, each time giving it a different UUID. I can see logs about "com.apple.LaunchServices.pluginsregistered" and "com.apple.LaunchServices.pluginsunregistered" notifications being sent with their data. What seems to be the problem is that sometimes after this happens, when I attempt to mount the file system, the extensionkitservice would fail to find the extension because it is referencing it using one of its previous UUIDs assigned by lsd, not its latest one, judging by the UUID in the log message. Am I doing something wrong here? I think I may be causing the constant unregister/register of the extension idirectly by rebuilding via Xcode. Or is it a problem with extensionkitservice? I've never had this happen on Sequoia. macOS 26.0.1 (25A362); Xcode 26.0.1 (17A400) Thank you
Replies
5
Boosts
1
Views
907
Activity
3w
FSKit and CI Automation for Filesystem Development
Hi everyone, First, I'd like to say that I'm really excited about the direction FSKit is taking. Having a modern, user-space filesystem framework on macOS is a huge improvement, and I'm currently working on porting an existing cross-platform FUSE-based filesystem to use it. One challenge I've run into is automated testing. Our project has Linux, Windows, and macOS CI. On Linux, we can perform real mount/unmount integration tests on every commit. On Windows, we can do the same using WinFsp. However, on GitHub-hosted macOS runners, it appears that filesystem extensions still require interactive approval or registration before they can be mounted. This makes it difficult to validate the actual mount lifecycle in ephemeral CI environments. We can still compile and unit test our filesystem logic, but we can't exercise the final "mount a filesystem and verify it behaves correctly" integration tests without a self-hosted Mac. I'm curious whether this is the expected long-term workflow, or whether Apple has plans to make this easier for developers. Some questions I have are: Is unattended registration of an FSKit filesystem extension in CI something that's being considered? Are there plans to support ephemeral CI environments such as GitHub Actions without requiring manual interaction? Is there a recommended approach for automated integration testing of FSKit filesystems today that I'm overlooking? More generally, what does Apple envision as the best practice for projects that want to continuously test real filesystem mounts? I completely understand the security motivations for requiring user approval on end-user systems. My question is specifically about trusted development and CI environments where the machine is temporary and exists solely for automated testing. Thanks for any guidance, and thanks to the FSKit team for the work that's gone into making user-space filesystems a first-class experience on macOS.
Replies
0
Boosts
1
Views
360
Activity
Jul ’26
FSKit removeItem Not Being Called
Environment macOS Version: 26.1 Xcode Version: 16.2 Description I'm developing a custom file system using FSKit and have encountered an issue where the removeItem(_:named:fromDirectory:) method in my FSVolume.Operations implementation is not being invoked when attempting to delete files or directories through Finder or the command line. Implementation My volume implements the required FSVolume.Operations protocol with the following removeItem implementation: func removeItem( _ item: FSItem, named name: FSFileName, fromDirectory directory: FSItem ) async throws { logger.info("remove: \(name)") if let item = item as? MyFSItem, let directory = directory as? MyFSItem { directory.removeItem(item) } else { throw fs_errorForPOSIXError(POSIXError.EIO.rawValue) } } Steps to Reproduce Mount the custom FSKit-based file system using: mount -F -t MyFS /dev/diskX /tmp/mountpoint Create files using Finder or terminal (works correctly - createItem is called) Attempt to delete a file using any of the following methods: Terminal command: rm -rf /path/to/mounted/file option + cmd + delete to remove the file in Finder Expected Behavior The removeItem(_:named:fromDirectory:) method should be called, logging "remove: [filename]" and removing the item from the directory's children collection. Actual Behavior The removeItem method is never invoked. No logs appear from this method in Console.app. The deletion operation either fails silently or returns an error, but the callback never occurs. Additional Context Working operations: Other operations work correctly including: createItem - files and directories can be created lookupItem - items can be looked up successfully enumerateDirectory - directory listing works read and write - file I/O operations work correctly Volume state: The volume is properly mounted and accessible Files can be created, read, and written successfully Volume capabilities configured: var supportedVolumeCapabilities: FSVolume.SupportedCapabilities { let capabilities = FSVolume.SupportedCapabilities() capabilities.supportsHardLinks = true capabilities.supportsSymbolicLinks = true capabilities.supportsPersistentObjectIDs = true capabilities.doesNotSupportVolumeSizes = true capabilities.supportsHiddenFiles = true capabilities.supports64BitObjectIDs = true capabilities.caseFormat = .insensitiveCasePreserving return capabilities } Questions Are there specific volume capabilities or entitlements required for removeItem to be invoked? Is there a specific way deletion operations need to be enabled in FSKit? Could this be related to how file permissions or attributes are set during createItem? Are there any known issues with deletion operations in the current FSKit implementation? Do I need to implement additional protocols or set specific flags to support item deletion? Any guidance would be greatly appreciated. Has anyone successfully implemented deletion operations in FSKit? Thank you!
Replies
4
Boosts
2
Views
743
Activity
Jul ’26
FSKit: two extension processes after mount, one survives unmount — expected behavior?
Hi, I'm developing an FSKit extension and noticed a consistent process lifecycle that also reproduces with Apple's official passthrough sample. Environment: macOS: [26.5.2] Xcode: [26.6] Observed behavior: After a successful mount, Activity Monitor shows two processes with the same executable path (the embedded .appex inside the host app). After umount, one process exits; one remains. A subsequent mount again results in two active processes (one lingering + one new mount-serving instance, depending on timing). What I've ruled out: Not caused by Instruments / lldb attach (reproduces after reboot, with no debugger attached). Not specific to our project: Apple's official passthrough FSKit demo shows the same pattern. Not duplicate pluginkit registrations at different paths — both processes report the same .appex executable path. Not requiring the host app to be running — reproduces with command-line mount only (UDrive app and Xcode quit). Questions: Is this the intended FSKit lifecycle? After umount, is it expected that one extension process remains idle rather than exiting completely? Thanks!
Replies
2
Boosts
0
Views
328
Activity
Jul ’26
FUSE compat surface plans?
Any plans to provide (a subset of) the FUSE3 API directly on top of FSKit/an underlying primitive, in a way that doesn't compromise the new security model, but also reduces porting friction?
Replies
5
Boosts
2
Views
613
Activity
Jul ’26
Open Sourcing Legacy file systems (such as HFS)?
Hopefully this is an acceptable ask and place for this: With Apple abandoning support for certain legacy file systems, such as HFS, would this be something that could be made open source? The idea here is to make facilitate software preservation and access, and maybe even provide the opportunity to develop an FSKit implementation via the community? Also would Apple have any strong business reason to keep it closed source once essentially considered abandoned? Though maybe simply tryinging to port https://github.com/0x09/hfsfuse to FSKit would be more realistic in the HFS specific scenario?
Replies
3
Boosts
1
Views
366
Activity
Jul ’26
FSKit AppEx continious integration
Hi! I'm developing an FSKit module and experiencing some troubles with test harness automation: Registering an FSKit AppEx requires user intervention by clicking through a GUI. Re-deploying a new build signed with a local certificate involves the same roundabout to re-toggle the registered AppEx in the Settings. Are there any plans to improve developer experience in this regard?
Replies
3
Boosts
0
Views
372
Activity
Jun ’26
Notify file tree changes
Hi, I am very excited for the fskit changes. Now I finally had some time to actually read the docs. But I am not very sure how the new cache api is able to propagate external file tree changes to fskit. As far as I understand it only handels cached file data but not metadata? I really hope I am just misunderstanding and this is possible. Greetings Nils
Replies
2
Boosts
0
Views
321
Activity
Jun ’26
FSKit and Network File Systems?
Hi folks! I’ve been paying attention to FSKit for moment to develop a network file system designed for source control-use cases (à la Eden or Google’s CITC). The design goal is support instant clones, even of massive repositories, by lazily fetching files as needed. Based on this thread, it seems like macOS 27 has added some of the requisite APIs needed to support inode invalidation for network/shared file systems like the cache coherency APIs. For example, I’m thinking that for this file system, I’d want to bypass the kernel’s own caching and have my file system be entirely responsible for it, as it‘d have a better understanding/picture of what is up-to-date and what isn’t and there won’t need to be multiple layers of cache invalidation/coherency. Am I correctly reading the intent of these new APIs?
Replies
3
Boosts
0
Views
494
Activity
Jun ’26
OpenZFS on FSKit — Proof of Concept
Installing ZFSFSKit.appex ? /Library/ExtensionKit/Extensions/ Substituting real Mach-O (libtool wrapper ? .libs/ZFSFSKit) Installing zfs.fs ? /Library/Filesystems/ mount_zfs: Mach-O 64-bit executable arm64 Done. Signing (before pluginkit, so it sees a valid signature)... Re-signing /Library/ExtensionKit/Extensions/ZFSFSKit.appex ad-hoc (no identity). Note: requires amfi_get_out_of_my_way=1 in boot-args. Team ID: ADHOC /Library/ExtensionKit/Extensions/ZFSFSKit.appex: replacing existing signature Done. Signature: Identifier=org.openzfsonosx.filesystems.zfs.fsext Signature=adhoc TeamIdentifier=not set Entitlements: <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>com.apple.application-identifier</key><string>ADHOC.org.openzfsonosx.filesystems.zfs.fsext</string><key>com.apple.developer.fskit.fsmodule</key><true/><key>com.apple.developer.team-identifier</key><string>ADHOC</string><key>com.apple.security.app-sandbox</key><true/></dict></plist> Registering with pluginkit... pluginkit -a done. Restarting fskitd... # sudo pluginkit -v -m -p com.apple.fskit.fsmodule + org.openzfsonosx.filesystems.zfs.fsext((null)) 6A12A41280FB-4190-B957-FA94DC89BB1E 2026-05-29 01:17:58 +0000 /Library/ExtensionKit/Extensions/ZFSFSKit.appex # sudo mkdir /Volumes/tank # sudo mount -F -t zfs /dev/disk4 /Volumes/tank # ls -la /Volumes/tank total 3 drwxr-xr-x 3 lundman staff 4 May 29 09:21 . drwxr-xr-x 4 root wheel 128 May 29 10:18 .. -rw-r--r-- 1 lundman staff 11 May 29 09:21 file.txt drwxr-xr-x 2 lundman staff 2 May 29 09:21 HelloWorld # cat /Volumes/tank/file.txt HelloWorld Even though FSKit isn't quite ready, I built a proof-of-concept FSKit extension to understand what the migration path looks like. This post shares what we got working, specific technical findings that weren't documented, and the gaps we hit that would need Apple's attention for a production implementation. Luckily, OpenZFS already compiles in userland for the "zdb" utility so not much work was required on that side. There were certain amount of desperation applied when we came across hurdles, so possibly some assumptions we formed are not correct. (We didn't go back and confirm the problem after it started working).
Replies
6
Boosts
0
Views
581
Activity
Jun ’26
Is FSVolume.DataCacheHandler relevant for block device file systems?
I've been looking at the new kernel caching APIs in FSKit (FSVolume.DataCacheHandler), and they look like they'll be quite useful for network file systems. But are they recommended to be implemented for block device file systems? I see an "Important" note in the documentation that says If a file system doesn’t conform to this protocol, the kernel may still cache it. However, such a file system has no control over caching behavior; the kernel caches data as it sees fit. So I'm wondering in the case of a block device system, where I'm (mostly) using kernel offloaded IO, whether this has any relevance, or if I should instead skip this implementation and just let the kernel "do its thing."
Replies
2
Boosts
0
Views
352
Activity
Jun ’26
AppEx lifecycle improvements
Outside of a very narrow happy path, Filesystem Extensions can leave the system in a bad state that can be hard to get out of: For example, a hanging Volume call can leave any process attempting to read from it permanently stuck (no timeouts, process is unkillable, ps / pkill / pgrep themselves may start hanging). When it comes to installation, FS AppEx are registered with two subsystems afaict (LaunchServices and fskitd) — those two states can get out of sync, and typically cannot be repaired manually. In particular, the only way to reset fskit state seems to be to kill it (notably, disabling SIP is required to launchctl kickstart it, but sudo killall fskit works like a charm). AppEx installed/enabled state seems to be per-user. When mounting as root, fskit queries a different state (implying that a FS may be enabled for an admin user ie. John Doe, but not from the perspective of a root SMAppService — even when using launchctl asuser/bsexec to attempt to replicate the security context of John Doe's login session at their behest). The actual question here is hard to formulate... are there any plans to make FS AppEx behave more like the rest of the platform? More consistent/helpful/centralized logging (it is currently spread across multiple targets and as much as the "boom" and emojis are entertaining, on day 14 of debugging transient failures, it does get old). Making a .pkg installer with an FS AppEx inside prevents the AppEx from being installed through the prescribed happy path (simply having the user launch the containing .app) since it gets pre-registered via LaunchServices. In fact, building an AppEx through XCode automatically registers it with ls, making real-world testing of AppEx really difficult... The sheer breadth of subtle challenges in shipping a working, reliable FSKit-based filesystem on macOS has prevented me so far from filing tidy, individual bug reports, and for this I apologize, but: if you have a roadmap of "reliability improvements / behavior normalization / edge case resolutions" to share today, I'm sure many of us would be eager to read it.
Replies
6
Boosts
0
Views
348
Activity
Jun ’26
Is FSBlockDeviceResource (and other FSResources) thread-safe?
Is FSBlockDeviceResource thread-safe, or do I need to ensure that it’s not written across multiple threads simultaneously? I see that FSBlockDeviceResource is not marked as Sendable in Swift. (This question could also apply to the other FSResources as well if it's simple to answer for them too, but it's just that for my specific use case I'm using FSBlockDeviceResource.)
Replies
1
Boosts
0
Views
159
Activity
Jun ’26
volumeSupportsPersistentIDsKey semantics
What does volumeSupportsPersistentIDsKey represent and guarantee on macOS? Is it specifically about persistent filesystem object IDs such as fileIdentifierKey / inode / systemFileNumber, or can it refer to other kinds of persistent IDs? For which common volume/filesystem cases would this property be false, and what should I fall back to as file identity in those cases? Thanks!
Replies
1
Boosts
0
Views
141
Activity
Jun ’26
When to use the new FSExtentType.readOnly?
Is it necessary to switch to the new FSExtentType.readOnly when implementing kernel offloaded IO if my entire volume is read-only and marked as such via requestedMountOptions? (My assumption is "no" since I'd think all writes to the resource at that point should be prevented anyway, but wanted to ask just in case.)
Replies
1
Boosts
0
Views
157
Activity
Jun ’26
Is inode invalidation currently supported?
I cannot find anywhere in the documentation how to invalidate an FSItem. It seems to be cached indefinitely or am I missing something?
Replies
4
Boosts
1
Views
507
Activity
Jun ’26
request for a kernel I/O passthrough API for file-backed volumes (FUSE_PASSTHROUGH / ProjFS equivalent)
What I'm building An FSUnaryFileSystem that projects a large, read-mostly tree of existing on-disk files into a sandbox namespace — a build sandbox that lays out an action's declared inputs and points outputs at host scratch. This is squarely the "replace a third-party kext (macFUSE-style) with FSKit" use case, and it's a projection/overlay filesystem: nearly every file the volume serves is just a view of a regular file that already exists on a local APFS volume. The problem For file content, the only available path for a file-backed (non-block-device) volume is FSVolumeReadWriteOperations — every read that misses UBC is an XPC round-trip into my extension, where I memcpy from the backing file into the kernel buffer. The kernel already has, or could trivially open, the backing file; instead each page-in becomes: pagein → IPC → extension read → copy → return. FSVolumeKernelOffloadedIOOperations looks like the intended fast path, but it's built around FSBlockDeviceResource — i.e. it assumes the volume is backed by a block device the kernel can do extent I/O against. A projection over regular files has no block device, so there's no way to say "this item is backed by host file X — kernel, please do I/O directly against X and skip my process." What I measured In one representative build action my volume serves ~440 files and the kernel issues ~630 read RPCs (cold). A real build runs thousands of such actions, so this is on the order of millions of round-trips and buffer copies per build, for data that is already sitting in the host page cache. UBC absorbs repeats, but cold reads, cache eviction under memory pressure, and large sequential reads all pay the full RPC+copy cost. It dominates the I/O profile. The ask A passthrough/offload API for file-backed volumes: let the extension associate an FSItem with a backing file descriptor (or vnode) and have the kernel perform reads — and optionally writes — directly against the backing file, bypassing the userspace round-trip. Per-item, opt-in, and read-only-only would already be a huge win for projection/overlay workloads. This is exactly the model that already exists on other platforms: Linux FUSE passthrough (FUSE_PASSTHROUGH, backing-id via FUSE_DEV_IOC_BACKING_OPEN, mainline since 6.9): a FUSE daemon registers a backing fd and the kernel routes I/O straight to it. Windows Projected File System (ProjFS): content is hydrated/served from a provider-supplied source without a per-read user-space hop. FSKit is positioned as the supported replacement for kext-based filesystems, and projection/overlay/caching filesystems are a primary motivation for it — yet those are precisely the volumes that need zero-copy passthrough to be viable at scale. The block-device offload path covers disk-image-style filesystems; the gap is the file-backed case.
Replies
6
Boosts
0
Views
260
Activity
Jun ’26