
Outils de réparation BTRFS personnalisés pour corruption grave de l'arbre d'extents lorsque btrfs check --repair échoue (segfault, boucle ou blocage)
Outils personnalisés écrits lors de la récupération d'un pool BTRFS multi-périphériques de 12 To avec une corruption sévère de l'arbre des extents que les commandes natives (btrfs check --repair, --init-extent-tree, etc.) n'ont pas pu réparer.
Voir INCIDENT-ANALYSIS.md pour une étude de cas structurée de la récupération, une classification des causes profondes et un ensemble de propositions constructives pour des améliorations en amont de btrfs-progs qui auraient évité le besoin de la plupart de ces outils.
Utilisez ces outils UNIQUEMENT si btrfs check --repair fait un segfault, entre dans une boucle infinie, ou laisse le système de fichiers dans un état pire qu'avant.
Cas documentés où ils aident :
btrfs check --repair fait un segfault à [3/8] checking extents (Issue #525)btrfs check --init-extent-tree se bloque (deadlock)btrfs check --repair entre dans une boucle infinie en répétant les mêmes réparationsrescue=all,ro, échoue à monter en RWCes outils ne sont PAS pour des corruptions légères. Pour des dégâts normaux, essayez d'abord btrfs check --repair.
--write :
for DEV in sda1 sdb1 sdc1; do
sudo dd if=/dev/$DEV of=sb_${DEV}.bin bs=4096 count=1 skip=16
done
--write est optionnel)Les outils utilisent l'API interne de btrfs-progs et doivent être compilés à l'intérieur de l'arborescence source de btrfs-progs :
# 1. Clone btrfs-progs
git clone --depth 1 --branch v6.19.1 https://github.com/kdave/btrfs-progs.git
cd btrfs-progs
# 2. Apply the EEXIST patch (required for batch backref injection)
patch -p1 < path/to/btrfs_fixes/patches/alloc_reserved_tree_block_eexist.patch
# 3. Configure and build base btrfs-progs
./autogen.sh
./configure
make -j$(nproc)
# 4. Copy the .c files from this repo into the btrfs-progs directory
cp path/to/btrfs_fixes/programs/*.c .
# 5. For each program, add to the Makefile:
echo '
PROGNAME: PROGNAME.o $(objects) $(libs_shared)
@echo " [LD] $@"
$(Q)$(CC) -o $@ PROGNAME.o $(objects) $(libs_shared) $(LDFLAGS) $(LIBS)
' >> Makefile
# 6. Build
make PROGNAME
Ordre d'exécution recommandé :
scan_and_fix_all_backrefs.c (le plus important)L'outil le plus important. Parcourt récursivement chaque arbre du système de fichiers (ROOT, CHUNK, EXTENT, FS, DEV, CSUM, UUID, FREE_SPACE) et détecte les blocs de métadonnées qui n'ont pas de METADATA_ITEM de backref dans l'arbre des extents. Injecte tous les backrefs manquants en une seule transaction pour éviter le problème de "déplacement de l'arbre racine entre les commits".
Utilisation :
sudo ./scan_and_fix_all_backrefs /dev/sdX # scan only
sudo ./scan_and_fix_all_backrefs /dev/sdX --write # scan + inject
fix_owner_refs.cCorrige le owner dans le TREE_BLOCK_REF en ligne lorsqu'il ne correspond pas au vrai btrfs_header_owner() du bloc. Les discordances surviennent lorsque des blocs sont réassignés entre arbres lors de réparations échouées.
sudo ./fix_owner_refs /dev/sdX # scan
sudo ./fix_owner_refs /dev/sdX --write # fix
fix_bad_levels.cCorrige les entrées METADATA_ITEM et EXTENT_ITEM avec un niveau incorrect. Les niveaux corrompus (par exemple 50, 55, 237) sont des déchets laissés par btrfs check --repair entrant dans une boucle. Vérifié par rapport au vrai btrfs_header_level() du bloc.
sudo ./fix_bad_levels /dev/sdX # scan
sudo ./fix_bad_levels /dev/sdX --write # fix
fix_duplicate_extents.cSupprime les METADATA_ITEM en double (même bytenr, niveaux différents dans la clé). Garde celui dont le niveau correspond à btrfs_header_level et supprime l'autre.
sudo ./fix_duplicate_extents /dev/sdX # scan
sudo ./fix_duplicate_extents /dev/sdX --write # delete duplicates
remove_stale_ptrs.cScanne chaque nœud de niveau 1 du FS_TREE. Détecte les pointeurs enfants obsolètes à l'aide de trois vérifications : discordance d'owner, discordance de first_key, ou une first_key dont le type est invalide pour le FS_TREE (par exemple BLOCK_GROUP_ITEM). Les supprime avec btrfs_del_ptr.
sudo ./remove_stale_ptrs /dev/sdX # scan
sudo ./remove_stale_ptrs /dev/sdX --write # remove
fix_uuid_tree.c / fix_csum_tree.cCrée une feuille vide pour l'arbre UUID / l'arbre CSUM respectivement. Utile lorsque le ROOT_ITEM pointe vers un bloc qui a été réassigné à un autre arbre. Le noyau régénère automatiquement l'arbre UUID lors du montage RW. Avec un arbre CSUM vide, les fichiers marqués NODATASUM n'échouent pas à la vérification.
sudo ./fix_uuid_tree /dev/sdX
sudo ./fix_csum_tree /dev/sdX
set_nodatasum.cDéfinit le flag BTRFS_INODE_NODATASUM sur les inodes de fichiers réguliers. Utilisez ceci si l'arbre csum est vide mais que les fichiers ont toujours des sommes de contrôle attendues, ce qui cause des erreurs de lecture. Avec NODATASUM, le noyau ignore les recherches csum.
sudo ./set_nodatasum /dev/sdX # scan
sudo ./set_nodatasum /dev/sdX --write # apply
fix_fstree_node.cVersion avec une liste codée en dur de blocs obsolètes. Préférez remove_stale_ptrs, qui les détecte automatiquement. Utilisez-le uniquement si vous avez besoin d'un contrôle manuel sur les blocs spécifiques à supprimer.
add_backrefs.cVersion initiale avec une liste codée en dur de backrefs manquants. Préférez scan_and_fix_all_backrefs, qui les détecte automatiquement.
Lorsque les outils de base ci-dessus étaient insuffisants (pool avec plus de 200 000 erreurs réparties sur plusieurs arbres), ces outils supplémentaires ont été construits :
scan_fstree_extents.c + scan_extent_tree.cScanners de passe 1 et passe 2 qui parcourent respectivement le FS_TREE et l'arbre des extents, produisant des fichiers TSV avec chaque mapping ref/extent. Utilisé pour construire l'entrée de rebuild_extent_tree_apply lorsque l'arbre des extents doit être reconstruit à partir de zéro.
rebuild_extent_tree_apply.c (écrivain lourd)Le principal écrivain de la phase 3. Prend une liste pré-pliée de refs (à partir du diff de scan_fstree_extents + scan_extent_tree) et injecte plus de 3 millions d'EXTENT_DATA_REF dans l'arbre des extents par paquets de 5000 par transaction. Limite tous les 50 000 éléments pour éviter les blocages de ré-aimantation DM-SMR. Vérifié avec succès à 3 248 617 insertions en ~34 min sur 3× disques SMR WD40EFAX.
sudo ./rebuild_extent_tree_apply /dev/sdX1 refs_folded.txt to_insert.txt watermark.txt --dryrun
sudo ./rebuild_extent_tree_apply /dev/sdX1 refs_folded.txt to_insert.txt watermark.txt --write