Ejemplos de uso de Btrfs

per Victor Carceler darrera modificació 2021-06-19T06:52:43+01:00

Btrfs es un sistema de archivos de nueva generación para GNU/Linux con funciones que permiten escalar el almacenamiento a configuraciones de gran capacidad. Su desarrollo todavía no se ha completado pero está integrado en el núcleo desde la versión 2.6.29 y actualmente es utilizable incluso como sistema de archivos raíz. Además el formato en disco está estabilizado, de modo que se garantiza que los sistemas de archivos creados se podrán seguir utilizando con versiones nuevas de Linux.

Del mismo modo que lo hace ZFS; Btrfs hace un uso extensivo de copy-on-write, permite snapshots de solo lectura o modificables, incluye soporte nativo para sistemas de archivos multidispositivo y soporta subvolumenes. Además protege la información (datos y metadatos) mediante checksums, soporta compresión, optimizaciones para discos SSD, empaquetado eficiente de ficheros pequeños y un largo etcétera de funciones que sigue creciendo durante su desarrollo.

Para lograr estas características es necesario fusionar en Btrfs funciones que antes formaban parte del sistema de archivos, el controlador RAID y el gestor lógico de volúmenes LVM. Gracias a que Btrfs gestiona de manera integrada el almacenamiento, es posible por ejemplo, ofrecer redundancia a nivel de objeto en el sistema de ficheros.

Creación de un sistema de archivos Btrfs y soporte multidispositivo

Puede crearse un sistema de archivos Btrfs sobre un disco o partición de manera análoga a como se hace con cualquier otro sistema de ficheros:

root@ubuntu:~# mkfs.btrfs /dev/sdb

WARNING! - Btrfs Btrfs v0.19 IS EXPERIMENTAL
WARNING! - see http://btrfs.wiki.kernel.org before using

fs created label (null) on /dev/sdb
	nodesize 4096 leafsize 4096 sectorsize 4096 size 8.00GB
Btrfs Btrfs v0.19
root@ubuntu:~#

Pero con Btrfs también se puede crear un sistema de ficheros sobre múltiples dispositivos, cuando se hace esto se forma un pool de almacenamiento con la capacidad agregada.

root@ubuntu:~# mkfs.btrfs /dev/sdc /dev/sdd 

WARNING! - Btrfs Btrfs v0.19 IS EXPERIMENTAL
WARNING! - see http://btrfs.wiki.kernel.org before using

adding device /dev/sdd id 2
fs created label (null) on /dev/sdc
	nodesize 4096 leafsize 4096 sectorsize 4096 size 16.00GB
Btrfs Btrfs v0.19
root@ubuntu:~#

Como en el ejemplo se han utilizado discos de 8GiB, en el primer caso se ha creado un sistema de ficheros de 8GiB y en el segundo uno de 16GiB. Cuando se monta un sistema de archivos que utiliza varios dispositivos basta con indicar en el comando mount cualquiera de estos dispositivos. En el ejemplo se podría montar el sistema de archivos de 16GiB indicando sdc o sdd. Por supuesto los dispositivos pueden ser de diferente tamaño y/o tipo.

Las configuraciones de almacenamiento multidispositivo, como RAID, tradicionalmente se han utilizado para aportar tolerancia a fallos. Al utilizar Btrfs puede conseguirse la función equivalente al indicar que los datos/metadatos del sistema de ficheros deben guardarse con redundancia en diferentes dispositivos. Esto se puede hacer durante la creación del sistema de ficheros al utilizar las opciones -d, y -m, para especificar el perfil de redundancia para los datos y metadatos. Los valores posibles son: raid0, raid1, raid10, raid5, raid6 y single. Aunque el soporte para los niveles raid5 y raid6 se ha añadido recientemente y puede que todavía sufra algún bug importante (ver: RAID56 y Using Btrfs with multiple devices).

Así para crear el sistema de archivos de 16GiB con tolerancia a fallos se puede hacer:

root@ubuntu:/mnt# mkfs.btrfs -d raid1 -m raid1 /dev/sdc /dev/sdd 

WARNING! - Btrfs Btrfs v0.19 IS EXPERIMENTAL
WARNING! - see http://btrfs.wiki.kernel.org before using

adding device /dev/sdd id 2
fs created label (null) on /dev/sdc
	nodesize 4096 leafsize 4096 sectorsize 4096 size 16.00GB
