Agrandir un disque Linux à chaud : ext4, XFS, LVM

Après un passage à une formule plus grande, df affiche souvent l'ancienne taille : le disque a grandi, pas la partition ni le système de fichiers. ext4, XFS et LVM, agrandis à chaud sur une machine de test, sorties réelles à l'appui.

Trois couches empilées : le disque a grandi, la partition et le système de fichiers s'étirent à sa suite

Vous êtes passé à une formule plus grande, ou vous avez rattaché un disque plus gros, et df -h affiche toujours l'ancienne taille. Le disque a bien grandi. Ce qu'il porte, non : la partition, parfois une couche LVM, puis le système de fichiers. Il faut étendre chaque couche, dans cet ordre, et chacune a sa commande.

Tout ce qui suit a été lancé sur une machine de test Debian 13 dont nous avons agrandi trois disques à chaud : une racine en ext4, un disque de données en XFS et un disque de données sous LVM. Les sorties sont les vraies, et rien n'exige de redémarrer.

1. Souvent, un redémarrage suffit

La plupart de nos images agrandissent leur racine toutes seules : cloud-init lance growpart et étend le système de fichiers à chaque démarrage. Oracle Linux fait exception, parce que sa racine est sur LVM et que cloud-init ne touche pas à LVM. Nos images Oracle Linux ajoutent donc un petit service qui fait toute la chaîne à chaque démarrage. Sur un Starter (40 Go), la racine arrive à 34,8 Go. Passez la même machine sur un disque de 80 Go, redémarrez, et elle atteint 74,8 Go.

Si vous pouvez redémarrer, commencez par là. La suite sert quand ce n'est pas possible, ou quand l'espace concerne un second disque ou un montage LVM que vous avez fait vous-même.

2. Trouver où l'espace est bloqué

lsblk montre chaque couche avec sa taille. Juste après l'agrandissement, chaque disque est plus grand que la partition qu'il contient :

bash
$ lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS /dev/sda /dev/sdb /dev/sdc
NAME                SIZE TYPE FSTYPE      MOUNTPOINTS
sda                  12G disk
├─sda1              5.9G part ext4        /
├─sda14               3M part
└─sda15             124M part vfat        /boot/efi
sdb                   6G disk
└─sdb1                2G part xfs         /srv/data
sdc                   6G disk
└─sdc1                2G part LVM2_member
  └─vg_data-lv_srv    2G lvm  xfs         /srv/lvm

df -h confirme que les systèmes de fichiers n'ont pas bougé :

bash
$ df -h / /srv/data /srv/lvm
Filesystem                  Size  Used Avail Use% Mounted on
/dev/sda1                   5.8G  915M  4.6G  17% /
/dev/sdb1                   2.0G   71M  1.9G   4% /srv/data
/dev/mapper/vg_data-lv_srv  2.0G   71M  1.9G   4% /srv/lvm

Demandez ensuite à findmnt ce qui porte le point de montage à agrandir, et dans quel format. La réponse indique votre cas :

3. Installer growpart

growpart réécrit la table des partitions pour qu'une partition prenne tout l'espace libre qui la suit. Il est en général déjà présent sur les images cloud, puisque cloud-init s'en sert. Sinon, le nom du paquet dépend de la famille :

Les outils des systèmes de fichiers viennent de e2fsprogs (resize2fs), xfsprogs (xfs_growfs) et lvm2.

4. Cas 1 : une partition simple en ext4

Avant même de commencer, fdisk -l peut vous accueillir ainsi :

bash
GPT PMBR size mismatch (12582911 != 25165823) will be corrected by write.
The backup GPT table is not on the end of the device.

GPT garde une copie de secours de la table des partitions dans les derniers secteurs du disque. Quand le disque grandit, cette copie n'est plus à la fin. Le message est sans gravité, et growpart déplace la copie en réécrivant la table : après l'étape suivante, fdisk ne dit plus rien.

Le disque et le numéro de partition sont deux arguments séparés. Commencez par --dry-run, qui montre le changement sans l'écrire :

bash
$ sudo growpart --dry-run /dev/sda 1
CHANGE: partition=1 start=262144 old: size=12320735 end=12582878 new: size=24903647 end=25165790
$ sudo growpart /dev/sda 1
CHANGED: partition=1 start=262144 old: size=12320735 end=12582878 new: size=24903647 end=25165790

La partition couvre maintenant le disque, mais le système de fichiers garde son ancienne taille. resize2fs agrandit un ext4 monté, sur place :

bash
$ sudo resize2fs /dev/sda1
resize2fs 1.47.2 (1-Jan-2025)
Filesystem at /dev/sda1 is mounted on /; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 2
The filesystem on /dev/sda1 is now 3112955 (4k) blocks long.

$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        12G  915M   11G   9% /

Relancer growpart ne fait rien de mal : il répond qu'il n'y a plus rien à prendre.

bash
$ sudo growpart /dev/sda 1
NOCHANGE: partition 1 is size 24903647. it cannot be grown

growpart ne peut étendre une partition que dans l'espace libre qui la suit immédiatement. Sur cette image Debian, la partition 1 est la dernière du disque (les partitions 14 et 15 sont au début), elle a donc la place. Si une autre partition se trouve derrière la vôtre, vous obtenez aussi NOCHANGE, et il faut d'abord déplacer ou supprimer cette partition.

