ZFS (Português)

From ArchWiki
Jump to navigation Jump to search

ZFS é um sistema de arquivos avançado criado pela Sun Microsystems (atualmente propriedade da Oracle) e lançado para OpenSolaris em novembro de 2005.

Características do ZFS incluem: armazenamento em "pools" (gerenciamento integrado de volumes - zpool), cópia em gravação, instantâneos, verificação da integridade de dados e reparo automático (scrubbing - esfregar), RAID-Z, tamanho de arquivo máximo de 16 Exabytes, e um máximo de armazenamento de 256 quadrilhões de zettabytes sem limite de números de sistema de arquivos (datasets - conjuntos de dados) ou arquivos[1]. (Conteúdo em inglês). O ZFS está licenciado sob a Common Development and Distribution License (CDDL).

Descrito como "A última palavra em sistemas de arquivos" (Conteúdo em inglês), o ZFS é estável, rápido, seguro e à prova de futuro. Tendo a licença como CDDL, e, portanto, incompatível com a GPL, não é possível que o ZFS seja distribuído junto ao Kernel Linux. Esta necessidade, no entanto, não impede que um módulo do Kernel nativo de Linux seja distribuído por terceiros, como é o caso com o zfsonlinux.org (ZOL - ZFS no Linux/ZNL).

ZNL é um projeto fundado pelo Lawrence Livermore National Laboratory para desenvolver um módulo nativo do Kernel do Linux para a necessidade de armazenamento maciço de dados em supercomputadores.

Nota:

Devido à incompatibilidade potencialmente ilegais entre CDDL do ZFS e GPL do Kernel Linux, o desenvolvimento do ZFS não é suportado pelo Kernel, como mostrado nas seguintes páginas: ([2],CDDL-GPL,ZFS no Linux).

Como resultado:

  • O projeto ZFSonLinux deve acompanhar as versões do Kernel Linux. Após tornar um lançamento de uma versão estável do ZFSonLinux, os mantenedores do ZFS no Arch, fazem o lançamento junto à versão do Kernel.
  • Essa situação às vezes bloqueia o processo normal de atualização sem interrupção por dependências não satisfeitas, porque a nova versão do Kernel, proposta por atualização, não é suportada pelo ZFSonLinux

Contents

Instalação

Geral

Atenção: A não ser que você utilize as versões DKMS dos pacotes, os módulos do Kernel ZFS e SPL estarão amarrados a uma versão específica do Kernel. Não será possível aplicar nenhuma atualização do Kernel até que pacotes atualizados sejam subidos para o AUR ou o repositório não-oficial archzfs.
Dica: Você pode fazer o downgrade da sua versão do Linux para uma no repositório do archzfs se sua versão for mais nova.

Instale do repositório não-oficial archzfs ou, como alternativa, do AUR:

Estas versões têm dependências dos pacotes zfs-utils, spl, spl-utils. SPL (Solaris Porting Layer - camada de portabilidade de Solaris) é um módulo do Kernel Linux que implementa APIs do Solaris para compatibilidade com ZFS.

Teste a instalação rodando zpool status na linha de comando. Se aparecer um erro com "insmod", tente depmod -a.

ZFS na raiz

Veja Instalação.

DKMS

Usuários podem utilizar o DKMS para reconstruir o módulo do ZFS automaticamente com cada atualização do Kernel.

Instale zfs-dkmsAUR ou zfs-dkms-gitAUR e aplique as instruções de pós-instalação dadas por estes pacotes.

Dica: Adicione uma entrada de IgnorePkg em pacman.conf para impedir que estes pacotes sejam atualizados em uma atualização regular.

Experimentos com ZFS

Usuários que tenham o desejo de realizar experimentos com ZFS em dispositivos de blocos virtuais (conhecidos no ZFS como VDEVs) que podem ser arquivos simples como ~/zfs0.img, ~/zfs1.img, ~/zfs2.img, etc. sem a possibilidade de perda real de dados devem ver o artigo Experimenting with ZFS. Tarefas comuns como construir um array (conjunto) em RAIDZ, propositalmente corromper dados e então recuperá-los, obter instantâneos de datasets, etc. são cobertos nele.

Configuração

ZFS é considerado como um sitema de arquivos com "administração zero" pelos seus criadores; portanto, configurar o ZFS é um processo bem direto. A configuração é feita com 2 comandos: zfs e zpool.

Inicialização automática

