命令行手册

Man » fuse 手册在线 - fuse 手册页的详细在线文档

🌍

fuse - 用户空间文件系统 (FUSE) 设备

概要

include

描述

此设备是 FUSE 文件系统驱动程序和希望提供文件系统的用户空间进程之间的主要接口(在本文档的其余部分中,将该进程称为“文件系统守护程序”)。 本手册页旨在帮助有兴趣了解内核接口的人。 那些实施 FUSE 文件系统的人可能希望使用用户空间库(如 libfuse),它抽象了低级接口。

从根本上说,FUSE 是一种简单的客户端-服务器协议,其中 Linux 内核是客户端,守护程序是服务器。 在获得此设备的的文件描述符后,守护程序可以从该文件描述符读取请求,并应将响应写入该文件描述符。 重要的一点是,文件描述符与唯一的 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 指示)。

然后,守护程序应处理请求,并且(如果适用)通过对文件描述符执行写入操作来发送响应(几乎所有操作都需要响应;如果不需要,则会在下面进行记录)。 所有响应都必须以以下标头开头:

struct fuse_out_header {
uint32_t len;       /* 写入文件描述符的数据总大小 */
int32_t  error;     /* 发生的任何错误(如果没有,则为 0) */
uint64_t unique;    /* 来自
相应的请求的值 */
};

此标头后也是(可能是空的)变长数据,具体取决于执行的请求。 但是,如果响应是错误响应(即,设置了错误),则不应发送任何进一步的负载数据,而与请求无关。


交换的消息

本部分应包含协议中每个消息的文档。此手册页目前尚未完成,因此并非所有消息都已记录。对于每个消息,首先给出内核发送的结构,然后描述消息的语义。

FUSE_INIT

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

如果内核支持的主版本号大于守护进程支持的主版本号,则回复应仅包含 uint32_t major(遵循通常的头部),指示守护进程支持的最高主版本号。然后,内核将发出符合较旧版本的新 FUSE_INIT 请求。在反之情况下,守护进程应安静地回退到内核的主版本号。

协商后的次要版本被认为是守护进程和内核提供的次要版本中的最小值,并且双方都应使用与所述次要版本相对应的协议。

FUSE_GETATTR

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 标志,则由文件句柄 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;
};

FUSE_ACCESS

struct fuse_access_in {
uint32_t mask;
uint32_t padding;
};

如果未使用 default_permissions 挂载选项,则可以使用此请求进行权限检查。 预计不会有回复数据,但可以通过在回复标头中设置错误字段来指示错误(特别是,拒绝访问错误可以通过返回 -EACCES 来指示)。

FUSE_OPEN
FUSE_OPENDIR
struct fuse_open_in {
uint32_t flags;     /* 传递给 open(2) 的标志 */
uint32_t unused;
};

请求的操作是打开由 header->nodeid 指示的节点。 这的确切含义将取决于所实现的 文件系统。 但是,最重要的是,文件系统应验证请求的标志是否对指示的资源有效,然后发送一个具有以下格式的回复:

struct fuse_open_out {
uint64_t fh;
uint32_t open_flags;
uint32_t padding;
};

fh 字段是一个不透明的标识符,内核将使用它来引用此资源。 open_flags 字段是任何数量的指示文件句柄到内核的属性的标志的位掩码:

FOPEN_DIRECT_IO   绕过此打开文件的页面缓存。

FOPEN_KEEP_CACHE  不要在打开时使数据缓存失效。

FOPEN_NONSEEKABLE 该文件不可寻址。

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

请求的操作是从文件或目录中读取最多 size 字节的数据,从 offset 开始。 字节应直接位于通常的回复标头之后返回。

FUSE_INTERRUPT
struct fuse_interrupt_in {
uint64_t unique;
};

请求的操作是取消由 unique 指示的待处理操作。 此请求不需要响应。 但是,收到此消息本身并不会取消指示的操作。 内核仍然需要对所述操作进行回复(例如,EINTR 错误或短读取)。 对于给定的操作,最多只能发出一个 FUSE_INTERRUPT 请求。 发出所述操作后,内核将无中断地等待指示请求的完成。

FUSE_LOOKUP

在标头之后,直接是需要在由 header->nodeid 指示的目录中查找的文件名。 预期的回复形式如下:


struct fuse_entry_out {
uint64_t nodeid;            /* 节点 ID */
uint64_t generation;        /* 节点世代 */
uint64_t entry_valid;
uint64_t attr_valid;
uint32_t entry_valid_nsec;
uint32_t attr_valid_nsec;
struct fuse_attr attr;
};

^ odeidgeneration 的组合在文件系统的生命周期内必须是唯一的。

^ imeoutsattr 的解释与 FUSE_GETATTR 相同。

FUSE_FLUSH
struct fuse_flush_in {
uint64_t fh;
uint32_t unused;
uint32_t padding;
uint64_t lock_owner;
};

请求的操作是刷新与指示的文件句柄关联的任何待处理更改。不期望任何回复数据。但是,一旦完成刷新操作,仍然需要发出一个空的回复消息。

FUSE_RELEASE
FUSE_RELEASEDIR
struct fuse_release_in {
uint64_t fh;
uint32_t flags;
uint32_t release_flags;
uint64_t lock_owner;
};

这些分别是 FUSE_OPENFUSE_OPENDIR 的反向操作。守护进程现在可以释放与文件句柄 fh 关联的任何资源,因为内核将不再引用它。没有与此请求关联的回复数据,但请求完全处理完成后仍然需要发出回复。

FUSE_STATFS

此操作为文件系统实现 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)

错误

E2BIG 从 `read(2)` 操作返回,当内核的请求对于提供的缓冲区来说太大时,并且请求是 `FUSE_SETXATTR`。

EINVAL 从 `write(2)` 返回,如果回复的验证失败。回复中的所有错误都不会被此验证捕获。但是,基本的错误,例如回复太短或唯一值不正确,将被检测到。

EIO 从 `read(2)` 操作返回,当内核的请求对于提供的缓冲区来说太大时。

注意:以不正确的方式使用这些接口会导致对提供的文件系统中文件和目录的操作失败,并返回 EIO。可能的错误使用包括:

更改模式和 `S_IFMT` 标志,用于先前已报告给内核的 inode;或者

向内核提供比内核预期的更短的回复。

ENODEV 从 `read(2)` 和 `write(2)` 返回,如果 FUSE 文件系统已卸载。

EPERM 从对未挂载的 `/dev/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)