From 4f487f35faf0f027fa5d7b6e60f5004da711d8bb Mon Sep 17 00:00:00 2001 From: Haakan Johansson Date: Fri, 16 Sep 2016 10:25:01 +0200 Subject: [PATCH] zpool iostat -k and status -k show type of vdevs: ssd, hdd, file or mixed. Keep track of mixed nonrotational (ssd+hdd) devices. Only mirrors are mixed. If a pool consist of several mixed vdevs, it is mixed if all vdevs are either mixed, or ssd (fully nonrotational). Pass info to zpool cmd whether devices are solid state, or rotational. Info is passed in ZPOOL_CONFIG_VDEV_STATS_EX -> ZPOOL_CONFIG_VDEV_TYPE. --- cmd/zpool/zpool_main.c | 74 +++++++++++++++++++++++++++++++++++------ include/sys/fs/zfs.h | 16 +++++++++ include/sys/vdev_impl.h | 1 + man/man8/zpool.8 | 26 ++++++++++++--- module/zfs/vdev.c | 24 ++++++++++++- module/zfs/vdev_disk.c | 1 + module/zfs/vdev_file.c | 1 + module/zfs/vdev_label.c | 2 ++ 8 files changed, 129 insertions(+), 16 deletions(-) diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index f4873cf196a6..eafa53c1fd55 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -152,8 +152,9 @@ enum iostat_type { IOS_DEFAULT = 0, IOS_LATENCY = 1, IOS_QUEUES = 2, - IOS_L_HISTO = 3, - IOS_RQ_HISTO = 4, + IOS_ROT_TYPE = 3, + IOS_L_HISTO = 4, + IOS_RQ_HISTO = 5, IOS_COUNT, /* always last element */ }; @@ -161,6 +162,7 @@ enum iostat_type { #define IOS_DEFAULT_M (1ULL << IOS_DEFAULT) #define IOS_LATENCY_M (1ULL << IOS_LATENCY) #define IOS_QUEUES_M (1ULL << IOS_QUEUES) +#define IOS_ROT_TYPE_M (1ULL << IOS_ROT_TYPE) #define IOS_L_HISTO_M (1ULL << IOS_L_HISTO) #define IOS_RQ_HISTO_M (1ULL << IOS_RQ_HISTO) @@ -197,6 +199,9 @@ static const char *vsx_type_to_nvlist[IOS_COUNT][11] = { ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE, ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE, NULL}, + [IOS_ROT_TYPE] = { + ZPOOL_CONFIG_VDEV_ROT_TYPE, + NULL}, [IOS_RQ_HISTO] = { ZPOOL_CONFIG_VDEV_SYNC_IND_R_HISTO, ZPOOL_CONFIG_VDEV_SYNC_AGG_R_HISTO, @@ -312,7 +317,7 @@ get_usage(zpool_help_t idx) { "[-R root] [-F [-n]]\n" "\t [newpool]\n")); case HELP_IOSTAT: - return (gettext("\tiostat [-c CMD] [-T d | u] [-ghHLpPvy] " + return (gettext("\tiostat [-c CMD] [-T d | u] [-ghHkLpPvy] " "[[-lq]|[-r|-w]]\n" "\t [[pool ...]|[pool vdev ...]|[vdev ...]] " "[interval [count]]\n")); @@ -335,7 +340,7 @@ get_usage(zpool_help_t idx) { case HELP_SCRUB: return (gettext("\tscrub [-s] ...\n")); case HELP_STATUS: - return (gettext("\tstatus [-c CMD] [-gLPvxD] [-T d|u] [pool]" + return (gettext("\tstatus [-c CMD] [-gkLPvxD] [-T d|u] [pool]" " ... [interval [count]]\n")); case HELP_UPGRADE: return (gettext("\tupgrade\n" @@ -1455,6 +1460,30 @@ max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max, return (max); } +static const char * +rot_type_mark(nvlist_t *nv) +{ + nvlist_t *nvx; + uint64_t type = VDEV_ROT_TYPE_UNKNOWN; + + if (nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_VDEV_STATS_EX, &nvx) == 0) + nvlist_lookup_uint64(nvx, ZPOOL_CONFIG_VDEV_ROT_TYPE, + &type); + + switch (type) { + case VDEV_ROT_TYPE_SSD: + return ("ssd"); + case VDEV_ROT_TYPE_FILE: + return ("file"); + case VDEV_ROT_TYPE_MIXED: + return ("mix"); + case VDEV_ROT_TYPE_HDD: + return ("hdd"); + default: + return ("-"); + } +} + typedef struct spare_cbdata { uint64_t cb_guid; zpool_handle_t *cb_zhp; @@ -1509,6 +1538,7 @@ typedef struct status_cbdata { boolean_t cb_explain; boolean_t cb_first; boolean_t cb_dedup_stats; + boolean_t cb_rot_type; boolean_t cb_print_status; vdev_cmd_data_list_t *vcdl; } status_cbdata_t; @@ -1572,8 +1602,13 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name, zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf); + } else { + (void) printf(" "); } + if (cb->cb_rot_type) + (void) printf(" %4s", rot_type_mark(nv)); + if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, ¬present) == 0) { verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0); @@ -2628,6 +2663,7 @@ static const name_and_columns_t iostat_top_labels[][IOSTAT_MAX_LABELS] = [IOS_QUEUES] = {{"syncq_read", 2}, {"syncq_write", 2}, {"asyncq_read", 2}, {"asyncq_write", 2}, {"scrubq_read", 2}, {NULL}}, + [IOS_ROT_TYPE] = {{"", 1}, {NULL}}, [IOS_L_HISTO] = {{"total_wait", 2}, {"disk_wait", 2}, {"sync_queue", 2}, {"async_queue", 2}, {NULL}}, [IOS_RQ_HISTO] = {{"sync_read", 2}, {"sync_write", 2}, @@ -2644,6 +2680,7 @@ static const name_and_columns_t iostat_bottom_labels[][IOSTAT_MAX_LABELS] = {"write"}, {"read"}, {"write"}, {"wait"}, {NULL}}, [IOS_QUEUES] = {{"pend"}, {"activ"}, {"pend"}, {"activ"}, {"pend"}, {"activ"}, {"pend"}, {"activ"}, {"pend"}, {"activ"}, {NULL}}, + [IOS_ROT_TYPE] = {{"type"}, {NULL}}, [IOS_L_HISTO] = {{"read"}, {"write"}, {"read"}, {"write"}, {"read"}, {"write"}, {"read"}, {"write"}, {"scrub"}, {NULL}}, [IOS_RQ_HISTO] = {{"ind"}, {"agg"}, {"ind"}, {"agg"}, {"ind"}, {"agg"}, @@ -2706,9 +2743,10 @@ default_column_width(iostat_cbdata_t *cb, enum iostat_type type) [IOS_DEFAULT] = 15, /* 1PB capacity */ [IOS_LATENCY] = 10, /* 1B ns = 10sec */ [IOS_QUEUES] = 6, /* 1M queue entries */ + [IOS_ROT_TYPE] = 4, /* type/file/ssd/hdd/mix */ }; - if (cb->cb_literal) + if (cb->cb_literal || type == IOS_ROT_TYPE) column_width = widths[type]; return (column_width); @@ -3411,6 +3449,9 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, print_iostat_latency(cb, oldnv, newnv, scale); if (cb->cb_flags & IOS_QUEUES_M) print_iostat_queues(cb, oldnv, newnv, scale); + if (cb->cb_flags & IOS_ROT_TYPE_M) + printf("%s%4s", cb->cb_scripted ? "\t" : " ", + rot_type_mark(newnv)); if (cb->cb_flags & IOS_ANYHISTO_M) { printf("\n"); print_iostat_histos(cb, oldnv, newnv, scale, name); @@ -3959,7 +4000,7 @@ fsleep(float sec) { /* - * zpool iostat [-c CMD] [-ghHLpPvy] [[-lq]|[-r|-w]] [-n name] [-T d|u] + * zpool iostat [-c CMD] [-ghHkLpPvy] [[-lq]|[-r|-w]] [-n name] [-T d|u] * [[ pool ...]|[pool vdev ...]|[vdev ...]] * [interval [count]] * @@ -3972,6 +4013,7 @@ fsleep(float sec) { * -p Display values in parsable (exact) format. * -H Scripted mode. Don't display headers, and separate properties * by a single tab. + * -k Display type of device, e.g. solid-state or mixed. * -l Display average latency * -q Display queue depths * -w Display latency histograms @@ -4000,6 +4042,7 @@ zpool_do_iostat(int argc, char **argv) boolean_t guid = B_FALSE; boolean_t follow_links = B_FALSE; boolean_t full_name = B_FALSE; + boolean_t type = B_FALSE; iostat_cbdata_t cb = { 0 }; char *cmd = NULL; @@ -4010,7 +4053,7 @@ zpool_do_iostat(int argc, char **argv) uint64_t unsupported_flags; /* check options */ - while ((c = getopt(argc, argv, "c:gLPT:vyhplqrwH")) != -1) { + while ((c = getopt(argc, argv, "c:gLPT:vyhpklqrwH")) != -1) { switch (c) { case 'c': cmd = optarg; @@ -4033,6 +4076,9 @@ zpool_do_iostat(int argc, char **argv) case 'p': parsable = B_TRUE; break; + case 'k': + type = B_TRUE; + break; case 'l': latency = B_TRUE; break; @@ -4188,6 +4234,8 @@ zpool_do_iostat(int argc, char **argv) cb.cb_flags |= IOS_LATENCY_M; if (queues) cb.cb_flags |= IOS_QUEUES_M; + if (type) + cb.cb_flags |= IOS_ROT_TYPE_M; } /* @@ -6006,9 +6054,9 @@ status_callback(zpool_handle_t *zhp, void *data) cbp->cb_namewidth = 10; (void) printf(gettext("config:\n\n")); - (void) printf(gettext("\t%-*s %-8s %5s %5s %5s\n"), + (void) printf(gettext("\t%-*s %-8s %5s %5s %5s%s\n"), cbp->cb_namewidth, "NAME", "STATE", "READ", "WRITE", - "CKSUM"); + "CKSUM", cbp->cb_rot_type ? " TYPE" : ""); print_status_config(zhp, cbp, zpool_get_name(zhp), nvroot, 0, B_FALSE); @@ -6068,10 +6116,11 @@ status_callback(zpool_handle_t *zhp, void *data) } /* - * zpool status [-c CMD] [-gLPvx] [-T d|u] [pool] ... [interval [count]] + * zpool status [-c CMD] [-gkLPvx] [-T d|u] [pool] ... [interval [count]] * * -c CMD For each vdev, run command CMD * -g Display guid for individual vdev name. + * -k Display type of device, e.g. solid-state or mixed. * -L Follow links when resolving vdev path name. * -P Display full path for vdev name. * -v Display complete error logs @@ -6092,7 +6141,7 @@ zpool_do_status(int argc, char **argv) char *cmd = NULL; /* check options */ - while ((c = getopt(argc, argv, "c:gLPvxDT:")) != -1) { + while ((c = getopt(argc, argv, "c:gkLPvxDT:")) != -1) { switch (c) { case 'c': cmd = optarg; @@ -6100,6 +6149,9 @@ zpool_do_status(int argc, char **argv) case 'g': cb.cb_name_flags |= VDEV_NAME_GUID; break; + case 'k': + cb.cb_rot_type = B_TRUE; + break; case 'L': cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS; break; diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index 45b6d4981bca..f4cdc9b130bd 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -595,6 +595,9 @@ typedef struct zpool_rewind_policy { /* vdev enclosure sysfs path */ #define ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH "vdev_enc_sysfs_path" +/* Type (ssd, file, mix, hdd) (part of vdev_stat_ex_t) */ +#define ZPOOL_CONFIG_VDEV_ROT_TYPE "rot_type" + #define ZPOOL_CONFIG_WHOLE_DISK "whole_disk" #define ZPOOL_CONFIG_ERRCOUNT "error_count" #define ZPOOL_CONFIG_NOT_PRESENT "not_present" @@ -730,6 +733,14 @@ typedef enum vdev_aux { VDEV_AUX_SPLIT_POOL /* vdev was split off into another pool */ } vdev_aux_t; +typedef enum vdev_rot_type_info { + VDEV_ROT_TYPE_UNKNOWN = 0, /* not set yet */ + VDEV_ROT_TYPE_SSD, /* device is solid state */ + VDEV_ROT_TYPE_FILE, /* device is file backed */ + VDEV_ROT_TYPE_MIXED, /* device has both types */ + VDEV_ROT_TYPE_HDD /* device is not solid state */ +} vdev_rot_type_info_t; + /* * pool state. The following states are written to disk as part of the normal * SPA lifecycle: ACTIVE, EXPORTED, DESTROYED, SPARE, L2CACHE. The remaining @@ -887,6 +898,11 @@ typedef struct vdev_stat_ex { uint64_t vsx_agg_histo[ZIO_PRIORITY_NUM_QUEUEABLE] [VDEV_RQ_HISTO_BUCKETS]; + /* + * Rotational type of vdev (ssd, file, mixed, hdd). + * Exported as one value. + */ + uint64_t vsx_rot_type; } vdev_stat_ex_t; /* diff --git a/include/sys/vdev_impl.h b/include/sys/vdev_impl.h index d7f11a2b885d..7187f957ba65 100644 --- a/include/sys/vdev_impl.h +++ b/include/sys/vdev_impl.h @@ -159,6 +159,7 @@ struct vdev { boolean_t vdev_expanding; /* expand the vdev? */ boolean_t vdev_reopening; /* reopen in progress? */ boolean_t vdev_nonrot; /* true if solid state */ + boolean_t vdev_nonrot_mix; /* true if partial solid state */ int vdev_open_error; /* error on last open */ kthread_t *vdev_open_thread; /* thread opening children */ uint64_t vdev_crtxg; /* txg when top-level was added */ diff --git a/man/man8/zpool.8 b/man/man8/zpool.8 index 883d1173973f..9b5a7bd14324 100644 --- a/man/man8/zpool.8 +++ b/man/man8/zpool.8 @@ -96,7 +96,7 @@ zpool \- configures ZFS storage pools .LP .nf -\fB\fBzpool iostat\fR [\fB-c\fR \fBCMD\fR] [\fB-T\fR \fBd\fR | \fBu\fR] [\fB-ghHLpPvy\fR] [\fB-lq\fR]|[\fB-r\fR|-\fBw\fR]] +\fB\fBzpool iostat\fR [\fB-c\fR \fBCMD\fR] [\fB-T\fR \fBd\fR | \fBu\fR] [\fB-ghHkLpPvy\fR] [\fB-lq\fR]|[\fB-r\fR|-\fBw\fR]] [[\fIpool\fR ...]|[\fIpool vdev\fR ...]|[\fIvdev\fR ...]] [\fIinterval\fR[\fIcount\fR]]\fR .fi @@ -159,7 +159,7 @@ zpool \- configures ZFS storage pools .LP .nf -\fBzpool status\fR [\fB-c\fR \fBCMD\fR] [\fB-gLPvxD\fR] [\fB-T\fR d | u] [\fIpool\fR] ... [\fIinterval\fR [\fIcount\fR]] +\fBzpool status\fR [\fB-c\fR \fBCMD\fR] [\fB-gkLPvxD\fR] [\fB-T\fR d | u] [\fIpool\fR] ... [\fIinterval\fR [\fIcount\fR]] .fi .LP @@ -1523,7 +1523,7 @@ Scan using the default search path, the libblkid cache will not be consulted. A .sp .ne 2 .na -\fB\fBzpool iostat\fR [\fB-c\fR \fBCMD\fR] [\fB-T\fR \fBd\fR | \fBu\fR] [\fB-ghHLpPvy\fR] [[\fB-lq\fR]|[\fB-r\fR|\fB-w\fR]] [[\fIpool\fR ...]|[\fIpool vdev\fR ...]|[\fIvdev\fR ...]] [\fIinterval\fR[\fIcount\fR]]\fR +\fB\fBzpool iostat\fR [\fB-c\fR \fBCMD\fR] [\fB-T\fR \fBd\fR | \fBu\fR] [\fB-ghHkLpPvy\fR] [[\fB-lq\fR]|[\fB-r\fR|\fB-w\fR]] [[\fIpool\fR ...]|[\fIpool vdev\fR ...]|[\fIvdev\fR ...]] [\fIinterval\fR[\fIcount\fR]]\fR .ad .sp .6 @@ -1585,6 +1585,15 @@ Display vdev GUIDs instead of the normal device names. These GUIDs can be used i Scripted mode. Do not display headers, and separate fields by a single tab instead of arbitrary space. .RE +.sp +.ne 2 +.na +\fB\fB-k\fR\fR +.ad +.RS 12n +Display the type of device a pool or vdev is based on: ssd, hdd or file. Mixed mirror vdevs that have both ssd (or file) and hdd members are marked "mix". A pool is considered mixed if all members are at least mixed, i.e. no pure hdd. +.RE + .sp .ne 2 .na @@ -2099,7 +2108,7 @@ Sets the specified property for \fInewpool\fR. See the “Properties” section .sp .ne 2 .na -\fBzpool status\fR [\fB-c\fR \fBCMD\fR] [\fB-gLPvxD\fR] [\fB-T\fR d | u] [\fIpool\fR] ... [\fIinterval\fR [\fIcount\fR]] +\fBzpool status\fR [\fB-c\fR \fBCMD\fR] [\fB-gkLPvxD\fR] [\fB-T\fR d | u] [\fIpool\fR] ... [\fIinterval\fR [\fIcount\fR]] .ad .sp .6 .RS 4n @@ -2133,6 +2142,15 @@ in parallel for each vdev for performance. Display vdev GUIDs instead of the normal device names. These GUIDs can be used innplace of device names for the zpool detach/offline/remove/replace commands. .RE +.sp +.ne 2 +.na +\fB\fB-k\fR\fR +.ad +.RS 12n +Display the type of device a pool or vdev is based on: ssd, hdd or file. Mixed mirror vdevs that have both ssd (or file) and hdd members are marked "mix". A pool is considered mixed if all members are at least mixed, i.e. no pure hdd. +.RE + .sp .ne 2 .na diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c index 77bfef3a0a9b..ecc4328c3f03 100644 --- a/module/zfs/vdev.c +++ b/module/zfs/vdev.c @@ -1173,6 +1173,7 @@ vdev_open_children(vdev_t *vd) taskq_t *tq; int children = vd->vdev_children; int c; + boolean_t nonrot_some; /* * in order to handle pools on top of zvols, do the opens @@ -1198,9 +1199,19 @@ vdev_open_children(vdev_t *vd) } vd->vdev_nonrot = B_TRUE; + vd->vdev_nonrot_mix = B_TRUE; + nonrot_some = B_FALSE; - for (c = 0; c < children; c++) + for (c = 0; c < children; c++) { vd->vdev_nonrot &= vd->vdev_child[c]->vdev_nonrot; + vd->vdev_nonrot_mix &= vd->vdev_child[c]->vdev_nonrot_mix | + vd->vdev_child[c]->vdev_nonrot; + nonrot_some |= vd->vdev_child[c]->vdev_nonrot; + } + if (vd->vdev_ops == &vdev_mirror_ops) + vd->vdev_nonrot_mix |= nonrot_some; + if (vd->vdev_nonrot) + vd->vdev_nonrot_mix = B_FALSE; } /* @@ -2895,6 +2906,17 @@ vdev_get_stats_ex_impl(vdev_t *vd, vdev_stat_t *vs, vdev_stat_ex_t *vsx) &vd->vdev_queue.vq_class[t].vqc_queued_tree); } } + if (vsx) { + if (vd->vdev_nonrot) { + if (vd->vdev_ops == &vdev_file_ops) + vsx->vsx_rot_type = VDEV_ROT_TYPE_FILE; + else + vsx->vsx_rot_type = VDEV_ROT_TYPE_SSD; + } else if (vd->vdev_nonrot_mix) + vsx->vsx_rot_type = VDEV_ROT_TYPE_MIXED; + else + vsx->vsx_rot_type = VDEV_ROT_TYPE_HDD; + } } void diff --git a/module/zfs/vdev_disk.c b/module/zfs/vdev_disk.c index d096d754f709..6fe7b8efa47e 100644 --- a/module/zfs/vdev_disk.c +++ b/module/zfs/vdev_disk.c @@ -321,6 +321,7 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize, /* Inform the ZIO pipeline that we are non-rotational */ v->vdev_nonrot = blk_queue_nonrot(bdev_get_queue(vd->vd_bdev)); + v->vdev_nonrot_mix = B_FALSE; /* Physical volume size in bytes */ *psize = bdev_capacity(vd->vd_bdev); diff --git a/module/zfs/vdev_file.c b/module/zfs/vdev_file.c index 54a50c318fe8..e674f0e45ebc 100644 --- a/module/zfs/vdev_file.c +++ b/module/zfs/vdev_file.c @@ -62,6 +62,7 @@ vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, /* Rotational optimizations only make sense on block devices */ vd->vdev_nonrot = B_TRUE; + vd->vdev_nonrot_mix = B_FALSE; /* * We must have a pathname, and it must be absolute. diff --git a/module/zfs/vdev_label.c b/module/zfs/vdev_label.c index 7a3a0e8a0644..be1d97e23fd1 100644 --- a/module/zfs/vdev_label.c +++ b/module/zfs/vdev_label.c @@ -344,6 +344,8 @@ vdev_config_generate_stats(vdev_t *vd, nvlist_t *nv) vsx->vsx_agg_histo[ZIO_PRIORITY_SCRUB], ARRAY_SIZE(vsx->vsx_agg_histo[ZIO_PRIORITY_SCRUB])); + fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_ROT_TYPE, vsx->vsx_rot_type); + /* Add extended stats nvlist to main nvlist */ fnvlist_add_nvlist(nv, ZPOOL_CONFIG_VDEV_STATS_EX, nvx);