ZFS sous GNU/linux

GNU/Linux Magazine n° 114 | mars 2009 | Olivier Delhomme
Creative Commons
  • Actuellement 0 sur 5 étoiles
0
Merci d'avoir participé !
Vous avez déjà noté cette page, vous ne pouvez la noter qu'une fois !
Votre note a été changée, merci de votre participation !
Un système de fichiers révolutionnaire qui s'auto-répare, permet l'utilisation d'un genre de raid (niveaux 0, 1, 5 et même 6), permet la compression et la création de snapshots à la volée, possède des limites qui n'ont aucune signification physique aujourd'hui et fonctionne sous GNU/Linux. Pas possible ? ZFS !

ZFS est un système de fichiers dédié serveur qui promet de réconcilier les administrateurs système avec les systèmes de fichiers. Il a été écrit par les développeurs de Sun. Il est donc disponible nativement sous Solaris. Il simplifie toutes les opérations qui nous horripilent ou nous rebutent. Il a une fonctionnalité qui m'a vraiment fait craquer et qui me paraît tellement évidente qu'on se demande pourquoi les autres systèmes de fichiers ne la proposent pas : il est capable (avec un système de disques redondants) de s'auto-réparer ! Le code [0] est placé sous licence CDDL, approuvée par l'OSI (l'Open Source Initiative [1]), c'est donc un logiciel libre même si l'on peut regretter ce choix pour des raisons éthiques [2]. Voyons ce dont ZFS est capable.

1. Des chiffres

Lorsque l'on parle de chiffres, pour un système de fichiers, il s'agit généralement de ses limites. ZFS, dans ce domaine, a été conçu directement pour le futur, jugez plutôt :

- Système de fichiers entièrement 128 bits, c'est-à-dire non seulement pour le nombre d'inodes, mais aussi pour la taille maximale d'un fichier .

- 264 soit plus de 18 milliards de milliards de fichiers au maximum dans chaque système de fichiers.

- 248snapshots au maximum. Si on en fait 10 par seconde, on peut tenir pendant plus de 890 000 ans ! Mais, il faudrait de la place et justement…

- 16 exa octets, soit plus de 16 000 peta octets. C'est la taille maximale d'un système de fichiers. 16 exa octets, c'est aussi la taille maximale d'un fichier !

- 248 fichiers au maximum dans un répertoire.

- 256 zeta octets, soit plus de 256 000 exa octets. C'est la taille maximale d'un pool (un ensemble de périphériques) qui peut contenir au maximum 264 systèmes de fichiers.

- Les pools peuvent être formés d'au maximum 264 périphériques.

Ces chiffres sont tellement immenses qu'on ne se rend pas bien compte de ce que cela représente. Aussi, il est probable que l'énergie nécessaire pour remplir un système de fichiers comme celui-là soit si gigantesque qu'elle pourrait suffire à faire bouillir l'eau des océans [3]. On comprend mieux pourquoi ce système de fichiers a été nommé Zeta File System, soit ZFS.

2. Installation

Donc, en cherchant bien, on trouve Ricardo Correia (connu sous le pseudonyme wizeman), un gentil développeur, qui a porté ZFS pour qu'il utilise fuse sous GNU/Linux. En effet, la licence CDDL est incompatible avec la licence GPL (dans sa version 2), celle du noyau GNU/Linux. C'est pourquoi ZFS n'est pas intégré au noyau et que l'on doit utiliser fuse pour le faire fonctionner sous GNU/Linux. Ce n'est par exemple pas le cas de FreeBSD où ZFS est intégré nativement depuis la version 7.0. Sur le site de FreeBSD [4], il est écrit qu'il s'agit d'un support expérimental, mais un certain D.B., rédacteur en chef d'un magazine sur GNU/Linux me souffle qu'en réalité c'est « intégré de manière très très propre » !

Du coup, avant toute chose sous GNU/Linux (les noms des paquets cités ici proviennent de ma Debian), il faut installer fuse-utils et aussi libfuse-dev, car nous allons compiler le programme qui utilise les structures de fuse. Il faut aussi installer libaio-dev et libaio1 qui permettent d'effectuer les entrées/sorties de manière asynchrone. La bibliothèque de compression de données zlib vous sera demandée avec sa version de développement. Il faut également un noyau GNU/Linux2.6.x supérieur à 2.6.15 et une glibc avec les pthreads dans une version supérieure à 2.3.3. Le système de compilation utilise la commande scons [5] en remplacement de la commande make. Il vous la faudra également.

Téléchargez [6] l'archive et décompressez-la avant de lancer la compilation :

$ tar jxvf zfs-fuse-0.5.0.tar.bz2

$ cd zfs-fuse-0.5.0/src/

$ scons

Si, comme moi, vous avez une machine dont l'âge est honorable, il faudra une bonne dizaine de minutes avant que cette opération ne se termine.

Installons le programme :

$ sudo scons install

Et voilà !!

Par défaut, tout s'installe dans /usr/local/sbin. Vous pouvez modifier cela en spécifiant une option à scons :

$ sudo scons install install_dir=/chemin/vers/les/programmes

3. Tour d'horizon rapide des commandes et des fonctionnalités

Nous venons d'installer les commandes zdb, zfs, zfs-fuse, zpool et ztest.

zdb est la commande qui permet de diagnostiquer des pannes et erreurs de ZFS. Toutefois, comme le fonctionnement de ZFS lui garantit d'être toujours cohérent et qu'il se répare tout seul, cette commande n'est pas très utile dans un premier temps.

zpool permet de gérer les « pools » de stockage, c'est-à-dire les regroupements de disques de stockage.

zfs permet de configurer le ou les systèmes de fichiers contenus dans les « pools ».

ztest permet de faire des tests.

zfs-fuse va nous servir sous GNU/Linux puisqu'il s'agit du mauvais génie (le démon quoi !) qui gère tout ça !!

Mentionnons l'option pour obtenir l'aide des commandes. Cette dernière n'étant pas très POSIX [7], elle est un peu inhabituelle. Aussi, vous devrez utiliser l'option -?.

Les fonctionnalités présentes dans la version 0.5 sont les suivantes :

- Créer et détruire des pools, des snapshots et des clones.

- Fonctionnalités de raid, raid-0 ou agrégats, raid 1 ou miroir, raid 5 ou à parité contrôlée (cette fonctionnalité se nomme raidz pour ZFS), raid 6 à double parité (nommée raidz2).

- Possibilité d'utiliser n'importe quel périphérique en mode bloc ou n'importe quel fichier (sauf un issu d'un système de fichiers ZFS) pour réaliser un périphérique virtuel.