Btrfs Btrfs v0.19
root@ubuntu:/mnt#

Hay que notar que esta configuración toma el nombre del nivel RAID equivalente por inspiración, no porque se trate de una configuración idéntica. En un nivel RAID 1 cada disco es un espejo de los otros. En Btrfs utilizar un nivel RAID 1 para los datos o metadatos únicamente indica que los bloques se deben copiar en dos dispositivos diferentes pero ningún disco es una réplica bloque a bloque del resto y además se pueden utilizar discos de diferente tamaño. Si se realiza un RAID 1 tradicional con cuatro discos tendríamos cuatro réplicas, al utilizar el nivel RAID 1 en Btrfs se aseguraría que cada bloque estaría duplicado en dos discos diferentes pero no habría cuatro réplicas.

Gestión del pool de dispositivos, agregando y eliminando discos de forma dinámica.

Un sistema de ficheros Btrfs que utiliza varios dispositivos cuenta con un pool de capacidad agregada. Con el sistema de archivos montado es posible aumentar y disminuir dicho pool al añadir o eliminar discos. Claro está que solo se podrán eliminar discos cuando la capacidad resultante sea suficiente para mantener los datos escritos, incluyendo las condiciones impuestas por el nivel raid utilizado. Es decir, antes de eliminar un disco puede ser necesario añadir otro al que se migrará la información del disco a eliminar.

Con el sistema de archivos montado podemos agregar un disco:

root@ubuntu:/mnt# btrfs device add /dev/sdb /mnt/btrfs2/

y después eliminar uno de los discos originales. Antes y después de la eliminación utilizaré el comando btrfs filesystem show para comprobar el uso de los discos:

root@ubuntu:/mnt# btrfs filesystem show
failed to read /dev/sr0
Label: none  uuid: 8132fbeb-3837-4682-80e1-96ef29ba3208
	Total devices 1 FS bytes used 770.20MB
	devid    1 size 7.44GB used 2.27GB path /dev/sda2

Label: none  uuid: 8e6b5cbd-6ce6-4e09-9f71-12c0db19ac0b
	Total devices 3 FS bytes used 1.00GB
	devid    3 size 8.00GB used 0.00 path /dev/sdb
	devid    1 size 8.00GB used 3.03GB path /dev/sdc
	devid    2 size 8.00GB used 3.01GB path /dev/sdd

Btrfs Btrfs v0.19
root@ubuntu:/mnt# btrfs device delete /dev/sdc /mnt/btrfs2
root@ubuntu:/mnt# btrfs filesystem show
failed to read /dev/sr0
Label: none  uuid: 8132fbeb-3837-4682-80e1-96ef29ba3208
	Total devices 1 FS bytes used 770.20MB
	devid    1 size 7.44GB used 2.27GB path /dev/sda2

Label: none  uuid: 8e6b5cbd-6ce6-4e09-9f71-12c0db19ac0b
	Total devices 3 FS bytes used 1.00GB
	devid    3 size 8.00GB used 2.26GB path /dev/sdb
	devid    2 size 8.00GB used 2.26GB path /dev/sdd
	*** Some devices missing

Btrfs Btrfs v0.19
root@ubuntu:/mnt#

Cuando se agregan nuevos discos a un sistema de archivos, puede desearse distribuir los datos que ya estaban escritos en los antiguos componentes del sistema de ficheros entre todos los discos disponibles. A esta operación se la llama balanceo y puede dispararse mediante el comando btrfs filesystem balance.

En el siguiente ejemplo se vuelve a añadir el dispositivo /dev/sdc al pool y después se balancea la información entre los tres discos:

root@ubuntu:/mnt/btrfs2# btrfs filesystem show
failed to read /dev/sr0
Label: none  uuid: 8132fbeb-3837-4682-80e1-96ef29ba3208
	Total devices 1 FS bytes used 770.25MB
	devid    1 size 7.44GB used 2.27GB path /dev/sda2

Label: none  uuid: 8e6b5cbd-6ce6-4e09-9f71-12c0db19ac0b
	Total devices 3 FS bytes used 1.00GB
	devid    3 size 8.00GB used 2.26GB path /dev/sdb
	devid    4 size 8.00GB used 0.00 path /dev/sdc
	devid    2 size 8.00GB used 2.26GB path /dev/sdd

