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