|  | /* | 
|  | * Copyright (c) 2016 Jeff Mahoney <jeffm@suse.com> | 
|  | * Copyright (c) 2016-2018 The strace developers. | 
|  | * 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" | 
|  |  | 
|  | #ifdef HAVE_LINUX_BTRFS_H | 
|  |  | 
|  | #include DEF_MPERS_TYPE(struct_btrfs_ioctl_dev_replace_args) | 
|  | #include DEF_MPERS_TYPE(struct_btrfs_ioctl_send_args) | 
|  | #include DEF_MPERS_TYPE(struct_btrfs_ioctl_received_subvol_args) | 
|  | #include DEF_MPERS_TYPE(struct_btrfs_ioctl_vol_args_v2) | 
|  |  | 
|  | # include <linux/btrfs.h> | 
|  |  | 
|  | typedef struct btrfs_ioctl_dev_replace_args | 
|  | struct_btrfs_ioctl_dev_replace_args; | 
|  | typedef struct btrfs_ioctl_send_args | 
|  | struct_btrfs_ioctl_send_args; | 
|  | typedef struct btrfs_ioctl_received_subvol_args | 
|  | struct_btrfs_ioctl_received_subvol_args; | 
|  | typedef struct btrfs_ioctl_vol_args_v2 | 
|  | struct_btrfs_ioctl_vol_args_v2; | 
|  |  | 
|  | #endif /* HAVE_LINUX_BTRFS_H */ | 
|  |  | 
|  | #include MPERS_DEFS | 
|  |  | 
|  | #ifdef HAVE_LINUX_BTRFS_H | 
|  |  | 
|  | #include "print_fields.h" | 
|  | #include <linux/fs.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; | 
|  |  | 
|  | #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_IOC_QUOTA_RESCAN | 
|  | struct btrfs_ioctl_quota_rescan_args { | 
|  | uint64_t flags, progress, reserved[6]; | 
|  | }; | 
|  | # define BTRFS_IOC_QUOTA_RESCAN _IOW(BTRFS_IOCTL_MAGIC, 44, \ | 
|  | struct btrfs_ioctl_quota_rescan_args) | 
|  | # define BTRFS_IOC_QUOTA_RESCAN_STATUS _IOR(BTRFS_IOCTL_MAGIC, 45, \ | 
|  | struct btrfs_ioctl_quota_rescan_args) | 
|  | #endif | 
|  |  | 
|  | #ifndef BTRFS_IOC_QUOTA_RESCAN_WAIT | 
|  | # define BTRFS_IOC_QUOTA_RESCAN_WAIT _IO(BTRFS_IOCTL_MAGIC, 46) | 
|  | #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_args.h" | 
|  | #include "xlat/btrfs_balance_ctl_cmds.h" | 
|  | #include "xlat/btrfs_balance_flags.h" | 
|  | #include "xlat/btrfs_balance_state.h" | 
|  | #include "xlat/btrfs_compress_types.h" | 
|  | #include "xlat/btrfs_cont_reading_from_srcdev_mode.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_logical_ino_args_flags.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_send_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 = '\0'; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static void | 
|  | btrfs_print_balance_args(const char *name, const struct btrfs_balance_args *bba) | 
|  | { | 
|  | tprintf(", %s=", name); | 
|  | PRINT_FIELD_FLAGS("{", *bba, profiles, btrfs_space_info_flags, | 
|  | "BTRFS_BLOCK_GROUP_???"); | 
|  | PRINT_FIELD_U64(", ", *bba, usage); | 
|  | PRINT_FIELD_DEV(", ", *bba, devid); | 
|  | PRINT_FIELD_U64(", ", *bba, pstart); | 
|  | PRINT_FIELD_U64(", ", *bba, pend); | 
|  | PRINT_FIELD_U64(", ", *bba, vstart); | 
|  | PRINT_FIELD_U64(", ", *bba, vend); | 
|  | PRINT_FIELD_U64(", ", *bba, target); | 
|  | PRINT_FIELD_FLAGS(", ", *bba, flags, btrfs_balance_args, | 
|  | "BTRFS_BALANCE_ARGS_???"); | 
|  | tprints("}"); | 
|  | } | 
|  |  | 
|  | static void | 
|  | btrfs_print_balance(struct tcb *const tcp, const kernel_ulong_t arg, bool out) | 
|  | { | 
|  | struct btrfs_ioctl_balance_args balance_args; | 
|  |  | 
|  | if (umove_or_printaddr(tcp, arg, &balance_args)) | 
|  | return; | 
|  |  | 
|  | PRINT_FIELD_FLAGS("{", balance_args, flags, btrfs_balance_flags, | 
|  | "BTRFS_BALANCE_???"); | 
|  | if (out) | 
|  | PRINT_FIELD_FLAGS(", ", balance_args, state, | 
|  | btrfs_balance_state, | 
|  | "BTRFS_BALANCE_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(const struct btrfs_ioctl_feature_flags *flags) | 
|  | { | 
|  | PRINT_FIELD_FLAGS("{", *flags, compat_flags, btrfs_features_compat, | 
|  | "BTRFS_FEATURE_COMPAT_???"); | 
|  | PRINT_FIELD_FLAGS(", ", *flags, compat_ro_flags, | 
|  | btrfs_features_compat_ro, | 
|  | "BTRFS_FEATURE_COMPAT_RO_???"); | 
|  | PRINT_FIELD_FLAGS(", ", *flags, incompat_flags, btrfs_features_incompat, | 
|  | "BTRFS_FEATURE_INCOMPAT_???"); | 
|  | tprints("}"); | 
|  | } | 
|  |  | 
|  | static void | 
|  | btrfs_print_qgroup_limit(const struct btrfs_qgroup_limit *lim) | 
|  | { | 
|  | PRINT_FIELD_FLAGS(", lim={", *lim, flags, btrfs_qgroup_limit_flags, | 
|  | "BTRFS_QGROUP_LIMIT_???"); | 
|  | PRINT_FIELD_U(", ", *lim, max_rfer); | 
|  | PRINT_FIELD_U(", ", *lim, max_excl); | 
|  | PRINT_FIELD_U(", ", *lim, rsv_rfer); | 
|  | PRINT_FIELD_U(", ", *lim, rsv_excl); | 
|  | tprints("}"); | 
|  | } | 
|  |  | 
|  | #define btrfs_print_key_type(prefix_, where_, field_) \ | 
|  | PRINT_FIELD_XVAL_U((prefix_), (where_), field_, btrfs_key_types, NULL) | 
|  | #define btrfs_print_objectid(prefix_, where_, field_) \ | 
|  | PRINT_FIELD_XVAL_U((prefix_), (where_), field_, btrfs_tree_objectids, \ | 
|  | NULL) | 
|  |  | 
|  | static void | 
|  | btrfs_print_data_container_header(const struct btrfs_data_container *container) | 
|  | { | 
|  | PRINT_FIELD_U("{", *container, bytes_left); | 
|  | PRINT_FIELD_U(", ", *container, bytes_missing); | 
|  | PRINT_FIELD_U(", ", *container, elem_cnt); | 
|  | PRINT_FIELD_U(", ", *container, elem_missed); | 
|  | } | 
|  |  | 
|  | static void | 
|  | btrfs_print_data_container_footer(void) | 
|  | { | 
|  | tprints("}"); | 
|  | } | 
|  |  | 
|  | static bool | 
|  | print_btrfs_data_container_logical_ino(struct tcb *tcp, void *elem_buf, | 
|  | size_t elem_size, void *data) | 
|  | { | 
|  | const struct { | 
|  | uint64_t inum; | 
|  | uint64_t offset; | 
|  | uint64_t root; | 
|  | } *const record = elem_buf; | 
|  |  | 
|  | PRINT_FIELD_U("{", *record, inum); | 
|  | PRINT_FIELD_U(", ", *record, offset); | 
|  | PRINT_FIELD_U(", ", *record, root); | 
|  | tprints("}"); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static void | 
|  | btrfs_print_logical_ino_container(struct tcb *tcp, | 
|  | const uint64_t inodes_addr) | 
|  | { | 
|  | struct btrfs_data_container container; | 
|  |  | 
|  | if (umove_or_printaddr(tcp, inodes_addr, &container)) | 
|  | return; | 
|  |  | 
|  | btrfs_print_data_container_header(&container); | 
|  |  | 
|  | if (abbrev(tcp)) { | 
|  | tprints(", ..."); | 
|  | } else { | 
|  | const uint64_t val_addr = | 
|  | inodes_addr + offsetof(typeof(container), val); | 
|  | uint64_t record[3]; | 
|  | tprints(", val="); | 
|  | print_array(tcp, val_addr, container.elem_cnt / 3, | 
|  | record, sizeof(record), | 
|  | tfetch_mem, | 
|  | print_btrfs_data_container_logical_ino, 0); | 
|  | } | 
|  |  | 
|  | btrfs_print_data_container_footer(); | 
|  | } | 
|  |  | 
|  | static bool | 
|  | print_btrfs_data_container_ino_path(struct tcb *tcp, void *elem_buf, | 
|  | size_t elem_size, void *data) | 
|  | { | 
|  | const uint64_t *const offset = elem_buf; | 
|  | const uint64_t *const val_addr = data; | 
|  |  | 
|  | printpath(tcp, *val_addr + *offset); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static void | 
|  | btrfs_print_ino_path_container(struct tcb *tcp, | 
|  | const uint64_t fspath_addr) | 
|  | { | 
|  | struct btrfs_data_container container; | 
|  |  | 
|  | if (umove_or_printaddr(tcp, fspath_addr, &container)) | 
|  | return; | 
|  |  | 
|  | btrfs_print_data_container_header(&container); | 
|  |  | 
|  | if (abbrev(tcp)) { | 
|  | tprints(", ..."); | 
|  | } else { | 
|  | uint64_t val_addr = | 
|  | fspath_addr + offsetof(typeof(container), val); | 
|  | uint64_t offset; | 
|  | tprints(", val="); | 
|  | print_array(tcp, val_addr, container.elem_cnt, | 
|  | &offset, sizeof(offset), | 
|  | tfetch_mem, | 
|  | print_btrfs_data_container_ino_path, &val_addr); | 
|  | } | 
|  |  | 
|  | btrfs_print_data_container_footer(); | 
|  | } | 
|  |  | 
|  | static void | 
|  | btrfs_print_qgroup_inherit(struct tcb *const tcp, const kernel_ulong_t qgi_addr) | 
|  | { | 
|  | struct btrfs_qgroup_inherit inherit; | 
|  |  | 
|  | if (umove_or_printaddr(tcp, qgi_addr, &inherit)) | 
|  | return; | 
|  |  | 
|  | PRINT_FIELD_FLAGS("{", inherit, flags, btrfs_qgroup_inherit_flags, | 
|  | "BTRFS_QGROUP_INHERIT_???"); | 
|  | PRINT_FIELD_U(", ", inherit, num_qgroups); | 
|  | PRINT_FIELD_U(", ", inherit, num_ref_copies); | 
|  | PRINT_FIELD_U(", ", inherit, num_excl_copies); | 
|  |  | 
|  | btrfs_print_qgroup_limit(&inherit.lim); | 
|  |  | 
|  | if (abbrev(tcp)) { | 
|  | tprints(", ..."); | 
|  | } else { | 
|  | uint64_t record; | 
|  | tprints(", qgroups="); | 
|  | print_array(tcp, qgi_addr + offsetof(typeof(inherit), qgroups), | 
|  | inherit.num_qgroups, &record, sizeof(record), | 
|  | tfetch_mem, print_uint64_array_member, 0); | 
|  | } | 
|  | tprints("}"); | 
|  | } | 
|  |  | 
|  | static void | 
|  | btrfs_print_tree_search(struct tcb *tcp, struct btrfs_ioctl_search_key *key, | 
|  | uint64_t buf_addr, uint64_t buf_size, bool print_size) | 
|  | { | 
|  | if (entering(tcp)) { | 
|  | btrfs_print_objectid("{key={", *key, tree_id); | 
|  |  | 
|  | if (key->min_objectid != BTRFS_FIRST_FREE_OBJECTID || | 
|  | !abbrev(tcp)) | 
|  | btrfs_print_objectid(", ", *key, min_objectid); | 
|  |  | 
|  | if (key->max_objectid != BTRFS_LAST_FREE_OBJECTID || | 
|  | !abbrev(tcp)) | 
|  | btrfs_print_objectid(", ", *key, max_objectid); | 
|  |  | 
|  | PRINT_FIELD_U64(", ", *key, min_offset); | 
|  | PRINT_FIELD_U64(", ", *key, max_offset); | 
|  | PRINT_FIELD_U64(", ", *key, min_transid); | 
|  | PRINT_FIELD_U64(", ", *key, max_transid); | 
|  |  | 
|  | btrfs_print_key_type(", ", *key, min_type); | 
|  | btrfs_print_key_type(", ", *key, max_type); | 
|  | PRINT_FIELD_U(", ", *key, nr_items); | 
|  | tprints("}"); | 
|  | if (print_size) | 
|  | tprintf(", buf_size=%" PRIu64, buf_size); | 
|  | tprints("}"); | 
|  | } else { | 
|  | PRINT_FIELD_U("{key={", *key, nr_items); | 
|  | tprints("}"); | 
|  | if (print_size) | 
|  | tprintf(", buf_size=%" PRIu64, buf_size); | 
|  | if (abbrev(tcp)) { | 
|  | tprints(", ..."); | 
|  | } else { | 
|  | uint64_t i; | 
|  | uint64_t off = 0; | 
|  | tprints(", buf=["); | 
|  | 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) { | 
|  | tprints("..."); | 
|  | break; | 
|  | } | 
|  | if (umove(tcp, addr, &sh)) { | 
|  | tprints("..."); | 
|  | printaddr_comment(addr); | 
|  | break; | 
|  | } | 
|  | PRINT_FIELD_U("{", sh, transid); | 
|  | btrfs_print_objectid(", ", sh, objectid); | 
|  | PRINT_FIELD_U(", ", sh, offset); | 
|  | btrfs_print_key_type(", ", sh, type); | 
|  | PRINT_FIELD_U(", ", sh, len); | 
|  | tprints("}"); | 
|  | off += sizeof(sh) + sh.len; | 
|  |  | 
|  | } | 
|  | tprints("]"); | 
|  | } | 
|  | tprints("}"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static bool | 
|  | print_objectid_callback(struct tcb *tcp, void *elem_buf, | 
|  | size_t elem_size, void *data) | 
|  | { | 
|  | printxvals_ex(*(uint64_t *) elem_buf, NULL, XLAT_STYLE_FMT_U, | 
|  | btrfs_tree_objectids, NULL); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool | 
|  | print_btrfs_ioctl_space_info(struct tcb *tcp, void *elem_buf, | 
|  | size_t elem_size, void *data) | 
|  | { | 
|  | const struct btrfs_ioctl_space_info *info = elem_buf; | 
|  |  | 
|  | PRINT_FIELD_FLAGS("{", *info, flags, btrfs_space_info_flags, | 
|  | "BTRFS_SPACE_INFO_???"); | 
|  | PRINT_FIELD_U(", ", *info, total_bytes); | 
|  | PRINT_FIELD_U(", ", *info, used_bytes); | 
|  | tprints("}"); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static void | 
|  | print_btrfs_timespec(const char *prefix, uint64_t sec, uint32_t nsec) | 
|  | { | 
|  | tprintf("%s{sec=%" PRIu64 ", nsec=%u}", prefix, sec, nsec); | 
|  | tprints_comment(sprinttime_nsec(sec, nsec)); | 
|  | } | 
|  |  | 
|  | MPERS_PRINTER_DECL(int, btrfs_ioctl, | 
|  | struct tcb *const tcp, const unsigned int code, | 
|  | const kernel_ulong_t arg) | 
|  | { | 
|  | 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: | 
|  | /* | 
|  | * The codes for these ioctls are based on each accepting a | 
|  | * vol_args but none of them actually consume an argument. | 
|  | */ | 
|  | case BTRFS_IOC_DEFRAG: | 
|  | case BTRFS_IOC_BALANCE: | 
|  | break; | 
|  |  | 
|  | /* takes a signed int */ | 
|  | case BTRFS_IOC_BALANCE_CTL: | 
|  | tprints(", "); | 
|  | printxval(btrfs_balance_ctl_cmds, arg, "BTRFS_BALANCE_CTL_???"); | 
|  | break; | 
|  |  | 
|  | /* returns a 64 */ | 
|  | case BTRFS_IOC_START_SYNC: /* R */ | 
|  | if (entering(tcp)) | 
|  | return 0; | 
|  | ATTRIBUTE_FALLTHROUGH; | 
|  | /* takes 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; | 
|  |  | 
|  | PRINT_FIELD_U("{", args, start); | 
|  | PRINT_FIELD_U64(", ", args, len); | 
|  |  | 
|  | PRINT_FIELD_FLAGS(", ", args, flags, btrfs_defrag_flags, | 
|  | "BTRFS_DEFRAG_RANGE_???"); | 
|  | PRINT_FIELD_U(", ", args, extent_thresh); | 
|  | PRINT_FIELD_XVAL(", ", args, compress_type, | 
|  | btrfs_compress_types, "BTRFS_COMPRESS_???"); | 
|  | tprints("}"); | 
|  | 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; | 
|  |  | 
|  | valid = btrfs_unparse_uuid(args.uuid, uuid); | 
|  | if (entering(tcp)) { | 
|  | PRINT_FIELD_DEV("{", args, devid); | 
|  | if (valid) | 
|  | tprintf(", uuid=%s", uuid); | 
|  | tprints("}"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | tprints("{"); | 
|  | if (valid) | 
|  | tprintf("uuid=%s, ", uuid); | 
|  |  | 
|  | PRINT_FIELD_U("", args, bytes_used); | 
|  | PRINT_FIELD_U(", ", args, total_bytes); | 
|  | PRINT_FIELD_CSTRING(", ", args, path); | 
|  | tprints("}"); | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BTRFS_IOC_DEV_REPLACE: { /* RW */ | 
|  | struct_btrfs_ioctl_dev_replace_args args; | 
|  |  | 
|  | if (entering(tcp)) | 
|  | tprints(", "); | 
|  | else if (syserror(tcp)) | 
|  | break; | 
|  | else | 
|  | tprints(" => "); | 
|  |  | 
|  | if (umove_or_printaddr(tcp, arg, &args)) | 
|  | break; | 
|  |  | 
|  | if (entering(tcp)) { | 
|  | PRINT_FIELD_XVAL("{", args, cmd, btrfs_dev_replace_cmds, | 
|  | "BTRFS_IOCTL_DEV_REPLACE_CMD_???"); | 
|  | if (args.cmd == BTRFS_IOCTL_DEV_REPLACE_CMD_START) { | 
|  | PRINT_FIELD_DEV(", start={", args.start, | 
|  | srcdevid); | 
|  | PRINT_FIELD_XVAL(", ", args.start, | 
|  | cont_reading_from_srcdev_mode, | 
|  | btrfs_cont_reading_from_srcdev_mode, | 
|  | "BTRFS_IOCTL_DEV_REPLACE_CONT_READING" | 
|  | "_FROM_SRCDEV_MODE_???"); | 
|  | PRINT_FIELD_CSTRING(", ", args.start, | 
|  | srcdev_name); | 
|  | PRINT_FIELD_CSTRING(", ", args.start, | 
|  | tgtdev_name); | 
|  | tprints("}"); | 
|  |  | 
|  | } | 
|  | tprints("}"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | PRINT_FIELD_XVAL("{", args, result, btrfs_dev_replace_results, | 
|  | "BTRFS_IOCTL_DEV_REPLACE_RESULT_???"); | 
|  | if (args.cmd == BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS) { | 
|  | PRINT_FIELD_XVAL(", status={", args.status, | 
|  | replace_state, btrfs_dev_replace_state, | 
|  | "BTRFS_IOCTL_DEV_REPLACE_STATE_???"); | 
|  |  | 
|  | PRINT_FIELD_U(", ", args.status, progress_1000); | 
|  | if (args.status.progress_1000 <= 1000) | 
|  | tprintf_comment("%u.%u%%", | 
|  | (unsigned) args.status.progress_1000 / 10, | 
|  | (unsigned) args.status.progress_1000 % 10); | 
|  |  | 
|  | PRINT_FIELD_U(", ", args.status, time_started); | 
|  | tprints_comment(sprinttime(args.status.time_started)); | 
|  |  | 
|  | PRINT_FIELD_U(", ", args.status, time_stopped); | 
|  | tprints_comment(sprinttime(args.status.time_stopped)); | 
|  |  | 
|  | PRINT_FIELD_U(", ", args.status, num_write_errors); | 
|  | PRINT_FIELD_U(", ", 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("["); | 
|  | btrfs_print_features(&flarg[0]); | 
|  | tprints_comment("supported"); | 
|  |  | 
|  | tprints(", "); | 
|  | btrfs_print_features(&flarg[1]); | 
|  | tprints_comment("safe to set"); | 
|  |  | 
|  | tprints(", "); | 
|  | btrfs_print_features(&flarg[2]); | 
|  | tprints_comment("safe to clear"); | 
|  | 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 | 
|  | uint32_t *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 = (void *) args.reserved; | 
|  | nodesize = reserved32[0]; | 
|  | sectorsize = reserved32[1]; | 
|  | clone_alignment = reserved32[2]; | 
|  | #endif | 
|  | btrfs_unparse_uuid(args.fsid, uuid); | 
|  |  | 
|  | PRINT_FIELD_U("{", args, max_id); | 
|  | PRINT_FIELD_U(", ", args, num_devices); | 
|  | tprintf(", fsid=%s, nodesize=%u, sectorsize=%u" | 
|  | ", clone_alignment=%u", | 
|  | 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)) { | 
|  | PRINT_FIELD_DEV("", args, devid); | 
|  | tprints(", "); | 
|  | } | 
|  |  | 
|  | PRINT_FIELD_U("", args, nr_items); | 
|  | PRINT_FIELD_FLAGS(", ", args, flags, btrfs_dev_stats_flags, | 
|  | "BTRFS_DEV_STATS_???"); | 
|  |  | 
|  | if (entering(tcp)) { | 
|  | tprints("}"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * The structure has a 1k limit; Let's make sure we don't | 
|  | * go off into the middle of nowhere with a bad nr_items | 
|  | * value. | 
|  | */ | 
|  | tprints(", ["); | 
|  | for (i = 0; i < args.nr_items; i++) { | 
|  | if (i) | 
|  | tprints(", "); | 
|  | if (i >= ARRAY_SIZE(args.values)) { | 
|  | tprints("..."); | 
|  | break; | 
|  | } | 
|  |  | 
|  | tprints("["); | 
|  | printxval_u(btrfs_dev_stats_values, i, NULL); | 
|  | 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) | 
|  | set_tcb_priv_ulong(tcp, 1); | 
|  |  | 
|  | btrfs_print_objectid("{", args, treeid); | 
|  | btrfs_print_objectid(", ", args, objectid); | 
|  | tprints("}"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | tprints("{"); | 
|  | if (get_tcb_priv_ulong(tcp)) { | 
|  | btrfs_print_objectid("", args, treeid); | 
|  | tprints(", "); | 
|  | } | 
|  |  | 
|  | PRINT_FIELD_CSTRING("", args, name); | 
|  | 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; | 
|  |  | 
|  | if (entering(tcp)) { | 
|  | PRINT_FIELD_U("{", args, inum); | 
|  | PRINT_FIELD_U(", ", args, size); | 
|  | PRINT_FIELD_ADDR64(", ", args, fspath); | 
|  | tprints("}"); | 
|  | 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; | 
|  |  | 
|  | if (entering(tcp)) { | 
|  | PRINT_FIELD_U("{", args, logical); | 
|  | PRINT_FIELD_U(", ", args, size); | 
|  |  | 
|  | if (!IS_ARRAY_ZERO(args.reserved)) { | 
|  | tprints(", reserved=["); | 
|  | for (size_t i = 0; i < 3; ++i) | 
|  | tprintf("%s%#" PRI__x64, | 
|  | i ? ", " : "", | 
|  | args.reserved[i]); | 
|  | tprints("]"); | 
|  | } | 
|  |  | 
|  | tprintf(", flags="); | 
|  | printflags64(btrfs_logical_ino_args_flags, | 
|  | #ifdef HAVE_STRUCT_BTRFS_IOCTL_LOGICAL_INO_ARGS_FLAGS | 
|  | args.flags | 
|  | #else | 
|  | args.reserved[3] | 
|  | #endif | 
|  | , "BTRFS_LOGICAL_INO_ARGS_???"); | 
|  | PRINT_FIELD_ADDR64(", ", args, inodes); | 
|  | tprints("}"); | 
|  | 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; | 
|  |  | 
|  | PRINT_FIELD_U("{", args, assign); | 
|  | PRINT_FIELD_U(", ", args, src); | 
|  | PRINT_FIELD_U(", ", args, dst); | 
|  | tprints("}"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BTRFS_IOC_QGROUP_CREATE: { /* W */ | 
|  | struct btrfs_ioctl_qgroup_create_args args; | 
|  |  | 
|  | tprints(", "); | 
|  | if (umove_or_printaddr(tcp, arg, &args)) | 
|  | break; | 
|  |  | 
|  | PRINT_FIELD_U("{", args, create); | 
|  | PRINT_FIELD_U(", ", args, qgroupid); | 
|  | tprints("}"); | 
|  | 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; | 
|  |  | 
|  | PRINT_FIELD_U("{", 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; | 
|  |  | 
|  | PRINT_FIELD_XVAL("{", args, cmd, btrfs_qgroup_ctl_cmds, | 
|  | "BTRFS_QUOTA_CTL_???"); | 
|  | tprints("}"); | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BTRFS_IOC_QUOTA_RESCAN: { /* W */ | 
|  | struct btrfs_ioctl_quota_rescan_args args; | 
|  |  | 
|  | tprints(", "); | 
|  | if (umove_or_printaddr(tcp, arg, &args)) | 
|  | break; | 
|  |  | 
|  | PRINT_FIELD_U("{", args, flags); | 
|  | tprints("}"); | 
|  | 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; | 
|  |  | 
|  | PRINT_FIELD_U("{", args, flags); | 
|  | 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", uuid); | 
|  | PRINT_FIELD_U(", ", args, stransid); | 
|  | print_btrfs_timespec(", stime=", | 
|  | args.stime.sec, args.stime.nsec); | 
|  | PRINT_FIELD_U(", ", args, flags); | 
|  | tprints("}"); | 
|  | return 0; | 
|  | } | 
|  | PRINT_FIELD_U("{", args, rtransid); | 
|  | print_btrfs_timespec(", rtime=", | 
|  | args.rtime.sec, args.rtime.nsec); | 
|  | tprints("}"); | 
|  | 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)) { | 
|  | PRINT_FIELD_DEV("{", args, devid); | 
|  | if (code == BTRFS_IOC_SCRUB) { | 
|  | PRINT_FIELD_U(", ", args, start); | 
|  | PRINT_FIELD_U64(", ", args, end); | 
|  | PRINT_FIELD_FLAGS(", ", args, flags, | 
|  | btrfs_scrub_flags, | 
|  | "BTRFS_SCRUB_???"); | 
|  | } | 
|  | tprints("}"); | 
|  | return 0; | 
|  | } | 
|  | PRINT_FIELD_U("{progress={", args.progress, | 
|  | data_extents_scrubbed); | 
|  | PRINT_FIELD_U(", ", args.progress, tree_extents_scrubbed); | 
|  | PRINT_FIELD_U(", ", args.progress, data_bytes_scrubbed); | 
|  | PRINT_FIELD_U(", ", args.progress, tree_bytes_scrubbed); | 
|  | PRINT_FIELD_U(", ", args.progress, read_errors); | 
|  | PRINT_FIELD_U(", ", args.progress, csum_errors); | 
|  | PRINT_FIELD_U(", ", args.progress, verify_errors); | 
|  | PRINT_FIELD_U(", ", args.progress, no_csum); | 
|  | PRINT_FIELD_U(", ", args.progress, csum_discards); | 
|  | PRINT_FIELD_U(", ", args.progress, super_errors); | 
|  | PRINT_FIELD_U(", ", args.progress, malloc_errors); | 
|  | PRINT_FIELD_U(", ", args.progress, uncorrectable_errors); | 
|  | PRINT_FIELD_U(", ", args.progress, corrected_errors); | 
|  | PRINT_FIELD_U(", ", args.progress, last_physical); | 
|  | PRINT_FIELD_U(", ", args.progress, unverified_errors); | 
|  | tprints("}}"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BTRFS_IOC_TREE_SEARCH: { /* RW */ | 
|  | struct btrfs_ioctl_search_args args; | 
|  | uint64_t buf_offset; | 
|  |  | 
|  | if (entering(tcp)) | 
|  | tprints(", "); | 
|  | else if (syserror(tcp)) | 
|  | break; | 
|  | else | 
|  | tprints(" => "); | 
|  |  | 
|  | if (umove_or_printaddr(tcp, arg, &args)) | 
|  | break; | 
|  |  | 
|  | buf_offset = offsetof(struct btrfs_ioctl_search_args, buf); | 
|  | btrfs_print_tree_search(tcp, &args.key, arg + buf_offset, | 
|  | sizeof(args.buf), false); | 
|  | if (entering(tcp)) | 
|  | return 0; | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BTRFS_IOC_TREE_SEARCH_V2: { /* RW */ | 
|  | struct btrfs_ioctl_search_args_v2 args; | 
|  | uint64_t buf_offset; | 
|  |  | 
|  | if (entering(tcp)) | 
|  | tprints(", "); | 
|  | else if (syserror(tcp)) { | 
|  | if (tcp->u_error == EOVERFLOW) { | 
|  | tprints(" => "); | 
|  | if (!umove_or_printaddr_ignore_syserror(tcp, | 
|  | arg, &args)) { | 
|  | PRINT_FIELD_U("{", args, buf_size); | 
|  | tprints("}"); | 
|  | } | 
|  | } | 
|  | break; | 
|  | } else | 
|  | tprints(" => "); | 
|  |  | 
|  | if (umove_or_printaddr(tcp, arg, &args)) | 
|  | break; | 
|  |  | 
|  | buf_offset = offsetof(struct btrfs_ioctl_search_args_v2, buf); | 
|  | btrfs_print_tree_search(tcp, &args.key, arg + buf_offset, | 
|  | args.buf_size, true); | 
|  | if (entering(tcp)) | 
|  | return 0; | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BTRFS_IOC_SEND: { /* W */ | 
|  | struct_btrfs_ioctl_send_args args; | 
|  |  | 
|  | tprints(", "); | 
|  | if (umove_or_printaddr(tcp, arg, &args)) | 
|  | break; | 
|  |  | 
|  | PRINT_FIELD_FD("{", args, send_fd, tcp); | 
|  | PRINT_FIELD_U(", ", args, clone_sources_count); | 
|  |  | 
|  | tprints(", clone_sources="); | 
|  | if (abbrev(tcp)) | 
|  | printaddr((uintptr_t) args.clone_sources); | 
|  | else { | 
|  | uint64_t record; | 
|  | print_array(tcp, ptr_to_kulong(args.clone_sources), | 
|  | args.clone_sources_count, | 
|  | &record, sizeof(record), | 
|  | tfetch_mem, | 
|  | print_objectid_callback, 0); | 
|  | } | 
|  | btrfs_print_objectid(", ", args, parent_root); | 
|  | PRINT_FIELD_FLAGS(", ", args, flags, btrfs_send_flags, | 
|  | "BTRFS_SEND_FLAGS_???"); | 
|  | tprints("}"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BTRFS_IOC_SPACE_INFO: { /* RW */ | 
|  | struct btrfs_ioctl_space_args args; | 
|  |  | 
|  | if (entering(tcp)) | 
|  | tprints(", "); | 
|  | else if (syserror(tcp)) | 
|  | break; | 
|  | else | 
|  | tprints(" => "); | 
|  |  | 
|  | if (umove_or_printaddr(tcp, arg, &args)) | 
|  | break; | 
|  |  | 
|  | if (entering(tcp)) { | 
|  | PRINT_FIELD_U("{", args, space_slots); | 
|  | tprints("}"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | PRINT_FIELD_U("{", args, total_spaces); | 
|  |  | 
|  | if (args.space_slots == 0 && args.total_spaces) { | 
|  | tprints("}"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (abbrev(tcp)) { | 
|  | tprints(", ..."); | 
|  | } else { | 
|  | struct btrfs_ioctl_space_info info; | 
|  | tprints(", spaces="); | 
|  | print_array(tcp, arg + offsetof(typeof(args), spaces), | 
|  | args.total_spaces, | 
|  | &info, sizeof(info), tfetch_mem, | 
|  | print_btrfs_ioctl_space_info, 0); | 
|  | } | 
|  | tprints("}"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BTRFS_IOC_SNAP_CREATE: | 
|  | case BTRFS_IOC_RESIZE: | 
|  | case BTRFS_IOC_SCAN_DEV: | 
|  | case BTRFS_IOC_ADD_DEV: | 
|  | case BTRFS_IOC_RM_DEV: | 
|  | 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; | 
|  |  | 
|  | PRINT_FIELD_FD("{", args, fd, tcp); | 
|  | PRINT_FIELD_CSTRING(", ", args, name); | 
|  | tprints("}"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BTRFS_IOC_SNAP_CREATE_V2: | 
|  | case BTRFS_IOC_SUBVOL_CREATE_V2: { /* code is W, but is actually RW */ | 
|  | struct_btrfs_ioctl_vol_args_v2 args; | 
|  |  | 
|  | if (entering(tcp)) | 
|  | tprints(", "); | 
|  | else if (syserror(tcp)) | 
|  | break; | 
|  | else | 
|  | tprints(" => "); | 
|  |  | 
|  | if (umove_or_printaddr(tcp, arg, &args)) | 
|  | break; | 
|  |  | 
|  | if (entering(tcp)) { | 
|  | PRINT_FIELD_FD("{", args, fd, tcp); | 
|  | PRINT_FIELD_FLAGS(", ", args, flags, | 
|  | btrfs_snap_flags_v2, | 
|  | "BTRFS_SUBVOL_???"); | 
|  | if (args.flags & BTRFS_SUBVOL_QGROUP_INHERIT) { | 
|  | PRINT_FIELD_U(", ", args, size); | 
|  | tprints(", qgroup_inherit="); | 
|  | btrfs_print_qgroup_inherit(tcp, | 
|  | ptr_to_kulong(args.qgroup_inherit)); | 
|  | } | 
|  | PRINT_FIELD_CSTRING(", ", args, name); | 
|  | tprints("}"); | 
|  | return 0; | 
|  | } | 
|  | PRINT_FIELD_U("{", args, transid); | 
|  | tprints("}"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BTRFS_IOC_GET_FSLABEL: /* R */ | 
|  | if (entering(tcp)) | 
|  | return 0; | 
|  | ATTRIBUTE_FALLTHROUGH; | 
|  | case BTRFS_IOC_SET_FSLABEL: { /* W */ | 
|  | char label[BTRFS_LABEL_SIZE]; | 
|  |  | 
|  | tprints(", "); | 
|  | if (umove_or_printaddr(tcp, arg, &label)) | 
|  | break; | 
|  | print_quoted_cstring(label, sizeof(label)); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case BTRFS_IOC_CLONE:			/* FICLONE */ | 
|  | case BTRFS_IOC_CLONE_RANGE:		/* FICLONERANGE */ | 
|  | #ifdef BTRFS_IOC_FILE_EXTENT_SAME | 
|  | case BTRFS_IOC_FILE_EXTENT_SAME:	/* FIDEDUPERANGE */ | 
|  | #endif | 
|  | /* | 
|  | * 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 RVAL_IOCTL_DECODED; | 
|  | } | 
|  | #endif /* HAVE_LINUX_BTRFS_H */ |