APFS snapshot revert

I'm trying to restore an APFS volume to its previous state using a snapshot created with the tmutil command. The only native Apple tool I've found for this purpose is apfs.util. According to the documentation, the correct command for this task is /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -R <snapshot name> </dev/diskXsY>. However, this command is not working for me. It returns the error "No such file or directory" for any existing <snapshot name>. If I use a valid file/dir path instead of the <snapshot name> as an experiment, I get an "Invalid argument" error. To investigate the issue, I decided to debug apfs.util and found that the fsctl() function is responsible for these errors (ENOENT and EINVAL). The first argument passed to fsctl() is the <snapshot name> (or file/dir path in my experiment), and the second argument is the value 0x80084A01, which corresponds to the APFSIOC_REVERT_TO_SNAPSHOT command according to xnu's source code (https://github.com/apple-oss-distributions/xnu/blob/8d741a5de7ff4191bf97d57b9f54c2f6d4a15585/bsd/vfs/vfs_syscalls.c#L174). It seems that this command is not supported by the latest versions of macOS (see https://github.com/apple-oss-distributions/xnu/blob/8d741a5de7ff4191bf97d57b9f54c2f6d4a15585/bsd/vfs/vfs_syscalls.c#L12984) and always returns EINVAL error. Is this correct? Are there any other tools available that can be used to revert APFS snapshots?

Answered by DTS Engineer in 814302022

I'm trying to restore an APFS volume to its previous state using a snapshot created with the tmutil command. The only native Apple tool I've found for this purpose is apfs.util.

We don't currently have any mechanism (tool or API) that allows snapshot reversion. If you'd like us to provide something like this, then all I can suggest is filing an enhancement request asking for us to add it.

It seems that this command is not supported by the latest versions of macOS

Basically, yes. Snapshot was originally implemented in APFS through fsctl(APFSIOC_REVERT_TO_SNAPSHOT), however, when snapshot support was added to the full VFS layer, that block as added to prevent sending the command through the fsctl path. If you look lower in the same file, snapshot_revert first tries VFSIOC_REVERT_SNAPSHOT (the public VFS ioctl) and then tries APFSIOC_REVERT_TO_SNAPSHOT (the APFS private ioctl).

For the curious, if you're wondering why this kind of code is there, the answer is that it's a hold over from the original transition and that it's still there because it provides the most flexibility to both teams. The VFS layer originally added it because they wanted the new code path to work even if the APFS team hadn't adopted VFSIOC_REVERT_SNAPSHOT (or, more likely, if someone wanted to test something like an older APFS build). Similarly, APFS actually does support VFSIOC_REVERT_SNAPSHOT but they left APFSIOC_REVERT_TO_SNAPSHOT in place because they didn't want to worry about breaking existing stuff that was still using APFSIOC_REVERT_TO_SNAPSHOT.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

I'm trying to restore an APFS volume to its previous state using a snapshot created with the tmutil command. The only native Apple tool I've found for this purpose is apfs.util.

We don't currently have any mechanism (tool or API) that allows snapshot reversion. If you'd like us to provide something like this, then all I can suggest is filing an enhancement request asking for us to add it.

It seems that this command is not supported by the latest versions of macOS

Basically, yes. Snapshot was originally implemented in APFS through fsctl(APFSIOC_REVERT_TO_SNAPSHOT), however, when snapshot support was added to the full VFS layer, that block as added to prevent sending the command through the fsctl path. If you look lower in the same file, snapshot_revert first tries VFSIOC_REVERT_SNAPSHOT (the public VFS ioctl) and then tries APFSIOC_REVERT_TO_SNAPSHOT (the APFS private ioctl).

For the curious, if you're wondering why this kind of code is there, the answer is that it's a hold over from the original transition and that it's still there because it provides the most flexibility to both teams. The VFS layer originally added it because they wanted the new code path to work even if the APFS team hadn't adopted VFSIOC_REVERT_SNAPSHOT (or, more likely, if someone wanted to test something like an older APFS build). Similarly, APFS actually does support VFSIOC_REVERT_SNAPSHOT but they left APFSIOC_REVERT_TO_SNAPSHOT in place because they didn't want to worry about breaking existing stuff that was still using APFSIOC_REVERT_TO_SNAPSHOT.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thank you for your response!

We don't currently have any mechanism (tool or API) that allows snapshot reversion

I know that there is a fs_snapshot_* family of functions, and according to its manual "To revert the filesystem to a previous snapshot, the fs_snapshot_revert() can be used". This function is only available to apps/tools that have both the com.apple.developer.vfs.snapshot and the com.apple.private.apfs.revert-to-snapshot entitlements enabled. The latter seems to be available only to Apple itself. So why does the fs_snapshot_revert() function exist if it is not available to third-party developers and is not used by Apple in their tools?

By the way, I have disabled SIP and AMFI and tried calling fs_snapshot_revert(), and it worked as expected for me!

I know that there is a fs_snapshot_* family of functions, and according to its manual "To revert the filesystem to a previous snapshot, the fs_snapshot_revert() can be used". This function is only available to apps/tools that have both the com.apple.developer.vfs.snapshot and the com.apple.private.apfs.revert-to-snapshot entitlements enabled. The latter seems to be available only to Apple itself.

Yes. At this point, snapshot reversion is basically SPI that is used by the system itself.

So why does the fs_snapshot_revert() function exist if it is not available to third-party developers and is not used by Apple in their tools?

The APFS team has decided that APFS snapshot reversion is not functionality that should be generally accessible to 3rd party developers or accessible to users through our tools.

By the way, I have disabled SIP and AMFI and tried calling fs_snapshot_revert(), and it worked as expected for me!

Yes, that's expected and I'm sorry if that was unexpected. To clarify things, fs_snapshot_revert is the syscall for snapshot reversion. The introduction of that function was the reason "fsctl(APFSIOC_REVERT_TO_SNAPSHOT)" was blocked. It was an old code path and we wanted to make sure it didn't unexpectedly get used again. In any case, APFS uses an entitlement to restrict snapshot reversions, so disabling AMFI does bypass that restriction. That's not an acceptable solution for general software use, but if it meets your needs then you're welcome to use it.

__
Kevin Elliot
DTS Engineer, CoreOS/Hardware

APFS snapshot revert
 
 
Q