static void zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data) { dev_data_t *dp = data; char *path; uint_t c, children; nvlist_t **child; /* * First iterate over any children. */ if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN, &child, &children) == 0) { for (c = 0; c < children; c++) zfs_iter_vdev(zhp, child[c], data); return; } /* once a vdev was matched and processed there is nothing left to do */ if (dp->dd_found) return; /* * Match by GUID if available otherwise fallback to devid or physical */ if (dp->dd_vdev_guid != 0) { uint64_t guid; if (nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID, &guid) != 0 || guid != dp->dd_vdev_guid) { return; } zed_log_msg(LOG_INFO, " zfs_iter_vdev: matched on %llu", guid); dp->dd_found = B_TRUE; } else if (dp->dd_compare != NULL) { /* * NOTE: On Linux there is an event for partition, so unlike * illumos, substring matching is not required to accomodate * the partition suffix. An exact match will be present in * the dp->dd_compare value. */ if (nvlist_lookup_string(nvl, dp->dd_prop, &path) != 0 || strcmp(dp->dd_compare, path) != 0) { return; } zed_log_msg(LOG_INFO, " zfs_iter_vdev: matched %s on %s", dp->dd_prop, path); dp->dd_found = B_TRUE; /* pass the new devid for use by replacing code */ if (dp->dd_islabeled && dp->dd_new_devid != NULL) { (void) nvlist_add_string(nvl, "new_devid", dp->dd_new_devid); } } (dp->dd_func)(zhp, nvl, dp->dd_islabeled); }
static void zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data) { dev_data_t *dp = data; char *path; uint_t c, children; nvlist_t **child; size_t len; uint64_t guid; /* * First iterate over any children. */ if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN, &child, &children) == 0) { for (c = 0; c < children; c++) zfs_iter_vdev(zhp, child[c], data); return; } if (dp->dd_vdev_guid != 0) { if (nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID, &guid) != 0 || guid != dp->dd_vdev_guid) return; } else if (dp->dd_compare != NULL) { len = strlen(dp->dd_compare); if (nvlist_lookup_string(nvl, dp->dd_prop, &path) != 0 || strncmp(dp->dd_compare, path, len) != 0) return; /* * Normally, we want to have an exact match for the comparison * string. However, we allow substring matches in the following * cases: * * <path>: This is a devpath, and the target is one * of its children. * * <path/> This is a devid for a whole disk, and * the target is one of its children. */ if (path[len] != '\0' && path[len] != ':' && path[len - 1] != '/') return; } (dp->dd_func)(zhp, nvl, dp->dd_isdisk); }
static int zfs_iter_pool(zpool_handle_t *zhp, void *data) { nvlist_t *config, *nvl; dev_data_t *dp = data; uint64_t pool_guid; unavailpool_t *pool; zed_log_msg(LOG_INFO, "zfs_iter_pool: evaluating vdevs on %s (by %s)", zpool_get_name(zhp), dp->dd_vdev_guid ? "GUID" : dp->dd_prop); /* * For each vdev in this pool, look for a match to apply dd_func */ if ((config = zpool_get_config(zhp, NULL)) != NULL) { if (dp->dd_pool_guid == 0 || (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &pool_guid) == 0 && pool_guid == dp->dd_pool_guid)) { (void) nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nvl); zfs_iter_vdev(zhp, nvl, data); } } /* * if this pool was originally unavailable, * then enable its datasets asynchronously */ if (g_enumeration_done) { for (pool = list_head(&g_pool_list); pool != NULL; pool = list_next(&g_pool_list, pool)) { if (pool->uap_enable_tid != 0) continue; /* entry already processed */ if (strcmp(zpool_get_name(zhp), zpool_get_name(pool->uap_zhp))) continue; if (zfs_toplevel_state(zhp) >= VDEV_STATE_DEGRADED) { /* send to a background thread; keep on list */ (void) pthread_create(&pool->uap_enable_tid, NULL, zfs_enable_ds, pool); break; } } } zpool_close(zhp); return (dp->dd_found); /* cease iteration after a match */ }
/* * This function handles the ESC_ZFS_config_sync event. It will iterate over * the pools vdevs and to update the FRU property. */ int zfs_deliver_sync(nvlist_t *nvl) { dev_data_t dd = { 0 }; char *pname; zpool_handle_t *zhp; nvlist_t *config, *vdev; if (nvlist_lookup_string(nvl, "pool_name", &pname) != 0) { syseventd_print(9, "zfs_deliver_sync: no pool name\n"); return (-1); } /* * If this event was triggered by a pool export or destroy we cannot * open the pool. This is not an error, just return 0 as we don't care * about these events. */ zhp = zpool_open_canfail(g_zfshdl, pname); if (zhp == NULL) return (0); config = zpool_get_config(zhp, NULL); if (config == NULL) { syseventd_print(9, "zfs_deliver_sync: " "failed to get pool config for %s\n", pname); zpool_close(zhp); return (-1); } if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &vdev) != 0) { syseventd_print(0, "zfs_deliver_sync: " "failed to get vdev tree for %s\n", pname); zpool_close(zhp); return (-1); } libzfs_fru_refresh(g_zfshdl); dd.dd_func = zfs_sync_vdev_fru; zfs_iter_vdev(zhp, vdev, &dd); zpool_close(zhp); return (0); }
static int zfs_iter_pool(zpool_handle_t *zhp, void *data) { nvlist_t *config, *nvl; dev_data_t *dp = data; uint64_t pool_guid; unavailpool_t *pool; if ((config = zpool_get_config(zhp, NULL)) != NULL) { if (dp->dd_pool_guid == 0 || (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &pool_guid) == 0 && pool_guid == dp->dd_pool_guid)) { (void) nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nvl); zfs_iter_vdev(zhp, nvl, data); } } if (g_enumeration_done) { for (pool = list_head(&g_pool_list); pool != NULL; pool = list_next(&g_pool_list, pool)) { if (strcmp(zpool_get_name(zhp), zpool_get_name(pool->uap_zhp))) continue; if (zfs_toplevel_state(zhp) >= VDEV_STATE_DEGRADED) { list_remove(&g_pool_list, pool); (void) tpool_dispatch(g_tpool, zfs_enable_ds, pool); break; } } } zpool_close(zhp); return (0); }