Introducción

Buenas, en este post vamos a instalar y configurar el software de BTRFS, un sistema de ficheros avanzados para ver su uso y funcionamiento.

Configuración escenario

Hemos creado una máquina en OpenStack y le hemos añadido 4 volúmenes de prueba de diferentes tamaños cada uno:

lsblk
NAME   MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vda    254:0    0  20G  0 disk 
└─vda1 254:1    0  20G  0 part /
vdb    254:16   0   1G  0 disk /mnt
vdd    254:48   0   2G  0 disk 
vde    254:64   0   3G  0 disk 
vdf    254:80   0   4G  0 disk

Instalación

Vamos a instalar Btrfs, para ello, actualizamos la máquina e instalamos:

sudo apt update && sudo apt upgrade -y
sudo apt install btrfs-tools -y

Crear sistema Btrfs

Para dar formato a uno de los discos con el nuevo sistema de ficheros:

sudo mkfs.btrfs /dev/vdb
btrfs-progs v4.20.1 
See http://btrfs.wiki.kernel.org for more information.

Label:              (null)
UUID:               9a11dd38-95e9-46c7-892e-180eab7f211f
Node size:          16384
Sector size:        4096
Filesystem size:    1.00GiB
Block group profiles:
  Data:             single            8.00MiB
  Metadata:         DUP              51.19MiB
  System:           DUP               8.00MiB
SSD detected:       no
Incompat features:  extref, skinny-metadata
Number of devices:  1
Devices:
   ID        SIZE  PATH
    1     1.00GiB  /dev/vdb

Y podemos comprobarlo:

lsblk -f
NAME   FSTYPE LABEL UUID                                 FSAVAIL FSUSE% MOUNTPOINT
vda                                                                     
└─vda1 ext4         9659e5d4-dd87-42af-bf70-0bb6f7b2e31b   17.8G     5% /
vdb    btrfs        9a11dd38-95e9-46c7-892e-180eab7f211f                
vdd                                                                     
vde                                                                     
vdf

Gestion discos

Vamos a dar formato a dos discos para ver que ocurre, para ello:

sudo mkfs.btrfs -f /dev/vdb /dev/vdd
btrfs-progs v4.20.1 
See http://btrfs.wiki.kernel.org for more information.

Label:              (null)
UUID:               c4ed17de-6443-4750-b59b-b9db8aa9d589
Node size:          16384
Sector size:        4096
Filesystem size:    3.00GiB
Block group profiles:
  Data:             RAID0           307.12MiB
  Metadata:         RAID1           153.56MiB
  System:           RAID1             8.00MiB
SSD detected:       no
Incompat features:  extref, skinny-metadata
Number of devices:  2
Devices:
   ID        SIZE  PATH
    1     1.00GiB  /dev/vdb
    2     2.00GiB  /dev/vdd

Hemos usado la opción -f porque uno de los discos ya le dimos formato anteriormente. Si nos damos cuenta, lo que hemos conseguido hacer es unir los dos dispositivos como si fueran uno sólo, en lo que parece un RAID híbrido entre RAID 1 y RAID 0. Podemos comprobar que los dos dispositivos tienen el mismo UID de la siguiente forma:

lsblk -f
NAME   FSTYPE LABEL UUID                                 FSAVAIL FSUSE% MOUNTPOINT
vda                                                                     
└─vda1 ext4         9659e5d4-dd87-42af-bf70-0bb6f7b2e31b   17.8G     5% /
vdb    btrfs        c4ed17de-6443-4750-b59b-b9db8aa9d589                
vdd    btrfs        c4ed17de-6443-4750-b59b-b9db8aa9d589                
vde                                                                     
vdf

Podemos montar cualquiera de los dos dispositivos para verlo:

sudo mount /dev/vdb /mnt/

Veremos que la capacidad es la de los dos discos juntos:

df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            235M     0  235M   0% /dev
tmpfs            49M  1.6M   47M   4% /run
/dev/vda1        20G  1.1G   18G   6% /
tmpfs           243M     0  243M   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           243M     0  243M   0% /sys/fs/cgroup
tmpfs            49M     0   49M   0% /run/user/1000
/dev/vdb        3.0G   17M  1.7G   1% /mnt

