return ret;
}
+static const char * const cmd_dev_stats_usage[] = {
+ "btrfs device stats [-z] <path>|<device>",
+ "Show current device IO stats. -z to reset stats afterwards.",
+ NULL
+};
+
+static int cmd_dev_stats(int argc, char **argv)
+{
+ char *path;
+ struct btrfs_ioctl_fs_info_args fi_args;
+ struct btrfs_ioctl_dev_info_args *di_args = NULL;
+ int ret;
+ int fdmnt;
+ int i;
+ char c;
+ int fdres = -1;
+ int err = 0;
+ __u64 flags = 0;
+
+ optind = 1;
+ while ((c = getopt(argc, argv, "z")) != -1) {
+ switch (c) {
+ case 'z':
+ flags = BTRFS_DEV_STATS_RESET;
+ break;
+ case '?':
+ default:
+ fprintf(stderr, "ERROR: device stat args invalid.\n"
+ " device stat [-z] <path>|<device>\n"
+ " -z to reset stats after reading.\n");
+ return 1;
+ }
+ }
+
+ if (optind + 1 != argc) {
+ fprintf(stderr, "ERROR: device stat needs path|device as single"
+ " argument\n");
+ return 1;
+ }
+
+ path = argv[optind];
+
+ fdmnt = open_file_or_dir(path);
+ if (fdmnt < 0) {
+ fprintf(stderr, "ERROR: can't access '%s'\n", path);
+ return 12;
+ }
+
+ ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
+ if (ret) {
+ fprintf(stderr, "ERROR: getting dev info for devstats failed: "
+ "%s\n", strerror(-ret));
+ err = 1;
+ goto out;
+ }
+ if (!fi_args.num_devices) {
+ fprintf(stderr, "ERROR: no devices found\n");
+ err = 1;
+ goto out;
+ }
+
+ for (i = 0; i < fi_args.num_devices; i++) {
+ struct btrfs_ioctl_get_dev_stats args = {0};
+ __u8 path[BTRFS_DEVICE_PATH_NAME_MAX + 1];
+
+ strncpy((char *)path, (char *)di_args[i].path,
+ BTRFS_DEVICE_PATH_NAME_MAX);
+ path[BTRFS_DEVICE_PATH_NAME_MAX] = '\0';
+
+ args.devid = di_args[i].devid;
+ args.nr_items = BTRFS_DEV_STAT_VALUES_MAX;
+ args.flags = flags;
+
+ if (ioctl(fdmnt, BTRFS_IOC_GET_DEV_STATS, &args) < 0) {
+ fprintf(stderr,
+ "ERROR: ioctl(BTRFS_IOC_GET_DEV_STATS) on %s failed: %s\n",
+ path, strerror(errno));
+ err = 1;
+ } else {
+ if (args.nr_items >= BTRFS_DEV_STAT_WRITE_ERRS + 1)
+ printf("[%s].write_io_errs %llu\n",
+ path,
+ (unsigned long long) args.values[
+ BTRFS_DEV_STAT_WRITE_ERRS]);
+ if (args.nr_items >= BTRFS_DEV_STAT_READ_ERRS + 1)
+ printf("[%s].read_io_errs %llu\n",
+ path,
+ (unsigned long long) args.values[
+ BTRFS_DEV_STAT_READ_ERRS]);
+ if (args.nr_items >= BTRFS_DEV_STAT_FLUSH_ERRS + 1)
+ printf("[%s].flush_io_errs %llu\n",
+ path,
+ (unsigned long long) args.values[
+ BTRFS_DEV_STAT_FLUSH_ERRS]);
+ if (args.nr_items >= BTRFS_DEV_STAT_CORRUPTION_ERRS + 1)
+ printf("[%s].corruption_errs %llu\n",
+ path,
+ (unsigned long long) args.values[
+ BTRFS_DEV_STAT_CORRUPTION_ERRS]);
+ if (args.nr_items >= BTRFS_DEV_STAT_GENERATION_ERRS + 1)
+ printf("[%s].generation_errs %llu\n",
+ path,
+ (unsigned long long) args.values[
+ BTRFS_DEV_STAT_GENERATION_ERRS]);
+ }
+ }
+
+out:
+ free(di_args);
+ close(fdmnt);
+ if (fdres > -1)
+ close(fdres);
+
+ return err;
+}
+
const struct cmd_group device_cmd_group = {
device_cmd_group_usage, NULL, {
{ "add", cmd_add_dev, cmd_add_dev_usage, NULL, 0 },
{ "delete", cmd_rm_dev, cmd_rm_dev_usage, NULL, 0 },
{ "scan", cmd_scan_dev, cmd_scan_dev_usage, NULL, 0 },
{ "ready", cmd_ready_dev, cmd_ready_dev_usage, NULL, 0 },
+ { "stats", cmd_dev_stats, cmd_dev_stats_usage, NULL, 0 },
{ 0, 0, 0, 0, 0 }
}
};
__u64 qgroupid;
};
+enum btrfs_dev_stat_values {
+ /* disk I/O failure stats */
+ BTRFS_DEV_STAT_WRITE_ERRS, /* EIO or EREMOTEIO from lower layers */
+ BTRFS_DEV_STAT_READ_ERRS, /* EIO or EREMOTEIO from lower layers */
+ BTRFS_DEV_STAT_FLUSH_ERRS, /* EIO or EREMOTEIO from lower layers */
+
+ /* stats for indirect indications for I/O failures */
+ BTRFS_DEV_STAT_CORRUPTION_ERRS, /* checksum error, bytenr error or
+ * contents is illegal: this is an
+ * indication that the block was damaged
+ * during read or write, or written to
+ * wrong location or read from wrong
+ * location */
+ BTRFS_DEV_STAT_GENERATION_ERRS, /* an indication that blocks have not
+ * been written */
+
+ BTRFS_DEV_STAT_VALUES_MAX
+};
+
+/* Reset statistics after reading; needs SYS_ADMIN capability */
+#define BTRFS_DEV_STATS_RESET (1ULL << 0)
+
+struct btrfs_ioctl_get_dev_stats {
+ __u64 devid; /* in */
+ __u64 nr_items; /* in/out */
+ __u64 flags; /* in/out */
+
+ /* out values: */
+ __u64 values[BTRFS_DEV_STAT_VALUES_MAX];
+
+ __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */
+};
+
/* BTRFS_IOC_SNAP_CREATE is no longer used by the btrfs command */
#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
struct btrfs_ioctl_vol_args)
struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_DEVICES_READY _IOR(BTRFS_IOCTL_MAGIC, 39, \
struct btrfs_ioctl_vol_args)
-
#define BTRFS_IOC_SET_RECEIVED_SUBVOL _IOWR(BTRFS_IOCTL_MAGIC, 37, \
struct btrfs_ioctl_received_subvol_args)
#define BTRFS_IOC_SEND _IOW(BTRFS_IOCTL_MAGIC, 38, struct btrfs_ioctl_send_args)
struct btrfs_ioctl_qgroup_create_args)
#define BTRFS_IOC_QGROUP_LIMIT _IOR(BTRFS_IOCTL_MAGIC, 43, \
struct btrfs_ioctl_qgroup_limit_args)
+#define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \
+ struct btrfs_ioctl_get_dev_stats)
+
#endif