- La compression, la détection d'erreur, la vérification des données ainsi que l'auto-réparation (sur un volume de type raid redondant type raid 1, raid 5 ou raid 6).

- Les quotas et la réservation fonctionnent, même s'il ne s'agit pas de « vrais quotas » à la sauce POSIX du terme.

- Sauvegarde et restauration (via les snapshots).

Bien qu'il y ait déjà de nombreuses fonctionnalités opérationnelles, il en existe beaucoup d'autres qui ne le sont pas encore, soit qu'elles ne sont pas encore implémentées, soit qu'elles ne peuvent l'être du fait de limitations dues principalement à fuse (que l'on remercie quand même d'exister). Pour avoir une idée plus précise des fonctionnalités qui restent à écrire, reportez-vous au fichier STATUS qui se trouve à la racine des sources.

4. Passons aux choses sérieuses

4.1 Création d'un pool

Avant toute chose, vérifiez que fuse est bien là et lancer le processus ZFS pour ce dernier comme suit. Attention, la commande ne se termine pas, ouvrez donc un terminal dédié :

$ sudo -s

# modprobe fuse

# zfs-fuse --no-daemon

Si cela ne fonctionne pas, reportez vous au paragraphe 6. Pour faire mes tests, vu qu'à la maison je n'ai pas un serveur de fichiers avec plusieurs contrôleurs et plusieurs disques, j'utilise des fichiers comme s'ils étaient des disques. Je me crée dix « disques » de 512 Mo :

$ mkdir test_zfs

$ cd test_zfs

$ for i in $(seq 0 9); \

do dd if=/dev/zero of=./disque_$i bs=1M count=512; \

done;

Après un long moment (ma machine a mis plus de 5 minutes), vous obtenez dix magnifiques fichiers, tous d'une taille identique de 512 Mo. Nous admettrons qu'il s'agit là de dix disques durs très haute performance !

Note

Attention : La création d'un pool nécessite des périphériques (ou fichiers) dont la taille est supérieure ou égale à 64 Mo.

Donc, nous allons créer un pool avec les dix disques, en raidz2, c'est-à-dire un genre de raid 6 et disons que, comme on est très prudent, on va utiliser un disque de réserve (« spare » en anglais). On souhaite aussi que le volume correspondant soit monté sur /media/zfs_test (qui est un dossier qui n'existe pas sur le système utilisé). Utilisons la commande suivante :

# zpool create raid6 raidz2 \

/tmp/test_zfs/disque_{0,1,2,3,4,5,6,7,8} \

spare /tmp/test_zfs/disque_9 -m /media/zfs_test

Note

S'agissant de fichiers et non de périphériques, veillez à bien spécifier le chemin absolu (depuis la racine) de chaque fichier.

Hop et voilà !! Si si, c'est tout ce qu'il y a à faire. D'ailleurs, vérifions tout de suite avec la commande df -h qui donne :

# df -h

Sys. de fich.         Tail. Occ. Disp. %Occ. Monté sur

/dev/hda2              12G 7,9G 3,5G 70% /

tmpfs                 237M     0 237M   0% /lib/init/rw

udev                   10M 104K 9,9M   2% /dev

tmpfs                 237M     0 237M   0% /dev/shm

/dev/hda1             236M 145M   79M 65% /boot

/dev/hda5              24G 9,2G   14G 41% /home

raid6                 3,4G   42K 3,4G   1% /media/zfs_test

3,4 Gode libre, c'est bien7*512Mo, car, pour schématiser, on a 9 disques dans le raidz2 dont 2 disques de parités soit 7 disques utiles plus un disque de réserve (ici spare). Cette place est directement utilisable, car montée automatiquement sur /media/zfs_test (comme on lui avait demandé). Ici, pas besoin d'un long mkfs. La commande s'est exécutée en un clin d’œil : la taper a presque été plus long ! Une commande utile à ce stade est zpool status qui permet de connaître l'état des pools (ici un seul) :

# zpool status

pool: raid6

state: ONLINE

scrub: none requested

config:

        NAME                        STATE     READ WRITE CKSUM

        raid6                       ONLINE       0     0     0

          raidz2                    ONLINE       0     0     0

            /tmp/zfs_test/disque_0 ONLINE       0     0     0

            /tmp/zfs_test/disque_1 ONLINE       0     0     0

            /tmp/zfs_test/disque_2 ONLINE       0     0     0

            /tmp/zfs_test/disque_3 ONLINE       0     0     0

            /tmp/zfs_test/disque_4 ONLINE       0     0     0

            /tmp/zfs_test/disque_5 ONLINE       0     0     0

            /tmp/zfs_test/disque_6 ONLINE       0     0     0

            /tmp/zfs_test/disque_7 ONLINE       0     0     0

            /tmp/zfs_test/disque_8 ONLINE       0     0     0

        spares

          /tmp/zfs_test/disque_9    AVAIL

errors: No known data errors

