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