Entendendo snapshots em BTRFS

O snapshot, ou instantâneo como traduzido em alguns programas, registra um estado instantâneo do sistema de arquivos em um subvolume, de forma análoga ao modo que uma fotografia captura um instante na paisagem. Para tal feito o sistema de arquivos já deve ser criado com essa característica desde a sua concepção. Por isso não podemos obter snapshots de sistemas ext4 ou xfs.

Para entender na totalidade os snapshots em sistemas BTRFS, é necessário que já se tenha compreensão do funcionamento de subvolumes. Leia, compreenda e exercite o texto anterior: Entendendo subvolumes no BTRFS

1) Como o snapshot funciona?

Quando é dado o comando para gerar um instantaneo, todos os acessos ao disco são temporariamente suspensos. O comando então cria um novo subvolume e replica a informação dos metadados do subvolume especificado para este novo subvolume de snapshot. Pode ser escolhido se esse subvolume será apenas leitura (recomendável) ou leitura e escrita. Uma vez finalizada a operação, as operações ao disco são retomadas.

2) Como que um snapshot não aumenta o espaço ocupado em disco?

Os arquivos são “copiados” apenas por referência. Os dados em disco continuam no mesmo local, apenas é criada uma nova referência para ele. No caso do snapshot TODOS os arquivos são duplicados por referência. O aumento de espaço ocupado é apenas em metadados.

3) Mas o que acontece quando um arquivo é modificado?

A informação de um arquivo modificado em um subvolume passa a ocupar um novo espaço físico. Se há snapshots desse arquivo, o conteúdo antigo é preservado. Os dados só serão descartados quando não houver mais referência a eles em todo o disco. É por isso que os snapshots começam ocupando bem pouco espaço (apenas mais informação em metadados) e conforme há alterações nos arquivos do subvolume principal, o sistema indica que há mais espaço ocupado pelos subvolumes dos snapshots.

4) Como organizar os snapshots?

Há duas abordagens comuns para organização dos subvolumes:

  1. Realizar os snapshots em um subdiretório oculto de nome .snapshots facilita o processo de criação de snapshots porém dificulta o rollback. Preferível usar em subvolumes que não precisarão de rollbacks, mas que seja interessante manter histórico de alterações de arquivos (timeline).
  2. Criar um subvolume @snapshots e então montá-lo na inicialização em um diretório .snapshots é mais trabalhoso para configurar, mas facilita em um possível rollback. Preferível nos casos onde o rollback pode ser frequente.

O processo de recuperação de arquivos isolados é o mesmo, independente do método escolhido. Como esse tutorial está mais focado para a reversão do sistema, será usada a segunda opção.

5) Como que eu reverto um snapshot? Ou ainda, como fazer o rollback de um snapshot?

Isso já vai depender do modo com que o snapshot foi feito e como é a distribuição de subvolumes no disco. De uma forma geral, para não perder a rastreabilidade de arquivos, costuma-se criar um snapshot do snapshot desejado. Em seguida altera-se esse snapshot para habilitar leitura e gravação. Então torna-se esse subvolume como padrão e remonta-se o subvolume (ou reinicia-se o computador no caso do raiz). Terá novamente os arquivos como naquele momento.

Esse procedimento pode ter vários complicadores, principalmente se for o raiz de uma instalação Linux, e se ele contém os arquivos de inicialização (pasta /boot). Para facilitar essa sequência de ações, o programa snapper foi criado e será alvo de um futuro tutorial.

6) Quero optar pelo gerenciamento manual. Quais recomendações?

Manter muitos snapshots (mais de 20) pode impactar de forma sensível a performance do disco. O espaço ocupado pelos snapshots vai crescendo conforme há mais modificações no sistema de arquivos, facilmente levando fim do espaço disponível. Evite manter snapshots muito antigos e se possível gerencie o espaço ocupado pelos snapshots com quotas e com o comando btrfs qgroup show <dir>. Verifique, instale e configure o pacote btrfsmaintenance, que mantém rotinas para balancear os sistemas.


