URL: https://linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-3-un-peu-de-maintenance
Title: [Btrfs et openSUSE] Épisode 3 : un peu de maintenance
Authors: AR7
Date: 2017年08月25日T00:18:39+02:00
License: CC By-SA
Tags: btrfs, opensuse et firefox
Score: 32

**« Btrfs et openSUSE »** est une série de journaux sur le système de fichiers Btrfs, basée sur ma propre expérience d’utilisateur d’openSUSE. Au menu :
* des généralités sur Btrfs [☑](https://linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-0-l-ex-fs-du-futur) ;
* des noms qui pètent : sous‐volumes, _snapshots_, _rollbacks_ [☑](https://linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-1-sous-volumes-snapshots-et-rollbacks) ;
* du snapper [☑](http://linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-2-snapper-et-grub2#snapper--un-gestionnaire-dinstantan%C3%A9s) ;
* du grub [☑](http://linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-2-snapper-et-grub2#grub2--booter-sur-du-btrfs) ;
* de la mise à jour incrémentale ;
* des quotas ;
* de la maintenance ;
* des trucs spécifiques à openSUSE ;
* des tentatives désespérées pour rester applicable à d’autres distributions ;
* des erreurs (pas taper) ;
* des bogues ;
* des cris ;
* des larmes ;
* et bien plus ! Ou bien moins.
**Aujourd’hui, l’épisode 3 : un peu de maintenance.**
# Surveiller son espace disque
## `df` or not `df` ?
Surveiller son espace disque, c’est important, en particulier si l’on utilise _snapper_ pour la première fois.
Un truc surprenant avec Btrfs, c’est que la commande `df` donne des valeurs assez approximatives.
Voyez l'exemple suivant :
```
~# df -h /
Sys. de fichiers Taille Utilisé Dispo Uti% Monté sur
/dev/sda2 41G 17G 24G 41% /
~# btrfs filesystem df /
Data, single: total=18.81GiB, used=14.67GiB
System, DUP: total=32.00MiB, used=16.00KiB
Metadata, DUP: total=1.00GiB, used=460.75MiB
GlobalReserve, single: total=512.00MiB, used=0.00B
~#
```
`df` m’indique que 17 Gio de ma partition racine sont utilisés.
`btrfs filesystem df` m’indique, lui, un truc complètement différent. Et incompréhensible. Mais qu’est‐ce que c’est que ça ?
Essayons de décomposer l’information :
1. il y a plusieurs lignes, qui semblent représenter chacune l’espace utilisé par un type de données : `Data`, `System`, `Metadata` et `GlobalReserve` ;
2. un type semble être soit `single`, soit `DUP` ;
3. ensuite il y a :
* une taille totale : bizarre, même en faisant leur somme, on n’arrive pas à la taille de la partition (40 Gio)...
* une taille utilisée.
### Types de blocs

`Data`, `System`, `Metadata` et `GlobalReserve` représentent en fait des groupes de blocs différents :
* `Data` : les données, les vraies ;
* `Metadata` : les données à propos des données ; par exemple, les noms de fichiers, les permissions, les sommes de contrôle, etc. ;
* `GlobalReserve` est un espace interne d’urgence. Il est utilisé par exemple quand le système de fichiers est plein. Sa taille totale est basée sur la taille du système de fichiers et ne dépasse pas les 512 Mio ;
* `System` : je ne sais pas ce que c’est. C’est petit en tout cas.
### Méthodes d’allocation
`single` et `DUP` sont en fait deux sortes de niveaux de RAID. Si si, en plus de `raid0`, `raid1`, `raid5`, `raid6` et `raid10`.
* `single` :
* chaque donnée n’est stockée qu’une fois,
* c’est la valeur par défaut pour les « vraies » données (type `Data`) ;
* `DUP` :
* chaque donnée est stockée deux fois sur le même disque,
* c’est la valeur par défaut pour les métadonnées (type `Metadata`) quand il n’y a qu’un seul disque,
* les données (type `Data`) ne peuvent être au niveau `DUP`,
* cela ressemble à du RAID 1, ça protège contre les erreurs au niveau bloc mais ne fournit aucune garantie si le périphérique crashe.
Je parle de ça uniquement parce que c’est utilisé pour estimer l’espace disque libre. En effet, selon le niveau de RAID, il faut appliquer un facteur correctif sur l’information renvoyée par `btrfs filesystem df`. Si.
Pour `single` c’est ×ばつ 1 (la donnée n’est présente qu’une fois) ; pour `DUP` c’est ×ばつ 2 (la donnée est présente deux fois). Pour les autres niveaux de RAID, [c’est plus compliqué](https://btrfs.wiki.kernel.org/index.php/FAQ#Understanding_free_space.2C_using_the_original_tools).
Si vous voulez en savoir plus sur le RAID avec Btrfs, il y a des informations [sur le wiki de Btrfs](https://btrfs.wiki.kernel.org/index.php/Using_Btrfs_with_Multiple_Devices) ainsi que dans le manuel de [mkfs.btrfs](https://btrfs.wiki.kernel.org/index.php/Manpage/mkfs.btrfs).
### Taille totale... vraiment totale ?
La taille mentionnée est seulement la taille allouée. En effet, Btrfs n’utilise pas directement toute la taille disponible du système de fichiers (_pool_) ; il alloue progressivement de l’espace en fonction de ses besoins.
## Bref, au total ça fait combien ?

Eh bien, cela fait :
```
14,67 Gio ×ばつ 1 + 16 Kio ×ばつ 2 + 460,75 Mio ×ばつ 2 + 0 o ×ばつ 1 = 15,57 Gio
`------- ́ `------ ́ | `------ ́ `--- ́ | `---------- ́ `--- ́ | `------------- ́ `------ ́
data single | system DUP | metadata DUP | GlobalReserve single
```
Un total de 15,57 Gio, ce qui est différent des 17 Gio donnés par `df`.
Mais pourquoi est‐ce si compliqué ‽
C’est [une bonne question](https://btrfs.wiki.kernel.org/index.php/FAQ#Why_is_free_space_so_complicated.3F).
Quelle que soit la réponse, c’est si compliqué que les développeurs de Btrfs se sont dit qu’il fallait offrir une autre commande. Cette commande, la voici :
```
~# btrfs filesystem usage /
Overall:
Device size: 40.00GiB
Device allocated: 20.88GiB
Device unallocated: 19.13GiB
Device missing: 0.00B
Used: 15.57GiB
Free (estimated): 23.27GiB (min: 13.71GiB)
Data ratio: 1.00
Metadata ratio: 2.00
Global reserve: 512.00MiB (used: 0.00B)
Data,single: Size:18.81GiB, Used:14.67GiB
/dev/sda2 18.81GiB
Metadata,DUP: Size:1.00GiB, Used:460.75MiB
/dev/sda2 2.00GiB
System,DUP: Size:32.00MiB, Used:16.00KiB
/dev/sda2 64.00MiB
Unallocated:
/dev/sda2 19.13GiB
```
C’est plus long, certes, mais plus clair ! En effet, il y a une section `Overall` qui résume tout et qui applique les facteurs correctifs tout seul. 😉 On retrouve bien notre taille de 15,57 Gio !
On a quand même un truc bizarre : une grosse différence entre l’espace libre estimé (23,27 Gio) et l’espace libre minimal (13,71 Gio). Cela vient des métadonnées :
* actuellement j’ai 460,75 Mio ×ばつ 2 = 921,5 Mio de métadonnées pour 14,67 Gio de données, soit un ratio métadonnées/données d’environ 6 % (je ne sais pas si c’est beaucoup) ;
* si jamais on écrit plein de petits fichiers, le pourcentage de métadonnées va augmenter et on va manquer de place plus tôt, car les métadonnées sont dupliquées ;
* si jamais on écrit de gros fichiers, le pourcentage de métadonnées ne sera pas énorme et on va se rapprocher de la limite théorique.
Une explication sur [ce message posté sur reddit](https://www.reddit.com/r/btrfs/comments/5f7mil/how_should_i_read_disk_usage/daj6lng/).
## Quelle taille prennent mes instantanés ?
À ma connaissance, le moyen le plus efficace pour connaître la taille d’un instantané, et plus généralement d’un sous‐volume, est de passer par les quotas Btrfs (qui seront dans un prochain épisode).
En attendant, vous pouvez utiliser `btrfs filesystem du` (qui est lent, car il compte) :
```
~# btrfs filesystem du -s /.snapshots/31/snapshot/
Total Exclusive Set shared Filename
2.19GiB 634.02MiB 1.57GiB /.snapshots/31/snapshot/
~#
```
Pour moi, la taille intéressante est la colonne `Exclusive`, qui représente la taille des données qui n’est pas partagée avec d’autres sous‐volumes. `Set shared` représente la taille des données partagées avec d’autres sous‐volumes. Puis le `Total`, la somme des deux.
# btrfsmaintenance, la boîte à outils pour maintenir un système de fichiers Btrfs
Sur openSUSE, les outils du projet [_btrfsmaintenance_](https://github.com/kdave/btrfsmaintenance) (GPL v2.0) sont installés par défaut.
Il s’agit d’une collection de scripts pouvant être automatisés avec _cron_ :
```sh
~$ ls /etc/cron.{month,week}ly
/etc/cron.monthly:
btrfs-scrub
/etc/cron.weekly:
btrfs-balance btrfs-trim
~$
```
J’ai vu que des paquets étaient disponibles pour [Arch Linux](https://aur.archlinux.org/packages/btrfsmaintenance/), [Fedora](https://copr.fedorainfracloud.org/coprs/tofik/btrfs/package/btrfsmaintenance/) (Copr), [Gentoo](https://packages.gentoo.org/packages/sys-fs/btrfsmaintenance). Chez Debian, le paquet est en cours de préparation ([deb#813901](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=813901)).
Les scripts appellent des commandes classiques de _btrfsprogs_. Voyons lesquelles.
## Équilibrage : `btrfs balance`

Cela permet de répartir les données sur les disques.
```
~# btrfs balance start
btrfs balance start: too few arguments
usage: btrfs balance start [options]
Balance chunks across the devices
Balance and/or convert (change allocation profile of) chunks that
passed all filters in a comma-separated list of filters for a
particular chunk type. If filter list is not given balance all
chunks of that type. In case none of the -d, -m or -s options is
given balance all chunks in a filesystem. This is potentially
long operation and the user is warned before this start, with
a delay to stop it.
-d[filters] act on data chunks
-m[filters] act on metadata chunks
-s[filters] act on system chunks (only under -f)
-v be verbose
-f force reducing of metadata integrity
--full-balance do not print warning and do not delay start
--background|--bg
run the balance as a background process
~#
```
Cela est utile pour :
* répartir les données à l’ajout d’un nouveau périphérique ;
* sur un système de fichiers avec des réplications endommagés (genre RAID 1 avec disque endommagé et enlevé), cela force le système de fichiers à reconstruire les copies sur les disques actifs ;
* sur un système de fichiers avec un seul disque, cela permet de diminuer l’espace alloué.
Les [filtres](https://btrfs.wiki.kernel.org/index.php/Balance_Filters) sont obligatoires si l’on ne veut pas que l’équilibrage dure une éternité. Par exemple, `btrfs balance start -dusage=30 -musage=30` ne déplacera que les données et les métadonnées des groupes de blocs qui ne sont utilisés qu’à moins de 30 %.
Le script fourni dans _btrfsmaintenance_ effectue plusieurs passes avec ce genre de filtre :
* d’abord avec un `-dusage=0 -musage=0` pour nettoyer les groupes de blocs complètement vides ;
* puis avec des valeurs prises [dans un fichier de configuration](https://github.com/kdave/btrfsmaintenance/blob/master/sysconfig.btrfsmaintenance#L50-L71), typiquement : 1, 5, 10, 20... sans dépasser les 50.
## Vérification des sommes de contrôle : `btrfs scrub`
Le _scrub_ consiste à lire tous les blocs de données et de métadonnées et à vérifier leurs sommes de contrôle. Une réparation automatique est faite s’il existe une copie valide.
La syntaxe :
```
~# btrfs scrub start
btrfs scrub start: too few arguments
usage: btrfs scrub start [-BdqrRf] [-c ioprio_class -n ioprio_classdata] |
Start a new scrub. If a scrub is already running, the new one fails.
-B do not background
-d stats per device (-B only)
-q be quiet
-r read only mode
-R raw print mode, print full data instead of summary
-c set ioprio class (see ionice(1) manpage)
-n set ioprio classdata (see ionice(1) manpage)
-f force starting new scrub even if a scrub is already running
this is useful when scrub stats record file is damaged
~#
```
La tâche _cron_ de _btrfsmaintenance_ est appelée tous les mois.
Note : il n’y a pas de [somme de contrôle pour les fichiers, dossiers et sous‐volumes pour lesquels le [CoW](https://fr.wikipedia.org/wiki/Copy-on-write "copy‐on‐write ou copie sur écriture") est désactivé](https://btrfs.wiki.kernel.org/index.php/FAQ#Can_I_have_nodatacow_.28or_chattr_.2BC.29_but_still_have_checksumming.3F). Le _scrub_ ne peut rien faire pour eux.
## Défragmentation : `btrfs filesystem defragment`
J’ai noté que la défragmentation est un sujet qui intéresse, donc je vais détailler un peu plus en essayant de ne pas trop dire de bêtises.
### Qu’est‐ce que c’est au juste ?
La [défragmentation](https://fr.wikipedia.org/wiki/D%C3%A9fragmentation) « _consiste à regrouper les fragments de fichiers éparpillés sur le disque dur afin d’optimiser les temps d’accès du disque dur lors de la lecture de fichiers de taille importante_ ».
### Est‐ce que Btrfs fragmente ?
La réponse est : oui.
Est‐ce que Btrfs fragmente beaucoup ? La réponse est : ça dépend.
La fragmentation des fichiers dépend de la façon dont les applications écrivent ces fichiers sur le disque. Donc, cela dépend des applications qui tournent. Par exemple, les bases de données – ne serait‐ce que les bases de données SQLite de Firefox – ont tendance à beaucoup fragmenter avec Btrfs, du fait que le _CoW_ n’est pas adapté à leur fonctionnement.
Pour les fichiers qui sont complètement réécrits, [il n’y a pas de fragmentation](https://linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-0-l-ex-fs-du-futur#comment-1710497).
Vous pouvez utiliser la commande `filefrag` pour évaluer la fragmentation :
```
~# filefrag /var/log/zypper.log
/var/log/zypper.log: 66 extents found
~#
```
Essayons de vérifier tout le système. Cherchons les fichiers fragmentés à plus de 100 _extents_ :
```sh
~# cat checkfrag.sh
#!/bin/bash
# Inspiré de https://gist.github.com/kylemanna/b5cac22b6164b14aa967
# Chemin des sous‐volumes / systèmes de fichiers à analyser
subvols=${2:-/ $(btrfs subvolume list / | grep -v snapshots | sed 's/@//' | awk '{ print "/"9ドル }')}
# Seuil d’extents en dessous duquel les fichiers sont ignorés
min=${1:-100}
# Un petit find
find ${subvols} -xdev -type f -exec filefrag '{}' \+ | awk "{ if ( \$(NF-2)> $min ) print \0ドル }"
~# ./checkfrag.sh
/var/log/alternatives.log: 225 extents found
/var/log/journal/016627c3c4784cd4812d4b7e96a34226/user-1001.journal: 164 extents found
/var/log/cups/access_log: 185 extents found
/var/log/YaST2/mkinitrd.log: 305 extents found
/var/log/audit/audit.log.4: 1472 extents found
/var/log/audit/audit.log.3: 1607 extents found
/var/log/audit/audit.log.2: 1804 extents found
/var/log/audit/audit.log.1: 1597 extents found
/var/log/audit/audit.log: 106 extents found
/var/log/wpa_supplicant.log: 269 extents found
/var/log/zypper.log-20170214: 108 extents found
/var/tmp/build-root/openSUSE_Tumbleweed-x86_64/var/lib/rpm/Packages: 1777 extents found
/var/tmp/build-root/openSUSE_Tumbleweed-x86_64/var/lib/rpm/Basenames: 501 extents found
/var/tmp/build-root/openSUSE_Leap_42.2-x86_64/var/lib/rpm/Basenames: 128 extents found
/var/tmp/build-root/openSUSE_Leap_42.3-x86_64/var/lib/rpm/Basenames: 124 extents found
/var/cache/man/index.db: 146 extents found
~#
```
On voit :
* surtout des journaux ;
* la base de données des pages _man_ ;
* des bases de données RPM : c’est très particulier à ma machine, ce sont des _chroots_ que j’utilise pour construire des paquets avec [_osc_](https://en.opensuse.org/openSUSE:OSC). Vous noterez que la base de données RPM du système (dans `/var/lib/rpm/`) n’est pas mentionnée. On va y revenir.
Dans l’ensemble, ça va, sachant que ce système n’a pas vraiment été défragmenté depuis 2015... Bon, après, je n’ai pas de base de données qui tourne et j’ai une partition en XFS pour le `/home`.
### Est‐ce qu’il faut défragmenter un disque dur classique avec Btrfs ?
La réponse est : oui, si nécessaire (c’te non‐réponse !).
Cela peut améliorer significativement les performance, si tant est qu’il y ait fragmentation. Voir question précédente (c’te double non‐réponse 😋).
### Est‐ce qu’il faut défragmenter un SSD avec Btrfs ?

La réponse est : cela peut être utile (😃).
C’est vrai que les effets de la fragmentation se ressentent avant tout sur les disques durs classiques.
Il est vrai que pour les SSD, l’usage est de ne pas défragmenter. L’idée derrière cela est que les SSD ont des vitesses d’accès tellement rapides que la fragmentation du système de fichiers est négligeable. Il semble alors pertinent d’éviter les opérations de défragmentation, coûteuses en termes de cycles d’écriture. Surtout que ces machins‐là se montrent parfois fragiles (_dixit_ un ex‐propriétaire d’un Kingston à la durée de vie de libellule).
Cependant, sur un SSD, une fragmentation massive (genre plus de 10 000 _extents_) entraînera tout de même [des pics de consommation du processeur](https://btrfs.wiki.kernel.org/index.php/Gotchas#Fragmentation), pouvant atteindre plusieurs secondes, ce qui n’est pas souhaitable. Je suppose que c’est parce qu’il doit quand même y avoir du calcul pour résoudre tous ces fragments et que le processeur n’a pas le temps de se reposer sur le disque, vu que le SSD est très rapide.
Du coup, la défragmentation de fichiers très fragmentés est pertinente même pour un SSD.
### Est‐ce que _btrfsmaintenance_ défragmente ?
La réponse est : pas par défaut, mais il en est capable.
C’est donc à nous de jouer [en réglant la configuration de _btrfsmaintenance_](https://github.com/kdave/btrfsmaintenance/blob/791581f84f884d172df5a2e297f03e4f6e3cdb63/sysconfig.btrfsmaintenance#L17-L23) ou en utilisant directement la commande :
```
~# btrfs filesystem defragment
btrfs filesystem defragment: too few arguments
usage: btrfs filesystem defragment [options] | [|...]
Defragment a file or a directory
-v be verbose
-r defragment files recursively
-c[zlib,lzo] compress the file while defragmenting
-f flush data to disk immediately after defragmenting
-s start defragment only from byte onward
-l len defragment only up to len bytes
-t size target extent size hint (default: 32M)
~#
```
Exemple :
```sh
~# filefrag /var/log/zypper.log
/var/log/zypper.log: 66 extents found
~# btrfs filesystem defragment -f /var/log/zypper.log
~# filefrag /var/log/zypper.log
/var/log/zypper.log: 1 extent found
~#
```
Pour lancer sur tout le disque, c’est : `btrfs filesystem defragment -r /`. Après, vous pouvez aussi adapter le script écrit plus haut pour ne défragmenter que les fichiers très fragmentés :
```sh
~# files=$(checkfrag.sh 3000 | cut -f1 -d ":")
~# [ -n files ] && btrfs filesystem defragment ${files} || echo "0 fragmented file found"
0 fragmented file found
~#
```
### Sur openSUSE

On l’a vu dans l’épisode 1 : [openSUSE désactive le _CoW_ pour certains sous‐volumes](http://linuxfr.org/users/ar7/journaux/btrfs-et-opensuse-episode-1-sous-volumes-snapshots-et-rollbacks#la-solution-actuelle-sur-opensuse), notamment ceux des bases de données MySQL et MariaDB, ainsi que ceux des machines virtuelles. Donc, cela nous évite de gérer la fragmentation de ces fichiers.
De plus, par défaut, le `/home` n’est pas en Btrfs : c’est une partition séparée en XFS. Cela évite d’avoir à gérer la fragmentation de toutes les bases de données utilisateurs (Firefox, Chromium, Thunderbird, Digikam...). Ce n’est sans doute pas la seule raison à ce choix, mais je pense que c’en est une valable.
Enfin, une défragmentation de la base de données RPM est faite après chaque installation de paquet via un _hook_ de [_libzypp_](https://doc.opensuse.org/projects/libzypp/HEAD/). Résultat :
```sh
~# filefrag /var/lib/rpm/*
/var/lib/rpm/alternatives: FIBMAP unsupported
/var/lib/rpm/Basenames: 1 extent found
/var/lib/rpm/Conflictname: 1 extent found
/var/lib/rpm/Dirnames: 1 extent found
/var/lib/rpm/Enhancename: 1 extent found
/var/lib/rpm/Filetriggername: 1 extent found
/var/lib/rpm/Group: 1 extent found
/var/lib/rpm/Installtid: 1 extent found
/var/lib/rpm/Name: 1 extent found
/var/lib/rpm/Obsoletename: 1 extent found
/var/lib/rpm/Packages: 2 extents found
/var/lib/rpm/Providename: 1 extent found
/var/lib/rpm/Recommendname: 1 extent found
/var/lib/rpm/Requirename: 1 extent found
/var/lib/rpm/Sha1header: 1 extent found
/var/lib/rpm/Sigmd5: 1 extent found
/var/lib/rpm/Suggestname: 2 extents found
/var/lib/rpm/Supplementname: 1 extent found
/var/lib/rpm/Transfiletriggername: 1 extent found
/var/lib/rpm/Triggername: 1 extent found
~#
```
## Pour les SSD : `fstrim`
_btrfsmaintenance_ inclut également un script qui appelle `fstrim`, dont l’exécution est planifiée toutes les semaines. Il est considéré comme préférable de faire des `fstrim` périodiquement ainsi, plutôt que de monter le système de fichiers avec l’option `discard`.
_That’s all folks!_
# Liens
Sur le wiki Btrfs :
* la FAQ, en particulier les parties :
* [_Combien d’espace libre me reste‐t‐il ?_](https://btrfs.wiki.kernel.org/index.php/FAQ#How_much_free_space_do_I_have.3F),
* [_TRIM et discard_](https://btrfs.wiki.kernel.org/index.php/FAQ#Does_Btrfs_support_TRIM.2Fdiscard.3F) ;
* [_Les filtres pour l’équilibrage_](https://btrfs.wiki.kernel.org/index.php/Balance_Filters) (_balance filters_) ;
* [_Les_ gotchas _sur la fragmentation_](https://btrfs.wiki.kernel.org/index.php/Gotchas#Fragmentation).
Ailleurs :
* le dépôt de [_btrfsmaintenance_](https://github.com/kdave/btrfsmaintenance) sur GitHub.