Table of Content
- useful links
- Pool handling
- Dataset handling
- Encrypted Datasets
- Snapshots
- Send and Receive
- Troubleshooting and Fixes
useful links
https://wiki.archlinux.org/index.php/ZFS
Pool handling
Comands | Description |
---|---|
zpool status | gives status over all pools |
zpool scrub ${pool} | initiate a scrub. Should be done on a regular basis. Takes ages on big pools. |
zpool scrub -s ${pool} | cancel a running scrub |
zpool create -o ashift=<SHIFTsize> -m none <pool_name> <UUID_of_disk> | create a new storage pool with one disk |
zpool attach <pool_name> <UUID_of_disk1> <UUID_of_disk2> | adds a second disk to a “normal” zpool and converts it to a mirror pool |
zpool create -m none main raidz1 ${spaceSepUUIDs} | create a new storage pool called main . Make sure you use /dev/disk/by-id |
zpool create -o ashift=12 -m /mnt/main main raidz1 ${spaceSepUUIDs.} | use ashift=12 for HDDs with 4k Sektors |
zpool create -o ashift=13 -m none ssd mirror ${spaceSepUUIDs.} | mirror use ashift=13 for SSDs with 8k Sektors |
zpool import -d /dev/disk/by-id ${pool} | do not import without -d /dev/disk/by... otherwise it will import it using /dev/sd... |
zpool destroy ${pool} | destroy a pool |
zpool export ${pool} | export a pool to e.g. use it on another system |
zpool import -f -d /dev/disk/by-id ${pool} | force import if you forgot to export it |
zfs set mountpoint=/foo/bar ${pool} | set the mountpoint for a pool |
blockdev --getpbsz /dev/sdXY | print sector size reported by the device ioctls |
lsblk -t | print physical and logical sector size of all disks |
Dataset handling
Comands | Description |
---|---|
zfs list | lists all datasets and their mountpoint |
zfs create ${pool}/${dataset} | create a dataset |
zfs create -o recordsize=8K -o primarycache=metadata -o logbias=throughput ssd/database | |
zfs set quota=20G ${pool}/${dataset} | set quota of dataset to 20G |
zfs set mountpoint=/foo/bar ${pool}/${dataset} | set the mountpoint for a dataset |
zpool destroy ${pool}/${dataset} | destroy a dataset |
Encrypted Datasets
Comands | Description |
---|---|
zfs create -o encryption=on -o keyformat=passphrase ${pool}/${dataset} | Create a dataset with native default encryption (currently AES-256-gcm) and passphrase |
dd if=/dev/random of=/path/to/key bs=1 count=32 | create a key to use for keyformat=raw |
zfs create -o encryption=on -o keyformat=raw -o keylocation=file:///path/to/key ${pool}/${dataset} | Create a dataset using a raw key |
Auto unlock of encrypted datasets
If you want to get your encrypted datasets auto unlocked while booting you could create a systemd
service which performs the action for you.
You just need ot make sure that the
passphrase
is somehow accessable in this state.
Lets assume that you have created your dataset with keyformat=raw
and lets assume you have only one zpool
.
First create a generic systemd
serivce file which you can use for this, something like this (if you don’t get it by installing zfs already):
$ cat /etc/systemd/system/zfs-load-key@.service
[Unit]
Description=Load ZFS keys
DefaultDependencies=no
Before=zfs-mount.service
After=zfs-import.target
Requires=zfs-import.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/zfs load-key <zpool_name>/%I
[Install]
WantedBy=zfs-mount.service
Next could be that you just create a soft link like:
$ ln -s zfs-load-key@.service zfs-load-key@<zfs_dataset_name>.service
This will require to reload systemd
and of course enable the service so that it runs while your system is booting.
$ systemctl daemon-reload
$ systemctl enable zfs-load-key@<zfs_dataset_name>.service
But what happens if you have more then one zpool
and you want to auto unlock them.
systemd
can deal make use of parameters only via the attribute EnvironmentFile
.
This means that you would need to prepare for each zfs
dataset such an config file.
cat /etc/zfs/service_config/<zpool_name>_<zfs_dataset_name>
zpool_name=<zpool_name>
zfs_dataset_name=<zfs_dataset_name>
Sample:
$ cat /etc/zfs/service_config/data_pool-picture_dataset zpool_name=data_pool zfs_dataset_name=picture_dataset
This brings us the benefit, that we can use %I
in the service name as the file name:
$ cat /etc/systemd/system/zfs-load-key@data_pool-picture_dataset.service
[Unit]
Description=Load ZFS keys
DefaultDependencies=no
Before=zfs-mount.service
After=zfs-import.target
Requires=zfs-import.target
[Service]
Type=oneshot
EnvironmentFile=/etc/zfs/service_config/%I
RemainAfterExit=yes
ExecStart=/usr/sbin/zfs load-key $zpool_name/$zfs_dataset_name
[Install]
WantedBy=zfs-mount.service
And from now on it is very easy to auto unlock multible zfs
datasets located in multible zpool
s.
Side note, of course you could also use service config file to specify different comands to execute, e.g. if you require a
yubikey
or need to get the pwd from yourpass
/gpg
.$ cat /etc/zfs/service_config/data_pool-picture_dataset zpool_name=data_pool zfs_dataset_name=picture_dataset decrypt_cmd="gpg --batch --decrypt --pinentry-mode loopback /root/.zfs/${zpool_name}/${zfs_dataset_name}.gpg | /usr/sbin/zfs load-key ${zpool_name}/${zfs_dataset_name}"
$ cat /etc/systemd/system/zfs-load-key@data_pool-picture_dataset.service [Unit] Description=Load ZFS keys DefaultDependencies=no Before=zfs-mount.service After=zfs-import.target Requires=zfs-import.target [Service] Type=oneshot EnvironmentFile=/etc/zfs/service_config/%I RemainAfterExit=yes ExecStart=$decrypt_cmd [Install] WantedBy=zfs-mount.service
Btw this is not the best sample ;) but it shows what the idea behind it is
Snapshots
Comands | Description |
---|---|
zfs snapshot ${pool}/${dataset}@${snapshotname} | create a snapshot |
zfs list -t snapshot | list all snapshots. Column “USED” is space dedicated to one snapshot. Space occupied by n snapshots only becomes visible after deleting n-1 of those snapshots. |
zfs list -o space -r ${pool} | list all datasets. Column “USEDSNAP” includes total size of all snapshots. |
zfs destroy ${pool}/${dataset}@${snapshotname} | delete a snapshot |
zfs destroy ${pool}/${dataset}@${snapshotA}%${snapshotB} | delete all snapshots between A and B including A and B |
zfs rename ${pool}/${dataset}@${oldname} ${pool}/${dataset}@${newname} | rename a snapshot |
zfs rollback ${pool}/${dataset}@${snapshot} | rollback |
zfs clone ${pool}/${dataset}@${snapshotname} ${pool}/${newdataset} | create a new dataset from a snapshot |
zfs list -po written,written@${snapshotname} ${pool}/${dataset} | if 0, then snapshot is pristine. add -H for usage in scripts. |
Send and Receive
Comands | Description |
---|---|
zfs send [pool]/[dataset]@[snapshotname] | ssh [destinationhost] (sudo) zfs receive [pool]/[dataset] | send full dataset, may not exist previously on target |
zfs send -Rw [pool]/[dataset]@[snapshotname] | ssh [destinationhost] (sudo) zfs receive [pool]/[dataset] | same as above for encrpyted datasets |
zfs send -i [pool]/[dataset]@[oldsnapshotname] [pool]/[dataset]@[newsnapshotname] | ssh [destinationhost] (sudo) zfs receive [pool]/[dataset] | send incremental snapshot diff, oldsnapshot must exist on dest |
zfs send -Rwi [pool]/[dataset]@[oldsnapshotname] [pool]/[dataset]@[newsnapshotname] | ssh [destinationhost] (sudo) zfs receive [pool]/[dataset] | same as above for encrpyted datasets |
Send and Receive with mbuffer
ssh is the more secure but a bit slower approach since it does not buffer and needs to encrypt data. In case of a trustworthy network path mbuffer can be used.
Open up a port restricted to the source IP on the destination node
mbuffer -I ${sourceIP}:${destPort} | zfs receive ${pool}/${ds}
Start transfer on source node
zfs send ${pool}/${ds}@${snapshot} | mbuffer -O ${destIP}:${destPort}
If ram allowes it, you can increase the mbuffer cache by using for example -m 4G
.
Troubleshooting and Fixes
used /dev/sd instead of /dev/disk/by-id on creation
# no data loss, first export the pool
$ sudo zpool export [pool name]
# import the pool again using the right IDs
$ sudo zpool import -d /dev/disk/by-id [pool name]
replace disk of raidz1/2/3
# get status of pool
$ zpool status ${pool}
# find out which disk is the new disk in case you did not note down the serial
$ lsblk
$ ls -la /dev/disk/by-id/
# replace disk
$ zpool replace ${pool} ${old_disk_id} ${new_disk_id}