[PATCH 3/3] Add btrfs ioctl support.

Jeff Mahoney jeffm at suse.com
Thu Mar 31 04:34:18 UTC 2016


* btrfs.c: New file.
* Makefile.am (strace_SOURCES): Add it.
* defs.h [LINUX] (btrfs_ioctl): New function.
* ioctls.c (ioctl_decode) [LINUX]: Use it to decode BTRFS_* ioctls.
* configure.ac: Add check for struct btrfs_ioctl_feature_flags.
  Add check for struct btrfs_ioctl_fs_info_args.nodesize.
  Add struct btrfs_ioctl_defrag_range_args.
* xlat/btrfs_balance_flags.in: New file.
* xlat/btrfs_defrag_flags.in: New file.
* xlat/btrfs_dev_replace_cmds.in: New file.
* xlat/btrfs_dev_replace_results.in: New file.
* xlat/btrfs_dev_replace_state.in: New file.
* xlat/btrfs_dev_stats_flags.in: New file.
* xlat/btrfs_dev_stats_values.in: New file.
* xlat/btrfs_features_compat_ro.in: New file.
* xlat/btrfs_features_incompat.in: New file.
* xlat/btrfs_key_types.in: New file.
* xlat/btrfs_qgroup_ctl_cmds.in: New file.
* xlat/btrfs_qgroup_inherit_flags.in: New file.
* xlat/btrfs_qgroup_limit_flags.in: New file.
* xlat/btrfs_qgroup_status_flags.in: New file.
* xlat/btrfs_scrub_flags.in: New file.
* xlat/btrfs_snap_flags_v2.in: New file.
* xlat/btrfs_space_info_flags.in: New file.
* xlat/btrfs_tree_objectids.in: New file.
---
 Makefile.am                        |    1 +
 btrfs.c                            | 1219 ++++++++++++++++++++++++++++++++++++
 configure.ac                       |    8 +
 defs.h                             |    1 +
 ioctl.c                            |    4 +
 xlat/btrfs_balance_flags.in        |   12 +
 xlat/btrfs_defrag_flags.in         |    2 +
 xlat/btrfs_dev_replace_cmds.in     |    3 +
 xlat/btrfs_dev_replace_results.in  |    4 +
 xlat/btrfs_dev_replace_state.in    |    5 +
 xlat/btrfs_dev_stats_flags.in      |    1 +
 xlat/btrfs_dev_stats_values.in     |   11 +
 xlat/btrfs_features_compat.in      |    0
 xlat/btrfs_features_compat_ro.in   |    1 +
 xlat/btrfs_features_incompat.in    |   10 +
 xlat/btrfs_key_types.in            |   40 ++
 xlat/btrfs_qgroup_ctl_cmds.in      |    3 +
 xlat/btrfs_qgroup_inherit_flags.in |    1 +
 xlat/btrfs_qgroup_limit_flags.in   |    6 +
 xlat/btrfs_qgroup_status_flags.in  |    2 +
 xlat/btrfs_scrub_flags.in          |    1 +
 xlat/btrfs_snap_flags_v2.in        |    3 +
 xlat/btrfs_space_info_flags.in     |   11 +
 xlat/btrfs_tree_objectids.in       |   12 +
 24 files changed, 1361 insertions(+)
 create mode 100644 btrfs.c
 create mode 100644 xlat/btrfs_balance_flags.in
 create mode 100644 xlat/btrfs_defrag_flags.in
 create mode 100644 xlat/btrfs_dev_replace_cmds.in
 create mode 100644 xlat/btrfs_dev_replace_results.in
 create mode 100644 xlat/btrfs_dev_replace_state.in
 create mode 100644 xlat/btrfs_dev_stats_flags.in
 create mode 100644 xlat/btrfs_dev_stats_values.in
 create mode 100644 xlat/btrfs_features_compat.in
 create mode 100644 xlat/btrfs_features_compat_ro.in
 create mode 100644 xlat/btrfs_features_incompat.in
 create mode 100644 xlat/btrfs_key_types.in
 create mode 100644 xlat/btrfs_qgroup_ctl_cmds.in
 create mode 100644 xlat/btrfs_qgroup_inherit_flags.in
 create mode 100644 xlat/btrfs_qgroup_limit_flags.in
 create mode 100644 xlat/btrfs_qgroup_status_flags.in
 create mode 100644 xlat/btrfs_scrub_flags.in
 create mode 100644 xlat/btrfs_snap_flags_v2.in
 create mode 100644 xlat/btrfs_space_info_flags.in
 create mode 100644 xlat/btrfs_tree_objectids.in

diff --git a/Makefile.am b/Makefile.am
index e15c2d9..cd1857f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -75,6 +75,7 @@ strace_SOURCES =	\
 	bjm.c		\
 	block.c		\
 	bpf.c		\
+	btrfs.c		\
 	cacheflush.c	\
 	capability.c	\
 	caps0.h		\
