fuse - Dispositivo Filesystem in Userspace (FUSE)
SINOPSIS
#include <linux/fuse.h>
DESCRIPCIÓN
Este dispositivo es la interfaz principal entre el controlador del sistema de archivos FUSE y un proceso de espacio de usuario que desea proporcionar el sistema de archivos (al que se hace referencia en el resto de esta página de manual como el daemon del sistema de archivos). Esta página de manual está destinada a aquellos interesados en comprender la propia interfaz del kernel. Aquellos que implementan un sistema de archivos FUSE pueden desear utilizar una biblioteca de espacio de usuario como libfuse que abstraiga la interfaz de bajo nivel.
En esencia, FUSE es un protocolo cliente-servidor simple, en el que el kernel de Linux es el cliente y el daemon es el servidor. Después de obtener un descriptor de archivo para este dispositivo, el daemon puede leer (2) solicitudes de ese descriptor de archivo y se espera que escriba (2) sus respuestas. Es importante tener en cuenta que un descriptor de archivo está asociado a un sistema de archivos FUSE único. En particular, abrir una segunda copia de este dispositivo no permitirá el acceso a los recursos creados a través del primer descriptor de archivo (y viceversa).
El protocolo básico
Cada mensaje que lee el daemon comienza con una cabecera descrita por la siguiente estructura:
struct fuse_in_header {
uint32_t len; /* Tamaño total de los datos,
incluida esta cabecera */
uint32_t opcode; /* El tipo de operación (ver abajo) */
uint64_t unique; /* Un identificador único para esta solicitud */
uint64_t nodeid; /* ID del objeto del sistema de archivos
sobre el que se está operando */
uint32_t uid; /* UID del proceso solicitante */
uint32_t gid; /* GID del proceso solicitante */
uint32_t pid; /* PID del proceso solicitante */
uint32_t padding;
};
La cabecera va seguida de una porción de datos de tamaño variable (que puede estar vacía) específica de la operación solicitada (la operación solicitada se indica mediante opcode).
El daemon debe procesar la solicitud y, si es aplicable, enviar una respuesta realizando una operación de escritura (2) en el descriptor de archivo. Casi todas las operaciones requieren una respuesta; si no, esto se documenta a continuación.
Todas las respuestas deben comenzar con la siguiente cabecera:
struct fuse_out_header {
uint32_t len; /* Tamaño total de los datos escritos
en el descriptor de archivo */
int32_t error; /* Cualquier error que haya ocurrido (0 si no hay ninguno) */
uint64_t unique; /* El valor de la
solicitud correspondiente */
};
Esta cabecera también va seguida de datos de tamaño variable (potencialmente vacíos) que dependen de la solicitud ejecutada. Sin embargo, si la respuesta es una respuesta de error (es decir, error está establecido), no se deben enviar más datos de carga útil, independientemente de la solicitud.
Mensajes intercambiados
Esta sección debe contener la documentación de cada uno de los mensajes del protocolo. Esta página del manual está actualmente incompleta, por lo que no todos los mensajes están documentados. Para cada mensaje, primero se proporciona la estructura enviada por el kernel, seguida de una descripción de la semántica del mensaje.
FUSE_INIT
struct fuse_init_in {
uint32_t major;
uint32_t minor;
uint32_t max_readahead; /* Desde la versión 7.6 del protocolo */
uint32_t flags; /* Desde la versión 7.6 del protocolo */
};
Este es el primer mensaje que el kernel envía al daemon. Se utiliza para negociar la versión del protocolo y otros parámetros del sistema de archivos. Tenga en cuenta que la versión del protocolo puede afectar el diseño de cualquier estructura en el protocolo (incluida esta estructura). Por lo tanto, el daemon debe recordar la versión y los indicadores negociados para cada sesión. Al momento de escribir esta página del manual, la versión del protocolo del kernel más alta admitida es 7.26.
Los usuarios deben tener en cuenta que las descripciones de esta página del manual pueden ser incompletas o incorrectas para versiones del protocolo más antiguas o más recientes.
La respuesta para esta solicitud tiene el siguiente formato:
struct fuse_init_out {
uint32_t major;
uint32_t minor;
uint32_t max_readahead; /* Desde la v7.6 */
uint32_t flags; /* Desde la v7.6; algunos bits de indicador se introdujeron más tarde */
uint16_t max_background; /* Desde la v7.13 */
uint16_t congestion_threshold; /* Desde la v7.13 */
uint32_t max_write; /* Desde la v7.5 */
uint32_t time_gran; /* Desde la v7.6 */
uint32_t unused[9];
};
Si la versión principal admitida por el kernel es mayor que la admitida por el daemon, la respuesta consistirá únicamente en uint32_t major (siguiendo el encabezado habitual), lo que indica la versión principal más alta admitida por el daemon. Luego, el kernel emitirá una nueva solicitud FUSE_INIT que se ajuste a la versión anterior. En el caso contrario, el daemon debe retroceder silenciosamente a la versión principal del kernel.
La versión secundaria negociada se considera el mínimo de las versiones secundarias proporcionadas por el daemon y el kernel, y ambas partes deben utilizar el protocolo correspondiente a dicha versión secundaria.
FUSE_GETATTR
struct fuse_getattr_in {
uint32_t getattr_flags;
uint32_t dummy;
uint64_t fh; /* Se establece solo si
(getattr_flags & FUSE_GETATTR_FH)
};
La operación solicitada es calcular los atributos que se devolverán mediante stat(2) y operaciones similares para el objeto del sistema de archivos dado. El objeto para el cual se deben calcular los atributos se indica mediante header->nodeid o, si se establece el indicador FUSE_GETATTR_FH, mediante el identificador de archivo fh. El último caso de operación es análogo a fstat(2).
Por razones de rendimiento, estos atributos se pueden almacenar en caché en el kernel durante un período de tiempo específico. Mientras no se exceda el tiempo de espera de la caché, los atributos se servirán desde la caché y no provocarán solicitudes FUSE_GETATTR adicionales.
Los atributos calculados y el tiempo de espera de la caché solicitados deben devolverse en la siguiente estructura:
struct fuse_attr_out {
/* Duración de la caché de atributos (segundos + nanosegundos) */
uint64_t attr_valid;
uint32_t attr_valid_nsec;
uint32_t dummy;
struct fuse_attr {
uint64_t ino;
uint64_t size;
uint64_t blocks;
uint64_t atime;
uint64_t mtime;
uint64_t ctime;
uint32_t atimensec;
uint32_t mtimensec;
uint32_t ctimensec;
uint32_t mode;
uint32_t nlink;
uint32_t uid;
uint32_t gid;
uint32_t rdev;
uint32_t blksize;
uint32_t padding;
} attr;
};
FUSE_ACCESS
struct fuse_access_in {
uint32_t mask;
uint32_t padding;
};
Si no se utiliza la opción de montaje default_permissions, esta solicitud se puede utilizar para la comprobación de permisos. No se espera ningún dato de respuesta, pero los errores se pueden indicar como de costumbre estableciendo el campo de error en la cabecera de la respuesta (en particular, los errores de acceso denegado se pueden indicar devolviendo -EACCES).
FUSE_OPEN
FUSE_OPENDIR
struct fuse_open_in {
uint32_t flags; /* Los indicadores que se pasaron a la función open(2) */
uint32_t unused;
};
La operación solicitada es abrir el nodo indicado por header->nodeid. La semántica exacta de lo que esto significa dependerá del sistema de archivos que se esté implementando. Sin embargo, como mínimo, el sistema de archivos debe validar que los indicadores solicitados sean válidos para el recurso indicado y, a continuación, enviar una respuesta con el siguiente formato:
struct fuse_open_out {
uint64_t fh;
uint32_t open_flags;
uint32_t padding;
};
El campo fh es un identificador opaco que el kernel utilizará para hacer referencia a este recurso. El campo open_flags es una máscara de bits de cualquier número de indicadores que indiquen las propiedades de este descriptor de archivo para el kernel:
FOPEN_DIRECT_IO Omitir la caché de páginas para este archivo abierto.
FOPEN_KEEP_CACHE No invalidar la caché de datos al abrir.
FOPEN_NONSEEKABLE El archivo no se puede buscar.
FUSE_READ
FUSE_READDIR
struct fuse_read_in {
uint64_t fh;
uint64_t offset;
uint32_t size;
uint32_t read_flags;
uint64_t lock_owner;
uint32_t flags;
uint32_t padding;
};
La acción solicitada es leer hasta size bytes del archivo o directorio, comenzando en offset. Los bytes deben devolverse directamente después de la cabecera de respuesta habitual.
FUSE_INTERRUPT
struct fuse_interrupt_in {
uint64_t unique;
};
La acción solicitada es cancelar la operación pendiente indicada por unique. Esta solicitud no requiere respuesta. Sin embargo, la recepción de este mensaje no cancela por sí sola la operación indicada. El kernel seguirá esperando una respuesta a dicha operación (por ejemplo, un error EINTR o una lectura corta). Como máximo, se emitirá una solicitud FUSE_INTERRUPT para una operación determinada. Después de emitir dicha operación, el kernel esperará de forma ininterrumpida hasta que se complete la operación indicada.
FUSE_LOOKUP
Directamente después de la cabecera se encuentra el nombre de archivo que se va a buscar en el directorio indicado por header->nodeid. La respuesta esperada tiene el siguiente formato:
struct fuse_entry_out {
uint64_t nodeid; /* ID de nodo */
uint64_t generation; /* Generación de nodo */
uint64_t entry_valid;
uint64_t attr_valid;
uint32_t entry_valid_nsec;
uint32_t attr_valid_nsec;
struct fuse_attr attr;
};
La combinación de nodeid y generation debe ser única durante la vida útil del sistema de archivos.
La interpretación de los tiempos de espera y attr es la misma que para FUSE_GETATTR.
FUSE_FLUSH
struct fuse_flush_in {
uint64_t fh;
uint32_t unused;
uint32_t padding;
uint64_t lock_owner;
};
La acción solicitada es vaciar cualquier cambio pendiente al descriptor de archivo indicado. No se espera ningún dato de respuesta. Sin embargo, aún debe enviarse un mensaje de respuesta vacío una vez que se complete la operación de vaciado.
FUSE_RELEASE
FUSE_RELEASEDIR
struct fuse_release_in {
uint64_t fh;
uint32_t flags;
uint32_t release_flags;
uint64_t lock_owner;
};
Estas son las operaciones inversas de FUSE_OPEN y FUSE_OPENDIR, respectivamente. El daemon ahora puede liberar cualquier recurso asociado con el descriptor de archivo fh, ya que el kernel ya no se referirá a él. No hay datos de respuesta asociados con esta solicitud, pero aún debe enviarse una respuesta una vez que se haya procesado completamente la solicitud.
FUSE_STATFS
Esta operación implementa statfs(2) para este sistema de archivos. No hay datos de entrada asociados con esta solicitud. Los datos de respuesta esperados tienen la siguiente estructura:
struct fuse_kstatfs {
uint64_t blocks;
uint64_t bfree;
uint64_t bavail;
uint64_t files;
uint64_t ffree;
uint32_t bsize;
uint32_t namelen;
uint32_t frsize;
uint32_t padding;
uint32_t spare[6];
};
struct fuse_statfs_out {
struct fuse_kstatfs st;
};
Para la interpretación de estos campos, consulte statfs(2).
ERRORES
E2BIG Devuelto de las operaciones read(2) cuando la solicitud del kernel es demasiado grande para el búfer proporcionado y la solicitud fue FUSE_SETXATTR.
EINVAL Devuelto de write(2) si la validación de la respuesta falló. No todos los errores en las respuestas serán detectados por esta validación. Sin embargo, los errores básicos, como las respuestas cortas o un valor único incorrecto, se detectan.
EIO Devuelto de las operaciones read(2) cuando la solicitud del kernel es demasiado grande para el búfer proporcionado.
Nota: Hay varias formas en que el uso incorrecto de estas interfaces puede hacer que las operaciones en los archivos y directorios del sistema de archivos proporcionado fallen con EIO. Entre los posibles usos incorrectos se encuentran:
cambiar el modo y S_IFMT para un inodo que previamente se informó al kernel; o
enviar respuestas al kernel que sean más cortas de lo que esperaba el kernel.
ENODEV Devuelto de read(2) y write(2) si el sistema de archivos FUSE se desmontó.
EPERM Devuelto de las operaciones en un descriptor de archivo /dev/fuse que no se ha montado.
ESTÁNDARES
Linux.
NOTAS
Los siguientes mensajes aún no están documentados en esta página de manual:
FUSE_BATCH_FORGET
FUSE_BMAP
FUSE_CREATE
FUSE_DESTROY
FUSE_FALLOCATE
FUSE_FORGET
FUSE_FSYNC
FUSE_FSYNCDIR
FUSE_GETLK
FUSE_GETXATTR
FUSE_IOCTL
FUSE_LINK
FUSE_LISTXATTR
FUSE_LSEEK
FUSE_MKDIR
FUSE_MKNOD
FUSE_NOTIFY_REPLY
FUSE_POLL
FUSE_READDIRPLUS
FUSE_READLINK
FUSE_REMOVEXATTR
FUSE_RENAME
FUSE_RENAME2
FUSE_RMDIR
FUSE_SETATTR
FUSE_SETLK
FUSE_SETLKW
FUSE_SYMLINK
FUSE_UNLINK
FUSE_WRITE
VER TAMBIÉN
fusermount(1), mount.fuse(8)