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
9271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
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 */
59a0b956f5SMartin Matuska static const char *const 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
9216038816SMartin Matuska * ZPOOL_STATUS_INCOMPATIBLE_FEAT
93eda14cbcSMatt Macy * ZPOOL_STATUS_OK
94eda14cbcSMatt Macy */
95eda14cbcSMatt Macy };
96eda14cbcSMatt Macy
97eda14cbcSMatt Macy #define NMSGID (sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
98eda14cbcSMatt Macy
99eda14cbcSMatt Macy static int
vdev_missing(vdev_stat_t * vs,uint_t vsc)100eda14cbcSMatt Macy vdev_missing(vdev_stat_t *vs, uint_t vsc)
101eda14cbcSMatt Macy {
102e92ffd9bSMartin Matuska (void) vsc;
103eda14cbcSMatt Macy return (vs->vs_state == VDEV_STATE_CANT_OPEN &&
104eda14cbcSMatt Macy vs->vs_aux == VDEV_AUX_OPEN_FAILED);
105eda14cbcSMatt Macy }
106eda14cbcSMatt Macy
107eda14cbcSMatt Macy static int
vdev_faulted(vdev_stat_t * vs,uint_t vsc)108eda14cbcSMatt Macy vdev_faulted(vdev_stat_t *vs, uint_t vsc)
109eda14cbcSMatt Macy {
110e92ffd9bSMartin Matuska (void) vsc;
111eda14cbcSMatt Macy return (vs->vs_state == VDEV_STATE_FAULTED);
112eda14cbcSMatt Macy }
113eda14cbcSMatt Macy
114eda14cbcSMatt Macy static int
vdev_errors(vdev_stat_t * vs,uint_t vsc)115eda14cbcSMatt Macy vdev_errors(vdev_stat_t *vs, uint_t vsc)
116eda14cbcSMatt Macy {
117e92ffd9bSMartin Matuska (void) vsc;
118eda14cbcSMatt Macy return (vs->vs_state == VDEV_STATE_DEGRADED ||
119eda14cbcSMatt Macy vs->vs_read_errors != 0 || vs->vs_write_errors != 0 ||
120eda14cbcSMatt Macy vs->vs_checksum_errors != 0);
121eda14cbcSMatt Macy }
122eda14cbcSMatt Macy
123eda14cbcSMatt Macy static int
vdev_broken(vdev_stat_t * vs,uint_t vsc)124eda14cbcSMatt Macy vdev_broken(vdev_stat_t *vs, uint_t vsc)
125eda14cbcSMatt Macy {
126e92ffd9bSMartin Matuska (void) vsc;
127eda14cbcSMatt Macy return (vs->vs_state == VDEV_STATE_CANT_OPEN);
128eda14cbcSMatt Macy }
129eda14cbcSMatt Macy
130eda14cbcSMatt Macy static int
vdev_offlined(vdev_stat_t * vs,uint_t vsc)131eda14cbcSMatt Macy vdev_offlined(vdev_stat_t *vs, uint_t vsc)
132eda14cbcSMatt Macy {
133e92ffd9bSMartin Matuska (void) vsc;
134eda14cbcSMatt Macy return (vs->vs_state == VDEV_STATE_OFFLINE);
135eda14cbcSMatt Macy }
136eda14cbcSMatt Macy
137eda14cbcSMatt Macy static int
vdev_removed(vdev_stat_t * vs,uint_t vsc)138eda14cbcSMatt Macy vdev_removed(vdev_stat_t *vs, uint_t vsc)
139eda14cbcSMatt Macy {
140e92ffd9bSMartin Matuska (void) vsc;
141eda14cbcSMatt Macy return (vs->vs_state == VDEV_STATE_REMOVED);
142eda14cbcSMatt Macy }
143eda14cbcSMatt Macy
144eda14cbcSMatt Macy static int
vdev_non_native_ashift(vdev_stat_t * vs,uint_t vsc)145eda14cbcSMatt Macy vdev_non_native_ashift(vdev_stat_t *vs, uint_t vsc)
146eda14cbcSMatt Macy {
147eda14cbcSMatt Macy if (getenv("ZPOOL_STATUS_NON_NATIVE_ASHIFT_IGNORE") != NULL)
148eda14cbcSMatt Macy return (0);
149eda14cbcSMatt Macy
150eda14cbcSMatt Macy return (VDEV_STAT_VALID(vs_physical_ashift, vsc) &&
151eda14cbcSMatt Macy vs->vs_configured_ashift < vs->vs_physical_ashift);
152eda14cbcSMatt Macy }
153eda14cbcSMatt Macy
154eda14cbcSMatt Macy /*
155eda14cbcSMatt Macy * Detect if any leaf devices that have seen errors or could not be opened.
156eda14cbcSMatt Macy */
157eda14cbcSMatt Macy static boolean_t
find_vdev_problem(nvlist_t * vdev,int (* func)(vdev_stat_t *,uint_t),boolean_t ignore_replacing)158eda14cbcSMatt Macy find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t),
159eda14cbcSMatt Macy boolean_t ignore_replacing)
160eda14cbcSMatt Macy {
161eda14cbcSMatt Macy nvlist_t **child;
162da5137abSMartin Matuska uint_t c, 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) {
171*2a58b312SMartin Matuska const char *type = fnvlist_lookup_string(vdev,
172*2a58b312SMartin Matuska ZPOOL_CONFIG_TYPE);
173eda14cbcSMatt Macy if (strcmp(type, VDEV_TYPE_REPLACING) == 0)
174eda14cbcSMatt Macy return (B_FALSE);
175eda14cbcSMatt Macy }
176eda14cbcSMatt Macy
177eda14cbcSMatt Macy if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
178eda14cbcSMatt Macy &children) == 0) {
179eda14cbcSMatt Macy for (c = 0; c < children; c++)
180eda14cbcSMatt Macy if (find_vdev_problem(child[c], func, ignore_replacing))
181eda14cbcSMatt Macy return (B_TRUE);
182eda14cbcSMatt Macy } else {
183da5137abSMartin Matuska uint_t vsc;
184da5137abSMartin Matuska vdev_stat_t *vs = (vdev_stat_t *)fnvlist_lookup_uint64_array(
185da5137abSMartin Matuska vdev, ZPOOL_CONFIG_VDEV_STATS, &vsc);
186eda14cbcSMatt Macy if (func(vs, vsc) != 0)
187eda14cbcSMatt Macy return (B_TRUE);
188eda14cbcSMatt Macy }
189eda14cbcSMatt Macy
190eda14cbcSMatt Macy /*
191eda14cbcSMatt Macy * Check any L2 cache devs
192eda14cbcSMatt Macy */
193eda14cbcSMatt Macy if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_L2CACHE, &child,
194eda14cbcSMatt Macy &children) == 0) {
195eda14cbcSMatt Macy for (c = 0; c < children; c++)
196eda14cbcSMatt Macy if (find_vdev_problem(child[c], func, ignore_replacing))
197eda14cbcSMatt Macy return (B_TRUE);
198eda14cbcSMatt Macy }
199eda14cbcSMatt Macy
200eda14cbcSMatt Macy return (B_FALSE);
201eda14cbcSMatt Macy }
202eda14cbcSMatt Macy
203eda14cbcSMatt Macy /*
204eda14cbcSMatt Macy * Active pool health status.
205eda14cbcSMatt Macy *
206eda14cbcSMatt Macy * To determine the status for a pool, we make several passes over the config,
207eda14cbcSMatt Macy * picking the most egregious error we find. In order of importance, we do the
208eda14cbcSMatt Macy * following:
209eda14cbcSMatt Macy *
210eda14cbcSMatt Macy * - Check for a complete and valid configuration
211eda14cbcSMatt Macy * - Look for any faulted or missing devices in a non-replicated config
212eda14cbcSMatt Macy * - Check for any data errors
213eda14cbcSMatt Macy * - Check for any faulted or missing devices in a replicated config
214eda14cbcSMatt Macy * - Look for any devices showing errors
215eda14cbcSMatt Macy * - Check for any resilvering or rebuilding devices
216eda14cbcSMatt Macy *
217eda14cbcSMatt Macy * There can obviously be multiple errors within a single pool, so this routine
218eda14cbcSMatt Macy * only picks the most damaging of all the current errors to report.
219eda14cbcSMatt Macy */
220eda14cbcSMatt Macy static zpool_status_t
check_status(nvlist_t * config,boolean_t isimport,zpool_errata_t * erratap,const char * compat)221ee36e25aSMartin Matuska check_status(nvlist_t *config, boolean_t isimport,
222ee36e25aSMartin Matuska zpool_errata_t *erratap, const char *compat)
223eda14cbcSMatt Macy {
224eda14cbcSMatt Macy pool_scan_stat_t *ps = NULL;
225eda14cbcSMatt Macy uint_t vsc, psc;
226eda14cbcSMatt Macy uint64_t suspended;
227eda14cbcSMatt Macy uint64_t hostid = 0;
228eda14cbcSMatt Macy uint64_t errata = 0;
229eda14cbcSMatt Macy unsigned long system_hostid = get_system_hostid();
230eda14cbcSMatt Macy
231da5137abSMartin Matuska uint64_t version = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION);
232da5137abSMartin Matuska nvlist_t *nvroot = fnvlist_lookup_nvlist(config,
233da5137abSMartin Matuska ZPOOL_CONFIG_VDEV_TREE);
234da5137abSMartin Matuska vdev_stat_t *vs = (vdev_stat_t *)fnvlist_lookup_uint64_array(nvroot,
235da5137abSMartin Matuska ZPOOL_CONFIG_VDEV_STATS, &vsc);
236da5137abSMartin Matuska uint64_t stateval = fnvlist_lookup_uint64(config,
237da5137abSMartin Matuska ZPOOL_CONFIG_POOL_STATE);
238eda14cbcSMatt Macy
239eda14cbcSMatt Macy /*
240eda14cbcSMatt Macy * Currently resilvering a vdev
241eda14cbcSMatt Macy */
242eda14cbcSMatt Macy (void) nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_SCAN_STATS,
243eda14cbcSMatt Macy (uint64_t **)&ps, &psc);
244eda14cbcSMatt Macy if (ps != NULL && ps->pss_func == POOL_SCAN_RESILVER &&
245eda14cbcSMatt Macy ps->pss_state == DSS_SCANNING)
246eda14cbcSMatt Macy return (ZPOOL_STATUS_RESILVERING);
247eda14cbcSMatt Macy
248eda14cbcSMatt Macy /*
249eda14cbcSMatt Macy * Currently rebuilding a vdev, check top-level vdevs.
250eda14cbcSMatt Macy */
251eda14cbcSMatt Macy vdev_rebuild_stat_t *vrs = NULL;
252eda14cbcSMatt Macy nvlist_t **child;
253eda14cbcSMatt Macy uint_t c, i, children;
254eda14cbcSMatt Macy uint64_t rebuild_end_time = 0;
255eda14cbcSMatt Macy if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
256eda14cbcSMatt Macy &child, &children) == 0) {
257eda14cbcSMatt Macy for (c = 0; c < children; c++) {
258eda14cbcSMatt Macy if ((nvlist_lookup_uint64_array(child[c],
259eda14cbcSMatt Macy ZPOOL_CONFIG_REBUILD_STATS,
260eda14cbcSMatt Macy (uint64_t **)&vrs, &i) == 0) && (vrs != NULL)) {
261eda14cbcSMatt Macy uint64_t state = vrs->vrs_state;
262eda14cbcSMatt Macy
263eda14cbcSMatt Macy if (state == VDEV_REBUILD_ACTIVE) {
264eda14cbcSMatt Macy return (ZPOOL_STATUS_REBUILDING);
265eda14cbcSMatt Macy } else if (state == VDEV_REBUILD_COMPLETE &&
266eda14cbcSMatt Macy vrs->vrs_end_time > rebuild_end_time) {
267eda14cbcSMatt Macy rebuild_end_time = vrs->vrs_end_time;
268eda14cbcSMatt Macy }
269eda14cbcSMatt Macy }
270eda14cbcSMatt Macy }
271eda14cbcSMatt Macy
272eda14cbcSMatt Macy /*
273eda14cbcSMatt Macy * If we can determine when the last scrub was run, and it
274eda14cbcSMatt Macy * was before the last rebuild completed, then recommend
275eda14cbcSMatt Macy * that the pool be scrubbed to verify all checksums. When
276eda14cbcSMatt Macy * ps is NULL we can infer the pool has never been scrubbed.
277eda14cbcSMatt Macy */
278eda14cbcSMatt Macy if (rebuild_end_time > 0) {
279eda14cbcSMatt Macy if (ps != NULL) {
280eda14cbcSMatt Macy if ((ps->pss_state == DSS_FINISHED &&
281eda14cbcSMatt Macy ps->pss_func == POOL_SCAN_SCRUB &&
282eda14cbcSMatt Macy rebuild_end_time > ps->pss_end_time) ||
283eda14cbcSMatt Macy ps->pss_state == DSS_NONE)
284eda14cbcSMatt Macy return (ZPOOL_STATUS_REBUILD_SCRUB);
285eda14cbcSMatt Macy } else {
286eda14cbcSMatt Macy return (ZPOOL_STATUS_REBUILD_SCRUB);
287eda14cbcSMatt Macy }
288eda14cbcSMatt Macy }
289eda14cbcSMatt Macy }
290eda14cbcSMatt Macy
291eda14cbcSMatt Macy /*
292eda14cbcSMatt Macy * The multihost property is set and the pool may be active.
293eda14cbcSMatt Macy */
294eda14cbcSMatt Macy if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
295eda14cbcSMatt Macy vs->vs_aux == VDEV_AUX_ACTIVE) {
296eda14cbcSMatt Macy mmp_state_t mmp_state;
297eda14cbcSMatt Macy nvlist_t *nvinfo;
298eda14cbcSMatt Macy
299eda14cbcSMatt Macy nvinfo = fnvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO);
300eda14cbcSMatt Macy mmp_state = fnvlist_lookup_uint64(nvinfo,
301eda14cbcSMatt Macy ZPOOL_CONFIG_MMP_STATE);
302eda14cbcSMatt Macy
303eda14cbcSMatt Macy if (mmp_state == MMP_STATE_ACTIVE)
304eda14cbcSMatt Macy return (ZPOOL_STATUS_HOSTID_ACTIVE);
305eda14cbcSMatt Macy else if (mmp_state == MMP_STATE_NO_HOSTID)
306eda14cbcSMatt Macy return (ZPOOL_STATUS_HOSTID_REQUIRED);
307eda14cbcSMatt Macy else
308eda14cbcSMatt Macy return (ZPOOL_STATUS_HOSTID_MISMATCH);
309eda14cbcSMatt Macy }
310eda14cbcSMatt Macy
311eda14cbcSMatt Macy /*
312eda14cbcSMatt Macy * Pool last accessed by another system.
313eda14cbcSMatt Macy */
314eda14cbcSMatt Macy (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
315eda14cbcSMatt Macy if (hostid != 0 && (unsigned long)hostid != system_hostid &&
316eda14cbcSMatt Macy stateval == POOL_STATE_ACTIVE)
317eda14cbcSMatt Macy return (ZPOOL_STATUS_HOSTID_MISMATCH);
318eda14cbcSMatt Macy
319eda14cbcSMatt Macy /*
320eda14cbcSMatt Macy * Newer on-disk version.
321eda14cbcSMatt Macy */
322eda14cbcSMatt Macy if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
323eda14cbcSMatt Macy vs->vs_aux == VDEV_AUX_VERSION_NEWER)
324eda14cbcSMatt Macy return (ZPOOL_STATUS_VERSION_NEWER);
325eda14cbcSMatt Macy
326eda14cbcSMatt Macy /*
327eda14cbcSMatt Macy * Unsupported feature(s).
328eda14cbcSMatt Macy */
329eda14cbcSMatt Macy if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
330eda14cbcSMatt Macy vs->vs_aux == VDEV_AUX_UNSUP_FEAT) {
331da5137abSMartin Matuska nvlist_t *nvinfo = fnvlist_lookup_nvlist(config,
332da5137abSMartin Matuska ZPOOL_CONFIG_LOAD_INFO);
333eda14cbcSMatt Macy if (nvlist_exists(nvinfo, ZPOOL_CONFIG_CAN_RDONLY))
334eda14cbcSMatt Macy return (ZPOOL_STATUS_UNSUP_FEAT_WRITE);
335eda14cbcSMatt Macy return (ZPOOL_STATUS_UNSUP_FEAT_READ);
336eda14cbcSMatt Macy }
337eda14cbcSMatt Macy
338eda14cbcSMatt Macy /*
339eda14cbcSMatt Macy * Check that the config is complete.
340eda14cbcSMatt Macy */
341eda14cbcSMatt Macy if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
342eda14cbcSMatt Macy vs->vs_aux == VDEV_AUX_BAD_GUID_SUM)
343eda14cbcSMatt Macy return (ZPOOL_STATUS_BAD_GUID_SUM);
344eda14cbcSMatt Macy
345eda14cbcSMatt Macy /*
346eda14cbcSMatt Macy * Check whether the pool has suspended.
347eda14cbcSMatt Macy */
348eda14cbcSMatt Macy if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED,
349eda14cbcSMatt Macy &suspended) == 0) {
350eda14cbcSMatt Macy uint64_t reason;
351eda14cbcSMatt Macy
352eda14cbcSMatt Macy if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED_REASON,
353eda14cbcSMatt Macy &reason) == 0 && reason == ZIO_SUSPEND_MMP)
354eda14cbcSMatt Macy return (ZPOOL_STATUS_IO_FAILURE_MMP);
355eda14cbcSMatt Macy
356eda14cbcSMatt Macy if (suspended == ZIO_FAILURE_MODE_CONTINUE)
357eda14cbcSMatt Macy return (ZPOOL_STATUS_IO_FAILURE_CONTINUE);
358eda14cbcSMatt Macy return (ZPOOL_STATUS_IO_FAILURE_WAIT);
359eda14cbcSMatt Macy }
360eda14cbcSMatt Macy
361eda14cbcSMatt Macy /*
362eda14cbcSMatt Macy * Could not read a log.
363eda14cbcSMatt Macy */
364eda14cbcSMatt Macy if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
365eda14cbcSMatt Macy vs->vs_aux == VDEV_AUX_BAD_LOG) {
366eda14cbcSMatt Macy return (ZPOOL_STATUS_BAD_LOG);
367eda14cbcSMatt Macy }
368eda14cbcSMatt Macy
369eda14cbcSMatt Macy /*
370eda14cbcSMatt Macy * Bad devices in non-replicated config.
371eda14cbcSMatt Macy */
372eda14cbcSMatt Macy if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
373eda14cbcSMatt Macy find_vdev_problem(nvroot, vdev_faulted, B_TRUE))
374eda14cbcSMatt Macy return (ZPOOL_STATUS_FAULTED_DEV_NR);
375eda14cbcSMatt Macy
376eda14cbcSMatt Macy if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
377eda14cbcSMatt Macy find_vdev_problem(nvroot, vdev_missing, B_TRUE))
378eda14cbcSMatt Macy return (ZPOOL_STATUS_MISSING_DEV_NR);
379eda14cbcSMatt Macy
380eda14cbcSMatt Macy if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
381eda14cbcSMatt Macy find_vdev_problem(nvroot, vdev_broken, B_TRUE))
382eda14cbcSMatt Macy return (ZPOOL_STATUS_CORRUPT_LABEL_NR);
383eda14cbcSMatt Macy
384eda14cbcSMatt Macy /*
385eda14cbcSMatt Macy * Corrupted pool metadata
386eda14cbcSMatt Macy */
387eda14cbcSMatt Macy if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
388eda14cbcSMatt Macy vs->vs_aux == VDEV_AUX_CORRUPT_DATA)
389eda14cbcSMatt Macy return (ZPOOL_STATUS_CORRUPT_POOL);
390eda14cbcSMatt Macy
391eda14cbcSMatt Macy /*
392eda14cbcSMatt Macy * Persistent data errors.
393eda14cbcSMatt Macy */
394eda14cbcSMatt Macy if (!isimport) {
39515f0b8c3SMartin Matuska uint64_t nerr;
396eda14cbcSMatt Macy if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
397eda14cbcSMatt Macy &nerr) == 0 && nerr != 0)
398eda14cbcSMatt Macy return (ZPOOL_STATUS_CORRUPT_DATA);
399eda14cbcSMatt Macy }
400eda14cbcSMatt Macy
401eda14cbcSMatt Macy /*
402eda14cbcSMatt Macy * Missing devices in a replicated config.
403eda14cbcSMatt Macy */
404eda14cbcSMatt Macy if (find_vdev_problem(nvroot, vdev_faulted, B_TRUE))
405eda14cbcSMatt Macy return (ZPOOL_STATUS_FAULTED_DEV_R);
406eda14cbcSMatt Macy if (find_vdev_problem(nvroot, vdev_missing, B_TRUE))
407eda14cbcSMatt Macy return (ZPOOL_STATUS_MISSING_DEV_R);
408eda14cbcSMatt Macy if (find_vdev_problem(nvroot, vdev_broken, B_TRUE))
409eda14cbcSMatt Macy return (ZPOOL_STATUS_CORRUPT_LABEL_R);
410eda14cbcSMatt Macy
411eda14cbcSMatt Macy /*
412eda14cbcSMatt Macy * Devices with errors
413eda14cbcSMatt Macy */
414eda14cbcSMatt Macy if (!isimport && find_vdev_problem(nvroot, vdev_errors, B_TRUE))
415eda14cbcSMatt Macy return (ZPOOL_STATUS_FAILING_DEV);
416eda14cbcSMatt Macy
417eda14cbcSMatt Macy /*
418eda14cbcSMatt Macy * Offlined devices
419eda14cbcSMatt Macy */
420eda14cbcSMatt Macy if (find_vdev_problem(nvroot, vdev_offlined, B_TRUE))
421eda14cbcSMatt Macy return (ZPOOL_STATUS_OFFLINE_DEV);
422eda14cbcSMatt Macy
423eda14cbcSMatt Macy /*
424eda14cbcSMatt Macy * Removed device
425eda14cbcSMatt Macy */
426eda14cbcSMatt Macy if (find_vdev_problem(nvroot, vdev_removed, B_TRUE))
427eda14cbcSMatt Macy return (ZPOOL_STATUS_REMOVED_DEV);
428eda14cbcSMatt Macy
429eda14cbcSMatt Macy /*
430eda14cbcSMatt Macy * Suboptimal, but usable, ashift configuration.
431eda14cbcSMatt Macy */
432eda14cbcSMatt Macy if (find_vdev_problem(nvroot, vdev_non_native_ashift, B_FALSE))
433eda14cbcSMatt Macy return (ZPOOL_STATUS_NON_NATIVE_ASHIFT);
434eda14cbcSMatt Macy
435eda14cbcSMatt Macy /*
436eda14cbcSMatt Macy * Informational errata available.
437eda14cbcSMatt Macy */
438eda14cbcSMatt Macy (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRATA, &errata);
439eda14cbcSMatt Macy if (errata) {
440eda14cbcSMatt Macy *erratap = errata;
441eda14cbcSMatt Macy return (ZPOOL_STATUS_ERRATA);
442eda14cbcSMatt Macy }
443eda14cbcSMatt Macy
444eda14cbcSMatt Macy /*
445eda14cbcSMatt Macy * Outdated, but usable, version
446eda14cbcSMatt Macy */
44716038816SMartin Matuska if (SPA_VERSION_IS_SUPPORTED(version) && version != SPA_VERSION) {
44816038816SMartin Matuska /* "legacy" compatibility disables old version reporting */
44916038816SMartin Matuska if (compat != NULL && strcmp(compat, ZPOOL_COMPAT_LEGACY) == 0)
45016038816SMartin Matuska return (ZPOOL_STATUS_OK);
45116038816SMartin Matuska else
452eda14cbcSMatt Macy return (ZPOOL_STATUS_VERSION_OLDER);
45316038816SMartin Matuska }
454eda14cbcSMatt Macy
455eda14cbcSMatt Macy /*
45616038816SMartin Matuska * Usable pool with disabled or superfluous features
45716038816SMartin Matuska * (superfluous = beyond what's requested by 'compatibility')
458eda14cbcSMatt Macy */
459eda14cbcSMatt Macy if (version >= SPA_VERSION_FEATURES) {
460eda14cbcSMatt Macy int i;
461eda14cbcSMatt Macy nvlist_t *feat;
462eda14cbcSMatt Macy
463eda14cbcSMatt Macy if (isimport) {
464eda14cbcSMatt Macy feat = fnvlist_lookup_nvlist(config,
465eda14cbcSMatt Macy ZPOOL_CONFIG_LOAD_INFO);
466eda14cbcSMatt Macy if (nvlist_exists(feat, ZPOOL_CONFIG_ENABLED_FEAT))
467eda14cbcSMatt Macy feat = fnvlist_lookup_nvlist(feat,
468eda14cbcSMatt Macy ZPOOL_CONFIG_ENABLED_FEAT);
469eda14cbcSMatt Macy } else {
470eda14cbcSMatt Macy feat = fnvlist_lookup_nvlist(config,
471eda14cbcSMatt Macy ZPOOL_CONFIG_FEATURE_STATS);
472eda14cbcSMatt Macy }
473eda14cbcSMatt Macy
474ee36e25aSMartin Matuska /* check against all features, or limited set? */
47516038816SMartin Matuska boolean_t c_features[SPA_FEATURES];
476ee36e25aSMartin Matuska
47716038816SMartin Matuska switch (zpool_load_compat(compat, c_features, NULL, 0)) {
47816038816SMartin Matuska case ZPOOL_COMPATIBILITY_OK:
47916038816SMartin Matuska case ZPOOL_COMPATIBILITY_WARNTOKEN:
48016038816SMartin Matuska break;
48116038816SMartin Matuska default:
482ee36e25aSMartin Matuska return (ZPOOL_STATUS_COMPATIBILITY_ERR);
48316038816SMartin Matuska }
484eda14cbcSMatt Macy for (i = 0; i < SPA_FEATURES; i++) {
485eda14cbcSMatt Macy zfeature_info_t *fi = &spa_feature_table[i];
486c170aa9fSMartin Matuska if (!fi->fi_zfs_mod_supported)
487c170aa9fSMartin Matuska continue;
48816038816SMartin Matuska if (c_features[i] && !nvlist_exists(feat, fi->fi_guid))
489eda14cbcSMatt Macy return (ZPOOL_STATUS_FEAT_DISABLED);
49016038816SMartin Matuska if (!c_features[i] && nvlist_exists(feat, fi->fi_guid))
49116038816SMartin Matuska return (ZPOOL_STATUS_INCOMPATIBLE_FEAT);
492eda14cbcSMatt Macy }
493eda14cbcSMatt Macy }
494eda14cbcSMatt Macy
495eda14cbcSMatt Macy return (ZPOOL_STATUS_OK);
496eda14cbcSMatt Macy }
497eda14cbcSMatt Macy
498eda14cbcSMatt Macy zpool_status_t
zpool_get_status(zpool_handle_t * zhp,const char ** msgid,zpool_errata_t * errata)499a0b956f5SMartin Matuska zpool_get_status(zpool_handle_t *zhp, const char **msgid,
500a0b956f5SMartin Matuska zpool_errata_t *errata)
501eda14cbcSMatt Macy {
502ee36e25aSMartin Matuska /*
503ee36e25aSMartin Matuska * pass in the desired feature set, as
504ee36e25aSMartin Matuska * it affects check for disabled features
505ee36e25aSMartin Matuska */
506ee36e25aSMartin Matuska char compatibility[ZFS_MAXPROPLEN];
507ee36e25aSMartin Matuska if (zpool_get_prop(zhp, ZPOOL_PROP_COMPATIBILITY, compatibility,
508ee36e25aSMartin Matuska ZFS_MAXPROPLEN, NULL, B_FALSE) != 0)
509ee36e25aSMartin Matuska compatibility[0] = '\0';
510ee36e25aSMartin Matuska
511ee36e25aSMartin Matuska zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata,
512ee36e25aSMartin Matuska compatibility);
513ee36e25aSMartin Matuska
514eda14cbcSMatt Macy if (msgid != NULL) {
515eda14cbcSMatt Macy if (ret >= NMSGID)
516eda14cbcSMatt Macy *msgid = NULL;
517eda14cbcSMatt Macy else
518eda14cbcSMatt Macy *msgid = zfs_msgid_table[ret];
519eda14cbcSMatt Macy }
520eda14cbcSMatt Macy return (ret);
521eda14cbcSMatt Macy }
522eda14cbcSMatt Macy
523eda14cbcSMatt Macy zpool_status_t
zpool_import_status(nvlist_t * config,const char ** msgid,zpool_errata_t * errata)524a0b956f5SMartin Matuska zpool_import_status(nvlist_t *config, const char **msgid,
525a0b956f5SMartin Matuska zpool_errata_t *errata)
526eda14cbcSMatt Macy {
527ee36e25aSMartin Matuska zpool_status_t ret = check_status(config, B_TRUE, errata, NULL);
528eda14cbcSMatt Macy
529eda14cbcSMatt Macy if (ret >= NMSGID)
530eda14cbcSMatt Macy *msgid = NULL;
531eda14cbcSMatt Macy else
532eda14cbcSMatt Macy *msgid = zfs_msgid_table[ret];
533eda14cbcSMatt Macy
534eda14cbcSMatt Macy return (ret);
535eda14cbcSMatt Macy }
536