Seit einiger Zeit ist das neue Dateisystem von Sun, ZFS, in FreeBSD 7-CURRENT verfügbar. Zeit sich mal ein bisschen genauer mit ZFS zu befassen. Folgende Beispiele zeigen, wie man einen Mehrbenutzerserver mit mehreren Festplatten und ZFS aufsetzen kann. Die Beispiele wurden mit dem Mai Snapshot von CURRENT durchgeführt:
# uname -a
FreeBSD test.chruetertee.ch 7.0-CURRENT-200705 FreeBSD 7.0-CURRENT-200705 #0: Mon May  7 11:24:25 UTC 2007
root@almeida.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386
Damit ZFS verwendet werden kann, muss es in der rc.conf aktiviert und das dazugehörige rc.d-Skript ausgeführt werden. Ist der Eintrag in rc.conf einmal gemacht, wird die ZFS-Unterstützung beim Systemstart aktiviert und die vorhandenen ZFS-Dateisysteme automatisch gemountet.
# echo 'zfs_enable="YES"' >> /etc/rc.conf 
# /etc/rc.d/zfs start
Damit das System mit dem ZFS-Dateisystem umgehen kann, wird automatisch das entsprechende Kernelmodul geladen:
# kldstat
Id Refs Address    Size     Name
 1    4 0xc0400000 7ddc50   kernel
 2    1 0xc0bde000 5f5dc    acpi.ko
 3    1 0xc756d000 92000    zfs.ko
Bei einem Neustart wird man dann immer mit folgender Meldung begrüsst:
WARNING: ZFS is considered to be an experimental feature in FreeBSD.
ZFS filesystem version 6
ZFS storage pool version 6
Damit man ZFS-Dateisysteme erstellen kann, müssen zuerst die Festplatten, auf denen man ZFS-Dateisysteme verwenden möchte, zu einem ZFS-Pool zusammengefügt werden. Folgender Befehl kreiert einen Pool, in denen die Platten da1 und da2 zur Datensicherheit gespiegelt sind. Der Pool namens tank ist danach im Verzeichnisbaum unter /tank eingehängt.
# zpool create tank mirror da1 da2
# zpool list
NAME                    SIZE    USED   AVAIL    CAP  HEALTH     ALTROOT
tank                   16.9G    111K   16.9G     0%  ONLINE     -
# df -h
Filesystem     Size    Used   Avail Capacity  Mounted on
/dev/da0s1a    496M    105M    351M    23%    /
devfs          1.0K    1.0K      0B   100%    /dev
/dev/da0s1d    989M     12K    910M     0%    /tmp
/dev/da0s1f    9.2G    116M    8.3G     1%    /usr
/dev/da0s1e    1.9G    250K    1.8G     0%    /var
tank            17G      0B     17G     0%    /tank
# mount
/dev/da0s1a on / (ufs, local)
devfs on /dev (devfs, local)
/dev/da0s1d on /tmp (ufs, local, soft-updates)
/dev/da0s1f on /usr (ufs, local, soft-updates)
/dev/da0s1e on /var (ufs, local, soft-updates)
tank on /tank (zfs, local)
Informationen zum Pool erhält man wie folgt:
# zpool status
  pool: tank
 state: ONLINE
 scrub: none requested
config:
        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            da1     ONLINE       0     0     0
            da2     ONLINE       0     0     0
Zu jeder Zeit können einem Pool weitere Platten hinzugefügt werden. Sind zu einem späteren Zeitpunkt die ZFS-Dateisysteme in einem Pool fast voll, so können dem Pool neue Platten hinzugefügt werden und die sich darin befindenden Dateisysteme sofort den neuen Speicherplatz benutzen. Im folgenden Beispiel werden dem schon bestehenden Pool tank die gespiegelten Platten da3 und da4 hinzugefügt:
# zpool add tank mirror da3 da4
# zpool status -v tank
  pool: tank
 state: ONLINE
 scrub: none requested
