From 551905dd475c6b4c4fa87d7734f018084a755af8 Mon Sep 17 00:00:00 2001 From: Gvozden Neskovic Date: Fri, 4 Aug 2017 12:23:10 +0200 Subject: [PATCH] vdev_mirror: kstat observables for preferred vdev Reviewed-by: Brian Behlendorf Signed-off-by: Gvozden Neskovic Closes #6461 --- include/sys/spa.h | 4 ++ module/zfs/spa_misc.c | 2 + module/zfs/vdev_mirror.c | 82 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 82 insertions(+), 6 deletions(-) diff --git a/include/sys/spa.h b/include/sys/spa.h index f6d2a5a711a3..d4661f4d38f8 100644 --- a/include/sys/spa.h +++ b/include/sys/spa.h @@ -1034,6 +1034,10 @@ extern void spa_get_errlists(spa_t *spa, avl_tree_t *last, avl_tree_t *scrub); extern void vdev_cache_stat_init(void); extern void vdev_cache_stat_fini(void); +/* vdev mirror */ +extern void vdev_mirror_stat_init(void); +extern void vdev_mirror_stat_fini(void); + /* Initialization and termination */ extern void spa_init(int flags); extern void spa_fini(void); diff --git a/module/zfs/spa_misc.c b/module/zfs/spa_misc.c index 14723a1ca9be..78e72aaf3292 100644 --- a/module/zfs/spa_misc.c +++ b/module/zfs/spa_misc.c @@ -1897,6 +1897,7 @@ spa_init(int mode) dmu_init(); zil_init(); vdev_cache_stat_init(); + vdev_mirror_stat_init(); vdev_raidz_math_init(); vdev_file_init(); zfs_prop_init(); @@ -1916,6 +1917,7 @@ spa_fini(void) vdev_file_fini(); vdev_cache_stat_fini(); + vdev_mirror_stat_fini(); vdev_raidz_math_fini(); zil_fini(); dmu_fini(); diff --git a/module/zfs/vdev_mirror.c b/module/zfs/vdev_mirror.c index 0cf2bc66500d..27a6bb932f44 100644 --- a/module/zfs/vdev_mirror.c +++ b/module/zfs/vdev_mirror.c @@ -34,6 +34,65 @@ #include #include +/* + * Vdev mirror kstats + */ +static kstat_t *mirror_ksp = NULL; + +typedef struct mirror_stats { + kstat_named_t vdev_mirror_stat_rotating_linear; + kstat_named_t vdev_mirror_stat_rotating_offset; + kstat_named_t vdev_mirror_stat_rotating_seek; + kstat_named_t vdev_mirror_stat_non_rotating_linear; + kstat_named_t vdev_mirror_stat_non_rotating_seek; + + kstat_named_t vdev_mirror_stat_preferred_found; + kstat_named_t vdev_mirror_stat_preferred_not_found; +} mirror_stats_t; + +static mirror_stats_t mirror_stats = { + /* New I/O follows directly the last I/O */ + { "rotating_linear", KSTAT_DATA_UINT64 }, + /* New I/O is within zfs_vdev_mirror_rotating_seek_offset of the last */ + { "rotating_offset", KSTAT_DATA_UINT64 }, + /* New I/O requires random seek */ + { "rotating_seek", KSTAT_DATA_UINT64 }, + /* New I/O follows directly the last I/O (nonrot) */ + { "non_rotating_linear", KSTAT_DATA_UINT64 }, + /* New I/O requires random seek (nonrot) */ + { "non_rotating_seek", KSTAT_DATA_UINT64 }, + /* Preferred child vdev found */ + { "preferred_found", KSTAT_DATA_UINT64 }, + /* Preferred child vdev not found or equal load */ + { "preferred_not_found", KSTAT_DATA_UINT64 }, + +}; + +#define MIRROR_STAT(stat) (mirror_stats.stat.value.ui64) +#define MIRROR_INCR(stat, val) atomic_add_64(&MIRROR_STAT(stat), val) +#define MIRROR_BUMP(stat) MIRROR_INCR(stat, 1) + +void +vdev_mirror_stat_init(void) +{ + mirror_ksp = kstat_create("zfs", 0, "vdev_mirror_stats", + "misc", KSTAT_TYPE_NAMED, + sizeof (mirror_stats) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL); + if (mirror_ksp != NULL) { + mirror_ksp->ks_data = &mirror_stats; + kstat_install(mirror_ksp); + } +} + +void +vdev_mirror_stat_fini(void) +{ + if (mirror_ksp != NULL) { + kstat_delete(mirror_ksp); + mirror_ksp = NULL; + } +} + /* * Virtual device vector for mirroring. */ @@ -140,8 +199,10 @@ vdev_mirror_load(mirror_map_t *mm, vdev_t *vd, uint64_t zio_offset) if (vd->vdev_nonrot) { /* Non-rotating media. */ - if (last_offset == zio_offset) + if (last_offset == zio_offset) { + MIRROR_BUMP(vdev_mirror_stat_non_rotating_linear); return (load + zfs_vdev_mirror_non_rotating_inc); + } /* * Apply a seek penalty even for non-rotating devices as @@ -149,12 +210,15 @@ vdev_mirror_load(mirror_map_t *mm, vdev_t *vd, uint64_t zio_offset) * the device, thus avoiding unnecessary per-command overhead * and boosting performance. */ + MIRROR_BUMP(vdev_mirror_stat_non_rotating_seek); return (load + zfs_vdev_mirror_non_rotating_seek_inc); } /* Rotating media I/O's which directly follow the last I/O. */ - if (last_offset == zio_offset) + if (last_offset == zio_offset) { + MIRROR_BUMP(vdev_mirror_stat_rotating_linear); return (load + zfs_vdev_mirror_rotating_inc); + } /* * Apply half the seek increment to I/O's within seek offset @@ -162,10 +226,13 @@ vdev_mirror_load(mirror_map_t *mm, vdev_t *vd, uint64_t zio_offset) * of a seek increment. */ offset_diff = (int64_t)(last_offset - zio_offset); - if (ABS(offset_diff) < zfs_vdev_mirror_rotating_seek_offset) + if (ABS(offset_diff) < zfs_vdev_mirror_rotating_seek_offset) { + MIRROR_BUMP(vdev_mirror_stat_rotating_offset); return (load + (zfs_vdev_mirror_rotating_seek_inc / 2)); + } /* Apply the full seek increment to all other I/O's. */ + MIRROR_BUMP(vdev_mirror_stat_rotating_seek); return (load + zfs_vdev_mirror_rotating_seek_inc); } @@ -387,12 +454,15 @@ vdev_mirror_child_select(zio_t *zio) mm->mm_preferred_cnt++; } - if (mm->mm_preferred_cnt == 1) + if (mm->mm_preferred_cnt == 1) { + MIRROR_BUMP(vdev_mirror_stat_preferred_found); return (mm->mm_preferred[0]); + } - - if (mm->mm_preferred_cnt > 1) + if (mm->mm_preferred_cnt > 1) { + MIRROR_BUMP(vdev_mirror_stat_preferred_not_found); return (vdev_mirror_preferred_child_randomize(zio)); + } /* * Every device is either missing or has this txg in its DTL.