14 de junio de 2016

Apple ya tiene su ZFS: APFS

ZFS fue una revolución en el mundo de los sistemas operativos de propósito general, hasta el punto que se puede afirmar tajantemente que el sistema operativo que no tenga un sistema de archivos inspirado en él, está obsoleto. En Apple no son tontos y en seguida se interesaron al menos en facilitar el uso de ZFS, pero acabaron abandonando la idea por problemas de licencia. Aun así, surgieron rumores de que Apple estaba desarrollando un sustituto de HFS+, sin que llegaran nunca a nada.

Hoy, en su conferencia para desarrolladores, Apple ha anunciado su nuevo sistema de archivos APFS. No se han dado muchos detalles, pero no se diferencia en nada de lo que se podría esperar de un clon de ZFS. Habrá que esperar hasta el año que viene para que den más detalles y publiquen el código fuente: APFS está tan verde, que ni tan siquiera garantizan la estabilidad del formato de disco.

Sorprende que Apple, con sus inacabables recursos monetarios, se haya tomado tanto tiempo en crear un clon de ZFS: todos sus sistemas usan aun HFS+ (prueba de que, como se ha sugerido en el pasado en este blog, una implementación rápida y estable de un sistema de archivos es mucho más importante en la práctica que las campanitas y luces de colores de un formato de disco nuevo). Un servidor esperaba a APFS años mucho antes; hace cuatro años predecía, erróneamente, que veríamos un ZFS de Apple antes de ver ReFS -el ZFS de Microsoft, recuerden- en los Windows de escritorio.

Pero sobre todo, lo que esperaba de Apple es que se atreviese a ir más allá de los sistemas de archivo jerárquicos. Tras haber contratado al desarrollador del sistema de archivos de BeOS, uno se esperaba que se atreverían a copiar su implementación de atributos extendidos, pero no parece haber ninguna innovación en ese frente. No pierdo la esperanza de que lo tengan reservado para el futuro.

2 de junio de 2016

Las novedades de Linux 4.3

(Tras un larguísimo retraso, esta es la lista de cambios de Linux 4.3)

Ya se ha anunciado la versión 4.6 de Linux. Esta versión elimina el sistema de archivos Ext3 (a partir de ahora los sistemas de archivo Ext3 se tendrán que montar con Ext4, que siempre los ha soportado). También añade la llamada al sistema userfaultfd() para gestionar fallos de páginas desde espacio de usuario; la llamada al sistema membarrier() para enviar barreras de memoria a un conjunto de hilos; un controlador de PIDs para limitar el número de PIDs que puede haber en un cgroup; "ambient" capabilities para hacer el sistema de capabilities menos difícil de usar; un sistema para conseguir mejores estadísticas sobre la memoria que está siendo utilizada por un proceso; soporte para Identifier Locator Addressing de IPv6, que permite implementar túneles o virtualización de redes sin encapsulación; soporte para Virtual Routing and Forwarding Lite, túneles de red ligeros, y muchas otras mejoras y nuevos controladores. La lista completa de cambios, en inglés, puede encontrarse aquí, como siempre.


· Eliminación del sistema de archivos Ext3
Se ha eliminado el sistema de archivos Ext3. La motivación es que los sistemas de archivo Ext3 siempre han estado soportados por Ext4, que de hecho Ext4 se creó pensando en sustituir Ext3, y que las principales distribuciones llevan ya mucho tiempo utilizando Ext4 para montar sistemas de archivos Ext3. Ahora que Ext4 es bastante estable, los mantenedores creen adecuado librarse de él.

· userfaultfd(), una llamada al sistema para gestionar fallos de página en espacio de usuario

Un fallo de página es algo que ocurre cuando un proceso que tiene alguna cosa mapeada en su espacio de direcciones, por ejemplo, un archivo, pero ese archivo no está en la memoria RAM: al tratar de acceder al archivo, se produce un fallo de pagina. El kernel es quien, normalmente, se ocupa de gestionar ese fallo de página: carga la porción del archivo en memoria.