Conteúdo disponível colaborativamente em GitHub - deleterium/TutoraisBTRFS: Tutoriais e exercícios para entender o funcionamento do sistema de arquivos BTRFS.

3 Curtidas

Exercícios:

Atenção, a forma manual de gerenciamento de snapshots será usada para fins didáticos. É como aprender a multiplicação no papel para depois usar a calculadora!

1) Criar, formatar e montar um volume btrfs em arquivo de imagem no seu diretório de usuário.

mkdir testesSnapshot
cd testesSnapshot
truncate -s 200M imagem.img
mkfs.btrfs -L MeuTesteSnapshot imagem.img
mkdir imagemMontada
sudo mount -o loop imagem.img imagemMontada/

Conforme exercício 1 do Entendendo Subvolumes em BTRFS - Exercícios

2) Criar dois subvolumes: @arquivos e @snapshots

sudo btrfs subvolume create imagemMontada/@arquivos
sudo btrfs subvolume create imagemMontada/@snapshots

3) Setar o volume padrão da partição para o subvolume @arquivos

sudo btrfs subvol list ./imagemMontada
sudo btrfs subvol set-default XXX ./imagemMontada

4) Remontar com o novo volume padrão

sudo umount ./imagemMontada
sudo mount -o loop imagem.img imagemMontada/

5) Montar o subvolume @snapshots no diretório .snapshots

sudo mkdir ./imagemMontada/.snapshots
sudo mount -o loop,subvol=@snapshots imagem.img imagemMontada/.snapshots

6) Criar um arquivo no diretório imagemMontada

sudo sh -c 'echo "Primeira versão do arquivo" > ./imagemMontada/exemplo.txt'
ls -la ./imagemMontada

7) Criar o primeiro snapshot do subvolume

sudo btrfs subvol snapshot -r ./imagemMontada ./imagemMontada/.snapshots/Snap1

Nota: É recomendável que os snapshots sejam somente-leitura (opção -r) para criar mais uma camada de proteção contra alterações inadvertidas

8) Sobrescrever o conteúdo do arquivo exemplo.txt

sudo sh -c 'echo "Versão com conteúdo inesperado" > ./imagemMontada/exemplo.txt'

9) Verificar o conteúdo do arquivo padrão e do arquivo que está no snapshot

cat ./imagemMontada/exemplo.txt
cat ./imagemMontada/.snapshots/Snap1/exemplo.txt

Nota: para esse simples exemplo com apenas um arquivo, seria muito mais fácil reverter apenas esse arquivo, copiando o arquivo do snapshot para o subvolume padrão. Porém em situações práticas, centenas de arquivos são adicionados, modificados ou deletados, tornando muito difícil comparar e reverter arquivo por arquivo manualmente (mais a frente veremos que o snapper automatiza esse processo também!)

10) Rollback #1: Criar um snapshot do snapshot a ser revertido em modo leitura e gravação. Confirme os modos

sudo btrfs subv snap ./imagemMontada/.snapshots/Snap1 ./imagemMontada/.snapshots/SnapRW
sudo btrfs property get ./imagemMontada/.snapshots/Snap1
sudo btrfs property get ./imagemMontada/.snapshots/SnapRW

11) Rollback #2: Montar a árvore do BTRFS para realizar operações de movimentação de subvolumes

mkdir btrfs
sudo mount -o loop,subvolid=5 imagem.img ./btrfs/

12) Rollback #3: Renomear o subvolume @arquivos para @arquivos.old

sudo mv ./btrfs/@arquivos ./btrfs/@arquivos.old

Nota: o subvolume continua montado em imagemMontada, mas não houve erro nessa operação.

13) Rollback #4: Renomear o SnapRW para @arquivos, movendo-o de subvolume pai

