Les drapeaux de fonctionnalités ZFS sont une de ces idées d’ingénierie qui paraissent élégantes sur une diapositive et deviennent très personnelles à 03:17 quand vous essayez d’importer un pool sur « l’autre » hôte et qu’il refuse tout net. Ce sont les marqueurs ADN de votre pool : une fois que certains traits sont exprimés, vous ne pouvez plus faire semblant qu’ils n’existent pas. Et le pool ne se laissera pas attendrir par votre nostalgie des noyaux plus anciens, des chargeurs d’amorçage obsolètes ou de ce serveur de secours que personne n’a mis à jour parce que « c’est juste une sauvegarde ».
Ce texte porte sur la portabilité : comment déplacer des pools entre hôtes, comment les mises à jour modifient les exigences d’un pool, et comment répliquer en toute sécurité entre versions. Il est écrit du point de vue de quelqu’un qui a vu un « on le met juste à jour » se transformer en appel d’incident, et qui a aussi vu la discipline compatibilité, ennuyeuse mais prudente, sauver un week-end en silence.
Ce que sont les drapeaux de fonctionnalités (et pourquoi ils existent)
ZFS à l’ancienne avait un numéro de « version de pool ». On mettait à jour un pool de la version N à la version N+1, et ce numéro indiquait ce que le pool pouvait faire et ce dont il avait besoin. Ça a fonctionné jusqu’à un certain point : différents fournisseurs ont livré des fonctionnalités différentes sous le même numéro de version, et des gens se sont retrouvés avec des pools qui « devraient » pouvoir être importés mais ne le pouvaient pas — ou pire, qui s’importaient et se comportaient de façon étrange.
Les drapeaux de fonctionnalités ont remplacé la version monolithique par un modèle plus honnête : un pool annonce un ensemble de fonctionnalités, chacune avec son propre nom (comme feature@async_destroy ou feature@encryption) et un état. Les hôtes annoncent les fonctionnalités qu’ils comprennent. La compatibilité devient un problème d’intersection d’ensembles plutôt qu’un mensonge basé sur un entier.
Opérationnellement, les drapeaux de fonctionnalités comptent parce qu’ils sont persistants. Certaines fonctions sont seulement « enabled » et sans danger tant qu’elles ne sont pas utilisées ; d’autres deviennent « active » et modifient les structures sur disque d’une manière que les implémentations plus anciennes ne peuvent pas analyser. Une fois que cela se produit, le pool ne peut pas être importé sur un hôte qui ne prend pas en charge la fonctionnalité — peu importe vos promesses de prudence.
Blague n°1 : Les drapeaux de fonctionnalités ZFS sont comme des tatouages : faciles à faire, difficiles à enlever, et votre futur vous demandera peut‑être pourquoi vous avez pris cette décision.
Le modèle de compatibilité : enabled vs active vs supported
Quand on parle de « drapeaux de fonctionnalités », on pense souvent à « la liste que j’ai vue dans zpool get all ». Cette liste est le début, pas toute l’histoire. L’histoire, c’est la machine à états derrière chaque drapeau et ce que cet état implique pour les imports et la réplication.
État d’une fonctionnalité : disabled, enabled, active
En termes d’OpenZFS, les drapeaux de fonctionnalités se présentent généralement comme :
- disabled : le pool n’a pas la fonctionnalité activée ; rien à signaler.
- enabled : le pool connaît la fonctionnalité et peut l’utiliser à l’avenir, mais n’a pas nécessairement écrit de structures spécifiques à la fonctionnalité.
- active : le pool a utilisé la fonctionnalité ; des structures sur disque existent et nécessitent un support pour être lues (et généralement pour être importées du tout).
Toutes les fonctionnalités ne se comportent pas exactement de la même façon, mais la règle pratique est : ce sont les fonctionnalités active qui vous abandonnent sur des hôtes plus anciens. Les fonctionnalités enabled mais non active peuvent encore poser problème si l’hôte cible refuse les pools avec des fonctionnalités enabled inconnues, mais la plupart des échecs de compatibilité surviennent lorsqu’une fonctionnalité devient active.
Capacité de l’hôte : « supported » n’est pas « enabled »
Un hôte (module noyau + outils userland) prend en charge un ensemble de fonctionnalités. Cela ne veut pas dire que ces fonctionnalités sont activées sur chaque pool. Cela signifie que l’hôte peut importer des pools qui ont ces fonctionnalités actives.
Le piège courant : « Nous avons mis à jour l’OS, donc nous sommes compatibles. » Vous êtes compatible avec des pools qui requièrent au plus ce que votre hôte prend en charge. Si vous importez un pool sur un hôte plus récent, vous n’avez pas nécessairement changé le pool. Mais si vous exécutez zpool upgrade, ou si vous activez certaines propriétés de dataset (comme le chiffrement natif), vous venez peut‑être de rendre votre pool incompatible avec des hôtes plus anciens de façon permanente.
Imports en lecture seule et le mythe du « je ne toucherai à rien »
Des gens essaient de se sauver avec des imports en lecture seule. Cela peut aider dans des cas restreints (par exemple, extraire des données d’un pool légèrement endommagé), mais ce n’est pas une échappatoire universelle à la compatibilité. Si l’hôte ne comprend pas une fonctionnalité active, il ne peut pas analyser de façon fiable les métadonnées du pool — même en lecture seule. L’incompatibilité de fonctionnalité n’est pas une question de sécurité d’écriture ; c’est une question de « puis‑je comprendre ce que je regarde ».
Règles de portabilité : les trois seuls résultats qui comptent
Quand vous déplacez des pools ou répliquez entre hôtes, vous voulez prédire lequel de ces trois résultats vous obtiendrez :
Résultat 1 : Import propre (ennuyeux, souhaitable)
L’hôte cible prend en charge chaque fonctionnalité active du pool. Le pool s’importe normalement. Vous pouvez monter les datasets, lancer un scrub, resilver, faire toutes les opérations habituelles. C’est le seul résultat souhaitable pour une bascule en production.
Résultat 2 : Import refusé (échec bruyant, souvent récupérable)
L’hôte cible voit une ou plusieurs fonctionnalités actives non prises en charge et refuse d’importer. C’est perturbant, mais honnête : vous n’avez pas corrompu les données silencieusement ; on vous arrête avant de faire quelque chose de dangereux.
En pratique, cela arrive quand vous essayez d’importer un pool mis à jour sur un OpenZFS plus récent dans un environnement plus ancien (noyau de distro plus ancien, firmware d’appliance plus ancien, image de secours plus ancienne). La correction habituelle est « mettre à jour l’hôte cible » ou « ne pas mettre à jour le pool en premier lieu ». Le second n’est possible que si vous l’attrapez avant que les fonctionnalités ne s’activent.
Résultat 3 : Le pool s’importe, mais d’autres opérations échouent (furtif, coûteux en opération)
Cela est plus rare avec les drapeaux de fonctionnalités qu’avec le chaos des anciennes versions de pool, mais ça arrive encore : les flux de réplication, les chargeurs d’amorçage, les outils d’initramfs ou les logiciels de gestion peuvent ne pas comprendre de nouvelles propriétés ou comportements par défaut même si le module noyau peut importer le pool.
Exemples : environnements de démarrage qui supposent un comportement de montage hérité, images de secours sans support crypto pour une racine chiffrée, ou cibles de réplication qui acceptent les flux mais ne gèrent pas correctement les grands blocs ou les réglages de données embarquées. Le pool s’importe, mais l’écosystème autour devient l’incident.
Blague n°2 : La seule chose plus permanente qu’une mise à niveau de pool ZFS est l’invitation calendrier pour le postmortem.
Faits intéressants et contexte historique
Voici les éléments qui rendent les drapeaux de fonctionnalités logiques — et qui expliquent aussi pourquoi deux boîtes exécutant « ZFS » peuvent se comporter comme des cousins éloignés.
- ZFS a commencé chez Sun et a été livré dans Solaris ; le design original intégrait des sommes de contrôle de bout en bout et des sémantiques copy-on-write bien avant qu’elles ne soient à la mode dans les piles de stockage linux grand public.
- Les « numéros de version » des pools sont devenus un bazar parce que plusieurs descendants ont implémenté des fonctionnalités dans un ordre différent ou sous des incréments de version conflictuels, rendant la compatibilité basée sur la version peu fiable entre vendeurs.
- Les drapeaux de fonctionnalités ont été introduits pour remplacer les versions de pool afin qu’un pool puisse se décrire précisément au lieu d’utiliser un entier unique.
- OpenZFS a unifié des bases de code divergentes (Illumos, FreeBSD, ports Linux) autour d’un modèle de drapeaux de fonctionnalités partagé, mais le calendrier de sortie diffère toujours selon les plateformes.
- Le chiffrement natif est une fonctionnalité charnière : ce n’est pas qu’une propriété de dataset ; cela change les workflows de gestion des clés, le comportement send/receive et les hypothèses de reprise après sinistre.
- Certaines fonctionnalités s’activent implicitement — vous ne lancez pas toujours « enable feature » explicitement. Définir une propriété (par ex. activer des classes d’allocation spécial vdev, l’utilisation de large_dnode par certains outils) peut basculer une fonctionnalité en active.
- Les pools de démarrage sont spéciaux : le noyau peut importer un pool sans problème, mais le chargeur d’amorçage peut ne pas comprendre des fonctions sur disque plus récentes. C’est un axe de compatibilité différent que la plupart apprennent à la dure.
- Les flux de réplication encodent les exigences de fonctionnalités. Même si le pool source s’importe partout, un flux send peut nécessiter un support côté cible selon les drapeaux et propriétés.
- Les drapeaux de fonctionnalités sont namespacés (souvent avec un préfixe fournisseur ou projet historiquement), ce qui était un compromis pragmatique pour éviter les collisions durant le développement fragmenté de ZFS.
Trois micro-histoires du monde de l’entreprise
Micro-histoire 1 : L’incident causé par une mauvaise hypothèse
Ils avaient deux datacenters et un plan simple : le primaire tournait sur Linux plus récent, le DR sur une build « stable » un peu plus ancienne parce qu’« il ne fait pas grand-chose ». La réplication se faisait par ZFS send/receive. La boîte DR était traitée comme un extincteur : inspectée occasionnellement, majoritairement ignorée.
Pendant une fenêtre de maintenance, un ingénieur a mis à jour les fonctionnalités du pool primaire pour obtenir une capacité nouvelle voulue pour la performance et la gestion des snapshots. Le changement semblait anodin : zpool upgrade s’est exécuté proprement, rien n’a explosé, et les graphiques applicatifs ne bougeaient pas. L’équipe s’est félicitée et est passée à autre chose.
Deux mois plus tard, ils ont fait un test DR et découvert que la réception avait échoué en silence depuis des jours. Les flux send exigeaient désormais des fonctionnalités que l’hôte DR ne supportait pas. La surveillance n’avait pas alerté parce qu’elle ne surveillait que la présence des snapshots, pas le succès des receives incrémentaux. Quand ils ont finalement essayé d’importer le pool répliqué sur DR, il a refusé : fonctionnalités non prises en charge. La réplique n’était pas juste obsolète ; elle était inutilisable.
La récupération a été sans glamour : mises à jour d’urgence en DR, alignement du noyau et du module ZFS, reconstruction de la baseline de réplication avec un send complet. Ça a marché, mais ça leur a coûté un week-end et brûlé de la confiance. La cause racine n’était pas « ZFS est dur ». C’était la mauvaise hypothèse : considérer qu’une mise à jour de pool est une optimisation locale, pas un événement de compatibilité global.
La contre-mesure du postmortem qui a réellement compté : ils ont mis en place un « contrat de compatibilité » entre sites — jeu minimal de fonctionnalités supportées documenté, versions OpenZFS figées sur les deux sites, et un test qui tente une réception en dry-run sur DR avant toute mise à jour de pool en prod.
Micro-histoire 2 : L’optimisation qui s’est retournée contre eux
Une autre entreprise voulait accélérer les opérations méta pour une flotte de serveurs de build. Quelqu’un a lu sur les special vdevs, les classes d’allocation métadonnées et de nouveaux formats de pointeurs de blocs. L’argument était convaincant : « On va rendre les stats de fichiers et les petits fichiers fulgurants. » Ils ont déployé des NVMe, créé un special vdev, et activé un ensemble de fonctionnalités « recommandées » par la build OpenZFS la plus récente qu’ils utilisaient.
La performance s’est améliorée immédiatement. Puis est venu le retournement : pendant un cycle de rafraîchissement matériel, certains pools ont été déplacés vers des hôtes de secours plus anciens pendant la maintenance. Ces spares tournaient un OpenZFS plus ancien parce que le noyau du fournisseur prenait du retard. Soudain, des pools avec des fonctionnalités récemment actives ne pouvaient plus être importés sur les spares. Les fenêtres de maintenance se sont allongées parce que « basculer vers le spare » est devenu « d’abord, mettre à jour le spare, puis reconstruire l’initramfs, puis redémarrer, puis prier ».
Pire, ils ont découvert que l’outil d’environnement de démarrage de cette distro n’aimait pas l’ensemble de fonctionnalités plus récent du pool root, et quelques boîtes sont devenues délicates à récupérer. Rien d’irrémédiable, mais le temps de réparation a explosé. L’optimisation était réelle ; le coût opérationnel aussi, et personne ne l’avait budgété dans la décision.
Ce qu’ils ont changé : ils ont séparé les préoccupations. Ils ont cessé de traiter les « upgrades de features de pool » comme des réglages de performance. Ils ont figé les pools de boot sur l’ensemble minimal de fonctionnalités supportées par les outils de boot, et isolé l’utilisation agressive des fonctionnalités aux pools de données qui n’ont pas besoin d’être démarrés sur des environnements de secours étranges. Les serveurs de build ont gardé leur vitesse ; la rotation on-call a retrouvé son sommeil.
Micro-histoire 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Cette équipe exploitaient des hôtes mixtes : certains sur FreeBSD pour les services réseau, d’autres sur Linux pour le calcul, tous partageant une stratégie de sauvegarde basée sur ZFS. L’environnement n’était pas tape-à-l’œil, mais il était discipliné. Chaque trimestre, ils faisaient un « drill de portabilité de pool » : exporter un pool non critique et l’importer sur un hôte de secours exécutant la pile ZFS la plus ancienne supportée dans la flotte.
Ça ressemblait à du travail inutile jusqu’au jour où ça a payé. Un hôte de production a eu une panne de carte mère, et la façon la plus rapide de s’en sortir était de câbler les disques sur une machine de secours. Le spare était plus ancien et n’avait pas été mis à jour depuis des mois. Dans beaucoup d’orgs, ça aurait été le début d’une mauvaise journée.
Au lieu de ça, le pool s’est importé proprement, parce que l’équipe avait une règle : pas de mise à jour de pool à moins que chaque hôte du matrice de support puisse importer le pool, et pas de nouvelle fonctionnalité activée sans test de portabilité. Ils gardaient aussi un petit ensemble d’images de récupération « connues bonnes » avec le support ZFS correspondant.
L’incident a quand même fait mal — le matériel, ça fait toujours mal — mais il est resté dans la catégorie « remplacer des pièces, importer le pool, reprendre le service ». Pas de drapeaux de fonctionnalités surprises, pas de verrouillage accidentel, pas de mises à jour d’OS frénétiques sous pression. Leur victoire était ennuyeuse, ce qui est le plus grand compliment qu’on puisse faire à une pratique SRE.
Tâches pratiques : commandes que vous exécuterez réellement
L’objectif ici est de vous donner de la mémoire musculaire opérationnelle : comment inspecter les fonctionnalités, prédire les imports et gérer les upgrades sans les transformer en roulette. Les commandes sont montrées avec des fragments de sortie typiques et comment les interpréter. Ajustez les noms de pool et de datasets si nécessaire.
Task 1: Identify ZFS and zpool versions on a host
cr0x@server:~$ zfs version
zfs-2.2.4-1
zfs-kmod-2.2.4-1
Interprétation : Le userland et le module noyau OpenZFS de cet hôte sont alignés. Un désalignement (userland plus récent que le module) peut provoquer des comportements déroutants ; pour la planification de portabilité, vous vous intéressez au support effectif des fonctionnalités par le module.
Task 2: List pools and confirm health before you touch anything
cr0x@server:~$ zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 3.62T 1.88T 1.74T - - 18% 51% 1.00x ONLINE -
Interprétation : Ne faites pas de travaux sur les fonctionnalités d’un pool qui est dégradé, en cours de resilver ou affichant des erreurs I/O à moins que votre objectif soit la récupération. Les upgrades n’endommagent pas habituellement les pools sains, mais ils réduisent vos voies de sortie.
Task 3: See which feature flags exist on the pool and their states
cr0x@server:~$ zpool get all tank | grep '^tank feature@' | head
tank feature@async_destroy enabled local
tank feature@bookmarks enabled local
tank feature@embedded_data active local
tank feature@enabled_txg active local
tank feature@extensible_dataset active local
Interprétation : Toute ligne active est une exigence dure : importer ce pool requiert un hôte qui supporte cette fonctionnalité. Les lignes enabled peuvent devenir des exigences plus tard si la fonctionnalité s’active.
Task 4: Show unsupported features on this host (pre-check imports)
cr0x@server:~$ zpool get -H -o value unsupported@features tank
-
Interprétation : Un tiret signifie typiquement « aucun ». Si vous voyez une liste, vous avez déjà un décalage (par exemple, vous avez importé le pool sur un hôte qui peut le lire mais qui manque d’une capacité attendue par les outils, ou vous vérifiez sur une pile partiellement compatible).
Task 5: Predict what zpool upgrade would do (do not run it yet)
cr0x@server:~$ zpool upgrade -v
This system supports ZFS pool feature flags.
The following features are supported:
FEAT DESCRIPTION
async_destroy Destroy filesystems asynchronously.
embedded_data Blocks which compress very well are stored embedded in metadata.
encryption Dataset level encryption.
Interprétation : Cela montre ce que l’hôte courant supporte, pas ce dont votre pool a besoin. Le geste dangereux est de mettre à jour un pool sur un hôte qui supporte plus que le reste de votre flotte.
Task 6: Check if a pool has pending feature upgrades available
cr0x@server:~$ zpool status
pool: tank
state: ONLINE
status: Some supported features are not enabled on the pool. The pool can
still be used, but some features are unavailable.
action: Enable all features using 'zpool upgrade'. Once this is done,
the pool may no longer be accessible by software that does not support
the features. See zpool-features(7) for details.
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
sda ONLINE 0 0 0
Interprétation : Ce message est ZFS qui est à la fois utile et dangereux. « Some supported features are not enabled » n’est pas un problème en soi ; c’est un compromis. La ligne d’action est la partie qui peut laisser le pool sur des hôtes plus anciens.
Task 7: Safely check importability on a target host (without importing)
cr0x@drhost:~$ sudo zpool import
pool: tank
id: 1234567890123456789
state: ONLINE
action: The pool can be imported using its name or numeric identifier.
config:
tank ONLINE
sda ONLINE
Interprétation : Si le pool apparaît avec un message « can be imported », l’hôte cible supporte probablement les fonctionnalités actives. S’il se plaint de fonctionnalités non supportées, arrêtez et corrigez le décalage de version de l’hôte cible avant la bascule.
Task 8: Attempt a read-only import for inspection (when you’re cautious)
cr0x@drhost:~$ sudo zpool import -o readonly=on -N tank
cr0x@drhost:~$ zpool status tank
pool: tank
state: ONLINE
Interprétation : -N importe sans monter les datasets. C’est une manière sûre d’inspecter les drapeaux et propriétés sur un hôte cible pendant une répétition de migration. Cela ne résout pas le manque de support des fonctionnalités ; ça réduit seulement le risque d’altérer les données lors de l’inspection.
Task 9: Confirm feature states after import on the target
cr0x@drhost:~$ zpool get all tank | grep '^tank feature@' | grep -E 'active|enabled' | head
tank feature@async_destroy enabled local
tank feature@embedded_data active local
tank feature@extensible_dataset active local
Interprétation : Comparez cette sortie entre hôtes. Si un hôte peut importer mais rapporte des bizarreries (fonctionnalités manquantes dans les outils), vous pouvez avoir un désalignement userland/module ou un userland plus ancien incapable d’afficher proprement tous les états.
Task 10: Identify encryption usage and key status (compatibility landmine)
cr0x@server:~$ zfs get -r -o name,property,value -s local,received encryption,keylocation,keystatus tank | head -n 12
NAME PROPERTY VALUE SOURCE
tank encryption off default
tank/secure encryption aes-256-gcm local
tank/secure keylocation prompt local
tank/secure keystatus unavailable -
Interprétation : Les datasets chiffrés exigent un support côté cible pour la fonctionnalité de chiffrement et des workflows de gestion de clés. Si le DR ne peut pas charger les clés (ou ne supporte pas le chiffrement), vous n’avez pas de DR — juste du texte chiffré coûteux.
Task 11: Test a replication receive in a safe sandbox dataset
cr0x@source:~$ sudo zfs snapshot -r tank/app@replica-test
cr0x@source:~$ sudo zfs send -R tank/app@replica-test | ssh drhost sudo zfs receive -uF tank/replica-sandbox
Interprétation : C’est un test pratique de compatibilité : si la réception échoue avec des erreurs liées aux fonctionnalités, vous le saurez maintenant plutôt que pendant une panne. -u évite le montage automatique ; -F force le rollback sur le chemin cible si nécessaire (à utiliser avec précaution).
Task 12: Inspect why a receive failed (look for feature requirements)
cr0x@drhost:~$ sudo zfs receive -uF tank/replica-sandbox < /tmp/stream.zfs
cannot receive: stream has unsupported feature(s)
Interprétation : Le flux exige quelque chose que la cible ne peut pas faire. Cela peut être une fonctionnalité plus récente dans le stream send, ou une propriété qui nécessite un drapeau de fonctionnalité. La correction est généralement « mettre à jour OpenZFS sur la cible » ou « changer le mode/propriétés de réplication pour éviter cette exigence », selon le contenu du flux.
Task 13: Freeze a pool’s portability by refusing feature upgrades (policy, not tech)
cr0x@server:~$ sudo zpool status tank | sed -n '1,12p'
pool: tank
state: ONLINE
status: Some supported features are not enabled on the pool. The pool can
still be used, but some features are unavailable.
Interprétation : La décision « ennuyeuse » est de laisser les choses ainsi. Si vous devez supporter des hôtes de secours plus anciens ou des imports cross-plateforme, ne pas upgrader les fonctionnalités est un choix délibéré de compatibilité.
Task 14: Perform a controlled pool feature upgrade (when you’ve earned it)
cr0x@server:~$ sudo zpool upgrade tank
This system supports ZFS pool feature flags.
Successfully upgraded 'tank'.
Interprétation : Cela active toutes les fonctionnalités supportées par cet hôte. Elles ne s’activent pas forcément immédiatement, mais vous avez modifié les capacités déclarées du pool. Traitez cela comme une porte sans retour pour la portabilité vers des hôtes plus anciens.
Task 15: Verify boot pool constraints (don’t brick your reboot)
cr0x@server:~$ zpool list -o name,size,health,altroot
NAME SIZE HEALTH ALTROOT
rpool 238G ONLINE -
tank 3.62T ONLINE -
Interprétation : Si rpool est votre pool de boot, soyez conservateur. Un pool de données bloqué sur des hôtes plus anciens est ennuyeux ; un pool de boot rendu incompatible avec votre chargeur d’amorçage est catastrophique d’une manière très spécifique et longue à réparer.
Task 16: Export a pool cleanly before moving disks between hosts
cr0x@server:~$ sudo zpool export tank
cr0x@server:~$ zpool list
no pools available
Interprétation : Un export propre réduit les frictions d’import et évite la confusion « pool in use ». Ça ne change pas les drapeaux de fonctionnalités, mais ça évite les problèmes de cache hôte et rend le prochain import plus propre.
Playbook de diagnostic rapide
Voici le playbook « j’ai dix minutes avant que la réunion ne devienne un incident ». L’objectif est de trouver si vous avez affaire à une incompatibilité de fonctionnalités, un décalage de version, ou un goulot d’étranglement de performance qui ressemble à une incompatibilité.
Étape 1 : Est-ce un échec de compatibilité dur ou un échec général d’import ?
cr0x@target:~$ sudo zpool import
pool: tank
id: 1234567890123456789
state: UNAVAIL
status: The pool uses the following feature(s) not supported by this system:
com.datto:encryption
action: The pool cannot be imported. Access the pool on a system that supports
the required feature(s), or restore the pool from backup.
Interprétation : Si vous voyez un « feature(s) not supported » explicite, arrêtez de déboguer les disques et commencez à déboguer les versions. Ce n’est pas un problème d’I/O ; c’est un décalage de capacité logicielle.
Étape 2 : Confirmez ce que l’hôte cible supporte
cr0x@target:~$ zfs version
zfs-2.1.11
zfs-kmod-2.1.11
Interprétation : Si l’hôte source est sur 2.2.x et le cible sur 2.1.x, vous devez supposer que des incompatibilités de fonctionnalités sont possibles. Alignez les versions de façon intentionnelle ; ne comptez pas sur l’intersection qui se débrouillera.
Étape 3 : Si l’import fonctionne mais que la performance est catastrophique, vérifiez la charge évidente du pool
cr0x@target:~$ zpool iostat -v tank 1 5
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 1.88T 1.74T 120 980 8.2M 112M
sda - - 60 490 4.1M 56M
sdb - - 60 490 4.1M 56M
Interprétation : Si vous êtes lié par la bande passante ou par les IOPS pendant un import/receive/scrub, vous pouvez attribuer à tort « c’est bloqué » à la compatibilité. L’incompatibilité de fonctionnalité échoue vite et bruyamment ; les problèmes de performance échouent lentement et de manière ambiguë.
Étape 4 : Vérifiez si un resilver ou un scrub monopolise la machine
cr0x@target:~$ zpool status tank | sed -n '1,25p'
pool: tank
state: ONLINE
scan: resilver in progress since Tue Dec 24 22:10:01 2025
312G scanned at 1.20G/s, 58.4G issued at 230M/s, 312G total
58.4G resilvered, 18.72% done, 0 days 00:18:22 to go
Interprétation : Un resilver peut rendre les receives et imports « lents » ou « bloqués ». Ce n’est pas un problème de drapeaux de fonctionnalités ; c’est de la physique. Si vous avez besoin de rapidité, reportez les receives ou limitez les workloads concurrents.
Étape 5 : Si la réplication échoue, reproduisez avec un petit stream
cr0x@source:~$ sudo zfs create -o mountpoint=none tank/_compat_test
cr0x@source:~$ sudo zfs snapshot tank/_compat_test@x
cr0x@source:~$ sudo zfs send tank/_compat_test@x | ssh target sudo zfs receive -u tank/_compat_rx
Interprétation : Un stream minimal aide à isoler si l’échec concerne les propriétés/fonctionnalités du dataset ou le pipeline (ssh, buffering, quotas, espace cible).
Erreurs courantes, symptômes et correctifs
Mistake 1: Upgrading the pool on one host and assuming the rest will cope
Symptôme : Le DR refuse l’import avec « unsupported feature(s) » ou des erreurs de receive de réplication après une maintenance apparemment sans rapport.
Correction : Alignez les versions OpenZFS sur tous les hôtes susceptibles d’importer le pool. Si ce n’est pas possible, ne lancez pas zpool upgrade sur ce pool. Traitez les upgrades de pool comme un changement à l’échelle de la flotte.
Mistake 2: Treating boot pools like data pools
Symptôme : Le système importe le pool en environnement de secours mais ne démarre pas normalement ; ou démarre de façon intermittente après l’activation de nouvelles fonctionnalités.
Correction : Gardez les pools de boot sur des ensembles de fonctionnalités conservateurs. Validez le support du chargeur d’amorçage avant d’activer des fonctionnalités. Testez des redémarrages réels, pas seulement des imports.
Mistake 3: Confusing “enabled” features with “active” consequences
Symptôme : Le pool s’est importé sur un hôte plus ancien le mois dernier, mais refuse maintenant après un changement de propriété ou une nouvelle charge de travail.
Correction : Suivez quelles fonctionnalités peuvent devenir actives en raison de changements opérationnels. Quand vous activez une propriété qui dépend d’une fonctionnalité, supposez qu’elle peut s’activer immédiatement et changer la portabilité.
Mistake 4: Replicating without testing receives on the oldest target
Symptôme : La réplication incrémentale commence à échouer, mais la surveillance ne vérifie que la présence de snapshots ou les codes de sortie des jobs send sont ignorés.
Correction : Implémentez une vérification explicite des receives et alertez sur les sorties non nulles. Effectuez périodiquement un petit test end-to-end send/receive.
Mistake 5: Thinking read-only import solves unsupported feature flags
Symptôme : Vous essayez -o readonly=on et vous ne pouvez toujours pas importer ; la frustration monte.
Correction : Si l’hôte ne supporte pas une fonctionnalité active, il vous faut un hôte qui la supporte. La lecture seule change seulement le comportement d’écriture, pas la compréhension des métadonnées.
Mistake 6: Userland and kernel module mismatch
Symptôme : Rapports étranges de fonctionnalités, propriétés manquantes, ou outils qui se comportent différemment entre hôtes avec des paquets apparemment « mêmes versions ».
Correction : Vérifiez que zfs version montre un userland et un module alignés. Sur Linux, assurez-vous que DKMS/kmod et les paquets userland correspondent. Recréez l’initramfs si nécessaire après des mises à jour.
Mistake 7: Importing pools on random rescue media
Symptôme : Le pool ne s’importe pas pendant la récupération, mais s’importe bien sur l’hôte de production.
Correction : Maintenez un environnement de récupération connu bon qui correspond à votre ensemble de fonctionnalités ZFS en production. Testez-le chaque trimestre. Traitez les outils de récupération comme une partie du système.
Checklists / plan étape par étape
Checklist A: Before enabling new features or running zpool upgrade
- Inventoriez chaque hôte qui pourrait avoir besoin d’importer le pool (production, DR, standby, sauvegarde, images de secours).
- Notez les versions OpenZFS sur chaque hôte avec
zfs version. - Sur le pool, listez les fonctionnalités actives :
zpool get all POOL | grep '^POOL feature@' | grep active. - Sur chaque hôte cible, exécutez
zpool import(avec les disques visibles) pour confirmer qu’il peut au moins voir le pool et ne se plaint pas des fonctionnalités. - Faites un test send/receive en bac à sable vers l’hôte le plus ancien du matrix.
- Pour les pools de boot, validez le chemin de redémarrage : chargeur d’amorçage, initramfs, chargement de clés (si chiffré) et procédure de rollback.
- Ce n’est qu’ensuite que vous décidez si la nouvelle fonctionnalité vaut la perte de portabilité.
Checklist B: Migration between hosts (export/import) without surprises
- Sur la source : confirmez la santé du pool (
zpool status), l’état du scrub et les compteurs d’erreurs. - Sur la source : capturez un snapshot des fonctionnalités et propriétés du pool pour les archives :
zpool get all POOL | grep feature@zfs get -r all POOL > /var/tmp/pool-properties.txt(attention aux informations sensibles)
- Exportez proprement :
zpool export POOL. - Sur la cible : vérifiez les versions ; assurez-vous que le module noyau est chargé.
- Sur la cible : exécutez
zpool importpour vérifier l’absence de plaintes sur les fonctionnalités. - Importez d’abord avec
-Npour inspection, puis montez intentionnellement.
Checklist C: Replication compatibility across versions
- Identifiez la version de receiver la plus ancienne que vous devez supporter.
- Testez les receives avec un dataset minimal (voir le playbook).
- Pour les datasets chiffrés, vérifiez les workflows de chargement de clés sur le récepteur avant de l’appeler « replica ».
- Alertez explicitement sur les échecs de receive ; n’inférez pas la santé de la réplication à partir des seuls snapshots.
- Quand vous mettez à jour les fonctionnalités du pool, relancez immédiatement les tests de réplication.
FAQ
1) If I upgrade OpenZFS on a host, does that upgrade my pools?
Non. Mettre à jour le logiciel augmente ce que l’hôte peut supporter. Vos pools conservent leurs états de fonctionnalités existants jusqu’à ce que vous activiez explicitement des fonctionnalités (via zpool upgrade) ou que des fonctionnalités s’activent indirectement (via des propriétés/workloads qui en dépendent).
2) Is zpool upgrade reversible?
Pratiquement, non. Vous pouvez parfois « éviter d’activer » certaines fonctionnalités en ne les utilisant pas, mais une fois qu’une fonctionnalité est active et que le pool a écrit des structures qui la requièrent, vous ne pouvez pas rétrograder le pool pour qu’il soit importable sur des hôtes plus anciens.
3) What’s the difference between “enabled” and “active” in terms of portability?
Active signifie que le pool utilise la fonctionnalité et que les hôtes plus anciens qui ne la supportent pas refuseront l’import. Enabled signifie que le pool peut l’utiliser plus tard. Les fonctionnalités enabled peuvent encore compter, mais les fonctionnalités active constituent le mur dur habituel.
4) Can I import a pool on an older host if I promise not to mount it or write to it?
Si l’hôte manque le support d’une fonctionnalité active, il ne peut généralement pas importer le pool du tout — en lecture seule ou non — parce qu’il ne peut pas interpréter les métadonnées nécessaires en toute sécurité.
5) Why did replication start failing after months of working?
Soit le pool source a activé une fonctionnalité (peut‑être via un changement de propriété), soit le flux send contient désormais des exigences que le récepteur ne peut satisfaire. Une autre cause fréquente est que le récepteur a été mis à jour/retrofait involontairement et a perdu du support ou l’alignement des outils.
6) Does cross-platform ZFS (Linux ↔ FreeBSD) change the rules?
La logique de base des drapeaux de fonctionnalités est la même, mais le calendrier de sortie diffère. Une fonctionnalité courante sur une plateforme peut être en retard sur une autre. Traitez les « différences de plateforme » comme des « différences de version » et testez les imports et receives sur les builds exacts que vous exécutez.
7) Should I always run zpool upgrade to get rid of the status warning?
Non. Ce message est informatif, pas une alarme de fiabilité. Laisser un pool non‑upgradé est une stratégie valide quand la portabilité compte — en particulier pour les pools amovibles, les imports DR ou les environnements hétérogènes.
8) How do I design a safe compatibility policy for a fleet?
Choisissez une version OpenZFS minimale que chaque hôte pertinent doit exécuter. N’activez que les fonctionnalités de pool supportées par cette minimale. Quand vous avez besoin d’une nouvelle fonctionnalité, traitez-la comme une migration de schéma : mettez d’abord à niveau les hôtes, puis les pools en dernier, et testez DR/réplication à chaque étape.
9) What about encrypted datasets—are they compatible with send/receive everywhere?
Le chiffrement introduit des exigences supplémentaires : le récepteur doit supporter la fonctionnalité de chiffrement et votre mode de réplication doit s’aligner sur vos objectifs de gestion des clés. Même quand le pool s’importe, la préparation opérationnelle dépend de la possibilité de charger les clés et de la façon dont vous gérez keylocation et keystatus en DR.
10) What’s the single safest habit with feature flags?
Supposez que toute mise à niveau de fonctionnalité de pool est une perte de portabilité. Si vous êtes d’accord avec ce compromis, procédez délibérément ; sinon, ne vous laissez pas intimider par un message de statut et n’appuyez pas sur le bouton.
Conclusion
Les drapeaux de fonctionnalités ZFS ne sont pas de la trivia ; ils sont le contrat de votre pool avec chaque machine susceptible d’en lire le contenu sous pression. Ils rendent la compatibilité plus explicite que l’ancien système de version de pool, mais ils rendent aussi les mises à niveau plus lourdes de conséquences : vous ne pouvez pas rester portable accidentellement une fois que vous avez franchi le seuil d’une fonctionnalité.
Si vous ne retenez qu’une chose, retenez ceci : mettez d’abord à niveau les hôtes, validez les imports et les receives sur l’environnement le plus ancien, et ne mettez les pools à niveau qu’en dernier. Les équipes qui font cela ont l’air ennuyeuses dans les revues de changement. Elles ont aussi l’air brillantes le jour où la machine de secours devient la machine de production.