En esta versión, Linux añade soporte para gestionar fallos de página en espacio de usuario a través de una nueva llamada al sistema: userfaultfd(). La ventaja de esta llamada al sistema comparada con las operaciones de gestión de memoria habituales como mremap()/mprotect() es que es mucho más ligera.

El principal usuario de esta llamada al sistema es QEMU, que puede usar esta llamada al sistema para implementar migración en vivo post-copia: se migran las VMs de un host a otro sin migrar su memoria, lo cual hace que la migración sea mucho más rápida, y una vez migrada la VM, QEMU utiliza userfaultfd() para ir transfiriendo la memoria al nuevo host a medida que ocurren fallos de página.

· membarrier(), una llamada al sistema para enviar barreras de memoria a un conjunto de hilos 

Esta versión añade una nueva llamada al sistema, membarrier(2), que ayuda a distribuir los costes de las barreras de memoria en espacio de usuario utilizadas para ordenar los accesos a memoria en sistemas multicore, y lo logra transformando parejas de barreras de memoria en parejas consistentes en membarrier(2) y una barrera de compilador. Para las primitivas de sincronización que distinguen entre el lado de lectura y el de escritura (por ejemplo, RCU, read-write locks), el lado de la lectura puede acelerarse significativamente con esta llamada al sistema, ya que se mueve la sobrecarga de la barrera de memoria al lado de la escritura. La idea fundamental es hacer que las CPUs ejecuten las barreras solamente cuando se requiere sincronización por parte del hilo que modifica datos, a diferencia de ejecutar las barreras antes y después toda vez que se acceden los datos desde un hilo de lectura.

· Nuevo controlador de PIDs para limitar el número de PIDs en los cgroups.

Esta versión añade un controlador de PIDs que permite limitar el número de procesos que pueden crearse dentro de un cgroup. Los PIDs son un recurso fundamentalmente global, porque es bastante fácil acabar con todos los PIDs posibles antes de alcanzar otros límites de recursos. Como resultado, es posible paralizar el sistema. El controlador de PIDs está diseñado para prevenir estos abusos.


Esencialmente, se trata de una implementación del límite RLIMIT_NPROC, sólo que se aplica a un cgroup en lugar de a un árbol de procesos. Sin embargo, hay que notar que las operaciones de añadir PIDs a un cgroup manualmente no están afectadas por el límite, sólo están limitados los procesos creados a través de fork().

Para usar este controlador de PIDs, hay que configurar el número máximo de tareas en pid.max. El número de procesos disponibles en el cgroup es proporcionado por pids.current. Para que el cgroup no tenga límite de procesos, se puede configurar pid.max a "max".

· Ambient capabilities

En Linux, hay un número de capabilities ("capacidades") definidas por el kernel. Para ejecutar varias operaciones privilegiadas, los procesos pueden ejercer las capacidades que tengan asignadas. Cada proceso tiene cuatro máscaras de capacidades: "effective", "permitted", "inheritable", y "bounding set". Cuando el kernel comprueba la validez de las capacidades comprueba la máscara "effective", el resto de máscaras sirven para modificar las capacidades que pueden estar en "effective"

Debido a los defectos de diseño de las capacidades de Linux (artículo de LWN recomendado al respecto: Inheriting capabilities), la herencia de capacidades no es muy útil. Para resolver los problemas, esta versión añade una quinta máscara llamada máscara "ambient". Esta máscara hace lo que la mayor parte de la gente esperaría que hiciera la máscara "inheritable". No se puede cambiar ningún bit de capacidades en "ambient" si no está previamente en "inheritable" y "permitted". Eliminar un bit de "permitted" o "inheritable" elimina ese bit de "ambient". Esto asegura que los programas que quieran intentar desprenderse de capacidades pueden hacerlo, sin complicaciones. Como la herencia de capacidades en Linux actualmente es tan chapucera, configurar prctl(PR_SET_KEEPCAPS,...), usar setresuid() para cambiarse a una uid no-root, y después llamar a execve(), tiene como efecto que se desactivan las capabilities. Por lo tanto, setresuid() de root a no-root limpia la máscara "ambient" al menos que no esté activada SECBIT_NO_SETUID_FIXUP.

