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