diff --git a/btrfs.c b/btrfs.c
new file mode 100644
index 0000000..705b223
--- /dev/null
+++ b/btrfs.c
@@ -0,0 +1,1219 @@
+/*
+ * Copyright (c) 2016 Jeff Mahoney <jeffm at suse.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "defs.h"
+#include <linux/fs.h>
+#ifdef HAVE_LINUX_BTRFS_H
+#include <linux/btrfs.h>
+
+#ifndef HAVE_STRUCT_BTRFS_IOCTL_FEATURE_FLAGS_COMPAT_FLAGS
+struct btrfs_ioctl_feature_flags {
+	uint64_t compat_flags;
+	uint64_t compat_ro_flags;
+	uint64_t incompat_flags;
+};
+#endif
+
+#ifndef HAVE_STRUCT_BTRFS_IOCTL_DEFRAG_RANGE_ARGS_START
+struct btrfs_ioctl_defrag_range_args {
+	uint64_t start;
+	uint64_t len;
+	uint64_t flags;
+	uint32_t extent_thresh;
+	uint32_t compress_type;
+	uint32_t unused[4];
+};
+#endif
+
+#ifndef BTRFS_LABEL_SIZE
+#define BTRFS_LABEL_SIZE 256
+#endif
+
+#ifndef BTRFS_FIRST_FREE_OBJECTID
+#define BTRFS_FIRST_FREE_OBJECTID 256ULL
+#endif
+
+#ifndef BTRFS_IOC_GET_FEATURES
+#define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \
+                                   struct btrfs_ioctl_feature_flags)
+#define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 57, \
+                                   struct btrfs_ioctl_feature_flags[2])
+#define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \
+                                   struct btrfs_ioctl_feature_flags[3])
+#endif
+
+#include "xlat/btrfs_balance_flags.h"
+#include "xlat/btrfs_defrag_flags.h"
+#include "xlat/btrfs_dev_replace_args.h"
+#include "xlat/btrfs_dev_replace_cmds.h"
+#include "xlat/btrfs_dev_replace_results.h"
+#include "xlat/btrfs_dev_replace_state.h"
+#include "xlat/btrfs_dev_stats_flags.h"
+#include "xlat/btrfs_dev_stats_values.h"
+#include "xlat/btrfs_features_compat.h"
+#include "xlat/btrfs_features_compat_ro.h"
+#include "xlat/btrfs_features_incompat.h"
+#include "xlat/btrfs_key_types.h"
+#include "xlat/btrfs_qgroup_ctl_cmds.h"
+#include "xlat/btrfs_qgroup_inherit_flags.h"
+#include "xlat/btrfs_qgroup_limit_flags.h"
+#include "xlat/btrfs_qgroup_status_flags.h"
+#include "xlat/btrfs_scrub_flags.h"
+#include "xlat/btrfs_snap_flags_v2.h"
+#include "xlat/btrfs_space_info_flags.h"
+#include "xlat/btrfs_tree_objectids.h"
+
+static inline char
+prnibble(char v)
+{
+	if (v >= 10)
+		return 'a' + (v - 10);
+	return '0' + v;
+}
+
+/* 8-4-4-4-12 = 36 characters */
+#define UUID_STRING_SIZE 36
+
+/* Formats uuid, returns 0 if it's all zeroes */
+static int
+btrfs_unparse_uuid(unsigned char *uuid, char *out)
+{
+	int i;
+	int ret = 0;
+	for (i = 0; i < BTRFS_UUID_SIZE; i++) {
+		if (i == 4 || i == 6 || i == 8 || i == 10)
+			*out++ = '-';
+		*out++ = prnibble(uuid[i] >> 4);
+		*out++ = prnibble(uuid[i] & 0xf);
+		if (uuid[i])
+			ret = 1;
+	}
+	out[UUID_STRING_SIZE] = '\0';
+	return ret;
+}
+
+static void
+print_u64(const char *name, uint64_t value)
+{
+	tprintf(", %s=%" PRIu64, name, value);
+}
+
+#define print_member_u64(obj, name) print_u64(#name, obj->name)
+
+static void
+btrfs_print_balance_args(const char *name, struct btrfs_balance_args *bba)
+{
+	tprintf(", %s={profiles=%" PRI__u64, name, bba->profiles);
+	print_member_u64(bba, usage);
+	print_member_u64(bba, devid);
+	print_member_u64(bba, pstart);
+	print_member_u64(bba, pend);
+	print_member_u64(bba, vstart);
+	print_member_u64(bba, vend);
+	print_member_u64(bba, target);
+	printflags64(btrfs_balance_flags, bba->flags, NULL);
+	tprints("}");
+}
+
+static void
+btrfs_print_balance(struct tcb *tcp, const long arg, bool out)
+{
+	struct btrfs_ioctl_balance_args balance_args;
+
+	if (umove_or_printaddr(tcp, arg, &balance_args))
+		return;
+
+	tprints("{flags=");
+	printflags64(btrfs_balance_flags, balance_args.flags, NULL);
+	if (out)
+		tprintf(", state=%" PRI__u64, balance_args.state);
+
+	if (balance_args.flags & BTRFS_BALANCE_DATA) {
+		tprints(", ");
+		btrfs_print_balance_args("data", &balance_args.data);
+	}
+	if (balance_args.flags & BTRFS_BALANCE_METADATA) {
+		tprints(", ");
+		btrfs_print_balance_args("meta", &balance_args.meta);
+	}
+	if (balance_args.flags & BTRFS_BALANCE_SYSTEM) {
+		tprints(", ");
+		btrfs_print_balance_args("sys", &balance_args.sys);
+	}
+	tprints("}");
+}
+
+static void
+btrfs_print_features(struct btrfs_ioctl_feature_flags *flags)
+{
+	tprints("{compat_flags=");
+	printflags64(btrfs_features_compat, flags->compat_flags,
+		     "BTRFS_FEATURE_COMPAT_???");
+
+	tprints(", compat_ro_flags=");
+	printflags64(btrfs_features_compat_ro, flags->compat_ro_flags,
+		     "BTRFS_FEATURE_COMPAT_RO_???");
+
+	tprints(", incompat_flags=");
+	printflags64(btrfs_features_incompat, flags->incompat_flags,
+		     "BTRFS_FEATURE_INCOMPAT_???");
+	tprints("}");
+}
+
+static void
+btrfs_print_qgroup_limit(struct btrfs_qgroup_limit *lim)
+{
+	tprints("{flags=");
+	printflags64(btrfs_qgroup_limit_flags, lim->flags, NULL);
+	tprintf(", max_rfer=%" PRI__u64 ", max_excl=%" PRI__u64
+		", rsv_rfer=%" PRI__u64 ", rsv_excl=%" PRI__u64 "}",
+		lim->max_rfer, lim->max_excl,
+		lim->rsv_rfer, lim->rsv_excl);
+}
+
+static void
+btrfs_print_key_type(uint32_t type)
+{
+	const char *str = xlookup(btrfs_key_types, type);
+	tprintf("%u", type);
+	if (str)
+		tprintf(" /* %s */", str);
+}
+
+static void
+btrfs_print_objectid(uint64_t objectid)
+{
+	const char *str = xlookup(btrfs_tree_objectids, objectid);
+	tprintf("%" PRIu64, objectid);
+	if (str)
+		tprintf(" /* %s */", str);
+}
+
+int
+btrfs_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
+{
+	int ret = 0;
+
+	switch (code) {
+	/* Take no arguments; Command only. */
+	case BTRFS_IOC_TRANS_START:
+	case BTRFS_IOC_TRANS_END:
+	case BTRFS_IOC_SYNC:
+	case BTRFS_IOC_SCRUB_CANCEL:
+	case BTRFS_IOC_QUOTA_RESCAN_WAIT:
+		break;
+
+	/* take a signed int */
+	case BTRFS_IOC_CLONE: /* also FICLONE */
+	case BTRFS_IOC_BALANCE_CTL:
+		printnum_int(tcp, arg, ", %d");
+		break;
+
+	/* returns a 64 */
+	case BTRFS_IOC_START_SYNC: /* R */
+		if (entering(tcp))
+			return 0;
+	/* fallthrough */
+	/* take a u64 */
+	case BTRFS_IOC_DEFAULT_SUBVOL: /* W */
+	case BTRFS_IOC_WAIT_SYNC: /* W */
+		tprints(", ");
+		printnum_int64(tcp, arg, "%" PRIu64);
+		break;
+
+	/* u64 but describe a flags bitfield; We can make that symbolic */
+	case BTRFS_IOC_SUBVOL_GETFLAGS: { /* R */
+		uint64_t flags;
+		if (entering(tcp))
+			return 0;
+
+		tprints(", ");
+
+		if (umove_or_printaddr(tcp, arg, &flags))
+			break;
+
+		printflags64(btrfs_snap_flags_v2, flags, "BTRFS_SUBVOL_???");
+		break;
+	}
+	case BTRFS_IOC_SUBVOL_SETFLAGS: { /* W */
+		uint64_t flags;
+
+		tprints(", ");
+
+		if (umove_or_printaddr(tcp, arg, &flags))
+			break;
+
+		printflags64(btrfs_snap_flags_v2, flags, "BTRFS_SUBVOL_???");
+		break;
+	}
+
+	/* More complex types */
+	case BTRFS_IOC_BALANCE_V2: /* RW */
+		if (entering(tcp)) {
+			tprints(", ");
+			btrfs_print_balance(tcp, arg, false);
+			return 0;
+		}
+
+		if (syserror(tcp))
+			break;
+
+		tprints(" => ");
+		btrfs_print_balance(tcp, arg, true);
+		break;
+	case BTRFS_IOC_BALANCE_PROGRESS: /* R */
+		if (entering(tcp))
+			return 0;
+
+		tprints(", ");
+		btrfs_print_balance(tcp, arg, true);
+		break;
+	case BTRFS_IOC_CLONE_RANGE: { /* W */
+		struct btrfs_ioctl_clone_range_args args;
+
+		tprints(", ");
+
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprintf("{src_fd=%" PRI__s64 ", "
+			"src_offset=%" PRI__u64 ", "
+			"src_length=%" PRI__u64 ", "
+			"dest_offset=%" PRI__u64 "}",
+			args.src_fd, args.src_offset,
+			args.src_length, args.dest_offset);
+		break;
+	}
+
+	case BTRFS_IOC_DEFRAG_RANGE: {/* W */
+		struct btrfs_ioctl_defrag_range_args args;
+
+		tprints(", ");
+
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprintf("{start=%" PRIu64 ", len=%" PRIu64 ", flags=",
+			(uint64_t)args.start, (uint64_t)args.len);
+		printflags64(btrfs_defrag_flags, args.flags, NULL);
+		tprintf(", extent_thresh=%u, compress_type=%u}",
+			args.extent_thresh, args.compress_type);
+		break;
+	}
+
+	case BTRFS_IOC_DEV_INFO: { /* RW */
+		struct btrfs_ioctl_dev_info_args args;
+		char uuid[UUID_STRING_SIZE+1];
+		int valid;
+
+		if (entering(tcp))
+			tprints(", ");
+		else if (syserror(tcp))
+			break;
+		else
+			tprints(" => ");
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+		tprints("{");
+
+		valid = btrfs_unparse_uuid(args.uuid, uuid);
+		if (entering(tcp)) {
+			tprintf("devid=%" PRI__u64, args.devid);
+			if (valid)
+				tprintf(", uuid=%s", uuid);
+			tprints("}");
+			return 0;
+		}
+		if (valid)
+			tprintf("uuid=%s, ", uuid);
+		tprintf("bytes_used=%" PRI__u64 ", "
+			"total_bytes=%" PRI__u64 ", "
+			"path=\"%s\"}",
+			args.bytes_used, args.total_bytes, args.path);
+		break;
+	}
+
+	case BTRFS_IOC_DEV_REPLACE: { /* RW */
+		struct btrfs_ioctl_dev_replace_args args;
+
+		if (entering(tcp))
+			tprints(", ");
+
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		if (entering(tcp)) {
+			tprints("{cmd=");
+			printxvals(args.cmd, "BTRFS_IOCTL_DEV_REPLACE_CMD_???",
+				   btrfs_dev_replace_cmds, NULL);
+			if (args.cmd == BTRFS_IOCTL_DEV_REPLACE_CMD_START) {
+				tprintf(", start={srcdevid=%" PRI__u64 ", "
+				   "cont_reading_from_srcdev_mode=%" PRI__u64
+				   ", srcdev_name=\"%s\", tgtdev_name=\"%s\"}",
+				   args.start.srcdevid,
+				   args.start.cont_reading_from_srcdev_mode,
+				   args.start.srcdev_name,
+				   args.start.tgtdev_name);
+			}
+			tprints("}");
+			return 0;
+		}
+
+		tprints(" => {result=");
+		printxvals(args.result, "BTRFS_IOCTL_DEV_REPLACE_RESULT_???",
+			   btrfs_dev_replace_results, NULL);
+		if (args.cmd == BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS) {
+			char buf[10];
+			time_t time;
+			tprints(", ");
+			printxvals(args.status.replace_state,
+				   "BTRFS_IOCTL_DEV_REPLACE_STATE_???",
+				   btrfs_dev_replace_state, NULL);
+			snprintf(buf, sizeof(buf), ", %" PRI__u64
+				 ".%" PRI__u64 "%%",
+				 args.status.progress_1000 / 10,
+				 args.status.progress_1000 % 10);
+			tprintf(", progress_1000=[%" PRI__u64 "(%s)], ",
+				args.status.progress_1000, buf);
+
+			time = args.status.time_started;
+			strftime(buf, sizeof(buf), "%T",
+				 localtime(&time));
+			tprintf("time_started=[%" PRI__u64" (%s)], ",
+				args.status.time_started, buf);
+
+			time = args.status.time_stopped;
+			strftime(buf, sizeof(buf), "%T",
+				 localtime(&time));
+			tprintf("time_stopped=[%" PRI__u64" (%s)], ",
+				args.status.time_stopped, buf);
+
+			tprintf("num_write_errors=%" PRI__u64 ", "
+				"num_uncorrectable_read_errors=%" PRI__u64 "}",
+				args.status.num_write_errors,
+				args.status.num_uncorrectable_read_errors);
+		}
+		break;
+	}
+
+	case BTRFS_IOC_GET_FEATURES: { /* R */
+		struct btrfs_ioctl_feature_flags flags;
+		if (entering(tcp))
+			return 0;
+
+		tprints(", ");
+		if (umove_or_printaddr(tcp, arg, &flags))
+			break;
+
+		btrfs_print_features(&flags);
+		break;
+	}
+	case BTRFS_IOC_SET_FEATURES: { /* W */
+		struct btrfs_ioctl_feature_flags flarg[2];
+
+		tprints(", ");
+
+		if (umove_or_printaddr(tcp, arg, &flarg))
+			break;
+
+		tprints("[");
+		btrfs_print_features(&flarg[0]);
+		tprints(", ");
+		btrfs_print_features(&flarg[1]);
+		tprints("]");
+		break;
+	}
+
+	case BTRFS_IOC_GET_SUPPORTED_FEATURES: { /* R */
+		struct btrfs_ioctl_feature_flags flarg[3];
+
+		if (entering(tcp))
+			return 0;
+
+		tprints(", ");
+		if (umove_or_printaddr(tcp, arg, &flarg))
+			break;
+
+		tprints("[ /* supported */ ");
+		btrfs_print_features(&flarg[0]);
+
+		tprints(", /* safe to set */ ");
+		btrfs_print_features(&flarg[1]);
+
+		tprints(", /* safe to clear */ ");
+		btrfs_print_features(&flarg[2]);
+		tprints("]");
+
+		break;
+	}
+
+	case BTRFS_IOC_FS_INFO: { /* R */
+		struct btrfs_ioctl_fs_info_args args;
+		char uuid[UUID_STRING_SIZE+1];
+		uint32_t nodesize, sectorsize, clone_alignment;
+#ifndef HAVE_STRUCT_BTRFS_IOCTL_FS_INFO_ARGS_NODESIZE
+		__u32 *reserved32;
+#endif
+
+		if (entering(tcp))
+			return 0;
+
+		tprints(", ");
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+#ifdef HAVE_STRUCT_BTRFS_IOCTL_FS_INFO_ARGS_NODESIZE
+		nodesize = args.nodesize,
+		sectorsize = args.sectorsize,
+		clone_alignment = args.clone_alignment;
+#else
+		reserved32 = (__u32 *)args.reserved;
+		nodesize = reserved32[0];
+		sectorsize = reserved32[1];
+		clone_alignment = reserved32[2];
+#endif
+		btrfs_unparse_uuid(args.fsid, uuid);
+
+		tprints("{");
+		tprintf("max_id=%" PRI__u64 ", num_devices=%" PRI__u64 ", "
+			"fsid=%s, nodesize=%u, sectorsize=%u, "
+			"clone_alignment=%u",
+			args.max_id, args.num_devices, uuid,
+			nodesize, sectorsize, clone_alignment);
+		tprints("}");
+		break;
+	}
+
+	case BTRFS_IOC_GET_DEV_STATS: { /* RW */
+		struct btrfs_ioctl_get_dev_stats args;
+		uint64_t i;
+
+		if (entering(tcp))
+			tprints(", ");
+		else if (syserror(tcp))
+			break;
+		else
+			tprints(" => ");
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprints("{");
+
+		if (entering(tcp))
+			tprintf("devid=%" PRI__u64 ", ", args.devid);
+
+		tprintf("nr_items=%" PRI__u64, args.nr_items);
+		printflags64(btrfs_dev_stats_flags, args.flags, NULL);
+
+		if (entering(tcp)) {
+			tprints("}");
+			return 0;
+		}
+
+		tprints(", [");
+		for (i = 0; i < args.nr_items; i++) {
+			const char *name = xlookup(btrfs_dev_stats_values, i);
+			if (i)
+				tprints(", ");
+			if (name)
+				tprintf("/* %s */ ", name);
+			tprintf("%" PRI__u64, args.values[i]);
+		}
+		tprints("]");
+		break;
+	}
+
+	case BTRFS_IOC_INO_LOOKUP: { /* RW */
+		struct btrfs_ioctl_ino_lookup_args args;
+
+		if (entering(tcp))
+			tprints(", ");
+		else if (syserror(tcp))
+			break;
+		else
+			tprints(" => ");
+
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		if (entering(tcp)) {
+			/* Use subvolume id of the containing root */
+			if (args.treeid == 0)
+				/* abuse of auxstr to retain state */
+				tcp->auxstr = (void *)1;
+
+			tprints("{treeid=");
+			btrfs_print_objectid(args.treeid);
+			tprints(", objectid=");
+			btrfs_print_objectid(args.objectid);
+			tprints("}");
+			return 0;
+		}
+
+		tprints("{");
+		if (tcp->auxstr) {
+			tprints("treeid=");
+			btrfs_print_objectid(args.treeid);
+			tprints(", ");
+		}
+		tcp->auxstr = NULL;
+
+		tprintf("name=\"%s\"}", args.name);
+		break;
+	}
+
+	case BTRFS_IOC_INO_PATHS: { /* RW */
+		struct btrfs_ioctl_ino_path_args args;
+		struct btrfs_data_container fspath;
+		uint64_t i;
+
+		if (entering(tcp))
+			tprints(", ");
+		else if (syserror(tcp))
+			break;
+		else
+			tprints(" => ");
+
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprints("{");
+
+		if (entering(tcp)) {
+			tprintf("inum=%" PRI__u64 ", size=%" PRI__u64 "}",
+				args.inum, args.size);
+			return 0;
+		}
+
+		if (umoven_or_printaddr(tcp, args.fspath, args.size, &fspath))
+			break;
+
+		tprintf("fspath={bytes_left=%u, bytes_missing=%u, "
+			"elem_cnt=%u, elem_missed=%u, val=[",
+			fspath.bytes_left, fspath.bytes_missing,
+			fspath.elem_cnt, fspath.elem_missed);
+		for (i = 0; i < fspath.elem_cnt; i++) {
+			uint64_t ptr;
+			char *str;
+			ptr = (uint64_t)(unsigned long)fspath.val;
+			ptr += fspath.val[i];
+			str = (char *)(unsigned long)ptr;
+			if (i)
+				tprints(", ");
+			tprints(str);
+		}
+		tprints("]}");
+
+		break;
+	}
+
+	case BTRFS_IOC_LOGICAL_INO: { /* RW */
+		struct btrfs_ioctl_logical_ino_args args;
+		struct btrfs_data_container *inodes;
+		uint64_t i;
+
+		if (entering(tcp))
+			tprints(", ");
+		else if (syserror(tcp))
+			break;
+		else
+			tprints(" => ");
+
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprints("{");
+
+		if (entering(tcp)) {
+			tprintf("logical=%" PRI__u64 ", size=%" PRI__u64 "}",
+				args.logical, args.size);
+			return 0;
+		}
+
+		tprints("inodes=");
+		inodes = malloc(args.size);
+		if (!inodes) {
+			tprintf("%#lx", (unsigned long)args.inodes);
+			break;
+		}
+
+		if (umoven_or_printaddr(tcp, args.inodes, args.size, inodes)) {
+			free(inodes);
+			break;
+		}
+
+		tprintf("{bytes_left=%u, bytes_missing=%u, "
+			"elem_cnt=%u, elem_missed=%u, val=[",
+			inodes->bytes_left, inodes->bytes_missing,
+			inodes->elem_cnt, inodes->elem_missed);
+		for (i = 0; i < inodes->elem_cnt; i += 3) {
+			if (i)
+				tprints(", ");
+			tprintf("{inum=%" PRI__u64 ", offset=%" PRI__u64
+				", root=%" PRI__u64 "}",
+				inodes->val[i],
+				inodes->val[i+1],
+				inodes->val[i+2]);
+		}
+		tprints("]}");
+		free(inodes);
+
+		break;
+	}
+
+	case BTRFS_IOC_QGROUP_ASSIGN: { /* W */
+		struct btrfs_ioctl_qgroup_assign_args args;
+
+		tprints(", ");
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprintf("{assign=%" PRI__u64 ", src=%" PRI__u64
+			", dst=%" PRI__u64 "}",
+			args.assign, args.src, args.dst);
+		break;
+	}
+
+	case BTRFS_IOC_QGROUP_CREATE: { /* W */
+		struct btrfs_ioctl_qgroup_create_args args;
+
+		tprints(", ");
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprintf("{create=%" PRI__u64 ", qgroupid=%" PRI__u64 "}",
+			args.create, args.qgroupid);
+		break;
+	}
+
+	case BTRFS_IOC_QGROUP_LIMIT: { /* R */
+		struct btrfs_ioctl_qgroup_limit_args args;
+
+		if (entering(tcp))
+			return 0;
+
+		tprints(", ");
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprintf("{qgroupid=%" PRI__u64 ", lim=", args.qgroupid);
+		btrfs_print_qgroup_limit(&args.lim);
+		tprints("}");
+		break;
+	}
+
+	case BTRFS_IOC_QUOTA_CTL: { /* W */
+		struct btrfs_ioctl_quota_ctl_args args;
+
+		tprints(", ");
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		printxvals(args.cmd, "BTRFS_QUOTA_CTL_???",
+			   btrfs_qgroup_ctl_cmds, NULL);
+		tprints("}");
+
+		break;
+	}
+	case BTRFS_IOC_QUOTA_RESCAN: { /* W */
+		struct btrfs_ioctl_quota_rescan_args args;
+
+		tprints(", ");
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprintf("{flags=%" PRI__u64 "}", args.flags);
+		break;
+	}
+	case BTRFS_IOC_QUOTA_RESCAN_STATUS: { /* R */
+		struct btrfs_ioctl_quota_rescan_args args;
+
+		if (entering(tcp))
+			return 0;
+
+		tprints(", ");
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprintf("{flags=%" PRI__u64 ", progress=", args.flags);
+		if (args.progress == -1ULL && abbrev(tcp))
+			tprints("-1");
+		else
+			btrfs_print_objectid(args.progress);
+		tprints("}");
+		break;
+	}
+	case BTRFS_IOC_SET_RECEIVED_SUBVOL: { /* RW */
+		struct btrfs_ioctl_received_subvol_args args;
+		char uuid[UUID_STRING_SIZE+1];
+
+		if (entering(tcp))
+			tprints(", ");
+		else if (syserror(tcp))
+			break;
+		else
+			tprints(" => ");
+
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		if (entering(tcp)) {
+			btrfs_unparse_uuid((unsigned char *)args.uuid, uuid);
+			tprintf("{uuid=%s, stransid=%" PRI__u64
+				", stime=%" PRI__u64 ".%u, flags=%" PRI__u64 "}",
+				uuid, args.stransid, args.stime.sec,
+				args.stime.nsec, args.flags);
+			return 0;
+		}
+		tprintf("{rtransid=%" PRI__u64
+			", rtime=%" PRI__u64 ".%u}",
+			args.rtransid, args.rtime.sec, args.rtime.nsec);
+		break;
+	}
+
+	case BTRFS_IOC_FILE_EXTENT_SAME: { /* RW */
+		int i;
+		unsigned size;
+		struct btrfs_ioctl_same_args args;
+		struct btrfs_ioctl_same_extent_info *info;
+
+		if (entering(tcp))
+			tprints(", ");
+		else if (syserror(tcp))
+			break;
+		else
+			tprints(" => ");
+
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		if (entering(tcp)) {
+			tprintf("{logical_offset=%" PRI__u64 ", "
+				"length=%" PRI__u64 ", "
+				"dest_count=%hu, info=",
+				args.logical_offset, args.length,
+				args.dest_count);
+		}
+
+		size = sizeof(*info) * args.dest_count;
+		info = malloc(size);
+		if (!info) {
+			tprintf("%#lx}", arg + sizeof(args));
+			break;
+		}
+
+		if (umoven_or_printaddr(tcp, arg + sizeof(args), size, info)) {
+			tprints("}");
+			free(info);
+			break;
+		}
+
+		if (entering(tcp))  {
+			tprints("[");
+			for (i = 0; i < args.dest_count; i++) {
+				if (i)
+					tprints(", ");
+				tprintf("{fd=%" PRI__s64 ", "
+					"logical_offset=%" PRI__u64 "}",
+					info[i].fd, info[i].logical_offset);
+			}
+			tprints("]");
+			return 0;
+		}
+		tprints("{info=[");
+		for (i = 0; i < args.dest_count; i++) {
+			if (i)
+				tprints(", ");
+			tprintf("{bytes_deduped=%" PRI__u64 ", "
+				"status=%d}",
+				info[i].bytes_deduped, info[i].status);
+		}
+		tprints("]");
+		free(info);
+		break;
+	}
+
+	case BTRFS_IOC_SCRUB: /* RW */
+	case BTRFS_IOC_SCRUB_PROGRESS: { /* RW */
+		struct btrfs_ioctl_scrub_args args;
+
+		if (entering(tcp))
+			tprints(", ");
+		else if (syserror(tcp))
+			break;
+		else
+			tprints(" => ");
+
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		if (entering(tcp)) {
+			tprintf("{devid=%" PRI__u64, args.devid);
+			if (code == BTRFS_IOC_SCRUB) {
+				tprintf(", start=%" PRI__u64 ", end=",
+					args.start);
+				if (args.end == -1ULL && abbrev(tcp))
+					tprints("-1");
+				else
+					tprintf("%" PRI__u64, args.end);
+				tprints(", flags=");
+				printflags64(btrfs_scrub_flags, args.flags,
+					     "BTRFS_SCRUB_???");
+			}
+			tprints("}");
+			return 0;
+		}
+		tprintf("{data_extents_scrubbed=%" PRI__u64 ", "
+			"tree_extents_scrubbed=%" PRI__u64 ", "
+			"data_bytes_scrubbed=%" PRI__u64 ", "
+			"tree_bytes_scrubbed=%" PRI__u64 ", "
+			"read_errors=%" PRI__u64 ", "
+			"csum_errors=%" PRI__u64 ", "
+			"verify_errors=%" PRI__u64 ", "
+			"no_csum=%" PRI__u64 ", "
+			"csum_discards=%" PRI__u64 ", "
+			"super_errors=%" PRI__u64 ", "
+			"malloc_errors=%" PRI__u64 ", "
+			"uncorrectable_errors=%" PRI__u64 ", "
+			"corrected_errors=%" PRI__u64 ", "
+			"last_physical=%" PRI__u64 ", "
+			"unverified_errors=%" PRI__u64 "}",
+			args.progress.data_extents_scrubbed,
+			args.progress.tree_extents_scrubbed,
+			args.progress.data_bytes_scrubbed,
+			args.progress.tree_bytes_scrubbed,
+			args.progress.read_errors,
+			args.progress.csum_errors,
+			args.progress.verify_errors,
+			args.progress.no_csum,
+			args.progress.csum_discards,
+			args.progress.super_errors,
+			args.progress.malloc_errors,
+			args.progress.uncorrectable_errors,
+			args.progress.corrected_errors,
+			args.progress.last_physical,
+			args.progress.unverified_errors);
+		break;
+	}
+
+	case BTRFS_IOC_TREE_SEARCH: { /* RW */
+		struct btrfs_ioctl_search_args args;
+
+		if (entering(tcp))
+			tprints(", ");
+		else if (syserror(tcp))
+			break;
+		else
+			tprints(" => ");
+
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		if (entering(tcp)) {
+			tprintf("{key={tree_id=");
+			btrfs_print_objectid(args.key.tree_id);
+
+			if (args.key.min_objectid !=
+					BTRFS_FIRST_FREE_OBJECTID ||
+			    !abbrev(tcp)) {
+				tprints(", min_objectid=");
+				btrfs_print_objectid(args.key.min_objectid);
+			}
+
+			if (args.key.max_objectid !=
+						BTRFS_LAST_FREE_OBJECTID ||
+			    !abbrev(tcp)) {
+				tprints(", max_objectid=");
+				btrfs_print_objectid(args.key.max_objectid);
+			}
+
+			if (args.key.min_offset || !abbrev(tcp))
+				tprintf(", min_offset=%" PRI__u64,
+					args.key.min_offset);
+
+			if (args.key.max_offset == -1ULL) {
+				if (!abbrev(tcp))
+					tprints(", max_offset=-1");
+			} else
+				tprintf(", max_offset=%" PRI__u64,
+					args.key.max_offset);
+
+			if (args.key.min_transid || !abbrev(tcp))
+				tprintf(", min_transid=%" PRI__u64,
+					args.key.min_transid);
+
+			if (args.key.max_transid == -1ULL) {
+				if (!abbrev(tcp))
+					tprints(", max_transid=-1");
+			} else
+				tprintf(", max_transid=%" PRI__u64,
+					args.key.max_transid);
+			tprints(", min_type=");
+			btrfs_print_key_type(args.key.min_type);
+			tprints(", max_type=");
+			btrfs_print_key_type(args.key.max_type);
+			tprintf(", nr_items=%u}}", args.key.nr_items);
+			return 0;
+		}
+		tprintf("{key={nr_items=%u}, buf=", args.key.nr_items);
+		if (abbrev(tcp))
+			tprints("...");
+		else {
+			struct btrfs_ioctl_search_header *sh;
+			uint64_t i;
+			uint64_t off = 0;
+			tprints("[");
+			for (i = 0; i < args.key.nr_items; i++) {
+				sh = (struct btrfs_ioctl_search_header *)
+							(args.buf + off);
+				if (i)
+					tprints(", ");
+				tprintf("{transid=%" PRI__u64 ", "
+					"objectid=", sh->transid);
+				btrfs_print_objectid(sh->objectid);
+				tprintf(", offset=%" PRI__u64 ", type=",
+					sh->offset);
+				btrfs_print_key_type(sh->type);
+				tprintf(", len=%u}", sh->len);
+				off += sizeof(*sh) + sh->len;
+			}
+			tprints("]");
+		}
+
+		tprints("}");
+
+		/* We don't need to parse the output buffer */
+		break;
+	}
+
+	case BTRFS_IOC_SEND: { /* W */
+		struct btrfs_ioctl_send_args args;
+		__u64 *sources;
+		size_t size;
+		uint64_t i;
+
+		tprints(", ");
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprintf("{send_fd=%" PRI__s64 ", clone_sources_count=%" PRI__u64
+			", clone_sources=", args.send_fd,
+			args.clone_sources_count);
+
+		size = args.clone_sources_count * sizeof(*args.clone_sources);
+		sources = malloc(size);
+		if (!sources) {
+			tprintf("%#lx}", (unsigned long)args.clone_sources);
+			break;
+		}
+
+		if (umoven_or_printaddr(tcp, (unsigned long)args.clone_sources,
+					size, sources)) {
+			tprintf("}");
+			free(sources);
+			break;
+		}
+
+		tprints("[");
+		for (i = 0; i < args.clone_sources_count; i++) {
+			if (i)
+				tprints(", ");
+			btrfs_print_objectid(sources[i]);
+		}
+		tprints("]}");
+		free(sources);
+		break;
+	}
+
+	case BTRFS_IOC_SPACE_INFO: { /* RW */
+		struct btrfs_ioctl_space_args args;
+		struct btrfs_ioctl_space_info *spaces;
+		size_t size;
+		uint64_t i;
+
+		if (entering(tcp))
+			tprints(", ");
+		else if (syserror(tcp))
+			break;
+		else
+			tprints(" => ");
+
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprints("{");
+		if (entering(tcp)) {
+			tprintf("space_slots=%" PRI__u64,
+				args.space_slots);
+			return 0;
+		}
+
+		tprintf("total_spaces=%" PRI__u64, args.total_spaces);
+
+		if (args.space_slots == 0 && args.total_spaces) {
+			tprints("}");
+			break;
+		}
+
+		tprints(", spaces=");
+		if (abbrev(tcp)) {
+			tprints("...}");
+			break;
+		}
+
+		size = args.total_spaces * sizeof(args.spaces[0]);
+		spaces = malloc(size);
+		if (!spaces) {
+			tprintf("%#lx}", arg + sizeof(arg));
+			break;
+		}
+
+		if (umoven_or_printaddr(tcp, arg + sizeof(args),
+					size, spaces)) {
+			tprintf("%#lx}", arg + sizeof(arg));
+			free(spaces);
+			break;
+		}
+
+		tprints("[");
+
+		for (i = 0; i < args.total_spaces; i++) {
+			if (i)
+				tprints(", ");
+			tprints("{flags=");
+			printflags64(btrfs_space_info_flags, spaces[i].flags,
+				     "BTRFS_SPACE_INFO_???");
+			tprintf(", total_bytes=%" PRI__u64 ", "
+				"used_bytes=%" PRI__u64 "}",
+				spaces[i].total_bytes,
+				spaces[i].used_bytes);
+
+		}
+		tprints("]}");
+		free(spaces);
+		break;
+	}
+
+	case BTRFS_IOC_SNAP_CREATE:
+	case BTRFS_IOC_DEFRAG:
+	case BTRFS_IOC_RESIZE:
+	case BTRFS_IOC_SCAN_DEV:
+	case BTRFS_IOC_ADD_DEV:
+	case BTRFS_IOC_RM_DEV:
+	case BTRFS_IOC_BALANCE:
+	case BTRFS_IOC_SUBVOL_CREATE:
+	case BTRFS_IOC_SNAP_DESTROY:
+	case BTRFS_IOC_DEVICES_READY: { /* W */
+		struct btrfs_ioctl_vol_args args;
+
+		tprints(", ");
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprintf("{fd=%" PRI__s64 ", name=\"%s\"}",
+			args.fd, args.name);
+		break;
+	}
+
+	case BTRFS_IOC_SNAP_CREATE_V2:
+	case BTRFS_IOC_SUBVOL_CREATE_V2: { /* W */
+		struct btrfs_ioctl_vol_args_v2 args;
+
+		tprints(", ");
+		if (umove_or_printaddr(tcp, arg, &args))
+			break;
+
+		tprintf("{fd=%" PRI__s64 ", flags=", args.fd);
+		printflags64(btrfs_snap_flags_v2, args.flags,
+			     "BTRFS_SUBVOL_???");
+		if (args.flags & BTRFS_SUBVOL_QGROUP_INHERIT) {
+			struct btrfs_qgroup_inherit *inherit;
+			uint64_t i;
+
+			tprintf(", size=%" PRI__u64 ", qgroup_inherit=",
+				args.size);
+
+			inherit = malloc(args.size);
+			if (!inherit) {
+				tprintf("%lx}",
+					(unsigned long)args.qgroup_inherit);
+				break;
+			}
+
+			if (umoven_or_printaddr(tcp,
+					(unsigned long)args.qgroup_inherit,
+					args.size, inherit) < 0) {
+				tprintf("%lx}",
+					(unsigned long)args.qgroup_inherit);
+				free(inherit);
+				break;
+			}
+
+			tprintf("{flags=");
+			printflags64(btrfs_qgroup_inherit_flags,
+				     inherit->flags,
+				     "BTRFS_QGROUP_INHERIT_???");
+			tprintf(", num_qgroups=%" PRI__u64
+				", num_ref_copies=%" PRI__u64
+				", num_excl_copies=%" PRI__u64
+				", lim=",
+				inherit->num_qgroups,
+				inherit->num_ref_copies,
+				inherit->num_excl_copies);
+
+			btrfs_print_qgroup_limit(&inherit->lim);
+
+			tprints(", [");
+			for (i = 0; i < inherit->num_qgroups; i++) {
+				if (i)
+					tprints(", ");
+				tprintf("%" PRI__u64, inherit->qgroups[i]);
+			}
+			tprints("]}");
+			free(inherit);
+		}
+		tprints("}");
+		break;
+	}
+	case BTRFS_IOC_GET_FSLABEL: /* R */
+	case BTRFS_IOC_SET_FSLABEL: {/* W */
+		char label[BTRFS_LABEL_SIZE];
+		if (code == BTRFS_IOC_GET_FSLABEL && entering(tcp))
+			return 0;
+
+		tprints(", ");
+		if (umoven_or_printaddr(tcp, arg, sizeof(label), label))
+			break;
+		tprintf("\"%s\"", label);
+		break;
+	}
+	default:
+		return RVAL_DECODED;
+	};
+	return ret | RVAL_DECODED | 1;
+}
+#endif /* HAVE_LINUX_BTRFS_H */
diff --git a/configure.ac b/configure.ac
index 98907a0..863b22c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -433,6 +433,14 @@ AC_CHECK_HEADERS([linux/bpf.h], [
 	fi
 ])
 