Btrfs Btrfs v0.19
root@ubuntu:/mnt/btrfs2# btrfs filesystem balance /mnt/btrfs2
root@ubuntu:/mnt/btrfs2# btrfs filesystem show
failed to read /dev/sr0
Label: none  uuid: 8132fbeb-3837-4682-80e1-96ef29ba3208
	Total devices 1 FS bytes used 770.25MB
	devid    1 size 7.44GB used 2.27GB path /dev/sda2

Label: none  uuid: 8e6b5cbd-6ce6-4e09-9f71-12c0db19ac0b
	Total devices 3 FS bytes used 1.00GB
	devid    3 size 8.00GB used 2.25GB path /dev/sdb
	devid    4 size 8.00GB used 2.26GB path /dev/sdc
	devid    2 size 8.00GB used 2.01GB path /dev/sdd

Btrfs Btrfs v0.19
root@ubuntu:/mnt/btrfs2#

Cambiando el modo RAID de un sistema de archivos

La mayor flexibilidad se consigue al indicar las opciones RAID en el momento de crear el sistema de archivos. Pero una vez creado, también esposible cambiar la configuración.

Por ejemplo, si se tiene un sistema operativo instalado sobre un sistema de ficheros Btrfs en un único disco.

root@Lunojod:~# btrfs filesystem show
Label: none uuid: 61df2f59-add0-4bd3-838e-08e59adff5dc
Total devices 1 FS bytes used 1.06GiB
devid 1 size 8.00GiB used 2.46GiB path /dev/sda1

Btrfs v3.12
root@Lunojod:~#

Y se desea pasar a una configuración con redundancia, es posible:

  1. Añadir un nuevo dispositivo al sistema de ficheros
  2. Lanzar una operación de balanceo del sistema de ficheros que convierta el modo de almacenamiento a al RAID deseado

Suponiendo que hemos añadido el disco sdb, y en él hemos creado la partición sdb1. Podemos hacer:

root@Lunojod:~# btrfs device add /dev/sdb1 /
root@Lunojod:~# btrfs balance start -dconvert=raid1 -mconvert=raid1 /
Done, had to relocate 7 out of 7 chunks

Esta operación tardará más o menos en función de los datos a balancear, pero no ha sido necesario desmontar el sistema de archivos y en todo momento sus ficheros han estado disponibles.

Al terminar el sistema de ficheros tendrá la nueva configuración.

root@Lunojod:~# btrfs filesystem show
Label: none uuid: 61df2f59-add0-4bd3-838e-08e59adff5dc
Total devices 2 FS bytes used 1.06GiB
devid 1 size 8.00GiB used 3.28GiB path /dev/sda1
devid 2 size 8.00GiB used 3.28GiB path /dev/sdb1

Btrfs v3.12
root@Lunojod:~#
root@Lunojod:~# btrfs filesystem df /
Data, RAID1: total=3.00GiB, used=1013.02MiB
System, RAID1: total=32.00MiB, used=16.00KiB
Metadata, RAID1: total=256.00MiB, used=75.48MiB
root@Lunojod:~#

Montar el sistema de archivos en modo degradado y reparar el raid

Un RAID con tolerancia a fallos en el que se ha producido la avería de un disco se encuentra en modo degradado. Cuando se utiliza Btrfs en modo raid1 y falla uno de los discos, solo se podrá montar el sistema de archivos al utilizar la opción -o degraded.

Si construimos un sistema de ficheros Btrfs con nivel raid1 para datos y metadatos utilizando los discos /dev/sdb y /dev/sdc. Podemos montarlo y escribir algunos datos en su interior.

root@ubuntu:~# mkfs.btrfs -m raid1 -d raid1 /dev/sdb /dev/sdc

WARNING! - Btrfs Btrfs v0.19 IS EXPERIMENTAL
WARNING! - see http://btrfs.wiki.kernel.org before using

adding device /dev/sdc id 2
fs created label (null) on /dev/sdb
	nodesize 4096 leafsize 4096 sectorsize 4096 size 16.00GB
Btrfs Btrfs v0.19
root@ubuntu:~# mount /dev/sdb /mnt/btrfs1
root@ubuntu:~# cp /etc/passwd /mnt/btrfs1
root@ubuntu:~#

Ahora podemos poner a prueba la integridad de Btrfs sobreescribiendo /dev/sdb y comprobar la integridad de nuestro fichero después de la catástrofe:

root@ubuntu:~# dd if=/dev/zero of=/dev/sdb
dd: escribiendo en «/dev/sdb»: No queda espacio en el dispositivo
16777217+0 registros leídos
16777216+0 registros escritos
8589934592 bytes (8,6 GB) copiados, 1952,08 s, 4,4 MB/s
root@ubuntu:~# diff /etc/passwd /mnt/btrfs1/passwd 
root@ubuntu:~# sha256sum /etc/passwd
73086c4039f1de315b431f6c7b95ef564a15b55f7339dd2f0f3201a13f0c2d8e  /etc/passwd
root@ubuntu:~# sha256sum /mnt/btrfs1/passwd 
73086c4039f1de315b431f6c7b95ef564a15b55f7339dd2f0f3201a13f0c2d8e  /mnt/btrfs1/passwd
root@ubuntu:~# 

El sistema de archivos sigue preservando el fichero aunque evidentemente el disco /dev/sdb ha perdido su contenido

En un sistema de archivos Btrfs con tolerancia en el que falla un disco, se debe: agregar un nuevo disco, eliminar del pool el disco 'missing' (nombre especial que representa al disco fallido) y después rebalancear el sistema de archivos para volver a replicar la información. Mientras el sistema de archivos esté degradado únicamente se podrá montar mediante la opción -o degraded.

Checksums y scrub

La redundancia permite proteger la información frente a la avería de un disco completo y también de los errores puntuales que se puedan producir en un bloque. Cada bloque, de datos o metadatos, está protegido mediante una suma de verificación CRC32C (en el futuro está planeado añadir otros algoritmos). En cada lectura se comprueba la integridad del bloque y si se detecta un error automáticamente se busca una copia alternativa. Este mecanismo protege la corrupción de bloques particulares.

La operación scrub, también disponible en ZFS, comprueba la integridad de todos los bloques de un sistema de archivos. Esta operación se realiza en segundo plano mientras el sistema de archivos está montado, aunque lógicamente conviene planificarla en los momentos de mínima carga. Puesto que Btrfs accede a las copias de los bloques de un modo determinista, si de un bloque tenemos la copia A y B, siempre se leerá la copia A y si no se detecta corrupción se ignorará la copia B. Esto nos lleva a que durante el funcionamiento normal, si la primera copia de un bloque conserva su integridad nunca se accederá (y por tanto comprobará) la integridad de la segunda copia. Cuando se realiza un scrub se detectan y corrige cualquier bloque corrupto (siempre que no se hayan perdido todas las copias del mismo, en cualquier caso se advertirá el error).

Puede lanzarse una operación scrub de la siguiente manera:

btrfs scrub start <punto de montaje>

Y obtener información sobre su estado:

btrfs scrub status <punto de montaje>