5. Cas 2 : XFS

XFS est le système de fichiers par défaut de la famille Red Hat. La première étape ne change pas. La seconde, si : xfs_growfs prend le point de montage, pas le périphérique, et ne fonctionne que sur un système de fichiers monté.

bash
$ sudo growpart /dev/sdb 1
CHANGED: partition=1 start=2048 old: size=4190208 end=4192255 new: size=12580831 end=12582878
$ sudo xfs_growfs /srv/data
[…]
data blocks changed from 523776 to 1572603

$ df -h /srv/data
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb1       6.0G  150M  5.8G   3% /srv/data

xfs_growfs affiche toute la géométrie du système de fichiers avant cette dernière ligne ; nous l'avons coupée.

6. Cas 3 : LVM

LVM ajoute une couche entre la partition et le système de fichiers. La partition est un volume physique (PV), les PV forment un groupe de volumes (VG), et le VG est découpé en volumes logiques (LV). Après growpart, il faut annoncer au PV sa nouvelle taille, ce qui libère de la place dans le groupe :

bash
$ sudo vgs
  VG      #PV #LV #SN Attr   VSize  VFree
  vg_data   1   1   0 wz--n- <2.00g    0
$ sudo growpart /dev/sdc 1
CHANGED: partition=1 start=2048 old: size=4190208 end=4192255 new: size=12580831 end=12582878
$ sudo pvresize /dev/sdc1
  Physical volume "/dev/sdc1" changed
  1 physical volume(s) resized or updated / 0 physical volume(s) not resized
$ sudo vgs
  VG      #PV #LV #SN Attr   VSize  VFree
  vg_data   1   1   0 wz--n- <6.00g 4.00g

lvextend -r donne cette place au volume logique et agrandit le système de fichiers dans la même commande, qu'il soit en ext4 ou en XFS :

bash
$ sudo lvextend -r -l +100%FREE /dev/vg_data/lv_srv
  File system xfs found on vg_data/lv_srv mounted at /srv/lvm.
  Size of logical volume vg_data/lv_srv changed from <2.00 GiB (511 extents) to <6.00 GiB (1535 extents).
  Extending file system xfs to <6.00 GiB (6438256640 bytes) on vg_data/lv_srv...
[…]
  Extended file system xfs on vg_data/lv_srv.
  Logical volume vg_data/lv_srv successfully resized.

$ df -h /srv/lvm
Filesystem                  Size  Used Avail Use% Mounted on
/dev/mapper/vg_data-lv_srv  6.0G  150M  5.8G   3% /srv/lvm

Une racine sur LVM suit le même chemin. findmnt / donne le volume logique et pvs la partition qui le porte. Sur nos images Oracle Linux, c'est la partition 4 :

bash
sudo growpart /dev/sda 4
sudo pvresize /dev/sda4
sudo lvextend -r -l +100%FREE /dev/mapper/vg_main-lv_root

7. Dans l'autre sens

Agrandir se fait à chaud. Réduire, non. XFS ne se réduit pas : les versions récentes de xfs_growfs proposent une tentative expérimentale, et sur notre machine de test elle a échoué :

bash
$ sudo xfs_growfs -D 1000000 /srv/data
[…]
[EXPERIMENTAL] try to shrink unused space 1000000, old size is 1572603
xfs_growfs: XFS_IOC_FSGROWFSDATA xfsctl failed: Invalid argument

ext4 sait rétrécir, mais seulement démonté, ce qui exclut une racine en marche :

bash
$ sudo resize2fs /dev/sda1 8G
resize2fs 1.47.2 (1-Jan-2025)
Filesystem at /dev/sda1 is mounted on /; on-line resizing required
resize2fs: On-line shrinking not supported

Pour obtenir un système de fichiers plus petit, on en crée un neuf à la taille voulue et on y recopie les données.

8. Avant de taper

Ces commandes réécrivent une table des partitions sur un système en marche. Elles sont courantes, mais un mauvais nom de périphérique touche le mauvais disque. Faites d'abord une sauvegarde depuis la console : chaque formule comprend 7 sauvegardes manuelles. Lisez les anciennes et nouvelles tailles qu'affiche growpart --dry-run avant de retirer l'option. Et vérifiez deux fois le nom du disque : sda et sdb ne diffèrent que d'une lettre.

Des images disque empilées, dont une marquée d'un signal d'alerte

Images cloud de 28 systèmes : 8 pièges corrigés

28 systèmes, chacun tiré de l'image cloud de sa distribution, chacun avec ses habitudes. Les pièges qui nous ont coûté du temps, ce que vous voyez quand ils vous tombent dessus, et le correctif que portent maintenant nos images.

Lire l'article 7 min de lecture

Un workflow confie un job à une machine neuve, comptée au chronomètre, avec son cache à côté ; les machines des jobs précédents sont déjà parties

Runners GitHub Actions : la moitié du prix, mesuré

Les runners GitHub Actions de FFxF sont ouverts à tous, en bêta. Le même workflow lancé chez GitHub et chez nous : compilation un peu plus rapide, facture divisée par deux, docker build plus lent à froid et 4 secondes avec le cache Docker.

Lire l'article 7 min de lecture

Support & discussions

Questions techniques, retours d'incidents ou discussions d'infrastructure, l'équipe est présente sur Discord, Telegram, X, Instagram, Reddit et IRC.