sudo btrfs subv list ./btrfs
sudo mv ./btrfs/@snapshots/SnapRW/ ./btrfs/@arquivos

Nota: É importante que o subvolume seja renomeado no caso de haver referências a ele durante a inicialização (caso possua a pasta /boot) ou no /etc/fstab. Caso ele seja apenas montado como subvolume padrão em outros pontos de montagem, essa etapa de renomear o subvolume é opcional, porém recomendável. Fica um tanto estranho ter o volume padrão dentro do subvolume @snapshots e não poder deletá-lo.

14) Rollback #5: Alterar o volume padrão do sistema de arquivos para o número do novo @arquivos

sudo btrfs subv list ./btrfs
sudo btrfs subv set-default XXX ./btrfs

15) Desmonte tudo e remonte o subvolume padrão e seus snapshots (simulando o reboot do computador)

sudo umount -R ./imagemMontada
sudo umount ./btrfs
sudo mount -o loop imagem.img imagemMontada/
sudo mount -o loop,subvol=@snapshots imagem.img imagemMontada/.snapshots

Nota: a opção -R do umount desmonta todos os demais pontos de montagem recursivamente dentro do ponto de montagem especificado.

16) Compare o conteúdo dos arquivos exemplo do subvolume padrão com o do snapshot

cat ./imagemMontada/exemplo.txt
cat ./imagemMontada/.snapshots/Snap1/exemplo.txt

17) Uma vez que a operação foi completada com sucesso, poderá apagar o subvolume indesejado.

sudo mount -o loop,subvolid=5 imagem.img ./btrfs/
sudo btrfs subvol delete ./btrfs/@arquivos.old

Exercícios solucionados:

john@MintVM:~$ # 1
john@MintVM:~$ mkdir testesSnapshot
john@MintVM:~$ cd testesSnapshot
john@MintVM:~/testesSnapshot$ truncate -s 200M imagem.img
john@MintVM:~/testesSnapshot$ mkfs.btrfs -L MeuTesteSnapshot imagem.img
btrfs-progs v4.15.1
See http://btrfs.wiki.kernel.org for more information.

Label:              MeuTesteSnapshot
UUID:               548770cc-7302-453d-a28a-82a0052e2278
Node size:          16384
Sector size:        4096
Filesystem size:    200.00MiB
Block group profiles:
  Data:             single            8.00MiB
  Metadata:         DUP              32.00MiB
  System:           DUP               8.00MiB
SSD detected:       no
Incompat features:  extref, skinny-metadata
Number of devices:  1
Devices:
   ID        SIZE  PATH
    1   200.00MiB  imagem.img