La operación scrub no está disponible en la versión de las herramientas que se instalan por defecto en Ubuntu 12.04 LTS, pues se incluye una versión muy antigua del paquete btrfs-progs. Sin embargo es posible descargar e instalar el paquete btrfs-tools de Debian (http://packages.debian.org/wheezy/btrfs-tools) que sí proporciona soporte.

Compresión transparente

Otra de las características que soporta Btrfs es la compresión transparente, cuando se monta un sistema de archivos con la opción -o compress se activa de forma automática la compresión. Con la compresión activa los bloques se comprimen antes de escribirse y se descomprimen de manera automática en las lecturas, de este modo las aplicaciones símplemente se dedican a escribir/leer en el sistema de archivos pero se ahorra espacio en disco.

Aunque la información en disco esté comprimida, cuando se realiza un listado del tamaño de los ficheros las cifras no varían. Para cada fichero se muestra el número de bytes que contiene, independientemente de que en disco estén comprimidos o no, pero al mostrar la cantidad de espacio consumida en disco (con df) se puede apreciar que hay menos espacio consumido del que debería si no se utilizase la compresión.

Activar la compresión supone ahorrar espacio a costa de aumentar el uso de CPU, pues hay más trabajo que hacer. Pero dependiendo del uso del sistema de archivos puede ofrecer un notable aumento de velocidad. Ya que al reducirse el tamaño de los datos en disco se precisan menos operaciones de disco que son mucho más lentas que la CPU.

Inicialmente Btrfs únicamente soportaba la compresión ofrecida por Gzip pero actualmente también soporta el algoritmo LZO que ofrece una mayor velocidad a costa de un menor ratio. Esta última es la opción por defecto en la actualidad, aunque puede escogerse el algoritmo a utilizar en el momento del montado (-o compress, -o compress=lzo, -o compress=zlib). Además se está implementando soporte para Snappy que todavía ofrece mayor velocidad.

En un mismo sistema de ficheros, o subvolumen, pueden coexistir datos comprimidos y sin comprimir (o bien comprimidos por diferentes algoritmos).

COW: Copy on write

Btrfs hace un uso integral de COW. Esta técnica es una optimización que permite almacenar una sola vez copias de datos indistinguibles. Es en el momento en el que una de estas copias se modifica en el que se realiza físicamente la copia. Así, aquellas copias que no llegan a modificarse nunca no existen más que en apariencia y remiten a los datos originales.

Esta idea, junto a la idea de que los bloques de Btrfs no se sobreescriben (como ocurre habitualmente en los sistemas de archivos tradicionales) sino que cuando se modifican se escriben en un nuevo lugar. Permite clonar la información de manera eficiente a diferentes niveles:

  1. A nivel de fichero o incluso parte de fichero (bloque)
  2. A nivel de subvolumen manejando instantáneas

La herramienta cp ahora cuenta con la opción --reflink=always que permite realizar un clon de un fichero. Es decir, una copia aparente basada en COW. La copia se realiza de manera instantánea, no consume espacio y es en el momento de actualizar los datos cuando se busca una nueva ubicación para los bloques modificados.

En el siguiente ejemplo puede comprobarse que al copiar un fichero no aumenta el espacio consumido. Las copias son extremadamente rápidas, y solo en el momento en el que se modifica algún bloque de cualquiera de los ficheros deberá reservarse espacio para dicho bloque.

root@ubuntu:/mnt/btrfs1# ll
total 689456
dr-xr-xr-x 1 root    root           56 may 23 11:59 ./
drwxr-xr-x 1 root    root           50 may 17 11:21 ../
-rw-rw-r-- 1 usuario usuario 705998848 may 23 12:01 ubuntu-12.04-server-i386.iso
root@ubuntu:/mnt/btrfs1# df -h
S.ficheros     Tamaño Usado  Disp Uso% Montado en
/dev/sda2        7,5G  816M  6,0G  12% /
udev             494M  4,0K  494M   1% /dev
tmpfs            201M  288K  200M   1% /run
none             5,0M     0  5,0M   0% /run/lock
none             501M     0  501M   0% /run/shm
/dev/sda2        7,5G  816M  6,0G  12% /home
/dev/sdb          16G  676M   15G   5% /mnt/btrfs1
root@ubuntu:/mnt/btrfs1# time cp --reflink=always ubuntu-12.04-server-i386.iso copia1-ubuntu.iso

real	0m0.085s
user	0m0.000s
sys	0m0.056s
root@ubuntu:/mnt/btrfs1# cp --reflink=always ubuntu-12.04-server-i386.iso copia2-ubuntu.iso
root@ubuntu:/mnt/btrfs1# cp --reflink=always ubuntu-12.04-server-i386.iso copia3-ubuntu.iso
root@ubuntu:/mnt/btrfs1# cp --reflink=always ubuntu-12.04-server-i386.iso copia4-ubuntu.iso
root@ubuntu:/mnt/btrfs1# cp --reflink=always ubuntu-12.04-server-i386.iso copia5-ubuntu.iso
root@ubuntu:/mnt/btrfs1# ll
total 4136716
dr-xr-xr-x 1 root    root          226 may 23 12:04 ./
drwxr-xr-x 1 root    root           50 may 17 11:21 ../
-rw-r--r-- 1 root    root    705998848 may 23 12:03 copia1-ubuntu.iso
-rw-r--r-- 1 root    root    705998848 may 23 12:04 copia2-ubuntu.iso
-rw-r--r-- 1 root    root    705998848 may 23 12:04 copia3-ubuntu.iso
-rw-r--r-- 1 root    root    705998848 may 23 12:04 copia4-ubuntu.iso
-rw-r--r-- 1 root    root    705998848 may 23 12:04 copia5-ubuntu.iso
-rw-rw-r-- 1 usuario usuario 705998848 may 23 12:01 ubuntu-12.04-server-i386.iso
root@ubuntu:/mnt/btrfs1# df -h
S.ficheros     Tamaño Usado  Disp Uso% Montado en
/dev/sda2        7,5G  816M  6,0G  12% /
udev             494M  4,0K  494M   1% /dev
tmpfs            201M  288K  200M   1% /run
none             5,0M     0  5,0M   0% /run/lock
none             501M     0  501M   0% /run/shm
/dev/sda2        7,5G  816M  6,0G  12% /home
/dev/sdb          16G  676M   15G   5% /mnt/btrfs1
root@ubuntu:/mnt/btrfs1#

Solo esta característica ya es extremadamente valiosa en muchos casos. Por ejemplo nosotros la utilizamos en una solución SAN en la que los ordenadores del aula arrancan mediante discos iSCSI. En el servidor existe un directorio con los ficheros master de los sistemas exportados, y estas imágenes son clonadas para que cada alumno cuente con su propio disco duro.

La otra manera de utilizar el COW consiste en realizar instantáneas del sistema de archivos, en concreto de lo que en Btrfs se denomina subvolumen. Una instantánea, snapshot, es una 'fotografía' de un determinado estado del sistema de archivos. Puede servir para realizar copias de seguridad o pruebas, tomarla no lleva tiempo ni consume espacio. Únicamente en la medida en la que se modifica la instantánea, o el subvolumen del que fue tomada, se aumenta el consumo de espacio.

Subvolúmenes e instantáneas

En Btrfs un subvolumen es equivalente a un sistema de ficheros contenido en el anfitrión. Un sistema de ficheros Btrfs tiene como mínimo un subvolumen pero pueden crearse otros. Cuando se monta un sistema de archivos se monta el subvolumen por defecto que inicialmente es el único que existe. Pero es posible montar un subvolumen concreto al especificar las opciones de montado subvolid= o subvol=. También es posible cambiar el subvolumen por defecto de un sistema de archivos, si después se pretende montar el subvolumen raíz se deberá utilizar la opción de montado subvolid=0.

Con la implementación actual los subvolúmenes comparten configuración raid con el sistema de archivos en el que existen, pero está pensado que en el futuro se pueda configurar la redundancia de manera independiente a nivel de subvolumen.

Desde el punto de vista del sistema de archivos que los contiene los subvolúmenes aparecen como directorios.

Podemos crear un sistema de archivos Btrfs sobre /dev/sdb, /dev/sdc, /dev/sdd y montarlo:

root@ubuntu:/mnt# mkfs.btrfs /dev/sdb /dev/sdc /dev/sdd

WARNING! - Btrfs Btrfs v0.19 IS EXPERIMENTAL
WARNING! - see http://btrfs.wiki.kernel.org before using

adding device /dev/sdc id 2
adding device /dev/sdd id 3
fs created label (null) on /dev/sdb
	nodesize 4096 leafsize 4096 sectorsize 4096 size 24.00GB
Btrfs Btrfs v0.19
root@ubuntu:/mnt# mount /dev/sdb /mnt/btrfs1
root@ubuntu:/mnt#

Una vez montado es posible definir tres subvolúmenes: subvolumen1, subvolumen2 y subvolumen3

root@ubuntu:/mnt# btrfs subvolume create /mnt/btrfs1/subvolumen1
Create subvolume '/mnt/btrfs1/subvolumen1'
root@ubuntu:/mnt# btrfs subvolume create /mnt/btrfs1/subvolumen2
Create subvolume '/mnt/btrfs1/subvolumen2'
root@ubuntu:/mnt# btrfs subvolume create /mnt/btrfs1/subvolumen3
Create subvolume '/mnt/btrfs1/subvolumen3'
root@ubuntu:/mnt#

Estos subvolúmenes se ven como directorios en el interior de /mnt/btrfs1:

root@ubuntu:/mnt# ls /mnt/btrfs1
subvolumen1  subvolumen2  subvolumen3
root@ubuntu:/mnt#

La herramienta btrfs permite listar subvolúmenes (no se muestra el subvolumen por defecto):

root@ubuntu:/mnt# btrfs subvolume list /mnt/btrfs1
ID 256 top level 5 path subvolumen1
ID 257 top level 5 path subvolumen2
ID 258 top level 5 path subvolumen3
root@ubuntu:/mnt#

Si se escribe algún fichero en, por ejemplo, subvolumen1 se puede comprobar que al montar dicho subvolumen en otro punto de montaje únicamente se ve su contenido:

root@ubuntu:/mnt# cp /etc/passwd /mnt/btrfs1/subvolumen1
root@ubuntu:/mnt# mkdir /mnt/subvolumen1
root@ubuntu:/mnt# mount -o subvolid=256 /dev/sdb /mnt/subvolumen1/
root@ubuntu:/mnt# ls /mnt/subvolumen1/
passwd
root@ubuntu:/mnt#

Evidentemente los subvolúmenes cuentan con la capacidad del pool al que pertenecen:

root@ubuntu:~# df -h
S.ficheros     Tamaño Usado  Disp Uso% Montado en
/dev/sda2        7,5G  817M  6,0G  12% /
udev             494M  4,0K  494M   1% /dev
tmpfs            201M  288K  200M   1% /run
none             5,0M     0  5,0M   0% /run/lock
none             501M     0  501M   0% /run/shm
/dev/sda2        7,5G  817M  6,0G  12% /home
/dev/sdb 24G 80K 21G 1% /mnt/btrfs1 /dev/sdb 24G 80K 21G 1% /mnt/subvolumen1
root@ubuntu:~#

En este caso los datos del subvolumen subvolumen1 son accesibles a través de dos sitios:

  • /mnt/btrfs1/subvolumen1
  • /mnt/subvolumen1

No se ha hecho ningún clon COW del fichero passwd copiado. Símplemente tenemos montados dos subvolúmenes (el padre y el hijo) en dos puntos diferentes, y por tanto los cambios realizados en /mnt/btrfs1/subvolumen1/passwd son visibles en /mnt/subvolumen1/passwd y viceversa.

Las instantáneas son clones COW de un subvolumen completo, por lo tanto se ven como un nuevo subvolumen que inicialmente contiene los datos del subvolumen clonado pero a partir de ahora los cambios en uno no afectan al otro. Por supuesto el espacio consumido irá aumentando en la medida en la que el subvolumen 'original' y la 'instantánea' se distancien.

Puede crearse una instantánea del subvolumen subvolumen1 tal que así:

root@ubuntu:/mnt# btrfs subvolume snapshot /mnt/btrfs1/subvolumen1 /mnt/btrfs1/subvolumen1_snapshot
Create a snapshot of '/mnt/btrfs1/subvolumen1' in '/mnt/btrfs1/subvolumen1_snapshot'
root@ubuntu:/mnt#

Una vez creada la instantánea es un nuevo subvolumen de pleno derecho, por eso me refería anteriormente al subvolumen original y la instantánea entrecomillando los términos:

root@ubuntu:/mnt# btrfs subvolume list /mnt/btrfs1
ID 256 top level 5 path subvolumen1
ID 257 top level 5 path subvolumen2
ID 258 top level 5 path subvolumen3
ID 259 top level 5 path subvolumen1_snapshot
root@ubuntu:/mnt#

En este caso si se monta subvolumen1_snapshot (id 259) en algún lugar se verá que contiene el fichero passwd que contenía el subvolumen 256, y gracias al COW cada subvolumen podrá modificarse de manera independiente sin que los cambios de uno afecten al otro.

Las diferencias frente a LVM son notables:

  • Un subvolumen tiene la capacidad del sistema de ficheros al que pertenece. En LVM un volumen lógico tiene una capacidad determinada que es una reserva de espacio del grupo de volúmenes al que pertenece.
  • Una instantánea es un subvolumen de pleno derecho, una vez creada no hay 'original' e 'instantánea'. En LVM una instantánea depende del volumen lógico del que fue creada. Por ejemplo no es posible cambiar el tamaño de un volumen lógico, o mover sus datos con pvmove, mientras tengamos instantáneas activas de dicho volumen lógico. Una instantánea parece un volumen lógico convencional pero tiene sus particularidades, por ejemplo el espacio reservado para las diferencias con el original.

 

La cuestión del espacio consumido/disponible en Btrfs

Como se ha podido ver Btrfs es un sistema de archivos con diferencias notables frente a lo convencional. Esto lleva a que unas cuestiones tradicionalmente tan sencillas de resolver como: ¿cuánto espacio he consumido en el sistema de archivos?, ¿cuánto espacio queda disponible?, ¿cuánto espacio gano si borro esto?. En Btrfs sean una cuestión muy espinosa o directamente y dicho de manera coloquial, un sindiós.

La replicación a nivel de objeto del sistema de archivos (con las configuración raid0, raid1, raid10 y otras que serán implementadas pronto seleccionables de manera independiente para datos/metadatos y en el futuro configurables por subvolumen), el uso intensivo de COW y la compresión (con diferentes objetos por subvolumen que pueden estar comprimidos o no y con diferentes algoritmos) rompe con lo establecido y hace imposible asumir que el espacio consumido es la suma de lo indicado por ls, o peor todavía ni siquiera por du ni por df.

Solo para ilustrar parte del problema piense en un espejo tradicional (RAID1) con dos discos de 1TiB. Puesto que todo se graba de manera duplicada en ambos discos al escribir 1TiB se habrá llenado el espejo. Así, el dispositivo resultante (digamos md0) se ve como un disco de 1TiB. Todo claro.

¿Qué ocurre en Btrfs? pues que para empezar, por cuestiones de seguridad, cuando no se indica una configuración para los metadatos al crear el sistema de archivos (con la opción -m) por defecto se aplica una configuración raid1. Aunque solo se utilice un disco cada bloque de metadatos tendrá dos copias, pero los bloques de datos solo una. Si se utilizan varios discos el pool muestra la capacidad agregada pero depende de las opciones -m y -d que se utilicen los bloques de datos/metadatos tendrán una o dos copias. Y está pensado que para cada subvolumen, del mismo sistema de archivos, se pueda escoger una opción -m/-d diferente. Así que resulta totalmente inviable mostrar la capacidad 'efectiva' del pool como se hace en el caso del RAID 1 tradicional.

Otra cuestión es el uso del COW. Cuanto ocupa un clon de un fichero? inicialmente nada, pero se ve como un fichero de terminado tamaño. Y en la medida en la que se vayan modificando bloques será necesario reservar bloques nuevos. ¿Cuánto gano al borrar un fichero que inicialmente era un clon y luego fué modificado? pues vaya usted a saber... ¿hay otros ficheros que compartan bloques?. Lo mismo con las instantáneas de subvolúmenes.

Por todo esto existe la opción btrfs filesystem df <path> para mostrar información sobre el uso de espacio en el sistema de archivos:

root@ubuntu:/mnt# btrfs filesystem df /mnt/btrfs1/
Data, RAID0: total=2.40GB, used=0.00
Data: total=8.00MB, used=0.00
System, RAID1: total=8.00MB, used=4.00KB
System: total=4.00MB, used=0.00
Metadata, RAID1: total=1.00GB, used=40.00KB
Metadata: total=8.00MB, used=0.00
root@ubuntu:/mnt#

Y btrfs filesystem show <device> para obtener información sobre el consumo en crudo de los diferentes dispositivos que forman el pool de almacenamiento:

root@ubuntu:~# btrfs filesystem show /dev/sdb
failed to read /dev/sr0
Label: none  uuid: 91809f86-7cc8-44c1-be19-d98ea80f63ff
	Total devices 3 FS bytes used 44.00KB
	devid    1 size 8.00GB used 1.82GB path /dev/sdb
	devid    2 size 8.00GB used 827.19MB path /dev/sdc
	devid    3 size 8.00GB used 1.81GB path /dev/sdd

Btrfs Btrfs v0.19
root@ubuntu:~#

La reserva de espacio en los dispositivos se realiza en grandes asignaciones (1GB para datos y 256MB para metadatos) y dependiendo de la configuración de redundancia utilizada. Por ejemplo con raid0 solo se reservará una rodaja en un dispositivo mientras que con raid1 se reservarían dos iguales en diferentes dispositivos. En el interior de la rodaja se ocupa espacio de la manera esperada, 1 MiB escrito consume 1 MiB. Cuando se acaba la rodaja se reserva otra.

Btrfs no está pensado para sistemas de archivos pequeños, no se recomienda su uso en sistemas de archivos menores de 16GiB.

Más información:

  1. Btrfs wiki
  2. Video del autor de Btrfs, Chris Mason: Btrfs filesystem, status and new features (2012)
  3. Video de Avi Miller: I Can't Believe This is Butter! A tour on btrfs (2012)
  4. Phoronix: Btrfs LZO Compression Performance
  5. Phoronix: Using Disk Compression With Btrfs To Enhance Performance (GZIP)
  6. Phoronix: Btrfs Picks Up Snappy Compression Support
  7. Btrfs FAQ: Why does df show incorrect free space for my RAID volume?
    Aaargh! My filesystem is full, and I've put almost nothing into it!
    Why are there so many ways to check the amount of free space?
  8. Btrfs FAQ: How much space do I get with unequal devices in RAID-1 mode?
  9. Oracle: How I Use the Advanced Capabilities of Btrfs
  10. Btrfs quota support