1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5ea8dc4b6Seschrock  * Common Development and Distribution License (the "License").
6ea8dc4b6Seschrock  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
21ad135b5dSChristopher Siden 
22fa9e4066Sahrens /*
233f9d6ad7SLin Ling  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24ad135b5dSChristopher Siden  * Copyright (c) 2012 by Delphix. All rights reserved.
257f2416efSSteven Hartland  * Copyright (c) 2013 Steven Hartland. All rights reserved.
26fa9e4066Sahrens  */
27fa9e4066Sahrens 
28fa9e4066Sahrens /*
29fa9e4066Sahrens  * This file contains the functions which analyze the status of a pool.  This
30fa9e4066Sahrens  * include both the status of an active pool, as well as the status exported
31fa9e4066Sahrens  * pools.  Returns one of the ZPOOL_STATUS_* defines describing the status of
32fa9e4066Sahrens  * the pool.  This status is independent (to a certain degree) from the state of
333d7072f8Seschrock  * the pool.  A pool's state describes only whether or not it is capable of
34fa9e4066Sahrens  * providing the necessary fault tolerance for data.  The status describes the
35fa9e4066Sahrens  * overall status of devices.  A pool that is online can still have a device
36fa9e4066Sahrens  * that is experiencing errors.
37fa9e4066Sahrens  *
38fa9e4066Sahrens  * Only a subset of the possible faults can be detected using 'zpool status',
39fa9e4066Sahrens  * and not all possible errors correspond to a FMA message ID.  The explanation
40fa9e4066Sahrens  * is left up to the caller, depending on whether it is a live pool or an
41fa9e4066Sahrens  * import.
42fa9e4066Sahrens  */
43fa9e4066Sahrens 
44fa9e4066Sahrens #include <libzfs.h>
45*d8ab6e12SDon Brady #include <libzutil.h>
46fa9e4066Sahrens #include <string.h>
4795173954Sek #include <unistd.h>
48fa9e4066Sahrens #include "libzfs_impl.h"
4957221772SChristopher Siden #include "zfeature_common.h"
50fa9e4066Sahrens 
51fa9e4066Sahrens /*
523d7072f8Seschrock  * Message ID table.  This must be kept in sync with the ZPOOL_STATUS_* defines
53fa9e4066Sahrens  * in libzfs.h.  Note that there are some status results which go past the end
54fa9e4066Sahrens  * of this table, and hence have no associated message ID.
55fa9e4066Sahrens  */
5695173954Sek static char *zfs_msgid_table[] = {
57e0f1c0afSOlaf Faaland 	"ZFS-8000-14", /* ZPOOL_STATUS_CORRUPT_CACHE */
58e0f1c0afSOlaf Faaland 	"ZFS-8000-2Q", /* ZPOOL_STATUS_MISSING_DEV_R */
59e0f1c0afSOlaf Faaland 	"ZFS-8000-3C", /* ZPOOL_STATUS_MISSING_DEV_NR */
60e0f1c0afSOlaf Faaland 	"ZFS-8000-4J", /* ZPOOL_STATUS_CORRUPT_LABEL_R */
61e0f1c0afSOlaf Faaland 	"ZFS-8000-5E", /* ZPOOL_STATUS_CORRUPT_LABEL_NR */
62e0f1c0afSOlaf Faaland 	"ZFS-8000-6X", /* ZPOOL_STATUS_BAD_GUID_SUM */
63e0f1c0afSOlaf Faaland 	"ZFS-8000-72", /* ZPOOL_STATUS_CORRUPT_POOL */
64e0f1c0afSOlaf Faaland 	"ZFS-8000-8A", /* ZPOOL_STATUS_CORRUPT_DATA */
65e0f1c0afSOlaf Faaland 	"ZFS-8000-9P", /* ZPOOL_STATUS_FAILING_DEV */
66e0f1c0afSOlaf Faaland 	"ZFS-8000-A5", /* ZPOOL_STATUS_VERSION_NEWER */
67e0f1c0afSOlaf Faaland 	"ZFS-8000-EY", /* ZPOOL_STATUS_HOSTID_MISMATCH */
68e0f1c0afSOlaf Faaland 	"ZFS-8000-EY", /* ZPOOL_STATUS_HOSTID_ACTIVE */
69e0f1c0afSOlaf Faaland 	"ZFS-8000-EY", /* ZPOOL_STATUS_HOSTID_REQUIRED */
70e0f1c0afSOlaf Faaland 	"ZFS-8000-HC", /* ZPOOL_STATUS_IO_FAILURE_WAIT */
71e0f1c0afSOlaf Faaland 	"ZFS-8000-JQ", /* ZPOOL_STATUS_IO_FAILURE_CONTINUE */
72e0f1c0afSOlaf Faaland 	"ZFS-8000-MM", /* ZPOOL_STATUS_IO_FAILURE_MMP */
73e0f1c0afSOlaf Faaland 	"ZFS-8000-K4", /* ZPOOL_STATUS_BAD_LOG */
74e0f1c0afSOlaf Faaland 	/*
75e0f1c0afSOlaf Faaland 	 * The following results have no message ID.
76e0f1c0afSOlaf Faaland 	 *	ZPOOL_STATUS_UNSUP_FEAT_READ
77e0f1c0afSOlaf Faaland 	 *	ZPOOL_STATUS_UNSUP_FEAT_WRITE
78e0f1c0afSOlaf Faaland 	 *	ZPOOL_STATUS_FAULTED_DEV_R
79e0f1c0afSOlaf Faaland 	 *	ZPOOL_STATUS_FAULTED_DEV_NR
80e0f1c0afSOlaf Faaland 	 *	ZPOOL_STATUS_VERSION_OLDER
81e0f1c0afSOlaf Faaland 	 *	ZPOOL_STATUS_FEAT_DISABLED
82e0f1c0afSOlaf Faaland 	 *	ZPOOL_STATUS_RESILVERING
83e0f1c0afSOlaf Faaland 	 *	ZPOOL_STATUS_OFFLINE_DEV
84e0f1c0afSOlaf Faaland 	 *	ZPOOL_STATUS_REMOVED_DEV
85e0f1c0afSOlaf Faaland 	 *	ZPOOL_STATUS_OK
86e0f1c0afSOlaf Faaland 	 */
87fa9e4066Sahrens };
88fa9e4066Sahrens 
8995173954Sek #define	NMSGID	(sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
90fa9e4066Sahrens 
91fa9e4066Sahrens /* ARGSUSED */
92fa9e4066Sahrens static int
vdev_missing(uint64_t state,uint64_t aux,uint64_t errs)93fa9e4066Sahrens vdev_missing(uint64_t state, uint64_t aux, uint64_t errs)
94fa9e4066Sahrens {
95fa9e4066Sahrens 	return (state == VDEV_STATE_CANT_OPEN &&
96fa9e4066Sahrens 	    aux == VDEV_AUX_OPEN_FAILED);
97fa9e4066Sahrens }
98fa9e4066Sahrens 
993d7072f8Seschrock /* ARGSUSED */
1003d7072f8Seschrock static int
vdev_faulted(uint64_t state,uint64_t aux,uint64_t errs)1013d7072f8Seschrock vdev_faulted(uint64_t state, uint64_t aux, uint64_t errs)
1023d7072f8Seschrock {
1033d7072f8Seschrock 	return (state == VDEV_STATE_FAULTED);
1043d7072f8Seschrock }
1053d7072f8Seschrock 
106fa9e4066Sahrens /* ARGSUSED */
107fa9e4066Sahrens static int
vdev_errors(uint64_t state,uint64_t aux,uint64_t errs)108fa9e4066Sahrens vdev_errors(uint64_t state, uint64_t aux, uint64_t errs)
109fa9e4066Sahrens {
1103d7072f8Seschrock 	return (state == VDEV_STATE_DEGRADED || errs != 0);
111fa9e4066Sahrens }
112fa9e4066Sahrens 
113fa9e4066Sahrens /* ARGSUSED */
114fa9e4066Sahrens static int
vdev_broken(uint64_t state,uint64_t aux,uint64_t errs)115fa9e4066Sahrens vdev_broken(uint64_t state, uint64_t aux, uint64_t errs)
116fa9e4066Sahrens {
117fa9e4066Sahrens 	return (state == VDEV_STATE_CANT_OPEN);
118fa9e4066Sahrens }
119fa9e4066Sahrens 
120fa9e4066Sahrens /* ARGSUSED */
121fa9e4066Sahrens static int
vdev_offlined(uint64_t state,uint64_t aux,uint64_t errs)122fa9e4066Sahrens vdev_offlined(uint64_t state, uint64_t aux, uint64_t errs)
123fa9e4066Sahrens {
124fa9e4066Sahrens 	return (state == VDEV_STATE_OFFLINE);
125fa9e4066Sahrens }
126fa9e4066Sahrens 
127c25309d4SGeorge Wilson /* ARGSUSED */
128c25309d4SGeorge Wilson static int
vdev_removed(uint64_t state,uint64_t aux,uint64_t errs)129c25309d4SGeorge Wilson vdev_removed(uint64_t state, uint64_t aux, uint64_t errs)
130c25309d4SGeorge Wilson {
131c25309d4SGeorge Wilson 	return (state == VDEV_STATE_REMOVED);
132c25309d4SGeorge Wilson }
133c25309d4SGeorge Wilson 
134fa9e4066Sahrens /*
135fa9e4066Sahrens  * Detect if any leaf devices that have seen errors or could not be opened.
136fa9e4066Sahrens  */
13799653d4eSeschrock static boolean_t
find_vdev_problem(nvlist_t * vdev,int (* func)(uint64_t,uint64_t,uint64_t))138fa9e4066Sahrens find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
139fa9e4066Sahrens {
140fa9e4066Sahrens 	nvlist_t **child;
141fa9e4066Sahrens 	vdev_stat_t *vs;
142fa9e4066Sahrens 	uint_t c, children;
143fa9e4066Sahrens 	char *type;
144fa9e4066Sahrens 
145fa9e4066Sahrens 	/*
146fa9e4066Sahrens 	 * Ignore problems within a 'replacing' vdev, since we're presumably in
147fa9e4066Sahrens 	 * the process of repairing any such errors, and don't want to call them
148fa9e4066Sahrens 	 * out again.  We'll pick up the fact that a resilver is happening
149fa9e4066Sahrens 	 * later.
150fa9e4066Sahrens 	 */
151fa9e4066Sahrens 	verify(nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE, &type) == 0);
152fa9e4066Sahrens 	if (strcmp(type, VDEV_TYPE_REPLACING) == 0)
15399653d4eSeschrock 		return (B_FALSE);
154fa9e4066Sahrens 
155fa9e4066Sahrens 	if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
156fa9e4066Sahrens 	    &children) == 0) {
157fa9e4066Sahrens 		for (c = 0; c < children; c++)
158fa9e4066Sahrens 			if (find_vdev_problem(child[c], func))
15999653d4eSeschrock 				return (B_TRUE);
160fa9e4066Sahrens 	} else {
1613f9d6ad7SLin Ling 		verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
162fa9e4066Sahrens 		    (uint64_t **)&vs, &c) == 0);
163fa9e4066Sahrens 
164fa9e4066Sahrens 		if (func(vs->vs_state, vs->vs_aux,
165fa9e4066Sahrens 		    vs->vs_read_errors +
166fa9e4066Sahrens 		    vs->vs_write_errors +
167fa9e4066Sahrens 		    vs->vs_checksum_errors))
16899653d4eSeschrock 			return (B_TRUE);
169fa9e4066Sahrens 	}
170fa9e4066Sahrens 
1717f2416efSSteven Hartland 	/*
1727f2416efSSteven Hartland 	 * Check any L2 cache devs
1737f2416efSSteven Hartland 	 */
1747f2416efSSteven Hartland 	if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_L2CACHE, &child,
1757f2416efSSteven Hartland 	    &children) == 0) {
1767f2416efSSteven Hartland 		for (c = 0; c < children; c++)
1777f2416efSSteven Hartland 			if (find_vdev_problem(child[c], func))
1787f2416efSSteven Hartland 				return (B_TRUE);
1797f2416efSSteven Hartland 	}
1807f2416efSSteven Hartland 
18199653d4eSeschrock 	return (B_FALSE);
182fa9e4066Sahrens }
183fa9e4066Sahrens 
184fa9e4066Sahrens /*
185fa9e4066Sahrens  * Active pool health status.
186fa9e4066Sahrens  *
187fa9e4066Sahrens  * To determine the status for a pool, we make several passes over the config,
188fa9e4066Sahrens  * picking the most egregious error we find.  In order of importance, we do the
189fa9e4066Sahrens  * following:
190fa9e4066Sahrens  *
191fa9e4066Sahrens  *	- Check for a complete and valid configuration
1923d7072f8Seschrock  *	- Look for any faulted or missing devices in a non-replicated config
193fa9e4066Sahrens  *	- Check for any data errors
1943d7072f8Seschrock  *	- Check for any faulted or missing devices in a replicated config
195ea8dc4b6Seschrock  *	- Look for any devices showing errors
196fa9e4066Sahrens  *	- Check for any resilvering devices
197fa9e4066Sahrens  *
198fa9e4066Sahrens  * There can obviously be multiple errors within a single pool, so this routine
199fa9e4066Sahrens  * only picks the most damaging of all the current errors to report.
200fa9e4066Sahrens  */
201fa9e4066Sahrens static zpool_status_t
check_status(nvlist_t * config,boolean_t isimport,zpool_errata_t * erratap)202eb633035STom Caputi check_status(nvlist_t *config, boolean_t isimport, zpool_errata_t *erratap)
203fa9e4066Sahrens {
204fa9e4066Sahrens 	nvlist_t *nvroot;
205fa9e4066Sahrens 	vdev_stat_t *vs;
2063f9d6ad7SLin Ling 	pool_scan_stat_t *ps = NULL;
2073f9d6ad7SLin Ling 	uint_t vsc, psc;
208ea8dc4b6Seschrock 	uint64_t nerr;
209eaca9bbdSeschrock 	uint64_t version;
21095173954Sek 	uint64_t stateval;
211e14bb325SJeff Bonwick 	uint64_t suspended;
21295173954Sek 	uint64_t hostid = 0;
213eb633035STom Caputi 	uint64_t errata = 0;
214e0f1c0afSOlaf Faaland 	unsigned long system_hostid = get_system_hostid();
215fa9e4066Sahrens 
216eaca9bbdSeschrock 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
217eaca9bbdSeschrock 	    &version) == 0);
218fa9e4066Sahrens 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
219fa9e4066Sahrens 	    &nvroot) == 0);
2203f9d6ad7SLin Ling 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
221fa9e4066Sahrens 	    (uint64_t **)&vs, &vsc) == 0);
22295173954Sek 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
22395173954Sek 	    &stateval) == 0);
2243f9d6ad7SLin Ling 
2253f9d6ad7SLin Ling 	/*
2263f9d6ad7SLin Ling 	 * Currently resilvering a vdev
2273f9d6ad7SLin Ling 	 */
2283f9d6ad7SLin Ling 	(void) nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_SCAN_STATS,
2293f9d6ad7SLin Ling 	    (uint64_t **)&ps, &psc);
230a3874b8bSToomas Soome 	if (ps != NULL && ps->pss_func == POOL_SCAN_RESILVER &&
2313f9d6ad7SLin Ling 	    ps->pss_state == DSS_SCANNING)
2323f9d6ad7SLin Ling 		return (ZPOOL_STATUS_RESILVERING);
23395173954Sek 
234e0f1c0afSOlaf Faaland 	/*
235e0f1c0afSOlaf Faaland 	 * The multihost property is set and the pool may be active.
236e0f1c0afSOlaf Faaland 	 */
237e0f1c0afSOlaf Faaland 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
238e0f1c0afSOlaf Faaland 	    vs->vs_aux == VDEV_AUX_ACTIVE) {
239e0f1c0afSOlaf Faaland 		mmp_state_t mmp_state;
240e0f1c0afSOlaf Faaland 		nvlist_t *nvinfo;
241e0f1c0afSOlaf Faaland 
242e0f1c0afSOlaf Faaland 		nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
243e0f1c0afSOlaf Faaland 		mmp_state = fnvlist_lookup_uint64(nvinfo,
244e0f1c0afSOlaf Faaland 		    ZPOOL_CONFIG_MMP_STATE);
245e0f1c0afSOlaf Faaland 
246e0f1c0afSOlaf Faaland 		if (mmp_state == MMP_STATE_ACTIVE)
247e0f1c0afSOlaf Faaland 			return (ZPOOL_STATUS_HOSTID_ACTIVE);
248e0f1c0afSOlaf Faaland 		else if (mmp_state == MMP_STATE_NO_HOSTID)
249e0f1c0afSOlaf Faaland 			return (ZPOOL_STATUS_HOSTID_REQUIRED);
250e0f1c0afSOlaf Faaland 		else
251e0f1c0afSOlaf Faaland 			return (ZPOOL_STATUS_HOSTID_MISMATCH);
252e0f1c0afSOlaf Faaland 	}
253e0f1c0afSOlaf Faaland 
25495173954Sek 	/*
25595173954Sek 	 * Pool last accessed by another system.
25695173954Sek 	 */
2573f9d6ad7SLin Ling 	(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
258e0f1c0afSOlaf Faaland 	if (hostid != 0 && (unsigned long)hostid != system_hostid &&
25995173954Sek 	    stateval == POOL_STATE_ACTIVE)
26095173954Sek 		return (ZPOOL_STATUS_HOSTID_MISMATCH);
261fa9e4066Sahrens 
262eaca9bbdSeschrock 	/*
263eaca9bbdSeschrock 	 * Newer on-disk version.
264eaca9bbdSeschrock 	 */
265eaca9bbdSeschrock 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
266eaca9bbdSeschrock 	    vs->vs_aux == VDEV_AUX_VERSION_NEWER)
267eaca9bbdSeschrock 		return (ZPOOL_STATUS_VERSION_NEWER);
268eaca9bbdSeschrock 
269ad135b5dSChristopher Siden 	/*
270ad135b5dSChristopher Siden 	 * Unsupported feature(s).
271ad135b5dSChristopher Siden 	 */
272ad135b5dSChristopher Siden 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
273ad135b5dSChristopher Siden 	    vs->vs_aux == VDEV_AUX_UNSUP_FEAT) {
274ad135b5dSChristopher Siden 		nvlist_t *nvinfo;
275ad135b5dSChristopher Siden 
276ad135b5dSChristopher Siden 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO,
277ad135b5dSChristopher Siden 		    &nvinfo) == 0);
278ad135b5dSChristopher Siden 		if (nvlist_exists(nvinfo, ZPOOL_CONFIG_CAN_RDONLY))
279ad135b5dSChristopher Siden 			return (ZPOOL_STATUS_UNSUP_FEAT_WRITE);
280ad135b5dSChristopher Siden 		return (ZPOOL_STATUS_UNSUP_FEAT_READ);
281ad135b5dSChristopher Siden 	}
282ad135b5dSChristopher Siden 
283fa9e4066Sahrens 	/*
284fa9e4066Sahrens 	 * Check that the config is complete.
285fa9e4066Sahrens 	 */
286fa9e4066Sahrens 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
287ea8dc4b6Seschrock 	    vs->vs_aux == VDEV_AUX_BAD_GUID_SUM)
288fa9e4066Sahrens 		return (ZPOOL_STATUS_BAD_GUID_SUM);
289fa9e4066Sahrens 
29032b87932Sek 	/*
291e0f1c0afSOlaf Faaland 	 * Check whether the pool has suspended.
29232b87932Sek 	 */
293e14bb325SJeff Bonwick 	if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED,
294e14bb325SJeff Bonwick 	    &suspended) == 0) {
295e0f1c0afSOlaf Faaland 		uint64_t reason;
296e0f1c0afSOlaf Faaland 
297e0f1c0afSOlaf Faaland 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED_REASON,
298e0f1c0afSOlaf Faaland 		    &reason) == 0 && reason == ZIO_SUSPEND_MMP)
299e0f1c0afSOlaf Faaland 			return (ZPOOL_STATUS_IO_FAILURE_MMP);
300e0f1c0afSOlaf Faaland 
301e14bb325SJeff Bonwick 		if (suspended == ZIO_FAILURE_MODE_CONTINUE)
30232b87932Sek 			return (ZPOOL_STATUS_IO_FAILURE_CONTINUE);
303e14bb325SJeff Bonwick 		return (ZPOOL_STATUS_IO_FAILURE_WAIT);
30432b87932Sek 	}
30532b87932Sek 
306b87f3af3Sperrin 	/*
307b87f3af3Sperrin 	 * Could not read a log.
308b87f3af3Sperrin 	 */
309b87f3af3Sperrin 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
310b87f3af3Sperrin 	    vs->vs_aux == VDEV_AUX_BAD_LOG) {
311b87f3af3Sperrin 		return (ZPOOL_STATUS_BAD_LOG);
312b87f3af3Sperrin 	}
313b87f3af3Sperrin 
314fa9e4066Sahrens 	/*
3153d7072f8Seschrock 	 * Bad devices in non-replicated config.
316fa9e4066Sahrens 	 */
3173d7072f8Seschrock 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
3183d7072f8Seschrock 	    find_vdev_problem(nvroot, vdev_faulted))
3193d7072f8Seschrock 		return (ZPOOL_STATUS_FAULTED_DEV_NR);
3203d7072f8Seschrock 
321ea8dc4b6Seschrock 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
322ea8dc4b6Seschrock 	    find_vdev_problem(nvroot, vdev_missing))
323ea8dc4b6Seschrock 		return (ZPOOL_STATUS_MISSING_DEV_NR);
324ea8dc4b6Seschrock 
325ea8dc4b6Seschrock 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
326ea8dc4b6Seschrock 	    find_vdev_problem(nvroot, vdev_broken))
327ea8dc4b6Seschrock 		return (ZPOOL_STATUS_CORRUPT_LABEL_NR);
328ea8dc4b6Seschrock 
329ea8dc4b6Seschrock 	/*
330ea8dc4b6Seschrock 	 * Corrupted pool metadata
331ea8dc4b6Seschrock 	 */
332ea8dc4b6Seschrock 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
333ea8dc4b6Seschrock 	    vs->vs_aux == VDEV_AUX_CORRUPT_DATA)
334ea8dc4b6Seschrock 		return (ZPOOL_STATUS_CORRUPT_POOL);
335fa9e4066Sahrens 
336fa9e4066Sahrens 	/*
337ea8dc4b6Seschrock 	 * Persistent data errors.
338fa9e4066Sahrens 	 */
339ea8dc4b6Seschrock 	if (!isimport) {
340ea8dc4b6Seschrock 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
341ea8dc4b6Seschrock 		    &nerr) == 0 && nerr != 0)
342ea8dc4b6Seschrock 			return (ZPOOL_STATUS_CORRUPT_DATA);
343fa9e4066Sahrens 	}
344fa9e4066Sahrens 
345ea8dc4b6Seschrock 	/*
346ea8dc4b6Seschrock 	 * Missing devices in a replicated config.
347ea8dc4b6Seschrock 	 */
3483d7072f8Seschrock 	if (find_vdev_problem(nvroot, vdev_faulted))
3493d7072f8Seschrock 		return (ZPOOL_STATUS_FAULTED_DEV_R);
350ea8dc4b6Seschrock 	if (find_vdev_problem(nvroot, vdev_missing))
351ea8dc4b6Seschrock 		return (ZPOOL_STATUS_MISSING_DEV_R);
352ea8dc4b6Seschrock 	if (find_vdev_problem(nvroot, vdev_broken))
353ea8dc4b6Seschrock 		return (ZPOOL_STATUS_CORRUPT_LABEL_R);
354ea8dc4b6Seschrock 
355fa9e4066Sahrens 	/*
356fa9e4066Sahrens 	 * Devices with errors
357fa9e4066Sahrens 	 */
358fa9e4066Sahrens 	if (!isimport && find_vdev_problem(nvroot, vdev_errors))
359fa9e4066Sahrens 		return (ZPOOL_STATUS_FAILING_DEV);
360fa9e4066Sahrens 
361fa9e4066Sahrens 	/*
362fa9e4066Sahrens 	 * Offlined devices
363fa9e4066Sahrens 	 */
364fa9e4066Sahrens 	if (find_vdev_problem(nvroot, vdev_offlined))
365fa9e4066Sahrens 		return (ZPOOL_STATUS_OFFLINE_DEV);
366fa9e4066Sahrens 
367c25309d4SGeorge Wilson 	/*
368c25309d4SGeorge Wilson 	 * Removed device
369c25309d4SGeorge Wilson 	 */
370c25309d4SGeorge Wilson 	if (find_vdev_problem(nvroot, vdev_removed))
371c25309d4SGeorge Wilson 		return (ZPOOL_STATUS_REMOVED_DEV);
372c25309d4SGeorge Wilson 
373eb633035STom Caputi 	/*
374eb633035STom Caputi 	 * Informational errata available.
375eb633035STom Caputi 	 */
376eb633035STom Caputi 	(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRATA, &errata);
377eb633035STom Caputi 	if (errata) {
378eb633035STom Caputi 		*erratap = errata;
379eb633035STom Caputi 		return (ZPOOL_STATUS_ERRATA);
380eb633035STom Caputi 	}
381eb633035STom Caputi 
382fa9e4066Sahrens 	/*
383eaca9bbdSeschrock 	 * Outdated, but usable, version
384fa9e4066Sahrens 	 */
385ad135b5dSChristopher Siden 	if (SPA_VERSION_IS_SUPPORTED(version) && version != SPA_VERSION)
386eaca9bbdSeschrock 		return (ZPOOL_STATUS_VERSION_OLDER);
387fa9e4066Sahrens 
38857221772SChristopher Siden 	/*
38957221772SChristopher Siden 	 * Usable pool with disabled features
39057221772SChristopher Siden 	 */
39157221772SChristopher Siden 	if (version >= SPA_VERSION_FEATURES) {
39257221772SChristopher Siden 		int i;
39357221772SChristopher Siden 		nvlist_t *feat;
39457221772SChristopher Siden 
39557221772SChristopher Siden 		if (isimport) {
39657221772SChristopher Siden 			feat = fnvlist_lookup_nvlist(config,
39757221772SChristopher Siden 			    ZPOOL_CONFIG_LOAD_INFO);
398e0f1c0afSOlaf Faaland 			if (nvlist_exists(feat, ZPOOL_CONFIG_ENABLED_FEAT))
399e0f1c0afSOlaf Faaland 				feat = fnvlist_lookup_nvlist(feat,
400e0f1c0afSOlaf Faaland 				    ZPOOL_CONFIG_ENABLED_FEAT);
40157221772SChristopher Siden 		} else {
40257221772SChristopher Siden 			feat = fnvlist_lookup_nvlist(config,
40357221772SChristopher Siden 			    ZPOOL_CONFIG_FEATURE_STATS);
40457221772SChristopher Siden 		}
40557221772SChristopher Siden 
40657221772SChristopher Siden 		for (i = 0; i < SPA_FEATURES; i++) {
40757221772SChristopher Siden 			zfeature_info_t *fi = &spa_feature_table[i];
40857221772SChristopher Siden 			if (!nvlist_exists(feat, fi->fi_guid))
40957221772SChristopher Siden 				return (ZPOOL_STATUS_FEAT_DISABLED);
41057221772SChristopher Siden 		}
41157221772SChristopher Siden 	}
41257221772SChristopher Siden 
413fa9e4066Sahrens 	return (ZPOOL_STATUS_OK);
414fa9e4066Sahrens }
415fa9e4066Sahrens 
416fa9e4066Sahrens zpool_status_t
zpool_get_status(zpool_handle_t * zhp,char ** msgid,zpool_errata_t * errata)417eb633035STom Caputi zpool_get_status(zpool_handle_t *zhp, char **msgid, zpool_errata_t *errata)
418fa9e4066Sahrens {
419eb633035STom Caputi 	zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata);
420fa9e4066Sahrens 
421fa9e4066Sahrens 	if (ret >= NMSGID)
422fa9e4066Sahrens 		*msgid = NULL;
423fa9e4066Sahrens 	else
4243d7072f8Seschrock 		*msgid = zfs_msgid_table[ret];
425fa9e4066Sahrens 
426fa9e4066Sahrens 	return (ret);
427fa9e4066Sahrens }
428fa9e4066Sahrens 
429fa9e4066Sahrens zpool_status_t
zpool_import_status(nvlist_t * config,char ** msgid,zpool_errata_t * errata)430eb633035STom Caputi zpool_import_status(nvlist_t *config, char **msgid, zpool_errata_t *errata)
431fa9e4066Sahrens {
432eb633035STom Caputi 	zpool_status_t ret = check_status(config, B_TRUE, errata);
433fa9e4066Sahrens 
434fa9e4066Sahrens 	if (ret >= NMSGID)
435fa9e4066Sahrens 		*msgid = NULL;
436fa9e4066Sahrens 	else
43795173954Sek 		*msgid = zfs_msgid_table[ret];
438fa9e4066Sahrens 
439fa9e4066Sahrens 	return (ret);
440fa9e4066Sahrens }
441