本篇文章主要内容来自 btrfs 文件系统的 ioctl 的官方接口文档,并在原文档的基础上,结合 Btrfs 内核代码的实现,补充了很多原文档缺失的内容,我愿称之为 btrfs-ioctl (2) plus

⚠️请注意, ioctl 的数量、含义和定义会随着时间改变,本文内容参考了 Linux v6.13.7 版本的代码,完稿时间为 2025 年 4 月 11 日,如果时间相差很远的话请自行验证文章内容的正确性。同时,由于笔者水平有限,如果有任何错误,恳请指正 Orz。

# 速览

名字描述数据结构(参数)
BTRFS_IOC_SNAP_CREATE创建子卷快照(已过时,被 BTRFS_IOC_SNAP_CREATE_V2 代替)struct btrfs_ioctl_vol_args
BTRFS_IOC_DEFRAG对文件或目录执行碎片整理NULL
BTRFS_IOC_DEFRAG_RANGE对文件或目录执行碎片整理struct btrfs_ioctl_defrag_range_args
BTRFS_IOC_RESIZE调整 Btrfs 设备的容量大小struct btrfs_ioctl_vol_args
BTRFS_IOC_SCAN_DEV扫描指定设备路径并将其注册到文件系统模块中struct btrfs_ioctl_vol_args
BTRFS_IOC_SYNC同步文件系统,可能处理排队等待的工作NULL
BTRFS_IOC_CLONE克隆(已废弃,被 VFS 的 FICLONE 代替)int
BTRFS_IOC_CLONE_RANGE指定范围克隆(已废弃,被 VFS 的 FICLONERANGE 代替)struct btrfs_ioctl_clone_range_args
BTRFS_IOC_FILE_EXTENT_SAME在多个文件中共享数据,即清除重复数据(已废弃,被 VFS 的 FIDEDUPERANGE 代替)struct btrfs_ioctl_same_args
BTRFS_IOC_ADD_DEV按路径将设备添加到文件系统中struct btrfs_ioctl_vol_args
BTRFS_IOC_RM_DEV按路径从文件系统中删除一个设备(已过时, 被 BTRFS_IOC_RM_DEV_V2 代替)struct btrfs_ioctl_vol_args
BTRFS_IOC_BALANCE平衡操作(已废弃,被 BTRFS_IOC_BALANCE_V2BTRFS_IOC_BALANCE_CTL 代替)struct btrfs_ioctl_vol_args
BTRFS_IOC_SUBVOL_CREATE创建一个子卷(已过时,被 BTRFS_IOC_SUBVOL_CREATE_V2 代替)struct btrfs_ioctl_vol_args
BTRFS_IOC_SNAP_DESTROY删除一个子卷(已过时,被 BTRFS_IOC_SNAP_DESTROY_V2 代替)struct btrfs_ioctl_vol_args
BTRFS_IOC_TREE_SEARCH查询 Btrfs 树中的结构信息(已过时,被 BTRFS_IOC_TREE_SEARCH_V2 代替)struct btrfs_ioctl_search_args
BTRFS_IOC_INO_LOOKUP将 inode 编号解析为路径,或查找其所在的子卷 IDstruct btrfs_ioctl_ino_lookup_args
BTRFS_IOC_DEFAULT_SUBVOL设置默认子卷 IDuint64_t
BTRFS_IOC_SPACE_INFO查询磁盘空间使用情况struct btrfs_ioctl_space_args
BTRFS_IOC_START_SYNC强制触发一次子卷的事务提交uint64_t
BTRFS_IOC_WAIT_SYNC等待指定的事务提交完成uint64_t
BTRFS_IOC_SNAP_CREATE_V2创建一个子卷快照struct btrfs_ioctl_vol_args_v2
BTRFS_IOC_SUBVOL_CREATE_V2创建一个子卷struct btrfs_ioctl_vol_args_v2
BTRFS_IOC_TREE_SEARCH_V2查询 Btrfs 树中的结构信息struct btrfs_ioctl_search_args_v2
BTRFS_IOC_SUBVOL_GETFLAGS获取子卷的 flagsuint64_t
BTRFS_IOC_SUBVOL_SETFLAGS设置子卷的 flagsuint64_t
BTRFS_IOC_SCRUB对一个 Btrfs 设备进行校验和修复操作struct btrfs_ioctl_scrub_args
BTRFS_IOC_SCRUB_CANCEL取消正在运行的 scrub 操作NULL
BTRFS_IOC_SCRUB_PROGRESS获取 scrub 进度信息struct btrfs_ioctl_scrub_args
BTRFS_IOC_DEV_INFO获取指定 Btrfs 设备的基本信息struct btrfs_ioctl_dev_info_args
BTRFS_IOC_FS_INFO获取文件系统信息(设备数、fsid、...)struct btrfs_ioctl_fs_info_args
BTRFS_IOC_BALANCE_V2触发或恢复一次平衡(balance)操作struct btrfs_ioctl_balance_args
BTRFS_IOC_BALANCE_CTL控制当前平衡(balance)操作int
BTRFS_IOC_BALANCE_PROGRESS获取当前 balance 操作的进度struct btrfs_ioctl_balance_args
BTRFS_IOC_INO_PATHS查找 inode 在文件系统中的所有路径struct btrfs_ioctl_ino_path_args
BTRFS_IOC_LOGICAL_INO根据逻辑地址查询用到该地址的 inodestruct btrfs_ioctl_logical_ino_args
BTRFS_IOC_SET_RECEIVED_SUBVOL设置子卷的 “接收元信息”struct btrfs_ioctl_received_subvol_args
BTRFS_IOC_SEND发送子卷快照struct btrfs_ioctl_send_args
BTRFS_IOC_DEVICES_READY检查设备是否准备就绪struct btrfs_ioctl_vol_args
BTRFS_IOC_QUOTA_CTL控制配额(quota)开启或关闭struct btrfs_ioctl_quota_ctl_args
BTRFS_IOC_QGROUP_ASSIGN管理配额组间关系struct btrfs_ioctl_qgroup_assign_args
BTRFS_IOC_QGROUP_CREATE创建或删除一个配额组struct btrfs_ioctl_qgroup_create_args
BTRFS_IOC_QGROUP_LIMIT为某个 qgroup(配额组 设置配额限制struct btrfs_ioctl_qgroup_limit_args
BTRFS_IOC_QUOTA_RESCAN对整个文件系统重新扫描以更新 qgroup(配额组)信息struct btrfs_ioctl_quota_rescan_args
BTRFS_IOC_QUOTA_RESCAN_STATUS返回当前的 qgroup rescan(重新扫描)状态struct btrfs_ioctl_quota_rescan_args
BTRFS_IOC_QUOTA_RESCAN_WAIT等待当前 qgroup rescan(重新扫描)完成NULL
BTRFS_IOC_GET_FSLABEL读取文件系统标签(BTRFS_LABEL_SIZE=256)char buffer[BTRFS_LABEL_SIZE]
BTRFS_IOC_SET_FSLABEL设置文件系统标签(BTRFS_LABEL_SIZE=256)char buffer[BTRFS_LABEL_SIZE]
BTRFS_IOC_GET_DEV_STATS获取块设备(device)的各项信息struct btrfs_ioctl_get_dev_stats
BTRFS_IOC_DEV_REPLACE进行设备替换(device replace)struct btrfs_ioctl_dev_replace_args
BTRFS_IOC_GET_FEATURES获取当前挂载文件系统支持的特性(feature) 标志struct btrfs_ioctl_feature_flags
BTRFS_IOC_SET_FEATURES设置文件系统特性(features)标志struct btrfs_ioctl_feature_flags[2]
BTRFS_IOC_GET_SUPPORTED_FEATURES获取当前内核支持的文件系统特性(features)标志struct btrfs_ioctl_feature_flags[3]
BTRFS_IOC_RM_DEV_V2从文件系统中删除一个设备struct btrfs_ioctl_vol_args_v2
BTRFS_IOC_LOGICAL_INO_V2根据逻辑地址查询用到该地址的 inodestruct btrfs_ioctl_logical_ino_args
BTRFS_IOC_GET_SUBVOL_INFO获取一个子卷的信息struct btrfs_ioctl_get_subvol_info_args
BTRFS_IOC_GET_SUBVOL_ROOTREF查询子卷的 ROOTREF 信息struct btrfs_ioctl_get_subvol_rootref_args
BTRFS_IOC_INO_LOOKUP_USER获取 inode 的路径信息struct btrfs_ioctl_ino_lookup_user_args
BTRFS_IOC_SNAP_DESTROY_V2删除一个子卷的快照或普通子卷struct btrfs_ioctl_vol_args_v2
BTRFS_IOC_ENCODED_READ读取文件的原始内容,绕过文件系统的编码struct btrfs_ioctl_encoded_io_args
BTRFS_IOC_ENCODED_WRITE向文件直接写入原始内容,绕过文件系统编码struct btrfs_ioctl_encoded_io_args
BTRFS_IOC_SUBVOL_SYNC_WAIT用于等待某个已删除子卷被系统彻底清理,或者用于查询其当前清理状态struct btrfs_ioctl_subvol_wait

# 数据结构与定义

# btrfs_ioctl_vol_args

/* this should be 4k */
#define BTRFS_PATH_NAME_MAX 4087
struct btrfs_ioctl_vol_args {
	__s64 fd;
	char name[BTRFS_PATH_NAME_MAX + 1];
};

# btrfs_ioctl_vol_args_v2

#define BTRFS_SUBVOL_RDONLY                  (1ULL << 1)
#define BTRFS_SUBVOL_QGROUP_INHERIT          (1ULL << 2)
#define BTRFS_DEVICE_SPEC_BY_ID              (1ULL << 3)
#define BTRFS_SUBVOL_SPEC_BY_ID              (1ULL << 4)
#define BTRFS_SUBVOL_NAME_MAX 		         4039
struct btrfs_ioctl_vol_args_v2 {
	__s64 fd;
	__u64 transid;
	__u64 flags;
	union {
		struct {
			__u64 size;
			struct btrfs_qgroup_inherit __user *qgroup_inherit;
		};
		__u64 unused[4];
	};
	union {
		char name[BTRFS_SUBVOL_NAME_MAX + 1];
		__u64 devid;
		__u64 subvolid;
	};
};
#define BTRFS_QGROUP_INHERIT_SET_LIMITS         (1ULL << 0)
struct btrfs_qgroup_inherit {
	__u64	flags;
	__u64	num_qgroups;
	__u64	num_ref_copies;
	__u64	num_excl_copies;
	struct btrfs_qgroup_limit lim;
	__u64	qgroups[];
};
#define BTRFS_QGROUP_LIMIT_MAX_RFER             (1ULL << 0)
#define BTRFS_QGROUP_LIMIT_MAX_EXCL             (1ULL << 1)
#define BTRFS_QGROUP_LIMIT_RSV_RFER             (1ULL << 2)
#define BTRFS_QGROUP_LIMIT_RSV_EXCL             (1ULL << 3)
#define BTRFS_QGROUP_LIMIT_RFER_CMPR            (1ULL << 4)
#define BTRFS_QGROUP_LIMIT_EXCL_CMPR            (1ULL << 5)
struct btrfs_qgroup_limit {
	__u64	flags;
	__u64	max_rfer;
	__u64	max_excl;
	__u64	rsv_rfer;
	__u64	rsv_excl;
};

# btrfs_ioctl_get_subvol_info_args

#define BTRFS_VOL_NAME_MAX 255
#define BTRFS_UUID_SIZE 16
struct btrfs_ioctl_get_subvol_info_args {
    __u64 treeid;          /* 此子卷的 ID */
    char name[BTRFS_VOL_NAME_MAX + 1];  /* 子卷名称,用于获取挂载点的真实名称 */
    __u64 parent_id;       /* 包含此子卷的父卷 ID,顶层子卷或已删除子卷为 0 */
    __u64 dirid;           /* 包含此子卷的目录的 inode 号,顶层子卷或已删除子卷为 0 */
    __u64 generation;      /* 子卷的最新事务 ID */
    __u64 flags;           /* 子卷标志 */
    __u8 uuid[BTRFS_UUID_SIZE];        /* 子卷 UUID */
    __u8 parent_uuid[BTRFS_UUID_SIZE];  /* 如果当前子卷是某个子卷的快照,就保存那个原始子卷的 UUID。否则为全 0。 */
    __u8 received_uuid[BTRFS_UUID_SIZE]; /* 如果这个子卷是通过 btrfs receive 创建的,这里记录 “发送方的源子卷 UUID”。否则全为 0 */
    
    /* 创建 / 修改 / 发送 / 接收操作的事务 ID */
    __u64 ctransid;        
    __u64 otransid;
    __u64 stransid;
    __u64 rtransid;
    /* 对应 c/o/s/rtransid 的时间 */
    struct btrfs_ioctl_timespec ctime;
    struct btrfs_ioctl_timespec otime;
    struct btrfs_ioctl_timespec stime;
    struct btrfs_ioctl_timespec rtime;
    __u64 reserved[8];     /* 必须为 0 */
};
struct btrfs_ioctl_timespec {
	__u64 sec;
	__u32 nsec;
};

# btrfs_ioctl_received_subvol_args

#define BTRFS_UUID_SIZE 16
struct btrfs_ioctl_received_subvol_args {
	char	uuid[BTRFS_UUID_SIZE];	/* 输入 */
	__u64	stransid;		/* 输入 */
	__u64	rtransid;		/* 输出 */
	struct btrfs_ioctl_timespec stime; /* 输入 */
	struct btrfs_ioctl_timespec rtime; /* 输出 */
	__u64	flags;			/* 输入 */
	__u64	reserved[16];		/* 输入 */
};

参见 struct btrfs_ioctl_timespec

# btrfs_ioctl_fs_info_args

/* 请求校验和类型和大小信息 */
#define BTRFS_FS_INFO_FLAG_CSUM_INFO                    (1U << 0) 
/* 请求文件系统代际(generation)信息 */
#define BTRFS_FS_INFO_FLAG_GENERATION                   (1U << 1) 
/* 请求文件系统元数据 UUID */
#define BTRFS_FS_INFO_FLAG_METADATA_UUID                (1U << 2) 
#define BTRFS_FSID_SIZE 16
struct btrfs_ioctl_fs_info_args {
    __u64 max_id;           /* 输出 */
    __u64 num_devices;      /* 输出 */
    __u8 fsid[BTRFS_FSID_SIZE];     /* 输出 */
    __u32 nodesize;         /* 输出 */
    __u32 sectorsize;       /* 输出 */
    __u32 clone_alignment;  /* 输出 */
    __u16 csum_type;        /* 输出 */
    __u16 csum_size;        /* 输出 */
    __u64 flags;            /* 输入 / 输出 */
    __u64 generation;       /* 输出 */
    __u8 metadata_uuid[BTRFS_FSID_SIZE];  /* 输出 */
    __u8 reserved[944];     /* 填充至 1KB */
};

# btrfs_ioctl_ino_lookup_args

#define BTRFS_INO_LOOKUP_PATH_MAX               4080
struct btrfs_ioctl_ino_lookup_args {
        __u64 treeid;
        __u64 objectid;
        char name[BTRFS_INO_LOOKUP_PATH_MAX];
};

# btrfs_ioctl_subvol_wait

/* 等待指定的 subvolid 删除完成(清理结束) */
#define BTRFS_SUBVOL_SYNC_WAIT_FOR_ONE         (0) 
/* 等待所有队列中的子卷清除完成 */
#define BTRFS_SUBVOL_SYNC_WAIT_FOR_QUEUED      (1) 
/* 统计队列中的子卷数 */
#define BTRFS_SUBVOL_SYNC_COUNT                (2) 
/* 读取清理队列中第一个子卷 ID(即 " 正在清理” 或 “马上要清理” 的那个)(若为空则为 0) */
#define BTRFS_SUBVOL_SYNC_PEEK_FIRST           (3) 
/* 查看队列中的最后一个子卷 ID(若为空则为 0) */
#define BTRFS_SUBVOL_SYNC_PEEK_LAST            (4) 
struct btrfs_ioctl_subvol_wait {
    __u64 subvolid; /* 子卷(包括快照)的唯一 ID */
    __u32 mode;
    __u32 count;
};

# btrfs_ioctl_clone_range_args

/* 如果把 src_length 设置为 0,那就表示 “从 src_offset 开始,一直到源文件结尾 (EOF) 的内容都会被克隆”。 */
struct btrfs_ioctl_clone_range_args {
	__s64 src_fd;
	__u64 src_offset, src_length;
	__u64 dest_offset;
};

# btrfs_ioctl_defrag_range_args

/*
 * 用于碎片整理区间 ioctl 的标志定义
 *
 * 使用于:
 * struct btrfs_ioctl_defrag_range_args.flags
 */
#define BTRFS_DEFRAG_RANGE_COMPRESS 1       // 开启压缩功能
#define BTRFS_DEFRAG_RANGE_START_IO 2       // 启动 I/O 操作
#define BTRFS_DEFRAG_RANGE_FLAGS_SUPP	(BTRFS_DEFRAG_RANGE_COMPRESS |		\
					 BTRFS_DEFRAG_RANGE_START_IO)  // 支持的标志位(压缩 + 启动 IO)