RAID 1

Vamos a configurar un RAID 1 con sistema de tolerancia a fallos, para ello:

sudo mkfs.btrfs -f -d raid1 -m raid1 /dev/vdf /dev/vdd /dev/vde
btrfs-progs v4.20.1 
See http://btrfs.wiki.kernel.org for more information.

Label:              (null)
UUID:               aef23e40-53f8-43a5-b849-16ecb3d938f2
Node size:          16384
Sector size:        4096
Filesystem size:    9.00GiB
Block group profiles:
  Data:             RAID1           460.75MiB
  Metadata:         RAID1           460.75MiB
  System:           RAID1             8.00MiB
SSD detected:       no
Incompat features:  extref, skinny-metadata
Number of devices:  3
Devices:
   ID        SIZE  PATH
    1     4.00GiB  /dev/vdf
    2     2.00GiB  /dev/vdd
    3     3.00GiB  /dev/vde

Como podemos apreciar se ha creado un RAID1 correctamente, es más, hemos podido aprovechar todo el espacio de los discos aunque sean de diferente tamaño. En el caso de que hubieramos hecho un RAID1 con el software mdadm todos los dispositivos de bloques deberían de tener el mismo tamaño, o en su defecto, se escogería la capacidad del disco menor.

Podemos mostrar los dispositivos de la siguiente forma:

sudo btrfs filesystem show

Label: none  uuid: aef23e40-53f8-43a5-b849-16ecb3d938f2
	Total devices 3 FS bytes used 128.00KiB
	devid    1 size 4.00GiB used 921.50MiB path /dev/vdf
	devid    2 size 2.00GiB used 468.75MiB path /dev/vdd
	devid    3 size 3.00GiB used 468.75MiB path /dev/vde

Añadir disco a RAID

Para añadir un disco al RAID, podemos hacerlo de la siguiente forma, primero tenemos que montar el RAID:

sudo mount /dev/vdf /mnt/

Y después añadimos el disco al RAID:

sudo btrfs device add -f /dev/vdb /mnt/

Mostramos otra vez los discos:

sudo btrfs filesystem show
Label: none  uuid: aef23e40-53f8-43a5-b849-16ecb3d938f2
	Total devices 4 FS bytes used 256.00KiB
	devid    1 size 4.00GiB used 921.50MiB path /dev/vdf
	devid    2 size 2.00GiB used 468.75MiB path /dev/vdd
	devid    3 size 3.00GiB used 468.75MiB path /dev/vde
	devid    4 size 1.00GiB used 0.00B path /dev/vdb

Se ha añadido correctamente pero no está haciendo uso de su espacio, para ello tenemos que activar el balanceo de carga para que se reparta la información entre todos los discos:

sudo btrfs balance start --full-balance /mnt/

Ahora vamos a escribir en el disco para comprobar que se está haciendo correctamente el balanceo y cuanto espacio puede soportar nuestro RAID:

sudo dd if=/dev/zero of=/mnt/prueba
dd: writing to '/mnt/prueba': No space left on device
9890530+0 records in
9890529+0 records out
5063950848 bytes (5.1 GB, 4.7 GiB) copied, 177.7 s, 28.5 MB/s

Y si comprobamos los dispositivos:

sudo btrfs filesystem show
Label: none  uuid: aef23e40-53f8-43a5-b849-16ecb3d938f2
	Total devices 4 FS bytes used 4.72GiB
	devid    1 size 4.00GiB used 4.00GiB path /dev/vdf
	devid    2 size 2.00GiB used 2.00GiB path /dev/vdd
	devid    3 size 3.00GiB used 3.00GiB path /dev/vde
	devid    4 size 1.00GiB used 1023.00MiB path /dev/vdb

Podemos observar que ha rellenado todos los discos con su capacidad máxima. Si hubiéramos hecho el RAID con mdadm sólo podríamos haber escrito 1GB, ya que es la capacidad máxima soportada por el menos disco.

Comando para saber integridad de datos en raid

