libzfs_status.c revision 225736
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25/*
26 * This file contains the functions which analyze the status of a pool.  This
27 * include both the status of an active pool, as well as the status exported
28 * pools.  Returns one of the ZPOOL_STATUS_* defines describing the status of
29 * the pool.  This status is independent (to a certain degree) from the state of
30 * the pool.  A pool's state describes only whether or not it is capable of
31 * providing the necessary fault tolerance for data.  The status describes the
32 * overall status of devices.  A pool that is online can still have a device
33 * that is experiencing errors.
34 *
35 * Only a subset of the possible faults can be detected using 'zpool status',
36 * and not all possible errors correspond to a FMA message ID.  The explanation
37 * is left up to the caller, depending on whether it is a live pool or an
38 * import.
39 */
40
41#include <libzfs.h>
42#include <string.h>
43#include <unistd.h>
44#include "libzfs_impl.h"
45
46/*
47 * Message ID table.  This must be kept in sync with the ZPOOL_STATUS_* defines
48 * in libzfs.h.  Note that there are some status results which go past the end
49 * of this table, and hence have no associated message ID.
50 */
51static char *zfs_msgid_table[] = {
52	"ZFS-8000-14",
53	"ZFS-8000-2Q",
54	"ZFS-8000-3C",
55	"ZFS-8000-4J",
56	"ZFS-8000-5E",
57	"ZFS-8000-6X",
58	"ZFS-8000-72",
59	"ZFS-8000-8A",
60	"ZFS-8000-9P",
61	"ZFS-8000-A5",
62	"ZFS-8000-EY",
63	"ZFS-8000-HC",
64	"ZFS-8000-JQ",
65	"ZFS-8000-K4",
66};
67
68#define	NMSGID	(sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
69
70/* ARGSUSED */
71static int
72vdev_missing(uint64_t state, uint64_t aux, uint64_t errs)
73{
74	return (state == VDEV_STATE_CANT_OPEN &&
75	    aux == VDEV_AUX_OPEN_FAILED);
76}
77
78/* ARGSUSED */
79static int
80vdev_faulted(uint64_t state, uint64_t aux, uint64_t errs)
81{
82	return (state == VDEV_STATE_FAULTED);
83}
84
85/* ARGSUSED */
86static int
87vdev_errors(uint64_t state, uint64_t aux, uint64_t errs)
88{
89	return (state == VDEV_STATE_DEGRADED || errs != 0);
90}
91
92/* ARGSUSED */
93static int
94vdev_broken(uint64_t state, uint64_t aux, uint64_t errs)
95{
96	return (state == VDEV_STATE_CANT_OPEN);
97}
98
99/* ARGSUSED */
100static int
101vdev_offlined(uint64_t state, uint64_t aux, uint64_t errs)
102{
103	return (state == VDEV_STATE_OFFLINE);
104}
105
106/* ARGSUSED */
107static int
108vdev_removed(uint64_t state, uint64_t aux, uint64_t errs)
109{
110	return (state == VDEV_STATE_REMOVED);
111}
112
113/*
114 * Detect if any leaf devices that have seen errors or could not be opened.
115 */
116static boolean_t
117find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
118{
119	nvlist_t **child;
120	vdev_stat_t *vs;
121	uint_t c, children;
122	char *type;
123
124	/*
125	 * Ignore problems within a 'replacing' vdev, since we're presumably in
126	 * the process of repairing any such errors, and don't want to call them
127	 * out again.  We'll pick up the fact that a resilver is happening
128	 * later.
129	 */
130	verify(nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE, &type) == 0);
131	if (strcmp(type, VDEV_TYPE_REPLACING) == 0)
132		return (B_FALSE);
133
134	if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
135	    &children) == 0) {
136		for (c = 0; c < children; c++)
137			if (find_vdev_problem(child[c], func))
138				return (B_TRUE);
139	} else {
140		verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
141		    (uint64_t **)&vs, &c) == 0);
142
143		if (func(vs->vs_state, vs->vs_aux,
144		    vs->vs_read_errors +
145		    vs->vs_write_errors +
146		    vs->vs_checksum_errors))
147			return (B_TRUE);
148	}
149
150	return (B_FALSE);
151}
152
153/*
154 * Active pool health status.
155 *
156 * To determine the status for a pool, we make several passes over the config,
157 * picking the most egregious error we find.  In order of importance, we do the
158 * following:
159 *
160 *	- Check for a complete and valid configuration
161 *	- Look for any faulted or missing devices in a non-replicated config
162 *	- Check for any data errors
163 *	- Check for any faulted or missing devices in a replicated config
164 *	- Look for any devices showing errors
165 *	- Check for any resilvering devices
166 *
167 * There can obviously be multiple errors within a single pool, so this routine
168 * only picks the most damaging of all the current errors to report.
169 */
170static zpool_status_t
171check_status(nvlist_t *config, boolean_t isimport)
172{
173	nvlist_t *nvroot;
174	vdev_stat_t *vs;
175	pool_scan_stat_t *ps = NULL;
176	uint_t vsc, psc;
177	uint64_t nerr;
178	uint64_t version;
179	uint64_t stateval;
180	uint64_t suspended;
181	uint64_t hostid = 0;
182
183	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
184	    &version) == 0);
185	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
186	    &nvroot) == 0);
187	verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
188	    (uint64_t **)&vs, &vsc) == 0);
189	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
190	    &stateval) == 0);
191
192	/*
193	 * Currently resilvering a vdev
194	 */
195	(void) nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_SCAN_STATS,
196	    (uint64_t **)&ps, &psc);
197	if (ps && ps->pss_func == POOL_SCAN_RESILVER &&
198	    ps->pss_state == DSS_SCANNING)
199		return (ZPOOL_STATUS_RESILVERING);
200
201	/*
202	 * Pool last accessed by another system.
203	 */
204	(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
205	if (hostid != 0 && (unsigned long)hostid != gethostid() &&
206	    stateval == POOL_STATE_ACTIVE)
207		return (ZPOOL_STATUS_HOSTID_MISMATCH);
208
209	/*
210	 * Newer on-disk version.
211	 */
212	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
213	    vs->vs_aux == VDEV_AUX_VERSION_NEWER)
214		return (ZPOOL_STATUS_VERSION_NEWER);
215
216	/*
217	 * Check that the config is complete.
218	 */
219	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
220	    vs->vs_aux == VDEV_AUX_BAD_GUID_SUM)
221		return (ZPOOL_STATUS_BAD_GUID_SUM);
222
223	/*
224	 * Check whether the pool has suspended due to failed I/O.
225	 */
226	if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED,
227	    &suspended) == 0) {
228		if (suspended == ZIO_FAILURE_MODE_CONTINUE)
229			return (ZPOOL_STATUS_IO_FAILURE_CONTINUE);
230		return (ZPOOL_STATUS_IO_FAILURE_WAIT);
231	}
232
233	/*
234	 * Could not read a log.
235	 */
236	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
237	    vs->vs_aux == VDEV_AUX_BAD_LOG) {
238		return (ZPOOL_STATUS_BAD_LOG);
239	}
240
241	/*
242	 * Bad devices in non-replicated config.
243	 */
244	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
245	    find_vdev_problem(nvroot, vdev_faulted))
246		return (ZPOOL_STATUS_FAULTED_DEV_NR);
247
248	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
249	    find_vdev_problem(nvroot, vdev_missing))
250		return (ZPOOL_STATUS_MISSING_DEV_NR);
251
252	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
253	    find_vdev_problem(nvroot, vdev_broken))
254		return (ZPOOL_STATUS_CORRUPT_LABEL_NR);
255
256	/*
257	 * Corrupted pool metadata
258	 */
259	if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
260	    vs->vs_aux == VDEV_AUX_CORRUPT_DATA)
261		return (ZPOOL_STATUS_CORRUPT_POOL);
262
263	/*
264	 * Persistent data errors.
265	 */
266	if (!isimport) {
267		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
268		    &nerr) == 0 && nerr != 0)
269			return (ZPOOL_STATUS_CORRUPT_DATA);
270	}
271
272	/*
273	 * Missing devices in a replicated config.
274	 */
275	if (find_vdev_problem(nvroot, vdev_faulted))
276		return (ZPOOL_STATUS_FAULTED_DEV_R);
277	if (find_vdev_problem(nvroot, vdev_missing))
278		return (ZPOOL_STATUS_MISSING_DEV_R);
279	if (find_vdev_problem(nvroot, vdev_broken))
280		return (ZPOOL_STATUS_CORRUPT_LABEL_R);
281
282	/*
283	 * Devices with errors
284	 */
285	if (!isimport && find_vdev_problem(nvroot, vdev_errors))
286		return (ZPOOL_STATUS_FAILING_DEV);
287
288	/*
289	 * Offlined devices
290	 */
291	if (find_vdev_problem(nvroot, vdev_offlined))
292		return (ZPOOL_STATUS_OFFLINE_DEV);
293
294	/*
295	 * Removed device
296	 */
297	if (find_vdev_problem(nvroot, vdev_removed))
298		return (ZPOOL_STATUS_REMOVED_DEV);
299
300	/*
301	 * Outdated, but usable, version
302	 */
303	if (version < SPA_VERSION)
304		return (ZPOOL_STATUS_VERSION_OLDER);
305
306	return (ZPOOL_STATUS_OK);
307}
308
309zpool_status_t
310zpool_get_status(zpool_handle_t *zhp, char **msgid)
311{
312	zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE);
313
314	if (ret >= NMSGID)
315		*msgid = NULL;
316	else
317		*msgid = zfs_msgid_table[ret];
318
319	return (ret);
320}
321
322zpool_status_t
323zpool_import_status(nvlist_t *config, char **msgid)
324{
325	zpool_status_t ret = check_status(config, B_TRUE);
326
327	if (ret >= NMSGID)
328		*msgid = NULL;
329	else
330		*msgid = zfs_msgid_table[ret];
331
332	return (ret);
333}
334
335static void
336dump_ddt_stat(const ddt_stat_t *dds, int h)
337{
338	char refcnt[6];
339	char blocks[6], lsize[6], psize[6], dsize[6];
340	char ref_blocks[6], ref_lsize[6], ref_psize[6], ref_dsize[6];
341
342	if (dds == NULL || dds->dds_blocks == 0)
343		return;
344
345	if (h == -1)
346		(void) strcpy(refcnt, "Total");
347	else
348		zfs_nicenum(1ULL << h, refcnt, sizeof (refcnt));
349
350	zfs_nicenum(dds->dds_blocks, blocks, sizeof (blocks));
351	zfs_nicenum(dds->dds_lsize, lsize, sizeof (lsize));
352	zfs_nicenum(dds->dds_psize, psize, sizeof (psize));
353	zfs_nicenum(dds->dds_dsize, dsize, sizeof (dsize));
354	zfs_nicenum(dds->dds_ref_blocks, ref_blocks, sizeof (ref_blocks));
355	zfs_nicenum(dds->dds_ref_lsize, ref_lsize, sizeof (ref_lsize));
356	zfs_nicenum(dds->dds_ref_psize, ref_psize, sizeof (ref_psize));
357	zfs_nicenum(dds->dds_ref_dsize, ref_dsize, sizeof (ref_dsize));
358
359	(void) printf("%6s   %6s   %5s   %5s   %5s   %6s   %5s   %5s   %5s\n",
360	    refcnt,
361	    blocks, lsize, psize, dsize,
362	    ref_blocks, ref_lsize, ref_psize, ref_dsize);
363}
364
365/*
366 * Print the DDT histogram and the column totals.
367 */
368void
369zpool_dump_ddt(const ddt_stat_t *dds_total, const ddt_histogram_t *ddh)
370{
371	int h;
372
373	(void) printf("\n");
374
375	(void) printf("bucket   "
376	    "           allocated             "
377	    "          referenced          \n");
378	(void) printf("______   "
379	    "______________________________   "
380	    "______________________________\n");
381
382	(void) printf("%6s   %6s   %5s   %5s   %5s   %6s   %5s   %5s   %5s\n",
383	    "refcnt",
384	    "blocks", "LSIZE", "PSIZE", "DSIZE",
385	    "blocks", "LSIZE", "PSIZE", "DSIZE");
386
387	(void) printf("%6s   %6s   %5s   %5s   %5s   %6s   %5s   %5s   %5s\n",
388	    "------",
389	    "------", "-----", "-----", "-----",
390	    "------", "-----", "-----", "-----");
391
392	for (h = 0; h < 64; h++)
393		dump_ddt_stat(&ddh->ddh_stat[h], h);
394
395	dump_ddt_stat(dds_total, -1);
396
397	(void) printf("\n");
398}
399