struct btrfs_ioctl_defrag_range_args {
	/* 碎片整理操作的起始位置 */
	__u64 start;
	/* 要整理的字节数,使用 (u64)-1 表示 “整理全部” */
	__u64 len;
	/* 操作标志,可以用来开启本次整理中的压缩功能 */
	__u64 flags;
	/* 任何大于该值的 extent(连续块)会被认为已经整理过。*/
	/* 使用 0 表示使用内核默认值;*/
	/* 使用 1 表示每一个 extent 都必须被重写。*/
	__u32 extent_thresh;
	/* 如果开启压缩,本字段用于指定使用哪种压缩方法。*/
	/* 如果未指定,默认使用 zlib。*/
	__u32 compress_type;
	/* 保留字段,供将来使用 */
	__u32 unused[4];
};

# btrfs_ioctl_search_args

#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
/* buf 是一个由多个搜索头(search header)组成的数组,*/
/* 每个头部后面紧跟着实际的 item(项目)。*/
/* 为了对齐(alignment),type 字段被扩展为 32 位。*/
struct btrfs_ioctl_search_args {
	struct btrfs_ioctl_search_key key;
	char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
};
/* Btrfs SEARCH ioctl 系列命令的搜索条件 */
struct btrfs_ioctl_search_key {
	/*
	 * 要搜索的树 ID。1 表示 “树根树”,2 表示 “extent 树”,等等……
	 *
	 * 如果 tree_id 设置为特殊值 0,则会在传递给 ioctl 的 inode 所在的子卷树中进行搜索。
	 */
	__u64 tree_id;		/* 输入 */
	/*
	 * 执行树搜索时,实际上是从一个 136 位线性搜索空间中取出一个区间。
	 *
	 * 一个完整的 136 位树键(tree key)格式如下:
	 *   (objectid << 72) + (type << 64) + offset
	 *
	 * 对 objectid、type 和 offset 的最小值和最大值定义了搜索区间的
	 * min_key 到 max_key 范围。所有落在该范围 [min_key, max_key]
	 * 内的元数据项(metadata item)将会被返回。
	 *
	 * 另外,也可以通过指定事务 ID 范围(transid)来过滤返回的项,这些 ID
	 * 表示这些元数据块最后一次被写入时所属的事务(COW 操作后的写入)。
	 * 需要注意的是,这个事务 ID 只是说明该元数据页最近一次被写入的事务,
	 * 并不代表某个具体 item 是在哪个事务中创建或修改的。
	 */
	__u64 min_objectid;	/* 输入 */
	__u64 max_objectid;	/* 输入 */
	__u64 min_offset;	/* 输入 */
	__u64 max_offset;	/* 输入 */
	__u64 min_transid;	/* 输入 */
	__u64 max_transid;	/* 输入 */
	__u32 min_type;		/* 输入 */
	__u32 max_type;		/* 输入 */
	/*
	 * 输入:期望返回的最大 item 数量;
	 * 输出:实际返回的 item 数量,受以下限制之一:
	 *  - 达到搜索范围的上限;
	 *  - 达到输入指定的 nr_items 数量;
	 *  - 填满了提供的内存缓冲区。
	 */
	__u32 nr_items;		/* 输入 / 输出 */
	/* 为对齐到 64 位而保留 */
	__u32 unused;
	/* 保留字段,用于将来扩展 */
	__u64 unused1;
	__u64 unused2;
	__u64 unused3;
	__u64 unused4;
};

# btrfs_ioctl_search_args_v2

/*
 * TREE_SEARCH ioctl 的扩展版本,允许返回超过 4KB 的数据。
 * 通过 buf_size 指定缓冲区的分配大小。
 */
struct btrfs_ioctl_search_args_v2 {
	struct btrfs_ioctl_search_key key; /* 输入 / 输出 - 搜索参数 */
	__u64 buf_size;           /* 输入 - 缓冲区大小
	                           * 输出 - 若返回 EOVERFLOW: 表示存储所有 item 所需的大小 */
	__u64 buf[];              /* 输出 - 搜索到的条目 */
};

btrfs_ioctl_search_key

# btrfs_ioctl_space_args