Si eres no-root pero tienes una capacidad, puedes añadirla a "ambient". Si lo haces, tus hijos también tendrán esa capacidad en "ambient", "permitted" y "effective". Por ejemplo, puedes configurar CAP_NET_BIND_SERVICE en "ambient", y tus hijos podrán, automáticamente, hacer bind() a puertos con números bajos. Los usuarios sin privilegios pueden crear espacios de nombres de usuario, mapearse ellos mismos a una uid no-cero, y crear árboles de procesos privilegiados y no privilegiados (relativos a su espacio de nombres).


· page tracking, una manera más precisa de medir la memoria utilizada por las aplicaciones
Saber qué páginas de memoria están siendo accedidas por una carga determinada y cuáles es útil para saber el tamaño de trabajo de la carga, lo cual es útil para configurar la aplicación, decidir en qué nodo debe ejecutarse, o configurar límites de memoria. Actualmente, la única manera de estimar la cantidad de memoria que no está siendo usada es /proc/PID/clear_refs y /proc/PID/smaps: el usuario puede eliminar el bit de acceso de todas las páginas de un determinado proceso escribiendo "1" al archivo clear_refs, esperar un tiempo, y contar la memoria que está siendo utilizada en la sección "Referenced" del archivo smaps. Sin embargo, este método tiene dos inconvenientes serios: 1) no puede contar las memoria de archivo que no está mapeada (ej, los archivos no mapeados, accedidos mediante read()/write()) 2) limpiar el bit de acceso de las páginas distorsiona la gestión de memoria.

Para resolver esos problemas, esta versión introduce una nueva manera de analizar el uso de memoria. Para estimar la cantidad de páginas que no están siendo usadas por una aplicación, se deben seguir los siguientes procesos:
  · Marcar todas las páginas de la tarea en cuestión, configurando los bits correspondientes en /mm/page_idle/bitmap (este archivo implementa un bitmap donde cada bit representa una página de memoria). Las páginas a ser marcadas pueden encontrase en /proc/PID/pagemap, si se trata de un proceso, o /proc/kpagecgroup (un nuevo archivo) si se trata de una carga ubicada en un cgroup.
  · Esperar a que la carga en cuestión haga su trabajo
  · Leer /sys/kernel/mm/page_idle/bitmap y contar el número de bits que han cambiado

· Soporte para IPv6 Identifier Locator Addressing

Esta versión añade soporte para Identifier Locator Addressing, un mecanismo diseñado para permitir la implementación de túneles o virtualización de redes sin encapsulación. El concepto básico de ILA es que una dirección IPv6 es dividida en dos partes de 64 bits: localizador e identificador. El identificador es la identidad de la entidad que se comunica ("quien"); el localizador expresa la localización de la entidad ("dónde"). Las aplicaciones usan direcciones visibles externamente que contienen el identificador. Cuando se envía un paquete, se hace una traducción que sobreescribe los primeros 64 bits de la dirección con el localizador. El paquete puede entonces ser redirigido por la red al host donde esté ubicada la entidad. El receptor hace la traducción inversa de manera que la aplicación vea la dirección original, sin traducir.

Esta característica se configura con el comando "ip -6 route", usando la opción "encap ila ", donde es el valor a configurar en el localizador de destino del paquete, ej. ip -6 route add 3333:0:0:1:5555:0:1:0/128 encap ila 2001:0:0:1 via 2401:db00:20:911a:face:0:25:0 configurará una ruta donde 333:0:0:1 será sobreescrito por 2001:0:0:1

