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 */ 51 static 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 */ 71 static int 72 vdev_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 */ 79 static int 80 vdev_faulted(uint64_t state, uint64_t aux, uint64_t errs) 81 { 82 return (state == VDEV_STATE_FAULTED); 83 } 84 85 /* ARGSUSED */ 86 static int 87 vdev_errors(uint64_t state, uint64_t aux, uint64_t errs) 88 { 89 return (state == VDEV_STATE_DEGRADED || errs != 0); 90 } 91 92 /* ARGSUSED */ 93 static int 94 vdev_broken(uint64_t state, uint64_t aux, uint64_t errs) 95 { 96 return (state == VDEV_STATE_CANT_OPEN); 97 } 98 99 /* ARGSUSED */ 100 static int 101 vdev_offlined(uint64_t state, uint64_t aux, uint64_t errs) 102 { 103 return (state == VDEV_STATE_OFFLINE); 104 } 105 106 /* ARGSUSED */ 107 static int 108 vdev_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 */ 116 static boolean_t 117 find_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 */ 170 static zpool_status_t 171 check_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 309 zpool_status_t 310 zpool_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 322 zpool_status_t 323 zpool_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 335 static void 336 dump_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 */ 368 void 369 zpool_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