Ici, on voit très nettement qu'il y a 9 disques dans le raidz2 que j'ai nommé « raid6 » et un disque de réserve qui est disponible (AVAIL). Cette commande nous servira, par la suite, pour connaître l'état du pool.

Copions donc des données. Une commande du -hs /var/cache m'indique que ce dernier occupe 3,4 Go, parfait pour être copié dans mon volume de test :

# cp -a /var/* /media/zfs_test/

Là, pour le coup, c'est long, très long même, plus de 30 minutes sur ma machine. Mais c'est normal, car toutes les opérations ont lieu sur le même disque physique. De plus, ZFS crée le système de fichiers à la volée et calcule les sommes de contrôle (checksums) qui lui seront utiles au cas où il lui arriverait malheur (et croyez-moi, je ne vais pas être tendre). Si, comme moi, vous essayez de mettre plus de données que le volume ne peut en contenir, vous allez vous rendre compte, vers la fin, que ZFS cherche de la place et se réorganise. Si vous regardez la place libre avec la commande df -h régulièrement, il est possible que vous voyiez cette dernière augmenter, alors même que vous copiez des données !! Astuce : Pour réaliser cela, utilisez la commande watch comme suit (utilisez [Ctrl-C] pour quitter le programme) :

$ watch -t -d -n1 "df -h"

La recherche de place libre est très consommatrice de ressources et écroule totalement les performances (sous GNU/Linux en tout cas). Il est préférable de ne jamais remplir totalement un système de fichiers ZFS pour éviter ce problème. Notamment, cela vous évitera de vous demander pourquoi vous n'arrivez pas à effacer un fichier de 2 Go quand votre pool ZFS est plein à 99%...

Notons que ZFS gère plusieurs types de systèmes de fichiers tels que « raidz2 » que nous venons de voir ou « raidz » qui est une sorte de raid5 et « mirror » qui est une sorte de raid1. De base, il gère le raid0 qui est un simple agrégat. Nous le verrons plus tard. Il est possible de mélanger, dans une certaine mesure, tout cela.

4.2 Faisons souffrir le système de fichiers

4.2.1 Un disque rempli d'erreurs

Écrivons n'importe quoi dans le fichier disque_4 par exemple :

# shred -n 1 disque_4

Après une manœuvre pareille, le contenu du fichier disque_4 n'est plus du tout le même qu'avant.