· Túneles de red ligeros

Esta versión proporciona infraestructura para soportar túneles ligeros tales como túneles ip sobre MPLS. Permite una encapsulación escalable sin la sobrecarga de un netdevice completo. Para más información, leer este artículo de LWN Identifier locator addressing, o estas diapositivas netconf2015Herbert-ILA.pdf

iproute2 ha sido extendido con dos nuevos casos: VXLAN: ip route add 40.1.1.1/32 encap vxlan id 10 dst 50.1.1.2 dev vxlan0; MPLS: ip route add 10.1.1.0/30 encap mpls 200 via inet 10.1.1.1 dev swp1

·  Soporte de Virtual Routing and Forwarding (Lite)

 
Esta versión añade soporte de Virtual Routing and Forwarding (VRF), que, combinado con reglas ip, proporciona la abilidad de crear enrutados virtuales y dominios de reenvío (VRFs, o más bien VRF-lite para ser más específico). Para más información, leer la documentación en Documentation/networking/vrf.txt 


Estas son las novedades principales de este kernel. Como siempre, pueden encontrar la lista completa, y en inglés, en esta página.

16 de mayo de 2016

Las novedades de Linux 4.6

Ya se ha anunciado la versión 4.6 de Linux. Esta versión añade soporte para USB 3.1 SuperSpeedPlus (10 Gbps), un nuevo sistema de archivos distribuido OrangeFS, una implementación del "OOM killer" más fiable, soporte para una característica de CPUs Intel llamada "memory protection keys", un sistema para implementar más fácilmente protocolos de capa de aplicación (nivel 7 OSI), soporte para cifrado a nivel de MAC 802.1AE (conocido como MACsec), soporte para la versión V del protocolo BATMAN, un chequeador de inodos online en OCFS2, soporte de diferentes espacios de nombre en los cgroups, soporte del layout SCSI en pNFS, y muchas otras mejoras y nuevos controladores. La lista completa de cambios, en inglés, puede encontrarse aquí, como siempre.


· Soporte de USB 3.1 SuperSpeedPlus (10Gbps)
La especificación de USB 3.1 incluye un nuevo protocolo SuperSpeedPlus que soporta velocidades de hasta 10 Gbps. Los dispositivos que utilizan este nuevo protocolo son apodados como dispositivos USB 3.1 Gen2 (nótese que SuperSpeedPlus no es lo mismo que Type-C)

Esta versión añade soporte de la velocidad de 10 Gbps de USB 3.1 SuperSpeedPlus para el subsistema USB y el controlador host xHCI, lo cual significa que un dispositivo de almacenamiento USB 3.1 conectado a un host xHCI USB 3.1 debería poder alcanzar la velocidad de 10 Gbps.

· Mejora de la fiabilidad del asesino OOM

En anteriores versiones, el asesino OOM (que intenta matar un proceso cuando el sistema se queda sin memoria) intentaba matar un proceso con la esperanza de que acabase en un tiempo razonable y liberase su memoria. En la práctica, se ha demostrado que es fácil crear situaciones en las que esa asunción sea errónea, y el proceso elegido para ser eliminado tarde mucho tiempo porque ha sido bloqueado por otro proceso que está, a su vez, esperando a que se libere memoria. Esta versión añade un thread de kernel especializado, oom_reaper, que intenta liberar memoria librándose por adelantado de la memoria anónima o enviada al swap de la víctima, bajo la asunción de que esa memoria no será utilizada posteriormente.

· Soporte de Intel Memory Protection keys

