Scroll to navigation

FUSE(4) Руководство программиста Linux FUSE(4)

ИМЯ

fuse - устройство файловой системы в пользовательском пространстве (FUSE)

СИНТАКСИС

#include <linux/fuse.h>

ОПИСАНИЕ

Это устройство является основным интерфейсом между драйвером файловой системы FUSE и процессом в пользовательском пространстве, который будет предоставлять файловую систему (далее здесь называется службой файловой системы (filesystem daemon)). Данная справочная страница предназначена тому, кто заинтересован в понимании интерфейса самого ядра. Тем, кто реализует файловую систему FUSE, важнее описание библиотеки пользовательского пространства такой как libfuse, которая скрывает низкоуровневый интерфейс.

В основе FUSE лежит простой клиент-серверный протокол, в котором ядро Linux является клиентом, а служба — сервером. После получения файлового дескриптора этого устройства, служба может читать запросы с помощью read(2) из этого файлового дескриптора и писать ответы с помощью write(2). Важно отметить, что данный файловый дескриптор, связанный с файловой системой FUSE, является индивидуальным. В частности, открытие второй копии этого устройства не даст доступ к ресурсам, созданным через первый файловый дескриптор (и наоборот).

Основной протокол

Каждое сообщение, читаемое службой, начинается с заголовка следующей структуры:


struct fuse_in_header {

uint32_t len; /* общая длина данных,
включая этот заголовок */
uint32_t opcode; /* тип операции (смотрите ниже) */
uint64_t unique; /* уникальный идентификатор этого запроса */
uint64_t nodeid; /* ID объекта файловой системы, с
которым выполняется действие */
uint32_t uid; /* UID запрашивающего процесса */
uint32_t gid; /* GID запрашивающего процесса */
uint32_t pid; /* PID запрашивающего процесса */
uint32_t padding; };

После заголовка располагаются данные произвольной длины (их может и не быть), используемые вместе с запрашиваемой операцией (запрашиваемая операция указывается в opcode).

Служба обрабатывает запрос и, если нужен ответ (почти все операции требуют ответа; если нет, то это описано далее), выполняет запись с помощью write(2) в файловый дескриптор. Все ответы должны начинаться со следующего заголовка:


struct fuse_out_header {

uint32_t len; /* общая длина данных, записываемых
в файловый дескриптор */
int32_t error; /* возникшая ошибка (0, если нет) */
uint64_t unique; /* значение из
соответствующего запроса */ };

После этого заголовка также располагаются данные произвольной длины (возможно их отсутствие), в зависимости от запроса. Однако, если ответ является ответом, содержащим ошибку, (т. е., error не равно нулю), то дополнительных данных посылаться не должно, независимо от запроса.

Расширенные сообщения

В этом разделе должна быть документация по каждому сообщению протокола. Данная справочная страница не закончена, поэтому описаны не все сообщения. Для каждого сообщения сначала приводится структура, посылаемая ядром, после чего описывается семантика сообщения.


struct fuse_init_in {

uint32_t major;
uint32_t minor;
uint32_t max_readahead; /* начиная с протокола v7.6 */
uint32_t flags; /* начиная с протокола v7.6 */ };

Это первый запрос, посылаемый ядром службе. Он используется для согласования версии протокола и других параметров файловой системы. Заметим, что версия протокола может влиять на любую структуру протокола (включая эту). Служба должна запоминать согласованную версию и флаги для каждого сеанса. На момент написания этой справочной страницы наибольшей версией поддерживаемого ядром протокола была 7.26.
Пользователи должны учесть, что описания в этой справочной странице могут быть неполны или некорректны по отношению к старым или более новым версиям протокола.
Ответ на этот запрос имеет следующий формат:

struct fuse_init_out {

uint32_t major;
uint32_t minor;
uint32_t max_readahead; /* Начиная с v7.6 */
uint32_t flags; /* Начиная с v7.6; некоторые биты флагов были введены позднее */
uint16_t max_background; /* Начиная с v7.13 */
uint16_t congestion_threshold; /* Начиная с v7.13 */
uint32_t max_write; /* Начиная с v7.5 */
uint32_t time_gran; /* Начиная с v7.6 */
uint32_t unused[9]; };

Если главная (major) версия, поддерживаемая ядром, больше чем поддерживаемая службой, то ответ должен содержать только uint32_t major (как обычный заголовок), показывающий наибольшую главную версию, поддерживаемую службой. После этого ядро создаст новый запрос FUSE_INIT, соответствующий более старой версии. В противном случае (то есть, если версия службы новее), служба должна переключиться на работу с главной версией ядра.
Согласованной вспомогательной (minor) версией считается минимальная из вспомогательных версий, поддерживаемых службой и ядром, и обе стороны должны использовать протокол, соответствующий указанной вспомогательной версии.

struct fuse_getattr_in {

uint32_t getattr_flags;
uint32_t dummy;
uint64_t fh; /* задаётся, только если
(getattr_flags & FUSE_GETATTR_FH) };

Операция запроса вычисления атрибутов, возвращаемых stat(2) и подобными операциями для указанного объекта файловой системы. Объект, для которого вычисляются атрибуты, задаётся в виде header->nodeid или, если указан флаг FUSE_GETATTR_FH, в виде файлового описателя (handle) fh. Для последнего случая операция аналогична fstat(2).
С целью оптимизации производительности, эти атрибуты могут кэшироваться в ядре на указанный период времени. Пока срок хранения кэша не истёк, атрибуты будут браться из кэша и дополнительные запросы FUSE_GETATTR выполняться не будут.
Вычисленные атрибуты и срок хранения в кэше возвращаются в следующей структуре:

struct fuse_attr_out {

/* срок хранения атрибута в кэше (секунды + наносекунды) */
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; };


