[PATCH] Add btrfs ioctl support.
jeffm at suse.com
jeffm at suse.com
Thu May 5 00:07:13 UTC 2016
From: Jeff Mahoney <jeffm at suse.com>
* btrfs.c: New file.
* file_ioctl.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 | 2 +
btrfs.c | 1298 ++++++++++++++++++++++++++++++++++++
configure.ac | 8 +
defs.h | 2 +
file_ioctl.c | 163 +++++
ioctl.c | 4 +
xlat/btrfs_balance_flags.in | 17 +
xlat/btrfs_defrag_flags.in | 3 +
xlat/btrfs_dev_replace_cmds.in | 4 +
xlat/btrfs_dev_replace_results.in | 5 +
xlat/btrfs_dev_replace_state.in | 6 +
xlat/btrfs_dev_stats_flags.in | 2 +
xlat/btrfs_dev_stats_values.in | 12 +
xlat/btrfs_features_compat.in | 0
xlat/btrfs_features_compat_ro.in | 2 +
xlat/btrfs_features_incompat.in | 11 +
xlat/btrfs_key_types.in | 41 ++
xlat/btrfs_qgroup_ctl_cmds.in | 4 +
xlat/btrfs_qgroup_inherit_flags.in | 2 +
xlat/btrfs_qgroup_limit_flags.in | 7 +
xlat/btrfs_qgroup_status_flags.in | 3 +
xlat/btrfs_scrub_flags.in | 2 +
xlat/btrfs_snap_flags_v2.in | 4 +
xlat/btrfs_space_info_flags.in | 12 +
xlat/btrfs_tree_objectids.in | 13 +
25 files changed, 1627 insertions(+)
create mode 100644 btrfs.c
create mode 100644 file_ioctl.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 b14f8ed..a6b4186 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -81,6 +81,7 @@ strace_SOURCES = \
bjm.c \
block.c \
bpf.c \
+ btrfs.c \
cacheflush.c \
capability.c \
caps0.h \
@@ -110,6 +111,7 @@ strace_SOURCES = \
fetch_struct_statfs.c \
file.c \
file_handle.c \
+ file_ioctl.c \
flock.c \
flock.h \
futex.c \
diff --git a/btrfs.c b/btrfs.c
new file mode 100644
index 0000000..d9c29aa
--- /dev/null
+++ b/btrfs.c
@@ -0,0 +1,1298 @@
+/*
+ * 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
+/*
+ * Prior to Linux 3.12, the BTRFS_IOC_DEFAULT_SUBVOL used u64 in
+ * its definition, which isn't exported by the kernel.
+ */
+typedef __u64 u64;
+
+#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_SUBVOL_NAME_MAX
+#define BTRFS_SUBVOL_NAME_MAX 4039
+#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
+
+#ifndef BTRFS_IOC_TREE_SEARCH_V2
+#define BTRFS_IOC_TREE_SEARCH_V2 _IOWR(BTRFS_IOCTL_MAGIC, 17, \
+ struct btrfs_ioctl_search_args_v2)
+struct btrfs_ioctl_search_args_v2 {
+ struct btrfs_ioctl_search_key key; /* in/out - search parameters */
+ uint64_t buf_size; /* in - size of buffer
+ * out - on EOVERFLOW: needed size
+ * to store item */
+ uint64_t buf[0]; /* out - found items */
+};
+#endif
+
+#include "xlat/btrfs_balance_flags.h"
+#include "xlat/btrfs_defrag_flags.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);
+ tprints(", flags=");
+ printflags64(btrfs_balance_flags, bba->flags, "BTRFS_BALANCE_???");
+ 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,
+ "BTRFS_BALANCE_???");
+ if (out)
+ tprintf(", state=%" PRI__u64, balance_args.state);
+
+ if (balance_args.flags & BTRFS_BALANCE_DATA)
+ btrfs_print_balance_args("data", &balance_args.data);
+ if (balance_args.flags & BTRFS_BALANCE_METADATA)
+ btrfs_print_balance_args("meta", &balance_args.meta);
+ if (balance_args.flags & BTRFS_BALANCE_SYSTEM)
+ 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,
+ "BTRFS_QGROUP_LIMIT_???");
+ 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);
+}
+
+static void
+btrfs_print_data_container_header(struct btrfs_data_container *container)
+{
+ tprintf("{bytes_left=%u, bytes_missing=%u, "
+ "elem_cnt=%u, elem_missed=%u, val=",
+ container->bytes_left, container->bytes_missing,
+ container->elem_cnt, container->elem_missed);
+}
+
+static void
+btrfs_print_data_container_footer(void)
+{
+ tprints("}");
+}
+
+static void
+btrfs_print_logical_ino_container(struct tcb *tcp, uint64_t inodes_addr)
+{
+ struct btrfs_data_container container;
+ uint64_t val_addr;
+ uint32_t i;
+ uint32_t printed = 0;
+
+ if (umoven_or_printaddr(tcp, inodes_addr,
+ sizeof(container), &container))
+ return;
+
+ btrfs_print_data_container_header(&container);
+ if (abbrev(tcp)) {
+ tprints("...");
+ btrfs_print_data_container_footer();
+ return;
+ }
+
+ tprints("[");
+
+ val_addr = inodes_addr + offsetof(typeof(container), val);
+ for (i = 0; i < container.elem_cnt; i += 3, printed++) {
+ uint64_t addr = val_addr + sizeof(uint64_t) * i;
+ uint64_t record[3];
+
+ if (i)
+ tprints(", ");
+
+ if (printed > max_strlen ||
+ umoven(tcp, addr, sizeof(record), record)) {
+ tprints("...");
+ break;
+ }
+ tprintf("{inum=%" PRIu64 ", offset=%" PRIu64
+ ", root=%" PRIu64 "}", record[0], record[1], record[2]);
+ }
+ tprints("]");
+ btrfs_print_data_container_footer();
+}
+
+static void
+btrfs_print_ino_path_container(struct tcb *tcp, uint64_t fspath_addr)
+{
+ struct btrfs_data_container container;
+ uint32_t i;
+ uint64_t val_addr;
+
+ if (umoven_or_printaddr(tcp, fspath_addr,
+ sizeof(container), &container))
+ return;
+
+ btrfs_print_data_container_header(&container);
+ if (abbrev(tcp)) {
+ tprints("...");
+ btrfs_print_data_container_footer();
+ return;
+ }
+
+ tprints("[");
+
+ val_addr = fspath_addr + offsetof(typeof(container), val);
+ for (i = 0; i < container.elem_cnt; i++) {
+ uint64_t addr = val_addr + sizeof(uint64_t) * i;
+ uint64_t ptr;
+
+ if (i)
+ tprints(", ");
+
+ if (i > max_strlen || umoven(tcp, addr, sizeof(ptr), &ptr)) {
+ tprints("...");
+ break;
+ }
+
+ printpath(tcp, val_addr + ptr);
+ }
+ tprints("]");
+ btrfs_print_data_container_footer();
+}
+
+static void
+btrfs_print_qgroup_inherit(struct tcb *tcp, uint64_t qgi_addr)
+{
+ struct btrfs_qgroup_inherit inherit;
+
+ if (umoven_or_printaddr(tcp, qgi_addr, sizeof(inherit), &inherit) < 0) {
+ tprintf("%lx", (unsigned long)qgi_addr);
+ return;
+ }
+
+ 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(", qgroups=");
+
+ if (abbrev(tcp)) {
+ tprints("...");
+ } else {
+ uint64_t qgroups_addr = qgi_addr +
+ offsetof(typeof(inherit), qgroups);
+ uint32_t i;
+
+ tprints("[");
+ for (i = 0; i < inherit.num_qgroups; i++) {
+ uint64_t record;
+ uint64_t addr = qgroups_addr + sizeof(record) * i;
+ if (i)
+ tprints(", ");
+ if (i > max_strlen ||
+ umoven(tcp, addr, sizeof(record), &record)) {
+ tprints("...");
+ break;
+ }
+
+ tprintf("%" PRIu64, record);
+ }
+ tprints("]");
+ }
+ tprints("}");
+}
+
+static void
+__print_key_value(struct tcb *tcp, const char *name, uint64_t value)
+{
+ if (value == UINT64_MAX)
+ tprintf(", %s=UINT64_MAX", name);
+ else if (value || !abbrev(tcp))
+ tprintf(", %s=%" PRIu64, name, value);
+}
+#define print_key_value(tcp, key, name) \
+ __print_key_value((tcp), #name, (key)->name)
+
+static void
+btrfs_print_tree_search(struct tcb *tcp, struct btrfs_ioctl_search_key *key,
+ uint64_t buf_addr, uint64_t buf_size)
+{
+ if (entering(tcp)) {
+ tprintf("{key={tree_id=");
+ btrfs_print_objectid(key->tree_id);
+
+ if (key->min_objectid != BTRFS_FIRST_FREE_OBJECTID ||
+ !abbrev(tcp)) {
+ tprints(", min_objectid=");
+ btrfs_print_objectid(key->min_objectid);
+ }
+
+ if (key->max_objectid != BTRFS_LAST_FREE_OBJECTID ||
+ !abbrev(tcp)) {
+ tprints(", max_objectid=");
+ btrfs_print_objectid(key->max_objectid);
+ }
+
+ print_key_value(tcp, key, min_offset);
+ print_key_value(tcp, key, max_offset);
+ print_key_value(tcp, key, min_transid);
+ print_key_value(tcp, key, max_transid);
+ print_key_value(tcp, key, min_offset);
+
+ tprints(", min_type=");
+ btrfs_print_key_type(key->min_type);
+ tprints(", max_type=");
+ btrfs_print_key_type(key->max_type);
+ tprintf(", nr_items=%u}}", key->nr_items);
+ return;
+ }
+ tprintf("{key={nr_items=%u}, buf=", key->nr_items);
+ if (abbrev(tcp))
+ tprints("...");
+ else {
+ uint64_t i;
+ uint64_t off = 0;
+ tprints("[");
+ for (i = 0; i < key->nr_items; i++) {
+ struct btrfs_ioctl_search_header sh;
+ uint64_t addr = buf_addr + off;
+ if (i)
+ tprints(", ");
+ if (i > max_strlen ||
+ umoven(tcp, addr, sizeof(sh), &sh)) {
+ tprints("...");
+ break;
+ }
+ 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("}");
+}
+
+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_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_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,
+ "BTRFS_DEFRAG_RANGE_???");
+ 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=",
+ args.bytes_used, args.total_bytes);
+ print_quoted_string((const char *)args.path, sizeof(args.path),
+ QUOTE_0_TERMINATED);
+ tprints("}");
+ 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) {
+ const char *str;
+ tprintf(", start={srcdevid=%" PRI__u64 ", "
+ "cont_reading_from_srcdev_mode=%" PRI__u64
+ ", srcdev_name=",
+ args.start.srcdevid,
+ args.start.cont_reading_from_srcdev_mode);
+
+ str = (const char*) args.start.srcdev_name;
+ print_quoted_string(str,
+ sizeof(args.start.srcdev_name),
+ QUOTE_0_TERMINATED);
+ tprints(", tgtdev_name=");
+ str = (const char*) args.start.tgtdev_name;
+ print_quoted_string(str,
+ sizeof(args.start.tgtdev_name),
+ QUOTE_0_TERMINATED);
+ tprints("}");
+
+ }
+ 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[sizeof("HH:MM:SS") + 1];
+ time_t time;
+ tprints(", ");
+ printxvals(args.status.replace_state,
+ "BTRFS_IOCTL_DEV_REPLACE_STATE_???",
+ btrfs_dev_replace_state, NULL);
+ tprintf(", progress_1000=%" PRI__u64 " /* ",
+ args.status.progress_1000);
+ if (args.status.progress_1000 <= 1000)
+ tprintf("%" PRI__u64 ".%.2" PRI__u64 "%%",
+ args.status.progress_1000 / 10,
+ args.status.progress_1000 % 10);
+ else
+ tprints("???");
+ tprints(" */ ,");
+
+ 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);
+ }
+ tprints("}");
+ 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,
+ "BTRFS_DEV_STATS_???");
+
+ 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;
+
+ tprints("name=");
+ print_quoted_string(args.name, sizeof(args.name),
+ QUOTE_0_TERMINATED);
+ tprints("}");
+ break;
+ }
+
+ case BTRFS_IOC_INO_PATHS: { /* RW */
+ struct btrfs_ioctl_ino_path_args args;
+
+ 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;
+ }
+
+ tprints("fspath=");
+ btrfs_print_ino_path_container(tcp, args.fspath);
+
+ tprints("}");
+ break;
+ }
+
+ case BTRFS_IOC_LOGICAL_INO: { /* RW */
+ struct btrfs_ioctl_logical_ino_args args;
+
+ 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=");
+ btrfs_print_logical_ino_container(tcp, args.inodes);
+
+ tprints("}");
+ 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 == UINT64_MAX)
+ tprints("UINT64_MAX");
+ else
+ btrfs_print_objectid(args.progress);
+ tprints("}");
+ break;
+ }
+ case BTRFS_IOC_SET_RECEIVED_SUBVOL: { /* RW */
+#ifdef BTRFS_IOC_SET_RECEIVED_SUBVOL_32
+ case BTRFS_IOC_SET_RECEIVED_SUBVOL_32: { /* RW */
+ struct btrfs_ioctl_received_subvol_args_32 args32;
+#endif
+ struct btrfs_ioctl_received_subvol_args args;
+ char uuid[UUID_STRING_SIZE+1];
+
+ if (entering(tcp))
+ tprints(", ");
+ else if (syserror(tcp))
+ break;
+ else
+ tprints(" => ");
+
+#ifdef BTRFS_IOC_SET_RECEIVED_SUBVOL_32
+ /*
+ * This is a compat ioctl for 32 bit tools on
+ * 64 bit systems.
+ */
+ if (code == BTRFS_IOC_SET_RECEIVED_SUBVOL_32) {
+ if (umove_or_printaddr(tcp, arg, &args32))
+ break;
+ memcpy(args.uuid, args32.uuid, sizeof(uuid));
+ args.stransid = args32.stransid;
+ args.rtransid = args32.rtransid;
+ args.stime.sec = args32.stime.sec;
+ args.stime.nsec = args32.stime.nsec;
+ args.rtime.sec = args32.rtime.sec;
+ args.rtime.nsec = args32.rtime.nsec;
+ args.flags = args32.flags;
+ } else
+#endif
+ 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_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 == UINT64_MAX)
+ tprints("UINT64_MAX");
+ 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;
+ uint64_t buf_addr;
+
+ if (entering(tcp))
+ tprints(", ");
+ else if (syserror(tcp))
+ break;
+ else
+ tprints(" => ");
+
+ if (umove_or_printaddr(tcp, arg, &args))
+ break;
+
+ buf_addr = arg + offsetof(struct btrfs_ioctl_search_args, buf);
+ btrfs_print_tree_search(tcp, &args.key, buf_addr,
+ sizeof(args.buf));
+ if (entering(tcp))
+ return 0;
+ break;
+ }
+
+ case BTRFS_IOC_TREE_SEARCH_V2: { /* RW */
+ struct btrfs_ioctl_search_args_v2 args;
+ uint64_t buf_addr;
+
+ if (entering(tcp))
+ tprints(", ");
+ else if (syserror(tcp))
+ break;
+ else
+ tprints(" => ");
+
+ if (umove_or_printaddr(tcp, arg, &args))
+ break;
+
+ buf_addr = arg + offsetof(struct btrfs_ioctl_search_args, buf);
+ btrfs_print_tree_search(tcp, &args.key, buf_addr,
+ args.buf_size);
+ if (entering(tcp))
+ return 0;
+ break;
+ }
+
+ case BTRFS_IOC_SEND: { /* W */
+ struct btrfs_ioctl_send_args args;
+ uint64_t base_addr;
+ uint64_t i;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, arg, &args))
+ break;
+
+ tprintf("{send_fd=%" PRI__d64 ", clone_sources_count=%" PRI__u64
+ ", clone_sources=", args.send_fd,
+ args.clone_sources_count);
+
+ if (abbrev(tcp)) {
+ tprints("...}");
+ break;
+ }
+
+ tprints("[");
+ base_addr = (unsigned long)args.clone_sources;
+ for (i = 0; i < args.clone_sources_count; i++) {
+ uint64_t addr = base_addr + sizeof(uint64_t) * i;
+ uint64_t record;
+ if (i)
+ tprints(", ");
+ if (i > max_strlen ||
+ umoven(tcp, addr, sizeof(record), &record)) {
+ tprints("...");
+ break;
+ }
+ btrfs_print_objectid(record);
+ }
+ tprints("]}");
+ break;
+ }
+
+ case BTRFS_IOC_SPACE_INFO: { /* RW */
+ struct btrfs_ioctl_space_args args;
+ uint64_t spaces_addr;
+ 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;
+ }
+
+ tprints("[");
+
+ spaces_addr = arg + offsetof(typeof(args), spaces);
+ for (i = 0; i < args.total_spaces; i++) {
+ struct btrfs_ioctl_space_info info;
+ uint64_t addr = spaces_addr + sizeof(info) * i;
+ if (i)
+ tprints(", ");
+
+ if (i > max_strlen ||
+ umoven(tcp, addr, sizeof(info), &info)) {
+ tprints("...");
+ break;
+ }
+
+ tprints("{flags=");
+ printflags64(btrfs_space_info_flags, info.flags,
+ "BTRFS_SPACE_INFO_???");
+ tprintf(", total_bytes=%" PRI__u64 ", "
+ "used_bytes=%" PRI__u64 "}",
+ info.total_bytes, info.used_bytes);
+ }
+ tprints("]}");
+ 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__d64 ", name=", args.fd);
+ print_quoted_string(args.name, sizeof(args.name),
+ QUOTE_0_TERMINATED);
+ tprints("}");
+ 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__d64 ", flags=", args.fd);
+ printflags64(btrfs_snap_flags_v2, args.flags,
+ "BTRFS_SUBVOL_???");
+ if (args.flags & BTRFS_SUBVOL_QGROUP_INHERIT) {
+ tprintf(", size=%" PRI__u64 ", qgroup_inherit=",
+ args.size);
+
+ btrfs_print_qgroup_inherit(tcp,
+ (unsigned long)args.qgroup_inherit);
+
+ }
+ tprintf(", name=");
+ print_quoted_string(args.name, BTRFS_SUBVOL_NAME_MAX + 1,
+ QUOTE_0_TERMINATED);
+ 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;
+ print_quoted_string(label, sizeof(label), QUOTE_0_TERMINATED);
+ break;
+ }
+
+ case BTRFS_IOC_CLONE: /* FICLONE */
+ case BTRFS_IOC_CLONE_RANGE: /* FICLONERANGE */
+ case BTRFS_IOC_FILE_EXTENT_SAME: /* FIDEDUPERANGE */
+ /*
+ * FICLONE, FICLONERANGE, and FIDEDUPERANGE started out as
+ * btrfs ioctls and the code was kept for the generic
+ * implementations. We use the BTRFS_* names here because
+ * they will be available on older systems.
+ */
+ return file_ioctl(tcp, code, arg);
+
+ default:
+ return RVAL_DECODED;
+ };
+ return ret | RVAL_DECODED | 1;
+}
+#endif /* HAVE_LINUX_BTRFS_H */
diff --git a/configure.ac b/configure.ac
index 8a776d2..883dab5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -455,6 +455,14 @@ AC_CHECK_TYPES([struct statfs64], [
],, [#include <linux/types.h>
#include <asm/statfs.h>])
+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 d1e8e1b..7dd4d41 100644
--- a/defs.h
+++ b/defs.h
@@ -638,7 +638,9 @@ extern void print_struct_statfs(struct tcb *tcp, long);
extern void print_struct_statfs64(struct tcb *tcp, long, 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 file_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);
extern int ptp_ioctl(struct tcb *, const unsigned int, long);
diff --git a/file_ioctl.c b/file_ioctl.c
new file mode 100644
index 0000000..7caa6de
--- /dev/null
+++ b/file_ioctl.c
@@ -0,0 +1,163 @@
+/*
+ * 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>
+
+#ifndef FICLONE
+#define FICLONE _IOW(0x94, 9, int)
+#endif
+
+#ifndef FICLONERANGE
+#define FICLONERANGE _IOW(0x94, 13, struct file_clone_range)
+struct file_clone_range {
+ int64_t src_fd;
+ uint64_t src_offset;
+ uint64_t src_length;
+ uint64_t dest_offset;
+};
+#endif
+
+#ifndef FIDEDUPERANGE
+#define FIDEDUPERANGE _IOWR(0x94, 54, struct file_dedupe_range)
+struct file_dedupe_range_info {
+ int64_t dest_fd; /* in - destination file */
+ uint64_t dest_offset; /* in - start of extent in destination */
+ uint64_t bytes_deduped; /* out - total # of bytes we were able
+ * to dedupe from this file. */
+ /* status of this dedupe operation:
+ * < 0 for error
+ * == FILE_DEDUPE_RANGE_SAME if dedupe succeeds
+ * == FILE_DEDUPE_RANGE_DIFFERS if data differs
+ */
+ int32_t status; /* out - see above description */
+ uint32_t reserved; /* must be zero */
+};
+
+struct file_dedupe_range {
+ uint64_t src_offset; /* in - start of extent in source */
+ uint64_t src_length; /* in - length of extent */
+ uint16_t dest_count; /* in - total elements in info array */
+ uint16_t reserved1; /* must be zero */
+ uint32_t reserved2; /* must be zero */
+ struct file_dedupe_range_info info[0];
+};
+#endif
+
+int
+file_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
+{
+ int ret = 0;
+
+ switch (code) {
+ /* take a signed int */
+ case FICLONE: /* W */
+ printnum_int(tcp, arg, ", %d");
+ break;
+
+ case FICLONERANGE: { /* W */
+ struct file_clone_range args;
+
+ tprints(", ");
+
+ if (umove_or_printaddr(tcp, arg, &args))
+ break;
+
+ tprintf("{src_fd=%" PRIi64 ", "
+ "src_offset=%" PRIu64 ", "
+ "src_length=%" PRIu64 ", "
+ "dest_offset=%" PRIu64 "}",
+ (int64_t)args.src_fd, (uint64_t)args.src_offset,
+ (uint64_t)args.src_length, (uint64_t)args.dest_offset);
+ break;
+ }
+
+ case FIDEDUPERANGE: { /* RW */
+ struct file_dedupe_range args;
+ uint64_t info_addr;
+ uint16_t i;
+
+ if (entering(tcp))
+ tprints(", ");
+ else if (syserror(tcp))
+ break;
+ else
+ tprints(" => ");
+
+ if (umove_or_printaddr(tcp, arg, &args))
+ break;
+
+ if (entering(tcp)) {
+ tprintf("{src_offset=%" PRIu64 ", "
+ "src_length=%" PRIu64 ", "
+ "dest_count=%hu, info=",
+ (uint64_t)args.src_offset,
+ (uint64_t)args.src_length,
+ (uint16_t)args.dest_count);
+ } else
+ tprints("{info=");
+
+ if (abbrev(tcp)) {
+ tprints("...}");
+ break;
+ }
+
+ tprints("[");
+ info_addr = arg + offsetof(typeof(args), info);
+ for (i = 0; i < args.dest_count; i++) {
+ struct file_dedupe_range_info info;
+ uint64_t addr = info_addr + sizeof(info) * i;
+ if (i)
+ tprints(", ");
+
+ if (umoven(tcp, addr, sizeof(info), &info)) {
+ tprints("...");
+ break;
+ }
+
+ if (entering(tcp))
+ tprintf("{dest_fd=%" PRIi64 ", "
+ "dest_offset=%" PRIu64 "}",
+ (int64_t)info.dest_fd,
+ (uint64_t)info.dest_offset);
+ else {
+ tprintf("{bytes_deduped=%" PRIu64 ", "
+ "status=%d}",
+ (uint64_t)info.bytes_deduped,
+ info.status);
+ }
+
+ }
+
+ tprints("]}");
+ break;
+ }
+ default:
+ return RVAL_DECODED;
+ };
+ return ret | RVAL_DECODED | 1;
+}
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..b3a1ca1
--- /dev/null
+++ b/xlat/btrfs_balance_flags.in
@@ -0,0 +1,17 @@
+#val_type uint64_t
+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 (1ULL << 0)
+BTRFS_BALANCE_ARGS_USAGE (1ULL << 1)
+BTRFS_BALANCE_ARGS_DEVID (1ULL << 2)
+BTRFS_BALANCE_ARGS_DRANGE (1ULL << 3)
+BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4)
+BTRFS_BALANCE_ARGS_LIMIT (1ULL << 5)
+BTRFS_BALANCE_ARGS_LIMIT_RANGE (1ULL << 6)
+BTRFS_BALANCE_ARGS_STRIPES_RANGE (1ULL << 7)
+BTRFS_BALANCE_ARGS_CONVERT (1ULL << 8)
+BTRFS_BALANCE_ARGS_SOFT (1ULL << 9)
+BTRFS_BALANCE_ARGS_USAGE_RANGE (1ULL << 10)
diff --git a/xlat/btrfs_defrag_flags.in b/xlat/btrfs_defrag_flags.in
new file mode 100644
index 0000000..ae026c8
--- /dev/null
+++ b/xlat/btrfs_defrag_flags.in
@@ -0,0 +1,3 @@
+#val_type uint64_t
+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..18600f0
--- /dev/null
+++ b/xlat/btrfs_dev_replace_cmds.in
@@ -0,0 +1,4 @@
+#val_type uint64_t
+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..bf89282
--- /dev/null
+++ b/xlat/btrfs_dev_replace_results.in
@@ -0,0 +1,5 @@
+#val_type uint64_t
+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..bbc0ba1
--- /dev/null
+++ b/xlat/btrfs_dev_replace_state.in
@@ -0,0 +1,6 @@
+#val_type uint64_t
+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..9ff56c3
--- /dev/null
+++ b/xlat/btrfs_dev_stats_flags.in
@@ -0,0 +1,2 @@
+#val_type uint64_t
+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..ffb7405
--- /dev/null
+++ b/xlat/btrfs_dev_stats_values.in
@@ -0,0 +1,12 @@
+#val_type uint64_t
+#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..3fd1b6d
--- /dev/null
+++ b/xlat/btrfs_features_compat_ro.in
@@ -0,0 +1,2 @@
+#val_type uint64_t
+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..45baacf
--- /dev/null
+++ b/xlat/btrfs_features_incompat.in
@@ -0,0 +1,11 @@
+#val_type uint64_t
+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..fdd8b37
--- /dev/null
+++ b/xlat/btrfs_key_types.in
@@ -0,0 +1,41 @@
+#val_type uint64_t
+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..05e2003
--- /dev/null
+++ b/xlat/btrfs_qgroup_ctl_cmds.in
@@ -0,0 +1,4 @@
+#val_type uint64_t
+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..0e133b9
--- /dev/null
+++ b/xlat/btrfs_qgroup_inherit_flags.in
@@ -0,0 +1,2 @@
+#val_type uint64_t
+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..bac7abe
--- /dev/null
+++ b/xlat/btrfs_qgroup_limit_flags.in
@@ -0,0 +1,7 @@
+#val_type uint64_t
+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..86f60ac
--- /dev/null
+++ b/xlat/btrfs_qgroup_status_flags.in
@@ -0,0 +1,3 @@
+#val_type uint64_t
+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..914de3d
--- /dev/null
+++ b/xlat/btrfs_scrub_flags.in
@@ -0,0 +1,2 @@
+#val_type uint64_t
+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..43ea574
--- /dev/null
+++ b/xlat/btrfs_snap_flags_v2.in
@@ -0,0 +1,4 @@
+#val_type uint64_t
+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..be6d195
--- /dev/null
+++ b/xlat/btrfs_space_info_flags.in
@@ -0,0 +1,12 @@
+#val_type uint64_t
+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..4fc1f73
--- /dev/null
+++ b/xlat/btrfs_tree_objectids.in
@@ -0,0 +1,13 @@
+#val_type uint64_t
+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