struct btrfs_ioctl_space_args {
	__u64 space_slots;
	__u64 total_spaces;
	struct btrfs_ioctl_space_info spaces[];
};
struct btrfs_ioctl_space_info {
	__u64 flags; //flags 代表不同空间类型,参考下面的代码块
	__u64 total_bytes;
	__u64 used_bytes;
};
/* different types of block groups (and chunks) */
#define BTRFS_BLOCK_GROUP_DATA		(1ULL << 0)
#define BTRFS_BLOCK_GROUP_SYSTEM	(1ULL << 1)
#define BTRFS_BLOCK_GROUP_METADATA	(1ULL << 2)
#define BTRFS_BLOCK_GROUP_RAID0		(1ULL << 3)
#define BTRFS_BLOCK_GROUP_RAID1		(1ULL << 4)
#define BTRFS_BLOCK_GROUP_DUP		(1ULL << 5)
#define BTRFS_BLOCK_GROUP_RAID10	(1ULL << 6)
#define BTRFS_BLOCK_GROUP_RAID5         (1ULL << 7)
#define BTRFS_BLOCK_GROUP_RAID6         (1ULL << 8)
#define BTRFS_BLOCK_GROUP_RAID1C3       (1ULL << 9)
#define BTRFS_BLOCK_GROUP_RAID1C4       (1ULL << 10)
#define BTRFS_BLOCK_GROUP_RESERVED	(BTRFS_AVAIL_ALLOC_BIT_SINGLE | \
					 BTRFS_SPACE_INFO_GLOBAL_RSV)
#define BTRFS_BLOCK_GROUP_TYPE_MASK	(BTRFS_BLOCK_GROUP_DATA |    \
					 BTRFS_BLOCK_GROUP_SYSTEM |  \
					 BTRFS_BLOCK_GROUP_METADATA)
#define BTRFS_BLOCK_GROUP_PROFILE_MASK	(BTRFS_BLOCK_GROUP_RAID0 |   \
					 BTRFS_BLOCK_GROUP_RAID1 |   \
					 BTRFS_BLOCK_GROUP_RAID1C3 | \
					 BTRFS_BLOCK_GROUP_RAID1C4 | \
					 BTRFS_BLOCK_GROUP_RAID5 |   \
					 BTRFS_BLOCK_GROUP_RAID6 |   \
					 BTRFS_BLOCK_GROUP_DUP |     \
					 BTRFS_BLOCK_GROUP_RAID10)
#define BTRFS_BLOCK_GROUP_RAID56_MASK	(BTRFS_BLOCK_GROUP_RAID5 |   \
					 BTRFS_BLOCK_GROUP_RAID6)
#define BTRFS_BLOCK_GROUP_RAID1_MASK	(BTRFS_BLOCK_GROUP_RAID1 |   \
					 BTRFS_BLOCK_GROUP_RAID1C3 | \
					 BTRFS_BLOCK_GROUP_RAID1C4)

# btrfs_ioctl_scrub_args

#define BTRFS_SCRUB_READONLY	1
#define BTRFS_SCRUB_SUPPORTED_FLAGS	(BTRFS_SCRUB_READONLY)
struct btrfs_ioctl_scrub_args {
	__u64 devid;				/* 输入 */
	__u64 start;				/* 输入 */
	__u64 end;				/* 输入 */
	__u64 flags;				/* 输入 */
	struct btrfs_scrub_progress progress;	/* 输出 */
	/* 填充到 1K */
	__u64 unused[(1024-32-sizeof(struct btrfs_scrub_progress))/8];
};
/*
 * 向用户空间报告错误和进度的结构体,用于以下几种情况:
 * - scrub(校验 / 清理)操作完成后
 * - scrub 操作被取消时
 * - 用户主动查询 scrub 进度时
 */
struct btrfs_scrub_progress {
	__u64 data_extents_scrubbed;   /* 已校验的数据 extent 数量 */
	__u64 tree_extents_scrubbed;   /* 已校验的元数据(树) extent 数量 */
	__u64 data_bytes_scrubbed;     /* 已校验的数据字节数 */
	__u64 tree_bytes_scrubbed;     /* 已校验的元数据字节数 */
	__u64 read_errors;             /* 读取错误次数(例如 EIO 错误) */
	__u64 csum_errors;             /* 校验和(checksum)检查失败次数 */
	__u64 verify_errors;           /* 元数据校验失败次数,例如树块中的
	                                * generation(版本号)或逻辑地址不一致 */
	__u64 no_csum;                 /* 缺失校验和的 4K 数据块数量,可能由于写入时
	                                * 使用了 nodatasum 挂载选项 */
	__u64 csum_discards;           /* 检测到校验和项但未能在 extent 树中
	                                * 找到对应数据的次数 */
	__u64 super_errors;            /* 检测到损坏的超级块数量 */
	__u64 malloc_errors;           /* 内部 kmalloc 分配失败次数,这通常意味着
	                                * scrub 操作未能完整执行 */
	__u64 uncorrectable_errors;    /* 无法修复的错误次数:
	                                * 要么无法找到完好的副本,要么回写失败 */
	__u64 corrected_errors;        /* 已成功修复的错误数量 */
	__u64 last_physical;           /* 最后一次成功 scrub 的物理地址;
	                                * 如果 scrub 中断,可以用此值重启 */
	__u64 unverified_errors;       /* 未确认错误次数:
	                                * 指整块(64KB bio)读取失败,但逐个 4K
	                                * 分片重新校验后都通过,属于间歇性错误 */
};

# btrfs_ioctl_dev_info_args

#define BTRFS_UUID_SIZE 16
#define BTRFS_DEVICE_PATH_NAME_MAX	1024
struct btrfs_ioctl_dev_info_args {
	__u64 devid;				/* 输入 / 输出 */
	__u8 uuid[BTRFS_UUID_SIZE];		/* 输入 / 输出 */
	__u64 bytes_used;			/* 输出 */
	__u64 total_bytes;			/* 输出 */
	/*
 	 * 可选输出项(out)。
 	 *
 	 * 用于显示该设备的 fsid,允许用户空间检查该设备是否是一个 seeding 设备。
 	 *
 	 * 此字段在内核 v6.3 中引入,因此用户空间仍需检查内核是否修改了此值。
 	 * 较旧的内核版本不会修改这里的值。
 	 */
	__u8 fsid[BTRFS_UUID_SIZE];
	__u64 unused[377];			/* 填充到 4K */
	__u8 path[BTRFS_DEVICE_PATH_NAME_MAX];	/* 输出 */
};

seeding device:只读的「种子设备」,用于创建新文件系统的初始快照,不参与后续写操作。

# btrfs_ioctl_balance_args

/*
 * balance 的 flags 定义
 *
 * Restriper's general type filter
 *
 * 用于:
 * btrfs_ioctl_balance_args.flags
 * btrfs_balance_control.flags (internal)
 */
#define BTRFS_BALANCE_DATA		(1ULL << 0)
#define BTRFS_BALANCE_SYSTEM		(1ULL << 1)
#define BTRFS_BALANCE_METADATA		(1ULL << 2)
#define BTRFS_BALANCE_TYPE_MASK		(BTRFS_BALANCE_DATA |	    \
					 BTRFS_BALANCE_SYSTEM |	    \
					 BTRFS_BALANCE_METADATA)
#define BTRFS_BALANCE_FORCE		(1ULL << 3)
#define BTRFS_BALANCE_RESUME		(1ULL << 4)
/*
 * balance state 的 flags 定义
 *
 * 用于:
 * struct btrfs_ioctl_balance_args.state
 */
#define BTRFS_BALANCE_STATE_RUNNING	(1ULL << 0)
#define BTRFS_BALANCE_STATE_PAUSE_REQ	(1ULL << 1)
#define BTRFS_BALANCE_STATE_CANCEL_REQ	(1ULL << 2)
struct btrfs_ioctl_balance_args {
	__u64 flags;				/* 输入 / 输出 */
	__u64 state;				/* 输出 */
	struct btrfs_balance_args data;		/* 输入 / 输出 */
	struct btrfs_balance_args meta;		/* 输入 / 输出 */
	struct btrfs_balance_args sys;		/* 输入 / 输出 */
	struct btrfs_balance_progress stat;	/* 输出 */
	__u64 unused[72];			/* 填充至 1k */
};
/*
 * per-type balance args 的 flags 定义
 *
 * Balance filters
 *
 * 用于:
 * struct btrfs_balance_args
 */
#define BTRFS_BALANCE_ARGS_PROFILES	(1ULL << 0)
#define BTRFS_BALANCE_ARGS_USAGE	(1ULL << 1)
#define BTRFS_BALANCE_ARGS_DEVID	(1ULL << 2)
#define BTRFS_BALANCE_ARGS_DRANGE	(1ULL << 3)
#define BTRFS_BALANCE_ARGS_VRANGE	(1ULL << 4)
#define BTRFS_BALANCE_ARGS_LIMIT	(1ULL << 5)
#define BTRFS_BALANCE_ARGS_LIMIT_RANGE	(1ULL << 6)
#define BTRFS_BALANCE_ARGS_STRIPES_RANGE (1ULL << 7)
#define BTRFS_BALANCE_ARGS_USAGE_RANGE	(1ULL << 10)
#define BTRFS_BALANCE_ARGS_MASK			\
	(BTRFS_BALANCE_ARGS_PROFILES |		\
	 BTRFS_BALANCE_ARGS_USAGE |		\
	 BTRFS_BALANCE_ARGS_DEVID | 		\
	 BTRFS_BALANCE_ARGS_DRANGE |		\
	 BTRFS_BALANCE_ARGS_VRANGE |		\
	 BTRFS_BALANCE_ARGS_LIMIT |		\
	 BTRFS_BALANCE_ARGS_LIMIT_RANGE |	\
	 BTRFS_BALANCE_ARGS_STRIPES_RANGE |	\
	 BTRFS_BALANCE_ARGS_USAGE_RANGE)
/*
 * 此结构体使用了 packed(紧凑)属性,
 * 因为它必须与磁盘上的字节序对应结构体(struct btrfs_disk_balance_args)完全一致。
 */
struct btrfs_balance_args {
	__u64 profiles;
	/*
	 * 使用率过滤器
	 * 使用 BTRFS_BALANCE_ARGS_USAGE 且赋单个值表示使用率在 0 到 N 之间
	 * 使用 BTRFS_BALANCE_ARGS_USAGE_RANGE 表示范围语法,即 min 到 max
	 */
	union {
		__u64 usage;
		struct {
			__u32 usage_min; // 使用率下限(单位是百分比 * 100)
			__u32 usage_max;
		};
	};
	__u64 devid;
	__u64 pstart;
	__u64 pend;
	__u64 vstart;
	__u64 vend;
	__u64 target;
	__u64 flags;
	/*
	 * 使用 BTRFS_BALANCE_ARGS_LIMIT 且赋值 'limit'
	 * 或使用 BTRFS_BALANCE_ARGS_LIMIT_RANGE,支持最小值与最大值
	 */
	union {
		__u64 limit;		// 限制处理的数据块(chunk)数量
		struct {
			__u32 limit_min;
			__u32 limit_max;
		};
	};
	/*
	 * 处理跨越 stripes_min 到 stripes_max 个设备的数据块
	 * 使用 BTRFS_BALANCE_ARGS_STRIPES_RANGE
	 */
	__u32 stripes_min;
	__u32 stripes_max;
	__u64 unused[6];
} __attribute__ ((__packed__));
/* 向用户空间报告 balance 进度 */
struct btrfs_balance_progress {
	__u64 expected;		/* 预估为满足本次 balance 请求而需要迁移的数据块(chunk)数量 */
	__u64 considered;	/* 到目前为止已经被考虑处理的数据块数量 */
	__u64 completed;	/* 到目前为止已成功迁移的数据块数量 */
};

