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