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
find_pool(zpool_handle_t * zhp,void * data)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
fmd_fmri_nvl2str(nvlist_t * nvl,char * buf,size_t buflen)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 *
find_vdev_iter(nvlist_t * nv,uint64_t search)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 *
find_vdev(zpool_handle_t * zhp,uint64_t guid)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
fmd_fmri_present(nvlist_t * nvl)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
fmd_fmri_replaced(nvlist_t * nvl)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
fmd_fmri_unusable(nvlist_t * nvl)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
fmd_fmri_init(void)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
fmd_fmri_fini(void)250 fmd_fmri_fini(void)
251 {
252 if (g_zfs)
253 libzfs_fini(g_zfs);
254 }
255