# btrfs_ioctl_ino_path_args

struct btrfs_ioctl_ino_path_args {
	__u64				inum;		/* 输入 */
	__u64				size;		/* 输入 */
	__u64				reserved[4];
	/* struct btrfs_data_container	*fspath;*/
	__u64				fspath;		/* 输出 */
};
struct btrfs_data_container {
	__u32 bytes_left;     /* 输出:未使用的字节数 —— 指输出结果所需空间少于提供的空间时,剩余的字节数 */
	__u32 bytes_missing;  /* 输出:结果还需要的额外字节数 —— 当提供的缓冲区不够用时,表示还缺多少字节 */
	__u32 elem_cnt;       /* 输出:实际返回的元素数量 */
	__u32 elem_missed;    /* 输出:因为空间不足而未返回的元素数量 */
	__u64 val[];          /* 输出:可变长度数组,用于存放返回的数据值(通常是 u64 类型的 ID 或其他值) */
};

# btrfs_ioctl_logical_ino_args

/*
 * Return every ref to the extent, not just those containing logical block.
 * Requires logical == extent bytenr.
 */
#define BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET	(1ULL << 0)
struct btrfs_ioctl_logical_ino_args {
	__u64				logical;	/* 输入 */
	__u64				size;		/* 输入 */
	__u64				reserved[3];	/* 目前必须为 0 */
	__u64				flags;		/* 输入,v2 only */
	/* struct btrfs_data_container	*inodes;	输出   */
	__u64				inodes;
};

参见 struct btrfs_data_container

# btrfs_ioctl_send_args

/*
 * 调用者不希望在发送流(send stream)中包含文件数据,即使在克隆源查找时找不到相应的数据块。
 * 此时将发送 UPDATE_EXTENT 指令,而不是 WRITE 指令。
 */
#define BTRFS_SEND_FLAG_NO_FILE_DATA        0x1
/*
 * 不添加流头部(stream header)。该选项用于连续发送多个快照时。
 */
#define BTRFS_SEND_FLAG_OMIT_STREAM_HEADER  0x2
/*
 * 省略发送流末尾用于标识结束的指令。
 * 该选项用于连续发送多个快照的场景。
 */
#define BTRFS_SEND_FLAG_OMIT_END_CMD        0x4
/*
 * 从结构体中读取协议版本。
 */
#define BTRFS_SEND_FLAG_VERSION             0x8
/*
 * 使用 ENCODED_WRITE 指令发送压缩数据,而不是先解压再用 WRITE 指令发送。
 * 需要协议版本 >= 2。
 */
#define BTRFS_SEND_FLAG_COMPRESSED          0x10
#define BTRFS_SEND_FLAG_MASK \
	(BTRFS_SEND_FLAG_NO_FILE_DATA | \
	 BTRFS_SEND_FLAG_OMIT_STREAM_HEADER | \
	 BTRFS_SEND_FLAG_OMIT_END_CMD | \
	 BTRFS_SEND_FLAG_VERSION | \
	 BTRFS_SEND_FLAG_COMPRESSED)
struct btrfs_ioctl_send_args {
	__s64 send_fd;			/* 输入 */
	__u64 clone_sources_count;	/* 输入 */
	__u64 __user *clone_sources;	/* 输入 */
	__u64 parent_root;		/* 输入 */
	__u64 flags;			/* 输入 */
	__u32 version;			/* 输入 */
	__u8  reserved[28];		/* 输入 */
};

# btrfs_ioctl_quota_ctl_args

#define BTRFS_QUOTA_CTL_ENABLE	1
#define BTRFS_QUOTA_CTL_DISABLE	2
#define BTRFS_QUOTA_CTL_RESCAN__NOTUSED	3
#define BTRFS_QUOTA_CTL_ENABLE_SIMPLE_QUOTA 4
struct btrfs_ioctl_quota_ctl_args {
	__u64 cmd;
	__u64 status;
};

# btrfs_ioctl_qgroup_assign_args

struct btrfs_ioctl_qgroup_assign_args {
	__u64 assign;
	__u64 src;
	__u64 dst;
};

# btrfs_ioctl_qgroup_create_args

struct btrfs_ioctl_qgroup_create_args {
	__u64 create;
	__u64 qgroupid;
};

# btrfs_ioctl_qgroup_limit_args

struct btrfs_ioctl_qgroup_limit_args {
	__u64	qgroupid;
	struct btrfs_qgroup_limit lim;
};

参见 struct btrfs_qgroup_limit

# btrfs_ioctl_quota_rescan_args

struct btrfs_ioctl_quota_rescan_args {
	__u64	flags;
	__u64   progress;
	__u64   reserved[6];
};

# btrfs_ioctl_get_dev_stats

enum btrfs_dev_stat_values {
	/* 磁盘 I/O 故障统计 */
	BTRFS_DEV_STAT_WRITE_ERRS,  /* 来自底层的写入错误(EIO 或 EREMOTEIO) */
	BTRFS_DEV_STAT_READ_ERRS,   /* 来自底层的读取错误(EIO 或 EREMOTEIO) */
	BTRFS_DEV_STAT_FLUSH_ERRS,  /* 来自底层的刷新错误(EIO 或 EREMOTEIO) */
	/* 间接反映 I/O 错误的统计数据 */
	BTRFS_DEV_STAT_CORRUPTION_ERRS, /* 校验和错误、bytenr 错误或内容非法:
	                                 * 表明数据块在读写过程中遭到破坏,
	                                 * 或写入 / 读取了错误的位置 */
	BTRFS_DEV_STAT_GENERATION_ERRS, /* 表示某些块可能尚未被写入 */
	BTRFS_DEV_STAT_VALUES_MAX       /* 统计值的最大数目(用于数组边界) */
};
/* 读取后重置统计数据;需要 SYS_ADMIN 权限 */
#define BTRFS_DEV_STATS_RESET (1ULL << 0)
/* 获取设备统计信息的结构体 */
struct btrfs_ioctl_get_dev_stats {
	__u64 devid;      /* 输入 - 要查询的设备 ID */
	__u64 nr_items;   /* 输入 / 输出 - 请求的统计项数量,返回实际填充的数量 */
	__u64 flags;      /* 输入 / 输出 - 控制标志,比如是否重置统计数据 */
	/* 输出值:各类错误计数 */
	__u64 values[BTRFS_DEV_STAT_VALUES_MAX];
	/*
	 * 此结构体被填充为 1032 字节。
	 * 原本意图是填充到 1024 字节,但在添加 flags 字段时未调整填充计算。
	 */
	__u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX];
};

# btrfs_ioctl_dev_replace_args

#define BTRFS_IOCTL_DEV_REPLACE_CMD_START			0
#define BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS			1
#define BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL			2
#define BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR			0
#define BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED		1
#define BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED		2
#define BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS		3
struct btrfs_ioctl_dev_replace_args {
	__u64 cmd;	/* 输入 */
	__u64 result;	/* 输出 */
	union {
		struct btrfs_ioctl_dev_replace_start_params start;
		struct btrfs_ioctl_dev_replace_status_params status;
	};	/* 输入 / 输出 */
	__u64 spare[64];
};
#define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS	0
#define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID	    1
struct btrfs_ioctl_dev_replace_start_params {
	__u64 srcdevid;	/* 输入,如果是 0, 使用 srcdev_name 来代替 */
	__u64 cont_reading_from_srcdev_mode;	/* 输入,使用上面定义的 #define */
	__u8 srcdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1];	/* 输入 */
	__u8 tgtdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1];	/* 输入 */
};
#define BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED	0
#define BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED		1
#define BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED		2
#define BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED		3
#define BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED		4
struct btrfs_ioctl_dev_replace_status_params {
	__u64 replace_state;	/* 输出,使用上面定义的 #define */
	__u64 progress_1000;	/* 输出,0 <= x <= 1000 */
	__u64 time_started;	/* 输出,是从 1-Jan-1970 开始的秒数 */
	__u64 time_stopped;	/* 输出,是从 1-Jan-1970 开始的秒数 */
	__u64 num_write_errors;	/* 输出 */
	__u64 num_uncorrectable_read_errors;	/* 输出 */
};

# btrfs_ioctl_same_args

struct btrfs_ioctl_same_args {
	__u64 logical_offset;   /* 输入 - 源文件中 extent 的起始偏移 */
	__u64 length;           /* 输入 - extent 的长度 */
	__u16 dest_count;       /* 输入 - info 数组中的目标文件数量 */
	__u16 reserved1;
	__u32 reserved2;
	struct btrfs_ioctl_same_extent_info info[];  /* 每个目标文件的去重信息 */
};
#define BTRFS_SAME_DATA_DIFFERS	1
/* 用于 extent-same ioctl */
struct btrfs_ioctl_same_extent_info {
	__s64 fd;               /* 输入 - 目标文件的文件描述符 */
	__u64 logical_offset;   /* 输入 - 目标文件中 extent 的起始偏移 */
	__u64 bytes_deduped;    /* 输出 - 实际成功去重的字节数 */
	/* 本次去重操作的状态:
	 * 0 表示成功去重
	 * 小于 0 表示发生错误
	 * 等于 BTRFS_SAME_DATA_DIFFERS 表示数据不一致,不能去重
	 */
	__s32 status;           /* 输出 - 状态值,含义如上 */
	__u32 reserved;
};

# btrfs_ioctl_feature_flags

/*
 * feature flags
 *
 * 用于:
 * struct btrfs_ioctl_feature_flags
 */
#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE		(1ULL << 0)
/*
 * 在大端系统上,旧版内核(< 4.9)会生成损坏的空闲空间树位图,
 * 而 btrfs-progs 工具(版本 < 4.7.3)也可能破坏空闲空间树。
 * 如果该位被清除(为 0),则表示空闲空间树不可信。
 * btrfs-progs 也可以有意清除此位,以请求内核重建空闲空间树,
 * 但对于不了解该位的旧内核,此操作可能无效。
 * 如果不确定,建议在首次挂载时手动清除缓存,
 * 尤其是在启动旧版本内核时。
 */
#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID	(1ULL << 1)
#define BTRFS_FEATURE_COMPAT_RO_VERITY			(1ULL << 2)
/*
 * 将所有块组项放入专用的块组树中,
 * 由于更好的局部性,这可以大大减少大文件系统的挂载时间。
 */
