xref: /illumos-gate/usr/src/cmd/fm/schemes/zfs/scheme.c (revision b23a7923)
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