Entendendo snapshots em BTRFS

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$ 
9 curtidas