#define BTRFS_FEATURE_COMPAT_RO_BLOCK_GROUP_TREE	(1ULL << 3)
#define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF	(1ULL << 0)
#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL	(1ULL << 1)
#define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS	(1ULL << 2)
#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO	(1ULL << 3)
#define BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD	(1ULL << 4)
/*
 * 较早的内核曾尝试使用更大的元数据块,
 * 但相关代码存在很多问题。我们不再允许它们继续尝试。
 */
#define BTRFS_FEATURE_INCOMPAT_BIG_METADATA	(1ULL << 5)
#define BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF	(1ULL << 6)
#define BTRFS_FEATURE_INCOMPAT_RAID56		(1ULL << 7)
#define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA	(1ULL << 8)
#define BTRFS_FEATURE_INCOMPAT_NO_HOLES		(1ULL << 9)
#define BTRFS_FEATURE_INCOMPAT_METADATA_UUID	(1ULL << 10)
#define BTRFS_FEATURE_INCOMPAT_RAID1C34		(1ULL << 11)
#define BTRFS_FEATURE_INCOMPAT_ZONED		(1ULL << 12)
#define BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2	(1ULL << 13)
#define BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE	(1ULL << 14)
#define BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA	(1ULL << 16)
struct btrfs_ioctl_feature_flags {
	__u64 compat_flags;
	__u64 compat_ro_flags;
	__u64 incompat_flags;
};

# btrfs_ioctl_get_subvol_rootref_args

#define BTRFS_MAX_ROOTREF_BUFFER_NUM 255
struct btrfs_ioctl_get_subvol_rootref_args {
		/* 输入 / 输出,用于指定要搜索的 rootref 的最小 treeid */
		__u64 min_treeid;
		/* 输出 */
		struct {
			__u64 treeid;
			__u64 dirid;
		} rootref[BTRFS_MAX_ROOTREF_BUFFER_NUM];
		/* 输出,找到的项的数量 */
		__u8 num_items;
		__u8 align[7];
};

# btrfs_ioctl_ino_lookup_user_args

#define BTRFS_VOL_NAME_MAX 255
#define BTRFS_INO_LOOKUP_USER_PATH_MAX (4080 - BTRFS_VOL_NAME_MAX - 1)
struct btrfs_ioctl_ino_lookup_user_args {
	/* 输入,包含'subvolid' 所对应子卷的 inode 编号 */
	__u64 dirid;
	/* 输入 */
	__u64 treeid;
	/* 输出,指定 'treeid' 的子卷名称 */
	char name[BTRFS_VOL_NAME_MAX + 1];
	/* 输出,从调用该 ioctl 的目录到指定 dirid 所构建的路径 */
	char path[BTRFS_INO_LOOKUP_USER_PATH_MAX];
};

# btrfs_ioctl_encoded_io_args

/*
 * 用于编码读写的数据和元数据。
 *
 * 编码 I/O (Encoded I/O) 会绕过文件系统自动执行的任何编码操作(例如压缩)。
 * 这可以用于读取文件的压缩内容,或直接将预压缩数据写入文件。
 *
 * BTRFS_IOC_ENCODED_READ 和 BTRFS_IOC_ENCODED_WRITE 本质上类似于
 * preadv/pwritev,但额外携带了有关数据编码方式和未编码数据大小的元信息。
 *
 * BTRFS_IOC_ENCODED_READ 会将编码数据填入提供的 iovec 中,填充元数据字段,
 * 并返回编码数据的大小。每次调用读取一个 extent。它也可以读取未编码数据。
 *
 * BTRFS_IOC_ENCODED_WRITE 使用元数据字段,从 iovec 中写入编码数据,并返回编码数据的大小。
 * 注意:写入时不会验证编码数据是否有效;如果数据无效(例如无法解压),则后续读取可能会返回错误。
 *
 * 由于文件系统的页缓存中保存的是解码后的数据,因此编码 I/O 会绕过页缓存。
 * 编码 I/O 需要 CAP_SYS_ADMIN 权限。
 */
struct btrfs_ioctl_encoded_io_args {
	/* 读写操作的输入参数 */
	/*
	 * 包含编码数据的 iovec 数组。
	 *
	 * 对于读取操作,如果编码数据大小大于所有 iov [n].iov_len (0 <= n < iovcnt) 的总和,
	 * 则 ioctl 调用失败并返回 ENOBUFS。
	 *
	 * 对于写入操作,编码数据的大小为所有 iov [n].iov_len 的总和(0 <= n < iovcnt)。
	 * 必须小于 128 KiB(未来可能放宽限制),也必须小于等于 unencoded_len。
	 */
	const struct iovec __user *iov;
	/* iovec 数组中的元素数量 */
	unsigned long iovcnt;
	/*
	 * 文件偏移量
	 *
	 * 对于写操作,必须对齐到文件系统的扇区大小。
	 */
	__s64 offset;
	/* 当前必须为零 */
	__u64 flags;
	/*
	 * 以下字段为读取操作的输出参数,包含返回的编码数据元信息;
	 * 对于写入操作,这些字段必须由用户设置为编码数据的元信息。
	 */
	/*
	 * 文件中数据的长度
	 *
	 * 必须小于等于 unencoded_len - unencoded_offset。
	 * 对于写操作,除非数据末尾位于或超出文件当前末尾,否则必须对齐到扇区大小。
	 */
	__u64 len;
	/*
	 * 未编码(即解密解压后)的数据长度。
	 *
	 * 对于写操作,不能超过 128 KiB(未来可能放宽限制)。
	 * 如果实际未编码数据长于 unencoded_len,则会被截断;
	 * 若短于该值,则使用 0 填充。
	 */
	__u64 unencoded_len;
	/*
	 * 从未编码数据首字节到文件中逻辑数据首字节的偏移。
	 *
	 * 必须小于 unencoded_len。
	 */
	__u64 unencoded_offset;
	/*
	 * BTRFS_ENCODED_IO_COMPRESSION_* 类型。
	 *
	 * 对于写操作,不能为 BTRFS_ENCODED_IO_COMPRESSION_NONE。
	 */
	__u32 compression;
	/* 当前总是 BTRFS_ENCODED_IO_ENCRYPTION_NONE */
	__u32 encryption;
	/*
	 * 为将来扩展预留
	 *
	 * 对于读取操作,总是返回为零。用户应检查是否有非零字节,
	 * 如果有,说明内核使用了结构体的新版本,包含用户定义中缺失的附加信息。
	 *
	 * 对于写操作,必须将其清零。
	 */
	__u8 reserved[64];
};
/* 数据未压缩 */
#define BTRFS_ENCODED_IO_COMPRESSION_NONE 0
/* 数据作为单个 zlib 流进行压缩。 */
#define BTRFS_ENCODED_IO_COMPRESSION_ZLIB 1
/*
 * 数据作为单个 zstd 帧进行压缩,并且 windowLog 压缩参数设置为不超过 17。
 */
#define BTRFS_ENCODED_IO_COMPRESSION_ZSTD 2
/*
 * 数据按扇区逐个压缩(使用常量名称中指示的扇区大小),
 * 使用 LZO1X 压缩,并以 fs/btrfs/lzo.c 中文档化的格式进行包装。
 * 对于写操作,压缩扇区大小必须与文件系统的扇区大小匹配。
 */
#define BTRFS_ENCODED_IO_COMPRESSION_LZO_4K 3
#define BTRFS_ENCODED_IO_COMPRESSION_LZO_8K 4
#define BTRFS_ENCODED_IO_COMPRESSION_LZO_16K 5
#define BTRFS_ENCODED_IO_COMPRESSION_LZO_32K 6
#define BTRFS_ENCODED_IO_COMPRESSION_LZO_64K 7
#define BTRFS_ENCODED_IO_COMPRESSION_TYPES 8
/* 数据未加密 */
#define BTRFS_ENCODED_IO_ENCRYPTION_NONE 0
#define BTRFS_ENCODED_IO_ENCRYPTION_TYPES 1

# 详细描述

# BTRFS_IOC_SNAP_CREATE_V2

为一个子卷创建一个快照。

FieldDescription
ioctl fd创建新快照的目录的文件描述符
ioctl argsstruct btrfs_ioctl_vol_args_v2
args.fd表示要快照的子卷中任意目录的文件描述符,必须位于同一个文件系统上
args.transid该字段会被忽略
args.flags可以设置为 BTRFS_SUBVOL_RDONLY 的任意子集来使新快照只读,或设置为 BTRFS_SUBVOL_QGROUP_INHERIT 来应用 qgroup_inherit 字段
args.name新子卷在 ioctl fd 指定的目录下的名称

# BTRFS_IOC_SCAN_DEV

扫描指定设备并将其注册到文件系统模块中,以便在挂载时自动关联设备和文件系统。此操作针对的是控制设备,而不是已挂载文件系统中的文件。可以安全地重复调用同一设备路径。

FieldDescription
ioctl fd控制设备的文件描述符 /dev/btrfs-control
ioctl argsstruct btrfs_ioctl_vol_args
args.fd该字段会被忽略
args.name设备的绝对路径

# BTRFS_IOC_SYNC

sync() 系统调用一样同步文件系统数据,另外会唤醒内部事务线程,从而触发子卷清理或队列碎片整理等操作。

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl argsNULL

# BTRFS_IOC_ADD_DEV

将指定的块设备添加到文件系统。与命令 btrfs device add 不同的是,这个操作不会执行任何安全检查(例如:该设备上是否已有其他文件系统)、也不会进行设备预处理(比如 TRIM 操作或重置分区区域),因此请谨慎使用

这是一个文件系统独占操作,如果当前文件系统已有其他实例正在运行,这个操作将会失败。但有一个例外:当系统处于 “平衡操作(balance)已暂停” 的状态时,仍然可以执行该操作。

所需权限: CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl argsstruct btrfs_ioctl_vol_args
args.fd该字段会被忽略
args.name要被添加的块设备的绝对路径

# BTRFS_IOC_RM_DEV

*(Linux v3.0 引入,v4.7 过时)* 从文件系统中移除指定路径的设备,或者通过特殊路径 "cancel" 取消正在进行的设备删除操作。

这是一个文件系统独占操作,如果已有其他操作在运行,则该操作会失败。

执行此操作需要权限:CAP_SYS_ADMIN。

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl argsstruct btrfs_ioctl_vol_args
args.fd该字段会被忽略
args.name要被删除的块设备的绝对路径 或 字符串 *“cancel”*

# BTRFS_IOC_INO_LOOKUP

解析 inode 号为路径(需要 CAP_SYS_ADMIN 权限),或读取给定文件所属的子卷 ID(此为特殊情况,不受权限限制)。由于路径名缓冲区的大小小于 PATH_MAX(4096 字节),因此路径有可能会被截断。该功能也可以通过 btrfs inspect-internal rootid 实现。