+AC_CHECK_HEADERS([linux/btrfs.h], [
+	AC_CHECK_MEMBERS(m4_normalize([
+		struct btrfs_ioctl_feature_flags.compat_flags,
+		struct btrfs_ioctl_fs_info_args.nodesize,
+		struct btrfs_ioctl_defrag_range_args.start
+		]),,, [ #include <stdio.h>
+#include <linux/btrfs.h>])],)
+
 AC_CHECK_DECLS([sys_errlist])
 AC_CHECK_DECLS(m4_normalize([
 	PTRACE_PEEKUSER,
diff --git a/defs.h b/defs.h
index cc2a0d4..1e67ddc 100644
--- a/defs.h
+++ b/defs.h
@@ -642,6 +642,7 @@ extern const char *sprint_open_modes(int);
 extern void print_seccomp_filter(struct tcb *tcp, unsigned long);
 
 extern int block_ioctl(struct tcb *, const unsigned int, long);
+extern int btrfs_ioctl(struct tcb *, const unsigned int, long);
 extern int evdev_ioctl(struct tcb *, const unsigned int, long);
 extern int loop_ioctl(struct tcb *, const unsigned int, long);
 extern int mtd_ioctl(struct tcb *, const unsigned int, long);
diff --git a/ioctl.c b/ioctl.c
index f70dc44..3f7eae1 100644
--- a/ioctl.c
+++ b/ioctl.c
@@ -263,6 +263,10 @@ ioctl_decode(struct tcb *tcp)
 	case 'E':
 		return evdev_ioctl(tcp, code, arg);
 #endif
+#ifdef HAVE_LINUX_BTRFS_H
+	case 0x94:
+		return btrfs_ioctl(tcp, code, arg);
+#endif
 	default:
 		break;
 	}
diff --git a/xlat/btrfs_balance_flags.in b/xlat/btrfs_balance_flags.in
new file mode 100644
index 0000000..6bd7549
--- /dev/null
+++ b/xlat/btrfs_balance_flags.in
@@ -0,0 +1,12 @@
+BTRFS_BALANCE_DATA              (1ULL << 0)
+BTRFS_BALANCE_SYSTEM            (1ULL << 1)
+BTRFS_BALANCE_METADATA          (1ULL << 2)
+BTRFS_BALANCE_FORCE
+BTRFS_BALANCE_RESUME
+BTRFS_BALANCE_ARGS_PROFILES
+BTRFS_BALANCE_ARGS_USAGE
+BTRFS_BALANCE_ARGS_DEVID
+BTRFS_BALANCE_ARGS_DRANGE
+BTRFS_BALANCE_ARGS_VRANGE
+BTRFS_BALANCE_ARGS_CONVERT
+BTRFS_BALANCE_ARGS_SOFT
diff --git a/xlat/btrfs_defrag_flags.in b/xlat/btrfs_defrag_flags.in
new file mode 100644
index 0000000..33b490f
--- /dev/null
+++ b/xlat/btrfs_defrag_flags.in
@@ -0,0 +1,2 @@
+BTRFS_DEFRAG_RANGE_COMPRESS
+BTRFS_DEFRAG_RANGE_START_IO
diff --git a/xlat/btrfs_dev_replace_cmds.in b/xlat/btrfs_dev_replace_cmds.in
new file mode 100644
index 0000000..65bbf3b
--- /dev/null
+++ b/xlat/btrfs_dev_replace_cmds.in
@@ -0,0 +1,3 @@
+BTRFS_IOCTL_DEV_REPLACE_CMD_START
+BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS
+BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL
diff --git a/xlat/btrfs_dev_replace_results.in b/xlat/btrfs_dev_replace_results.in
new file mode 100644
index 0000000..4b75d09
--- /dev/null
+++ b/xlat/btrfs_dev_replace_results.in
@@ -0,0 +1,4 @@
+BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR
+BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED
+BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED
+BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS
diff --git a/xlat/btrfs_dev_replace_state.in b/xlat/btrfs_dev_replace_state.in
new file mode 100644
index 0000000..e89e5e6
--- /dev/null
+++ b/xlat/btrfs_dev_replace_state.in
@@ -0,0 +1,5 @@
+BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED
+BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED
+BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED
+BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED
+BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED
diff --git a/xlat/btrfs_dev_stats_flags.in b/xlat/btrfs_dev_stats_flags.in
new file mode 100644
index 0000000..0d62b14
--- /dev/null
+++ b/xlat/btrfs_dev_stats_flags.in
@@ -0,0 +1 @@
+BTRFS_DEV_STATS_RESET
diff --git a/xlat/btrfs_dev_stats_values.in b/xlat/btrfs_dev_stats_values.in
new file mode 100644
index 0000000..0b843db
--- /dev/null
+++ b/xlat/btrfs_dev_stats_values.in
@@ -0,0 +1,11 @@
+#define HAVE_DECL_BTRFS_DEV_STAT_WRITE_ERRS 1
+#define HAVE_DECL_BTRFS_DEV_STAT_READ_ERRS 1
+#define HAVE_DECL_BTRFS_DEV_STAT_FLUSH_ERRS 1
+#define HAVE_DECL_BTRFS_DEV_STAT_CORRUPTION_ERRS 1
+#define HAVE_DECL_BTRFS_DEV_STAT_GENERATION_ERRS 1
+
+BTRFS_DEV_STAT_WRITE_ERRS
+BTRFS_DEV_STAT_READ_ERRS
+BTRFS_DEV_STAT_FLUSH_ERRS
+BTRFS_DEV_STAT_CORRUPTION_ERRS
+BTRFS_DEV_STAT_GENERATION_ERRS
diff --git a/xlat/btrfs_features_compat.in b/xlat/btrfs_features_compat.in
new file mode 100644
index 0000000..e69de29
diff --git a/xlat/btrfs_features_compat_ro.in b/xlat/btrfs_features_compat_ro.in
new file mode 100644
index 0000000..13808c8
--- /dev/null
+++ b/xlat/btrfs_features_compat_ro.in
@@ -0,0 +1 @@
+BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE (1ULL << 0)
diff --git a/xlat/btrfs_features_incompat.in b/xlat/btrfs_features_incompat.in
new file mode 100644
index 0000000..edb21c2
--- /dev/null
+++ b/xlat/btrfs_features_incompat.in
@@ -0,0 +1,10 @@
+BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF    (1ULL << 0)
+BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL   (1ULL << 1)
+BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS     (1ULL << 2)
+BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO     (1ULL << 3)
+BTRFS_FEATURE_INCOMPAT_COMPRESS_LZOv2   (1ULL << 4)
+BTRFS_FEATURE_INCOMPAT_BIG_METADATA     (1ULL << 5)
+BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF    (1ULL << 6)
+BTRFS_FEATURE_INCOMPAT_RAID56           (1ULL << 7)
+BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA  (1ULL << 8)
+BTRFS_FEATURE_INCOMPAT_NO_HOLES         (1ULL << 9)
diff --git a/xlat/btrfs_key_types.in b/xlat/btrfs_key_types.in
new file mode 100644
index 0000000..27f80e0
--- /dev/null
+++ b/xlat/btrfs_key_types.in
@@ -0,0 +1,40 @@
+BTRFS_INODE_ITEM_KEY            1
+BTRFS_INODE_REF_KEY             12
+BTRFS_INODE_EXTREF_KEY          13
+BTRFS_XATTR_ITEM_KEY            24
+BTRFS_ORPHAN_ITEM_KEY           48
+BTRFS_DIR_LOG_ITEM_KEY  60
+BTRFS_DIR_LOG_INDEX_KEY 72
+BTRFS_DIR_ITEM_KEY      84
+BTRFS_DIR_INDEX_KEY     96
+BTRFS_EXTENT_DATA_KEY   108
+BTRFS_EXTENT_CSUM_KEY   128
+BTRFS_ROOT_ITEM_KEY     132
+BTRFS_ROOT_BACKREF_KEY  144
+BTRFS_ROOT_REF_KEY      156
+BTRFS_EXTENT_ITEM_KEY   168
+BTRFS_METADATA_ITEM_KEY 169
+BTRFS_TREE_BLOCK_REF_KEY        176
+BTRFS_EXTENT_DATA_REF_KEY       178
+BTRFS_EXTENT_REF_V0_KEY         180
+BTRFS_SHARED_BLOCK_REF_KEY      182
+BTRFS_SHARED_DATA_REF_KEY       184
+BTRFS_BLOCK_GROUP_ITEM_KEY 192
+BTRFS_FREE_SPACE_INFO_KEY 198
+BTRFS_FREE_SPACE_EXTENT_KEY 199
+BTRFS_FREE_SPACE_BITMAP_KEY 200
+BTRFS_DEV_EXTENT_KEY    204
+BTRFS_DEV_ITEM_KEY      216
+BTRFS_CHUNK_ITEM_KEY    228
+BTRFS_QGROUP_STATUS_KEY         240
+BTRFS_QGROUP_INFO_KEY           242
+BTRFS_QGROUP_LIMIT_KEY          244
+BTRFS_QGROUP_RELATION_KEY       246
+BTRFS_BALANCE_ITEM_KEY  248
+BTRFS_TEMPORARY_ITEM_KEY        248
+BTRFS_DEV_STATS_KEY             249
+BTRFS_PERSISTENT_ITEM_KEY       249
+BTRFS_DEV_REPLACE_KEY   250
+BTRFS_UUID_KEY_SUBVOL   251
+BTRFS_UUID_KEY_RECEIVED_SUBVOL  252
+BTRFS_STRING_ITEM_KEY   253
diff --git a/xlat/btrfs_qgroup_ctl_cmds.in b/xlat/btrfs_qgroup_ctl_cmds.in
new file mode 100644
index 0000000..8e2aa5f
--- /dev/null
+++ b/xlat/btrfs_qgroup_ctl_cmds.in
@@ -0,0 +1,3 @@
+BTRFS_QUOTA_CTL_ENABLE
+BTRFS_QUOTA_CTL_DISABLE
+BTRFS_QUOTA_CTL_RESCAN__NOTUSED
diff --git a/xlat/btrfs_qgroup_inherit_flags.in b/xlat/btrfs_qgroup_inherit_flags.in
new file mode 100644
index 0000000..803c8c0
--- /dev/null
+++ b/xlat/btrfs_qgroup_inherit_flags.in
@@ -0,0 +1 @@
+BTRFS_QGROUP_INHERIT_SET_LIMITS
diff --git a/xlat/btrfs_qgroup_limit_flags.in b/xlat/btrfs_qgroup_limit_flags.in
new file mode 100644
index 0000000..3bf2f8f
--- /dev/null
+++ b/xlat/btrfs_qgroup_limit_flags.in
@@ -0,0 +1,6 @@
+BTRFS_QGROUP_LIMIT_MAX_RFER     (1ULL << 0)
+BTRFS_QGROUP_LIMIT_MAX_EXCL     (1ULL << 1)
+BTRFS_QGROUP_LIMIT_RSV_RFER     (1ULL << 2)
+BTRFS_QGROUP_LIMIT_RSV_EXCL     (1ULL << 3)
+BTRFS_QGROUP_LIMIT_RFER_CMPR    (1ULL << 4)
+BTRFS_QGROUP_LIMIT_EXCL_CMPR    (1ULL << 5)
diff --git a/xlat/btrfs_qgroup_status_flags.in b/xlat/btrfs_qgroup_status_flags.in
new file mode 100644
index 0000000..10236aa
--- /dev/null
+++ b/xlat/btrfs_qgroup_status_flags.in
@@ -0,0 +1,2 @@
+BTRFS_QGROUP_STATUS_FLAG_ON             (1ULL << 0)
+BTRFS_QGROUP_STATUS_FLAG_RESCAN         (1ULL << 1)
diff --git a/xlat/btrfs_scrub_flags.in b/xlat/btrfs_scrub_flags.in
new file mode 100644
index 0000000..31e4f65
--- /dev/null
+++ b/xlat/btrfs_scrub_flags.in
@@ -0,0 +1 @@
+BTRFS_SCRUB_READONLY    1
diff --git a/xlat/btrfs_snap_flags_v2.in b/xlat/btrfs_snap_flags_v2.in
new file mode 100644
index 0000000..3fe3358
--- /dev/null
+++ b/xlat/btrfs_snap_flags_v2.in
@@ -0,0 +1,3 @@
+BTRFS_SUBVOL_CREATE_ASYNC
+BTRFS_SUBVOL_RDONLY
+BTRFS_SUBVOL_QGROUP_INHERIT
diff --git a/xlat/btrfs_space_info_flags.in b/xlat/btrfs_space_info_flags.in
new file mode 100644
index 0000000..9feaf74
--- /dev/null
+++ b/xlat/btrfs_space_info_flags.in
@@ -0,0 +1,11 @@
+BTRFS_BLOCK_GROUP_DATA          (1ULL << 0)
+BTRFS_BLOCK_GROUP_SYSTEM        (1ULL << 1)
+BTRFS_BLOCK_GROUP_METADATA      (1ULL << 2)
+BTRFS_BLOCK_GROUP_RAID0         (1ULL << 3)
+BTRFS_BLOCK_GROUP_RAID1         (1ULL << 4)
+BTRFS_BLOCK_GROUP_DUP           (1ULL << 5)
+BTRFS_BLOCK_GROUP_RAID10        (1ULL << 6)
+BTRFS_BLOCK_GROUP_RAID5         (1ULL << 7)
+BTRFS_BLOCK_GROUP_RAID6         (1ULL << 8)
+BTRFS_AVAIL_ALLOC_BIT_SINGLE    (1ULL << 48)
+BTRFS_SPACE_INFO_GLOBAL_RSV     (1ULL << 49)
diff --git a/xlat/btrfs_tree_objectids.in b/xlat/btrfs_tree_objectids.in
new file mode 100644
index 0000000..cc89c20
--- /dev/null
+++ b/xlat/btrfs_tree_objectids.in
@@ -0,0 +1,12 @@
+BTRFS_ROOT_TREE_OBJECTID 1ULL
+BTRFS_EXTENT_TREE_OBJECTID 2ULL
+BTRFS_CHUNK_TREE_OBJECTID 3ULL
+BTRFS_DEV_TREE_OBJECTID 4ULL
+BTRFS_FS_TREE_OBJECTID 5ULL
+BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL
+BTRFS_CSUM_TREE_OBJECTID 7ULL
+BTRFS_QUOTA_TREE_OBJECTID 8ULL
+BTRFS_UUID_TREE_OBJECTID 9ULL
+BTRFS_FREE_SPACE_TREE_OBJECTID 10ULL
+BTRFS_FIRST_FREE_OBJECTID 256ULL
+BTRFS_LAST_FREE_OBJECTID -256ULL
-- 
2.7.1





More information about the Strace-devel mailing list