config:
        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            da1     ONLINE       0     0     0
            da2     ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            da3     ONLINE       0     0     0
            da4     ONLINE       0     0     0
Ein Pool kann wie folgt entfernt werden. Alle Daten gehen dabei jedoch verloren.
# zpool destroy tank
# zpool status -v tank
cannot open 'tank': no such pool
Folgendes Beispiel erstellt einen Pool, in welchem die Daten auf die Spiegel da1, da2 und da3, da4 verteilt werden.
# zpool create tank mirror da1 da2 mirror da3 da4
Nun kann ein ZFS-Dateisystem innerhalb des Pools erstellt werden. Hier wird das Dateisystem /ports innerhalb vom Pool tank erstellt:
# zfs create tank/ports
In das Dateisystem /ports soll später der Portbaum hinein kommen. Da der Portbaum fast ausschliesslich aus Textdateien besteht, kann eine Komprimierung auf dieses Dateisystem eingeschaltet werden.
# zfs set compression=gzip tank/ports
# zfs get compression tank/ports
NAME        PROPERTY     VALUE       SOURCE
tank/ports  compression  gzip        local
Nun kann das Dateisystem nach /usr/ports gemountet und der Portbaum heruntergeladen werden:
# zfs set mountpoint=/usr/ports tank/ports
# portsnap fetch extract
Jetzt wird ein Dateisystem für die home-Verzeichnisse kreiert. In diesem Dateisystem wird nun ein weiteres für den Benutzer beat erstellt.
# zfs create tank/home
# zfs create tank/home/beat
Für den Benutzer setzen wir nun ein Quota von 1GB fest:
# zfs set quota=1G tank/home/beat
Alle Informationen eines Dateisystems können wie folgt abgefragt werden:
# zfs get all tank/home/beat
NAME            PROPERTY       VALUE                  SOURCE
tank/home/beat  type           filesystem             -
tank/home/beat  creation       Mon May  7 12:42 2007  -
tank/home/beat  used           18K                    -
tank/home/beat  available      1024M                  -
tank/home/beat  referenced     18K                    -
tank/home/beat  compressratio  1.00x                  -
tank/home/beat  mounted        yes                    -
tank/home/beat  quota          1G                     local
tank/home/beat  reservation    none                   default
tank/home/beat  recordsize     128K                   default
tank/home/beat  mountpoint     /tank/home/beat        default
tank/home/beat  sharenfs       off                    default
tank/home/beat  checksum       on                     default
tank/home/beat  compression    off                    default
tank/home/beat  atime          on                     default
tank/home/beat  devices        on                     default
tank/home/beat  exec           on                     default
tank/home/beat  setuid         on                     default
tank/home/beat  readonly       off                    default
tank/home/beat  jailed         off                    default
tank/home/beat  snapdir        hidden                 default
tank/home/beat  aclmode        groupmask              default
tank/home/beat  aclinherit     secure                 default
tank/home/beat  canmount       on                     default
tank/home/beat  shareiscsi     off                    default
tank/home/beat  xattr          off                    temporary
tank/home/beat  copies         1                      default
Nun werden die home-Verzeichnisse nach /usr/home gemountet:
# zfs set mountpoint=/usr/home tank/home
# df -h
Filesystem        Size    Used   Avail Capacity  Mounted on
/dev/da0s1a       496M    105M    351M    23%    /
devfs             1.0K    1.0K      0B   100%    /dev
/dev/da0s1d       989M     12K    910M     0%    /tmp
/dev/da0s1f       9.2G    116M    8.3G     1%    /usr
/dev/da0s1e       1.9G    310K    1.8G     0%    /var
tank               33G      0B     33G     0%    /tank
tank/ports         33G     98M     33G     0%    /usr/ports
tank/home          33G      0B     33G     0%    /usr/home
tank/home/beat    1.0G    128K    1.0G     0%    /usr/home/beat
Nun wird versucht, das home-Verzeichnis von beat mit einer zu großen Testdatei zu füllen:
# cd /usr/home/beat/
# dd if=/dev/zero of=bla bs=1M count=2024
# df -h
Filesystem        Size    Used   Avail Capacity  Mounted on
/dev/da0s1a       496M    105M    351M    23%    /
devfs             1.0K    1.0K      0B   100%    /dev
/dev/da0s1d       989M     12K    910M     0%    /tmp
/dev/da0s1f       9.2G    116M    8.3G     1%    /usr
/dev/da0s1e       1.9G    466K    1.8G     0%    /var
tank               32G    128K     32G     0%    /tank
tank/ports         32G     98M     32G     0%    /usr/ports
tank/home          32G    128K     32G     0%    /usr/home
tank/home/beat    1.0G    1.0G    1.5M   100%    /usr/home/beat
Das gesetzte Quota verhindet, dass mehr als 1GB Daten in diesem Verzeichnis abgelegt werden. Ist das zuwenig, kann die Quota-Grenze auch erhöht werden:
# zfs set quota=2G tank/home/beat
# df -h | grep beat
tank/home/beat    2.0G    1.0G    2.0G    50%    /usr/home/beat
# rm bla
# df -h | grep beat
tank/home/beat    2.0G    128K    2.0G     0%    /usr/home/beat
Es lässt sich auch in einem ZFS-Dateisystem Speicherplatz reservieren. Für den Benutzer beat wird nun 1GB Speicherplatz reserviert.
# zfs set reservation=1G tank/home/beat
# zfs get reservation tank/home/beat
NAME            PROPERTY     VALUE           SOURCE
tank/home/beat  reservation  1G              local
Das home-Verzeichnis von beat ist immer noch gleich gross, in dem darüberliegenden Dateisystemen ist der reservierte Platz nun als besetzt markiert. Der Benutzer beat hat nun also immer mind. 1GB zur Verfügung, egal wieviel Platz andere Benutzer verbrauchen.
# zfs list
NAME             USED  AVAIL  REFER  MOUNTPOINT
tank            1.10G  32.1G    18K  /tank
tank/home       1.00G  32.1G    20K  /usr/home
tank/home/beat  25.5K  2.00G  25.5K  /usr/home/beat
tank/ports      97.8M  32.1G  97.8M  /usr/ports
Der reservierte Speicherplatz kann auch wieder aufgehoben werden. In den höherliegenden Dateisystemen wird der Speicherplatz nun wieder freigegeben:
# zfs set reservation=0 tank/home/beat
# zfs list
NAME             USED  AVAIL  REFER  MOUNTPOINT
tank            98.0M  33.1G    18K  /tank
tank/home       45.5K  33.1G    20K  /usr/home
tank/home/beat  25.5K  2.00G  25.5K  /usr/home/beat
tank/ports      97.8M  33.1G  97.8M  /usr/ports
Nun wird ein weiteres Benutzerverzeichnis erstellt und dieses mit Daten gefüllt:
# zfs create tank/home/andereruser
# dd if=/dev/zero of=/usr/home/andereruser/wichtig count=2000
2000+0 records in
2000+0 records out
1024000 bytes transferred in 0.232209 secs (4409821 bytes/sec)
# pwd
/usr/home/andereruser
# echo "Hallo" > Datei
# ll
total 1027
-rw-r--r--  1 root  wheel        6 May  7 13:08 Datei
-rw-r--r--  1 root  wheel  1024000 May  7 13:07 wichtig
Nun kann ein Snapshot aller Benutzerverzeichnisse gezogen werden. Durch die -r-Option werden auch Snapshots von darunterliegenden Dateissystemen gemacht. 
# zfs snapshot -r tank/home@now
# zfs list -t snapshot
NAME                        USED  AVAIL  REFER  MOUNTPOINT
tank/home@now                  0      -    21K  -
tank/home/andereruser@now      0      -  1.02M  -
tank/home/beat@now             0      -  27.5K  -
Nun werden die Daten verändert.
# pwd
/usr/home/andereruser
# rm wichtig
# echo "Hallo2" >> Datei
# echo "Neu" > DateiNeu
# ls -l
total 2
-rw-r--r--  1 root  wheel  13 May  7 13:09 Datei
-rw-r--r--  1 root  wheel   4 May  7 13:09 DateiNeu
Die gezogenen Snapshots sind wie Dateisysteme sichtbar und können auch so genutzt werden.
# zfs list
NAME                        USED  AVAIL  REFER  MOUNTPOINT
tank                       99.0M  33.1G    18K  /tank
tank/home                  1.09M  33.1G    21K  /usr/home
tank/home@now                  0      -    21K  -
tank/home/andereruser      1.04M  33.1G    20K  /usr/home/andereruser
tank/home/andereruser@now  1.02M      -  1.02M  -
tank/home/beat             27.5K  2.00G  27.5K  /usr/home/beat
tank/home/beat@now             0      -  27.5K  -
tank/ports                 97.8M  33.1G  97.8M  /usr/ports
Ein Snapshot kann jederzeit zurückgespielt werden. Dabei werden alle Änderungen, die seit dem Snapshot gemacht wurden, rückgängig gemacht.
# zfs rollback -r tank/home/andereruser@now
# ll
total 1028
-rw-r--r--  1 root  wheel        6 May  7 13:08 Datei
-rw-r--r--  1 root  wheel  1024000 May  7 13:07 wichtig
# cat Datei
Hallo
Benötigt man den Snapshot nicht mehr, kann dieser gelöscht werden.
# zfs destroy -r tank/home@now
Soll eine Festplatte ausgetauscht werden, kann man diese zuerst offline setzten. Danach werden keine Lese- und Schreiboperationen mehr auf das Laufwerk ausgeführt.
# zpool offline tank da4
Bringing device da4 offline
# zpool status
  pool: tank
 state: DEGRADED