一般情况下,此操作需要 CAP_SYS_ADMIN 权限,并且可以将任意文件解析为其路径。而用于读取所属子卷的特殊情况则不受权限限制:

struct btrfs_ioctl_ino_lookup_args args;
fd = open("file", ...);
args.treeid = 0;
args.objectid = BTRFS_FIRST_FREE_OBJECTID;
ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
/* args.treeid now contains the subvolume id */
FieldDescription
ioctl fd待寻找子卷 id 的文件或目录的文件描述符
ioctl argsstruct btrfs_ioctl_ino_lookup_args
args.treeid用于路径解析的子卷 ID(需要 CAP_SYS_ADMIN 权限);如果设置为 0,则使用包含该 fd 的子卷。
args.objectid要查询的 inode 号,对应于 INODE_REF_KEYkey.objectid 。或者,作为特殊情况,设置为 BTRFS_FIRST_FREE_OBJECTID 以仅读取树 ID 并清空 args.name 缓冲区。
args.name相对于顶层子卷的路径,或留空字符串。

# BTRFS_IOC_DEFAULT_SUBVOL

将指定的子卷 ID 设置为默认子卷,当挂载该文件系统时如果未指定 subvol=路径subvolid=ID 选项,则挂载此默认子卷。

FieldDescription
ioctl fd用于在其内部创建新快照的目录的文件描述符
ioctl args要设置为默认子卷的子卷数字值 (uint64_t)

# BTRFS_IOC_SUBVOL_CREATE_V2

(3.6 版本引入) 创建一个新的子卷, qgroup inheritancelimits 可以被指定。

FieldDescription
ioctl fd新子卷的父目录的文件描述符
ioctl argsstruct btrfs_ioctl_vol_args_v2
args.fd该字段会被忽略
args.transid该字段会被忽略
args.flags要在子卷上设置的 flags, BTRFS_SUBVOL_RDONLY 表示只读, BTRFS_SUBVOL_QGROUP_INHERIT 表示要处理 qgroup 相关的字段
args.sizeargs.qgroup_inherit 中的条目数
args.qgroup_inherit继承给定的配额组(qgroups (struct btrfs_qgroup_inherit) )和 limits (struct btrfs_qgroup_limit)
name子卷的名字,尽管缓冲区已经几乎能到达 4KB,但是 Linux VFS 限制了文件名长度最大为 255 个字符且不能包含斜杠( /

# BTRFS_IOC_SUBVOL_GETFLAGS

读取一个子卷的 flags。返回的 flags 要么是 0,要么是 BTRFS_SUBVOL_RDONLY

FieldDescription
ioctl fd要检查的子卷的文件描述符
ioctl argsuint64_t

# BTRFS_IOC_SUBVOL_SETFLAGS

设置一个子卷的 flags。

FieldDescription
ioctl fd要改变的子卷的文件描述符
ioctl argsuint64_t,要么是 0,要么是 BTRFS_SUBVOL_RDONLY

# BTRFS_IOC_GET_FSLABEL

将文件系统的标签读取到给定的缓冲区中,也可以从 /sys/fs/btrfs/FSID/label 中读取,但这需要知道该文件系统的 FSID

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argschar buffer[BTRFS_LABEL_SIZE]

# BTRFS_IOC_SET_FSLABEL

将文件系统的标签设置为给定的缓冲区内容。最大长度包括终止的 NUL 字符。或者,也可以通过写入 /sys/fs/btrfs/FSID/label 来设置标签,但这需要知道文件系统的 FSID(并且在更改永久生效之前需要显式提交)。

所需权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argschar buffer[BTRFS_LABEL_SIZE]

# BTRFS_IOC_FS_INFO

读取文件系统的内部信息。数据可以双向交换,部分结构可以选择性填充。保留的字节可用于获取新的信息,但始终取决于设置的标志。

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_fs_info_args

# BTRFS_IOC_GET_SUBVOL_INFO

获取一个子卷的信息。

FieldDescription
ioctl fd要检查的子卷的文件描述符
ioctl argsstruct btrfs_ioctl_get_subvol_info_args

# BTRFS_IOC_SNAP_DESTROY_V2

销毁一个子卷,该子卷可能是也可能不是快照。

FieldDescription
ioctl fd如果 flags 不包括 BTRFS_SUBVOL_SPEC_BY_ID ,或者在非 root 用户命名空间中执行,参数 fd 为包含要删除的子卷的父目录的文件描述符;否则, fd 为要删除的子卷在同一文件系统中的任何目录的文件描述符,但不在同一子卷中
ioctl argsstruct btrfs_ioctl_vol_args_v2
args.fd该字段会被忽略
args.transid该字段会被忽略
args.flags如果通过 name 字段用指定目录中的名称标识子卷,则为 0;如果用 subvolid 字段指定子卷的 ID,则为 BTRFS_SUBVOL_SPEC_BY_ID
args.name仅当 flags 不包含 BTRFS_SUBVOL_SPEC_BY_ID 时有用,指定要删除的子卷的名称(在参数 fd 所标识的目录中)
args.subvolid只有在 flags 包含 BTRFS_SUBVOL_SPEC_BY_ID 时有用,指定要删除的子卷的子卷 ID

# BTRFS_IOC_SUBVOL_SYNC_WAIT

(自内核 6.13 起) 等待一个已删除的子卷被清理完成,或查询其当前状态。

该 ioctl 提供多种操作模式,其中最常见的是:等待特定子卷的清理完成,或等待所有当前排队待清理的子卷。例如,备份程序在删除子卷后会使用该功能,等待其真正被清理,以确认磁盘空间是否已释放。

其他模式则提供更高的灵活性,比如用于监控或在子卷删除队列中设置 “检查点”,而无需使用 SEARCH_TREE 操作。

注意事项:

  • 等待操作是可中断的,超时时间为 1 秒,且该值不可配置。
  • 多次调用该 ioctl 会看到不同的状态,因此在使用 “计数” 或 “查看下一个 / 最后一个” 等模式时存在竞争条件(racy)。

使用场景(常量定义详见此处):

  • 某个子卷 A 被删除后,等待其清理完成( WAIT_FOR_ONE
  • 一批子卷被删除后,等待所有清理完成( WAIT_FOR_QUEUEDPEEK_LAST + WAIT_FOR_ONE
  • 统计当前待清理子卷的数量(非阻塞),用于监控目的
  • 报告清理进度(使用 PEEK_NEXT ),若清理太快可能会遗漏部分子卷
  • 在用户空间自行实现等待逻辑(持续使用 PEEK_LAST ,直到其返回 0)
FieldDescription
ioctl fdBtrfs 文件系统中的任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_subvol_wait
args.subvolid依赖于具体的模式,指定是要等待的子卷的数字 id,还是 PEEK 模式查询的子卷的数字 id
args.mode上述描述的操作模式
args.count如果 mode 设置为 COUNT ,则为排队等待清理的子卷数量

# BTRFS_IOC_DEFRAG

对文件或目录执行碎片整理(defragmentation)。

对目录操作所需权限: CAP_SYS_ADMIN

对文件操作所需权限:对该 inode 具有 “写权限”。

BTRFS_IOC_DEFRAGinclude/uapi/linux/btrfs.h 中的参数定义为:

#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
				   struct btrfs_ioctl_vol_args)

然而实际上在 fs/btrfs/ioctl.c 的具体实现为:

case BTRFS_IOC_DEFRAG:
	return btrfs_ioctl_defrag(file, NULL);
case BTRFS_IOC_DEFRAG_RANGE:
	return btrfs_ioctl_defrag(file, argp);

可见 BTRFS_IOC_DEFRAGBTRFS_IOC_DEFRAG_RANGE 最终都调用了 btrfs_ioctl_defrag,且 btrfs_ioctl_defrag 实际的调用参数是 NULL ,与声明不符,这是一个 “历史遗留” 问题,在早期 BTRFS_IOC_DEFRAG 确实使用 btrfs_ioctl_vol_args 参数,但是后来,这个 ioctl 的处理方式发生了变化,用户空间传参变得 “可选”,允许传一个更详细的结构体 struct btrfs_ioctl_defrag_range_args ,这里不变只是为保持 ioctl 编号一致性的一个声明。

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl args该字段会被忽略

# BTRFS_IOC_DEFRAG_RANGE

对文件或目录执行碎片整理(新接口,可以提供更细颗粒度的管理)

对目录操作所需权限: CAP_SYS_ADMIN

对文件操作所需权限:对该 inode 具有 “写权限”。

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl argsstruct btrfs_ioctl_defrag_range_args
args.start碎片整理操作的起始位置
args.len要进行碎片整理的字节数,使用 (u64)-1 表示所有
args.flags操作的标记,包括开启压缩功能等
args.extent_thresh任何大于该值的 extent(连续块)会被认为已经整理过;0 表示使用内核默认值,1 表示必须重写所有范围
args.compress_type如果为该磁盘碎片操作开启压缩功能,应使用哪种压缩方法。如果未指定,将使用 zlib
args.unused备用

# BTRFS_IOC_RESIZE

调整(resize)某个 Btrfs 设备的容量大小。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl argsstruct btrfs_ioctl_vol_args
args.fd该字段会被忽略
args.name见下表

args.name 的含义见下表

args.name含义
"max"将设备扩容到其最大容量
"+10G"当前设备扩容 10 GB
"1:+5G"devid=1 的设备扩容 5 GB
"2:-1T"devid=2 的设备缩小 1 TB
"cancel"取消当前 resize 操作

# BTRFS_IOC_CLONE

用于提供 CoW 文件系统的 clone 支持。

这里的 “clone”,指的是 文件数据块级的 “写时复制”(Copy-on-Write, COW)克隆操作,它让你在两个文件之间共享物理存储数据而不进行真正的数据复制。简单来说就是:“把一个文件的一段内容,映射到另一个文件中相同长度的位置 —— 如果没人改动,两个文件用的是同一块磁盘空间;只有修改时,才会触发真正的复制。”

早期用于兼容的通用接口,该接口等价于内核中的 FICLONE 命令。 FICLONE 命令是 Linux 4.5 之后内核中引入的用于支持所有 CoW(Copy-on-Write)文件系统的命令,所以在这之后,该接口就被 FICLONE 代替了。Btrfs 在 btrfs_ioctl()没有专门实现 BTRFS_IOC_CLONE ,而是统一走 VFS 层的 FICLONE 分发逻辑,VFS 会调用 Btrfs 的 btrfs_remap_file_range() ,最终执行 clone 逻辑。调用路径为: ioctl_file_clonevfs_clone_file_rangebtrfs_remap_file_range

# BTRFS_IOC_CLONE_RANGE

FICLONE 的扩展,用于将一个文件中的指定范围的数据 clone 到另一个文件的指定位置,提供了比 FICLONE 更灵活的 克隆部分范围的能力

BTRFS_IOC_CLONE 一样, BTRFS_IOC_CLONE_RANGE 也是 btrfs 早期实现的,后被又被 VFS 统一的实现的 FICLONERANGE 所替代,现在在 Btrfs 代码中已经没有专门的实现了,而是走 VFS 层的 FICLONERANGE 分发逻辑,调用路径为: ioctl_file_clone_rangeioctl_file_clonevfs_clone_file_rangebtrfs_remap_file_range

# BTRFS_IOC_FILE_EXTENT_SAME

在支持 CoW 的文件系统上,可以使用此 ioctl 来让两个数据相同的文件使用同一份物理存储(相当于删除重复数据)。早期仅在 Btrfs 内实现,在 Linux 4.5 后由 VFS 统一实现并分发,调用路径为: ioctl_file_dedupe_rangevfs_dedupe_file_rangevfs_dedupe_file_range_onebtrfs_remap_file_range

Linux v3.0 引入,v3.16 过时)搜索 Btrfs 的元数据树。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl argsstruct btrfs_ioctl_search_args
args.key搜索配置,字段请参考 struct btrfs_ioctl_search_key
args.buf搜索到的条目

# BTRFS_IOC_TREE_SEARCH_V2

自内核 3.16 起)搜索 Btrfs 的元数据树。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl argsstruct btrfs_ioctl_search_args_V2
args.key搜索配置,字段请参考 struct btrfs_ioctl_search_key
args.buf_sizebuffer 缓冲区大小;若返回 EOVERFLOW,表示 buffer 空间不足,则该项存储所有 item 所需的大小
args.buf搜索到的条目

