El sistema de ficheros virtual (VFS) de Linux

Autor: Juan Antonio Martínez Castaño
E-mail: jantonio@dit.upm.es
Web: http://www.dit.upm.es/~jantonio

Copyright

Este artículo es Copyright 1999 de Juan Antonio Martínez Castaño y se distribuye bajo las siguientes condiciones:

Indice


Entradilla

Iniciamos aquí una nueva serie de artículos sobre uno de los componentes esenciales del núcleo Linux, y una de las razones de su potencia y versatilidad: la estructura y funcionamiento del sistema de ficheros, conocido como Virtual File System ( VFS )


Introducción

Los lectores de Linux Actual conocen sobradamente conceptos como "montar" y "desmontar" sistemas de ficheros, sistemas de ficheros "tipo XXX": ext2, vfat iso9660, nfs...., dispositivos, particiones...

El VFS esconde las peculiaridades de cada sistema de ficheros y unifica el manejo a través de un API común

A pesar de ello pocas veces nos ponemos a pensar cómo es posible unificar conceptos tan dispares como una partición de MS-Dos con un directorio de un servidor de red, de manera que podemos utilizar los mismos comandos, y de la misma forma en estructuras tan distintas.

La razón de esta aparente "magia" reside en un conjunto de estructuras que el núcleo Linux mantiene, y que sirve para unificar de cara al usuario todos y cada uno de los posibles tipos de estructuras de almacenamiento de datos. Esta capa intermedia se denomina Sistema de ficheros virtual, aunque todos lo conocemos por sus siglas en inglés: VFS , o Virtual File System

Esta serie de artículos trata sobre el VFS de Linux. Describiremos las estructuras que lo componen y su funcionamiento, explicando los conceptos de superbloque, inodo, fichero... analizando las operaciones de registro de un sistema de ficheros, el proceso de montaje y desmontaje, y las operaciones conocidas de open, close, read... etc
Para ilustrar el texto, recurriremos con frecuencia al código fuente del núcleo Linux. Salvo anotación expresa, los ejemplos están extraídos del código correspondiente a la versión 2.2.5 del núcleo Linux. Del mismo modo, y para ilustrar al lector sobre cómo desarrollar sus propios sistemas de ficheros ( no es difícil, una vez se sabe cómo :-) ) hemos incluído en el CD-Rom que acompaña a la revista dos ejemplos: el primero es un sistema de ficheros tipo tarfs que permite "montar" y examinar directamente desde el árbol de directorios ficheros tar. El segundo corresponde al esqueleto de un sistema de ficheros cachefs que hace caché bajo demanda del contenido de otro sistema de ficheros sobre el disco local. Este último ejemplo no es funcional, pero sirve para ilustrar las operaciones de registro y montaje de un sistema de ficheros, y su interacción con el /proc filesystem

En un número anterior de Linux Actual se describió la estructura del sistema de ficheros Ext2fs. En este mismo número se describe el funcionamiento y estructura del /proc filesystem

La serie de artículos sobre el Virtual File System se divide en tres entregas. Este artículo describe los elementos componentes del VFS de Linux, describiendo las estructuras y su interrelación. El siguiente número de la serie describe los diversos procesos y funcionamiento del VFS, y constituye una guía para el programador de sistemas de ficheros. El tercer y último artículo profundiza en el concepto del manejo del caché de Linux y de cómo el núcleo optimiza la gestión de recursos en los accesos a los diferentes sistemas de ficheros.

Cojamos pues los fuentes de los programas descritos, y tengamos a mano los fuentes del núcleo Linux, especialmente el directorio /usr/src/linux/fs, y empecemos a navegar por el VFS....


Estructura del VFS

Todos sabemos que Linux soporta multitud de tipos de sistemas de ficheros, cada uno de ellos sobre diversos soportes físicos. La figura 1 muestra algunos de ellos. Además Linux permite programar e insertar dentro del núcleo muchos otros más, incluso los programados por el usuario. Todo ello exige un API unificado y un modelo de programación

Diferentes sistemas ficheros de Linux
Figura 1: Algunos tipos de sistemas de ficheros de Linux