Atualmente, por padrão, o módulo do Kernel não é carregado durante a inicialização (veja mais detalhes em https://github.com/zfsonlinux/zfs/issues/6083 - conteúdo em inglês). Para carregar automaticamente o zfs, veja Kernel module (Português)#Carregamento automático de módulos com systemd.

Para que o ZFS faça juz à "administração zero",o serviço zfs-import-cache.service deve ser habilitado para importar as pools e o zfs-mount.service deve ser habilitado para montar o sistema de arquivos disponível nas pools. Um benefício disto é que não é necessário montar os sistemas ZFS no /etc/fstab. O zfs-import-cache.service importa as pools lendo o arquivo /etc/zfs/zpool.cache.

Para cada pool importada, é desejável que o serviço zfs-import-cache.service que foi importado automaticamente, execute o seguinte comando:

# zpool set cachefile=/etc/zfs/zpool.cache <pool>
Nota: À partir da versão 0.6.5.8 do ZNL, os arquivos das unidades de serviço do ZFS foram mudadas para que você explicitamente habilite quaisquer serviços do ZFS que você queira executar. Veja o conteúdo em inglês https://github.com/archzfs/archzfs/issues/72 para mais informações.

Habilite o serviço e o .target relevante para que as pools sejam automaticamente importadas durante a inicialização:

# systemctl enable zfs-import-cache
# systemctl enable zfs-import.target

Para montar os sistemas de arquivos ZFS, você possui 2 opções:

Usando zfs-mount.service

Para montar os sistemas de arquivos ZFS automaticamente durante o boot, você precisa habilitar os seguintes serviços e alvos.

# systemctl enable zfs-mount
# systemctl enable zfs.target

Usando zfs-mount-generator

Você também pode usar o zfs-mount-generator para criar unidades de montagem do systemd para seus sistemas de arquivos ZFS durante a inicialização. O systemd irá automaticamente montar os sistemas de arquivos baseados nas unidades de montagem sem a necessidade de usar zfs-mount.service para fazer isto. Para isto, você precisa:

  1. Criar o diretório /etc/zfs/zfs-list.cache.
  2. Habilitar o script do ZFS Event Daemon (ZED - servidor de evento do ZFS, chamado de ZEDLET) necessário para criar uma lista de sistemas de arquivos montáveis do ZFS.
    # ln -s /usr/lib/zfs/zed.d/history_event-zfs-list-cacher.sh /etc/zfs/zed.d
  3. Habilitar e iniciar o ZFS Event Daemon. Este serviço é responsável por executar o script do passo anterior.
    # systemctl enable zfs-zed.service
    # systemctl enable zfs.target
    # systemctl start zfs-zed.service
  4. Você precisa criar um arquivo vazio com o nome baseado no nome da sua pool em /etc/zfs/zfs-list.cache. O ZEDLET irá apenas atualizar a lista de sistema(s) de arquivos se o arquivo da pool já existir.
    # touch /etc/zfs/zfs-list.cache/nome-da-pool
  5. Verifique o conteúdo de /etc/zfs/zfs-list.cache/nome-da-pool. Se estiver vazio, assegure-se que o zfs-zed.service está executando e só mude a propriedade canmount de quaisquer sistemas de arquivos ZFS executando:
    zfs set canmount=off zroot/fs1
    Esta mudança faz com que o ZFS crie um evento que é capturado pelo ZED, que, então, roda o ZEDLET para atualizar o arquivo em /etc/zfs/zfs-list.cache. Se o arquivo em /etc/zfs/zfs-list.cache for atualizado, você pode definir a propriedade canmount do sistema de arquivos de volta executando:
    zfs set canmount=on zroot/fs1

Você precisa acrescentar um arquivo em /etc/zfs/zfs-list.cache para cada pool ZFS no seu sistema. Assegure-se que as pools serão importadas habilitando zfs-import-cache.service e zfs-import.target conforme explicado acima.

Pools de Armazenamento

Não é necessário particionar os dispositivos antes de criar o sistema de arquivos ZFS. É recomendado apontar o ZFS para um disco inteiro (ex: `/dev/sdx` em vez de `/dev/sdx1`), que irá automaticamente criar uma tabela de partições GPT (conteúdo em inglês) e acrescentar uma partição reservada de 8 MB no final do disco para carregadores de inicialização legados. No entando, você pode especificar a partição ou um arquivo dentro do sistema de arquivos existente, se você deseja criar multiplos volumes com propriedades de redundância diferentes.

Nota: Se algum ou todos os dispositivos foram usados em um conjunto de RAID por software, é primordial apagar quaisquer informações de configuração antigas de RAID.
Atenção: Para #Discos com formatação avançada com tamanho de setor de 4KB, um ashift com valor 12 é recomendado para melhor desempenho. Discos com formatação avançada emulam um setor com tamanho de disco de 512 bytes para compatibilidade com sistemas legado. Uma vez que o pool foi criado, a única maneira de mudar a opção do ashift é recriar o pool. Usar um ashift de 12 também diminui a capacidade disponível. Veja 1.10 What’s going on with performance?, 1.15 How does ZFS on Linux handle [Advanced(Advanced) Format disks?], e ZFS and Advanced Format disks.

Identificando discos

ZFS no Linux recomenda utilizar IDs do dispositivo quando for criar pools de armazenamento com menos de 10 dispositivos. Use Persistent block device naming (Português)#by-id e by-path para identificar a lista de dispositivos que serão utilizados no pool ZFS.

Os IDs dos discos serão similares ao seguinte:

$ ls -lh /dev/disk/by-id/
lrwxrwxrwx 1 root root  9 Aug 12 16:26 ata-ST3000DM001-9YN166_S1F0JKRR -> ../../sdc
lrwxrwxrwx 1 root root  9 Aug 12 16:26 ata-ST3000DM001-9YN166_S1F0JTM1 -> ../../sde
lrwxrwxrwx 1 root root  9 Aug 12 16:26 ata-ST3000DM001-9YN166_S1F0KBP8 -> ../../sdd
lrwxrwxrwx 1 root root  9 Aug 12 16:26 ata-ST3000DM001-9YN166_S1F0KDGY -> ../../sdb
Atenção: Se você criar zpools utilizando nomes dos dispositivos como /dev/sda, /dev/sdb, etc. o ZFS pode não ser capaz de detectar zpools intermitentemente na inicialização.

Utilizando rótulos GPT

Rótulos de disco e UUIDs podem ser utilizados por montagens de ZFS usando partições GPT. Dispositivos ZFS possuem rótulos mas o Linux não é capaz de lê-los durante a inicialização. Ao contrário de partições MBR, partições GPT diretamente suportam tanto UUID quanto rótulos, independente do formato dentro da partição. Particionar ao invés de utilizar o disco todo para o ZFS oferece duas vantagens adicionais. O SO não precisa gerar números de partição falsos à partir de quaisquer dados que o ZFS possa ter escrito no setor de particionamento, e, se desejado, é possível provisionar excessivamente dispositivos SSD, e provisionar ligeiramente mais discos de eixo para assegurar que diferentes modelos com contagem de setores diferentes possam substituir espelhos no seu zpool. Isto permite muita organização e controle sobre o ZFS utilizando ferramentas e técnicas prontamente disponíveis com custo quase nulo.

Utilize o gdisk para particionar todo ou apenas uma parte do disco como uma única partição. O gdisk não nomeia automaticamente as partições. Algumas razões para preferir rótulos ao invés de UUID são: rótulos são fáceis de controlar, podem indicar o propósito de cada disco, são mais curtos e mais simples de digitar. Estas são vantagens quando o servidor está inoperante e há pressão para restabelecimento. Rótulos de partições do GPT possuem amplo espaço disponível e podem suportar a maioria dos caracteres internacionais (Entradas de Partição) permitindo que grandes pools de dados sejam rotulados de uma maneira organizada.

Discos particionados com GPT possuem rótulos e UUIDs que parecem com o seguinte:

$ ls -l /dev/disk/by-partlabel
lrwxrwxrwx 1 root root 10 Apr 30 01:44 zfsdata1 -> ../../sdd1
lrwxrwxrwx 1 root root 10 Apr 30 01:44 zfsdata2 -> ../../sdc1
lrwxrwxrwx 1 root root 10 Apr 30 01:59 zfsl2arc -> ../../sda1
$ ls -l /dev/disk/by-partuuid
lrwxrwxrwx 1 root root 10 Apr 30 01:44 148c462c-7819-431a-9aba-5bf42bb5a34e -> ../../sdd1
lrwxrwxrwx 1 root root 10 Apr 30 01:59 4f95da30-b2fb-412b-9090-fc349993df56 -> ../../sda1
lrwxrwxrwx 1 root root 10 Apr 30 01:44 e5ccef58-5adf-4094-81a7-3bac846a885f -> ../../sdc1
Dica: Para minimizar digitar e erros ao copiar/colar, defina uma variável local com o PARTUUID de destino: $ UUID=$(lsblk --noheadings --output PARTUUID /dev/sdXY)

Criando pools ZFS

Para criar uma pool com ZFS:

# zpool create -f -m <montagem> <pool> [raidz(2|3)|mirror] <ids>
Dica: É útil ler primeiro #Discos com formatação avançada para definir o valor correto de ashift durante a criação da pool
  • create: subcomando para criar a pool.
  • -m: O ponto de montagem da pool. Se não for especificado, então a pool será montada diretamente em /<pool>.
  • pool: É o nome da pool.
  • raidz(2|3)|mirror: Este é o tipo de dispositivo virtual que será criado à partir do conjunto de dispositivos de armazenamento, raidz possui um único disco de paridade, raidz2, 2 discos e raidz3 possui 3 discos de paridade, similares ao RAID5 e RAID6. Também há mirror, que é similar ao RAID1 ou RAID10, mas não é restrito à apenas 2 dispositivos. Se não especificado, cada dispositivo será acrescido como vdev, o que é similar ao RAID0. Após a criação, um dispositivo pode ser adicionado a cada vdev de dispositivo para transformar em um espelho (mirror), o que pode ser útil para migrar dados.
  • ids: O ID dos dispositivos ou partições para incluir na pool.

Criar pool com um único vdev em raidz:

# zpool create -f -m /mnt/dados bigdata \
        raidz \
            ata-ST3000DM001-9YN166_S1F0KDGY \
            ata-ST3000DM001-9YN166_S1F0JKRR \
            ata-ST3000DM001-9YN166_S1F0KBP8 \
            ata-ST3000DM001-9YN166_S1F0JTM1

Criar pool com dois vdevs em espelhados:

# zpool create -f -m /mnt/dados bigdata \
        mirror \
            ata-ST3000DM001-9YN166_S1F0KDGY \
            ata-ST3000DM001-9YN166_S1F0JKRR \
        mirror \
            ata-ST3000DM001-9YN166_S1F0KBP8 \
            ata-ST3000DM001-9YN166_S1F0JTM1

Discos com formatação avançada

Durante a criação da pool, ashift=12 deve sempre ser utilizado, exceto com SSDs que possuem setores com 8km onde ashift=13 é o correto. Um disco com vdev de tamanho 512 bytes usando setores de 4k não irá experienciar problemas de desempenho, mas um disco de 4k usando 512 irá. Já que ashift não pode ser mudado após a criação da pool, até uma pool com apenas discos de 512 bytes deve usar 4k pois pode ser necessário a substituição destes discos com outros de 4k, ou ainda a pool pode ser expandida acrescentando um vdev composto por discos de 4k. Como a detecção correta de discos de 4k não é confiável -o ashift=12 deve sempre ser utilizado durante a criação da pool, veja o conteúdo em inglês ZFS on Linux FAQ para mais detalhes.

Dica: Use blockdev(8) (parte do util-linux) como root para mostrar o tamanho do setor informado pelo ioctls do dispositivo: blockdev --getpbsz /dev/sdXY.

Crie uma pool com ashift=12 e um único vdev em raidz:

# zpool create -f -o ashift=12 -m /mnt/dados bigdata \
               raidz \
                  ata-ST3000DM001-9YN166_S1F0KDGY \
                  ata-ST3000DM001-9YN166_S1F0JKRR \
                  ata-ST3000DM001-9YN166_S1F0KBP8 \
                  ata-ST3000DM001-9YN166_S1F0JTM1

Criação de pool compatível com GRUB

Nota: Esta seção frequentemente fica desatualizada com atualizações de GRUB e ZFS. Consulte as páginas de manual para informação mais atual.

Por padrão, zpool create permite todas as opções em uma pool. Se /boot reside em um ZFS quando usando o GRUB, você deve habilitar apenas as opções suportadas pelo GRUB, caso não faça isso, o GRUB não conseguirá ler a pool. O GRUB 2.02 suporta as opções de leitura e gravação lz4_compress, hole_birth, embedded_data, extensible_dataset, e large_blocks, isto não condiz com todas as opções no ZFSonLinux 0.8.0, e deve ter as opções não adequadas desabilitadas. Pode-se inserir explicitamente o nome das opções habilitadas com o argumento -d para o comando zpool create, que desabilita todas as opções por padrão.

Você pode criar a pool com apenas as opções permitidas habilitadas:

# zpool create -d -o feature@allocation_classes=enabled \
                  -o feature@async_destroy=enabled      \
                  -o feature@bookmarks=enabled          \
                  -o feature@embedded_data=enabled      \
                  -o feature@empty_bpobj=enabled        \
                  -o feature@enabled_txg=enabled        \
                  -o feature@extensible_dataset=enabled \
                  -o feature@filesystem_limits=enabled  \
                  -o feature@hole_birth=enabled         \
                  -o feature@large_blocks=enabled       \
                  -o feature@lz4_compress=enabled       \
                  -o feature@project_quota=enabled      \
                  -o feature@resilver_defer=enabled     \
                  -o feature@spacemap_histogram=enabled \
                  -o feature@spacemap_v2=enabled        \
                  -o feature@userobj_accounting=enabled \
                  -o feature@zpool_checkpoint=enabled   \
                  $NOME_DA_POOL $VDEVS

Verificando status da pool

Se o comando for executado com sucesso, não será mostrada saída. Usando o comando mount mostrará que a pool está montada. Usando zpool status mostrará que a pool foi criada:

# zpool status -v
  pool: bigdata
 state: ONLINE
  scan: none requested
config:

        NAME                                       STATE     READ WRITE CKSUM
        bigdata                                    ONLINE       0     0     0
          -0                                       ONLINE       0     0     0
            ata-ST3000DM001-9YN166_S1F0KDGY-part1  ONLINE       0     0     0
            ata-ST3000DM001-9YN166_S1F0JKRR-part1  ONLINE       0     0     0
            ata-ST3000DM001-9YN166_S1F0KBP8-part1  ONLINE       0     0     0
            ata-ST3000DM001-9YN166_S1F0JTM1-part1  ONLINE       0     0     0

errors: No known data errors

Nesse momento, seria bom reiniciar a máquina para assegurar-se que a pool ZFS será montada durante a inicialização. É melhor lidar com todos os erros antes de transferir dados.

Importando por id uma pool criada

Eventualmente, uma pool pode falhar ao auto montar, então você precisará importar para trazer a pool de volta. Cuidado para evitar usar a solução óbvia.

Atenção: Não rode zpool import pool! Isto irá importar seus pools utilizando /dev/sd? que irá causar problemas a próxima vez que rearranjar seus drives. Que pode ser algo simples como reiniciar com um USB conectado na máquina.

Adapte algum dos comandos seguintes para importar sua pool para que as importações dela retenham a persistência com que foram criadas.

# zpool import -d /dev/disk/by-id         bigdata
# zpool import -d /dev/disk/by-partlabel  bigdata
# zpool import -d /dev/disk/by-partuuid   bigdata
Nota: Use a opção -l ao importar a pool que contenha chaves de conjuntos de dados criptografadas:
# zpool import -l -d /dev/disk/by-id bigdata

Finalmente, verifique o estado da pool:

# zpool status -v bigdata

Destruir uma pool de armazenamento

ZFS torna fácil destruir uma pool de armazenamento montada, removendo todos os metadados sobre o dispositivo ZFS.

Atenção: Este comando destrói qualquer dado contido no pool e/ou dataset.

Para destruir a pool:

# zpool destroy <pool>

Para destruir o dataset:

# zfs destroy <pool>/<dataset>

E agora, ao verificar o status:

# zpool status
no pools available

Exportar uma pool de armazenamento

Se uma pool de armazenamento precisar ser utilizada em outro sistema, primeiro necessitará ser importada. Também faz-se necessário exportar uma pool se ela foi importada à partir da archiso pois o hostid será diferente entre a ISO e o sistema inicializado. O comando zpool se recusará a importar quaisquer pools de armazenamento que não foram exportadas. É possível forçar a importação com a opção -f mas esta prática é considerada ruim.

Quaisquer tentativas de importar uma pool de armazenamento não exportadas resultará em um erro ao iniciar a pool de armazenamento informando estar sendo utilizada em outro sistema. Este erro pode ser produzido durante a inicialização, abruptamente abandonando o sistema na console busybox, necessitando da archiso para fazer o conserto, seja via exportação da pool, seja acrescentando zfs_force=1 aos parâmetros de inicialização do Kernel (o que não é ideal). Veja o conteúdo em inglês #On boot the zfs pool does not mount stating: "pool may be in use from other system".

Para exportar uma pool:

# zpool export <pool>

Estendendo uma pool existente

Um dispositivo (uma partição ou um disco) pode ser acrescentado a uma zpool existente:

# zpool add <pool> <id-do-dispositivo>

Para importar uma pool que consiste de múltiplos dispositivos:

# zpool import -d <id-do-dispositivo-1> -d <id-do-dispositivo-2> <pool>

Ou simplesmente:

# zpool import -d /dev/disk-by-id/ <pool>

Renomear uma pool

Renomear uma pool que já foi criada é feito em 2 passos:

# zpool export nome-antigo
# zpool import nome-antigo nome-novo

Definir um ponto de montagem diferente

O ponto de montagem para uma determinada zpool pode ser movido conforme desejado com um comando:

# zfs set mountpoint=/foo/bar nome-da-pool

Criando datasets

Usuários possuem a opção de criar um dataset sob uma zpool, diferente de manualmente criar diretórios sob a zpool. Datasets permitem um nível maior de controle (por exemplo quotas), além de snapshots. Para conseguir criar e montar um dataset, um diretório homônimo não deve existir na zpool. Para criar um dataset, use:

# zfs create <nome-da-zpool>/<nome-do-dataset>

Então é possível aplicar atributos específicos do ZFS ao dataset. Por exemplo, limite de quota para um diretório específico dentro de um dataset:

# zfs set quota=20G <nome-da-zpool>/<nome-do-dataset>/<diretório>

Para ver todos os comandos disponíveis no ZFS, veja zfs(8) ou zpool(8).

Criptografia nativa

ZFS oferece as seguintes opções suportadas de Criptografia: aes-128-ccm, aes-192-ccm, aes-256-ccm, aes-128-gcm, aes-192-gcm e aes-256-gcm. Quando a Criptografia é definida como on, aes-256-gcm será usada.

Os seguintes formatos de chave são suportados: passphrase, raw, hex.

É possível também especificar as iterações padrões do PBKDF2 quando usando passphrase com -o pbkdf2iters <n>, embora isto possa aumentar o tempo até terminar a descriptografia.

Nota:
  • Criptografia nativa no ZFS tornou-se disponível à partir da versão estável 0.8.0 ou mais nova. Anteriormente estavam disponíveis apenas em versões de desenvolvimento fornecidas por pacotes como zfs-linux-gitAUR, zfs-dkms-gitAUR ou outras versões de desenvolvimento. Usuários que estavam utilizando as versões de desenvolvimento devido à criptografia podem agora trocar pela versão estável se assim desejarem.
  • A suite padrão de criptografia foi mudada de aes-256-ccm para aes-256-gcm na versão 0.8.4.
  • Para importar uma pool com chaves, é necessário especificar a opção -l, sem esta opção, datasets criptografados ficarão indisponíveis até que as chaves sejam carregadas. Veja#Importando por id uma pool criada.

Para criar um dataset, incluíndo criptografia por senha, use:

# zfs create -o encryption=on -o keyformat=passphrase <nome-da-zpool>/<nome-do-dataset>

Para utilizar chave ao invés de senha, use:

# dd if=/dev/random of=/caminho/para/chave bs=1 count=32
# zfs create -o encryption=on -o keyformat=raw -o keylocation=file://of=/caminho/para/chave <nome-da-zpool>/<nome-do-dataset>

Para verificar o local da chave:

# zfs get keylocation <nome-da-zpool>/<nome-do-dataset>

Para mudar o local da chave:

# zfs set keylocation=file:///caminho/para/chave <nome-da-zpool>/<nome-do-dataset>

Você também pode manualmente carregar as chaves utilizando um dos seguintes comandos:

# zfs load-key <nome-da-zpool>/<nome-do-dataset> # Carrega uma chave para um dataset específico
# zfs load-key -a                                # Carrega todas as chaves
# zfs load-key -r zpool/dataset                  # Carrega todas as chaves em um dataset

Para montar um dataset criptografado criado:

# zfs mount <nome-da-zpool>/<nome-do-dataset>

Desbloquear durante a inicialização

É possível automaticamente desbloquear um dataset de uma pool durante a inicialição usando uma unidade do systemd. Por exemplo, criar o seguinte serviço para desbloquear qualquer dataset específico.

/etc/systemd/system/zfs-load-key@.service
[Unit]
Description=Carregar chaves de criptografia %I
Before=systemd-user-sessions.service
After=zfs-import.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/bash -c 'until (systemd-ask-password "Senha criptografada do ZFS para %I" --no-tty | zfs load-key %I); do echo "Tente novamente!"; done'

[Install]
WantedBy=zfs-mount.service

Habilite e inicie o serviço para cada dataset criptografado, e.g. systemctl enable zfs-load-key@pool0-dataset0 como o usuário root. Note o uso do -, que é um / escapado nas definições de unidade do systemd. Veja systemd-escape(1) para mais informações.

Nota: O Before=systemd-user-sessions.service garante que o systemd-ask-password seja invocado antes que os dispositivos locais de E/S sejam entregues para o ambiente de desktop.

Uma alternativa é carregar todas as chaves possíveis:

/etc/systemd/system/zfs-load-key.service
[Unit]
Description=Carregar chaves de criptografia
DefaultDependencies=no
After=zfs-import.target
Before=zfs-mount.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/bash -c '/usr/bin/zfs load-key -a'

[Install]
WantedBy=zfs-mount.service

Habilite e inicie zfs-load-key.service.

Volume de swap

Atenção: Em sistemas com pressão de memória extremamente alto, usar um zvol como swap pode resultar em em travamento, independente da quantidade de swap disponível. Este problema está atualmente sendo investigado https://github.com/zfsonlinux/zfs/issues/7734

ZFS não permite o uso de arquivos de swap, mas usuários podem utilizar um volume de ZFS (ZVOL) como swap. É importante definir o tamanho de bloco do ZVOL para ser o mesmo do tamanho de página do sistema, que pode ser obtida com o comando getconf PAGESIZE (o padrão em x86_64 é 4KiB). Outra opção útil para manter o sistema rodando bem em situações de memória baixa é não fazer o cache dos dados do ZVOL.

Crie um volume ZFS de 8 GiB:

# zfs create -V 8G -b $(getconf PAGESIZE) \
              -o logbias=throughput -o sync=always\
              -o primarycache=metadata \
              -o com.sun:auto-snapshot=false <pool>/swap

Prepare-o como partição de swap:

# mkswap -f /dev/zvol/<pool>/swap
# swapon /dev/zvol/<pool>/swap

Para tornar permanente, edite o /etc/fstab. ZVOLs suportam "discard", que potencialmente pode ajudar o alocador de blocos do ZFS e reduzir a fragmentação para todos os outros datasets quando/se o swap não estiver cheio.

Acrescente uma linha no /etc/fstab:

/dev/zvol/<pool>/swap none swap discard 0 0

Access Control Lists

Para utilizar Listas de Controle de Acesso (ACL) em um dataset:

# zfs set acltype=posixacl <nome-da-zpool>/<nome-do-dataset>
# zfs set xattr=sa         <nome-da-zpool>/<nome-do-dataset>

Definir xattr é recomendado por questões de desempenho, como é possível ver no conteúdo em inglês [3].

Pode ser preferível habilitar o ACL na zpool pois os datasets irão herdar os parâmetros de ACL. Configurar aclinherit=passthrough Pode ser desejado pois o modo padrão é restricted, vide [4] (conteúdo em inglês):

# zfs set aclinherit=passthrough  <nome-da-zpool>
# zfs set acltype=posixacl        <nome-da-zpool>
# zfs set xattr=sa                <nome-da-zpool>

Databases

ZFS, unlike most other file systems, has a variable record size, or what is commonly referred to as a block size. By default, the recordsize on ZFS is 128KiB, which means it will dynamically allocate blocks of any size from 512B to 128KiB depending on the size of file being written. This can often help fragmentation and file access, at the cost that ZFS would have to allocate new 128KiB blocks each time only a few bytes are written to.

Most RDBMSes work in 8KiB-sized blocks by default. Although the block size is tunable for MySQL/MariaDB, PostgreSQL, and Oracle Database, all three of them use an 8KiB block size by default. For both performance concerns and keeping snapshot differences to a minimum (for backup purposes, this is helpful), it is usually desirable to tune ZFS instead to accommodate the databases, using a command such as:

# zfs set recordsize=8K <pool>/postgres

These RDBMSes also tend to implement their own caching algorithm, often similar to ZFS's own ARC. In the interest of saving memory, it is best to simply disable ZFS's caching of the database's file data and let the database do its own job:

# zfs set primarycache=metadata <pool>/postgres

If your pool has no configured log devices, ZFS reserves space on the pool's data disks for its intent log (the ZIL). ZFS uses this for crash recovery, but databases are often syncing their data files to the file system on their own transaction commits anyway. The end result of this is that ZFS will be committing data twice to the data disks, and it can severely impact performance. You can tell ZFS to prefer to not use the ZIL, and in which case, data is only committed to the file system once. Setting this for non-database file systems, or for pools with configured log devices, can actually negatively impact the performance, so beware:

# zfs set logbias=throughput <pool>/postgres

These can also be done at file system creation time, for example:

# zfs create -o recordsize=8K \
             -o primarycache=metadata \
             -o mountpoint=/var/lib/postgres \
             -o logbias=throughput \
              <pool>/postgres

Please note: these kinds of tuning parameters are ideal for specialized applications like RDBMSes. You can easily hurt ZFS's performance by setting these on a general-purpose file system such as your /home directory.

/tmp

If you would like to use ZFS to store your /tmp directory, which may be useful for storing arbitrarily-large sets of files or simply keeping your RAM free of idle data, you can generally improve performance of certain applications writing to /tmp by disabling file system sync. This causes ZFS to ignore an application's sync requests (eg, with fsync or O_SYNC) and return immediately. While this has severe application-side data consistency consequences (never disable sync for a database!), files in /tmp are less likely to be important and affected. Please note this does not affect the integrity of ZFS itself, only the possibility that data an application expects on-disk may not have actually been written out following a crash.

# zfs set sync=disabled <pool>/tmp

Additionally, for security purposes, you may want to disable setuid and devices on the /tmp file system, which prevents some kinds of privilege-escalation attacks or the use of device nodes:

# zfs set setuid=off <pool>/tmp
# zfs set devices=off <pool>/tmp

Combining all of these for a create command would be as follows:

# zfs create -o setuid=off -o devices=off -o sync=disabled -o mountpoint=/tmp <pool>/tmp

Please note, also, that if you want /tmp on ZFS, you will need to mask (disable) systemd's automatic tmpfs-backed /tmp, else ZFS will be unable to mount your dataset at boot-time or import-time:

# systemctl mask tmp.mount

Tuning

General

ZFS pools and datasets can be further adjusted using parameters.

Note: All settable properties, with the exception of quotas and reservations, inherit their value from the parent dataset.

To retrieve the current pool parameter status:

# zfs get all <pool>

To retrieve the current dataset parameter status:

# zfs get all <pool>/<dataset>

To disable access time (atime), which is enabled by default:

# zfs set atime=off <pool>

To disable access time (atime) on a particular dataset:

# zfs set atime=off <pool>/<dataset>

An alternative to turning off atime completely, relatime is available. This brings the default ext4/XFS atime semantics to ZFS, where access time is only updated if the modified time or changed time changes, or if the existing access time has not been updated within the past 24 hours. It is a compromise between atime=off and atime=on. This property only takes effect if atime is on:

# zfs set atime=on <pool>
# zfs set relatime=on <pool>

Compression is just that, transparent compression of data. ZFS supports a few different algorithms, presently lz4 is the default, gzip is also available for seldom-written yet highly-compressible data; consult the OpenZFS Wiki for more details.

To enable compression:

# zfs set compression=on <pool>

To reset a property of a pool and/or dataset to it's default state, use zfs inherit:

# zfs inherit -rS atime <pool>
# zfs inherit -rS atime <pool>/<dataset>
Warning: Using the -r flag will recursively reset all datasets of the zpool.

Scrubbing

Whenever data is read and ZFS encounters an error, it is silently repaired when possible, rewritten back to disk and logged so you can obtain an overview of errors on your pools. There is no fsck or equivalent tool for ZFS. Instead, ZFS supports a feature known as scrubbing. This traverses through all the data in a pool and verifies that all blocks can be read.

To scrub a pool:

# zpool scrub <pool>

To cancel a running scrub:

# zpool scrub -s <pool>

How often should I do this?

From the Oracle blog post Disk Scrub - Why and When?:

This question is challenging for Support to answer, because as always the true answer is "It Depends". So before I offer a general guideline, here are a few tips to help you create an answer more tailored to your use pattern.
  • What is the expiration of your oldest backup? You should probably scrub your data at least as often as your oldest tapes expire so that you have a known-good restore point.
  • How often are you experiencing disk failures? While the recruitment of a hot-spare disk invokes a "resilver" -- a targeted scrub of just the VDEV which lost a disk -- you should probably scrub at least as often as you experience disk failures on average in your specific environment.
  • How often is the oldest piece of data on your disk read? You should scrub occasionally to prevent very old, very stale data from experiencing bit-rot and dying without you knowing it.
If any of your answers to the above are "I do not know", the general guideline is: you should probably be scrubbing your zpool at least once per month. It is a schedule that works well for most use cases, provides enough time for scrubs to complete before starting up again on all but the busiest & most heavily-loaded systems, and even on very large zpools (192+ disks) should complete fairly often between disk failures.

In the ZFS Administration Guide by Aaron Toponce, he advises to scrub consumer disks once a week.

Start with a service or timer

Using a systemd timer/service it is possible to automatically scrub pools.

To perform scrubbing monthly on a particular pool:

/etc/systemd/system/zfs-scrub@.timer
[Unit]
Description=Monthly zpool scrub on %i

[Timer]
OnCalendar=monthly
AccuracySec=1h
Persistent=true

[Install]
WantedBy=multi-user.target
/etc/systemd/system/zfs-scrub@.service
[Unit]
Description=zpool scrub on %i

[Service]
Nice=19
IOSchedulingClass=idle
KillSignal=SIGINT
ExecStart=/usr/bin/zpool scrub %i

Enable/start zfs-scrub@pool-to-scrub.timer unit for monthly scrubbing the specified zpool.

SSD Caching

You can add SSD devices as a write intent log (external ZIL or SLOG) and also as a layer 2 adaptive replacement cache (L2ARC). The process to add them is very similar to adding a new VDEV.

All of the below references to device-id are the IDs from /dev/disk/by-id/*.

SLOG

To add a mirrored SLOG:

 # zpool add <pool> log mirror <device-id-1> <device-id-2>

Or to add a single device SLOG (unsafe):

 # zpool add <pool> log <device-id>

Because the SLOG device stores data that has not been written to the pool, it is important to use devices that can finish writes when power is lost. It is also important to use redundancy, since a device failure can cause data loss. In addition, the SLOG is only used for sync writes, so may not provide any performance improvement.

L2ARC

To add L2ARC:

 # zpool add <pool> cache <device-id>

Because every block cached in L2ARC uses a small amount of memory, it is generally only useful in workloads where the amount of hot data is *bigger* than the maximum amount of memory that can fit in the computer, but small enough to fit into L2ARC. It is also cleared at reboot and is only a read cache, so redundancy is unnecessary. Un-intuitively, L2ARC can actually harm performance since it takes memory away from ARC.

ZVOLs

ZFS volumes (ZVOLs) can suffer from the same block size-related issues as RDBMSes, but it is worth noting that the default recordsize for ZVOLs is 8 KiB already. If possible, it is best to align any partitions contained in a ZVOL to your recordsize (current versions of fdisk and gdisk by default automatically align at 1MiB segments, which works), and file system block sizes to the same size. Other than this, you might tweak the recordsize to accommodate the data inside the ZVOL as necessary (though 8 KiB tends to be a good value for most file systems, even when using 4 KiB blocks on that level).

RAIDZ and Advanced Format physical disks

Each block of a ZVOL gets its own parity disks, and if you have physical media with logical block sizes of 4096B, 8192B, or so on, the parity needs to be stored in whole physical blocks, and this can drastically increase the space requirements of a ZVOL, requiring 2× or more physical storage capacity than the ZVOL's logical capacity. Setting the recordsize to 16k or 32k can help reduce this footprint drastically.

See ZFS on Linux issue #1807 for details

I/O Scheduler

When the pool is imported, for whole disk vdevs, the block device I/O scheduler is set to zfs_vdev_scheduler [5]. The most common schedulers are: noop, cfq, bfq, and deadline.

In some cases, the scheduler is not changeable using this method. Known schedulers that cannot be changed are: scsi_mq and none. In these cases, the scheduler is unchanged and an error message can be reported to logs. Manually setting one of the common schedulers used by zfs_vdev_scheduler can result in more consistent performance.

Troubleshooting

Creating a zpool fails

If the following error occurs then it can be fixed.

# the kernel failed to rescan the partition table: 16
# cannot label 'sdc': try using parted(8) and then provide a specific slice: -1

One reason this can occur is because ZFS expects pool creation to take less than 1 second. This is a reasonable assumption under ordinary conditions, but in many situations it may take longer. Each drive will need to be cleared again before another attempt can be made.

# parted /dev/sda rm 1
# parted /dev/sda rm 1
# dd if=/dev/zero of=/dev/sdb bs=512 count=1
# zpool labelclear /dev/sda

A brute force creation can be attempted over and over again, and with some luck the ZPool creation will take less than 1 second. Once cause for creation slowdown can be slow burst read writes on a drive. By reading from the disk in parallell to ZPool creation, it may be possible to increase burst speeds.

# dd if=/dev/sda of=/dev/null

This can be done with multiple drives by saving the above command for each drive to a file on separate lines and running

# cat $FILE | parallel

Then run ZPool creation at the same time.

ZFS is using too much RAM

By default, ZFS caches file operations (ARC) using up to two-thirds of available system memory on the host. To adjust the ARC size, add the following to the Kernel parameters list:

zfs.zfs_arc_max=536870912 # (for 512MB)

For a more detailed description, as well as other configuration options, see gentoo-wiki:zfs#arc.

Does not contain an EFI label

The following error will occur when attempting to create a zfs filesystem,

/dev/disk/by-id/<id> does not contain an EFI label but it may contain partition

The way to overcome this is to use -f with the zfs create command.

No hostid found

An error that occurs at boot with the following lines appearing before initscript output:

ZFS: No hostid found on kernel command line or /etc/hostid.

This warning occurs because the ZFS module does not have access to the spl hosted. There are two solutions, for this. Either place the spl hostid in the kernel parameters in the boot loader. For example, adding spl.spl_hostid=0x00bab10c.

The other solution is to make sure that there is a hostid in /etc/hostid, and then regenerate the initramfs image. Which will copy the hostid into the initramfs image.

Pool cannot be found while booting from SAS/SCSI devices

In case you are booting a SAS/SCSI based, you might occassionally get boot problems where the pool you are trying to boot from cannot be found. A likely reason for this is that your devices are initialized too late into the process. That means that zfs cannot find any devices at the time when it tries to assemble your pool.

In this case you should force the scsi driver to wait for devices to come online before continuing. You can do this by putting this into /etc/modprobe.d/zfs.conf:

/etc/modprobe.d/zfs.conf
options scsi_mod scan=sync

Afterwards, regenerate the initramfs.

This works because the zfs hook will copy the file at /etc/modprobe.d/zfs.conf into the initcpio which will then be used at build time.

On boot the zfs pool does not mount stating: "pool may be in use from other system"

Unexported pool

If the new installation does not boot because the zpool cannot be imported, chroot into the installation and properly export the zpool. See #Emergency chroot repair with archzfs.

Once inside the chroot environment, load the ZFS module and force import the zpool,

# zpool import -a -f

now export the pool:

# zpool export <pool>

To see the available pools, use,

# zpool status

It is necessary to export a pool because of the way ZFS uses the hostid to track the system the zpool was created on. The hostid is generated partly based on the network setup. During the installation in the archiso the network configuration could be different generating a different hostid than the one contained in the new installation. Once the zfs filesystem is exported and then re-imported in the new installation, the hostid is reset. See Re: Howto zpool import/export automatically? - msg#00227[dead link 2020-04-03 ⓘ].

If ZFS complains about "pool may be in use" after every reboot, properly export pool as described above, and then regenerate the initramfs in normally booted system.

Incorrect hostid

Double check that the pool is properly exported. Exporting the zpool clears the hostid marking the ownership. So during the first boot the zpool should mount correctly. If it does not there is some other problem.

Reboot again, if the zfs pool refuses to mount it means the hostid is not yet correctly set in the early boot phase and it confuses zfs. Manually tell zfs the correct number, once the hostid is coherent across the reboots the zpool will mount correctly.

Boot using zfs_force and write down the hostid. This one is just an example.

$ hostid
0a0af0f8

This number have to be added to the kernel parameters as spl.spl_hostid=0x0a0af0f8. Another solution is writing the hostid inside the initram image, see the installation guide[broken link: invalid section] explanation about this.

Users can always ignore the check adding zfs_force=1 in the kernel parameters, but it is not advisable as a permanent solution.

Devices have different sector alignment

Once a drive has become faulted it should be replaced A.S.A.P. with an identical drive.

# zpool replace bigdata ata-ST3000DM001-9YN166_S1F0KDGY ata-ST3000DM001-1CH166_W1F478BD -f

but in this instance, the following error is produced:

cannot replace ata-ST3000DM001-9YN166_S1F0KDGY with ata-ST3000DM001-1CH166_W1F478BD: devices have different sector alignment

ZFS uses the ashift option to adjust for physical block size. When replacing the faulted disk, ZFS is attempting to use ashift=12, but the faulted disk is using a different ashift (probably ashift=9) and this causes the resulting error.

For Advanced Format Disks with 4KB blocksize, an ashift of 12 is recommended for best performance. See 1.10 What’s going on with performance? and ZFS and Advanced Format disks.

Use zdb to find the ashift of the zpool: zdb , then use the -o argument to set the ashift of the replacement drive:

# zpool replace bigdata ata-ST3000DM001-9YN166_S1F0KDGY ata-ST3000DM001-1CH166_W1F478BD -o ashift=9 -f

Check the zpool status for confirmation:

# zpool status -v
pool: bigdata
state: DEGRADED
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.
scan: resilver in progress since Mon Jun 16 11:16:28 2014
    10.3G scanned out of 5.90T at 81.7M/s, 20h59m to go
    2.57G resilvered, 0.17% done
config:

        NAME                                   STATE     READ WRITE CKSUM
        bigdata                                DEGRADED     0     0     0
        raidz1-0                               DEGRADED     0     0     0
            replacing-0                        OFFLINE      0     0     0
            ata-ST3000DM001-9YN166_S1F0KDGY    OFFLINE      0     0     0
            ata-ST3000DM001-1CH166_W1F478BD    ONLINE       0     0     0  (resilvering)
            ata-ST3000DM001-9YN166_S1F0JKRR    ONLINE       0     0     0
            ata-ST3000DM001-9YN166_S1F0KBP8    ONLINE       0     0     0
            ata-ST3000DM001-9YN166_S1F0JTM1    ONLINE       0     0     0

errors: No known data errors

Pool resilvering stuck/restarting/slow?

According to the ZFSonLinux github it is a known issue since 2012 with ZFS-ZED which causes the resilvering process to constantly restart, sometimes get stuck and be generally slow for some hardware. The simplest mitigation is to stop zfs-zed.service until the resilver completes

Fix slow boot caused by failed import of unavailable pools in the initramfs zpool.cache

Your boot time can be significantly impacted if you update your intitramfs (eg when doing a kernel update) when you have additional but non-permanently attached pools imported because these pools will get added to your initramfs zpool.cache and ZFS will attempt to import these extra pools on every boot, regardless of whether you have exported it and removed it from your regular zpool.cache.

If you notice ZFS trying to import unavailable pools at boot, first run:

$ zdb -C

To check your zpool.cache for pools you do not want imported at boot. If this command is showing (a) additional, currently unavailable pool(s), run:

# zpool set cachefile=/etc/zfs/zpool.cache zroot

To clear the zpool.cache of any pools other than the pool named zroot. Sometimes there is no need to refresh your zpool.cache, but instead all you need to do is regenerate the initramfs.

Tips and tricks

Embed the archzfs packages into an archiso

Follow the Archiso steps for creating a fully functional Arch Linux live CD/DVD/USB image.

Enable the archzfs repository:

~/archlive/pacman.conf
...
[archzfs]
Server = http://archzfs.com/$repo/x86_64
SigLevel = Optional TrustAll

Add the archzfs-linux group to the list of packages to be installed (the archzfs repository provides packages for the x86_64 architecture only).

~/archlive/packages.x86_64
...
archzfs-linux

Complete Build the ISO to finally build the iso.

Note: If you later have problems running modprobe zfs, you should include the linux-headers in the packages.x86_64.

Automatic snapshots

ZFS Automatic Snapshot Service for Linux

The zfs-auto-snapshot-gitAUR package from AUR provides a shell script to automate the management of snapshots, with each named by date and label (hourly, daily, etc), giving quick and convenient snapshotting of all ZFS datasets. The package also installs cron tasks for quarter-hourly, hourly, daily, weekly, and monthly snapshots. Optionally adjust the --keep parameter from the defaults depending on how far back the snapshots are to go (the monthly script by default keeps data for up to a year).

To prevent a dataset from being snapshotted at all, set com.sun:auto-snapshot=false on it. Likewise, set more fine-grained control as well by label, if, for example, no monthlies are to be kept on a snapshot, for example, set com.sun:auto-snapshot:monthly=false.

Note: zfs-auto-snapshot-git will not create snapshots during scrubbing. It is possible to override this by editing provided systemd unit (Systemd#Editing provided units) and removing `--skip-scrub` from `ExecStart` line. Consequences not known, someone please edit.

Once the package has been installed, enable and start the selected timers (zfs-auto-snapshot-{frequent,daily,weekly,monthly}.timer).

ZFS Snapshot Manager

The zfs-snap-managerAUR package from AUR provides a python service that takes daily snapshots from a configurable set of ZFS datasets and cleans them out in a "Grandfather-father-son" scheme. It can be configured to e.g. keep 7 daily, 5 weekly, 3 monthly and 2 yearly snapshots.

The package also supports configurable replication to other machines running ZFS by means of zfs send and zfs receive. If the destination machine runs this package as well, it could be configured to keep these replicated snapshots for a longer time. This allows a setup where a source machine has only a few daily snapshots locally stored, while on a remote storage server a much longer retention is available.

Creating a share

ZFS has support for creating shares by SMB or NFS.

NFS

Make sure NFS has been installed/configured, note there is no need to edit the /etc/exports file. For sharing over NFS the services nfs-server.service and zfs-share.service should be started.

To make a pool available on the network:

# zfs set sharenfs=on <nameofzpool>

To make a dataset available on the network:

# zfs set sharenfs=on <nameofzpool>/<nameofdataset>

To enable read/write access for a specific ip-range(s):

# zfs set sharenfs="rw=@192.168.1.100/24,rw=@10.0.0.0/24" <nameofzpool>/<nameofdataset>

To check if the dataset is exported successful:

# showmount -e `hostname`
Export list for hostname:
/path/of/dataset 192.168.1.100/24

To view the current loaded exports state in more detail, use:

# exportfs -v
/path/of/dataset
    192.168.1.100/24(sync,wdelay,hide,no_subtree_check,mountpoint,sec=sys,rw,secure,no_root_squash,no_all_squash)

SMB

When sharing smb shares configuring usershares in your smb.conf will allow ZFS to setup and create the shares.

# [global]
#    usershare path = /var/lib/samba/usershares
#    usershare max shares = 100
#    usershare allow guests = yes
#    usershare owner only = no

Create and set permissions on the user directory as root

# mkdir /var/lib/samba/usershares
# chmod +t /var/lib/samba/usershares

Encryption in ZFS using dm-crypt

The stable release version of ZFS on Linux used to not support encryption directly (now it's available, see #Native encryption), but zpools can be created on dm-crypt block devices. Since the zpool is created on the plain-text abstraction, it is possible to have the data encrypted while having all the advantages of ZFS like deduplication, compression, and data robustness.

dm-crypt, possibly via LUKS, creates devices in /dev/mapper and their name is fixed. So you just need to change zpool create commands to point to that names. The idea is configuring the system to create the /dev/mapper block devices and import the zpools from there. Since zpools can be created in multiple devices (raid, mirroring, striping, ...), it is important all the devices are encrypted otherwise the protection might be partially lost.

For example, an encrypted zpool can be created using plain dm-crypt (without LUKS) with:

# cryptsetup --hash=sha512 --cipher=twofish-xts-plain64 --offset=0 \
             --key-file=/dev/sdZ --key-size=512 open --type=plain /dev/sdX enc
# zpool create zroot /dev/mapper/enc

In the case of a root filesystem pool, the mkinitcpio.conf HOOKS line will enable the keyboard for the password, create the devices, and load the pools. It will contain something like:

HOOKS="... keyboard encrypt zfs ..."

Since the /dev/mapper/enc name is fixed no import errors will occur.

Creating encrypted zpools works fine. But if you need encrypted directories, for example to protect your users' homes, ZFS loses some functionality.

ZFS will see the encrypted data, not the plain-text abstraction, so compression and deduplication will not work. The reason is that encrypted data has always high entropy making compression ineffective and even from the same input you get different output (thanks to salting) making deduplication impossible. To reduce the unnecessary overhead it is possible to create a sub-filesystem for each encrypted directory and use eCryptfs on it.

For example to have an encrypted home: (the two passwords, encryption and login, must be the same)

# zfs create -o compression=off -o dedup=off -o mountpoint=/home/<username> <zpool>/<username>
# useradd -m <username>
# passwd <username>
# ecryptfs-migrate-home -u <username>
<log in user and complete the procedure with ecryptfs-unwrap-passphrase>

Emergency chroot repair with archzfs

To get into the ZFS filesystem from live system for maintenance, there are two options:

  1. Build custom archiso with ZFS as described in #Embed the archzfs packages into an archiso.
  2. Boot the latest official archiso and bring up the network. Then enable archzfs repository inside the live system as usual, sync the pacman package database and install the archzfs-archiso-linux package.

To start the recovery, load the ZFS kernel modules:

# modprobe zfs

Import the pool:

# zpool import -a -R /mnt

Mount the boot partitions (if any):

# mount /dev/sda2 /mnt/boot
# mount /dev/sda1 /mnt/boot/efi

Chroot into the ZFS filesystem:

# arch-chroot /mnt /bin/bash

Check the kernel version:

# pacman -Qi linux
# uname -r

uname will show the kernel version of the archiso. If they are different, run depmod (in the chroot) with the correct kernel version of the chroot installation:

# depmod -a 3.6.9-1-ARCH (version gathered from pacman -Qi linux but using the matching kernel modules directory name under the chroot's /lib/modules)

This will load the correct kernel modules for the kernel version installed in the chroot installation.

Regenerate the initramfs. There should be no errors.

Bind mount

Here a bind mount from /mnt/zfspool to /srv/nfs4/music is created. The configuration ensures that the zfs pool is ready before the bind mount is created.

fstab

See systemd.mount for more information on how systemd converts fstab into mount unit files with systemd-fstab-generator.

/etc/fstab
/mnt/zfspool		/srv/nfs4/music		none	bind,defaults,nofail,x-systemd.requires=zfs-mount.service	0 0

Monitoring / Mailing on Events

See ZED: The ZFS Event Daemon for more information.

An email forwarder, such as S-nail (installed as part of base), is required to accomplish this. Test it to be sure it is working correctly.

Uncomment the following in the configuration file:

/etc/zfs/zed.d/zed.rc
 ZED_EMAIL_ADDR="root"
 ZED_EMAIL_PROG="mailx"
 ZED_NOTIFY_VERBOSE=0
 ZED_EMAIL_OPTS="-s '@SUBJECT@' @ADDRESS@"

Update 'root' in ZED_EMAIL_ADDR="root" to the email address you want to receive notifications at.

If you are keeping your mailrc in your home directory, you can tell mail to get it from there by setting MAILRC:

/etc/zfs/zed.d/zed.rc
export MAILRC=/home/<user>/.mailrc

This works because ZED sources this file, so mailx sees this environment variable.

If you want to receive an email no matter the state of your pool, you will want to set ZED_NOTIFY_VERBOSE=1. You will need to do this temporary to test.

Start and enable zfs-zed.service.

With ZED_NOTIFY_VERBOSE=1, you can test by running a scrub as root: zpool scrub <pool-name>.

Wrap shell commands in pre & post snapshots

Since it is so cheap to make a snapshot, we can use this as a measure of security for sensitive commands such as system and package upgrades. If we make a snapshot before, and one after, we can later diff these snapshots to find out what changed on the filesystem after the command executed. Furthermore we can also rollback in case the outcome was not desired.

E.g.:

# zfs snapshot -r zroot@pre
# pacman -Syu
# zfs snapshot -r zroot@post
# zfs diff zroot@pre zroot@post 
# zfs rollback zroot@pre

A utility that automates the creation of pre and post snapshots around a shell command is znp.

E.g.:

# znp pacman -Syu
# znp find / -name "something*" -delete

and you would get snapshots created before and after the supplied command, and also output of the commands logged to file for future reference so we know what command created the diff seen in a pair of pre/post snapshots.

Remote unlocking of ZFS encrypted root

As of PR #261, archzfs supports SSH unlocking of natively-encrypted ZFS datasets. This section describes how to use this feature, and is largely based on dm-crypt/Specialties#Remote unlocking (hooks: netconf, dropbear, tinyssh, ppp).

  1. Install mkinitcpio-netconf to provide hooks for setting up early user space networking.
  2. Choose an SSH server to use in early user space. The options are mkinitcpio-tinyssh or mkinitcpio-dropbear, and are mutually exclusive.
    1. If using mkinitcpio-tinyssh, it is also recommended to install tinyssh-convert or tinyssh-convert-gitAUR. This tool converts an existing OpenSSH hostkey to the TinySSH key format, preserving the key fingerprint and avoiding connection warnings. The TinySSH and Dropbear mkinitcpio install scripts will automatically convert existing hostkeys when generating a new initcpio image.
  3. Decide whether to use an existing OpenSSH key or generate a new one (recommended) for the host that will be connecting to and unlocking the encrypted ZFS machine. Copy the public key into /etc/tinyssh/root_key or /etc/dropbear/root_key. When generating the initcpio image, this file will be added to authorized_keys for the root user and is only valid in the initrd environment.
  4. Add the ip= kernel parameter to your boot loader configuration. The ip string is highly configurable. A simple DHCP example is shown below.
    ip=:::::eth0:dhcp
  5. Edit /etc/mkinitcpio.conf to include the netconf, dropbear or tinyssh, and zfsencryptssh hooks before the zfs hook:
    HOOKS=(... netconf <tinyssh>|<dropbear> zfsencryptssh zfs ...)
  6. Regenerate the initramfs.
  7. Reboot and try it out!

Changing the SSH server port

By default, mkinitcpio-tinyssh and mkinitcpio-dropbear listen on port 22. You may wish to change this.

For TinySSH, copy /usr/lib/initcpio/hooks/tinyssh to /etc/initcpio/hooks/tinyssh, and find/modify the following line in the run_hook() function:

/etc/initcpio/hooks/tinyssh
/usr/bin/tcpserver -HRDl0 0.0.0.0 <new_port> /usr/sbin/tinysshd -v /etc/tinyssh/sshkeydir &

For Dropbear, copy /usr/lib/initcpio/hooks/dropbear to /etc/initcpio/hooks/dropbear, and find/modify the following line in the run_hook() function:

/etc/initcpio/hooks/tinyssh
 /usr/sbin/dropbear -E -s -j -k -p <new_port>

Regenerate the initramfs.

Unlocking from a Windows machine using PuTTY/Plink

First, we need to use puttygen.exe to import and convert the OpenSSH key generated earlier into PuTTY's .ppk private key format. Let us call it zfs_unlock.ppk for this example.

The mkinitcpio-netconf process above does not setup a shell (nor do we need need one). However, because there is no shell, PuTTY will immediately close after a successful connection. This can be disabled in the PuTTY SSH configuration (Connection -> SSH -> [X] Do not start a shell or command at all), but it still does not allow us to see stdout or enter the encryption passphrase. Instead, we use plink.exe with the following parameters:

plink.exe -ssh -l root -i c:\path\to\zfs_unlock.ppk <hostname>

The plink command can be put into a batch script for ease of use.

See also