xref: /freebsd-src/sys/contrib/openzfs/lib/libzfs/libzfs_status.c (revision c170aa9f37e4ce9338a0f26e3e983f7123ea8c1a)
1eda14cbcSMatt Macy /*
2eda14cbcSMatt Macy  * CDDL HEADER START
3eda14cbcSMatt Macy  *
4eda14cbcSMatt Macy  * The contents of this file are subject to the terms of the
5eda14cbcSMatt Macy  * Common Development and Distribution License (the "License").
6eda14cbcSMatt Macy  * You may not use this file except in compliance with the License.
7eda14cbcSMatt Macy  *
8eda14cbcSMatt Macy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9eda14cbcSMatt Macy  * or http://www.opensolaris.org/os/licensing.
10eda14cbcSMatt Macy  * See the License for the specific language governing permissions
11eda14cbcSMatt Macy  * and limitations under the License.
12eda14cbcSMatt Macy  *
13eda14cbcSMatt Macy  * When distributing Covered Code, include this CDDL HEADER in each
14eda14cbcSMatt Macy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15eda14cbcSMatt Macy  * If applicable, add the following below this CDDL HEADER, with the
16eda14cbcSMatt Macy  * fields enclosed by brackets "[]" replaced with your own identifying
17eda14cbcSMatt Macy  * information: Portions Copyright [yyyy] [name of copyright owner]
18eda14cbcSMatt Macy  *
19eda14cbcSMatt Macy  * CDDL HEADER END
20eda14cbcSMatt Macy  */
21eda14cbcSMatt Macy 
22eda14cbcSMatt Macy /*
23eda14cbcSMatt Macy  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24eda14cbcSMatt Macy  * Copyright (c) 2012 by Delphix. All rights reserved.
25eda14cbcSMatt Macy  * Copyright (c) 2013 Steven Hartland. All rights reserved.
26ee36e25aSMartin Matuska  * Copyright (c) 2021, Colm Buckley <colm@tuatha.org>
27eda14cbcSMatt Macy  */
28eda14cbcSMatt Macy 
29eda14cbcSMatt Macy /*
30eda14cbcSMatt Macy  * This file contains the functions which analyze the status of a pool.  This
31eda14cbcSMatt Macy  * include both the status of an active pool, as well as the status exported
32eda14cbcSMatt Macy  * pools.  Returns one of the ZPOOL_STATUS_* defines describing the status of
33eda14cbcSMatt Macy  * the pool.  This status is independent (to a certain degree) from the state of
34eda14cbcSMatt Macy  * the pool.  A pool's state describes only whether or not it is capable of
35eda14cbcSMatt Macy  * providing the necessary fault tolerance for data.  The status describes the
36eda14cbcSMatt Macy  * overall status of devices.  A pool that is online can still have a device
37eda14cbcSMatt Macy  * that is experiencing errors.
38eda14cbcSMatt Macy  *
39eda14cbcSMatt Macy  * Only a subset of the possible faults can be detected using 'zpool status',
40eda14cbcSMatt Macy  * and not all possible errors correspond to a FMA message ID.  The explanation
41eda14cbcSMatt Macy  * is left up to the caller, depending on whether it is a live pool or an
42eda14cbcSMatt Macy  * import.
43eda14cbcSMatt Macy  */
44eda14cbcSMatt Macy 
45eda14cbcSMatt Macy #include <libzfs.h>
46eda14cbcSMatt Macy #include <libzutil.h>
47eda14cbcSMatt Macy #include <stdlib.h>
48eda14cbcSMatt Macy #include <string.h>
49eda14cbcSMatt Macy #include <unistd.h>
50eda14cbcSMatt Macy #include <sys/systeminfo.h>
51eda14cbcSMatt Macy #include "libzfs_impl.h"
52eda14cbcSMatt Macy #include "zfeature_common.h"
53eda14cbcSMatt Macy 
54eda14cbcSMatt Macy /*
55eda14cbcSMatt Macy  * Message ID table.  This must be kept in sync with the ZPOOL_STATUS_* defines
56eda14cbcSMatt Macy  * in include/libzfs.h.  Note that there are some status results which go past
57eda14cbcSMatt Macy  * the end of this table, and hence have no associated message ID.
58eda14cbcSMatt Macy  */
59eda14cbcSMatt Macy static char *zfs_msgid_table[] = {
60eda14cbcSMatt Macy 	"ZFS-8000-14", /* ZPOOL_STATUS_CORRUPT_CACHE */
61eda14cbcSMatt Macy 	"ZFS-8000-2Q", /* ZPOOL_STATUS_MISSING_DEV_R */
62eda14cbcSMatt Macy 	"ZFS-8000-3C", /* ZPOOL_STATUS_MISSING_DEV_NR */
63eda14cbcSMatt Macy 	"ZFS-8000-4J", /* ZPOOL_STATUS_CORRUPT_LABEL_R */
64eda14cbcSMatt Macy 	"ZFS-8000-5E", /* ZPOOL_STATUS_CORRUPT_LABEL_NR */
65eda14cbcSMatt Macy 	"ZFS-8000-6X", /* ZPOOL_STATUS_BAD_GUID_SUM */
66eda14cbcSMatt Macy 	"ZFS-8000-72", /* ZPOOL_STATUS_CORRUPT_POOL */
67eda14cbcSMatt Macy 	"ZFS-8000-8A", /* ZPOOL_STATUS_CORRUPT_DATA */
68eda14cbcSMatt Macy 	"ZFS-8000-9P", /* ZPOOL_STATUS_FAILING_DEV */
69eda14cbcSMatt Macy 	"ZFS-8000-A5", /* ZPOOL_STATUS_VERSION_NEWER */
70eda14cbcSMatt Macy 	"ZFS-8000-EY", /* ZPOOL_STATUS_HOSTID_MISMATCH */
71eda14cbcSMatt Macy 	"ZFS-8000-EY", /* ZPOOL_STATUS_HOSTID_ACTIVE */
72eda14cbcSMatt Macy 	"ZFS-8000-EY", /* ZPOOL_STATUS_HOSTID_REQUIRED */
73eda14cbcSMatt Macy 	"ZFS-8000-HC", /* ZPOOL_STATUS_IO_FAILURE_WAIT */
74eda14cbcSMatt Macy 	"ZFS-8000-JQ", /* ZPOOL_STATUS_IO_FAILURE_CONTINUE */
75eda14cbcSMatt Macy 	"ZFS-8000-MM", /* ZPOOL_STATUS_IO_FAILURE_MMP */
76eda14cbcSMatt Macy 	"ZFS-8000-K4", /* ZPOOL_STATUS_BAD_LOG */
77eda14cbcSMatt Macy 	"ZFS-8000-ER", /* ZPOOL_STATUS_ERRATA */
78eda14cbcSMatt Macy 	/*
79eda14cbcSMatt Macy 	 * The following results have no message ID.
80eda14cbcSMatt Macy 	 *	ZPOOL_STATUS_UNSUP_FEAT_READ
81eda14cbcSMatt Macy 	 *	ZPOOL_STATUS_UNSUP_FEAT_WRITE
82eda14cbcSMatt Macy 	 *	ZPOOL_STATUS_FAULTED_DEV_R
83eda14cbcSMatt Macy 	 *	ZPOOL_STATUS_FAULTED_DEV_NR
84eda14cbcSMatt Macy 	 *	ZPOOL_STATUS_VERSION_OLDER
85eda14cbcSMatt Macy 	 *	ZPOOL_STATUS_FEAT_DISABLED
86eda14cbcSMatt Macy 	 *	ZPOOL_STATUS_RESILVERING
87eda14cbcSMatt Macy 	 *	ZPOOL_STATUS_OFFLINE_DEV
88eda14cbcSMatt Macy 	 *	ZPOOL_STATUS_REMOVED_DEV
89eda14cbcSMatt Macy 	 *	ZPOOL_STATUS_REBUILDING
90eda14cbcSMatt Macy 	 *	ZPOOL_STATUS_REBUILD_SCRUB
91ee36e25aSMartin Matuska 	 *	ZPOOL_STATUS_COMPATIBILITY_ERR
92eda14cbcSMatt Macy 	 *	ZPOOL_STATUS_OK
93eda14cbcSMatt Macy 	 */
94eda14cbcSMatt Macy };
95eda14cbcSMatt Macy 
96eda14cbcSMatt Macy #define	NMSGID	(sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
97eda14cbcSMatt Macy 
98eda14cbcSMatt Macy /* ARGSUSED */
99eda14cbcSMatt Macy static int
100eda14cbcSMatt Macy vdev_missing(vdev_stat_t *vs, uint_t vsc)
101eda14cbcSMatt Macy {
102eda14cbcSMatt Macy 	return (vs->vs_state == VDEV_STATE_CANT_OPEN &&
103eda14cbcSMatt Macy 	    vs->vs_aux == VDEV_AUX_OPEN_FAILED);
104eda14cbcSMatt Macy }
105eda14cbcSMatt Macy 
106eda14cbcSMatt Macy /* ARGSUSED */
107eda14cbcSMatt Macy static int
108eda14cbcSMatt Macy vdev_faulted(vdev_stat_t *vs, uint_t vsc)
109eda14cbcSMatt Macy {
110eda14cbcSMatt Macy 	return (vs->vs_state == VDEV_STATE_FAULTED);
111eda14cbcSMatt Macy }
112eda14cbcSMatt Macy 
113eda14cbcSMatt Macy /* ARGSUSED */
114eda14cbcSMatt Macy static int
115eda14cbcSMatt Macy vdev_errors(vdev_stat_t *vs, uint_t vsc)
116eda14cbcSMatt Macy {
117eda14cbcSMatt Macy 	return (vs->vs_state == VDEV_STATE_DEGRADED ||
118eda14cbcSMatt Macy 	    vs->vs_read_errors != 0 || vs->vs_write_errors != 0 ||
119eda14cbcSMatt Macy 	    vs->vs_checksum_errors != 0);
120eda14cbcSMatt Macy }
121eda14cbcSMatt Macy 
122eda14cbcSMatt Macy /* ARGSUSED */
123eda14cbcSMatt Macy static int
124eda14cbcSMatt Macy vdev_broken(vdev_stat_t *vs, uint_t vsc)
125eda14cbcSMatt Macy {
126eda14cbcSMatt Macy 	return (vs->vs_state == VDEV_STATE_CANT_OPEN);
127eda14cbcSMatt Macy }
128eda14cbcSMatt Macy 
129eda14cbcSMatt Macy /* ARGSUSED */
130eda14cbcSMatt Macy static int
131eda14cbcSMatt Macy vdev_offlined(vdev_stat_t *vs, uint_t vsc)
132eda14cbcSMatt Macy {
133eda14cbcSMatt Macy 	return (vs->vs_state == VDEV_STATE_OFFLINE);
134eda14cbcSMatt Macy }
135eda14cbcSMatt Macy 
136eda14cbcSMatt Macy /* ARGSUSED */
137eda14cbcSMatt Macy static int
138eda14cbcSMatt Macy vdev_removed(vdev_stat_t *vs, uint_t vsc)
139eda14cbcSMatt Macy {
140eda14cbcSMatt Macy 	return (vs->vs_state == VDEV_STATE_REMOVED);
141eda14cbcSMatt Macy }
142eda14cbcSMatt Macy 
143eda14cbcSMatt Macy static int
144eda14cbcSMatt Macy vdev_non_native_ashift(vdev_stat_t *vs, uint_t vsc)
145eda14cbcSMatt Macy {
146eda14cbcSMatt Macy 	if (getenv("ZPOOL_STATUS_NON_NATIVE_ASHIFT_IGNORE") != NULL)
147eda14cbcSMatt Macy 		return (0);
148eda14cbcSMatt Macy 
149eda14cbcSMatt Macy 	return (VDEV_STAT_VALID(vs_physical_ashift, vsc) &&
150eda14cbcSMatt Macy 	    vs->vs_configured_ashift < vs->vs_physical_ashift);
151eda14cbcSMatt Macy }
152eda14cbcSMatt Macy 
153eda14cbcSMatt Macy /*
154eda14cbcSMatt Macy  * Detect if any leaf devices that have seen errors or could not be opened.
155eda14cbcSMatt Macy  */
156eda14cbcSMatt Macy static boolean_t
157eda14cbcSMatt Macy find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t),
158eda14cbcSMatt Macy     boolean_t ignore_replacing)
159eda14cbcSMatt Macy {
160eda14cbcSMatt Macy 	nvlist_t **child;
161eda14cbcSMatt Macy 	vdev_stat_t *vs;
162eda14cbcSMatt Macy 	uint_t c, vsc, children;
163eda14cbcSMatt Macy 
164eda14cbcSMatt Macy 	/*
165eda14cbcSMatt Macy 	 * Ignore problems within a 'replacing' vdev, since we're presumably in
166eda14cbcSMatt Macy 	 * the process of repairing any such errors, and don't want to call them
167eda14cbcSMatt Macy 	 * out again.  We'll pick up the fact that a resilver is happening
168eda14cbcSMatt Macy 	 * later.
169eda14cbcSMatt Macy 	 */
170eda14cbcSMatt Macy 	if (ignore_replacing == B_TRUE) {
171eda14cbcSMatt Macy 		char *type;
172eda14cbcSMatt Macy 
173eda14cbcSMatt Macy 		verify(nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE,
174eda14cbcSMatt Macy 		    &type) == 0);
175eda14cbcSMatt Macy 		if (strcmp(type, VDEV_TYPE_REPLACING) == 0)
176eda14cbcSMatt Macy 			return (B_FALSE);
177eda14cbcSMatt Macy 	}
178eda14cbcSMatt Macy 
179eda14cbcSMatt Macy 	if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
180eda14cbcSMatt Macy 	    &children) == 0) {
181eda14cbcSMatt Macy 		for (c = 0; c < children; c++)
182eda14cbcSMatt Macy 			if (find_vdev_problem(child[c], func, ignore_replacing))
183eda14cbcSMatt Macy 				return (B_TRUE);
184eda14cbcSMatt Macy 	} else {
185eda14cbcSMatt Macy 		verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
186eda14cbcSMatt Macy 		    (uint64_t **)&vs, &vsc) == 0);
187eda14cbcSMatt Macy 
188eda14cbcSMatt Macy 		if (func(vs, vsc) != 0)
189eda14cbcSMatt Macy 			return (B_TRUE);
190eda14cbcSMatt Macy 	}
191eda14cbcSMatt Macy 
192eda14cbcSMatt Macy 	/*
193eda14cbcSMatt Macy 	 * Check any L2 cache devs
194eda14cbcSMatt Macy 	 */
195eda14cbcSMatt Macy 	if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_L2CACHE, &child,
196eda14cbcSMatt Macy 	    &children) == 0) {
197eda14cbcSMatt Macy 		for (c = 0; c < children; c++)
198eda14cbcSMatt Macy 			if (find_vdev_problem(child[c], func, ignore_replacing))
199eda14cbcSMatt Macy 				return (B_TRUE);
200eda14cbcSMatt Macy 	}
201eda14cbcSMatt Macy 
202eda14cbcSMatt Macy 	return (B_FALSE);
203eda14cbcSMatt Macy }
204eda14cbcSMatt Macy 
205eda14cbcSMatt Macy /*
206eda14cbcSMatt Macy  * Active pool health status.
207eda14cbcSMatt Macy  *
208eda14cbcSMatt Macy  * To determine the status for a pool, we make several passes over the config,
209eda14cbcSMatt Macy  * picking the most egregious error we find.  In order of importance, we do the
210eda14cbcSMatt Macy  * following:
211eda14cbcSMatt Macy  *
212eda14cbcSMatt Macy  *	- Check for a complete and valid configuration
213eda14cbcSMatt Macy  *	- Look for any faulted or missing devices in a non-replicated config
214eda14cbcSMatt Macy  *	- Check for any data errors
215eda14cbcSMatt Macy  *	- Check for any faulted or missing devices in a replicated config
216eda14cbcSMatt Macy  *	- Look for any devices showing errors
217eda14cbcSMatt Macy  *	- Check for any resilvering or rebuilding devices
218eda14cbcSMatt Macy  *
219eda14cbcSMatt Macy  * There can obviously be multiple errors within a single pool, so this routine
220eda14cbcSMatt Macy  * only picks the most damaging of all the current errors to report.
221eda14cbcSMatt Macy  */
222eda14cbcSMatt Macy static zpool_status_t
223ee36e25aSMartin Matuska check_status(nvlist_t *config, boolean_t isimport,
224ee36e25aSMartin Matuska     zpool_errata_t *erratap, const char *compat)
225eda14cbcSMatt Macy {
226eda14cbcSMatt Macy 	nvlist_t *nvroot;
227eda14cbcSMatt Macy 	vdev_stat_t *vs;
228eda14cbcSMatt Macy 	pool_scan_stat_t *ps = NULL;
229eda14cbcSMatt Macy 	uint_t vsc, psc;
230eda14cbcSMatt Macy 	uint64_t nerr;
231eda14cbcSMatt Macy 	uint64_t version;
232eda14cbcSMatt Macy 	uint64_t stateval;
233eda14cbcSMatt Macy 	uint64_t suspended;
234eda14cbcSMatt Macy 	uint64_t hostid = 0;
235eda14cbcSMatt Macy 	uint64_t errata = 0;
236eda14cbcSMatt Macy 	unsigned long system_hostid = get_system_hostid();
237eda14cbcSMatt Macy 
238eda14cbcSMatt Macy 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
239eda14cbcSMatt Macy 	    &version) == 0);
240eda14cbcSMatt Macy 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
241eda14cbcSMatt Macy 	    &nvroot) == 0);
242eda14cbcSMatt Macy 	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
243eda14cbcSMatt Macy 	    (uint64_t **)&vs, &vsc) == 0);
244eda14cbcSMatt Macy 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
245eda14cbcSMatt Macy 	    &stateval) == 0);
246eda14cbcSMatt Macy 
247eda14cbcSMatt Macy 	/*
248eda14cbcSMatt Macy 	 * Currently resilvering a vdev
249eda14cbcSMatt Macy 	 */
250eda14cbcSMatt Macy 	(void) nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_SCAN_STATS,
251eda14cbcSMatt Macy 	    (uint64_t **)&ps, &psc);
252eda14cbcSMatt Macy 	if (ps != NULL && ps->pss_func == POOL_SCAN_RESILVER &&
253eda14cbcSMatt Macy 	    ps->pss_state == DSS_SCANNING)
254eda14cbcSMatt Macy 		return (ZPOOL_STATUS_RESILVERING);
255eda14cbcSMatt Macy 
256eda14cbcSMatt Macy 	/*
257eda14cbcSMatt Macy 	 * Currently rebuilding a vdev, check top-level vdevs.
258eda14cbcSMatt Macy 	 */
259eda14cbcSMatt Macy 	vdev_rebuild_stat_t *vrs = NULL;
260eda14cbcSMatt Macy 	nvlist_t **child;
261eda14cbcSMatt Macy 	uint_t c, i, children;
262eda14cbcSMatt Macy 	uint64_t rebuild_end_time = 0;
263eda14cbcSMatt Macy 	if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
264eda14cbcSMatt Macy 	    &child, &children) == 0) {
265eda14cbcSMatt Macy 		for (c = 0; c < children; c++) {
266eda14cbcSMatt Macy 			if ((nvlist_lookup_uint64_array(child[c],
267eda14cbcSMatt Macy 			    ZPOOL_CONFIG_REBUILD_STATS,
268eda14cbcSMatt Macy 			    (uint64_t **)&vrs, &i) == 0) && (vrs != NULL)) {
269eda14cbcSMatt Macy 				uint64_t state = vrs->vrs_state;
270eda14cbcSMatt Macy 
271eda14cbcSMatt Macy 				if (state == VDEV_REBUILD_ACTIVE) {
272eda14cbcSMatt Macy 					return (ZPOOL_STATUS_REBUILDING);
273eda14cbcSMatt Macy 				} else if (state == VDEV_REBUILD_COMPLETE &&
274eda14cbcSMatt Macy 				    vrs->vrs_end_time > rebuild_end_time) {
275eda14cbcSMatt Macy 					rebuild_end_time = vrs->vrs_end_time;
276eda14cbcSMatt Macy 				}
277eda14cbcSMatt Macy 			}
278eda14cbcSMatt Macy 		}
279eda14cbcSMatt Macy 
280eda14cbcSMatt Macy 		/*
281eda14cbcSMatt Macy 		 * If we can determine when the last scrub was run, and it
282eda14cbcSMatt Macy 		 * was before the last rebuild completed, then recommend
283eda14cbcSMatt Macy 		 * that the pool be scrubbed to verify all checksums.  When
284eda14cbcSMatt Macy 		 * ps is NULL we can infer the pool has never been scrubbed.
285eda14cbcSMatt Macy 		 */
286eda14cbcSMatt Macy 		if (rebuild_end_time > 0) {
287eda14cbcSMatt Macy 			if (ps != NULL) {
288eda14cbcSMatt Macy 				if ((ps->pss_state == DSS_FINISHED &&
289eda14cbcSMatt Macy 				    ps->pss_func == POOL_SCAN_SCRUB &&
290eda14cbcSMatt Macy 				    rebuild_end_time > ps->pss_end_time) ||
291eda14cbcSMatt Macy 				    ps->pss_state == DSS_NONE)
292eda14cbcSMatt Macy 					return (ZPOOL_STATUS_REBUILD_SCRUB);
293eda14cbcSMatt Macy 			} else {
294eda14cbcSMatt Macy 				return (ZPOOL_STATUS_REBUILD_SCRUB);
295eda14cbcSMatt Macy 			}
296eda14cbcSMatt Macy 		}
297eda14cbcSMatt Macy 	}
298eda14cbcSMatt Macy 
299eda14cbcSMatt Macy 	/*
300eda14cbcSMatt Macy 	 * The multihost property is set and the pool may be active.
301eda14cbcSMatt Macy 	 */
302eda14cbcSMatt Macy 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
303eda14cbcSMatt Macy 	    vs->vs_aux == VDEV_AUX_ACTIVE) {
304eda14cbcSMatt Macy 		mmp_state_t mmp_state;
305eda14cbcSMatt Macy 		nvlist_t *nvinfo;
306eda14cbcSMatt Macy 
307eda14cbcSMatt Macy 		nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
308eda14cbcSMatt Macy 		mmp_state = fnvlist_lookup_uint64(nvinfo,
309eda14cbcSMatt Macy 		    ZPOOL_CONFIG_MMP_STATE);
310eda14cbcSMatt Macy 
311eda14cbcSMatt Macy 		if (mmp_state == MMP_STATE_ACTIVE)
312eda14cbcSMatt Macy 			return (ZPOOL_STATUS_HOSTID_ACTIVE);
313eda14cbcSMatt Macy 		else if (mmp_state == MMP_STATE_NO_HOSTID)
314eda14cbcSMatt Macy 			return (ZPOOL_STATUS_HOSTID_REQUIRED);
315eda14cbcSMatt Macy 		else
316eda14cbcSMatt Macy 			return (ZPOOL_STATUS_HOSTID_MISMATCH);
317eda14cbcSMatt Macy 	}
318eda14cbcSMatt Macy 
319eda14cbcSMatt Macy 	/*
320eda14cbcSMatt Macy 	 * Pool last accessed by another system.
321eda14cbcSMatt Macy 	 */
322eda14cbcSMatt Macy 	(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
323eda14cbcSMatt Macy 	if (hostid != 0 && (unsigned long)hostid != system_hostid &&
324eda14cbcSMatt Macy 	    stateval == POOL_STATE_ACTIVE)
325eda14cbcSMatt Macy 		return (ZPOOL_STATUS_HOSTID_MISMATCH);
326eda14cbcSMatt Macy 
327eda14cbcSMatt Macy 	/*
328eda14cbcSMatt Macy 	 * Newer on-disk version.
329eda14cbcSMatt Macy 	 */
330eda14cbcSMatt Macy 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
331eda14cbcSMatt Macy 	    vs->vs_aux == VDEV_AUX_VERSION_NEWER)
332eda14cbcSMatt Macy 		return (ZPOOL_STATUS_VERSION_NEWER);
333eda14cbcSMatt Macy 
334eda14cbcSMatt Macy 	/*
335eda14cbcSMatt Macy 	 * Unsupported feature(s).
336eda14cbcSMatt Macy 	 */
337eda14cbcSMatt Macy 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
338eda14cbcSMatt Macy 	    vs->vs_aux == VDEV_AUX_UNSUP_FEAT) {
339eda14cbcSMatt Macy 		nvlist_t *nvinfo;
340eda14cbcSMatt Macy 
341eda14cbcSMatt Macy 		verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO,
342eda14cbcSMatt Macy 		    &nvinfo) == 0);
343eda14cbcSMatt Macy 		if (nvlist_exists(nvinfo, ZPOOL_CONFIG_CAN_RDONLY))
344eda14cbcSMatt Macy 			return (ZPOOL_STATUS_UNSUP_FEAT_WRITE);
345eda14cbcSMatt Macy 		return (ZPOOL_STATUS_UNSUP_FEAT_READ);
346eda14cbcSMatt Macy 	}
347eda14cbcSMatt Macy 
348eda14cbcSMatt Macy 	/*
349eda14cbcSMatt Macy 	 * Check that the config is complete.
350eda14cbcSMatt Macy 	 */
351eda14cbcSMatt Macy 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
352eda14cbcSMatt Macy 	    vs->vs_aux == VDEV_AUX_BAD_GUID_SUM)
353eda14cbcSMatt Macy 		return (ZPOOL_STATUS_BAD_GUID_SUM);
354eda14cbcSMatt Macy 
355eda14cbcSMatt Macy 	/*
356eda14cbcSMatt Macy 	 * Check whether the pool has suspended.
357eda14cbcSMatt Macy 	 */
358eda14cbcSMatt Macy 	if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED,
359eda14cbcSMatt Macy 	    &suspended) == 0) {
360eda14cbcSMatt Macy 		uint64_t reason;
361eda14cbcSMatt Macy 
362eda14cbcSMatt Macy 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED_REASON,
363eda14cbcSMatt Macy 		    &reason) == 0 && reason == ZIO_SUSPEND_MMP)
364eda14cbcSMatt Macy 			return (ZPOOL_STATUS_IO_FAILURE_MMP);
365eda14cbcSMatt Macy 
366eda14cbcSMatt Macy 		if (suspended == ZIO_FAILURE_MODE_CONTINUE)
367eda14cbcSMatt Macy 			return (ZPOOL_STATUS_IO_FAILURE_CONTINUE);
368eda14cbcSMatt Macy 		return (ZPOOL_STATUS_IO_FAILURE_WAIT);
369eda14cbcSMatt Macy 	}
370eda14cbcSMatt Macy 
371eda14cbcSMatt Macy 	/*
372eda14cbcSMatt Macy 	 * Could not read a log.
373eda14cbcSMatt Macy 	 */
374eda14cbcSMatt Macy 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
375eda14cbcSMatt Macy 	    vs->vs_aux == VDEV_AUX_BAD_LOG) {
376eda14cbcSMatt Macy 		return (ZPOOL_STATUS_BAD_LOG);
377eda14cbcSMatt Macy 	}
378eda14cbcSMatt Macy 
379eda14cbcSMatt Macy 	/*
380eda14cbcSMatt Macy 	 * Bad devices in non-replicated config.
381eda14cbcSMatt Macy 	 */
382eda14cbcSMatt Macy 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
383eda14cbcSMatt Macy 	    find_vdev_problem(nvroot, vdev_faulted, B_TRUE))
384eda14cbcSMatt Macy 		return (ZPOOL_STATUS_FAULTED_DEV_NR);
385eda14cbcSMatt Macy 
386eda14cbcSMatt Macy 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
387eda14cbcSMatt Macy 	    find_vdev_problem(nvroot, vdev_missing, B_TRUE))
388eda14cbcSMatt Macy 		return (ZPOOL_STATUS_MISSING_DEV_NR);
389eda14cbcSMatt Macy 
390eda14cbcSMatt Macy 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
391eda14cbcSMatt Macy 	    find_vdev_problem(nvroot, vdev_broken, B_TRUE))
392eda14cbcSMatt Macy 		return (ZPOOL_STATUS_CORRUPT_LABEL_NR);
393eda14cbcSMatt Macy 
394eda14cbcSMatt Macy 	/*
395eda14cbcSMatt Macy 	 * Corrupted pool metadata
396eda14cbcSMatt Macy 	 */
397eda14cbcSMatt Macy 	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
398eda14cbcSMatt Macy 	    vs->vs_aux == VDEV_AUX_CORRUPT_DATA)
399eda14cbcSMatt Macy 		return (ZPOOL_STATUS_CORRUPT_POOL);
400eda14cbcSMatt Macy 
401eda14cbcSMatt Macy 	/*
402eda14cbcSMatt Macy 	 * Persistent data errors.
403eda14cbcSMatt Macy 	 */
404eda14cbcSMatt Macy 	if (!isimport) {
405eda14cbcSMatt Macy 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
406eda14cbcSMatt Macy 		    &nerr) == 0 && nerr != 0)
407eda14cbcSMatt Macy 			return (ZPOOL_STATUS_CORRUPT_DATA);
408eda14cbcSMatt Macy 	}
409eda14cbcSMatt Macy 
410eda14cbcSMatt Macy 	/*
411eda14cbcSMatt Macy 	 * Missing devices in a replicated config.
412eda14cbcSMatt Macy 	 */
413eda14cbcSMatt Macy 	if (find_vdev_problem(nvroot, vdev_faulted, B_TRUE))
414eda14cbcSMatt Macy 		return (ZPOOL_STATUS_FAULTED_DEV_R);
415eda14cbcSMatt Macy 	if (find_vdev_problem(nvroot, vdev_missing, B_TRUE))
416eda14cbcSMatt Macy 		return (ZPOOL_STATUS_MISSING_DEV_R);
417eda14cbcSMatt Macy 	if (find_vdev_problem(nvroot, vdev_broken, B_TRUE))
418eda14cbcSMatt Macy 		return (ZPOOL_STATUS_CORRUPT_LABEL_R);
419eda14cbcSMatt Macy 
420eda14cbcSMatt Macy 	/*
421eda14cbcSMatt Macy 	 * Devices with errors
422eda14cbcSMatt Macy 	 */
423eda14cbcSMatt Macy 	if (!isimport && find_vdev_problem(nvroot, vdev_errors, B_TRUE))
424eda14cbcSMatt Macy 		return (ZPOOL_STATUS_FAILING_DEV);
425eda14cbcSMatt Macy 
426eda14cbcSMatt Macy 	/*
427eda14cbcSMatt Macy 	 * Offlined devices
428eda14cbcSMatt Macy 	 */
429eda14cbcSMatt Macy 	if (find_vdev_problem(nvroot, vdev_offlined, B_TRUE))
430eda14cbcSMatt Macy 		return (ZPOOL_STATUS_OFFLINE_DEV);
431eda14cbcSMatt Macy 
432eda14cbcSMatt Macy 	/*
433eda14cbcSMatt Macy 	 * Removed device
434eda14cbcSMatt Macy 	 */
435eda14cbcSMatt Macy 	if (find_vdev_problem(nvroot, vdev_removed, B_TRUE))
436eda14cbcSMatt Macy 		return (ZPOOL_STATUS_REMOVED_DEV);
437eda14cbcSMatt Macy 
438eda14cbcSMatt Macy 	/*
439eda14cbcSMatt Macy 	 * Suboptimal, but usable, ashift configuration.
440eda14cbcSMatt Macy 	 */
441eda14cbcSMatt Macy 	if (find_vdev_problem(nvroot, vdev_non_native_ashift, B_FALSE))
442eda14cbcSMatt Macy 		return (ZPOOL_STATUS_NON_NATIVE_ASHIFT);
443eda14cbcSMatt Macy 
444eda14cbcSMatt Macy 	/*
445eda14cbcSMatt Macy 	 * Informational errata available.
446eda14cbcSMatt Macy 	 */
447eda14cbcSMatt Macy 	(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRATA, &errata);
448eda14cbcSMatt Macy 	if (errata) {
449eda14cbcSMatt Macy 		*erratap = errata;
450eda14cbcSMatt Macy 		return (ZPOOL_STATUS_ERRATA);
451eda14cbcSMatt Macy 	}
452eda14cbcSMatt Macy 
453eda14cbcSMatt Macy 	/*
454eda14cbcSMatt Macy 	 * Outdated, but usable, version
455eda14cbcSMatt Macy 	 */
456eda14cbcSMatt Macy 	if (SPA_VERSION_IS_SUPPORTED(version) && version != SPA_VERSION)
457eda14cbcSMatt Macy 		return (ZPOOL_STATUS_VERSION_OLDER);
458eda14cbcSMatt Macy 
459eda14cbcSMatt Macy 	/*
460eda14cbcSMatt Macy 	 * Usable pool with disabled features
461eda14cbcSMatt Macy 	 */
462eda14cbcSMatt Macy 	if (version >= SPA_VERSION_FEATURES) {
463eda14cbcSMatt Macy 		int i;
464eda14cbcSMatt Macy 		nvlist_t *feat;
465eda14cbcSMatt Macy 
466eda14cbcSMatt Macy 		if (isimport) {
467eda14cbcSMatt Macy 			feat = fnvlist_lookup_nvlist(config,
468eda14cbcSMatt Macy 			    ZPOOL_CONFIG_LOAD_INFO);
469eda14cbcSMatt Macy 			if (nvlist_exists(feat, ZPOOL_CONFIG_ENABLED_FEAT))
470eda14cbcSMatt Macy 				feat = fnvlist_lookup_nvlist(feat,
471eda14cbcSMatt Macy 				    ZPOOL_CONFIG_ENABLED_FEAT);
472eda14cbcSMatt Macy 		} else {
473eda14cbcSMatt Macy 			feat = fnvlist_lookup_nvlist(config,
474eda14cbcSMatt Macy 			    ZPOOL_CONFIG_FEATURE_STATS);
475eda14cbcSMatt Macy 		}
476eda14cbcSMatt Macy 
477ee36e25aSMartin Matuska 		/* check against all features, or limited set? */
478ee36e25aSMartin Matuska 		boolean_t pool_features[SPA_FEATURES];
479ee36e25aSMartin Matuska 
480ee36e25aSMartin Matuska 		if (zpool_load_compat(compat, pool_features, NULL, NULL) !=
481ee36e25aSMartin Matuska 		    ZPOOL_COMPATIBILITY_OK)
482ee36e25aSMartin Matuska 			return (ZPOOL_STATUS_COMPATIBILITY_ERR);
483eda14cbcSMatt Macy 		for (i = 0; i < SPA_FEATURES; i++) {
484eda14cbcSMatt Macy 			zfeature_info_t *fi = &spa_feature_table[i];
485*c170aa9fSMartin Matuska 			if (!fi->fi_zfs_mod_supported)
486*c170aa9fSMartin Matuska 				continue;
487ee36e25aSMartin Matuska 			if (pool_features[i] &&
488ee36e25aSMartin Matuska 			    !nvlist_exists(feat, fi->fi_guid))
489eda14cbcSMatt Macy 				return (ZPOOL_STATUS_FEAT_DISABLED);
490eda14cbcSMatt Macy 		}
491eda14cbcSMatt Macy 	}
492eda14cbcSMatt Macy 
493eda14cbcSMatt Macy 	return (ZPOOL_STATUS_OK);
494eda14cbcSMatt Macy }
495eda14cbcSMatt Macy 
496eda14cbcSMatt Macy zpool_status_t
497eda14cbcSMatt Macy zpool_get_status(zpool_handle_t *zhp, char **msgid, zpool_errata_t *errata)
498eda14cbcSMatt Macy {
499ee36e25aSMartin Matuska 	/*
500ee36e25aSMartin Matuska 	 * pass in the desired feature set, as
501ee36e25aSMartin Matuska 	 * it affects check for disabled features
502ee36e25aSMartin Matuska 	 */
503ee36e25aSMartin Matuska 	char compatibility[ZFS_MAXPROPLEN];
504ee36e25aSMartin Matuska 	if (zpool_get_prop(zhp, ZPOOL_PROP_COMPATIBILITY, compatibility,
505ee36e25aSMartin Matuska 	    ZFS_MAXPROPLEN, NULL, B_FALSE) != 0)
506ee36e25aSMartin Matuska 		compatibility[0] = '\0';
507ee36e25aSMartin Matuska 
508ee36e25aSMartin Matuska 	zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata,
509ee36e25aSMartin Matuska 	    compatibility);
510ee36e25aSMartin Matuska 
511eda14cbcSMatt Macy 	if (msgid != NULL) {
512eda14cbcSMatt Macy 		if (ret >= NMSGID)
513eda14cbcSMatt Macy 			*msgid = NULL;
514eda14cbcSMatt Macy 		else
515eda14cbcSMatt Macy 			*msgid = zfs_msgid_table[ret];
516eda14cbcSMatt Macy 	}
517eda14cbcSMatt Macy 	return (ret);
518eda14cbcSMatt Macy }
519eda14cbcSMatt Macy 
520eda14cbcSMatt Macy zpool_status_t
521eda14cbcSMatt Macy zpool_import_status(nvlist_t *config, char **msgid, zpool_errata_t *errata)
522eda14cbcSMatt Macy {
523ee36e25aSMartin Matuska 	zpool_status_t ret = check_status(config, B_TRUE, errata, NULL);
524eda14cbcSMatt Macy 
525eda14cbcSMatt Macy 	if (ret >= NMSGID)
526eda14cbcSMatt Macy 		*msgid = NULL;
527eda14cbcSMatt Macy 	else
528eda14cbcSMatt Macy 		*msgid = zfs_msgid_table[ret];
529eda14cbcSMatt Macy 
530eda14cbcSMatt Macy 	return (ret);
531eda14cbcSMatt Macy }
532