# BTRFS_IOC_SPACE_INFO

查询磁盘空间使用情况(包括数据区、元数据区、系统区、RAID 分布情况等)。

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl argsstruct btrfs_ioctl_space_args
args.space_slots用户请求的条目数量(0 表示只想获取总数)
args.total_spaces实际返回的空间条目数量
args.spaces空间条目的内存区,参考 struct btrfs_ioctl_space_info

可返回的空间类型包括:

static const u64 types[] = {
		BTRFS_BLOCK_GROUP_DATA,
		BTRFS_BLOCK_GROUP_SYSTEM,
		BTRFS_BLOCK_GROUP_METADATA,
		BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA
};

# BTRFS_IOC_START_SYNC

强制触发一次子卷事务(transaction)提交,并返回该次提交(或最近一次提交)的 transaction ID 给用户。

FieldDescription
ioctl fd待同步的子卷的文件 / 目录的文件描述符
ioctl argsuint64_t,事务 ID;如果当前没有进行中的事务,则返回的是上一次的 transaction ID

# BTRFS_IOC_WAIT_SYNC

等待指定的事务 ID(transaction ID)提交完成,如果没有指定,则等待当前正在提交的事务完成。

FieldDescription
ioctl fd等待的子卷的文件 / 目录的文件描述符
ioctl argsuint64_t,事务 ID;如果为 NULL,表示等待当前活跃的事务完成

# BTRFS_IOC_SCRUB

对一个 Btrfs 设备进行 scrub(校验和修复)操作,主要用于数据完整性检查。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl argsstruct btrfs_ioctl_scrub_args
args.device目标设备 ID,0 表示默认设备,也可用 BTRFS_IOC_DEV_INFO 获取设备列表
args.start开始偏移,0 表示从设备起始位置
args.end结束偏移
args.flags控制行为,目前只有两个:0 表示读写(校验 + 修复),1 表示只读(只校验不修复)
args.progress记录 scrub 的错误或进度信息,具体请参考 struct btrfs_scrub_progress

# BTRFS_IOC_SCRUB_CANCEL

取消正在运行的 scrub 操作。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl argsNULL

# BTRFS_IOC_SCRUB_PROGRESS

获取 scrub 进度信息。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl argsstruct btrfs_ioctl_scrub_args
args.device目标设备 ID,0 表示默认设备,也可用 BTRFS_IOC_DEV_INFO 获取设备列表
args.start无需填充,由内核填写,表示 scrub 的开始偏移
args.end无需填充,由内核填写,表示 scrub 的结束偏移
args.flags无需填充,由内核填写,表示行为标志
args.progress无需填充,由内核填写,记录 scrub 的错误或进度信息,具体请参考 struct btrfs_scrub_progress

# BTRFS_IOC_DEV_INFO

获取指定 Btrfs 设备的基本信息(设备 ID、使用空间、总空间、UUID、挂载路径等)。

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl argsstruct btrfs_ioctl_dev_info_args
args.devid指定设备 ID
args.uuid指定设备的 UUID,若 uuid 不为全零,就使用 uuid 查找;否则就使用 devid 查找
args.bytes_used无需填充,由内核填写,表示设备已使用了多少字节
args.total_bytes无需填充,由内核填写,表示设备总可用字节数
args.fsid无需填充,由内核填写,表示文件系统的唯一标识符(此字段在内核 v6.3 中引入)
args.path无需填充,由内核填写,表示设备的挂载路径(或设备名称)

# BTRFS_IOC_ENCODED_READ

以用户指定的格式(可能包括压缩)从 Btrfs 文件系统中读取一个数据范围,并将其写入用户空间的 iovec 缓冲区中,这个读取是按块读取原始数据的。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fd要读取的文件的文件描述符
ioctl argsstruct btrfs_ioctl_encoded_io_args
args.iov用户空间 iovec 数组地址,用于接收数据
args.iovcntiovec 数组的数量
args.offset文件偏移
args.flags目前必须为 0
args.len要读取的长度
args.unencoded_len未编码(例如解密、解压后)的数据长度
args.unencoded_offset从未编码数据首字节到文件中逻辑数据首字节的偏移
args.compression返回压缩算法类型,类型参考 BTRFS_ENCODED_IO_COMPRESSION_*
args.encryption目前必须是 BTRFS_ENCODED_IO_ENCRYPTION_NONE
args.reserved保留项

# BTRFS_IOC_ENCODED_WRITE

向文件中写入已编码(通常压缩过)的原始数据块,常用于备份恢复、数据迁移等低层次的操作。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fd要写入的文件的文件描述符
ioctl argsstruct btrfs_ioctl_encoded_io_args
args.iov用户空间 iovec 数组地址,用于写入数据
args.iovcntiovec 数组的数量
args.offset文件偏移,指定从何处开始写,必须扇区对齐
args.flags目前必须为 0
args.len要写入的逻辑数据长度(解压后的大小),必须扇区对齐
args.unencoded_len未编码(例如解密、解压后)的数据长度,必须小于 128KB(未来可能扩展)
args.unencoded_offset从未编码数据首字节到文件中逻辑数据首字节的偏移
args.compression目前必须为 BTRFS_ENCODED_IO_COMPRESSION_NONE
args.encryption目前必须是 BTRFS_ENCODED_IO_ENCRYPTION_NONE
args.reserved保留项,必须为 0

# BTRFS_IOC_GET_SUBVOL_ROOTREF

查询包含当前 inode 的子卷(subvolume)所对应的 ROOTREF 信息,但不返回子卷名称。

Btrfs 通过 “引用(root ref)” 来记录和管理子卷之间的关系,其定义为一组键值对(key-value):

  • key 的类型为 struct btrfs_key;

    //btrfs_key 是 btrfs 的一个通用核心结构,当其作为 root ref 项的 key 时,其 type 取值只能为注释中的两种。
    struct btrfs_key {
    	__u64 objectid;
    	__u8 type; // BTRFS_ROOT_REF_KEY 或 BTRFS_ROOT_BACKREF_KEY
    	__u64 offset;
    } __attribute__ ((__packed__));
  • value 的类型为 struct btrfs_root_ref;

    /*
     * this is used for both forward and backward root refs
     */
    struct btrfs_root_ref {
    	__le64 dirid;    // 父目录 Inode
    	__le64 sequence; // 在父目录中的目录索引
    	__le16 name_len; // 引用该子卷的目录项的名称长度
        /* 实际的名称字符串紧随其后(变长数据) */
    } __attribute__ ((__packed__));

当新创建一个子卷 / 快照时,会创建两个 ROOT REF 项,他们的作用是便于快速识别某个子卷或快照的父目录。每当创建一个子卷时,系统会创建两个 ROOT REF 项(一个用于前向引用(parent → child),一个用于反向引用(child → parent))。前向引用可以让我们快速定位子卷在目录中的挂载位置(即该子卷是在哪个目录下创建的),这在执行递归快照等操作时非常有用。反向引用则用于帮助恢复丢失的快照。

这两个 ROOT REF 项的 key 的字段含义是不同的,当代表前向引用时,key 字段的含义如下:

  • key.objectid = 父子卷的 id
  • key.type = BTRFS_ROOT_REF_KEY
  • key.offset = 新创建的子卷 / 快照的 id

当代表反向引用时,key 字段的含义如下:

  • key.objectid = 新创建的子卷 / 快照的 id
  • key.type = BTRFS_ROOT_REF_KEY
  • key.offset = 父子卷的 id
FieldDescription
ioctl fd指定子卷(或快照)内的任意文件或目录 的文件描述符
ioctl argsstruct btrfs_ioctl_get_subvol_rootref_args
args.min_treeid指定要搜索的 rootref 的最小 treeid,可用于分页搜索,执行后该项将替换为搜索的最后一个子树 ID, 这样就可以用该项执行继续搜索。
args.rootref.treeid无需填充,由内核填写,表示当前子卷引用的子卷 id
args.rootref.dirid无需填充,由内核填写,表示当前子卷引用的子卷的父目录 Inode
args.num_items无需填充,由内核填写,表示找到的项的数量

# BTRFS_IOC_INO_LOOKUP_USER

在用户态安全地获取某个 inode 的路径信息,专为 非特权用户(unprivileged user)设计,主要用于让用户程序安全地查询某个 inode 在文件系统中的路径。相比于 ino_lookup ioctl 的区别如下:

  1. 会调用 inode_permission() 检查路径构建过程中的执行权限( EXEC )和读取权限( READ ),没有权限就返回 -EACCES

  2. 路径的起点必须是打开的 fd 所指的 inode,构造路径只能在此子树中进行。如果路径跳出了这个范围(不是此目录下的某项),也返回 -EACCES

  3. 不仅查 inode 的路径,也会查到它所属的子卷的名字。

FieldDescription
ioctl fd包含待搜索 inode 的目录的文件描述符
ioctl argsstruct btrfs_ioctl_ino_lookup_user_args
args.dirid要查询的 inode 编号
args.treeid待查询的 inode 所在子卷的 tree ID
args.name无需填充,由内核填写,inode 所在的子卷名称
args.path无需填充,由内核填写,从调用该 ioctl 的目录到指定 dirid 所构建的路径

# BTRFS_IOC_BALANCE_V2