Para hacer un chequeo de la integridad de los datos del raid, podemos ejecutar lo siguiente:

sudo btrfs scrub start /mnt/

Y es un proceso que se ejecuta en segundo plano el cual podemos ver su estado de la siguiente forma:

sudo btrfs scrub status /mnt/
scrub status for aef23e40-53f8-43a5-b849-16ecb3d938f2
	scrub started at Thu Jan 21 17:18:38 2021, running for 00:00:20
	total bytes scrubbed: 2.08GiB with 0 errors

Cuando acabe nos saldrá el siguiente mensaje:

sudo btrfs scrub status /mnt/
scrub status for aef23e40-53f8-43a5-b849-16ecb3d938f2
	scrub started at Fri Jan 22 07:37:06 2021 and finished after 00:01:34
	total bytes scrubbed: 9.44GiB with 0 errors

El cual nos ha dicho que no ha habido ningún error.

Fallo en algún disco

Vamos a quitar un disco haciéndo creer que ha fallado y ejecutamos la instrucción para ver el raid:

sudo btrfs filesystem show
Label: none  uuid: aef23e40-53f8-43a5-b849-16ecb3d938f2
	Total devices 4 FS bytes used 4.72GiB
	devid    1 size 4.00GiB used 4.00GiB path /dev/vdf
	devid    2 size 2.00GiB used 2.00GiB path /dev/vdd
	devid    3 size 3.00GiB used 3.00GiB path /dev/vde
	*** Some devices missing

Como vemos ejecutando el comando anterior tenemos errores porque un disco no funciona:

sudo btrfs scrub status /mnt/
scrub status for aef23e40-53f8-43a5-b849-16ecb3d938f2
	scrub started at Fri Jan 22 08:27:21 2021 and finished after 00:03:08
	total bytes scrubbed: 9.44GiB with 261874 errors
	error details: read=261872 super=2
	corrected errors: 0, uncorrectable errors: 261872, unverified errors: 0

Sustitución de disco dañado

Para poder sustituir el disco hemos añadido uno nuevo:

lsblk
NAME   MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vda    254:0    0  20G  0 disk 
└─vda1 254:1    0  20G  0 part /
vdc    254:32   0   1G  0 disk /mnt
vdd    254:48   0   2G  0 disk 
vde    254:64   0   3G  0 disk 
vdf    254:80   0   4G  0 disk

Y vamos a ejecutar la siguiente orden:

sudo btrfs replace start 4 /dev/vdc /mnt/

Seguidamente podremos ver su progreso como muestro a continuación:

sudo btrfs replace status /mnt/
0.0% done, 0 write errs, 0 uncorr. read errs

Y cuando finalize nos saldrá el siguiente mensaje:

sudo btrfs replace status /mnt/
Started on 22.Jan 09:08:01, finished on 22.Jan 09:11:38, 0 write errs, 0 uncorr. read errs

Comprobación

Vemos que todo está correcto:

sudo btrfs filesystem show
Label: none  uuid: aef23e40-53f8-43a5-b849-16ecb3d938f2
	Total devices 4 FS bytes used 4.72GiB
	devid    1 size 4.00GiB used 4.00GiB path /dev/vdf
	devid    2 size 2.00GiB used 2.00GiB path /dev/vdd
	devid    3 size 3.00GiB used 3.00GiB path /dev/vde
	devid    4 size 1.00GiB used 1023.00MiB path /dev/vdc

Para comprobar el estado del RAID:

sudo btrfs scrub start /mnt/
scrub started on /mnt/, fsid aef23e40-53f8-43a5-b849-16ecb3d938f2 (pid=9150)

Y al finalizar:

sudo btrfs scrub status /mnt/
scrub status for aef23e40-53f8-43a5-b849-16ecb3d938f2
	scrub started at Fri Jan 22 09:52:45 2021 and finished after 00:01:32
	total bytes scrubbed: 9.44GiB with 0 errors

Compresión

Existen dos formas de compresión al vuelo en BTRFS, ZLIB y LZO. Este último es más rápido pero comprime menos. Nosotros usaremos ZLIB, que comprime con mayor detalle pero más lento.

