25 de julio de 2016

Las novedades de Linux 4.7

Ya se ha anunciado la versión 4.7 de Linux. Esta versión añade soporte para las recientemente puestas en venta GPUs Radeon RX 480 'Polaris', soporte para búsquedas de rutas de archivo paralelas en el mismo directorio, un nuevo gobernador de frecuencia experimental "schedutils" que debería ser más rápido y veloz que otros gobernadores, soporte para el mecanismo EFI "Capsule" que facilita las actualizaciones de firmware, soporte de controladores virtuales USB en la funcionalidad USB/IP para que los emuladores de teléfonos puedan funcionar como dispositivos USB reales, un módulo de seguridad llamado "LoadPin" que asegura que los módulos del kernel sólo se puedan cargar desde un sistema de archivos determinado, soporte para construir histogramas de eventos en la interfaz de trazado ftrace, soporte para asociar programas BPF a tracepoints del kernel, soporte para callchains en la utilidad perf trace, y soporte estable para la funcionalidad sync_file de Android. También se han incluido drivers nuevos y muchas otras mejoras y pequeños cambios. La lista completa de cambios, en inglés, puede encontrarse aquí, como siempre.



· Soporte para GPUs Radeon RX 480 'Polaris'

Como resultado de la nueva política de drivers libres de AMD, esta versión incluye soporte en el driver amdgpu para las recientísimamente puestas en venta GPUs Polaris, la nueva generación de  GPUs Radeon RX 480. El soporte está al mismo nivel que el resto de dispositivos del driver.



· Búsquedas de ruta de archivo paralelas en el mismo directorio

El caché de directorio (conocido como "dcache") es una de las partes más críticas del kernel, se trata de un caché de las rutas de los sistema de archivos, lo cual permite agilizar enormemente ciertas operaciones; por ejemplo, permite determinar si cierto archivo o directorio existe o no sin tener que leer datos del disco. Este cache usa un mutex para serializar las búsquedas de rutas en el mismo directorio.

Esta versión permite hacer búsquedas de rutas en el mismo directorio; el mutex serializador ha sido sustituido por un semáforo de lectura-escritura. Esta mejora no se notará en la vastísima mayoría de casos, porque las búsquedas en el caché de directorios son muy rápidas y es muy raro que se convierta en un punto de contención. Pero para algunas cargas específicas que utilizan la búsqueda de rutas muy intensivamente, verán una mejora del rendimiento porque a partir de ahora podrán hacerse en paralelo. La mayor parte  de los sistemas de archivos han sido convertidos para utilizar esta característica.


· Nuevo gobernador de frecuencia experimental 'schedutils'

Esta versión incorpora un nuevo gobernador para el subsistema de escalado de frecuencias (cpufreq). Hay dos grandes diferencias entre este nuevo gobernador y los existentes. Primero, schedutils utiliza información proporcionada directamente por el planificador de procesos. Segundo, puede invocar los drivers cpufreq y cambiar la frecuencia más rápidamente.

Lo que esto significa es que el tiempo que tarda el gobernador en hacer cambios de frecuencia y la calidad de las decisiones tomadas mejora respecto a anteriores gobernadores. Nótese que este nuevo gobernador es muy simple, y está considerado como una base sobre la que fundar futuros cambios que mejoren la integración entre el planificador de procesos y la gestión de energía. Sin embargo, funciona y los resultados preliminares son prometedores. Este gobernador comparte algunos valores tuneables con los otros gobernadores.


· Soporte para construir histogramas de eventos en la interfaz de trazado ftrace

Los "Hist triggers" son una funcionalidad que se incorpora a ftrace, la infraestructura de trazado de Linux disponible desde 2.6.27 que está embebida en el kernel y disponible en /sys/kernel/debug/tracing. Esta versión añade el comando "hist" a ftrace, que permite construir "histogramas" de eventos, agregando el número de eventos en una tabla hash. Como ejemplo, vamos a suponer que un usuario quiere conseguir una lista de bytes leídos por cada proceso en el sistema. Se puede hacer con el comando "hist" de la siguiente manera:

# echo 'hist:key=common_pid.execname:val=count:sort=count.descending' > /sys/kernel/debug/tracing/events/syscalls/sys_enter_read/trigger

Lo que hace este extraño comando es escribir un comando al archivo trigger del evento sys_enter_read (el evento que corresponde a entrar en la llamada al sistema read(), es decir, intentar leer un archivo). Cuando se produzca el evento, se ejecutará un comando hist (hist:) que significa lo siguiente: cada vez que se dispare el evento, leer el PID (common_pid - puedes ver todos los campos posibles del evento en el archivo /sys/kernel/debug/tracing/events/syscalls/sys_enter_read/format) y convertirlo a nombre de proceso (sufijo .execname); esto será usado como clave (key=) en el histograma. El parámetro val=count hace que se lea también el campo count, que en el evento sys_enter_read se refiere al número de bytes leídos. Finalmente, tras el separador :, el parámetro sort=count.descending hace que el comando ordene el resultado por el campo count en orden descendiente. La salida resultante es esta:


Esta salida muestra qué procesos han leído archivos, cuantos bytes (count), y con cuanta frecuencia (hitcount, que no fue especificado en el comando pero se incluye por defecto).

Como se puede observar, esta pequeña herramienta permite hacer análisis muy útiles del sistema, y si bien ftrace no puede competir (ni lo pretende) con herramientas de trazado más potentes como LTTng, perf o SystemTap, puede ser una herramienta muy conveniente. Para más información, puedes ver la documentación sobre hist triggers, or leer este post recomendado de Brendan Egg: Hist Triggers in Linux 4.7. Para más documentation sobre ftrace, ver Documentation/trace/ftrace.txt


· Soporte para callchains en la utilidad perf trace

En esta versión, perf trace añade la habilidad de mostrar callchains cada vez que el proceso a trazar encuentra una llamada al sistema. Puedes probarlo con comandos como # perf trace --call dwarf ping 127.0.0.1. Puedes mostrar callchains para los eventos deseados: # perf trace --event sched:sched_switch/call-graph=fp/ -a sleep 1. El trazado de fallos de página (options -F/--pf) también lo soportan, por ejemplo, para trazar las llamadas a write() y los fallos de página con callchains mientras se inicia firefox, puede hacerse con # perf trace -e write --pf maj --max-stack 5 firefox. Una análisis de perf trace con callchains de todos los procesos de un sistema completo puede encontrarse aquí.


· Permitir que los programas BPF usen tracepoints

Los tracepoints son una suerte de printf()s dinámicos que los desarrolladores introducen en su código para que puedan ser utilizados más tarde para analizar el comportamiento del sistema. Los Tracepoints pueden ser utilizados por muchas utilidades: LTTng, perf, SystemTap, ftrace...pero no podían ser utilizados por programas BPF

Esta versión añade un nuevo tipo de programa BPF (BPF_PROG_TYPE_TRACEPOINT) que puede usarse para construir programas BPF que puedan recoger datos de los tracepoints y procesarlos dentro del programa BPF. Esta alternativa puede ser más rápida que acceder a los tracepoints mediante kprobes, puede hacer las interfaces de los programas de trazado más estable, y permite la construcción de herramientas de trazado más complejas.


· Soporte para el mecanismo 'Capsule' de EFI

Esta versión añade soporte para el mecanismo 'Capsule' de EFI, que permite pasar a EFI archivos de datos. EFI los valida y toma decisiones de acuerdo con sus contenidos. El uso más común para este mecanismo es incluir actualizaciones de firmware en una Capsule para que EFI haga la actualización en el próximo reinicio. Los usuarios pueden subir datos a Capsule escribiendo el firmware en el dispositivo /dev/efi_capsule_loader device.


· Soporte para controladores de USB virtuales en USB/IP

USB/IP permite compartir dispositivos USB sobre la red. Los dispositivos a compartir necesitan, sin emabrgo, ser reales. Esta versión soporte la capacidad de crear dispositivos USB virtuales sin necesidad de tener un dispositivo USB físico, tal sólo utilizando el subsistema de USB gadgets.

Esta característica tiene varios usos; el más obvio (el que ha motivado su desarrollo) es la mejora de la emulación de teléfonos en los entornos de desarrollo. Los teléfonos emulados pueden ahora conectarse a la máquina del desarrollador, o a una virtual, mediante USB/IP, y así utilizarlos como si fuera un teléfono físico. También es útil, por razones obvias, para pruebas y experimentos.


· El mecanismo de fencing de Android, sync_file, se considera estable

En esta versión, el código sync_file que estaba en el directorio de pruebas staging/, ha sido movido al kernel principal. Sync_file es una API desarrollada para Android para cubrir las deficiencias del mecanismo de fencing de Linux; para los interesados se pueden encontrar más detalles en la documentación oficial, Documentation/sync_file.txt.


· LoadPin, un módulo de seguridad para restringir el origen de los módulos del kernel 

LoadPin es un módulo de seguridad que se asegura de que todos los archivos cargados por el kernel (módulos del kernel, firmware, imágenes kexec, políticas de seguridad, etc) tengan origen en un mismo sistema de archivos. Las expectativas son que ese sistema de archivos sea de sólo lectura, como por ejemplo un DVD o dm-verity (esta característica viene de ChromeOS, donde el sistema principal está verificado criptográficamente con dm-verity). Los sistemas con este tipo de sistemas de archivos podrán con este sistema forzar las restricciones citadas sin tener que recurrir a firmar criptográficamente los módulos (algo que Linux también soporta), lo cual es obviamente beneficioso para la seguridad


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

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.