john@MintVM:~/testesSnapshot$ mkdir imagemMontada
john@MintVM:~/testesSnapshot$ sudo mount -o loop imagem.img imagemMontada/
[sudo] senha para john:     
john@MintVM:~/testesSnapshot$ # 2
john@MintVM:~/testesSnapshot$ sudo btrfs subvolume create imagemMontada/@arquivos
Create subvolume 'imagemMontada/@arquivos'
john@MintVM:~/testesSnapshot$ sudo btrfs subvolume create imagemMontada/@snapshots
Create subvolume 'imagemMontada/@snapshots'
john@MintVM:~/testesSnapshot$ # 3
john@MintVM:~/testesSnapshot$ sudo btrfs subvol list ./imagemMontada
ID 256 gen 8 top level 5 path @arquivos
ID 257 gen 9 top level 5 path @snapshots
john@MintVM:~/testesSnapshot$ sudo btrfs subvol set-default 256 ./imagemMontada
john@MintVM:~/testesSnapshot$ # 4
john@MintVM:~/testesSnapshot$ sudo umount ./imagemMontada
john@MintVM:~/testesSnapshot$ sudo mount -o loop imagem.img imagemMontada/
john@MintVM:~/testesSnapshot$ # 5
john@MintVM:~/testesSnapshot$ sudo mkdir ./imagemMontada/.snapshots
john@MintVM:~/testesSnapshot$ sudo mount -o loop,subvol=@snapshots imagem.img imagemMontada/.snapshots
john@MintVM:~/testesSnapshot$ # 6
john@MintVM:~/testesSnapshot$ sudo sh -c 'echo "Primeira versão do arquivo" > ./imagemMontada/exemplo.txt'
john@MintVM:~/testesSnapshot$ ls -la ./imagemMontada
total 4
drwxr-xr-x 1 root root 42 mar 17 22:38 .
drwxr-xr-x 1 john john 46 mar 17 22:33 ..
-rw-r--r-- 1 root root 28 mar 17 22:38 exemplo.txt
drwxr-xr-x 1 root root  0 mar 17 22:33 .snapshots
john@MintVM:~/testesSnapshot$ # 7
john@MintVM:~/testesSnapshot$ sudo btrfs subvol snapshot -r ./imagemMontada ./imagemMontada/.snapshots/Snap1
Create a readonly snapshot of './imagemMontada' in './imagemMontada/.snapshots/Snap1'
john@MintVM:~/testesSnapshot$ # 8
john@MintVM:~/testesSnapshot$ sudo sh -c 'echo "Versão com conteúdo inesperado" > ./imagemMontada/exemplo.txt'
john@MintVM:~/testesSnapshot$ # 9
john@MintVM:~/testesSnapshot$ cat ./imagemMontada/exemplo.txt
Versão com conteúdo inesperado
john@MintVM:~/testesSnapshot$ cat ./imagemMontada/.snapshots/Snap1/exemplo.txt
Primeira versão do arquivo
john@MintVM:~/testesSnapshot$ # 10
john@MintVM:~/testesSnapshot$ sudo btrfs subv snap ./imagemMontada/.snapshots/Snap1 ./imagemMontada/.snapshots/SnapRW
Create a snapshot of './imagemMontada/.snapshots/Snap1' in './imagemMontada/.snapshots/SnapRW'
john@MintVM:~/testesSnapshot$ sudo btrfs property get ./imagemMontada/.snapshots/Snap1
ro=true
john@MintVM:~/testesSnapshot$ sudo btrfs property get ./imagemMontada/.snapshots/SnapRW
ro=false
john@MintVM:~/testesSnapshot$ # 11
john@MintVM:~/testesSnapshot$ mkdir btrfs
john@MintVM:~/testesSnapshot$ sudo mount -o loop,subvolid=5 imagem.img ./btrfs/
john@MintVM:~/testesSnapshot$ # 12
john@MintVM:~/testesSnapshot$ sudo mv ./btrfs/@arquivos ./btrfs/@arquivos.old
john@MintVM:~/testesSnapshot$ # 13
john@MintVM:~/testesSnapshot$ sudo btrfs subv list ./btrfs
ID 256 gen 16 top level 5 path @arquivos.old
ID 257 gen 17 top level 5 path @snapshots
ID 258 gen 17 top level 257 path @snapshots/Snap1
ID 259 gen 17 top level 257 path @snapshots/SnapRW
john@MintVM:~/testesSnapshot$ sudo mv ./btrfs/@snapshots/SnapRW/ ./btrfs/@arquivos
john@MintVM:~/testesSnapshot$ # 14
john@MintVM:~/testesSnapshot$ sudo btrfs subv list ./btrfs
ID 256 gen 16 top level 5 path @arquivos.old
ID 257 gen 19 top level 5 path @snapshots
ID 258 gen 17 top level 257 path @snapshots/Snap1
ID 259 gen 17 top level 5 path @arquivos
john@MintVM:~/testesSnapshot$ sudo btrfs subv set-default 259 ./btrfs
john@MintVM:~/testesSnapshot$ # 15
john@MintVM:~/testesSnapshot$ sudo umount -R ./imagemMontada
john@MintVM:~/testesSnapshot$ sudo umount ./btrfs
john@MintVM:~/testesSnapshot$ sudo mount -o loop imagem.img imagemMontada/
john@MintVM:~/testesSnapshot$ sudo mount -o loop,subvol=@snapshots imagem.img imagemMontada/.snapshots
john@MintVM:~/testesSnapshot$ # 16
john@MintVM:~/testesSnapshot$ cat ./imagemMontada/exemplo.txt
Primeira versão do arquivo
john@MintVM:~/testesSnapshot$ cat ./imagemMontada/.snapshots/Snap1/exemplo.txt
Primeira versão do arquivo
john@MintVM:~/testesSnapshot$ # 17
john@MintVM:~/testesSnapshot$ sudo mount -o loop,subvolid=5 imagem.img ./btrfs/
john@MintVM:~/testesSnapshot$ sudo btrfs subvol delete ./btrfs/@arquivos.old
Delete subvolume (no-commit): '/home/john/testesSnapshot/btrfs/@arquivos.old'
john@MintVM:~/testesSnapshot$ 
6 Curtidas