Para poder ejecutar la comprensión al vuelo vamos a formatear uno de los discos de 4G que tenemos:

sudo mkfs.btrfs -f /dev/vde 
btrfs-progs v4.20.1 
See http://btrfs.wiki.kernel.org for more information.

Label:              (null)
UUID:               0cbafa86-b631-423e-9050-1119842d3b01
Node size:          16384
Sector size:        4096
Filesystem size:    4.00GiB
Block group profiles:
  Data:             single            8.00MiB
  Metadata:         DUP             204.75MiB
  System:           DUP               8.00MiB
SSD detected:       no
Incompat features:  extref, skinny-metadata
Number of devices:  1
Devices:
   ID        SIZE  PATH
    1     4.00GiB  /dev/vde

Y lo vamos a montar de la siguiente forma:

$ sudo mount -o compress=zlib /dev/vde /mnt/

$ lsblk
NAME   MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vda    254:0    0  20G  0 disk 
└─vda1 254:1    0  20G  0 part /
vdb    254:16   0   1G  0 disk 
vdc    254:32   0   2G  0 disk 
vdd    254:48   0   3G  0 disk 
vde    254:64   0   4G  0 disk /mnt

Ahora vamos a rellenar el disco con gran cantidad de datos:

 sudo dd if=/dev/zero of=/mnt/prueba
^C175804802+0 records in
175804802+0 records out
90012058624 bytes (90 GB, 84 GiB) copied, 1281.03 s, 70.3 MB/s

Y podemos comprobar que nuestro disco es de tan sólo 4GB:

sudo btrfs filesystem show /mnt/
Label: none  uuid: 0cbafa86-b631-423e-9050-1119842d3b01
	Total devices 1 FS bytes used 2.78GiB
	devid    1 size 4.00GiB used 3.27GiB path /dev/vde

Pero que los datos que ahora mismo tiene en él son los siguientes:

du -h /mnt/
84G	/mnt/

84GB es lo que tiene comprimidos de tal forma que sólo ocupan 3.27GiB, y cada vez que queramos acceder a ese dato automáticamente BTRFS lo descomprimirá y lo volverá a comprimir.

Subvolumenes y snapshots

Vamos a crear subvolumenes, los cuales podemos montar en varios directorios para poder usarlos simúltaneamente, por ejemplo, tener montado uno en /home y otro en /etc y gracias a los snapshots tener una copia de cada uno de los directorios, para ello lo primero que haremos será crear el grupo de volúmenes:

sudo mkfs.btrfs /dev/vdc /dev/vdd /dev/vdb -f -L 'sub'
btrfs-progs v4.20.1 
See http://btrfs.wiki.kernel.org for more information.

Label:              sub
UUID:               a4328666-4496-446e-86ad-a723db37aad6
Node size:          16384
Sector size:        4096
Filesystem size:    6.00GiB
Block group profiles:
  Data:             RAID0           614.25MiB
  Metadata:         RAID1           307.19MiB
  System:           RAID1             8.00MiB
SSD detected:       no
Incompat features:  extref, skinny-metadata
Number of devices:  3
Devices:
   ID        SIZE  PATH
    1     2.00GiB  /dev/vdc
    2     3.00GiB  /dev/vdd
    3     1.00GiB  /dev/vdb

Montamos el grupo de volúmenes:

sudo mount /dev/vdc /mnt/

Comprobamos:

sudo btrfs filesystem show
Label: 'sub'  uuid: a4328666-4496-446e-86ad-a723db37aad6
	Total devices 3 FS bytes used 128.00KiB
	devid    1 size 2.00GiB used 511.94MiB path /dev/vdc
	devid    2 size 3.00GiB used 212.75MiB path /dev/vdd
	devid    3 size 1.00GiB used 519.94MiB path /dev/vdb

Y ahora creamos varios subvolúmenes:

sudo btrfs subvolume create /mnt/sub1
sudo btrfs subvolume create /mnt/sub2
sudo btrfs subvolume create /mnt/sub3

Los listamos para comprobar que se han creado correctamente:

sudo btrfs subvolume list /mnt/
ID 258 gen 7 top level 5 path sub1
ID 259 gen 8 top level 5 path sub2
ID 260 gen 9 top level 5 path sub3

Para poder montar dichos subvolúmenes tenemos que saber su ID como hemos visto anteriormente, lo vamos a montar en /media:

sudo mount -o subvolid=258 /dev/vdc /media

Creamos un fichero en /media:

sudo touch /media/fichero.txt

Y si comprobamos en /mnt/sub1:

ls /mnt/sub1/
fichero.txt

Podemos también comprobar qué volumen está montado en el directorio:

sudo btrfs subvolume show /media
sub1
	Name: 			sub1
	UUID: 			2861b2ba-3fa4-f745-9b05-6d4e135f7d04
	Parent UUID: 		-
	Received UUID: 		-
	Creation time: 		2021-01-22 16:23:18 +0000
	Subvolume ID: 		258
	Generation: 		11
	Gen at creation: 	7
	Parent ID: 		5
	Top level ID: 		5
	Flags: 			-
	Snapshot(s):

Snapshots

Para poder hacerle un snapshots a un subvolumen:

sudo btrfs subvolume snapshot /mnt/sub1 /mnt/sub1.snap
Create a snapshot of '/mnt/sub1' in '/mnt/sub1.snap'

Y para poder restaurar dicha copia:

sudo mv /mnt/sv1.snap /mnt/sv1

Redimensionado

Podemos redimensionar el cualquier momento un sistema de btrfs, suponiendo que tenemos lo siguiente:

sudo btrfs filesystem show /mnt/
Label: 'red'  uuid: 6abfd83c-3dcd-4fd5-b5d9-e5766e72c2cf
	Total devices 1 FS bytes used 128.00KiB
	devid    1 size 2.00GiB used 228.75MiB path /dev/vdc

Vamos a redimensionar a 1G, para ello:

sudo btrfs filesystem resize -1g /mnt/
Resize '/mnt/' of '-1g'

Y comprobamos:

sudo btrfs filesystem show /mnt/
Label: 'red'  uuid: 6abfd83c-3dcd-4fd5-b5d9-e5766e72c2cf
	Total devices 1 FS bytes used 192.00KiB
	devid    1 size 1.00GiB used 228.75MiB path /dev/vdc

Podemos volver a darle su valor máximo de siguiente forma:

sudo btrfs filesystem resize max /mnt/
Resize '/mnt/' of 'max'

Y lo volvemos a comprobar:

sudo btrfs filesystem show /mnt/
Label: 'red'  uuid: 6abfd83c-3dcd-4fd5-b5d9-e5766e72c2cf
	Total devices 1 FS bytes used 192.00KiB
	devid    1 size 2.00GiB used 228.75MiB path /dev/vdc

Copy on write

Vamos a hacer Copy on write, lo cuál nos permite copiar varios ficheros iguales pero sólo ocupando el espacio de uno. Tenemos el siguiente escenario:

sudo btrfs filesystem show /mnt/
Label: 'red'  uuid: 6abfd83c-3dcd-4fd5-b5d9-e5766e72c2cf
	Total devices 1 FS bytes used 192.00KiB
	devid    1 size 2.00GiB used 228.75MiB path /dev/vdc

Para poder utilizar esta utilidad, vamos a crear un fichero de 1G:

sudo dd if=/dev/urandom of=/mnt/fichero1 bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 8.50991 s, 123 MB/s

Si vemos su tamaño:

ls -lh /mnt/
total 1000M
-rw-r--r-- 1 root root 1000M Jan 22 17:05 fichero1

Vamos a copiar varios ficheros, nuestro espacio máximo es de 2GB:

sudo cp --reflink=always fichero1 fichero2
sudo cp --reflink=always fichero1 fichero3
sudo cp --reflink=always fichero1 fichero4
sudo cp --reflink=always fichero1 fichero5

Nos ha dejado perfectamente, ya que si vemos en realidad cuánto espacio está consumiendo:

df -h /mnt/
Filesystem      Size  Used Avail Use% Mounted on
/dev/vdc        2.0G 1019M  826M  56% /mnt