From 289a948a4495e1ed1f07b7631c00081a1f90316c Mon Sep 17 00:00:00 2001 From: Haakan Johansson Date: Fri, 16 Sep 2016 10:25:01 +0200 Subject: [PATCH] zpool iostat -M and status -M show media 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 media type info to zpool cmd (mainly whether devices are solid state, or rotational). Info is passed in ZPOOL_CONFIG_VDEV_STATS_EX -> ZPOOL_CONFIG_VDEV_MEDIA_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 | 3 ++ 8 files changed, 130 insertions(+), 16 deletions(-) diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index f4873cf196a6..ec7aaf75d120 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_MEDIA_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_MEDIA_TYPE_M (1ULL << IOS_MEDIA_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_MEDIA_TYPE] = { + ZPOOL_CONFIG_VDEV_MEDIA_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] [-ghHLMpPvy] " "[[-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] [-gLMPvxD] [-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 * +media_type_mark(nvlist_t *nv) +{ + nvlist_t *nvx; + uint64_t type = VDEV_MEDIA_TYPE_UNKNOWN; + + if (nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_VDEV_STATS_EX, &nvx) == 0) + nvlist_lookup_uint64(nvx, ZPOOL_CONFIG_VDEV_MEDIA_TYPE, + &type); + + switch (type) { + case VDEV_MEDIA_TYPE_SSD: + return ("ssd"); + case VDEV_MEDIA_TYPE_FILE: + return ("file"); + case VDEV_MEDIA_TYPE_MIXED: + return ("mix"); + case VDEV_MEDIA_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_media_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_media_type) + (void) printf(" %5s", media_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_MEDIA_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_MEDIA_TYPE] = {{"media"}, {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_MEDIA_TYPE] = 5, /* type/file/ssd/hdd/mix */ }; - if (cb->cb_literal) + if (cb->cb_literal || type == IOS_MEDIA_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_MEDIA_TYPE_M) + printf("%s%5s", cb->cb_scripted ? "\t" : " ", + media_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] [-ghHLMpPvy] [[-lq]|[-r|-w]] [-n name] [-T d|u] * [[ pool ...]|[pool vdev ...]|[vdev ...]] * [interval [count]] * @@ -3973,6 +4014,7 @@ fsleep(float sec) { * -H Scripted mode. Don't display headers, and separate properties * by a single tab. * -l Display average latency + * -M Display media type of device, e.g. solid-state or mixed. * -q Display queue depths * -w Display latency histograms * -r Display request size histogram @@ -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 media_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:vyhplMqrwH")) != -1) { switch (c) { case 'c': cmd = optarg; @@ -4021,6 +4064,9 @@ zpool_do_iostat(int argc, char **argv) case 'L': follow_links = B_TRUE; break; + case 'M': + media_type = B_TRUE; + break; case 'P': full_name = 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 (media_type) + cb.cb_flags |= IOS_MEDIA_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_media_type ? " MEDIA" : ""); print_status_config(zhp, cbp, zpool_get_name(zhp), nvroot, 0, B_FALSE); @@ -6068,11 +6116,12 @@ status_callback(zpool_handle_t *zhp, void *data) } /* - * zpool status [-c CMD] [-gLPvx] [-T d|u] [pool] ... [interval [count]] + * zpool status [-c CMD] [-gLMPvx] [-T d|u] [pool] ... [interval [count]] * * -c CMD For each vdev, run command CMD * -g Display guid for individual vdev name. * -L Follow links when resolving vdev path name. + * -M Display media type of device, e.g. solid-state or mixed. * -P Display full path for vdev name. * -v Display complete error logs * -x Display only pools with potential problems @@ -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:gLMPvxDT:")) != -1) { switch (c) { case 'c': cmd = optarg; @@ -6103,6 +6152,9 @@ zpool_do_status(int argc, char **argv) case 'L': cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS; break; + case 'M': + cb.cb_media_type = B_TRUE; + break; case 'P': cb.cb_name_flags |= VDEV_NAME_PATH; break; diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index 45b6d4981bca..0a09b0769b4a 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_MEDIA_TYPE "media_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_media_type_info { + VDEV_MEDIA_TYPE_UNKNOWN = 0, /* not set yet */ + VDEV_MEDIA_TYPE_SSD, /* device is solid state */ + VDEV_MEDIA_TYPE_FILE, /* device is file backed */ + VDEV_MEDIA_TYPE_MIXED, /* device has both types */ + VDEV_MEDIA_TYPE_HDD /* device is not solid state */ +} vdev_media_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_media_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..47fd1b54b6f2 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-ghHLMpPvy\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-gLMPvxD\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-ghHLMpPvy\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 @@ -1594,6 +1594,15 @@ Scripted mode. Do not display headers, and separate fields by a single tab inste Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the /dev/disk/ path used to open it. .RE +.sp +.ne 2 +.na +\fB\fB-M\fR\fR +.ad +.RS 12n +Display the media 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-gLMPvxD\fR] [\fB-T\fR d | u] [\fIpool\fR] ... [\fIinterval\fR [\fIcount\fR]] .ad .sp .6 .RS 4n @@ -2142,6 +2151,15 @@ Display vdev GUIDs instead of the normal device names. These GUIDs can be used i Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the /dev/disk/ path used to open it. .RE +.sp +.ne 2 +.na +\fB\fB-M\fR\fR +.ad +.RS 12n +Display the media 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..aa50850877b1 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_media_type = VDEV_MEDIA_TYPE_FILE; + else + vsx->vsx_media_type = VDEV_MEDIA_TYPE_SSD; + } else if (vd->vdev_nonrot_mix) + vsx->vsx_media_type = VDEV_MEDIA_TYPE_MIXED; + else + vsx->vsx_media_type = VDEV_MEDIA_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..60064f4d01fb 100644 --- a/module/zfs/vdev_label.c +++ b/module/zfs/vdev_label.c @@ -344,6 +344,9 @@ 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_MEDIA_TYPE, + vsx->vsx_media_type); + /* Add extended stats nvlist to main nvlist */ fnvlist_add_nvlist(nv, ZPOOL_CONFIG_VDEV_STATS_EX, nvx);