Esta versión añade soporte para una característica de hardware para la protección de memoria, que estará disponible en futuras CPUs Intel: protection keys. Protection keys permite insertar en las entradas de la tabla de páginas una serie de máscaras de protección configurables. En lugar de tener en la tabla de páginas una protección fija para una página determinada (que requiere una llamada al sistema y debe cambiar los permisos una vez por cada página), el usuario puede definir unas pocas áreas de memoria. Luego, el espacio de usuario puede manipular un nuevo registro (PKRU, individual para cada proceso/thread) donde se pueden asignar a cada área de memoria dos bits separados: Desactivar Acceso y Desactivar Escritura. De ese modo, con la sola escritura en ese registro, se puede cambiar la protección de enormes porciones de memoria, sin tener que cambiar los permisos de cada una de las páginas.

También permite un control más preciso de los permisos de la MMU: Por ejemplo, el bit para desactivar la ejecución es distinto del bit para desactivar la lectura. Esta versión añade soporte para cambiar esos bits, y además añade una API para poder hacer uso de las protection keys. Si un programa en espacio de usuario hace la llamada mmap (..., PROT_EXEC) o mprotect(ptr, sz, PROT_EXEC), (nótese el PROT_EXEC sólo, sin PROT_READ/WRITE), el kernel notará este caso especial, y activará una protection key en este rango de memoria, y cambiará el contenido del registro PKRU. De ese modo, con las protection keys el kernel puede implementar un "verdadero" PROT_EXEC: código que puede ser ejecutado, pero no leído, lo cual es una pequeña ventaja de seguridad (pero téngase en cuenta que el código malicioso también puede manipular el registro PKRU). En el futuro, habrá mejoras en la implementación de esta caraterística y nuevas APIs de más alto nivel.

· OrangeFS, un nuevo sistema de archivos distribuido

OrangeFS es un sistema de almacenamiento paralelo, originalmente llamado PVFS y desarrollado en 1993 como parte de una beca de la NASA para estudiar los patrones de E/S de programas paralelos. Es ideal para solucionar los problemas de gran almacenamiento que se encuentran en entornos de HPC, BigData, Streaming de Video, Genómica, Bioinformática. OrangeFS puede ser accedido a través de utilidades del sistema, librerías, MPI-IO y puede ser utilizado por el ecosistema Hadoop como alternativa al sistema de archivos HDFS.

Las aplicaciones a menudo no requieren que OrangeFS esté montado en el VFS, pero el cliente del kernel de OrangeFS permite montarlos. El cliente del kernel se comunica con un demonio en espacio de usuario que a su vez se comunica con el demonio-servidor de OrangeFS que implementa el sistema de archivos. El demonio-servidor no tiene por qué estar ejecutándose en el mismo sistema que el cliente del kernel. Los sistemas de archivo OrangeFS también pueden montarse con FUSE.

· Multiplexor de conexiones del kernel, una herramienta para acelerar protocolos de capa de aplicación 

Esta versión añade el "Kernel Connection Multiplexor" o KCM, un sistema que proporciona una interfaz basada en mensajes sobre TCP para acelerar protocolos de la capa de aplicación. La motivación que tiene procede de la observación de que aunque TCP es un protocolo de transporte orientado a los streams de bytes, sin concepto de límites entre mensajes, un caso de uso común es la implementación de protocolos en la capa de aplicación dividido en mensajes, que se ejecuta sobre TCP. La mayor parte de pilas TCP ofrecen APIs de streams de bytes, lo cual fuerza a las aplicaciones a gestionar la delineación de mensajes, la atomicidad del envío y recepción de los mensajes, y balanceo de carga.

Con KCM una aplicación puede enviar y recibir eficientemente mensajes de un protocolo de la capa de aplicación sobre TCP. EL kernel proporciona la seguridad necesaria de que el mensaje será recibido y enviado atómicamente. Esto libera a la aplicación de buena parte del tedio de tener que mapear un protocolo basado en mensajes a un stream TCP. Para delinear el límite de los mensajes en el stream TCP, el kernel implementa un parseador de mensajes basado en BPF. Casi todos los protocolos de aplicación son parseables de esta manera, de modo que KCM debería ser usable por un amplio rango de aplicaciones.

