Skip to content

Commit f0ed6c7

Browse files
tonyhutterbehlendorf
authored andcommitted
Add pool state /proc entry, "SUSPENDED" pools
1. Add a proc entry to display the pool's state: $ cat /proc/spl/kstat/zfs/tank/state ONLINE This is done without using the spa config locks, so it will never hang. 2. Fix 'zpool status' and 'zpool list -o health' output to print "SUSPENDED" instead of "ONLINE" for suspended pools. Reviewed-by: Olaf Faaland <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Reviewed by: Richard Elling <[email protected]> Signed-off-by: Tony Hutter <[email protected]> Closes #7331 Closes #7563
1 parent 2d9142c commit f0ed6c7

File tree

18 files changed

+383
-26
lines changed

18 files changed

+383
-26
lines changed

cmd/zpool/zpool_main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6484,7 +6484,8 @@ status_callback(zpool_handle_t *zhp, void *data)
64846484
nvroot = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE);
64856485
verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
64866486
(uint64_t **)&vs, &c) == 0);
6487-
health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
6487+
6488+
health = zpool_get_state_str(zhp);
64886489

64896490
(void) printf(gettext(" pool: %s\n"), zpool_get_name(zhp));
64906491
(void) printf(gettext(" state: %s\n"), health);

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ AC_CONFIG_FILES([
278278
tests/zfs-tests/tests/functional/hkdf/Makefile
279279
tests/zfs-tests/tests/functional/inheritance/Makefile
280280
tests/zfs-tests/tests/functional/inuse/Makefile
281+
tests/zfs-tests/tests/functional/kstat/Makefile
281282
tests/zfs-tests/tests/functional/large_files/Makefile
282283
tests/zfs-tests/tests/functional/largest_pool/Makefile
283284
tests/zfs-tests/tests/functional/link_count/Makefile

include/libzfs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ int zfs_dev_is_whole_disk(char *dev_name);
301301
char *zfs_get_underlying_path(char *dev_name);
302302
char *zfs_get_enclosure_sysfs_path(char *dev_name);
303303

304+
const char *zpool_get_state_str(zpool_handle_t *);
305+
304306
/*
305307
* Functions to manage pool properties
306308
*/

include/spl/sys/kstat.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,9 @@
6969
#define KSTAT_FLAG_WRITABLE 0x04
7070
#define KSTAT_FLAG_PERSISTENT 0x08
7171
#define KSTAT_FLAG_DORMANT 0x10
72-
#define KSTAT_FLAG_UNSUPPORTED \
73-
(KSTAT_FLAG_VAR_SIZE | KSTAT_FLAG_WRITABLE | \
74-
KSTAT_FLAG_PERSISTENT | KSTAT_FLAG_DORMANT)
75-
72+
#define KSTAT_FLAG_INVALID 0x20
73+
#define KSTAT_FLAG_LONGSTRINGS 0x40
74+
#define KSTAT_FLAG_NO_HEADERS 0x80
7675

7776
#define KS_MAGIC 0x9d9d9d9d
7877

include/sys/spa.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,7 @@ typedef struct spa_stats {
873873
spa_stats_history_t tx_assign_histogram;
874874
spa_stats_history_t io_history;
875875
spa_stats_history_t mmp_history;
876+
spa_stats_history_t state; /* pool state */
876877
} spa_stats_t;
877878

878879
typedef enum txg_state {
@@ -1048,6 +1049,8 @@ extern void spa_history_log_internal_ds(struct dsl_dataset *ds, const char *op,
10481049
extern void spa_history_log_internal_dd(dsl_dir_t *dd, const char *operation,
10491050
dmu_tx_t *tx, const char *fmt, ...);
10501051

1052+
extern const char *spa_state_to_name(spa_t *spa);
1053+
10511054
/* error handling */
10521055
struct zbookmark_phys;
10531056
extern void spa_log_error(spa_t *spa, const zbookmark_phys_t *zb);

lib/libspl/include/sys/kstat.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ typedef struct kstat32 {
304304
#define KSTAT_FLAG_PERSISTENT 0x08
305305
#define KSTAT_FLAG_DORMANT 0x10
306306
#define KSTAT_FLAG_INVALID 0x20
307+
#define KSTAT_FLAG_LONGSTRINGS 0x40
308+
#define KSTAT_FLAG_NO_HEADERS 0x80
307309

308310
/*
309311
* Dynamic update support

lib/libzfs/libzfs_pool.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,38 @@ zpool_pool_state_to_name(pool_state_t state)
242242
return (gettext("UNKNOWN"));
243243
}
244244

245+
/*
246+
* Given a pool handle, return the pool health string ("ONLINE", "DEGRADED",
247+
* "SUSPENDED", etc).
248+
*/
249+
const char *
250+
zpool_get_state_str(zpool_handle_t *zhp)
251+
{
252+
zpool_errata_t errata;
253+
zpool_status_t status;
254+
nvlist_t *nvroot;
255+
vdev_stat_t *vs;
256+
uint_t vsc;
257+
const char *str;
258+
259+
status = zpool_get_status(zhp, NULL, &errata);
260+
261+
if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
262+
str = gettext("FAULTED");
263+
} else if (status == ZPOOL_STATUS_IO_FAILURE_WAIT ||
264+
status == ZPOOL_STATUS_IO_FAILURE_MMP) {
265+
str = gettext("SUSPENDED");
266+
} else {
267+
verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
268+
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
269+
verify(nvlist_lookup_uint64_array(nvroot,
270+
ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc)
271+
== 0);
272+
str = zpool_state_to_name(vs->vs_state, vs->vs_aux);
273+
}
274+
return (str);
275+
}
276+
245277
/*
246278
* Get a zpool property value for 'prop' and return the value in
247279
* a pre-allocated buffer.
@@ -253,9 +285,6 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf,
253285
uint64_t intval;
254286
const char *strval;
255287
zprop_source_t src = ZPROP_SRC_NONE;
256-
nvlist_t *nvroot;
257-
vdev_stat_t *vs;
258-
uint_t vsc;
259288

260289
if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
261290
switch (prop) {
@@ -264,7 +293,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf,
264293
break;
265294

266295
case ZPOOL_PROP_HEALTH:
267-
(void) strlcpy(buf, "FAULTED", len);
296+
(void) strlcpy(buf, zpool_get_state_str(zhp), len);
268297
break;
269298

270299
case ZPOOL_PROP_GUID:
@@ -365,14 +394,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf,
365394
break;
366395

367396
case ZPOOL_PROP_HEALTH:
368-
verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
369-
ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
370-
verify(nvlist_lookup_uint64_array(nvroot,
371-
ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc)
372-
== 0);
373-
374-
(void) strlcpy(buf, zpool_state_to_name(intval,
375-
vs->vs_aux), len);
397+
(void) strlcpy(buf, zpool_get_state_str(zhp), len);
376398
break;
377399
case ZPOOL_PROP_VERSION:
378400
if (intval >= SPA_VERSION_FEATURES) {

lib/libzfs/libzfs_status.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -404,12 +404,12 @@ zpool_status_t
404404
zpool_get_status(zpool_handle_t *zhp, char **msgid, zpool_errata_t *errata)
405405
{
406406
zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata);
407-
408-
if (ret >= NMSGID)
409-
*msgid = NULL;
410-
else
411-
*msgid = zfs_msgid_table[ret];
412-
407+
if (msgid != NULL) {
408+
if (ret >= NMSGID)
409+
*msgid = NULL;
410+
else
411+
*msgid = zfs_msgid_table[ret];
412+
}
413413
return (ret);
414414
}
415415

module/spl/spl-kstat.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,8 @@ kstat_seq_start(struct seq_file *f, loff_t *pos)
389389

390390
ksp->ks_snaptime = gethrtime();
391391

392-
if (!n && kstat_seq_show_headers(f))
392+
if (!(ksp->ks_flags & KSTAT_FLAG_NO_HEADERS) && !n &&
393+
kstat_seq_show_headers(f))
393394
return (NULL);
394395

395396
if (n >= ksp->ks_ndata)
@@ -539,7 +540,6 @@ __kstat_create(const char *ks_module, int ks_instance, const char *ks_name,
539540
ASSERT(ks_module);
540541
ASSERT(ks_instance == 0);
541542
ASSERT(ks_name);
542-
ASSERT(!(ks_flags & KSTAT_FLAG_UNSUPPORTED));
543543

544544
if ((ks_type == KSTAT_TYPE_INTR) || (ks_type == KSTAT_TYPE_IO))
545545
ASSERT(ks_ndata == 1);

module/zfs/spa_misc.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2254,6 +2254,45 @@ spa_set_missing_tvds(spa_t *spa, uint64_t missing)
22542254
spa->spa_missing_tvds = missing;
22552255
}
22562256

2257+
/*
2258+
* Return the pool state string ("ONLINE", "DEGRADED", "SUSPENDED", etc).
2259+
*/
2260+
const char *
2261+
spa_state_to_name(spa_t *spa)
2262+
{
2263+
vdev_state_t state = spa->spa_root_vdev->vdev_state;
2264+
vdev_aux_t aux = spa->spa_root_vdev->vdev_stat.vs_aux;
2265+
2266+
if (spa_suspended(spa) &&
2267+
(spa_get_failmode(spa) != ZIO_FAILURE_MODE_CONTINUE))
2268+
return ("SUSPENDED");
2269+
2270+
switch (state) {
2271+
case VDEV_STATE_CLOSED:
2272+
case VDEV_STATE_OFFLINE:
2273+
return ("OFFLINE");
2274+
case VDEV_STATE_REMOVED:
2275+
return ("REMOVED");
2276+
case VDEV_STATE_CANT_OPEN:
2277+
if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG)
2278+
return ("FAULTED");
2279+
else if (aux == VDEV_AUX_SPLIT_POOL)
2280+
return ("SPLIT");
2281+
else
2282+
return ("UNAVAIL");
2283+
case VDEV_STATE_FAULTED:
2284+
return ("FAULTED");
2285+
case VDEV_STATE_DEGRADED:
2286+
return ("DEGRADED");
2287+
case VDEV_STATE_HEALTHY:
2288+
return ("ONLINE");
2289+
default:
2290+
break;
2291+
}
2292+
2293+
return ("UNKNOWN");
2294+
}
2295+
22572296
#if defined(_KERNEL)
22582297

22592298
#include <linux/mod_compat.h>
@@ -2406,6 +2445,7 @@ EXPORT_SYMBOL(spa_namespace_lock);
24062445
EXPORT_SYMBOL(spa_trust_config);
24072446
EXPORT_SYMBOL(spa_missing_tvds_allowed);
24082447
EXPORT_SYMBOL(spa_set_missing_tvds);
2448+
EXPORT_SYMBOL(spa_state_to_name);
24092449

24102450
/* BEGIN CSTYLED */
24112451
module_param(zfs_flags, uint, 0644);

module/zfs/spa_stats.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include <sys/zfs_context.h>
2323
#include <sys/spa_impl.h>
2424
#include <sys/vdev_impl.h>
25+
#include <sys/spa.h>
26+
#include <zfs_comutil.h>
2527

2628
/*
2729
* Keeps stats on last N reads per spa_t, disabled by default.
@@ -997,6 +999,64 @@ spa_mmp_history_add(spa_t *spa, uint64_t txg, uint64_t timestamp,
997999
return ((void *)smh);
9981000
}
9991001

1002+
static void *
1003+
spa_state_addr(kstat_t *ksp, loff_t n)
1004+
{
1005+
return (ksp->ks_private); /* return the spa_t */
1006+
}
1007+
1008+
static int
1009+
spa_state_data(char *buf, size_t size, void *data)
1010+
{
1011+
spa_t *spa = (spa_t *)data;
1012+
(void) snprintf(buf, size, "%s\n", spa_state_to_name(spa));
1013+
return (0);
1014+
}
1015+
1016+
/*
1017+
* Return the state of the pool in /proc/spl/kstat/zfs/<pool>/state.
1018+
*
1019+
* This is a lock-less read of the pool's state (unlike using 'zpool', which
1020+
* can potentially block for seconds). Because it doesn't block, it can useful
1021+
* as a pool heartbeat value.
1022+
*/
1023+
static void
1024+
spa_state_init(spa_t *spa)
1025+
{
1026+
spa_stats_history_t *ssh = &spa->spa_stats.state;
1027+
char *name;
1028+
kstat_t *ksp;
1029+
1030+
mutex_init(&ssh->lock, NULL, MUTEX_DEFAULT, NULL);
1031+
1032+
name = kmem_asprintf("zfs/%s", spa_name(spa));
1033+
ksp = kstat_create(name, 0, "state", "misc",
1034+
KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
1035+
1036+
ssh->kstat = ksp;
1037+
if (ksp) {
1038+
ksp->ks_lock = &ssh->lock;
1039+
ksp->ks_data = NULL;
1040+
ksp->ks_private = spa;
1041+
ksp->ks_flags |= KSTAT_FLAG_NO_HEADERS;
1042+
kstat_set_raw_ops(ksp, NULL, spa_state_data, spa_state_addr);
1043+
kstat_install(ksp);
1044+
}
1045+
1046+
strfree(name);
1047+
}
1048+
1049+
static void
1050+
spa_health_destroy(spa_t *spa)
1051+
{
1052+
spa_stats_history_t *ssh = &spa->spa_stats.state;
1053+
kstat_t *ksp = ssh->kstat;
1054+
if (ksp)
1055+
kstat_delete(ksp);
1056+
1057+
mutex_destroy(&ssh->lock);
1058+
}
1059+
10001060
void
10011061
spa_stats_init(spa_t *spa)
10021062
{
@@ -1005,11 +1065,13 @@ spa_stats_init(spa_t *spa)
10051065
spa_tx_assign_init(spa);
10061066
spa_io_history_init(spa);
10071067
spa_mmp_history_init(spa);
1068+
spa_state_init(spa);
10081069
}
10091070

10101071
void
10111072
spa_stats_destroy(spa_t *spa)
10121073
{
1074+
spa_health_destroy(spa);
10131075
spa_tx_assign_destroy(spa);
10141076
spa_txg_history_destroy(spa);
10151077
spa_read_history_destroy(spa);

tests/runfiles/linux.run

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,10 @@ tests = ['inuse_001_pos', 'inuse_003_pos', 'inuse_004_pos',
575575
post =
576576
tags = ['functional', 'inuse']
577577

578+
[tests/functional/kstat]
579+
tests = ['state']
580+
tags = ['functional', 'kstat']
581+
578582
[tests/functional/large_files]
579583
tests = ['large_files_001_pos', 'large_files_002_pos']
580584
tags = ['functional', 'large_files']

tests/zfs-tests/include/blkdev.shlib

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,16 @@ function unload_scsi_debug
421421
#
422422
function get_debug_device
423423
{
424-
lsscsi | nawk '/scsi_debug/ {print $6; exit}' | cut -d / -f3
424+
for i in {1..10} ; do
425+
val=$(lsscsi | nawk '/scsi_debug/ {print $6; exit}' | cut -d / -f3)
426+
427+
# lsscsi can take time to settle
428+
if [ "$val" != "-" ] ; then
429+
break
430+
fi
431+
sleep 1
432+
done
433+
echo "$val"
425434
}
426435

427436
#

tests/zfs-tests/tests/functional/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ SUBDIRS = \
2828
hkdf \
2929
inheritance \
3030
inuse \
31+
kstat \
3132
large_files \
3233
largest_pool \
3334
libzfs \
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/kstat
2+
dist_pkgdata_SCRIPTS = \
3+
setup.ksh \
4+
cleanup.ksh \
5+
state.ksh
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/bin/ksh -p
2+
#
3+
# CDDL HEADER START
4+
#
5+
# The contents of this file are subject to the terms of the
6+
# Common Development and Distribution License (the "License").
7+
# You may not use this file except in compliance with the License.
8+
#
9+
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10+
# or http://www.opensolaris.org/os/licensing.
11+
# See the License for the specific language governing permissions
12+
# and limitations under the License.
13+
#
14+
# When distributing Covered Code, include this CDDL HEADER in each
15+
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16+
# If applicable, add the following below this CDDL HEADER, with the
17+
# fields enclosed by brackets "[]" replaced with your own identifying
18+
# information: Portions Copyright [yyyy] [name of copyright owner]
19+
#
20+
# CDDL HEADER END
21+
#
22+
#
23+
# Copyright (c) 2018 by Lawrence Livermore National Security, LLC.
24+
#
25+
26+
. $STF_SUITE/include/libtest.shlib
27+
28+
default_cleanup

0 commit comments

Comments
 (0)