status: One or more devices has been taken offline by the administrator.
        Sufficient replicas exist for the pool to continue functioning in a
        degraded state.
action: Online the device using 'zpool online' or replace the device with
        'zpool replace'.
 scrub: none requested
config:
        NAME        STATE     READ WRITE CKSUM
        tank        DEGRADED     0     0     0
          mirror    ONLINE       0     0     0
            da1     ONLINE       0     0     0
            da2     ONLINE       0     0     0
          mirror    DEGRADED     0     0     0
            da3     ONLINE       0     0     0
            da4     OFFLINE      0     0     0
errors: No known data errors
Nachdem das Laufwerk getauscht wurde, kann dieses wieder aktiviert werden:
# zpool online tank da4
Bringing device da4 online
Das ausgetauschte Laufwerk wird nun mit den Daten des gespiegelten Laufwerks synchronisiert.
# zpool status
  pool: tank
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
 scrub: resilver in progress, 82.43% done, 0h0m to go
config:
        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            da1     ONLINE       0     0     0
            da2     ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            da3     ONLINE       0     0     0
            da4     ONLINE       0     0     0
errors: No known data errors
Ist das Synchronisieren fertig, kann man nachschauen, ob dabei Fehler aufgetreten sind.
# zpool status
  pool: tank
 state: ONLINE
status: One or more devices is currently being resilvered.  The pool will
        continue to function, possibly in a degraded state.
action: Wait for the resilver to complete.
 scrub: resilver completed with 0 errors on Mon May  7 13:32:24 2007
config:
        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            da1     ONLINE       0     0     0
            da2     ONLINE       0     0     0
          mirror    ONLINE       0     0     0
            da3     ONLINE       0     0     0
            da4     ONLINE       0     0     0
errors: No known data errors
Die ZFS-Pools können auch täglich durch die periodic-Scripte geprüft werden:
# echo 'daily_status_zfs_enable="YES"' >> /etc/periodic.conf
Danach findet man täglich in den daily-Mails den Status aller Pools:
Checking status of zfs pools:
all pools are healthy
Weitere Informationen zu ZFS findet man im Quickstart-Guide, im äusserst ausführlichen ZFS-Handbuch von OpenSolaris und in den Manpages zpool(1) und zfs(1).