fuse - Dispositivo Filesystem in Userspace (FUSE)
SINTAXE
#include <linux/fuse.h>
DESCRIÇÃO
Este dispositivo é a interface primária entre o driver do sistema de arquivos FUSE e um processo em espaço de usuário que deseja fornecer o sistema de arquivos (referido no restante desta página de manual como o daemon do sistema de arquivos). Esta página de manual destina-se àqueles que desejam entender a interface do kernel em si. Aqueles que implementam um sistema de arquivos FUSE podem optar por usar uma biblioteca em espaço de usuário, como o libfuse, que abstrai a interface de baixo nível.
Em sua essência, o FUSE é um protocolo cliente-servidor simples, no qual o kernel Linux é o cliente e o daemon é o servidor. Depois de obter um descritor de arquivo para este dispositivo, o daemon pode ler(2) as solicitações desse descritor de arquivo e deve escrever(2) suas respostas. É importante observar que um descritor de arquivo está associado a um sistema de arquivos FUSE exclusivo. Em particular, abrir uma segunda cópia deste dispositivo não permitirá o acesso aos recursos criados por meio do primeiro descritor de arquivo (e vice-versa).
O protocolo básico
Cada mensagem que é lida pelo daemon começa com um cabeçalho descrito pela seguinte estrutura:
struct fuse_in_header {
uint32_t len; /* Tamanho total dos dados,
incluindo este cabeçalho */
uint32_t opcode; /* O tipo de operação (veja abaixo) */
uint64_t unique; /* Um identificador exclusivo para esta solicitação */
uint64_t nodeid; /* ID do objeto do sistema de arquivos
no qual a operação está sendo realizada */
uint32_t uid; /* UID do processo solicitante */
uint32_t gid; /* GID do processo solicitante */
uint32_t pid; /* PID do processo solicitante */
uint32_t padding;
};
O cabeçalho é seguido por uma porção de dados de tamanho variável (que pode estar vazia), específica da operação solicitada (a operação solicitada é indicada por opcode).
O daemon deve então processar a solicitação e —se aplicável— enviar uma resposta, executando uma operação de escrita(2) no descritor de arquivo. Quase todas as operações exigem uma resposta; se não exigirem, isso estará documentado abaixo.
Todos os replies devem começar com o seguinte cabeçalho:
struct fuse_out_header {
uint32_t len; /* Tamanho total dos dados gravados
no descritor de arquivo */
int32_t error; /* Qualquer erro que ocorreu (0 se nenhum) */
uint64_t unique; /* O valor da
solicitação correspondente */
};
Este cabeçalho também é seguido por dados de tamanho variável (potencialmente vazios), dependendo da solicitação executada. No entanto, se a resposta for uma resposta de erro (ou seja, o erro é definido), então nenhum dado de carga útil adicional deve ser enviado, independentemente da solicitação.
Mensagens trocadas
Esta seção deve conter a documentação de cada uma das mensagens do protocolo. Esta página de manual está atualmente incompleta, portanto, nem todas as mensagens estão documentadas. Para cada mensagem, primeiro é fornecida a estrutura enviada pelo kernel, seguida por uma descrição da semântica da mensagem.
FUSE_INIT
struct fuse_init_in {
uint32_t major;
uint32_t minor;
uint32_t max_readahead; /* Desde o protocolo v7.6 */
uint32_t flags; /* Desde o protocolo v7.6 */
};
Esta é a primeira requisição enviada pelo kernel para o daemon. É usada para negociar a versão do protocolo e outros parâmetros do sistema de arquivos. Observe que a versão do protocolo pode afetar o layout de qualquer estrutura no protocolo (incluindo esta estrutura). O daemon deve, portanto, lembrar a versão e os sinalizadores negociados para cada sessão. No momento da redação desta página de manual, a versão de protocolo do kernel mais alta suportada é 7.26.
Os usuários devem estar cientes de que as descrições nesta página de manual podem estar incompletas ou incorretas para versões de protocolo mais antigas ou mais recentes.
A resposta para esta requisição tem o seguinte formato:
struct fuse_init_out {
uint32_t major;
uint32_t minor;
uint32_t max_readahead; /* Desde v7.6 */
uint32_t flags; /* Desde v7.6; alguns bits de sinalizador foram introduzidos posteriormente \*/
uint16_t max_background; /* Desde v7.13 */
uint16_t congestion_threshold; /* Desde v7.13 */
uint32_t max_write; /* Desde v7.5 */
uint32_t time_gran; /* Desde v7.6 */
uint32_t unused[9];
};
Se a versão principal suportada pelo kernel for maior do que a suportada pelo daemon, a resposta consistirá apenas em uint32_t major (seguindo o cabeçalho usual), indicando a maior versão principal suportada pelo daemon. O kernel então emitirá uma nova requisição FUSE_INIT compatível com a versão mais antiga. No caso inverso, o daemon deve simplesmente retornar à versão principal do kernel.
A versão secundária negociada é considerada o mínimo das versões secundárias fornecidas pelo daemon e pelo kernel, e ambas as partes devem usar o protocolo correspondente a essa versão secundária.
FUSE_GETATTR
struct fuse_getattr_in {
uint32_t getattr_flags;
uint32_t dummy;
uint64_t fh; /* Definido apenas se
(getattr_flags & FUSE_GETATTR_FH)
};
A operação solicitada é calcular os atributos a serem retornados por stat(2) e operações semelhantes para o objeto do sistema de arquivos fornecido. O objeto para o qual os atributos devem ser calculados é indicado pelo header->nodeid ou, se o sinalizador FUSE_GETATTR_FH estiver definido, pelo file handle fh. O último caso de operação é análogo a fstat(2).
Por motivos de desempenho, esses atributos podem ser armazenados em cache no kernel por um período de tempo especificado. Enquanto o tempo limite do cache não for excedido, os atributos serão obtidos do cache e não causarão requisições FUSE_GETATTR adicionais.
Os atributos calculados e o tempo limite de cache solicitado devem então ser retornados na seguinte estrutura:
struct fuse_attr_out {
/* Duração do cache de atributos (segundos + nanossegundos) */
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;
};
Se a opção de montagem default_permissions não for usada, esta solicitação pode ser usada para verificação de permissões. Nenhum dado de resposta é esperado, mas erros podem ser indicados da maneira usual, definindo o campo de erro no cabeçalho da resposta (em particular, erros de acesso negado podem ser indicados retornando -EACCES).
FUSE_OPEN
FUSE_OPENDIR
struct fuse_open_in {
uint32_t flags; /* As flags que foram passadas para a função open(2) */
uint32_t unused;
};
A operação solicitada é abrir o nó indicado por header->nodeid. A semântica exata do que isso significa dependerá do sistema de arquivos que está sendo implementado. No entanto, no mínimo, o sistema de arquivos deve validar se as flags solicitadas são válidas para o recurso indicado e, em seguida, enviar uma resposta no seguinte formato:
struct fuse_open_out {
uint64_t fh;
uint32_t open_flags;
uint32_t padding;
};
O campo fh é um identificador opaco que o kernel usará para se referir a este recurso. O campo open_flags é uma máscara de bits de qualquer número de flags que indicam propriedades deste descritor de arquivo para o kernel:
FOPEN_DIRECT_IO Ignora a cache de página para este arquivo aberto.
FOPEN_KEEP_CACHE Não invalida a cache de dados na abertura.
FOPEN_NONSEEKABLE O arquivo não pode ser acessado aleatoriamente.
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;
};
A ação solicitada é ler até size bytes do arquivo ou diretório, começando em offset. Os bytes devem ser retornados diretamente após o cabeçalho de resposta usual.
FUSE_INTERRUPT
struct fuse_interrupt_in {
uint64_t unique;
};
A ação solicitada é cancelar a operação pendente indicada por unique. Esta solicitação não requer resposta. No entanto, o recebimento desta mensagem por si só não cancela a operação indicada. O kernel ainda esperará uma resposta para a operação indicada (por exemplo, um erro EINTR ou uma leitura curta). No máximo, uma solicitação FUSE_INTERRUPT será emitida para uma determinada operação. Depois de emitir a solicitação, o kernel aguardará ininterruptamente a conclusão da solicitação indicada.
FUSE_LOOKUP
Diretamente após o cabeçalho, está o nome do arquivo a ser pesquisado no diretório indicado por header->nodeid. A resposta esperada é do seguinte formato:
struct fuse_entry_out {
uint64_t nodeid; /* ID do inode */
uint64_t generation; /* Geração do inode */
uint64_t entry_valid;
uint64_t attr_valid;
uint32_t entry_valid_nsec;
uint32_t attr_valid_nsec;
struct fuse_attr attr;
};
A combinação de nodeid e generation deve ser única durante o ciclo de vida do sistema de arquivos.
A interpretação de timeouts e attr é a mesma que para FUSE_GETATTR.
FUSE_FLUSH
struct fuse_flush_in {
uint64_t fh;
uint32_t unused;
uint32_t padding;
uint64_t lock_owner;
};
A ação solicitada é liberar quaisquer alterações pendentes para o handle de arquivo indicado. Não há dados de resposta esperados. No entanto, uma mensagem de resposta vazia ainda precisa ser emitida quando a operação de flush for concluída.
FUSE_RELEASE
FUSE_RELEASEDIR
struct fuse_release_in {
uint64_t fh;
uint32_t flags;
uint32_t release_flags;
uint64_t lock_owner;
};
Estas são as operações inversas de FUSE_OPEN e FUSE_OPENDIR, respectivamente. O daemon agora pode liberar quaisquer recursos associados ao handle de arquivo fh, pois o kernel não se referirá mais a ele. Não há dados de resposta associados a esta solicitação, mas uma resposta ainda precisa ser emitida quando a solicitação for totalmente processada.
FUSE_STATFS
Esta operação implementa statfs(2) para este sistema de arquivos. Não há dados de entrada associados a esta solicitação. Os dados de resposta esperados têm a seguinte estrutura:
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 a interpretação desses campos, consulte statfs(2).
ERROS
E2BIG Retornado das operações read(2) quando a solicitação do kernel é muito grande para o buffer fornecido e a solicitação foi FUSE_SETXATTR.
EINVAL Retornado de write(2) se a validação da resposta falhar. Nem todos os erros nas respostas serão detectados por esta validação. No entanto, erros básicos, como respostas curtas ou um valor único incorreto, são detectados.
EIO Retornado das operações read(2) quando a solicitação do kernel é muito grande para o buffer fornecido.
Observação: Existem várias maneiras pelas quais o uso incorreto dessas interfaces pode fazer com que as operações nos arquivos e diretórios do sistema de arquivos fornecido falhem com EIO. Entre os possíveis usos incorretos estão:
alterar mode e S_IFMT para um inode que já foi relatado ao kernel; ou
fornecer respostas ao kernel que são menores do que o esperado.
ENODEV Retornado de read(2) e write(2) se o sistema de arquivos FUSE foi desmontado.
EPERM Retornado de operações em um descritor de arquivo /dev/fuse que não foi montado.
PADRÕES
Linux.
NOTAS
As seguintes mensagens ainda não estão documentadas nesta 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
VEJA TAMBÉM
fusermount(1), mount.fuse(8)