La commande zpool status annonce qu'il y a eue une erreur, mais que les applications n'ont pas été affectées. Elle indique aussi les actions à réaliser pour effacer les erreurs ou pour remplacer le disque défectueux. Par contre, l'accès aux fichiers dans /media/zfs_test/ reste possible et sans erreurs, car ZFS les détecte et les corrige à la volée. À noter que la commande zpool scrub raid6 permet de corriger l'ensemble des données du volume (moins le volume est rempli, plus c'est rapide).

La colonne CKSUM de la commande zpool status indique le nombre de sommes de contrôle trouvées en erreur.

4.2.2 Un disque en moins

Bon, dans la vrai vie, c'est rare que l'on puisse réécrire sur les secteurs défectueux d'un disque. Pour simuler un disque défectueux, tuez le processus zfs-fuse, supprimez le fichier de votre choix, relancez le processus zfs-fuse et réimportez le pool (voir § 6.) :

# killall zfs-fuse

# rm -f disque_4

# zpool import -d . raid6

# zpool status

  pool: raid6

state: DEGRADED

status: One or more devices could not be opened. Sufficient replicas exist for

 the pool to continue functioning in a degraded state.

action: Attach the missing device and online it using 'zpool online'.

   see: http://www.sun.com/msg/ZFS-8000-2Q

scrub: none requested

config:

 NAME                        STATE     READ WRITE CKSUM

 raid6                       DEGRADED     0     0     0

  raidz2                    DEGRADED     0     0     0

     /tmp/zfs_test/disque_0 ONLINE       0     0     0

     /tmp/zfs_test/disque_1 ONLINE       0     0     0

     /tmp/zfs_test/disque_2 ONLINE       0     0     0

     /tmp/zfs_test/disque_3 ONLINE       0     0     0

     7760834922797222775     UNAVAIL      0     0     0 was /tmp/zfs_test/disque_4

     /tmp/zfs_test/disque_5 ONLINE       0     0     0

     /tmp/zfs_test/disque_6 ONLINE       0     0     0

     /tmp/zfs_test/disque_7 ONLINE       0     0     0

     /tmp/zfs_test/disque_8 ONLINE       0     0     0

 spares

  /tmp/zfs_test/disque_9    AVAIL

errors: No known data errors

L'indication est claire : il manque un disque. La commande conseille de le brancher et de le mettre en ligne en utilisant la commande zpool online.

4.2.3 Deux disques en moins ! Vite, utilisons le disque de réserve !

Soyons fous, recommençons et supprimons disque_5. Les sorties sont les mêmes, mais, cette fois, nous n'avons plus la ceinture, ni les bretelles et le moindre problème dans l'un des disques restant serait fatal aux données. Utilisons donc le disque de spare :

# zpool replace /tmp/zfs_test/disque_4 /tmp/zfs_test/disque_9

Et voilà ! Comment ça et voilà ? Si si, je vous assure, c'est tout, ZFS s'occupe de reconstruire en arrière-plan le système de fichiers, de noter que le périphérique disque_9 est maintenant utilisé et qu'il remplace disque_4 et vous continuez d'avoir accès à vos fichiers de manière transparente, comme si de rien était :

# zpool status

  pool: raid6

state: DEGRADED

status: One or more devices could not be opened. Sufficient replicas exist for

 the pool to continue functioning in a degraded state.

action: Attach the missing device and online it using 'zpool online'.

   see: http://www.sun.com/msg/ZFS-8000-2Q

scrub: resilver in progress for 0h2m, 11,20% done, 0h16m to go

config:

 NAME                          STATE     READ WRITE CKSUM

 raid6                         DEGRADED     0     0     0

  raidz2                      DEGRADED     0     0     0

     /tmp/zfs_test/disque_0    ONLINE       0     0     0

     /tmp/zfs_test/disque_1    ONLINE       0     0     0

     /tmp/zfs_test/disque_2    ONLINE       0     0     0

     /tmp/zfs_test/disque_3    ONLINE       0     0     0

     spare                     DEGRADED     0     0     0

       7760834922797222775     UNAVAIL      0     0     0 was /tmp/zfs_test/disque_4

       /tmp/zfs_test/disque_9 ONLINE       0     0     0

     2705405041636850921       UNAVAIL      0     0     0 was /tmp/zfs_test/disque_5

     /tmp/zfs_test/disque_6    ONLINE       0     0     0

     /tmp/zfs_test/disque_7    ONLINE       0     0     0

     /tmp/zfs_test/disque_8    ONLINE       0     0     0

 spares

  /tmp/zfs_test/disque_9      INUSE     currently in use

errors: No known data errors

Regardez bien. La commande indique même depuis combien de temps elle reconstruit (ici 2 minutes) et combien de temps il va lui falloir pour terminer (à vitesse constante, ici 16 minutes – en réalité, il ne lui a fallu que 12 minutes).

4.2.4 Allons y gaiement...

Ce qui est agréable avec la commande zpool status, c'est qu'elle indique tout de manière précise et concise. Par exemple, supprimons le disque de spare (disque_9) et inscrivons 10 Mo de données aléatoires dans l'un des disques restants. Le résultat sera qu'un certain nombre de fichiers seront illisibles, oui, mais lesquels ?

# rm -f disque_9

# dd if=/dev/urandom of=disque_7 bs=1024 count=10000 \ seek=56654 conv=notrunc

10000+0 enregistrements lus

10000+0 enregistrements écrits

10240000 bytes (10MB) copied, 3,51317 s, 2,9 MB/s

# zpool import -d . raid6

# zpool status

  pool: raid6

state: DEGRADED

status: One or more devices could not be opened. Sufficient replicas exist for

 the pool to continue functioning in a degraded state.

action: Attach the missing device and online it using 'zpool online'.

   see: http://www.sun.com/msg/ZFS-8000-2Q

scrub: none requested

config:

 NAME                        STATE     READ WRITE CKSUM

 raid6                       DEGRADED     0     0     0

  raidz2                    DEGRADED     0     0     0

     /tmp/zfs_test/disque_0 ONLINE       0     0     0

     /tmp/zfs_test/disque_1 ONLINE       0     0     0

     /tmp/zfs_test/disque_2 ONLINE       0     0     0

     /tmp/zfs_test/disque_3 ONLINE       0     0     0

spare                   UNAVAIL      0     0     0 insufficient replicas

       7760834922797222775   UNAVAIL      0     0     0 was /tmp/zfs_test/disque_4

       9623051411205814655   UNAVAIL      0     0     0 was /tmp/zfs_test/disque_9

     2705405041636850921     UNAVAIL      0     0     0 was /tmp/zfs_test/disque_5

     /tmp/zfs_test/disque_6 ONLINE       0     0     0

     /tmp/zfs_test/disque_7 ONLINE 0 0 0

     /tmp/zfs_test/disque_8 ONLINE       0     0     0

 spares

  /tmp/zfs_test/disque_9    UNAVAIL   cannot open

errors: No known data errors

# zpool scrub raid6

#

Après l'import du nouveau pool très dégradé, zpool status nous indique bien avoir perdu le disque de réserve et qu'il n'y a pas assez de disques pour la réserve. Mais, la commande n'indique pas les éventuelles erreurs dans le système de fichiers (erreurs dues à la commande dd). La commande zpool scrub raid6 permet de parcourir l'ensemble des données pour y détecter des erreurs et éventuellement les corriger, le tout de manière transparente. Voyons le résultat avec la commande zpool status –v :

# zpool status -v

  pool: raid6

state: DEGRADED

status: One or more devices has experienced an error resulting in data

 corruption. Applications may be affected.

action: Restore the file in question if possible. Otherwise restore the

 entire pool from backup.

   see: http://www.sun.com/msg/ZFS-8000-8A

scrub: scrub in progress for 0h5m, 77,37% done, 0h1m to go

config:

 NAME                        STATE     READ WRITE CKSUM

 raid6                       DEGRADED 1,07K     0     0

  raidz2                    DEGRADED 1,07K     0     0

     /tmp/zfs_test/disque_0 ONLINE       0     0     0

     /tmp/zfs_test/disque_1 ONLINE       0     0     0

     /tmp/zfs_test/disque_2 ONLINE       0     0     0

     /tmp/zfs_test/disque_3 ONLINE       0     0     0

spare                   UNAVAIL      0     0     0 insufficient replicas

       7760834922797222775   UNAVAIL      0     0     0 was /tmp/zfs_test/disque_4

       9623051411205814655   UNAVAIL      0     0     0 was /tmp/zfs_test/disque_9

     2705405041636850921     UNAVAIL      0     0     0 was /tmp/zfs_test/disque_5

     /tmp/zfs_test/disque_6 ONLINE       0     0     0

     /tmp/zfs_test/disque_7 ONLINE 0 0 39

     /tmp/zfs_test/disque_8 ONLINE       0     0     0

 spares

  /tmp/zfs_test/disque_9    UNAVAIL   cannot open

errors: Permanent errors have been detected in the following files:

        /media/zfs_test/apt/archives/iceape-browser_1.1.9-5_i386.deb

        /media/zfs_test/apt/archives/libnspr4-0d_4.7.1-3_i386.deb

        /media/zfs_test/apt/archives/libedataserver1.2-9_2.22.2-1_i386.deb

        /media/zfs_test/apt/archives/libcamel1.2-11_2.22.2-1_i386.deb

        /media/zfs_test/apt/archives/libexchange-storage1.2-3_2.22.2-1_i386.deb

        /media/zfs_test/apt/archives/libgnome-pilot2_2.0.15-2.4_i386.deb

        /media/zfs_test/apt/archives/libgtkhtml3.14-19_3.18.2-1_i386.deb

        /media/zfs_test/apt/archives/libnm-glib0_0.6.6-1_i386.deb

        /media/zfs_test/apt/archives/libpisock9_0.12.3-5_i386.deb

        /media/zfs_test/apt/archives/libpisync1_0.12.3-5_i386.deb

        /media/zfs_test/apt/archives/libpanel-applet2-0_2.20.3-5_i386.deb

        /media/zfs_test/apt/archives/evolution-common_2.22.2-1.1_all.deb

        /media/zfs_test/apt/archives/libwnck22_2.22.3-1_i386.deb

        /media/zfs_test/apt/archives/libxslt1.1_1.1.24-1_i386.deb

Et ainsi de suite... La commande indique non seulement le disque où se sont produites les erreurs, via la colonne CKSUM, mais aussi très précisément quels sont les fichiers qui ne sont plus bons. Dans l'exemple, il s'agit de 79 fichiers du dossier /apt/archives/.

Dans le cas d'un système de fichiers réel, si une telle chose se produit, l'administrateur connaît rapidement le nom des fichiers erronés et peut, après avoir réparé, c'est-à-dire remplacé les disques, faire une restauration à partir de la sauvegarde.

4.2.6 Remplacement des disques

Comme vous avez des données très importantes sur vos disques, vous commandez de nouveaux disques qui iront remplacer les anciens. Manque de bol, la capacité ridicule de 512 Mo n'existe plus et les seuls nouveaux disques que vous trouvez sont des disques de 650 Mo :

# dd if=/dev/zero of=nouveau_0 bs=1M count=650

# dd if=/dev/zero of=nouveau_1 bs=1M count=650

Comment va se comporter le système avec des disques de taille supérieure ? Est-ce qu'il va subsister de la place non utilisée sur le disque ?

Le remplacement des disques manquant est possible, même avec des disques de plus grande taille. Toutefois, il n'est pas complètement effectif dans notre exemple, notamment, le système refuse obstinément d'enlever l'ancien disque arguant du fait qu'il manque des données. Supprimons donc ces données qui sont de toute manière perdues (on pensera à remercier l'administrateur d'avoir fait des sauvegardes sur bande) :

# zpool status -v raid6 | grep media | xargs rm -f

Demandons-lui de se réparer avec une commande du type fsck :

# zpool scrub raid6

La commande s'exécute en arrière plan et zpool status raid6 vous dit où elle en est. En attendant qu'elle termine, profitez-en pour regarder le résultat de la commande zpool iostat -v raid6. Elle indique la place utilisée et restante des pools et systèmes de fichiers, ainsi que le nombre d'opérations d'écriture et de lecture par secondes effectuées sur chaque disque et la bande passante que cela représente. Il est possible de demander à ce que l'exécution de cette commande se répète selon un intervalle donné, par exemple toutes les 3 secondes : zpool iostat -v raid6 3.

Lorsque la commande est terminée, vous pouvez enlever les anciens disques défectueux avec la commande zpool detach raid6 /tmp/zfs_test/disque_5 ou en utilisant le nom système du disque (dans notre exemple, il s'agit de : 2705405041636850921).

La commande zpool list qui donne un résumé très synthétique des pools indique qu'il n'y a pas eu d'augmentation de la capacité. Si l'on souhaite que la capacité augmente, il faudra remplacer tous les anciens disques avec des nouveaux de capacité identique. Tout cela se réalise bien entendu alors que le système de fichiers est monté, vous pouvez accéder à vos fichiers en toute transparence !

Un bémol toutefois, pour que mon système prenne effectivement en compte l'augmentation de la capacité totale, il a fallu que j'arrête puis relance zfs-fuse et que j'importe à nouveau le pool. Cette manipulation n'a pris que quelques secondes, mais, pendant ces quelques secondes, les fichiers ne sont plus accessibles (pensez à prévenir les utilisateurs).

4.2.7 Augmentation de capacité par ajout d'un nouveau raidz au pool

Un autre moyen d'augmenter la capacité est d'ajouter un nouvel ensemble de disques dans notre pool (que nous avons nommé raid6). Nous pouvons faire cela avec la commande suivante :

# zpool add raid6 raidz2 /tmp/zfs_test/dvd_{0,1,2,3,4,5,6,7,8}

Il faut garder en tête que ZFS a besoin d'un nombre de périphériques identiques entre ensemble de fichiers d'un même pool. Cela lui simplifie le travail (il est toutefois possible de le forcer avec l'option -f). Nous obtenons ainsi une sorte de raid 0+6 :

# zpool status -v

  pool: raid6

state: ONLINE

scrub: resilver completed after 0h11m with 0 errors on Thu Oct 16 22:35:33 2008

config:

 NAME                         STATE     READ WRITE CKSUM

 raid6                        ONLINE       0     0     0

  raidz2                     ONLINE       0     0     0

/tmp/zfs_test/nouveau_3 ONLINE       0     0     0

     /tmp/zfs_test/nouveau_4 ONLINE       0     0     0

     /tmp/zfs_test/nouveau_2 ONLINE       0     0     0

     /tmp/zfs_test/nouveau_5 ONLINE       0     0     0

     /tmp/zfs_test/nouveau_0 ONLINE       0     0     0

     /tmp/zfs_test/nouveau_1 ONLINE       0     0     0

     /tmp/zfs_test/nouveau_6 ONLINE       0     0     0

     /tmp/zfs_test/nouveau_7 ONLINE       0     0     0

     /tmp/zfs_test/nouveau_8 ONLINE       0     0     0

  raidz2 ONLINE 0 0 0

     /tmp/zfs_test/dvd_0      ONLINE       0     0     0

     /tmp/zfs_test/dvd_1      ONLINE       0     0     0

     /tmp/zfs_test/dvd_2      ONLINE       0     0     0

     /tmp/zfs_test/dvd_3      ONLINE       0     0     0

     /tmp/zfs_test/dvd_4      ONLINE       0     0     0

     /tmp/zfs_test/dvd_5      ONLINE       0     0     0

     /tmp/zfs_test/dvd_6      ONLINE       0     0     0

     /tmp/zfs_test/dvd_7      ONLINE       0     0     0

     /tmp/zfs_test/dvd_8      ONLINE       0     0     0

errors: No known data errors

Soit une capacité portée à

# df -h

Sys. de fich.         Tail. Occ. Disp. %Occ. Monté sur

/dev/hda1             9,2G 5,1G 3,7G 59% /

udev                   10M   52K   10M   1% /dev

/dev/hda3             141G 102G   32G 77% /home

overflow              1,0M   12K 1012K   2% /tmp

raid6                  32G 1,8G   30G   6% /media/zfs_test

ou encore :

# zpool list

NAME    SIZE   USED AVAIL    CAP HEALTH ALTROOT

raid6 40,7G 2,21G 38,4G     5% ONLINE -

En faisant ainsi, on a augmenté, de manière transparente, la taille totale du système de fichiers.

La taille donnée par la commande zfs-list et celle donnée par la commande du -h sont différentes. Il semble que la commande zfs-list ne prenne pas en compte dans son calcul les disques réservés au calcul des sommes de contrôle (deux dans notre cas).

4.2.8 Rappel des commandes utiles

zpool create nom_du_pool type_du_pool noms_des_périphériques crée un pool selon les options spécifiées. Le type du pool peut-être « mirror », « raidz » ou « raidz2 ».

zpool destroy nom_du_pool pour détruire un pool entier. Attention, cette commande ne demande pas de confirmation et il ne semble pas exister d'option « garde fou » du type « -i » des coreutils !

zpool iostat -v permet l'affichage des statistiques d'entrées/sorties des pools tout en indiquant la répartition des données et de ces entrées/sorties sur chacun des fichiers ou périphériques constituant le pool.

zpool status -v donne l'état de chacun des pools. Cette commande détaille les erreurs lorsqu'il y en a.

5. Systèmes de fichiers

La commande zpool que nous venons de voir crée un système de fichiers racine dans le pool et le monte sur le point de montage qu'on lui a indiqué. Il est toutefois possible de créer, dans le pool, des systèmes de fichiers indépendants. Listons les systèmes de fichiers déjà utilisables :

# zfs list

NAME    USED AVAIL REFER MOUNTPOINT

raid6 32,7M 26,6G 32,6M /media/zfs_test

Nous retrouvons notre système de fichiers raid6 (qui est aussi le nom du pool) monté sur /media/zfs_test. Nous pouvons maintenant créer au maximum 264 systèmes de fichiers dans ce pool, par exemple :

# zfs create raid6/usr

# zfs create raid6/home

# zfs create raid6/var

Ce qui donne :

# zfs list

NAME         USED AVAIL REFER MOUNTPOINT

raid6       32,9M 26,7G 32,6M /media/zfs_test

raid6/home 41,9K 26,7G 41,9K /media/zfs_test/home

raid6/usr   41,9K 26,7G 41,9K /media/zfs_test/usr

raid6/var   41,9K 26,7G 41,9K /media/zfs_test/var

Vous pouvez vérifier avec la commande df -h que les systèmes de fichiers sont bien montés. Ils se partagent tous un même espace de stockage qui est le pool en lui-même. Si on le souhaite, on peut remplir raid6/home et, dans ce cas, il ne restera plus de place pour les autres systèmes de fichiers. On peut voir cela comme des répertoires. À la différence prêt qu'il est possible de préciser quelques options nommées « propriétés ». Par exemple, il est possible de redéfinir le point de montage :

# zfs set mountpoint=/media/sauvegarde raid6

# zfs set mountpoint=/media/var raid6/var

# zfs list

NAME         USED AVAIL REFER MOUNTPOINT

raid6       32,9M 26,7G 32,6M /media/sauvegarde

raid6/home 41,9K 26,7G 41,9K /media/sauvegarde/home

raid6/usr   41,9K 26,7G 41,9K /media/sauvegarde/usr

raid6/var   41,9K 26,7G 41,9K /media/var

# zfs mount raid6/var

La dernière commande permet de remonter le système de fichiers dont on vient de modifier le point de montage, le changement l'ayant démonté automatiquement. Si on change plusieurs points de montage, on pourra utiliser la commande zfs mount -a.

Pour obtenir les propriétés d'un système de fichiers, utilisez la commande zfs get all nom_du_systeme_de_fichiers, par exemple :

# zfs get all raid6/var

NAME       PROPERTY              VALUE                  SOURCE

raid6/var type                  filesystem             -

raid6/var creation              lun oct 27 23:10 2008 -

raid6/var used                  41,9K                  -

raid6/var available             26,7G                  -

raid6/var referenced            41,9K                  -

raid6/var compressratio         1.00x                  -

raid6/var mounted               yes                    -

raid6/var quota                 none                   default

raid6/var reservation           none                   default

raid6/var recordsize            128K                   default

raid6/var mountpoint            /media/var             local

raid6/var sharenfs              off                    default

raid6/var checksum              on                     default

raid6/var compression           off                    default

raid6/var atime                 on                     default

raid6/var devices               on                     default

raid6/var exec                  on                     default

raid6/var setuid                on                     default

raid6/var readonly              off                    default

raid6/var zoned                 off                    default

raid6/var snapdir               hidden                 default

raid6/var aclmode               groupmask              default

raid6/var aclinherit            restricted             default

raid6/var canmount              on                     default

raid6/var shareiscsi            off                    default

raid6/var xattr                 on                     default

raid6/var copies                1                      default

raid6/var version               3                      -

raid6/var utf8only              off                    -

raid6/var normalization         none                   -

raid6/var casesensitivity       sensitive              -

raid6/var vscan                 off                    default

raid6/var nbmand                off                    default

raid6/var sharesmb              off                    default

raid6/var refquota              none                   default

raid6/var refreservation        none                   default

raid6/var primarycache          all                    default

raid6/var secondarycache        all                    default

raid6/var usedbysnapshots       0                      -

raid6/var usedbydataset         41,9K                  -

raid6/var usedbychildren        0                      -

raid6/var usedbyrefreservation 0                      -

Le paramètre SOURCE peut prendre trois valeurs :

- default qui indique une valeur par défaut (ou inchangée) ;

- local qui indique que la valeur a été fixée spécifiquement pour ce système de fichiers ;

- inherited qui indique que la valeur est héritée d'un système de fichiers parent.

On a déjà vu que l'on peut changer le point de montage en changeant la propriété mountpoint, mais ce changement nécessite de remonter les systèmes de fichiers. Heureusement, ce n'est pas toujours le cas et, notamment, il est possible de changer, de manière transparente et alors que le système de fichiers est en fonctionnement, certaines propriétés telles que compression, quota et reservation par exemple.

5.1 Compression

Il est possible d'indiquer, à la volée, à un système de fichier ZFS s'il doit compresser les données ou non. Pour l'exemple, créons un système de fichiers nomméraid6/etc. En général, ce dossier contient plein de fichiers de configuration de type texte qui se prêtent bien à la compression. Puis, indiquons-lui qu'il doit maintenant compresser les données en mettant la propriété compression à on. Enfin, copions le contenu de /etc et voyons le résultat de la compression :

# zfs create raid6/etc

# zfs set compression=on raid6/etc

# zfs get compression raid6/etc

NAME       PROPERTY     VALUE      SOURCE

raid6/etc compression on         local

# cp -a /etc/* /media/sauvegarde/etc/

# zfs get compression, compressratio raid6/etc

NAME       PROPERTY       VALUE      SOURCE

raid6/etc compression    on         local

raid6/etc compressratio 2.05x      -

# zfs list raid6/etc

NAME        USED AVAIL REFER MOUNTPOINT

raid6/etc 18,2M 26,7G 18,2M /media/sauvegarde/etc

# du -hs /etc

35M /etc

La propriété compressratio indique le taux effectif de compression des données, ici un peu plus de 2 fois.

Lorsqu'il existe des données préalablement à la modification de la propriété, ces dernières ne sont pas compressées. Elles restent non compressées sur le disque. Toutefois, et c'est là que c'est intéressant, les nouvelles données ajoutées aux fichiers non compressés, seront, elles, compressées. Ainsi, un fichier peut avoir une partie non compressée et une partie compressée (celle qui aura été écrite après le changement de la propriété).

De même, lorsque l'on modifie à nouveau la propriété vers la valeur off, c'est-à-dire sans compression, les données ajoutées le seront sans compression, mais l'état de celles qui étaient compressées précédemment n'est pas modifié.

Cet exemple montre que certaines propriétés affectent les blocs et pas, comme on pourrait s'y attendre, les fichiers eux-mêmes.

5.2 Quotas

Les quotas sur ZFS ne fonctionnent pas à la manière des quotas POSIX. Ils sont fixés par système de fichiers et non par utilisateur. Deux propriétés permettent de les fixer :

- quota limite l'espace du système de fichiers, pour lui-même et tous les systèmes de fichiers fils, incluant les instantanés ou snapshots.

- refquota fait exactement la même chose, mais la limite n'inclut pas les instantanés ou les descendants.

Il est donc possible de jouer avec ces deux propriétés de manière à limiter la taille maximale occupée par un système de fichiers. Dans notre exemple, on pourrait fixer la taille maximale de /var à 5 Go avec la propriété refquota et autoriser 5 Go pour les instantanés en fixant à 10 Go la propriété quota.

Dès que l'une ou l'autre des propriétés sont définies, la commande df -h indique la taille du disque, ainsi que la place restante. Elles sont déterminées par la propriété qui contraint le plus (en général, il s'agit de refquota).

Utilisée avec l'option de compression, le quota s'applique, une fois les données compressées. Ainsi, si un système de fichiers est plein avec un quota de 100 Mo, que la propriété de compression est à vrai et que le taux de compression est de 2x alors ce système de fichiers contient 200 Mo de données non compressées.

Lorsque que le quota est atteint, une erreur survient pour l'indiquer et, dès lors, il n'est plus possible d'ajouter des données ou des fichiers.

5.3 Réservation

La propriété reservation permet de réserver de l'espace sur un système de fichiers. Cet espace est directement et immédiatement consommé sur l'espace disponible du système de fichiers parent. Il doit donc être disponible au moment où l'on fixe la valeur de la propriété.

5.4 Héritage des propriétés

Certaines propriétés peuvent être héritées directement de leur(s) parent(s). C'est le cas par exemple pour la compression, le point de montage, les quotas et la réservation. Si l'on change les propriétés d'un système de fichiers, tous ses sous-systèmes hériteront de la nouvelle valeur.

5.5 Instantanés ou snapshots

Comme pour toutes les fonctionnalités que nous avons déjà vues, celle ci est très simple d'emploi. De plus, la création d'un instantané ne consomme pas de place supplémentaire. Seules les données créées ou modifiées à la suite de cette création utiliseront de l'espace supplémentaire. Un exemple d'utilisation des instantanés :

# zfs list raid6/home

NAME         USED AVAIL REFER MOUNTPOINT

raid6/home 57,0K 26,7G 57,0K /media/sauvegarde/home

# ls -lsa /media/sauvegarde/home

total 25

3 drwxr-xr-x 2 root root     5 nov 30 19:08 .

5 drwxr-xr-x 6 root root    10 oct 28 19:43 ..

11 -rw------- 1 root root 10653 nov 30 19:08 .bash_history

3 -rw------- 1 root root   701 nov 30 19:08 .bash_profile

3 -rw------- 1 root root 1244 nov 30 19:08 .bashrc

Maintenant que nous avons vu ce qu'il y a dans notre répertoire, créons notre premier instantané en utilisant la commande zfs snapshot nom_du_snapshot et observons le résultat :

# zfs snapshot raid6/home@premier

# zfs list

NAME                 USED AVAIL REFER MOUNTPOINT

raid6/home          57,0K 26,7G 57,0K /media/sauvegarde/home

raid6/home@premier      0      - 57,0K -

Comme on peut le voir, l'instantané premier n'occupe aucune place. Copions des données :

# cp /etc/passwd /media/sauvegarde/home

# zfs list

NAME                 USED AVAIL REFER MOUNTPOINT

raid6/home          98,9K 26,7G 61,6K /media/sauvegarde/home

raid6/home@premier 37,2K      - 57,0K -

Il est ainsi possible de créer autant d'instantanés que l'on désire. Nous pouvons par exemple réitérer l'opération : créer un instantané, puis copier un fichier dans le répertoire :

# zfs snapshot raid6/home@deuxieme

# cp /etc/X11/xorg.conf /media/sauvegarde/home

L'intérêt de tout cela, c'est qu'il est possible de revenir en arrière. Par exemple, je peux revenir à l'état initial en utilisant la commande zfs rollback raid6/home@premier ou encore à l'état juste avant la copie de mon dernier fichier avec zfs rollback raid6/home@deuxieme. Mieux, il est même possible d'obtenir la différence avec la commande zfs send -i raid6/home@premier raid6/home@deuxieme > diff. Dans l'exemple, il s'agit du fichier /etc/passwd copié entre les prises des instantanés. Cette différence pourra être relue avec la commande zfs receive qui créera alors un instantané correspondant à ce qui lui a été envoyé.

Ces deux dernières commandes peuvent être utilement combinées avec ssh pour, par exemple, générer des sauvegardes différentielles et les envoyer sur un serveur distant.

6. Après un redémarrage

Dans le cas où vous avez redémarré votre machine, votre beau système de fichiers ZFS n'est plus présent. Que faire pour le retrouver ? Comment se souvenir, après quelques jours, mois (ou années) quelle configuration vous aviez utilisée, les disques de spare, raidz1, raidz2, mirror ou pas, le point de montage ?

Avec ZFS, rien de plus simple. Après avoir chargé le module fuse et redémarré le démon zfs-fuse, rendez-vous directement dans le dossier où vous avez créé vos fichiers (les faux disques) et tapez la commande zpool import -d ..

Cette commande recherche, parmi les fichiers du dossier courant (« . »), les périphériques virtuels (vdev), puis elle indique le nom et la configuration de chaque pool trouvé parmi ces périphériques. Pour importer réellement un pool, nommez-le à la fin de la commande, par exemple : zpool import -d . raid6 . Après quelques instants, le système de fichiers est à nouveau monté (sur le bon point de montage) et prêt à être utilisé.

Si le système de fichiers n'est pas monté correctement, vérifiez que vous avez bien le module fuse chargé (modprobe fuse), que vous avez bien lancé le démon zfs-fuse (zfs-fuse –no-daemon) et que les répertoires sur lesquels sont montés vos systèmes de fichiers ZFS sont vides.

7. En conclusion

Cet article n'a pas fait le tour de toutes les fonctionnalités et propriétés de ZFS. Aussi, le lecteur curieux pourra regarder de près le système de clones et les permissions liées à l'administration par exemple.

Il est vraiment dommage que ce système de fichiers ne puisse être inclus nativement dans le noyau GNU/Linux par la faute d'une bête incompatibilité de licence...

Bien entendu, tout ce qui est décrit dans cet article est réalisable nativement, c'est-à-dire sans fuse et son démon zfs-fuse, sous FreeBSD 7.0, Solaris 10, Mac OS X et, me souffle-t-on, Nexenta [11].

Je tiens à remercier mes mentors qui ont été attentifs aux erreurs et imprécisions et m'ont patiemment relu et corrigé : Bruno Bonfils, Guillaume Lelarge et Sébastien Tricaud.

Références

[0] http://opensolaris.org/os/community/zfs/source/

[1] http://opensource.org/

[2] http://www.opensolaris.org/os/licensing/cddllicense.txt

[3] http://blogs.sun.com/bonwick/date/20040925#128_bit_storage_are_you

[4] http://www.freebsd.org/releases/7.0R/announce.html

[5] http://www.scons.org/

[6] https://developer.berlios.de/project/showfiles.php?group_id=6836

[7] http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02

[8] http://www.manpagez.com/man/8/zpool/

[9] http://docs.sun.com/app/docs/doc/817-2271/gazss?l=en&a=view

[10] http://opensolaris.org/os/community/zfs/docs/

[11] http://foss-boss.blogspot.com/2008/11/nexenta-can-you-say-solabuntu-part1.html