¿ Cómo se lleva a cabo este soporte?. Una primera aproximación la encontramos en la figura 2, donde se describe el diagrama de bloques de las diferentes estructuras relacionadas con el manejo de ficheros. Podemos ver que:

  • El VFS proporciona también mecanismos de bloqueo y control de accesos. No obstante estas operaciones son fuertememte dependientes de cada sistema de ficheros en particular, por lo que no las describiremos en detalle

    diagrama de bloques
    Figura 2: Diagrama de bloques del sistema de ficheros de Linux


    Registro y montaje de un sistema de ficheros

    En todo momento, el usuario puede consultar el fichero /proc/filesystems para obtener la lista de sistemas de ficheros registrados, y que el VFS comprende. La operación de registro es aquella por la que se informa al VFS de que se ha instalado un nuevo manejador de sistemas de ficheros. Esta operación se realiza bien en el arranque del núcleo, o bien en la carga de un módulo. Evidentemente existe la operación inversa al registro, para decir que un sistema de ficheros ya no es reconocido por el VFS. las llamadas a las funciones son:

    extern int register_filesystem(struct file_system_type *);
    extern int unregister_filesystem(struct file_system_type *); 
    

    A nivel de código, los diversos sistemas de ficheros se agrupan como una lista encadenada de estructuras que definen cada sistema de ficheros. La figura 3 ilustra esta lista:

    file system list
    Figura 3: Organización de la lista de sistemas de ficheros

    El lector podrá observar que la estructura de un descriptor de sistemas de ficheros es simple. No se requiere más que

    Un registro sin más nos vale de poco: la esencia de los sistemas de ficheros es que se pueden montar dentro del árbol de directorios. La operación de montaje se puede definir como la creación de una terna dispositivo - sistema de ficheros - punto de anclaje. La figura 4 despliega las estructuras que intervienen en la operación de "mount". Básicamente son:

    mount structure
    Figura 4: estructura de una entrada en la tabla de montajes


    El super-bloque. Estructura y operaciones

    En todo momento hemos estado hablando del concepto de superbloque . Es hora ya de definirlo y explicar sus funciones

    Por superbloque entendemos la estructura de datos que define el contenido de un sistema de ficheros. El listado 1 muestra la definición de un VFS superblock. En él se incluye información sobre:

    struct super_block {
    	struct list_head	s_list;		/* Keep this first */
    	kdev_t			s_dev;
    	unsigned long		s_blocksize;
    	unsigned char		s_blocksize_bits;
    	unsigned char		s_lock;
    	unsigned char		s_rd_only;
    	unsigned char		s_dirt;
    	struct file_system_type	*s_type;
    	struct super_operations	*s_op;
    	struct dquot_operations	*dq_op;
    	unsigned long		s_flags;
    	unsigned long		s_magic;
    	unsigned long		s_time;
    	struct dentry		*s_root;
    	struct wait_queue	*s_wait;
    
    	struct inode		*s_ibasket;
    	short int		s_ibasket_count;
    	short int		s_ibasket_max;
    	struct list_head	s_dirty;	/* dirty inodes */
    
    	union {
    		struct minix_sb_info	minix_sb;
    		struct ext2_sb_info	ext2_sb;
    		struct hpfs_sb_info	hpfs_sb;
    		struct ntfs_sb_info     ntfs_sb;
    		struct msdos_sb_info	msdos_sb;
    		struct isofs_sb_info	isofs_sb;
    		struct nfs_sb_info	nfs_sb;
    		struct sysv_sb_info	sysv_sb;
    		struct affs_sb_info	affs_sb;
    		struct ufs_sb_info	ufs_sb;
    		struct romfs_sb_info	romfs_sb;
    		struct smb_sb_info	smbfs_sb;
    		struct hfs_sb_info	hfs_sb;
    		struct adfs_sb_info	adfs_sb;
    		struct qnx4_sb_info	qnx4_sb;	   
    		void			*generic_sbp;
    	} u;
    };
    
    Listado 1: Estructura del VFS superblock

    La operación de mount crea en el VFS una nueva estructura tipo superbloque. El VFS llama a la rutina read_super() definida en la descripción del sistema de ficheros y le pasa como parámetro el VFS superblock recien creado. read_super() completa los datos de esta estructura, especialmente los referidos a los punteros a las operaciones a realizar con dicho sistema de ficheros ( campo *s_op de la estructura ) y retorna de nuevo el superbloque con los datos completos. En lo sucesivo, el VFS cada vez que requiera de alguna operación con este sistema de ficheros recien montado, no tiene sino que seguir los enlaces...

    La mejor manera de seguir este proceso es la lectura del código fuente de algún sistema de ficheros sencillo. El lector puede estudiar los ejemplos que se incluyen en el CD-Rom, o bien directamente en el kernel estudiar -por ejemplo- el código del Romfs


    Los inodos. Manejo de inodos

    Toda entrada en un sistema de ficheros tiene asociado un descriptor, que denominamos inodo

    Otro concepto que hemos estado manejando hasta ahora y que no hemos definido es el de inodo. Lo podemos definir como un descriptor de una entrada de un sistema de ficheros. Existe la tendencia de asociar el concepto de inodo con el de fichero dado que "en UNIX todos los dispositivos son ficheros" y "todo fichero tiene asociado un único inodo". Esto no es exactamente así por:

    El listado 2 describe la estructura de un VFS inode. Los comentarios describen los campos más importantes

    struct inode {
    	struct list_head	i_hash;
    	struct list_head	i_list;
    	struct list_head	i_dentry; /*datos utilizados por el VFS cache*/
    
    	unsigned long		i_ino;	  /* inode number */
    	unsigned int		i_count;
    	kdev_t			i_dev;	  /* dispositivo asociado */
    	umode_t			i_mode;	  /* flags */
    	nlink_t			i_nlink;  /* número de enlaces */
    	uid_t			i_uid;	  /* user id del propietario */
    	gid_t			i_gid;	  /* group id del propietario */
    	kdev_t			i_rdev;   /* si special file, major y minor */
    	off_t			i_size;	  /* tamaño del fichero asociado */
    	time_t			i_atime;  /* fecha de ultimo acceso */
    	time_t			i_mtime;  /* fecha de ultima modificacion */
    	time_t			i_ctime;  /* fecha de creacion */
    	unsigned long		i_blksize;/* tamaño del bloque */
    	unsigned long		i_blocks; /* numero de bloques */
    	unsigned long		i_version;
    	unsigned long		i_nrpages;
    	struct semaphore	i_sem;
    	struct semaphore	i_atomic_write;
    	struct inode_operations	*i_op;	/* operaciones sobre el inodo */
    	struct super_block	*i_sb;  /* puntero al superbloque */
    	struct wait_queue	*i_wait;
    	struct file_lock	*i_flock;
    	struct vm_area_struct	*i_mmap;
    	struct page		*i_pages;
    	struct dquot		*i_dquot[MAXQUOTAS];
    
    	unsigned long		i_state;
    
    	unsigned int		i_flags;
    	unsigned char		i_pipe;
    	unsigned char		i_sock;
    
    	int			i_writecount;
    	unsigned int		i_attr_flags;
    	__u32			i_generation;
    	union { /* datos especificos dependientes del tipo de filesystem */
    		struct pipe_inode_info		pipe_i;
    		struct minix_inode_info		minix_i;
    		struct ext2_inode_info		ext2_i;
    		struct hpfs_inode_info		hpfs_i;
    		struct ntfs_inode_info          ntfs_i;
    		struct msdos_inode_info		msdos_i;
    		struct umsdos_inode_info	umsdos_i;
    		struct iso_inode_info		isofs_i;
    		struct nfs_inode_info		nfs_i;
    		struct sysv_inode_info		sysv_i;
    		struct affs_inode_info		affs_i;
    		struct ufs_inode_info		ufs_i;
    		struct romfs_inode_info		romfs_i;
    		struct coda_inode_info		coda_i;
    		struct smb_inode_info		smbfs_i;
    		struct hfs_inode_info		hfs_i;
    		struct adfs_inode_info		adfs_i;
    		struct qnx4_inode_info		qnx4_i;	   
    		struct socket			socket_i;
    		void				*generic_ip;
    	} u;
    };
    
    
    Listado 2: Estructura del VFS inode

    Mención especial requiere el puntero i_op, pues es el que define las operaciones que se pueden realizar con cada inodo. Al igual que hemos diferenciado inodo de fichero, existen una serie de operacione que se pueden realizar con inodos ( link, unlink, mkdir, mknod, rename, etc ) y una serie de operaciones que se pueden realizar con los ficheros asociados a cada inodo, -caso de que existan- ( read, write, mmap, readdir, seek ). En la próxima entrega de esta serie detallaremos su manejo


    Resumen

    Hemos descrito en este artículo a grandes rasgos, la estructura y elementos del Virtual File System de Linux, detallando los conceptos de filesystem, superbloque, inodo y fichero. En el próximo número veremos mediante ejemplos su funcionamiento, asi como daremos guías para que el lector pueda crear sus propios sistemas de ficheros, o modificar los existentes

    Referencias

    En el CD-Rom que se acompaña a esta revista se incluye la mayor parte de la documentación disponible sobre el Virtual File System: Y por supuesto "Use the source, Luke", el código fuente del núcleo Linux es , como siempre, la mejor referencia.