struct fuse_access_in {

uint32_t mask;
uint32_t padding; };

Если не используется параметр монтирования default_permissions, то этот запрос можно использовать для проверки прав доступа. Данных в ответе не ожидается, но могут возвращаться ошибки, как обычно в поле error заголовка ответа (в частности, при ошибках отказа в доступе может возвращаться -EACCES).

struct fuse_open_in {

uint32_t flags; /* флаги, передаваемые
в open(2) */
uint32_t unused; };

Этот запрос открывает ноду, указанную в header->nodeid. Точна семантика будет зависеть от реализации в файловой системе. Однако, по крайней мере, файловая система должна проверить что запрашиваемые flags корректны для указанного ресурса и затем послать ответ в следующем формате:

struct fuse_open_out {

uint64_t fh;
uint32_t open_flags;
uint32_t padding; };

Поле fh представляет собой закрытый (opaque) идентификатор, который ядро будет использовать для ссылки на этот ресурс. Поле open_flags представляет собой битовую маску с набором флагов, которые определяют свойства этого описателя в ядре:
Не использовать страничный кэш для этого открытого файла.
Не делать недействительными данные кэша при открытии.
Внутри файла не поддерживается смена положения.

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; };

По этому запросу читается до size байт файла или каталога, начиная с offset. Байты должны возвращаться сразу за обычным заголовком ответа.

struct fuse_interrupt_in {

uint64_t unique; };

По этому запросу отменяется ожидающая операция, указанная в unique. По запросу не формируется ответ. Однако, само получение сообщения не отменяет указанную операцию. Ядро всё равно будет ждать ответа на указанную операцию (например, ошибку EINTR или короткое чтение). Для указанной операции будет выдано не более одно запроса FUSE_INTERRUPT. После выдачи указанной операции ядро будет непрерывно ожидать завершения указанного запроса.
Непосредственно после заголовка указывается имя файла, которое будет искаться в каталоге, указанном в header->nodeid. Ожидается ответ в виде:

struct fuse_entry_out {

uint64_t nodeid; /* идентификатор inode */
uint64_t generation; /* поколение inode */
uint64_t entry_valid;
uint64_t attr_valid;
uint32_t entry_valid_nsec;
uint32_t attr_valid_nsec;
struct fuse_attr attr; };

Комбинация nodeid и generation должна быть уникальной на время существования файловой системы.
Параметры сроков хранения и attr такие же как в FUSE_GETATTR.

struct fuse_flush_in {

uint64_t fh;
uint32_t unused;
uint32_t padding;
uint64_t lock_owner; };

По этому запросу сбрасываются (flush) все ожидающие изменения для указанного файлового описателя. Данных в ответе не ожидается. Однако, всё равно требуется ответное сообщения после завершения операции сброса.

struct fuse_release_in {

uint64_t fh;
uint32_t flags;
uint32_t release_flags;
uint64_t lock_owner; };

Запросы, обратные FUSE_OPEN и FUSE_OPENDIR, соответственно. Служба теперь может освободить ресурсы, связанные с файловым описателем fh, так как ядру он больше не нужен. Данных в ответе не посылается, но ответ нужно отправить после обработки запроса.
Данная операция реализует statfs(2) для этой файловой системы. В запросе нет данных. В ответе ожидаются данные следующей структуры:

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; };

Информацию об этих полях смотрите в statfs(2).

ОШИБКИ

Возвращается из операций read(2), когда запросы ядра слишком велики для предоставляемого буфера и запросом является FUSE_SETXATTR.
Возвращается из операции write(2), если ответ не прошёл тест на правильность. При этом не все ошибки в ответах будут пойманы. Однако обнаруживаются простые ошибки, такие как короткие ответы или некорректное значение unique.
Возвращается из операции read(2), когда запросы ядра слишком велики для предоставляемого буфера.
Замечание: Есть несколько вариантов, в которых неправильное использование этих интерфейсов с предоставляемыми файловой системой файлами и каталогами может завершиться ошибкой EIO. Например:
  • изменение mode & S_IFMT для иноды, о которой ранее было сообщено ядру; или
  • выдача более коротких ответов ядру, чем оно ожидает.
Возвращается из операций read(2) и write(2), если файловая система FUSE была размонтирована.
Возвращается из операций над файловым дескриптором /dev/fuse, если он не был смонтирован.

СООТВЕТСТВИЕ СТАНДАРТАМ

Файловая система FUSE есть только в Linux.

ЗАМЕЧАНИЯ

Следующие сообщения пока не документированы в этой справочной странице:


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

СМ. ТАКЖЕ

fusermount(1), mount.fuse(8)

ЗАМЕЧАНИЯ

Эта страница является частью проекта Linux man-pages версии 5.10. Описание проекта, информацию об ошибках и последнюю версию этой страницы можно найти по адресу https://www.kernel.org/doc/man-pages/.

ПЕРЕВОД

Русский перевод этой страницы руководства был сделан Azamat Hackimov <azamat.hackimov@gmail.com>, Dmitry Bolkhovskikh <d20052005@yandex.ru>, Yuri Kozlov <yuray@komyakino.ru> и Иван Павлов <pavia00@gmail.com>

Этот перевод является бесплатной документацией; прочитайте Стандартную общественную лицензию GNU версии 3 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ.

Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на man-pages-ru-talks@lists.sourceforge.net.

2 февраля 2018 г. Linux