Describe the feature you would like to see added to OpenZFS
I would like OpenZFS to support converting an existing plaintext filesystem dataset into a native encrypted dataset without requiring a second full-size copy of the dataset.
Today, native encryption must be selected when the dataset is created. For large existing plaintext datasets, the practical migration path is to create a new encrypted dataset and move data into it with zfs send | zfs receive, rsync, or a backup/restore workflow. That is safe when spare capacity exists, but it breaks down for large pools where used data is greater than half the pool size and no external temporary capacity is available.
This proposal is for a new filesystem-native conversion feature, not encryption below ZFS. The intended result is a real OpenZFS native encrypted dataset with normal native-encryption behavior after conversion completes.
One possible interface would be an encrypt command with mode options:
zfs encrypt [--dry-run] pool/dataset
zfs encrypt --status pool/dataset
zfs encrypt --resume pool/dataset
zfs encrypt --abort pool/dataset
Names are illustrative. The important part is the behavior: a resumable conversion that rewrites the dataset's logical block tree from plaintext blocks to encrypted replacement blocks in bounded batches using normal ZFS copy-on-write semantics.
The central safety invariant should be:
A plaintext block reference is never released until its encrypted replacement has been written, read back, decrypted, verified, and committed through normal ZFS transaction semantics.
For a first version, strict eligibility rules seem reasonable:
- filesystem datasets only; no zvols;
- dataset is currently unencrypted;
- no snapshots;
- no clones;
- no bookmarks;
- no dedup support during conversion;
- dataset is unmounted or mounted read-only;
- pool is healthy;
- no active scrub, resilver, trim, device removal, checkpoint discard, or similar pool-wide operation;
- sufficient free space exists for at least one conversion batch plus metadata overhead.
The no-snapshots/no-clones restriction is painful, but it removes one of the hardest v1 problems: shared historical references to plaintext blocks. A limited safe feature would still be useful.
How will this feature improve OpenZFS?
This would let administrators adopt OpenZFS native encryption for existing large datasets without buying or temporarily attaching enough storage to hold a full second copy of the data.
The user-visible problem is common:
- a pool was created before native encryption was required;
- the dataset now contains tens of TB of data;
- the data should be encrypted at rest;
- creating a full duplicate encrypted copy is impractical because of capacity, cost, time, and device wear;
- the administrator wants native ZFS encryption rather than LUKS/GELI or another block-device encryption layer underneath ZFS.
A constrained converter would fill the gap between "recreate the dataset" and "leave historical data plaintext forever."
This is intentionally not a per-disk migration. RAIDZ redundancy is valuable for pool health, but native encryption lives at the logical block/dataset layer, so conversion needs to operate on object sets, dnodes, block pointers, indirect blocks, and dataset metadata.
Additional context
I am interested in working on this, but I would like maintainer feedback before attempting an implementation. The proposal below is intentionally strict for v1 because safety and recovery semantics matter more than broad initial coverage.
The dataset should persist explicit conversion state, for example:
none
preflight
converting
verifying
failed-needs-resume
committed
abortable
Normal read-write import should fail if any dataset is in an incomplete conversion state, unless import is happening through the explicit conversion resume path.
Read-only import should remain available for diagnostics:
zpool import -o readonly=on pool
zfs encrypt --status pool/dataset
Normal read-write import should fail with a clear diagnostic, for example:
pool contains dataset pool/dataset in incomplete native encryption conversion;
import read-only for diagnostics or resume conversion with zfs encrypt --resume pool/dataset
For v1, normal scrub should probably refuse to run during conversion unless a conversion-aware scrub mode is explicitly implemented.
Abort should be conservative:
- abort is allowed only before any plaintext references have been released;
- after plaintext references have been released, the supported recovery path is resume-to-completion;
- a partially converted dataset must never silently appear as normal read-write storage.
This feature would need fault-injection tests before it should be trusted. Minimum coverage should include:
- empty dataset conversion;
- small files;
- large files spanning indirect blocks;
- xattrs, ACLs, and spill blocks;
- compression enabled;
- multiple record sizes;
- crash after encrypted replacement write and before metadata commit;
- crash after metadata commit and before plaintext free completion;
- read-only import exposes diagnostic state but does not allow writes;
- normal import refuses incomplete conversion;
- resume completes after each injected failure point;
- abort is allowed only before plaintext release;
- preflight rejects snapshots, clones, bookmarks, zvols, mounted read-write datasets, unhealthy pools, and active scrub/resilver.
Known hard areas:
- metadata conversion, especially dnodes, indirect blocks, ZAPs, spill blocks, xattrs, ACLs, and embedded data;
- encryption root creation and key hierarchy metadata;
- crash recovery during partially committed batches;
- space exhaustion during a batch;
zfs send / zfs receive behavior for converted datasets;
- scrub behavior against mixed conversion state;
- compatibility with older OpenZFS implementations.
Open questions for maintainers:
- Is this feature direction acceptable in principle if v1 is strictly limited?
- Is a new incompatible feature flag the right compatibility boundary?
- Should conversion be implemented as
zfs encrypt with mode options, a mode of an existing rewrite/remap mechanism if one exists, or another interface?
- Should read-only diagnostic import be allowed during incomplete conversion?
- Is refusing normal scrub during conversion acceptable for v1?
- Are there existing internal rewrite/remap facilities that would be a better implementation starting point?
- Are snapshots/clones/dedup restrictions acceptable for an initial proposal?
Current OpenZFS documentation describes native encryption as a dataset creation-time property that cannot be changed afterward. Existing migration guidance effectively requires creating a new encrypted dataset and moving data into it.
Relevant references:
I did not find an obvious existing issue or accepted proposal for this exact plaintext-to-native-encrypted conversion feature. If there is prior art or an existing design discussion, pointers would be appreciated.
Describe the feature you would like to see added to OpenZFS
I would like OpenZFS to support converting an existing plaintext filesystem dataset into a native encrypted dataset without requiring a second full-size copy of the dataset.
Today, native encryption must be selected when the dataset is created. For large existing plaintext datasets, the practical migration path is to create a new encrypted dataset and move data into it with
zfs send | zfs receive,rsync, or a backup/restore workflow. That is safe when spare capacity exists, but it breaks down for large pools where used data is greater than half the pool size and no external temporary capacity is available.This proposal is for a new filesystem-native conversion feature, not encryption below ZFS. The intended result is a real OpenZFS native encrypted dataset with normal native-encryption behavior after conversion completes.
One possible interface would be an
encryptcommand with mode options:Names are illustrative. The important part is the behavior: a resumable conversion that rewrites the dataset's logical block tree from plaintext blocks to encrypted replacement blocks in bounded batches using normal ZFS copy-on-write semantics.
The central safety invariant should be:
For a first version, strict eligibility rules seem reasonable:
The no-snapshots/no-clones restriction is painful, but it removes one of the hardest v1 problems: shared historical references to plaintext blocks. A limited safe feature would still be useful.
How will this feature improve OpenZFS?
This would let administrators adopt OpenZFS native encryption for existing large datasets without buying or temporarily attaching enough storage to hold a full second copy of the data.
The user-visible problem is common:
A constrained converter would fill the gap between "recreate the dataset" and "leave historical data plaintext forever."
This is intentionally not a per-disk migration. RAIDZ redundancy is valuable for pool health, but native encryption lives at the logical block/dataset layer, so conversion needs to operate on object sets, dnodes, block pointers, indirect blocks, and dataset metadata.
Additional context
I am interested in working on this, but I would like maintainer feedback before attempting an implementation. The proposal below is intentionally strict for v1 because safety and recovery semantics matter more than broad initial coverage.
The dataset should persist explicit conversion state, for example:
nonepreflightconvertingverifyingfailed-needs-resumecommittedabortableNormal read-write import should fail if any dataset is in an incomplete conversion state, unless import is happening through the explicit conversion resume path.
Read-only import should remain available for diagnostics:
Normal read-write import should fail with a clear diagnostic, for example:
For v1, normal scrub should probably refuse to run during conversion unless a conversion-aware scrub mode is explicitly implemented.
Abort should be conservative:
This feature would need fault-injection tests before it should be trusted. Minimum coverage should include:
Known hard areas:
zfs send/zfs receivebehavior for converted datasets;Open questions for maintainers:
zfs encryptwith mode options, a mode of an existing rewrite/remap mechanism if one exists, or another interface?Current OpenZFS documentation describes native encryption as a dataset creation-time property that cannot be changed afterward. Existing migration guidance effectively requires creating a new encrypted dataset and moving data into it.
Relevant references:
zfsprops(7), encryption property:https://openzfs.github.io/openzfs-docs/man/v2.3/7/zfsprops.7.html
zfs receive(8):https://openzfs.github.io/openzfs-docs/man/master/8/zfs-receive.8.html
https://openzfs.github.io/openzfs-docs/msg/ZFS-8000-ER/index.html
Repair encryption hierarchy of 'send -Rw | recv -d' datasets that do not bring their encryption root #12000
I did not find an obvious existing issue or accepted proposal for this exact plaintext-to-native-encrypted conversion feature. If there is prior art or an existing design discussion, pointers would be appreciated.