· Cifrado a nivel de MAC 802.1AE (MACsec)

Esta versión añade soporte para MACsec IEEE 802.1AE, un estandar que proporciona cifrado sobre ethernet. Cifra y autentifica todo el tráfico en una red LAN con GCM-AES-128. Puede proteger el tráfico DHCP y las VLANs y prevenir la manipulación de cabeceras de ethernet. MACSex está diseñado para ser utilizado con la extensión al protocolo 802.1X MACsec Key Agreement, que proporciona un mecanismo para la distribución de claves a los nodos, pero también puede utilizarse con claves estáticas configuradas manualmente por el administrador.

· Soporte para el protocolo V de BATMAN

B.A.T.M.A.N. (Better Approach To Mobile Adhoc Networking) añade en esta versión soporte para el  protocolo V, sucesor del protocolo IV. El nuevo protocolo divide el protocolo OGM en dos subcomponentes: ELP (Echo Location Protocol), que se ocupa del descubrimiento de nuevos nodos y estimación de la calidad de los enlaces; y un nuevo protocolo OGM, OGMv2, que implementa el algoritmo que difunde las métricas a lo largo de la red y computa las rutas óptimas. El cambio más importante introducido en esta versión del protocolo es la nueva métrica: Ya no se basará en la pérdida de paquetes, sino en la estimación del ancho de banda.

· dma-buf: una nueva ioctl para gestionar la coherencia entre la GPU y la CPU

Los programas pueden necesitar algún tipo de mecanismo de gestión de la coherencia cuando tanto la CPU como la GPU están accediendo a recursos dma-buf simultáneamente. Para resolver este problema se ha añadido la ioctl DMA_BUF_IOCTL_SYNC, que permite manejar esos problemas de coherencia.

· Chequeador de inodos online para OCFS2

OCFS2 a menudo es utilizado en sistemas de alta disponibilidad. OCFS2 suele remontar automáticamente el sistema de archivos al modo sólo-lectura cuando se encuentra un error, pero esta acción disminuye la disponibilidad, y no siempre es necesario. Existe una opción de montaje (errors=continue) que permite evitar ese montaje a sólo-lectura: sólo se devuelve -EIO al proceso que causó el error y se reporta el número de inodo problemático en el dmesg. Esta versión añade un chequeador de inodos muy simple en el kernel que puede utilizarse para comprobar y resetear el inodo. Nótese que esta característica está dirigida para problemas muy pequeños que puedan entorpecer las operaciones diarias de un cluster, no está dirigido a comprobaciones complejas, que deben seguir utilizando el fsck offline.

· Soporte para diferentes espacios de nombre en los cgroups

Esta versión añade soporte para diferentes espacios de nombre en los cgroups, lo cual proporciona un mecanismo para virtualizar el contenido del archivo /proc/$PID/cgroup y de los montajes de cgroups. Se ha añadido una nueva bandera a clone(2) y unshare(2), CLONE_NEWCGROUP, que permite crear un nuevo espacio de nombres de cgroup. Para un contenedor correctamente configurado, esto permite a las herramientas de contenedores (libcontainer, lxc, lmctfy, etc) crear contenedores virtualizados que no revelen información crítica sobre otras jerarquías cgroup del sistema.

· Soporte del layout SCSI para pNFS

Esta versión añade soporte en pNFS (parallel NFS, disponible en NFS v4.1) para layouts SCSI en el servidor NFS de Linux. Con los layouts SCSI, el servidor NFS actua como un Servidor de Metadatos para pNFS, que además de gestionar todo el acceso a metadatos de la exportación NFS, también ofrece layouts al cliente de manera que los clientes puedan acceder los LUNs SCSI. Para más detalles ver draft-ietf-nfsv4-scsi-layout

Estas son las novedades principales de este kernel. Como siempre, pueden encontrar la lista completa, y en inglés, en esta página.