触发或恢复一次平衡(balance)操作,同一时间只能有一个 balance 操作正在执行。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中的任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_balance_args
args.flags控制标志,控制 balance 的具体行为,具体请参考 BTRFS_BALANCE_*
args.state无需填充,由内核填写,有三种状态,具体请参考 BTRFS_BALANCE_STATE_*
args.data控制针对用户数据块(data)的 balance 行为,具体请参考 struct btrfs_balance_args
args.meta控制针对元数据块(metadata)的 balance 行为,具体请参考 struct btrfs_balance_args
args.sys控制针对系统块(system)的 balance 行为,具体请参考 struct btrfs_balance_args
args.stat无需填充,由内核填写,表示 balance 的进度信息

# BTRFS_IOC_BALANCE_CTL

暂停或取消当前正在运行的 balance 操作的状态

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中的任意文件 / 目录的文件描述符
ioctl argsint,只能是两种值 BTRFS_BALANCE_CTL_PAUSEBTRFS_BALANCE_CTL_CANCEL
/* balance control ioctl modes */
#define BTRFS_BALANCE_CTL_PAUSE   1
#define BTRFS_BALANCE_CTL_CANCEL  2

# BTRFS_IOC_BALANCE_PROGRESS

获取当前 balance 操作的进度

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中的任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_balance_args
args.flags无需填充,由内核填写,控制标志,具体请参考 BTRFS_BALANCE_*
args.state无需填充,由内核填写,返回当前 balance 状态,具体请参考 BTRFS_BALANCE_STATE_*
args.data无需填充,由内核填写,返回用户数据块(data)的 balance 状态,具体请参考 struct btrfs_balance_args
args.meta无需填充,由内核填写,返回元数据块(metadata)的 balance 状态,具体请参考 struct btrfs_balance_args
args.sys无需填充,由内核填写,返回系统块(system)的 balance 状态,具体请参考 struct btrfs_balance_args
args.stat无需填充,由内核填写,表示 balance 的进度信息

# BTRFS_IOC_INO_PATHS

给定一个 inode 编号,查找它在文件系统中所有对应的路径(从根到该 inode 的路径名),由于多个目录项可能指向同一个 inode(如硬链接),所以该函数可能会返回多个路径。

需要权限:CAP_DAC_READ_SEARCH

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_ino_path_args
args.inum要查找路径的 inode 编号
args.size用户分配的输出缓冲区大小
args.reserved保留
args.fspath传入一个 buffer 用于接收数据,其实是一个 struct btrfs_data_container 指针,存储了路径信息(一系列偏移值,可以在偏移值处找到对应路径字符串)

# BTRFS_IOC_LOGICAL_INO

根据物理地址(logical block address)反查出使用这个地址的文件 inode。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_logical_ino_args
args.logical要查询的逻辑地址
args.size传入 buffer 的大小
args.reserved保留,目前必须为 0
args.flags该字段会被忽略,仅 BTRFS_IOC_LOGICAL_INO_V2 支持该参数
args.inodes传入一个 buffer 用于接收数据,其实是一个 struct btrfs_data_container 指针,存储查询结果

# BTRFS_IOC_SET_RECEIVED_SUBVOL

设置子卷的 “接收元信息”,例如该子卷是哪个父子卷衍生的、什么时候发送 / 接收的等等信息。

FieldDescription
ioctl fd指向接收子卷目录的文件描述符
ioctl argsstruct btrfs_ioctl_received_subvol_args
args.uuid发送方子卷的 uuid
args.stransid发送方子卷创建时的 transid
args.rtransid无需填充,由内核填写,表示接收方的 transid(本地记录)
args.stime发送方的快照创建时间
args.rtime无需填充,由内核填写,表示接收方的接收时间
args.flags该字段目前会被忽略,建议置 0
args.reserved保留

# BTRFS_IOC_SEND

将一个子卷快照的数据(相对于父子卷快照的增量或全量数据)发送到用户空间,以便可以传输到远程或另一个 Btrfs 文件系统上进行 receive 操作。

FieldDescription
ioctl fd待发送子卷根目录的文件描述符
ioctl argsstruct btrfs_ioctl_send_args
args.send_fd发送目标(用户空间进程会从这个 fd 读取快照内容)
args.clone_sources_count克隆源快照的数量
args.clone_sources指向多个 clone 源 subvol 的 ID 列表(用于增量复制)
args.parent_root父快照的 root id;0 表示是全量快照导出
args.flags控制选项,参考 BTRFS_SEND_FLAG_*
args.version接口版本号
args.reserved保留

# BTRFS_IOC_DEVICES_READY

检查设备是否准备就绪。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fd/dev/btrfs-control 的文件描述符
ioctl argsstruct btrfs_ioctl_vol_args
args.fd该字段会被忽略
args.name待检查的设备名称,例如: /dev/sdb

# BTRFS_IOC_QUOTA_CTL

提供对配额(quota)系统的启用和禁用控制。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_quota_ctl_args
args.cmd实际执行的指令,包括启用、禁止等,具体请参考 BTRFS_QUOTA_CTL_ENABLE*
args.status该字段会被忽略

# BTRFS_IOC_QGROUP_ASSIGN

在两个 quota group(配额组)之间建立或删除父子关系,以便子 qgroup 的空间使用能正确累加到父 qgroup 中,实现 “层次配额” 的管理。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_qgroup_assign_args
args.assign非零:添加关系,零:删除关系
args.src子配额组 ID
args.dst父配额组 ID

# BTRFS_IOC_QGROUP_CREATE

创建或删除一个配额组(quota group)。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_qgroup_create_args
args.create非零:创建,零:删除
args.qgroupid配额组 ID

# BTRFS_IOC_QGROUP_LIMIT

为某个 qgroup 设置配额限制,需要先开启配额功能。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fd要设置配额的子卷目录的文件描述符
ioctl argsstruct btrfs_ioctl_qgroup_limit_args
args.qgroupid0,表示 “当前子卷”,也就是用户打开的这个 file 所在的子卷;否则就使用用户提供的 qgroupid
args.lim配额限制参数,具体请参考 struct btrfs_qgroup_limit

# BTRFS_IOC_QUOTA_RESCAN

对整个文件系统重新扫描以更新 qgroup(配额组)信息,确保它们是最新和一致的,需要先开启配额功能。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_quota_rescan_args
args.flags必须为 0
args.progress该字段会被忽略

# BTRFS_IOC_QUOTA_RESCAN_STATUS

获取当前的 qgroup rescan(重新扫描)状态。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_quota_rescan_args
args.flags无需填充,由内核填写,1 表示 “正在扫描”,0 表示 “没有扫描正在进行”
args.progress无需填充,由内核填写,表示当前扫描状态,对应 objectid

# BTRFS_IOC_QUOTA_RESCAN_WAIT

等待 quota rescan (配额重新扫描)完成。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsNULL

# BTRFS_IOC_GET_DEV_STATS

获取块设备(device)的统计信息,比如 I/O 错误次数,同时也可以重置这些统计数据。

重置操作需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_get_dev_stats
args.devid要查询的设备 ID
args.nr_items输入:请求的统计项数量,输出:返回实际填充的数量
args.flags控制标志,例如是否重置统计数据
args.values无需填充,由内核填写,输出各项信息,具体请参考 BTRFS_DEV_STAT_*_ERRS

# BTRFS_IOC_DEV_REPLACE

在 Btrfs 文件系统中进行设备替换(device replace)操作,包括启动、查询状态、取消设备替换。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_dev_replace_args
args.cmd要执行的设备替换操作:start、status、cancel 等
args.result无需填充,由内核填写,表示执行结果,具体请参考 BTRFS_IOCTL_DEV_REPLACE_RESULT_*
args.start (union)若执行的是开始(start)操作,则需要填充替换设备的信息,结构为 btrfs_ioctl_dev_replace_start_params
args.status (union)若执行的是查询(status)操作,则该项由内核填充为状态信息,结构为 btrfs_ioctl_dev_replace_status_params

# BTRFS_IOC_GET_FEATURES

获取当前挂载文件系统支持的 feature 标志。

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_feature_flags
args.compat_flags无需填写,由内核填充,表示兼容特性,不支持这些特性的内核可以安全忽略这些特性
args.compat_ro_flags无需填写,由内核填充,表示只读兼容特性,不支持这些特性的内核只能挂载为只读
args.incompat_flags无需填写,由内核填充,表示不兼容特性,不支持这些特性的内核无法挂载

上述三个 flag 的可选值请参考 struct btrfs_ioctl_feature_flags

# BTRFS_IOC_SET_FEATURES

开启或关闭某些文件系统特性标志(features flags)。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_feature_flags[2]
args[0]要修改的标志位
args[1]掩码,表示用户想保留的位(其他位会被清空)

其中每个参数都是 struct btrfs_ioctl_feature_flags 类型,flags 含义可以参考 BTRFS_IOC_GET_FEATURES

# BTRFS_IOC_GET_SUPPORTED_FEATURES

获取内核支持的特性(features)。

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_feature_flags[2]
args[0]无需填写,由内核填充,表示哪些特性是当前内核支持的
args[1]无需填写,由内核填充,表示哪些特性可以安全启用(set)
args[1]无需填写,由内核填充,表示哪些特性可以安全关闭(clear)

# BTRFS_IOC_RM_DEV_V2

4.7 版本引入) 删除一个设备(比如一个 btrfs 多设备卷中的某个设备),或取消当前的设备删除操作。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件或目录的文件描述符
ioctl argsstruct btrfs_ioctl_vol_args_V2
args.fd该字段目前会被忽略
args.transid该字段目前会被忽略
args.flags控制标志,只能是空或 BTRFS_DEVICE_SPEC_BY_ID
args.size该字段目前会被忽略
args.qgroup_inherit该字段目前会被忽略
args.name (union)"cancel" :取消当前设备删除操作;或是要删除设备的路径
args.devid (union)要删除的设备 id,使能该项需要 flag 为 BTRFS_DEVICE_SPEC_BY_ID
args.subvolid (union)该项目前会被忽略

# BTRFS_IOC_LOGICAL_INO_V2

将某个逻辑地址(logical address)反查出它所属于的 inode(也就是哪个文件使用了这个物理块)。

需要权限:CAP_SYS_ADMIN

FieldDescription
ioctl fdBtrfs 文件系统中任意文件 / 目录的文件描述符
ioctl argsstruct btrfs_ioctl_logical_ino_args
args.logical要查询的逻辑地址
args.size传入 buffer 的大小
args.reserved保留,目前必须为 0
args.flags控制标志,目前只能是 BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET ,用于控制是否忽略 page offset。
args.inodes传入一个 buffer 用于接收数据,其实是一个 struct btrfs_data_container 指针,存储查询结果

V2 版本允许根据 logical address 查找整个 block(或 extents),而不仅仅是精确 offset 对应的那一块。这在某些情况很有用,比如你只知道大致逻辑地址,但不是 page-aligned 或不是精确的起始偏移。


更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Gality 微信支付

微信支付

Gality 支付宝

支付宝