int zpool_expand_proplist(zpool_handle_t *zhp, zpool_proplist_t **plp) { libzfs_handle_t *hdl = zhp->zpool_hdl; zpool_proplist_t *entry; char buf[ZFS_MAXPROPLEN]; if (zfs_expand_proplist_common(hdl, plp, ZFS_TYPE_POOL) != 0) return (-1); for (entry = *plp; entry != NULL; entry = entry->pl_next) { if (entry->pl_fixed) continue; if (entry->pl_prop != ZFS_PROP_INVAL && zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf), NULL) == 0) { if (strlen(buf) > entry->pl_width) entry->pl_width = strlen(buf); } } return (0); }
/* * Function: be_get_node_data * Description: Helper function used to collect all the information to fill * in the be_node_list structure to be returned by be_list. * Parameters: * zhp - Handle to the root dataset for the BE whose information * we're collecting. * be_node - a pointer to the node structure we're filling in. * be_name - The BE name of the node whose information we're * collecting. * current_be - the name of the currently active BE. * be_ds - The dataset name for the BE. * * Returns: * BE_SUCCESS - Success * be_errno_t - Failure * Scope: * Private */ static int be_get_node_data( zfs_handle_t *zhp, be_node_list_t *be_node, char *be_name, const char *rpool, char *current_be, char *be_ds) { char prop_buf[MAXPATHLEN]; nvlist_t *userprops = NULL; nvlist_t *propval = NULL; nvlist_t *zone_propval = NULL; char *prop_str = NULL; char *zone_prop_str = NULL; char *grub_default_bootfs = NULL; zpool_handle_t *zphp = NULL; int err = 0; if (be_node == NULL || be_name == NULL || current_be == NULL || be_ds == NULL) { be_print_err(gettext("be_get_node_data: invalid arguments, " "can not be NULL\n")); return (BE_ERR_INVAL); } errno = 0; be_node->be_root_ds = strdup(be_ds); if ((err = errno) != 0 || be_node->be_root_ds == NULL) { be_print_err(gettext("be_get_node_data: failed to " "copy root dataset name\n")); return (errno_to_be_err(err)); } be_node->be_node_name = strdup(be_name); if ((err = errno) != 0 || be_node->be_node_name == NULL) { be_print_err(gettext("be_get_node_data: failed to " "copy BE name\n")); return (errno_to_be_err(err)); } if (strncmp(be_name, current_be, MAXPATHLEN) == 0) be_node->be_active = B_TRUE; else be_node->be_active = B_FALSE; be_node->be_rpool = strdup(rpool); if (be_node->be_rpool == NULL || (err = errno) != 0) { be_print_err(gettext("be_get_node_data: failed to " "copy root pool name\n")); return (errno_to_be_err(err)); } be_node->be_space_used = zfs_prop_get_int(zhp, ZFS_PROP_USED); if (getzoneid() == GLOBAL_ZONEID) { if ((zphp = zpool_open(g_zfs, rpool)) == NULL) { be_print_err(gettext("be_get_node_data: failed to open " "pool (%s): %s\n"), rpool, libzfs_error_description(g_zfs)); return (zfs_err_to_be_err(g_zfs)); } (void) zpool_get_prop(zphp, ZPOOL_PROP_BOOTFS, prop_buf, ZFS_MAXPROPLEN, NULL, B_FALSE); if (be_has_grub() && (be_default_grub_bootfs(rpool, &grub_default_bootfs) == BE_SUCCESS) && grub_default_bootfs != NULL) if (strcmp(grub_default_bootfs, be_ds) == 0) be_node->be_active_on_boot = B_TRUE; else be_node->be_active_on_boot = B_FALSE; else if (prop_buf != NULL && strcmp(prop_buf, be_ds) == 0) be_node->be_active_on_boot = B_TRUE; else be_node->be_active_on_boot = B_FALSE; be_node->be_global_active = B_TRUE; free(grub_default_bootfs); zpool_close(zphp); } else { if (be_zone_compare_uuids(be_node->be_root_ds)) be_node->be_global_active = B_TRUE; else be_node->be_global_active = B_FALSE; } /* * If the dataset is mounted use the mount point * returned from the zfs_is_mounted call. If the * dataset is not mounted then pull the mount * point information out of the zfs properties. */ be_node->be_mounted = zfs_is_mounted(zhp, &(be_node->be_mntpt)); if (!be_node->be_mounted) { if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf, ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) == 0) be_node->be_mntpt = strdup(prop_buf); else return (zfs_err_to_be_err(g_zfs)); } be_node->be_node_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION); /* Get all user properties used for libbe */ if ((userprops = zfs_get_user_props(zhp)) == NULL) { be_node->be_policy_type = strdup(be_default_policy()); } else { if (getzoneid() != GLOBAL_ZONEID) { if (nvlist_lookup_nvlist(userprops, BE_ZONE_ACTIVE_PROPERTY, &zone_propval) != 0 || zone_propval == NULL) { be_node->be_active_on_boot = B_FALSE; } else { verify(nvlist_lookup_string(zone_propval, ZPROP_VALUE, &zone_prop_str) == 0); if (strcmp(zone_prop_str, "on") == 0) { be_node->be_active_on_boot = B_TRUE; } else { be_node->be_active_on_boot = B_FALSE; } } } if (nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY, &propval) != 0 || propval == NULL) { be_node->be_policy_type = strdup(be_default_policy()); } else { verify(nvlist_lookup_string(propval, ZPROP_VALUE, &prop_str) == 0); if (prop_str == NULL || strcmp(prop_str, "-") == 0 || strcmp(prop_str, "") == 0) be_node->be_policy_type = strdup(be_default_policy()); else be_node->be_policy_type = strdup(prop_str); } if (getzoneid() != GLOBAL_ZONEID) { if (nvlist_lookup_nvlist(userprops, BE_ZONE_PARENTBE_PROPERTY, &propval) != 0 && nvlist_lookup_string(propval, ZPROP_VALUE, &prop_str) == 0) { be_node->be_uuid_str = strdup(prop_str); } } else { if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY, &propval) == 0 && nvlist_lookup_string(propval, ZPROP_VALUE, &prop_str) == 0) { be_node->be_uuid_str = strdup(prop_str); } } } /* * Increment the dataset counter to include the root dataset * of the BE. */ be_node->be_node_num_datasets++; return (BE_SUCCESS); }
/* * Active pool health status. * * To determine the status for a pool, we make several passes over the config, * picking the most egregious error we find. In order of importance, we do the * following: * * - Check for a complete and valid configuration * - Look for any faulted or missing devices in a non-replicated config * - Check for any data errors * - Check for any faulted or missing devices in a replicated config * - Look for any devices showing errors * - Check for any resilvering devices * * There can obviously be multiple errors within a single pool, so this routine * only picks the most damaging of all the current errors to report. */ static zpool_status_t check_status(zpool_handle_t *zhp, nvlist_t *config, boolean_t isimport) { nvlist_t *nvroot; vdev_stat_t *vs; uint_t vsc; uint64_t nerr; uint64_t version; uint64_t stateval; uint64_t hostid = 0; verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &version) == 0); verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &vsc) == 0); verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, &stateval) == 0); (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid); /* * Pool last accessed by another system. */ if (hostid != 0 && (unsigned long)hostid != gethostid() && stateval == POOL_STATE_ACTIVE) return (ZPOOL_STATUS_HOSTID_MISMATCH); /* * Newer on-disk version. */ if (vs->vs_state == VDEV_STATE_CANT_OPEN && vs->vs_aux == VDEV_AUX_VERSION_NEWER) return (ZPOOL_STATUS_VERSION_NEWER); /* * Check that the config is complete. */ if (vs->vs_state == VDEV_STATE_CANT_OPEN && vs->vs_aux == VDEV_AUX_BAD_GUID_SUM) return (ZPOOL_STATUS_BAD_GUID_SUM); /* * Pool has experienced failed I/O. */ if (stateval == POOL_STATE_IO_FAILURE) { zpool_handle_t *tmp_zhp = NULL; libzfs_handle_t *hdl = NULL; char property[ZPOOL_MAXPROPLEN]; char *failmode = NULL; if (zhp == NULL) { char *poolname; verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, &poolname) == 0); if ((hdl = libzfs_init()) == NULL) return (ZPOOL_STATUS_IO_FAILURE_WAIT); tmp_zhp = zpool_open_canfail(hdl, poolname); if (tmp_zhp == NULL) { libzfs_fini(hdl); return (ZPOOL_STATUS_IO_FAILURE_WAIT); } } if (zpool_get_prop(zhp ? zhp : tmp_zhp, ZPOOL_PROP_FAILUREMODE, property, sizeof (property), NULL) == 0) failmode = property; if (tmp_zhp != NULL) zpool_close(tmp_zhp); if (hdl != NULL) libzfs_fini(hdl); if (failmode == NULL) return (ZPOOL_STATUS_IO_FAILURE_WAIT); if (strncmp(failmode, "continue", strlen("continue")) == 0) return (ZPOOL_STATUS_IO_FAILURE_CONTINUE); else return (ZPOOL_STATUS_IO_FAILURE_WAIT); } /* * Could not read a log. */ if (vs->vs_state == VDEV_STATE_CANT_OPEN && vs->vs_aux == VDEV_AUX_BAD_LOG) { return (ZPOOL_STATUS_BAD_LOG); } /* * Bad devices in non-replicated config. */ if (vs->vs_state == VDEV_STATE_CANT_OPEN && find_vdev_problem(nvroot, vdev_faulted)) return (ZPOOL_STATUS_FAULTED_DEV_NR); if (vs->vs_state == VDEV_STATE_CANT_OPEN && find_vdev_problem(nvroot, vdev_missing)) return (ZPOOL_STATUS_MISSING_DEV_NR); if (vs->vs_state == VDEV_STATE_CANT_OPEN && find_vdev_problem(nvroot, vdev_broken)) return (ZPOOL_STATUS_CORRUPT_LABEL_NR); /* * Corrupted pool metadata */ if (vs->vs_state == VDEV_STATE_CANT_OPEN && vs->vs_aux == VDEV_AUX_CORRUPT_DATA) return (ZPOOL_STATUS_CORRUPT_POOL); /* * Persistent data errors. */ if (!isimport) { if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT, &nerr) == 0 && nerr != 0) return (ZPOOL_STATUS_CORRUPT_DATA); } /* * Missing devices in a replicated config. */ if (find_vdev_problem(nvroot, vdev_faulted)) return (ZPOOL_STATUS_FAULTED_DEV_R); if (find_vdev_problem(nvroot, vdev_missing)) return (ZPOOL_STATUS_MISSING_DEV_R); if (find_vdev_problem(nvroot, vdev_broken)) return (ZPOOL_STATUS_CORRUPT_LABEL_R); /* * Devices with errors */ if (!isimport && find_vdev_problem(nvroot, vdev_errors)) return (ZPOOL_STATUS_FAILING_DEV); /* * Offlined devices */ if (find_vdev_problem(nvroot, vdev_offlined)) return (ZPOOL_STATUS_OFFLINE_DEV); /* * Currently resilvering */ if (!vs->vs_scrub_complete && vs->vs_scrub_type == POOL_SCRUB_RESILVER) return (ZPOOL_STATUS_RESILVERING); /* * Outdated, but usable, version */ if (version < SPA_VERSION) return (ZPOOL_STATUS_VERSION_OLDER); return (ZPOOL_STATUS_OK); }