* [PATCH] Btrfs-progs: add command to get/reset device stats via ioctl
@ 2011-12-09 16:40 Stefan Behrens
2011-12-21 16:06 ` [PATCH v2] " Stefan Behrens
0 siblings, 1 reply; 2+ messages in thread
From: Stefan Behrens @ 2011-12-09 16:40 UTC (permalink / raw)
To: linux-btrfs
"btrfs device stats" is used to retrieve and print the device stats.
"btrfs device stats -z" is used atomically retrieve, reset and print
the stats.
Signed-off-by: Stefan Behrens <sbehrens@giantdisaster.de>
---
Makefile | 4 +-
btrfs.c | 5 ++
btrfs_cmds.c | 67 +++++++++++++++++++++++++++++
btrfs_cmds.h | 5 ++
ctree.h | 6 +++
devstats.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ioctl.h | 28 ++++++++++++
print-tree.c | 7 +++
scrub.c | 74 +-------------------------------
9 files changed, 254 insertions(+), 73 deletions(-)
diff --git a/Makefile b/Makefile
index eeb92ad..c7ad82b 100644
--- a/Makefile
+++ b/Makefile
@@ -36,8 +36,8 @@ all: version $(progs) manpages
version:
bash version.sh
-btrfs: $(objects) btrfs.o btrfs_cmds.o scrub.o
- $(CC) $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o scrub.o \
+btrfs: $(objects) btrfs.o btrfs_cmds.o scrub.o devstats.o
+ $(CC) $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o scrub.o devstats.o \
$(objects) $(LDFLAGS) $(LIBS) -lpthread
calc-size: $(objects) calc-size.o
diff --git a/btrfs.c b/btrfs.c
index 1def354..078729a 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -159,6 +159,11 @@ static struct Command commands[] = {
"filesystem.",
NULL
},
+ { do_device_stats, -1,
+ "device stats", "[-z] <path>|<device>\n"
+ "Show current device IO stats. -z to reset stats afterwards.",
+ NULL
+ },
{ do_add_volume, -2,
"device add", "<device> [<device>...] <path>\n"
"Add a device to a filesystem.",
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index b59e9cb..065e103 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -117,6 +117,73 @@ int open_file_or_dir(const char *fname)
return fd;
}
+int get_device_info(int fd, u64 devid,
+ struct btrfs_ioctl_dev_info_args *di_args)
+{
+ int ret;
+
+ di_args->devid = devid;
+ memset(&di_args->uuid, '\0', sizeof(di_args->uuid));
+
+ ret = ioctl(fd, BTRFS_IOC_DEV_INFO, di_args);
+ return ret ? -errno : 0;
+}
+
+int get_fs_info(int fd, char *path, struct btrfs_ioctl_fs_info_args *fi_args,
+ struct btrfs_ioctl_dev_info_args **di_ret)
+{
+ int ret = 0;
+ int ndevs = 0;
+ int i = 1;
+ struct btrfs_fs_devices *fs_devices_mnt = NULL;
+ struct btrfs_ioctl_dev_info_args *di_args;
+ char mp[BTRFS_PATH_NAME_MAX + 1];
+
+ memset(fi_args, 0, sizeof(*fi_args));
+
+ ret = ioctl(fd, BTRFS_IOC_FS_INFO, fi_args);
+ if (ret && (errno == EINVAL || errno == ENOTTY)) {
+ /* path is not a mounted btrfs. Try if it's a device */
+ ret = check_mounted_where(fd, path, mp, sizeof(mp),
+ &fs_devices_mnt);
+ if (!ret)
+ return -EINVAL;
+ if (ret < 0)
+ return ret;
+ fi_args->num_devices = 1;
+ fi_args->max_id = fs_devices_mnt->latest_devid;
+ i = fs_devices_mnt->latest_devid;
+ memcpy(fi_args->fsid, fs_devices_mnt->fsid, BTRFS_FSID_SIZE);
+ close(fd);
+ fd = open_file_or_dir(mp);
+ if (fd < 0)
+ return -errno;
+ } else if (ret) {
+ return -errno;
+ }
+
+ if (!fi_args->num_devices)
+ return 0;
+
+ di_args = *di_ret = malloc(fi_args->num_devices * sizeof(*di_args));
+ if (!di_args)
+ return -errno;
+
+ for (; i <= fi_args->max_id; ++i) {
+ BUG_ON(ndevs >= fi_args->num_devices);
+ ret = get_device_info(fd, i, &di_args[ndevs]);
+ if (ret == -ENODEV)
+ continue;
+ if (ret)
+ return ret;
+ ndevs++;
+ }
+
+ BUG_ON(ndevs == 0);
+
+ return 0;
+}
+
static u64 parse_size(char *s)
{
int len = strlen(s);
diff --git a/btrfs_cmds.h b/btrfs_cmds.h
index 81182b1..6be9cc5 100644
--- a/btrfs_cmds.h
+++ b/btrfs_cmds.h
@@ -41,4 +41,9 @@ int do_change_label(int argc, char **argv);
int open_file_or_dir(const char *fname);
int do_ino_to_path(int nargs, char **argv);
int do_logical_to_ino(int nargs, char **argv);
+int do_device_stats(int nargs, char **argv);
+int get_device_info(int fd, u64 devid,
+ struct btrfs_ioctl_dev_info_args *di_args);
+int get_fs_info(int fd, char *path, struct btrfs_ioctl_fs_info_args *fi_args,
+ struct btrfs_ioctl_dev_info_args **di_ret);
char *path_for_root(int fd, u64 root);
diff --git a/ctree.h b/ctree.h
index 54748c8..12a0603 100644
--- a/ctree.h
+++ b/ctree.h
@@ -912,6 +912,12 @@ struct btrfs_root {
#define BTRFS_CHUNK_ITEM_KEY 228
/*
+ * Persistantly stores the io stats in the device tree.
+ * One key for all stats, (0, BTRFS_DEVICE_STATS_KEY, devid).
+ */
+#define BTRFS_DEVICE_STATS_KEY 248
+
+/*
* string items are for debugging. They just store a short string of
* data in the FS
*/
diff --git a/devstats.c b/devstats.c
new file mode 100644
index 0000000..ae517ae
--- /dev/null
+++ b/devstats.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) STRATO AG 2011. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "ctree.h"
+#include "ioctl.h"
+#include "btrfs_cmds.h"
+#include "utils.h"
+#include "volumes.h"
+#include "disk-io.h"
+
+
+int do_device_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;
+ int cmd = BTRFS_IOC_GET_DEVICE_STATS;
+
+ optind = 1;
+ while ((c = getopt(argc, argv, "z")) != -1) {
+ switch (c) {
+ case 'z':
+ cmd = BTRFS_IOC_GET_AND_RESET_DEVICE_STATS;
+ 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;
+ }
+
+ printf("num_devices=%llu\n", (unsigned long long)fi_args.num_devices);
+ for (i = 0; i < fi_args.num_devices; i++) {
+ struct btrfs_ioctl_get_device_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_IOCTL_GET_DEVICE_STATS_MAX_NR_ITEMS;
+
+ if (ioctl(fdmnt, cmd, &args) < 0) {
+ fprintf(stderr, "ERROR: ioctl(%s) on %s failed: %s\n",
+ BTRFS_IOC_GET_AND_RESET_DEVICE_STATS == cmd ?
+ "BTRFS_IOC_GET_AND_RESET_DEVICE_STATS" :
+ "BTRFS_IOC_GET_DEVICE_STATS",
+ path, strerror(errno));
+ err = 1;
+ } else {
+ if (args.nr_items >= 1)
+ printf("[%s].cnt_write_io_errs %llu\n",
+ path, args.cnt_write_io_errs);
+ if (args.nr_items >= 2)
+ printf("[%s].cnt_read_io_errs %llu\n",
+ path, args.cnt_read_io_errs);
+ if (args.nr_items >= 3)
+ printf("[%s].cnt_flush_io_errs %llu\n",
+ path, args.cnt_flush_io_errs);
+ if (args.nr_items >= 4)
+ printf("[%s].cnt_corruption_errs %llu\n",
+ path, args.cnt_corruption_errs);
+ if (args.nr_items >= 5)
+ printf("[%s].cnt_generation_errs %llu\n",
+ path, args.cnt_generation_errs);
+ }
+ }
+
+out:
+ free(di_args);
+ close(fdmnt);
+ if (fdres > -1)
+ close(fdres);
+
+ return err;
+}
diff --git a/ioctl.h b/ioctl.h
index 1ae7537..340eccc 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -224,6 +224,29 @@ struct btrfs_ioctl_logical_ino_args {
__u64 inodes;
};
+#define BTRFS_IOCTL_GET_DEVICE_STATS_MAX_NR_ITEMS 5
+struct btrfs_ioctl_get_device_stats {
+ __u64 devid; /* in */
+ __u64 nr_items; /* in/out */
+
+ /* out values: */
+
+ /* disk I/O failure stats */
+ __u64 cnt_write_io_errs; /* EIO or EREMOTEIO from lower layers */
+ __u64 cnt_read_io_errs; /* EIO or EREMOTEIO from lower layers */
+ __u64 cnt_flush_io_errs; /* EIO or EREMOTEIO from lower layers */
+
+ /* stats for indirect indications for I/O failures */
+ __u64 cnt_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 */
+ __u64 cnt_generation_errs; /* an indication that blocks have not
+ * been written */
+};
+
/* 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)
@@ -277,5 +300,10 @@ struct btrfs_ioctl_logical_ino_args {
struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
struct btrfs_ioctl_ino_path_args)
+#define BTRFS_IOC_GET_DEVICE_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \
+ struct btrfs_ioctl_get_device_stats)
+#define BTRFS_IOC_GET_AND_RESET_DEVICE_STATS _IOWR(BTRFS_IOCTL_MAGIC, 53, \
+ struct btrfs_ioctl_get_device_stats)
+
#endif
diff --git a/print-tree.c b/print-tree.c
index 6039699..58178af 100644
--- a/print-tree.c
+++ b/print-tree.c
@@ -354,6 +354,9 @@ static void print_key_type(u8 type)
case BTRFS_STRING_ITEM_KEY:
printf("STRING_ITEM");
break;
+ case BTRFS_DEVICE_STATS_KEY:
+ printf("DEVICE_STATS_ITEM");
+ break;
default:
printf("UNKNOWN");
};
@@ -603,6 +606,10 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
str = l->data + btrfs_item_ptr_offset(l, i);
printf("\t\titem data %.*s\n", btrfs_item_size(l, item), str);
break;
+
+ case BTRFS_DEVICE_STATS_KEY:
+ printf("\t\tdevice stats\n");
+ break;
};
fflush(stdout);
}
diff --git a/scrub.c b/scrub.c
index 9dca5f6..ab3dc96 100644
--- a/scrub.c
+++ b/scrub.c
@@ -961,74 +961,6 @@ static struct scrub_file_record *last_dev_scrub(
return NULL;
}
-static int scrub_device_info(int fd, u64 devid,
- struct btrfs_ioctl_dev_info_args *di_args)
-{
- int ret;
-
- di_args->devid = devid;
- memset(&di_args->uuid, '\0', sizeof(di_args->uuid));
-
- ret = ioctl(fd, BTRFS_IOC_DEV_INFO, di_args);
- return ret ? -errno : 0;
-}
-
-static int scrub_fs_info(int fd, char *path,
- struct btrfs_ioctl_fs_info_args *fi_args,
- struct btrfs_ioctl_dev_info_args **di_ret)
-{
- int ret = 0;
- int ndevs = 0;
- int i = 1;
- struct btrfs_fs_devices *fs_devices_mnt = NULL;
- struct btrfs_ioctl_dev_info_args *di_args;
- char mp[BTRFS_PATH_NAME_MAX + 1];
-
- memset(fi_args, 0, sizeof(*fi_args));
-
- ret = ioctl(fd, BTRFS_IOC_FS_INFO, fi_args);
- if (ret && errno == EINVAL) {
- /* path is no mounted btrfs. try if it's a device */
- ret = check_mounted_where(fd, path, mp, sizeof(mp),
- &fs_devices_mnt);
- if (!ret)
- return -EINVAL;
- if (ret < 0)
- return ret;
- fi_args->num_devices = 1;
- fi_args->max_id = fs_devices_mnt->latest_devid;
- i = fs_devices_mnt->latest_devid;
- memcpy(fi_args->fsid, fs_devices_mnt->fsid, BTRFS_FSID_SIZE);
- close(fd);
- fd = open_file_or_dir(mp);
- if (fd < 0)
- return -errno;
- } else if (ret) {
- return -errno;
- }
-
- if (!fi_args->num_devices)
- return 0;
-
- di_args = *di_ret = malloc(fi_args->num_devices * sizeof(*di_args));
- if (!di_args)
- return -errno;
-
- for (; i <= fi_args->max_id; ++i) {
- BUG_ON(ndevs >= fi_args->num_devices);
- ret = scrub_device_info(fd, i, &di_args[ndevs]);
- if (ret == -ENODEV)
- continue;
- if (ret)
- return ret;
- ++ndevs;
- }
-
- BUG_ON(ndevs == 0);
-
- return 0;
-}
-
int mkdir_p(char *path)
{
int i;
@@ -1151,7 +1083,7 @@ static int scrub_start(int argc, char **argv, int resume)
return 12;
}
- ret = scrub_fs_info(fdmnt, path, &fi_args, &di_args);
+ ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
if (ret) {
ERR(!do_quiet, "ERROR: getting dev info for scrub failed: "
"%s\n", strerror(-ret));
@@ -1543,7 +1475,6 @@ int do_scrub_status(int argc, char **argv)
int ret;
int fdmnt;
int i;
- optind = 1;
int print_raw = 0;
int do_stats_per_dev = 0;
char c;
@@ -1551,6 +1482,7 @@ int do_scrub_status(int argc, char **argv)
int fdres = -1;
int err = 0;
+ optind = 1;
while ((c = getopt(argc, argv, "dR")) != -1) {
switch (c) {
case 'd':
@@ -1581,7 +1513,7 @@ int do_scrub_status(int argc, char **argv)
return 12;
}
- ret = scrub_fs_info(fdmnt, path, &fi_args, &di_args);
+ ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
if (ret) {
fprintf(stderr, "ERROR: getting dev info for scrub failed: "
"%s\n", strerror(-ret));
--
1.7.3.4
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH v2] Btrfs-progs: add command to get/reset device stats via ioctl
2011-12-09 16:40 [PATCH] Btrfs-progs: add command to get/reset device stats via ioctl Stefan Behrens
@ 2011-12-21 16:06 ` Stefan Behrens
0 siblings, 0 replies; 2+ messages in thread
From: Stefan Behrens @ 2011-12-21 16:06 UTC (permalink / raw)
To: linux-btrfs
"btrfs device stats" is used to retrieve and print the device stats.
"btrfs device stats -z" is used to atomically retrieve, reset and
print the stats.
Signed-off-by: Stefan Behrens <sbehrens@giantdisaster.de>
---
Changes v1->v2:
- Remove a verbose printf()
- Cast u64 to unsigned long long for printf()
- Update the man page
Makefile | 4 +-
btrfs.c | 5 ++
btrfs_cmds.c | 67 ++++++++++++++++++++++++++++
btrfs_cmds.h | 5 ++
ctree.h | 6 +++
devstats.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ioctl.h | 27 +++++++++++
man/btrfs.8.in | 13 +++++
print-tree.c | 6 +++
scrub.c | 74 +-----------------------------
10 files changed, 269 insertions(+), 73 deletions(-)
diff --git a/Makefile b/Makefile
index eeb92ad..c7ad82b 100644
--- a/Makefile
+++ b/Makefile
@@ -36,8 +36,8 @@ all: version $(progs) manpages
version:
bash version.sh
-btrfs: $(objects) btrfs.o btrfs_cmds.o scrub.o
- $(CC) $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o scrub.o \
+btrfs: $(objects) btrfs.o btrfs_cmds.o scrub.o devstats.o
+ $(CC) $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o scrub.o devstats.o \
$(objects) $(LDFLAGS) $(LIBS) -lpthread
calc-size: $(objects) calc-size.o
diff --git a/btrfs.c b/btrfs.c
index 1def354..078729a 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -159,6 +159,11 @@ static struct Command commands[] = {
"filesystem.",
NULL
},
+ { do_device_stats, -1,
+ "device stats", "[-z] <path>|<device>\n"
+ "Show current device IO stats. -z to reset stats afterwards.",
+ NULL
+ },
{ do_add_volume, -2,
"device add", "<device> [<device>...] <path>\n"
"Add a device to a filesystem.",
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index b59e9cb..065e103 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -117,6 +117,73 @@ int open_file_or_dir(const char *fname)
return fd;
}
+int get_device_info(int fd, u64 devid,
+ struct btrfs_ioctl_dev_info_args *di_args)
+{
+ int ret;
+
+ di_args->devid = devid;
+ memset(&di_args->uuid, '\0', sizeof(di_args->uuid));
+
+ ret = ioctl(fd, BTRFS_IOC_DEV_INFO, di_args);
+ return ret ? -errno : 0;
+}
+
+int get_fs_info(int fd, char *path, struct btrfs_ioctl_fs_info_args *fi_args,
+ struct btrfs_ioctl_dev_info_args **di_ret)
+{
+ int ret = 0;
+ int ndevs = 0;
+ int i = 1;
+ struct btrfs_fs_devices *fs_devices_mnt = NULL;
+ struct btrfs_ioctl_dev_info_args *di_args;
+ char mp[BTRFS_PATH_NAME_MAX + 1];
+
+ memset(fi_args, 0, sizeof(*fi_args));
+
+ ret = ioctl(fd, BTRFS_IOC_FS_INFO, fi_args);
+ if (ret && (errno == EINVAL || errno == ENOTTY)) {
+ /* path is not a mounted btrfs. Try if it's a device */
+ ret = check_mounted_where(fd, path, mp, sizeof(mp),
+ &fs_devices_mnt);
+ if (!ret)
+ return -EINVAL;
+ if (ret < 0)
+ return ret;
+ fi_args->num_devices = 1;
+ fi_args->max_id = fs_devices_mnt->latest_devid;
+ i = fs_devices_mnt->latest_devid;
+ memcpy(fi_args->fsid, fs_devices_mnt->fsid, BTRFS_FSID_SIZE);
+ close(fd);
+ fd = open_file_or_dir(mp);
+ if (fd < 0)
+ return -errno;
+ } else if (ret) {
+ return -errno;
+ }
+
+ if (!fi_args->num_devices)
+ return 0;
+
+ di_args = *di_ret = malloc(fi_args->num_devices * sizeof(*di_args));
+ if (!di_args)
+ return -errno;
+
+ for (; i <= fi_args->max_id; ++i) {
+ BUG_ON(ndevs >= fi_args->num_devices);
+ ret = get_device_info(fd, i, &di_args[ndevs]);
+ if (ret == -ENODEV)
+ continue;
+ if (ret)
+ return ret;
+ ndevs++;
+ }
+
+ BUG_ON(ndevs == 0);
+
+ return 0;
+}
+
static u64 parse_size(char *s)
{
int len = strlen(s);
diff --git a/btrfs_cmds.h b/btrfs_cmds.h
index 81182b1..6be9cc5 100644
--- a/btrfs_cmds.h
+++ b/btrfs_cmds.h
@@ -41,4 +41,9 @@ int do_change_label(int argc, char **argv);
int open_file_or_dir(const char *fname);
int do_ino_to_path(int nargs, char **argv);
int do_logical_to_ino(int nargs, char **argv);
+int do_device_stats(int nargs, char **argv);
+int get_device_info(int fd, u64 devid,
+ struct btrfs_ioctl_dev_info_args *di_args);
+int get_fs_info(int fd, char *path, struct btrfs_ioctl_fs_info_args *fi_args,
+ struct btrfs_ioctl_dev_info_args **di_ret);
char *path_for_root(int fd, u64 root);
diff --git a/ctree.h b/ctree.h
index 54748c8..12a0603 100644
--- a/ctree.h
+++ b/ctree.h
@@ -912,6 +912,12 @@ struct btrfs_root {
#define BTRFS_CHUNK_ITEM_KEY 228
/*
+ * Persistantly stores the io stats in the device tree.
+ * One key for all stats, (0, BTRFS_DEVICE_STATS_KEY, devid).
+ */
+#define BTRFS_DEVICE_STATS_KEY 248
+
+/*
* string items are for debugging. They just store a short string of
* data in the FS
*/
diff --git a/devstats.c b/devstats.c
new file mode 100644
index 0000000..b46fcf6
--- /dev/null
+++ b/devstats.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) STRATO AG 2011. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "ctree.h"
+#include "ioctl.h"
+#include "btrfs_cmds.h"
+#include "utils.h"
+#include "volumes.h"
+#include "disk-io.h"
+
+
+int do_device_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;
+ int cmd = BTRFS_IOC_GET_DEVICE_STATS;
+
+ optind = 1;
+ while ((c = getopt(argc, argv, "z")) != -1) {
+ switch (c) {
+ case 'z':
+ cmd = BTRFS_IOC_GET_AND_RESET_DEVICE_STATS;
+ 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_device_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_IOCTL_GET_DEVICE_STATS_MAX_NR_ITEMS;
+
+ if (ioctl(fdmnt, cmd, &args) < 0) {
+ fprintf(stderr, "ERROR: ioctl(%s) on %s failed: %s\n",
+ BTRFS_IOC_GET_AND_RESET_DEVICE_STATS == cmd ?
+ "BTRFS_IOC_GET_AND_RESET_DEVICE_STATS" :
+ "BTRFS_IOC_GET_DEVICE_STATS",
+ path, strerror(errno));
+ err = 1;
+ } else {
+ if (args.nr_items >= 1)
+ printf("[%s].cnt_write_io_errs %llu\n",
+ path, (unsigned long long)
+ args.cnt_write_io_errs);
+ if (args.nr_items >= 2)
+ printf("[%s].cnt_read_io_errs %llu\n",
+ path, (unsigned long long)
+ args.cnt_read_io_errs);
+ if (args.nr_items >= 3)
+ printf("[%s].cnt_flush_io_errs %llu\n",
+ path, (unsigned long long)
+ args.cnt_flush_io_errs);
+ if (args.nr_items >= 4)
+ printf("[%s].cnt_corruption_errs %llu\n",
+ path, (unsigned long long)
+ args.cnt_corruption_errs);
+ if (args.nr_items >= 5)
+ printf("[%s].cnt_generation_errs %llu\n",
+ path, (unsigned long long)
+ args.cnt_generation_errs);
+ }
+ }
+
+out:
+ free(di_args);
+ close(fdmnt);
+ if (fdres > -1)
+ close(fdres);
+
+ return err;
+}
diff --git a/ioctl.h b/ioctl.h
index 1ae7537..01bf158 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -224,6 +224,29 @@ struct btrfs_ioctl_logical_ino_args {
__u64 inodes;
};
+#define BTRFS_IOCTL_GET_DEVICE_STATS_MAX_NR_ITEMS 5
+struct btrfs_ioctl_get_device_stats {
+ __u64 devid; /* in */
+ __u64 nr_items; /* in/out */
+
+ /* out values: */
+
+ /* disk I/O failure stats */
+ __u64 cnt_write_io_errs; /* EIO or EREMOTEIO from lower layers */
+ __u64 cnt_read_io_errs; /* EIO or EREMOTEIO from lower layers */
+ __u64 cnt_flush_io_errs; /* EIO or EREMOTEIO from lower layers */
+
+ /* stats for indirect indications for I/O failures */
+ __u64 cnt_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 */
+ __u64 cnt_generation_errs; /* an indication that blocks have not
+ * been written */
+};
+
/* 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)
@@ -277,5 +300,9 @@ struct btrfs_ioctl_logical_ino_args {
struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
struct btrfs_ioctl_ino_path_args)
+#define BTRFS_IOC_GET_DEVICE_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \
+ struct btrfs_ioctl_get_device_stats)
+#define BTRFS_IOC_GET_AND_RESET_DEVICE_STATS _IOWR(BTRFS_IOCTL_MAGIC, 53, \
+ struct btrfs_ioctl_get_device_stats)
#endif
diff --git a/man/btrfs.8.in b/man/btrfs.8.in
index be478e0..14a5ded 100644
--- a/man/btrfs.8.in
+++ b/man/btrfs.8.in
@@ -35,6 +35,8 @@ btrfs \- control a btrfs filesystem
.PP
\fBbtrfs\fP \fBdevice show\fP\fI [--all-devices|<uuid>|<label>]\fP
.PP
+\fBbtrfs\fP \fBdevice stats\fP [-z] {\fI<path>\fP|\fI<device>\fP}
+.PP
\fBbtrfs\fP \fBdevice add\fP\fI <device> [<device>...] <path> \fP
.PP
\fBbtrfs\fP \fBdevice delete\fP\fI <device> [<device>...] <path> \fP
@@ -230,6 +232,17 @@ Finally, if \fB--all-devices\fP is passed, all the devices under /dev are
scanned.
.TP
+\fBdevice stats\fP [-z] {\fI<path>\fP|\fI<device>\fP}
+Read and print the device IO stats for all devices of the filesystem
+identified by \fI<path>\fR or for a single \fI<device>\fR.
+.RS
+
+\fIOptions\fR
+.IP -z 5
+Reset stats to zero after reading them.
+.RE
+.TP
+
\fBscrub start\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
Start a scrub on all devices of the filesystem identified by \fI<path>\fR or on
a single \fI<device>\fR. Without options, scrub is started as a background
diff --git a/print-tree.c b/print-tree.c
index 6039699..0923cd4 100644
--- a/print-tree.c
+++ b/print-tree.c
@@ -354,6 +354,9 @@ static void print_key_type(u8 type)
case BTRFS_STRING_ITEM_KEY:
printf("STRING_ITEM");
break;
+ case BTRFS_DEVICE_STATS_KEY:
+ printf("DEVICE_STATS_ITEM");
+ break;
default:
printf("UNKNOWN");
};
@@ -603,6 +606,9 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
str = l->data + btrfs_item_ptr_offset(l, i);
printf("\t\titem data %.*s\n", btrfs_item_size(l, item), str);
break;
+ case BTRFS_DEVICE_STATS_KEY:
+ printf("\t\tdevice stats\n");
+ break;
};
fflush(stdout);
}
diff --git a/scrub.c b/scrub.c
index 9dca5f6..ab3dc96 100644
--- a/scrub.c
+++ b/scrub.c
@@ -961,74 +961,6 @@ static struct scrub_file_record *last_dev_scrub(
return NULL;
}
-static int scrub_device_info(int fd, u64 devid,
- struct btrfs_ioctl_dev_info_args *di_args)
-{
- int ret;
-
- di_args->devid = devid;
- memset(&di_args->uuid, '\0', sizeof(di_args->uuid));
-
- ret = ioctl(fd, BTRFS_IOC_DEV_INFO, di_args);
- return ret ? -errno : 0;
-}
-
-static int scrub_fs_info(int fd, char *path,
- struct btrfs_ioctl_fs_info_args *fi_args,
- struct btrfs_ioctl_dev_info_args **di_ret)
-{
- int ret = 0;
- int ndevs = 0;
- int i = 1;
- struct btrfs_fs_devices *fs_devices_mnt = NULL;
- struct btrfs_ioctl_dev_info_args *di_args;
- char mp[BTRFS_PATH_NAME_MAX + 1];
-
- memset(fi_args, 0, sizeof(*fi_args));
-
- ret = ioctl(fd, BTRFS_IOC_FS_INFO, fi_args);
- if (ret && errno == EINVAL) {
- /* path is no mounted btrfs. try if it's a device */
- ret = check_mounted_where(fd, path, mp, sizeof(mp),
- &fs_devices_mnt);
- if (!ret)
- return -EINVAL;
- if (ret < 0)
- return ret;
- fi_args->num_devices = 1;
- fi_args->max_id = fs_devices_mnt->latest_devid;
- i = fs_devices_mnt->latest_devid;
- memcpy(fi_args->fsid, fs_devices_mnt->fsid, BTRFS_FSID_SIZE);
- close(fd);
- fd = open_file_or_dir(mp);
- if (fd < 0)
- return -errno;
- } else if (ret) {
- return -errno;
- }
-
- if (!fi_args->num_devices)
- return 0;
-
- di_args = *di_ret = malloc(fi_args->num_devices * sizeof(*di_args));
- if (!di_args)
- return -errno;
-
- for (; i <= fi_args->max_id; ++i) {
- BUG_ON(ndevs >= fi_args->num_devices);
- ret = scrub_device_info(fd, i, &di_args[ndevs]);
- if (ret == -ENODEV)
- continue;
- if (ret)
- return ret;
- ++ndevs;
- }
-
- BUG_ON(ndevs == 0);
-
- return 0;
-}
-
int mkdir_p(char *path)
{
int i;
@@ -1151,7 +1083,7 @@ static int scrub_start(int argc, char **argv, int resume)
return 12;
}
- ret = scrub_fs_info(fdmnt, path, &fi_args, &di_args);
+ ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
if (ret) {
ERR(!do_quiet, "ERROR: getting dev info for scrub failed: "
"%s\n", strerror(-ret));
@@ -1543,7 +1475,6 @@ int do_scrub_status(int argc, char **argv)
int ret;
int fdmnt;
int i;
- optind = 1;
int print_raw = 0;
int do_stats_per_dev = 0;
char c;
@@ -1551,6 +1482,7 @@ int do_scrub_status(int argc, char **argv)
int fdres = -1;
int err = 0;
+ optind = 1;
while ((c = getopt(argc, argv, "dR")) != -1) {
switch (c) {
case 'd':
@@ -1581,7 +1513,7 @@ int do_scrub_status(int argc, char **argv)
return 12;
}
- ret = scrub_fs_info(fdmnt, path, &fi_args, &di_args);
+ ret = get_fs_info(fdmnt, path, &fi_args, &di_args);
if (ret) {
fprintf(stderr, "ERROR: getting dev info for scrub failed: "
"%s\n", strerror(-ret));
--
1.7.3.4
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2011-12-21 16:06 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-09 16:40 [PATCH] Btrfs-progs: add command to get/reset device stats via ioctl Stefan Behrens
2011-12-21 16:06 ` [PATCH v2] " Stefan Behrens
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.