Para que serve, ou melhor, qual o benefício de se usar snapshot?

No caso serve para restaurar um sistema de arquivos a partir dele. Ou pelo menos uma parte dele.

Seria pelo processo rollback?

12) Rollback #3: Renomear o subvolume @arquivos para @arquivos.old

Os snapshots guardam histórico de alterações dos arquivos. O rollback pode ser usado para recuperar todas a informações que foram alteradas desde determinado snapshot, com a vantagem de guardar também uma cópia dos arquivos como estão atualmente.

Nesse tutorial eu apresentei a formas de fazer o rollback manual. Porém o conteúdo anterior dos arquivos pode ser recuperado manualmente (arquivo por arquiv) com operações de cópia do arquivo do subvolume.

O snapper pode ser usado para automatizar e facilitar a recuperação de um arquivo, através do comando snapper undochange. Ele também tem a funcionalidade de fazer o rollback através do snapper rollback.

É interessante com o snapper que é possível fazer o undochange de todos os arquivos de determinando snapshot, algo que seria semelhante ao rollback, mas seria diferente por não poder ser desfeito.

1 Curtida

Uso Snapshots + BtrFS desde Janeiro 2017, quando instalei openSUSE pela primeira vez.

Fiz upgrade do Leap várias vezes, e ano passado resolvi fazer logo upgrade para Tumbleweed.

Com tanta emoção, raras vezes precisei fazer rollback ─ openSUSE é sólido, como poucas distros!

Este ano, máquina nova, instalei o Tumbleweed do zero, e finalmente comecei a ter problemas.

Bom, isso já tem 6 meses, e continua funcionando. ─ Prefiro continuar lendo, pesquisando, tentando consertar, do que “zerar” e instalar de novo. ─ Acho que, tentando, aprendo mais.

É fantástico, maravilhoso. Eu não desistiria, por nada nesse mundo.

achei interessante adicionar aqui

https://en.opensuse.org/SDB:Cleanup_system#Cleanup_Btrfs_snapshots
Cleanup Btrfs snapshots

Tell snapper to delete old snapshots based on configuration at /etc/snapper/configs/root

sudo snapper cleanup number

By default, snapper allows:

Maximum 50% of root file system space for snapshots. (20 GB of 40 GB root file system)
Minimum 2 and maximum 10 normal snapshots.
Minimum 4 and maximum 10 important snapshots.

You can reduce it using the following command:

snapper set-config SPACE_LIMIT=0.2 NUMBER_LIMIT=2-6 NUMBER_LIMIT_IMPORTANT=4

Maximum 20% of root file system space for snapshots. (8 GB of 40 GB root file system)
Minimum 2 and maximum 6 normal snapshots.
4 important snapshots.

Which means