xref: /illumos-gate/usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c (revision b31b5de1357c915fe7dab4d9646d9d84f9fe69bc)
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 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "libzfs_jni_util.h"
30 #include "libzfs_jni_pool.h"
31 #include <strings.h>
32 
33 /*
34  * Types
35  */
36 
37 typedef struct ImportablePoolBean {
38 	zjni_Object_t super;
39 	PoolStatsBean_t interface_PoolStats;
40 
41 	jmethodID method_setName;
42 	jmethodID method_setId;
43 } ImportablePoolBean_t;
44 
45 typedef struct VirtualDeviceBean {
46 	zjni_Object_t super;
47 	DeviceStatsBean_t interface_DeviceStats;
48 
49 	jmethodID method_setPoolName;
50 	jmethodID method_setParentIndex;
51 	jmethodID method_setIndex;
52 } VirtualDeviceBean_t;
53 
54 typedef struct LeafVirtualDeviceBean {
55 	VirtualDeviceBean_t super;
56 
57 	jmethodID method_setName;
58 } LeafVirtualDeviceBean_t;
59 
60 typedef struct DiskVirtualDeviceBean {
61 	LeafVirtualDeviceBean_t super;
62 } DiskVirtualDeviceBean_t;
63 
64 typedef struct SliceVirtualDeviceBean {
65 	LeafVirtualDeviceBean_t super;
66 } SliceVirtualDeviceBean_t;
67 
68 typedef struct FileVirtualDeviceBean {
69 	LeafVirtualDeviceBean_t super;
70 } FileVirtualDeviceBean_t;
71 
72 typedef struct RAIDVirtualDeviceBean {
73 	VirtualDeviceBean_t super;
74 
75 	jmethodID method_setParity;
76 } RAIDVirtualDeviceBean_t;
77 
78 typedef struct MirrorVirtualDeviceBean {
79 	VirtualDeviceBean_t super;
80 } MirrorVirtualDeviceBean_t;
81 
82 /*
83  * Data
84  */
85 
86 /* vdev_state_t to DeviceStats$DeviceState map */
87 static zjni_field_mapping_t vdev_state_map[] = {
88 	{ VDEV_STATE_CANT_OPEN, "VDEV_STATE_CANT_OPEN" },
89 	{ VDEV_STATE_CLOSED, "VDEV_STATE_CLOSED" },
90 	{ VDEV_STATE_DEGRADED, "VDEV_STATE_DEGRADED" },
91 	{ VDEV_STATE_HEALTHY, "VDEV_STATE_HEALTHY" },
92 	{ VDEV_STATE_OFFLINE, "VDEV_STATE_OFFLINE" },
93 	{ VDEV_STATE_UNKNOWN, "VDEV_STATE_UNKNOWN" },
94 	{ -1, NULL },
95 };
96 
97 /* vdev_aux_t to DeviceStats$DeviceStatus map */
98 static zjni_field_mapping_t vdev_aux_map[] = {
99 	{ VDEV_AUX_NONE, "VDEV_AUX_NONE" },
100 	{ VDEV_AUX_OPEN_FAILED, "VDEV_AUX_OPEN_FAILED" },
101 	{ VDEV_AUX_CORRUPT_DATA, "VDEV_AUX_CORRUPT_DATA" },
102 	{ VDEV_AUX_NO_REPLICAS, "VDEV_AUX_NO_REPLICAS" },
103 	{ VDEV_AUX_BAD_GUID_SUM, "VDEV_AUX_BAD_GUID_SUM" },
104 	{ VDEV_AUX_TOO_SMALL, "VDEV_AUX_TOO_SMALL" },
105 	{ VDEV_AUX_BAD_LABEL, "VDEV_AUX_BAD_LABEL" },
106 	{ -1, NULL },
107 };
108 
109 /* zpool_state_t to PoolStats$PoolState map */
110 static zjni_field_mapping_t pool_state_map[] = {
111 	{ POOL_STATE_ACTIVE, "POOL_STATE_ACTIVE" },
112 	{ POOL_STATE_EXPORTED, "POOL_STATE_EXPORTED" },
113 	{ POOL_STATE_DESTROYED, "POOL_STATE_DESTROYED" },
114 	{ POOL_STATE_SPARE, "POOL_STATE_SPARE" },
115 	{ POOL_STATE_UNINITIALIZED, "POOL_STATE_UNINITIALIZED" },
116 	{ POOL_STATE_UNAVAIL, "POOL_STATE_UNAVAIL" },
117 	{ POOL_STATE_POTENTIALLY_ACTIVE, "POOL_STATE_POTENTIALLY_ACTIVE" },
118 	{ -1, NULL },
119 };
120 
121 /* zpool_status_t to PoolStats$PoolStatus map */
122 static zjni_field_mapping_t zpool_status_map[] = {
123 	{ ZPOOL_STATUS_CORRUPT_CACHE, "ZPOOL_STATUS_CORRUPT_CACHE" },
124 	{ ZPOOL_STATUS_MISSING_DEV_R, "ZPOOL_STATUS_MISSING_DEV_R" },
125 	{ ZPOOL_STATUS_MISSING_DEV_NR, "ZPOOL_STATUS_MISSING_DEV_NR" },
126 	{ ZPOOL_STATUS_CORRUPT_LABEL_R, "ZPOOL_STATUS_CORRUPT_LABEL_R" },
127 	{ ZPOOL_STATUS_CORRUPT_LABEL_NR, "ZPOOL_STATUS_CORRUPT_LABEL_NR" },
128 	{ ZPOOL_STATUS_BAD_GUID_SUM, "ZPOOL_STATUS_BAD_GUID_SUM" },
129 	{ ZPOOL_STATUS_CORRUPT_POOL, "ZPOOL_STATUS_CORRUPT_POOL" },
130 	{ ZPOOL_STATUS_CORRUPT_DATA, "ZPOOL_STATUS_CORRUPT_DATA" },
131 	{ ZPOOL_STATUS_FAILING_DEV, "ZPOOL_STATUS_FAILING_DEV" },
132 	{ ZPOOL_STATUS_VERSION_NEWER, "ZPOOL_STATUS_VERSION_NEWER" },
133 	{ ZPOOL_STATUS_HOSTID_MISMATCH, "ZPOOL_STATUS_HOSTID_MISMATCH" },
134 	{ ZPOOL_STATUS_FAULTED_DEV_R, "ZPOOL_STATUS_FAULTED_DEV_R" },
135 	{ ZPOOL_STATUS_FAULTED_DEV_NR, "ZPOOL_STATUS_FAULTED_DEV_NR" },
136 	{ ZPOOL_STATUS_BAD_LOG, "ZPOOL_STATUS_BAD_LOG" },
137 	{ ZPOOL_STATUS_VERSION_OLDER, "ZPOOL_STATUS_VERSION_OLDER" },
138 	{ ZPOOL_STATUS_RESILVERING, "ZPOOL_STATUS_RESILVERING" },
139 	{ ZPOOL_STATUS_OFFLINE_DEV, "ZPOOL_STATUS_OFFLINE_DEV" },
140 	{ ZPOOL_STATUS_OK, "ZPOOL_STATUS_OK" },
141 	{ -1, NULL }
142 };
143 
144 /*
145  * Function prototypes
146  */
147 
148 static void new_ImportablePoolBean(JNIEnv *, ImportablePoolBean_t *);
149 static void new_VirtualDevice(JNIEnv *, VirtualDeviceBean_t *);
150 static void new_LeafVirtualDevice(JNIEnv *, LeafVirtualDeviceBean_t *);
151 static void new_DiskVirtualDeviceBean(JNIEnv *, DiskVirtualDeviceBean_t *);
152 static void new_SliceVirtualDeviceBean(JNIEnv *, SliceVirtualDeviceBean_t *);
153 static void new_FileVirtualDeviceBean(JNIEnv *, FileVirtualDeviceBean_t *);
154 static void new_RAIDVirtualDeviceBean(JNIEnv *, RAIDVirtualDeviceBean_t *);
155 static void new_MirrorVirtualDeviceBean(JNIEnv *, MirrorVirtualDeviceBean_t *);
156 static int populate_ImportablePoolBean(
157     JNIEnv *, ImportablePoolBean_t *, nvlist_t *);
158 static int populate_VirtualDeviceBean(JNIEnv *, zpool_handle_t *,
159     nvlist_t *, uint64_t *p_vdev_id, VirtualDeviceBean_t *);
160 static int populate_LeafVirtualDeviceBean(JNIEnv *, zpool_handle_t *,
161     nvlist_t *, uint64_t *p_vdev_id, LeafVirtualDeviceBean_t *);
162 static int populate_DiskVirtualDeviceBean(JNIEnv *, zpool_handle_t *,
163     nvlist_t *, uint64_t *p_vdev_id, DiskVirtualDeviceBean_t *);
164 static int populate_SliceVirtualDeviceBean(JNIEnv *, zpool_handle_t *,
165     nvlist_t *, uint64_t *p_vdev_id, SliceVirtualDeviceBean_t *);
166 static int populate_FileVirtualDeviceBean(JNIEnv *, zpool_handle_t *,
167     nvlist_t *, uint64_t *p_vdev_id, FileVirtualDeviceBean_t *);
168 static int populate_RAIDVirtualDeviceBean(JNIEnv *, zpool_handle_t *,
169     nvlist_t *, uint64_t *p_vdev_id, RAIDVirtualDeviceBean_t *);
170 static int populate_MirrorVirtualDeviceBean(JNIEnv *, zpool_handle_t *,
171     nvlist_t *, uint64_t *p_vdev_id, MirrorVirtualDeviceBean_t *);
172 static jobject create_ImportablePoolBean(JNIEnv *, nvlist_t *);
173 static jobject create_DiskVirtualDeviceBean(
174     JNIEnv *, zpool_handle_t *, nvlist_t *, uint64_t *p_vdev_id);
175 static jobject create_SliceVirtualDeviceBean(
176     JNIEnv *, zpool_handle_t *, nvlist_t *, uint64_t *p_vdev_id);
177 static jobject create_FileVirtualDeviceBean(
178     JNIEnv *, zpool_handle_t *, nvlist_t *, uint64_t *p_vdev_id);
179 static jobject create_RAIDVirtualDeviceBean(
180     JNIEnv *, zpool_handle_t *, nvlist_t *, uint64_t *p_vdev_id);
181 static jobject create_MirrorVirtualDeviceBean(
182     JNIEnv *, zpool_handle_t *, nvlist_t *, uint64_t *p_vdev_id);
183 static char *find_field(const zjni_field_mapping_t *, int);
184 static jobject zjni_vdev_state_to_obj(JNIEnv *, vdev_state_t);
185 static jobject zjni_vdev_aux_to_obj(JNIEnv *, vdev_aux_t);
186 
187 /*
188  * Static functions
189  */
190 
191 /* Create a ImportablePoolBean */
192 static void
193 new_ImportablePoolBean(JNIEnv *env, ImportablePoolBean_t *bean)
194 {
195 	zjni_Object_t *object = (zjni_Object_t *)bean;
196 
197 	if (object->object == NULL) {
198 		object->class =
199 		    (*env)->FindClass(env,
200 		    ZFSJNI_PACKAGE_DATA "ImportablePoolBean");
201 
202 		object->constructor =
203 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
204 
205 		object->object =
206 		    (*env)->NewObject(env, object->class, object->constructor);
207 	}
208 
209 	new_PoolStats(env, &(bean->interface_PoolStats), object);
210 
211 	bean->method_setName = (*env)->GetMethodID(
212 	    env, object->class, "setName", "(Ljava/lang/String;)V");
213 
214 	bean->method_setId = (*env)->GetMethodID(
215 	    env, object->class, "setId", "(J)V");
216 }
217 
218 /* Create a VirtualDeviceBean */
219 static void
220 new_VirtualDevice(JNIEnv *env, VirtualDeviceBean_t *bean)
221 {
222 	zjni_Object_t *object = (zjni_Object_t *)bean;
223 
224 	if (object->object == NULL) {
225 		object->class =
226 		    (*env)->FindClass(env,
227 		    ZFSJNI_PACKAGE_DATA "VirtualDeviceBean");
228 
229 		object->constructor =
230 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
231 
232 		object->object =
233 		    (*env)->NewObject(env, object->class, object->constructor);
234 	}
235 
236 	new_DeviceStats(env, &(bean->interface_DeviceStats), object);
237 
238 	bean->method_setPoolName = (*env)->GetMethodID(
239 	    env, object->class, "setPoolName", "(Ljava/lang/String;)V");
240 
241 	bean->method_setParentIndex = (*env)->GetMethodID(
242 	    env, object->class, "setParentIndex", "(Ljava/lang/Long;)V");
243 
244 	bean->method_setIndex = (*env)->GetMethodID(
245 	    env, object->class, "setIndex", "(J)V");
246 }
247 
248 /* Create a LeafVirtualDeviceBean */
249 static void
250 new_LeafVirtualDevice(JNIEnv *env, LeafVirtualDeviceBean_t *bean)
251 {
252 	zjni_Object_t *object = (zjni_Object_t *)bean;
253 
254 	if (object->object == NULL) {
255 		object->class =
256 		    (*env)->FindClass(env,
257 		    ZFSJNI_PACKAGE_DATA "LeafVirtualDeviceBean");
258 
259 		object->constructor =
260 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
261 
262 		object->object =
263 		    (*env)->NewObject(env, object->class, object->constructor);
264 	}
265 
266 	new_VirtualDevice(env, (VirtualDeviceBean_t *)bean);
267 
268 	bean->method_setName = (*env)->GetMethodID(
269 	    env, object->class, "setName", "(Ljava/lang/String;)V");
270 }
271 
272 /* Create a DiskVirtualDeviceBean */
273 static void
274 new_DiskVirtualDeviceBean(JNIEnv *env, DiskVirtualDeviceBean_t *bean)
275 {
276 	zjni_Object_t *object = (zjni_Object_t *)bean;
277 
278 	if (object->object == NULL) {
279 		object->class = (*env)->FindClass(
280 		    env, ZFSJNI_PACKAGE_DATA "DiskVirtualDeviceBean");
281 
282 		object->constructor =
283 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
284 
285 		object->object =
286 		    (*env)->NewObject(env, object->class, object->constructor);
287 	}
288 
289 	new_LeafVirtualDevice(env, (LeafVirtualDeviceBean_t *)bean);
290 }
291 
292 /* Create a SliceVirtualDeviceBean */
293 static void
294 new_SliceVirtualDeviceBean(JNIEnv *env, SliceVirtualDeviceBean_t *bean)
295 {
296 	zjni_Object_t *object = (zjni_Object_t *)bean;
297 
298 	if (object->object == NULL) {
299 		object->class = (*env)->FindClass(
300 		    env, ZFSJNI_PACKAGE_DATA "SliceVirtualDeviceBean");
301 
302 		object->constructor =
303 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
304 
305 		object->object =
306 		    (*env)->NewObject(env, object->class, object->constructor);
307 	}
308 
309 	new_LeafVirtualDevice(env, (LeafVirtualDeviceBean_t *)bean);
310 }
311 
312 /* Create a FileVirtualDeviceBean */
313 static void
314 new_FileVirtualDeviceBean(JNIEnv *env, FileVirtualDeviceBean_t *bean)
315 {
316 	zjni_Object_t *object = (zjni_Object_t *)bean;
317 
318 	if (object->object == NULL) {
319 		object->class = (*env)->FindClass(
320 		    env, ZFSJNI_PACKAGE_DATA "FileVirtualDeviceBean");
321 
322 		object->constructor =
323 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
324 
325 		object->object =
326 		    (*env)->NewObject(env, object->class, object->constructor);
327 	}
328 
329 	new_LeafVirtualDevice(env, (LeafVirtualDeviceBean_t *)bean);
330 }
331 
332 /* Create a RAIDVirtualDeviceBean */
333 static void
334 new_RAIDVirtualDeviceBean(JNIEnv *env, RAIDVirtualDeviceBean_t *bean)
335 {
336 	zjni_Object_t *object = (zjni_Object_t *)bean;
337 
338 	if (object->object == NULL) {
339 
340 		object->class = (*env)->FindClass(
341 		    env, ZFSJNI_PACKAGE_DATA "RAIDVirtualDeviceBean");
342 
343 		object->constructor =
344 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
345 
346 		object->object =
347 		    (*env)->NewObject(env, object->class, object->constructor);
348 	}
349 
350 	new_VirtualDevice(env, (VirtualDeviceBean_t *)bean);
351 
352 	bean->method_setParity = (*env)->GetMethodID(
353 	    env, object->class, "setParity", "(J)V");
354 }
355 
356 /* Create a MirrorVirtualDeviceBean */
357 static void
358 new_MirrorVirtualDeviceBean(JNIEnv *env, MirrorVirtualDeviceBean_t *bean)
359 {
360 	zjni_Object_t *object = (zjni_Object_t *)bean;
361 
362 	if (object->object == NULL) {
363 		object->class = (*env)->FindClass(
364 		    env, ZFSJNI_PACKAGE_DATA "MirrorVirtualDeviceBean");
365 
366 		object->constructor =
367 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
368 
369 		object->object =
370 		    (*env)->NewObject(env, object->class, object->constructor);
371 	}
372 
373 	new_VirtualDevice(env, (VirtualDeviceBean_t *)bean);
374 }
375 
376 static int
377 populate_ImportablePoolBean(JNIEnv *env, ImportablePoolBean_t *bean,
378     nvlist_t *config)
379 {
380 	char *c;
381 	char *name;
382 	uint64_t guid;
383 	uint64_t state;
384 	uint64_t version;
385 	nvlist_t *devices;
386 
387 	zjni_Object_t *object = (zjni_Object_t *)bean;
388 	PoolStatsBean_t *pool_stats = &(bean->interface_PoolStats);
389 	DeviceStatsBean_t *dev_stats = (DeviceStatsBean_t *)pool_stats;
390 
391 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, &name) ||
392 	    nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) ||
393 	    nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, &state) ||
394 	    nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &version) ||
395 	    nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &devices) ||
396 	    populate_DeviceStatsBean(env, devices, dev_stats, object)) {
397 		return (-1);
398 	}
399 
400 	(*env)->CallVoidMethod(env, object->object,
401 	    bean->method_setName, (*env)->NewStringUTF(env, name));
402 
403 	(*env)->CallVoidMethod(env, object->object,
404 	    bean->method_setId, (jlong)guid);
405 
406 	(*env)->CallVoidMethod(env, object->object,
407 	    pool_stats->method_setPoolState,
408 	    zjni_pool_state_to_obj(env, (pool_state_t)state));
409 
410 	(*env)->CallVoidMethod(env, object->object,
411 	    pool_stats->method_setPoolStatus,
412 	    zjni_pool_status_to_obj(env, zpool_import_status(config, &c)));
413 
414 	(*env)->CallVoidMethod(env, object->object,
415 	    pool_stats->method_setPoolVersion, (jlong)version);
416 
417 	return (0);
418 }
419 
420 static int
421 populate_VirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
422     nvlist_t *vdev, uint64_t *p_vdev_id, VirtualDeviceBean_t *bean)
423 {
424 	int result;
425 	uint64_t vdev_id;
426 	jstring poolUTF;
427 
428 	zjni_Object_t *object = (zjni_Object_t *)bean;
429 	DeviceStatsBean_t *stats = &(bean->interface_DeviceStats);
430 
431 	result = populate_DeviceStatsBean(env, vdev, stats, object);
432 	if (result != 0) {
433 		return (1);
434 	}
435 
436 	/* Set pool name */
437 	poolUTF = (*env)->NewStringUTF(env, zpool_get_name(zhp));
438 	(*env)->CallVoidMethod(
439 	    env, object->object, bean->method_setPoolName, poolUTF);
440 
441 	/* Set parent vdev index */
442 	(*env)->CallVoidMethod(
443 	    env, object->object, bean->method_setParentIndex,
444 	    p_vdev_id == NULL ? NULL :
445 	    zjni_long_to_Long(env, *p_vdev_id));
446 
447 	/* Get index */
448 	result = nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &vdev_id);
449 	if (result != 0) {
450 		zjni_throw_exception(env,
451 		    "could not retrieve virtual device ID (pool %s)",
452 		    zpool_get_name(zhp));
453 		return (1);
454 	}
455 
456 	(*env)->CallVoidMethod(
457 	    env, object->object, bean->method_setIndex, (jlong)vdev_id);
458 
459 	return (0);
460 }
461 
462 static int
463 populate_LeafVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
464     nvlist_t *vdev, uint64_t *p_vdev_id, LeafVirtualDeviceBean_t *bean)
465 {
466 	return (populate_VirtualDeviceBean(
467 	    env, zhp, vdev, p_vdev_id, (VirtualDeviceBean_t *)bean));
468 }
469 
470 static int
471 populate_DiskVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
472     nvlist_t *vdev, uint64_t *p_vdev_id, DiskVirtualDeviceBean_t *bean)
473 {
474 	char *path;
475 	int result = populate_LeafVirtualDeviceBean(
476 	    env, zhp, vdev, p_vdev_id, (LeafVirtualDeviceBean_t *)bean);
477 
478 	if (result) {
479 		/* Must not call any more Java methods to preserve exception */
480 		return (-1);
481 	}
482 
483 	/* Set path */
484 	result = nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path);
485 	if (result != 0) {
486 		zjni_throw_exception(env,
487 		    "could not retrieve path from disk virtual device "
488 		    "(pool %s)", zpool_get_name(zhp));
489 	} else {
490 
491 		regex_t re;
492 		regmatch_t matches[2];
493 		jstring pathUTF = NULL;
494 
495 		/* Strip off slice portion of name, if applicable */
496 		if (regcomp(&re, "^(/dev/dsk/.*)s[0-9]+$", REG_EXTENDED) == 0) {
497 			if (regexec(&re, path, 2, matches, 0) == 0) {
498 				regmatch_t *match = matches + 1;
499 				if (match->rm_so != -1 && match->rm_eo != -1) {
500 					char *tmp = strdup(path);
501 					if (tmp != NULL) {
502 						char *end = tmp + match->rm_eo;
503 						*end = '\0';
504 						pathUTF = (*env)->NewStringUTF(
505 						    env, tmp);
506 						free(tmp);
507 					}
508 				}
509 			}
510 			regfree(&re);
511 		}
512 
513 		if (pathUTF == NULL) {
514 			pathUTF = (*env)->NewStringUTF(env, path);
515 		}
516 
517 		(*env)->CallVoidMethod(env, ((zjni_Object_t *)bean)->object,
518 		    ((LeafVirtualDeviceBean_t *)bean)->method_setName, pathUTF);
519 	}
520 
521 	return (result != 0);
522 }
523 
524 static int
525 populate_SliceVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
526     nvlist_t *vdev, uint64_t *p_vdev_id, SliceVirtualDeviceBean_t *bean)
527 {
528 	char *path;
529 	int result = populate_LeafVirtualDeviceBean(
530 	    env, zhp, vdev, p_vdev_id, (LeafVirtualDeviceBean_t *)bean);
531 
532 	if (result) {
533 		/* Must not call any more Java methods to preserve exception */
534 		return (-1);
535 	}
536 
537 	/* Set path */
538 	result = nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path);
539 	if (result != 0) {
540 		zjni_throw_exception(env,
541 		    "could not retrieve path from slice virtual device (pool "
542 		    "%s)", zpool_get_name(zhp));
543 	} else {
544 
545 		jstring pathUTF = (*env)->NewStringUTF(env, path);
546 		(*env)->CallVoidMethod(env, ((zjni_Object_t *)bean)->object,
547 		    ((LeafVirtualDeviceBean_t *)bean)->method_setName,
548 		    pathUTF);
549 	}
550 
551 	return (result != 0);
552 }
553 
554 static int
555 populate_FileVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
556     nvlist_t *vdev, uint64_t *p_vdev_id, FileVirtualDeviceBean_t *bean)
557 {
558 	char *path;
559 	int result = populate_LeafVirtualDeviceBean(
560 	    env, zhp, vdev, p_vdev_id, (LeafVirtualDeviceBean_t *)bean);
561 
562 	if (result) {
563 		/* Must not call any more Java methods to preserve exception */
564 		return (-1);
565 	}
566 
567 	/* Set path */
568 	result = nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path);
569 	if (result != 0) {
570 		zjni_throw_exception(env,
571 		    "could not retrieve path from disk virtual device "
572 		    "(pool %s)", zpool_get_name(zhp));
573 	} else {
574 
575 		jstring pathUTF = (*env)->NewStringUTF(env, path);
576 		(*env)->CallVoidMethod(env, ((zjni_Object_t *)bean)->object,
577 		    ((LeafVirtualDeviceBean_t *)bean)->method_setName, pathUTF);
578 	}
579 
580 	return (result != 0);
581 }
582 
583 static int
584 populate_RAIDVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
585     nvlist_t *vdev, uint64_t *p_vdev_id, RAIDVirtualDeviceBean_t *bean)
586 {
587 	return (populate_VirtualDeviceBean(env, zhp, vdev, p_vdev_id,
588 	    (VirtualDeviceBean_t *)bean));
589 }
590 
591 static int
592 populate_MirrorVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
593     nvlist_t *vdev, uint64_t *p_vdev_id, MirrorVirtualDeviceBean_t *bean)
594 {
595 	return (populate_VirtualDeviceBean(env, zhp, vdev, p_vdev_id,
596 	    (VirtualDeviceBean_t *)bean));
597 }
598 
599 static jobject
600 create_ImportablePoolBean(JNIEnv *env, nvlist_t *config)
601 {
602 	int result;
603 	ImportablePoolBean_t bean_obj = {0};
604 	ImportablePoolBean_t *bean = &bean_obj;
605 
606 	/* Construct ImportablePoolBean */
607 	new_ImportablePoolBean(env, bean);
608 
609 	result = populate_ImportablePoolBean(env, bean, config);
610 	if (result) {
611 		/* Must not call any more Java methods to preserve exception */
612 		return (NULL);
613 	}
614 
615 	return (((zjni_Object_t *)bean)->object);
616 }
617 
618 static jobject
619 create_DiskVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
620     nvlist_t *vdev, uint64_t *p_vdev_id)
621 {
622 	int result;
623 	DiskVirtualDeviceBean_t bean_obj = {0};
624 	DiskVirtualDeviceBean_t *bean = &bean_obj;
625 
626 	/* Construct DiskVirtualDeviceBean */
627 	new_DiskVirtualDeviceBean(env, bean);
628 
629 	result = populate_DiskVirtualDeviceBean(
630 	    env, zhp, vdev, p_vdev_id, bean);
631 	if (result) {
632 		/* Must not call any more Java methods to preserve exception */
633 		return (NULL);
634 	}
635 
636 	return (((zjni_Object_t *)bean)->object);
637 }
638 
639 static jobject
640 create_SliceVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
641     nvlist_t *vdev, uint64_t *p_vdev_id)
642 {
643 	int result;
644 	SliceVirtualDeviceBean_t bean_obj = {0};
645 	SliceVirtualDeviceBean_t *bean = &bean_obj;
646 
647 	/* Construct SliceVirtualDeviceBean */
648 	new_SliceVirtualDeviceBean(env, bean);
649 
650 	result = populate_SliceVirtualDeviceBean(
651 	    env, zhp, vdev, p_vdev_id, bean);
652 	if (result) {
653 		/* Must not call any more Java methods to preserve exception */
654 		return (NULL);
655 	}
656 
657 	return (((zjni_Object_t *)bean)->object);
658 }
659 
660 static jobject
661 create_FileVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
662     nvlist_t *vdev, uint64_t *p_vdev_id)
663 {
664 	int result;
665 	FileVirtualDeviceBean_t bean_obj = {0};
666 	FileVirtualDeviceBean_t *bean = &bean_obj;
667 
668 	/* Construct FileVirtualDeviceBean */
669 	new_FileVirtualDeviceBean(env, bean);
670 
671 	result = populate_FileVirtualDeviceBean(
672 	    env, zhp, vdev, p_vdev_id, bean);
673 	if (result) {
674 		/* Must not call any more Java methods to preserve exception */
675 		return (NULL);
676 	}
677 
678 	return (((zjni_Object_t *)bean)->object);
679 }
680 
681 static jobject
682 create_RAIDVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
683     nvlist_t *vdev, uint64_t *p_vdev_id)
684 {
685 	int result;
686 	uint64_t parity;
687 	RAIDVirtualDeviceBean_t bean_obj = {0};
688 	RAIDVirtualDeviceBean_t *bean = &bean_obj;
689 
690 	((zjni_Object_t *)bean)->object = NULL;
691 
692 	/* Construct RAIDVirtualDeviceBean */
693 	new_RAIDVirtualDeviceBean(env, bean);
694 
695 	/* Set parity bit */
696 	result = nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_NPARITY,
697 	    &parity);
698 	if (result) {
699 		/* Default to RAID-Z1 in case of error */
700 		parity = 1;
701 	}
702 
703 	(*env)->CallVoidMethod(
704 	    env, ((zjni_Object_t *)bean)->object, bean->method_setParity,
705 	    (jlong)parity);
706 
707 
708 	result = populate_RAIDVirtualDeviceBean(
709 	    env, zhp, vdev, p_vdev_id, bean);
710 	if (result) {
711 		/* Must not call any more Java methods to preserve exception */
712 		return (NULL);
713 	}
714 
715 	return (((zjni_Object_t *)bean)->object);
716 }
717 
718 static jobject
719 create_MirrorVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
720     nvlist_t *vdev, uint64_t *p_vdev_id)
721 {
722 	int result;
723 	MirrorVirtualDeviceBean_t bean_obj = {0};
724 	MirrorVirtualDeviceBean_t *bean = &bean_obj;
725 
726 	/* Construct MirrorVirtualDeviceBean */
727 	new_MirrorVirtualDeviceBean(env, bean);
728 
729 	result = populate_MirrorVirtualDeviceBean(
730 	    env, zhp, vdev, p_vdev_id, bean);
731 	if (result) {
732 		/* Must not call any more Java methods to preserve exception */
733 		return (NULL);
734 	}
735 
736 	return (((zjni_Object_t *)bean)->object);
737 }
738 
739 static char *
740 find_field(const zjni_field_mapping_t *mapping, int value) {
741 	int i;
742 	for (i = 0; mapping[i].name != NULL; i++) {
743 		if (value == mapping[i].value) {
744 			return (mapping[i].name);
745 		}
746 	}
747 	return (NULL);
748 }
749 
750 /*
751  * Converts a vdev_state_t to a Java DeviceStats$DeviceState object.
752  */
753 static jobject
754 zjni_vdev_state_to_obj(JNIEnv *env, vdev_state_t state)
755 {
756 	return (zjni_int_to_enum(env, state,
757 	    ZFSJNI_PACKAGE_DATA "DeviceStats$DeviceState",
758 	    "VDEV_STATE_UNKNOWN", vdev_state_map));
759 }
760 
761 /*
762  * Converts a vdev_aux_t to a Java DeviceStats$DeviceStatus object.
763  */
764 static jobject
765 zjni_vdev_aux_to_obj(JNIEnv *env, vdev_aux_t aux)
766 {
767 	return (zjni_int_to_enum(env, aux,
768 	    ZFSJNI_PACKAGE_DATA "DeviceStats$DeviceStatus",
769 	    "VDEV_AUX_NONE", vdev_aux_map));
770 }
771 
772 /*
773  * Package-private functions
774  */
775 
776 /* Create a DeviceStatsBean */
777 void
778 new_DeviceStats(JNIEnv *env, DeviceStatsBean_t *bean, zjni_Object_t *object)
779 {
780 	bean->method_setSize = (*env)->GetMethodID(
781 	    env, object->class, "setSize", "(J)V");
782 
783 	bean->method_setReplacementSize = (*env)->GetMethodID(
784 	    env, object->class, "setReplacementSize", "(J)V");
785 
786 	bean->method_setUsed = (*env)->GetMethodID(
787 	    env, object->class, "setUsed", "(J)V");
788 
789 	bean->method_setReadBytes = (*env)->GetMethodID(
790 	    env, object->class, "setReadBytes", "(J)V");
791 
792 	bean->method_setWriteBytes = (*env)->GetMethodID(
793 	    env, object->class, "setWriteBytes", "(J)V");
794 
795 	bean->method_setReadOperations = (*env)->GetMethodID(
796 	    env, object->class, "setReadOperations", "(J)V");
797 
798 	bean->method_setWriteOperations = (*env)->GetMethodID(
799 	    env, object->class, "setWriteOperations", "(J)V");
800 
801 	bean->method_setReadErrors = (*env)->GetMethodID(
802 	    env, object->class, "setReadErrors", "(J)V");
803 
804 	bean->method_setWriteErrors = (*env)->GetMethodID(
805 	    env, object->class, "setWriteErrors", "(J)V");
806 
807 	bean->method_setChecksumErrors = (*env)->GetMethodID(
808 	    env, object->class, "setChecksumErrors", "(J)V");
809 
810 	bean->method_setDeviceState = (*env)->GetMethodID(
811 	    env, object->class, "setDeviceState",
812 	    "(L" ZFSJNI_PACKAGE_DATA "DeviceStats$DeviceState;)V");
813 
814 	bean->method_setDeviceStatus = (*env)->GetMethodID(
815 	    env, object->class, "setDeviceStatus",
816 	    "(L" ZFSJNI_PACKAGE_DATA "DeviceStats$DeviceStatus;)V");
817 }
818 
819 /* Create a PoolStatsBean */
820 void
821 new_PoolStats(JNIEnv *env, PoolStatsBean_t *bean, zjni_Object_t *object)
822 {
823 	new_DeviceStats(env, (DeviceStatsBean_t *)bean, object);
824 
825 	bean->method_setPoolState = (*env)->GetMethodID(
826 	    env, object->class, "setPoolState",
827 	    "(L" ZFSJNI_PACKAGE_DATA "PoolStats$PoolState;)V");
828 
829 	bean->method_setPoolStatus = (*env)->GetMethodID(
830 	    env, object->class, "setPoolStatus",
831 	    "(L" ZFSJNI_PACKAGE_DATA "PoolStats$PoolStatus;)V");
832 
833 	bean->method_setPoolVersion = (*env)->GetMethodID(
834 	    env, object->class, "setPoolVersion", "(J)V");
835 }
836 
837 /*
838  * Gets the root vdev (an nvlist_t *) for the given pool.
839  */
840 nvlist_t *
841 zjni_get_root_vdev(zpool_handle_t *zhp)
842 {
843 	nvlist_t *root = NULL;
844 
845 	if (zhp != NULL) {
846 		nvlist_t *attrs = zpool_get_config(zhp, NULL);
847 
848 		if (attrs != NULL) {
849 			int result = nvlist_lookup_nvlist(
850 			    attrs, ZPOOL_CONFIG_VDEV_TREE, &root);
851 			if (result != 0) {
852 				root = NULL;
853 			}
854 		}
855 	}
856 
857 	return (root);
858 }
859 
860 /*
861  * Gets the vdev (an nvlist_t *) with the given vdev_id, below the
862  * given vdev.  If the given vdev is NULL, all vdevs within the given
863  * pool are searched.
864  *
865  * If p_vdev_id is not NULL, it will be set to the ID of the parent
866  * vdev, if any, or to vdev_id_to_find if the searched-for vdev is a
867  * toplevel vdev.
868  */
869 nvlist_t *
870 zjni_get_vdev(zpool_handle_t *zhp, nvlist_t *vdev_parent,
871     uint64_t vdev_id_to_find, uint64_t *p_vdev_id)
872 {
873 	int result;
874 	uint64_t id = vdev_id_to_find;
875 
876 	/* Was a vdev specified? */
877 	if (vdev_parent == NULL) {
878 		/* No -- retrieve the top-level pool vdev */
879 		vdev_parent = zjni_get_root_vdev(zhp);
880 	} else {
881 		/* Get index of this vdev and compare with vdev_id_to_find */
882 		result = nvlist_lookup_uint64(
883 		    vdev_parent, ZPOOL_CONFIG_GUID, &id);
884 		if (result == 0 && id == vdev_id_to_find) {
885 			return (vdev_parent);
886 		}
887 	}
888 
889 	if (vdev_parent != NULL) {
890 
891 		nvlist_t **children;
892 		uint_t nelem = 0;
893 
894 		/* Get the vdevs under this vdev */
895 		result = nvlist_lookup_nvlist_array(
896 		    vdev_parent, ZPOOL_CONFIG_CHILDREN, &children, &nelem);
897 
898 		if (result == 0) {
899 
900 			int i;
901 			nvlist_t *child;
902 
903 			/* For each vdev child... */
904 			for (i = 0; i < nelem; i++) {
905 				if (p_vdev_id != NULL) {
906 					/* Save parent vdev id */
907 					*p_vdev_id = id;
908 				}
909 
910 				child = zjni_get_vdev(zhp, children[i],
911 				    vdev_id_to_find, p_vdev_id);
912 				if (child != NULL) {
913 					return (child);
914 				}
915 			}
916 		}
917 	}
918 
919 	return (NULL);
920 }
921 
922 jobject
923 zjni_get_VirtualDevice_from_vdev(JNIEnv *env, zpool_handle_t *zhp,
924     nvlist_t *vdev, uint64_t *p_vdev_id)
925 {
926 	jobject obj = NULL;
927 	char *type = NULL;
928 	int result = nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE, &type);
929 
930 	if (result == 0) {
931 		if (strcmp(type, VDEV_TYPE_DISK) == 0) {
932 			uint64_t wholedisk;
933 			if (nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
934 			    &wholedisk) == 0 && wholedisk) {
935 				obj = create_DiskVirtualDeviceBean(
936 				    env, zhp, vdev, p_vdev_id);
937 			} else {
938 				obj = create_SliceVirtualDeviceBean(
939 				    env, zhp, vdev, p_vdev_id);
940 			}
941 		} else if (strcmp(type, VDEV_TYPE_FILE) == 0) {
942 			obj = create_FileVirtualDeviceBean(
943 			    env, zhp, vdev, p_vdev_id);
944 		} else if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
945 			obj = create_RAIDVirtualDeviceBean(
946 			    env, zhp, vdev, p_vdev_id);
947 		} else if (strcmp(type, VDEV_TYPE_MIRROR) == 0) {
948 			obj = create_MirrorVirtualDeviceBean(
949 			    env, zhp, vdev, p_vdev_id);
950 		} else if (strcmp(type, VDEV_TYPE_REPLACING) == 0) {
951 
952 			/* Get the vdevs under this vdev */
953 			nvlist_t **children;
954 			uint_t nelem = 0;
955 			int result = nvlist_lookup_nvlist_array(
956 			    vdev, ZPOOL_CONFIG_CHILDREN, &children, &nelem);
957 
958 			if (result == 0 && nelem > 0) {
959 
960 				/* Get last vdev child (replacement device) */
961 				nvlist_t *child = children[nelem - 1];
962 
963 				obj = zjni_get_VirtualDevice_from_vdev(env,
964 				    zhp, child, p_vdev_id);
965 			}
966 		}
967 	}
968 
969 	return (obj);
970 }
971 
972 jobject
973 zjni_get_VirtualDevices_from_vdev(JNIEnv *env, zpool_handle_t *zhp,
974     nvlist_t *vdev_parent, uint64_t *p_vdev_id)
975 {
976 	/* Create an array list for the vdevs */
977 	zjni_ArrayList_t list_class = {0};
978 	zjni_ArrayList_t *list_class_p = &list_class;
979 	zjni_new_ArrayList(env, list_class_p);
980 
981 	/* Was a vdev specified? */
982 	if (vdev_parent == NULL) {
983 		/* No -- retrieve the top-level pool vdev */
984 		vdev_parent = zjni_get_root_vdev(zhp);
985 	}
986 
987 	if (vdev_parent != NULL) {
988 
989 		/* Get the vdevs under this vdev */
990 		nvlist_t **children;
991 		uint_t nelem = 0;
992 		int result = nvlist_lookup_nvlist_array(
993 		    vdev_parent, ZPOOL_CONFIG_CHILDREN, &children, &nelem);
994 
995 		if (result == 0) {
996 
997 			/* For each vdev child... */
998 			int i;
999 			for (i = 0; i < nelem; i++) {
1000 				nvlist_t *child = children[i];
1001 
1002 				/* Create a Java object from this vdev */
1003 				jobject obj =
1004 				    zjni_get_VirtualDevice_from_vdev(env,
1005 				    zhp, child, p_vdev_id);
1006 
1007 				if ((*env)->ExceptionOccurred(env) != NULL) {
1008 					/*
1009 					 * Must not call any more Java methods
1010 					 * to preserve exception
1011 					 */
1012 					return (NULL);
1013 				}
1014 
1015 				if (obj != NULL) {
1016 				    /* Add child to child vdev list */
1017 					(*env)->CallBooleanMethod(env,
1018 					    ((zjni_Object_t *)
1019 					    list_class_p)->object,
1020 					    ((zjni_Collection_t *)
1021 					    list_class_p)->method_add, obj);
1022 				}
1023 			}
1024 		}
1025 	}
1026 
1027 	return (zjni_Collection_to_array(
1028 	    env, (zjni_Collection_t *)list_class_p,
1029 	    ZFSJNI_PACKAGE_DATA "VirtualDevice"));
1030 }
1031 
1032 int
1033 zjni_create_add_ImportablePool(nvlist_t *config, void *data) {
1034 
1035 	JNIEnv *env = ((zjni_ArrayCallbackData_t *)data)->env;
1036 	zjni_Collection_t *list = ((zjni_ArrayCallbackData_t *)data)->list;
1037 
1038 	/* Construct ImportablePool object */
1039 	jobject bean = create_ImportablePoolBean(env, config);
1040 	if (bean == NULL) {
1041 		return (-1);
1042 	}
1043 
1044 	/* Add bean to list */
1045 	(*env)->CallBooleanMethod(env, ((zjni_Object_t *)list)->object,
1046 	    ((zjni_Collection_t *)list)->method_add, bean);
1047 
1048 	return (0);
1049 }
1050 
1051 int
1052 populate_DeviceStatsBean(JNIEnv *env, nvlist_t *vdev,
1053     DeviceStatsBean_t *bean, zjni_Object_t *object)
1054 {
1055 	uint_t c;
1056 	vdev_stat_t *vs;
1057 
1058 	int result = nvlist_lookup_uint64_array(
1059 	    vdev, ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &c);
1060 	if (result != 0) {
1061 		zjni_throw_exception(env,
1062 		    "could not retrieve virtual device statistics");
1063 		return (1);
1064 	}
1065 
1066 	(*env)->CallVoidMethod(env, object->object,
1067 	    bean->method_setUsed, (jlong)vs->vs_alloc);
1068 
1069 	(*env)->CallVoidMethod(env, object->object,
1070 	    bean->method_setSize, (jlong)vs->vs_space);
1071 
1072 	(*env)->CallVoidMethod(env, object->object,
1073 	    bean->method_setReplacementSize, (jlong)vs->vs_rsize);
1074 
1075 	(*env)->CallVoidMethod(env, object->object,
1076 	    bean->method_setReadBytes, (jlong)vs->vs_bytes[ZIO_TYPE_READ]);
1077 
1078 	(*env)->CallVoidMethod(env, object->object,
1079 	    bean->method_setWriteBytes, (jlong)vs->vs_bytes[ZIO_TYPE_WRITE]);
1080 
1081 	(*env)->CallVoidMethod(env, object->object,
1082 	    bean->method_setReadOperations, (jlong)vs->vs_ops[ZIO_TYPE_READ]);
1083 
1084 	(*env)->CallVoidMethod(env, object->object,
1085 	    bean->method_setWriteOperations, (jlong)vs->vs_ops[ZIO_TYPE_WRITE]);
1086 
1087 	(*env)->CallVoidMethod(env, object->object,
1088 	    bean->method_setReadErrors, (jlong)vs->vs_read_errors);
1089 
1090 	(*env)->CallVoidMethod(env, object->object,
1091 	    bean->method_setWriteErrors, (jlong)vs->vs_write_errors);
1092 
1093 	(*env)->CallVoidMethod(env, object->object,
1094 	    bean->method_setChecksumErrors, (jlong)vs->vs_checksum_errors);
1095 
1096 	(*env)->CallVoidMethod(env, object->object,
1097 	    bean->method_setDeviceState,
1098 	    zjni_vdev_state_to_obj(env, vs->vs_state));
1099 
1100 	(*env)->CallVoidMethod(env, object->object,
1101 	    bean->method_setDeviceStatus,
1102 	    zjni_vdev_aux_to_obj(env, vs->vs_aux));
1103 
1104 	return (0);
1105 }
1106 
1107 /*
1108  * Converts a pool_state_t to a Java PoolStats$PoolState object.
1109  */
1110 jobject
1111 zjni_pool_state_to_obj(JNIEnv *env, pool_state_t state)
1112 {
1113 	return (zjni_int_to_enum(env, state,
1114 	    ZFSJNI_PACKAGE_DATA "PoolStats$PoolState",
1115 	    "POOL_STATE_ACTIVE", pool_state_map));
1116 }
1117 
1118 /*
1119  * Converts a zpool_status_t to a Java PoolStats$PoolStatus object.
1120  */
1121 jobject
1122 zjni_pool_status_to_obj(JNIEnv *env, zpool_status_t status)
1123 {
1124 	return (zjni_int_to_enum(env, status,
1125 	    ZFSJNI_PACKAGE_DATA "PoolStats$PoolStatus",
1126 	    "ZPOOL_STATUS_OK", zpool_status_map));
1127 }
1128 
1129 /*
1130  * Extern functions
1131  */
1132 
1133 /*
1134  * Iterates through each importable pool on the system.  For each
1135  * importable pool, runs the given function with the given void as the
1136  * last arg.
1137  */
1138 int
1139 zjni_ipool_iter(int argc, char **argv, zjni_ipool_iter_f func, void *data)
1140 {
1141 	nvlist_t *pools = zpool_find_import(g_zfs, argc, argv);
1142 
1143 	if (pools != NULL) {
1144 		nvpair_t *elem = NULL;
1145 
1146 		while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1147 			nvlist_t *config;
1148 
1149 			if (nvpair_value_nvlist(elem, &config) != 0 ||
1150 			    func(config, data)) {
1151 				return (-1);
1152 			}
1153 		}
1154 	}
1155 
1156 	return (0);
1157 }
1158 
1159 char *
1160 zjni_vdev_state_to_str(vdev_state_t state) {
1161 	return (find_field(vdev_state_map, state));
1162 }
1163 
1164 char *
1165 zjni_vdev_aux_to_str(vdev_aux_t aux) {
1166 	return (find_field(vdev_aux_map, aux));
1167 }
1168 
1169 char *
1170 zjni_pool_state_to_str(pool_state_t state) {
1171 	return (find_field(pool_state_map, state));
1172 }
1173 
1174 char *
1175 zjni_pool_status_to_str(zpool_status_t status) {
1176 	return (find_field(zpool_status_map, status));
1177 }
1178