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) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <fm/fmd_fmri.h> 26 #include <strings.h> 27 #include <libzfs.h> 28 29 typedef struct cbdata { 30 uint64_t cb_guid; 31 zpool_handle_t *cb_pool; 32 } cbdata_t; 33 34 libzfs_handle_t *g_zfs; 35 36 static int 37 find_pool(zpool_handle_t *zhp, void *data) 38 { 39 cbdata_t *cbp = data; 40 41 if (zpool_get_prop_int(zhp, ZPOOL_PROP_GUID, NULL) == cbp->cb_guid) { 42 cbp->cb_pool = zhp; 43 return (1); 44 } 45 46 zpool_close(zhp); 47 48 return (0); 49 } 50 51 ssize_t 52 fmd_fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 53 { 54 uint64_t pool_guid, vdev_guid; 55 cbdata_t cb; 56 ssize_t len; 57 const char *name; 58 char guidbuf[64]; 59 60 (void) nvlist_lookup_uint64(nvl, FM_FMRI_ZFS_POOL, &pool_guid); 61 62 /* 63 * Attempt to convert the pool guid to a name. 64 */ 65 cb.cb_guid = pool_guid; 66 cb.cb_pool = NULL; 67 68 if (zpool_iter(g_zfs, find_pool, &cb) == 1) { 69 name = zpool_get_name(cb.cb_pool); 70 } else { 71 (void) snprintf(guidbuf, sizeof (guidbuf), "%llx", pool_guid); 72 name = guidbuf; 73 } 74 75 if (nvlist_lookup_uint64(nvl, FM_FMRI_ZFS_VDEV, &vdev_guid) == 0) 76 len = snprintf(buf, buflen, "%s://pool=%s/vdev=%llx", 77 FM_FMRI_SCHEME_ZFS, name, vdev_guid); 78 else 79 len = snprintf(buf, buflen, "%s://pool=%s", 80 FM_FMRI_SCHEME_ZFS, name); 81 82 if (cb.cb_pool) 83 zpool_close(cb.cb_pool); 84 85 return (len); 86 } 87 88 static nvlist_t * 89 find_vdev_iter(nvlist_t *nv, uint64_t search) 90 { 91 uint_t c, children; 92 nvlist_t **child; 93 uint64_t guid; 94 nvlist_t *ret; 95 96 (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid); 97 98 if (search == guid) 99 return (nv); 100 101 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, 102 &child, &children) != 0) 103 return (NULL); 104 105 for (c = 0; c < children; c++) 106 if ((ret = find_vdev_iter(child[c], search)) != 0) 107 return (ret); 108 109 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE, 110 &child, &children) != 0) 111 return (NULL); 112 113 for (c = 0; c < children; c++) 114 if ((ret = find_vdev_iter(child[c], search)) != 0) 115 return (ret); 116 117 return (NULL); 118 } 119 120 static nvlist_t * 121 find_vdev(zpool_handle_t *zhp, uint64_t guid) 122 { 123 nvlist_t *config, *nvroot; 124 125 config = zpool_get_config(zhp, NULL); 126 127 (void) nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nvroot); 128 129 return (find_vdev_iter(nvroot, guid)); 130 } 131 132 int 133 fmd_fmri_present(nvlist_t *nvl) 134 { 135 uint64_t pool_guid, vdev_guid; 136 cbdata_t cb; 137 int ret; 138 139 (void) nvlist_lookup_uint64(nvl, FM_FMRI_ZFS_POOL, &pool_guid); 140 141 cb.cb_guid = pool_guid; 142 cb.cb_pool = NULL; 143 144 if (zpool_iter(g_zfs, find_pool, &cb) != 1) 145 return (0); 146 147 if (nvlist_lookup_uint64(nvl, FM_FMRI_ZFS_VDEV, &vdev_guid) != 0) { 148 zpool_close(cb.cb_pool); 149 return (1); 150 } 151 152 ret = (find_vdev(cb.cb_pool, vdev_guid) != NULL); 153 154 zpool_close(cb.cb_pool); 155 156 return (ret); 157 } 158 159 int 160 fmd_fmri_replaced(nvlist_t *nvl) 161 { 162 uint64_t pool_guid, vdev_guid; 163 cbdata_t cb; 164 int ret; 165 166 (void) nvlist_lookup_uint64(nvl, FM_FMRI_ZFS_POOL, &pool_guid); 167 168 cb.cb_guid = pool_guid; 169 cb.cb_pool = NULL; 170 171 if (zpool_iter(g_zfs, find_pool, &cb) != 1) 172 return (FMD_OBJ_STATE_NOT_PRESENT); 173 174 if (nvlist_lookup_uint64(nvl, FM_FMRI_ZFS_VDEV, &vdev_guid) != 0) { 175 zpool_close(cb.cb_pool); 176 return (FMD_OBJ_STATE_STILL_PRESENT); 177 } 178 179 ret = (find_vdev(cb.cb_pool, vdev_guid) != NULL) ? 180 FMD_OBJ_STATE_STILL_PRESENT : FMD_OBJ_STATE_NOT_PRESENT; 181 182 zpool_close(cb.cb_pool); 183 184 return (ret); 185 } 186 187 int 188 fmd_fmri_unusable(nvlist_t *nvl) 189 { 190 uint64_t pool_guid, vdev_guid; 191 cbdata_t cb; 192 nvlist_t *vd; 193 int ret; 194 195 (void) nvlist_lookup_uint64(nvl, FM_FMRI_ZFS_POOL, &pool_guid); 196 197 cb.cb_guid = pool_guid; 198 cb.cb_pool = NULL; 199 200 if (zpool_iter(g_zfs, find_pool, &cb) != 1) 201 return (1); 202 203 if (nvlist_lookup_uint64(nvl, FM_FMRI_ZFS_VDEV, &vdev_guid) != 0) { 204 ret = (zpool_get_state(cb.cb_pool) == POOL_STATE_UNAVAIL); 205 zpool_close(cb.cb_pool); 206 return (ret); 207 } 208 209 vd = find_vdev(cb.cb_pool, vdev_guid); 210 if (vd == NULL) { 211 ret = 1; 212 } else { 213 vdev_stat_t *vs; 214 uint_t c; 215 216 (void) nvlist_lookup_uint64_array(vd, ZPOOL_CONFIG_VDEV_STATS, 217 (uint64_t **)&vs, &c); 218 219 ret = (vs->vs_state < VDEV_STATE_DEGRADED); 220 } 221 222 zpool_close(cb.cb_pool); 223 224 return (ret); 225 } 226 227 int 228 fmd_fmri_init(void) 229 { 230 g_zfs = libzfs_init(); 231 232 if (g_zfs == NULL) 233 return (-1); 234 else 235 return (0); 236 } 237 238 void 239 fmd_fmri_fini(void) 240 { 241 if (g_zfs) 242 libzfs_fini(g_zfs); 243 } 244