xref: /illumos-gate/usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c (revision 43d18f1c320355e93c47399bea0b2e022fe06364)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 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_pool.h"
30 #include "libzfs_jni_util.h"
31 #include <strings.h>
32 
33 /*
34  * Types
35  */
36 
37 typedef struct ImportablePoolBean {
38 	zjni_Object_t super;
39 
40 	jmethodID method_setName;
41 	jmethodID method_setId;
42 	jmethodID method_setState;
43 	jmethodID method_setHealth;
44 } ImportablePoolBean_t;
45 
46 typedef struct VirtualDeviceBean {
47 	zjni_Object_t super;
48 
49 	jmethodID method_setPoolName;
50 	jmethodID method_setIndex;
51 	jmethodID method_setSize;
52 	jmethodID method_setUsed;
53 } VirtualDeviceBean_t;
54 
55 typedef struct DiskVirtualDeviceBean {
56 	VirtualDeviceBean_t super;
57 
58 	jmethodID method_setDiskName;
59 } DiskVirtualDeviceBean_t;
60 
61 typedef struct FileVirtualDeviceBean {
62 	VirtualDeviceBean_t super;
63 
64 	jmethodID method_setFileName;
65 } FileVirtualDeviceBean_t;
66 
67 typedef struct RAIDVirtualDeviceBean {
68 	VirtualDeviceBean_t super;
69 } RAIDVirtualDeviceBean_t;
70 
71 typedef struct MirrorVirtualDeviceBean {
72 	VirtualDeviceBean_t super;
73 } MirrorVirtualDeviceBean_t;
74 
75 /*
76  * Function prototypes
77  */
78 
79 static void new_ImportablePoolBean(JNIEnv *, ImportablePoolBean_t *);
80 static void new_VirtualDevice(JNIEnv *, VirtualDeviceBean_t *);
81 static void new_DiskVirtualDeviceBean(JNIEnv *, DiskVirtualDeviceBean_t *);
82 static void new_FileVirtualDeviceBean(JNIEnv *, FileVirtualDeviceBean_t *);
83 static void new_RAIDVirtualDeviceBean(JNIEnv *, RAIDVirtualDeviceBean_t *);
84 static void new_MirrorVirtualDeviceBean(JNIEnv *, MirrorVirtualDeviceBean_t *);
85 static jobject uint64_to_state(JNIEnv *, uint64_t);
86 static int populate_ImportablePoolBean(
87     JNIEnv *, ImportablePoolBean_t *, char *, uint64_t, uint64_t, char *);
88 static int populate_VirtualDeviceBean(
89     JNIEnv *, zpool_handle_t *, nvlist_t *, VirtualDeviceBean_t *);
90 static int populate_DiskVirtualDeviceBean(
91     JNIEnv *, zpool_handle_t *, nvlist_t *, DiskVirtualDeviceBean_t *);
92 static int populate_FileVirtualDeviceBean(
93     JNIEnv *, zpool_handle_t *, nvlist_t *, FileVirtualDeviceBean_t *);
94 static int populate_RAIDVirtualDeviceBean(
95     JNIEnv *, zpool_handle_t *, nvlist_t *, RAIDVirtualDeviceBean_t *);
96 static int populate_MirrorVirtualDeviceBean(
97     JNIEnv *, zpool_handle_t *, nvlist_t *, MirrorVirtualDeviceBean_t *);
98 static jobject create_ImportablePoolBean(
99     JNIEnv *, char *, uint64_t, uint64_t, char *);
100 static jobject create_DiskVirtualDeviceBean(
101     JNIEnv *, zpool_handle_t *, nvlist_t *);
102 static jobject create_FileVirtualDeviceBean(
103     JNIEnv *, zpool_handle_t *, nvlist_t *);
104 static jobject create_RAIDVirtualDeviceBean(
105     JNIEnv *, zpool_handle_t *, nvlist_t *);
106 static jobject create_MirrorVirtualDeviceBean(
107     JNIEnv *, zpool_handle_t *, nvlist_t *);
108 
109 /*
110  * Static functions
111  */
112 
113 /* Create a ImportablePoolBean */
114 static void
115 new_ImportablePoolBean(JNIEnv *env, ImportablePoolBean_t *bean)
116 {
117 	zjni_Object_t *object = (zjni_Object_t *)bean;
118 
119 	if (object->object == NULL) {
120 		object->class =
121 		    (*env)->FindClass(env,
122 			ZFSJNI_PACKAGE_DATA "ImportablePoolBean");
123 
124 		object->constructor =
125 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
126 
127 		object->object =
128 		    (*env)->NewObject(env, object->class, object->constructor);
129 	}
130 
131 	bean->method_setName = (*env)->GetMethodID(
132 	    env, object->class, "setName", "(Ljava/lang/String;)V");
133 
134 	bean->method_setId = (*env)->GetMethodID(
135 	    env, object->class, "setId", "(J)V");
136 
137 	bean->method_setState = (*env)->GetMethodID(
138 	    env, object->class, "setState",
139 	    "(L" ZFSJNI_PACKAGE_DATA "ImportablePool$State;)V");
140 
141 	bean->method_setHealth = (*env)->GetMethodID(
142 	    env, object->class, "setHealth", "(Ljava/lang/String;)V");
143 }
144 
145 /* Create a VirtualDeviceBean */
146 static void
147 new_VirtualDevice(JNIEnv *env, VirtualDeviceBean_t *bean)
148 {
149 	zjni_Object_t *object = (zjni_Object_t *)bean;
150 
151 	if (object->object == NULL) {
152 		object->class =
153 		    (*env)->FindClass(env,
154 			ZFSJNI_PACKAGE_DATA "VirtualDeviceBean");
155 
156 		object->constructor =
157 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
158 
159 		object->object =
160 		    (*env)->NewObject(env, object->class, object->constructor);
161 	}
162 
163 	bean->method_setPoolName = (*env)->GetMethodID(
164 	    env, object->class, "setPoolName", "(Ljava/lang/String;)V");
165 
166 	bean->method_setIndex = (*env)->GetMethodID(
167 	    env, object->class, "setIndex", "(J)V");
168 
169 	bean->method_setSize = (*env)->GetMethodID(
170 	    env, object->class, "setSize", "(J)V");
171 
172 	bean->method_setUsed = (*env)->GetMethodID(
173 	    env, object->class, "setUsed", "(J)V");
174 }
175 
176 /* Create a DiskVirtualDeviceBean */
177 static void
178 new_DiskVirtualDeviceBean(JNIEnv *env, DiskVirtualDeviceBean_t *bean)
179 {
180 	zjni_Object_t *object = (zjni_Object_t *)bean;
181 
182 	if (object->object == NULL) {
183 		object->class = (*env)->FindClass(
184 		    env, ZFSJNI_PACKAGE_DATA "DiskVirtualDeviceBean");
185 
186 		object->constructor =
187 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
188 
189 		object->object =
190 		    (*env)->NewObject(env, object->class, object->constructor);
191 	}
192 
193 	new_VirtualDevice(env, (VirtualDeviceBean_t *)bean);
194 
195 	bean->method_setDiskName = (*env)->GetMethodID(
196 	    env, object->class, "setDiskName", "(Ljava/lang/String;)V");
197 
198 }
199 
200 /* Create a FileVirtualDeviceBean */
201 static void
202 new_FileVirtualDeviceBean(JNIEnv *env, FileVirtualDeviceBean_t *bean)
203 {
204 	zjni_Object_t *object = (zjni_Object_t *)bean;
205 
206 	if (object->object == NULL) {
207 		object->class = (*env)->FindClass(
208 		    env, ZFSJNI_PACKAGE_DATA "FileVirtualDeviceBean");
209 
210 		object->constructor =
211 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
212 
213 		object->object =
214 		    (*env)->NewObject(env, object->class, object->constructor);
215 	}
216 
217 	new_VirtualDevice(env, (VirtualDeviceBean_t *)bean);
218 
219 	bean->method_setFileName = (*env)->GetMethodID(
220 	    env, object->class, "setFileName", "(Ljava/lang/String;)V");
221 }
222 
223 /* Create a RAIDVirtualDeviceBean */
224 static void
225 new_RAIDVirtualDeviceBean(JNIEnv *env, RAIDVirtualDeviceBean_t *bean)
226 {
227 	zjni_Object_t *object = (zjni_Object_t *)bean;
228 
229 	if (object->object == NULL) {
230 
231 		object->class = (*env)->FindClass(
232 		    env, ZFSJNI_PACKAGE_DATA "RAIDVirtualDeviceBean");
233 
234 		object->constructor =
235 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
236 
237 		object->object =
238 		    (*env)->NewObject(env, object->class, object->constructor);
239 	}
240 
241 	new_VirtualDevice(env, (VirtualDeviceBean_t *)bean);
242 }
243 
244 /* Create a MirrorVirtualDeviceBean */
245 static void
246 new_MirrorVirtualDeviceBean(JNIEnv *env, MirrorVirtualDeviceBean_t *bean)
247 {
248 	zjni_Object_t *object = (zjni_Object_t *)bean;
249 
250 	if (object->object == NULL) {
251 		object->class = (*env)->FindClass(
252 		    env, ZFSJNI_PACKAGE_DATA "MirrorVirtualDeviceBean");
253 
254 		object->constructor =
255 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
256 
257 		object->object =
258 		    (*env)->NewObject(env, object->class, object->constructor);
259 	}
260 
261 	new_VirtualDevice(env, (VirtualDeviceBean_t *)bean);
262 }
263 
264 static jobject
265 uint64_to_state(JNIEnv *env, uint64_t pool_state)
266 {
267 	jobject state_obj;
268 
269 	jclass class_State = (*env)->FindClass(
270 	    env, ZFSJNI_PACKAGE_DATA "ImportablePool$State");
271 
272 	jmethodID method_valueOf = (*env)->GetStaticMethodID(
273 	    env, class_State, "valueOf",
274 	    "(Ljava/lang/String;)L"
275 	    ZFSJNI_PACKAGE_DATA "ImportablePool$State;");
276 
277 	char *str = zjni_get_state_str(pool_state);
278 	if (str != NULL) {
279 	    jstring utf = (*env)->NewStringUTF(env, str);
280 
281 	    state_obj = (*env)->CallStaticObjectMethod(
282 		env, class_State, method_valueOf, utf);
283 	}
284 
285 	return (state_obj);
286 }
287 
288 static int
289 populate_ImportablePoolBean(JNIEnv *env, ImportablePoolBean_t *bean,
290     char *name, uint64_t guid, uint64_t pool_state, char *health)
291 {
292 	zjni_Object_t *object = (zjni_Object_t *)bean;
293 
294 	/* Set name */
295 	(*env)->CallVoidMethod(env, object->object, bean->method_setName,
296 	    (*env)->NewStringUTF(env, name));
297 
298 	/* Set state */
299 	(*env)->CallVoidMethod(
300 	    env, object->object, bean->method_setState,
301 	    uint64_to_state(env, pool_state));
302 
303 	/* Set guid */
304 	(*env)->CallVoidMethod(
305 	    env, object->object, bean->method_setId, (jlong)guid);
306 
307 	/* Set health */
308 	(*env)->CallVoidMethod(env, object->object, bean->method_setHealth,
309 	    (*env)->NewStringUTF(env, health));
310 
311 	return (0);
312 }
313 
314 static int
315 populate_VirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
316     nvlist_t *vdev, VirtualDeviceBean_t *bean)
317 {
318 	int result;
319 	uint64_t vdev_id;
320 	zjni_Object_t *object = (zjni_Object_t *)bean;
321 
322 	/* Set pool name */
323 	jstring poolUTF = (*env)->NewStringUTF(env, zpool_get_name(zhp));
324 	(*env)->CallVoidMethod(
325 	    env, object->object, bean->method_setPoolName, poolUTF);
326 
327 	/* Get index */
328 	result = nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &vdev_id);
329 	if (result != 0) {
330 		zjni_throw_exception(env,
331 		    "could not retrieve virtual device ID (pool %s)",
332 		    zpool_get_name(zhp));
333 	} else {
334 
335 		uint64_t used;
336 		uint64_t total;
337 
338 		(*env)->CallVoidMethod(
339 		    env, object->object, bean->method_setIndex, (jlong)vdev_id);
340 
341 		/* Set used space */
342 		used = zpool_get_space_used(zhp);
343 
344 		(*env)->CallVoidMethod(
345 		    env, object->object, bean->method_setUsed, (jlong)used);
346 
347 		/* Set available space */
348 		total = zpool_get_space_total(zhp);
349 
350 		(*env)->CallVoidMethod(
351 		    env, object->object, bean->method_setSize, (jlong)total);
352 	}
353 
354 	return (result != 0);
355 }
356 
357 static int
358 populate_DiskVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
359     nvlist_t *vdev, DiskVirtualDeviceBean_t *bean)
360 {
361 	char *path;
362 	int result = populate_VirtualDeviceBean(
363 	    env, zhp, vdev, (VirtualDeviceBean_t *)bean);
364 
365 	if (result) {
366 		/* Must not call any more Java methods to preserve exception */
367 		return (-1);
368 	}
369 
370 	/* Set path */
371 	result = nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path);
372 	if (result != 0) {
373 		zjni_throw_exception(env,
374 		    "could not retrive path from disk virtual device (pool %s)",
375 		    zpool_get_name(zhp));
376 	} else {
377 
378 		jstring pathUTF = (*env)->NewStringUTF(env, path);
379 		(*env)->CallVoidMethod(env, ((zjni_Object_t *)bean)->object,
380 		    bean->method_setDiskName, pathUTF);
381 	}
382 
383 	return (result != 0);
384 }
385 
386 static int
387 populate_FileVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
388     nvlist_t *vdev, FileVirtualDeviceBean_t *bean)
389 {
390 	char *path;
391 	int result = populate_VirtualDeviceBean(
392 	    env, zhp, vdev, (VirtualDeviceBean_t *)bean);
393 
394 	if (result) {
395 		/* Must not call any more Java methods to preserve exception */
396 		return (-1);
397 	}
398 
399 	/* Set path */
400 	result = nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path);
401 	if (result != 0) {
402 		zjni_throw_exception(env,
403 		    "could not retrive path from disk virtual device (pool %s)",
404 		    zpool_get_name(zhp));
405 	} else {
406 
407 		jstring pathUTF = (*env)->NewStringUTF(env, path);
408 		(*env)->CallVoidMethod(env, ((zjni_Object_t *)bean)->object,
409 		    bean->method_setFileName, pathUTF);
410 	}
411 
412 	return (result != 0);
413 }
414 
415 static int
416 populate_RAIDVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
417     nvlist_t *vdev, RAIDVirtualDeviceBean_t *bean)
418 {
419 	return (populate_VirtualDeviceBean(env, zhp, vdev,
420 	    (VirtualDeviceBean_t *)bean));
421 }
422 
423 static int
424 populate_MirrorVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
425     nvlist_t *vdev, MirrorVirtualDeviceBean_t *bean)
426 {
427 	return (populate_VirtualDeviceBean(env, zhp, vdev,
428 	    (VirtualDeviceBean_t *)bean));
429 }
430 
431 static jobject
432 create_ImportablePoolBean(JNIEnv *env, char *name,
433     uint64_t guid, uint64_t pool_state, char *health)
434 {
435 	int result;
436 	ImportablePoolBean_t bean_obj = {0};
437 	ImportablePoolBean_t *bean = &bean_obj;
438 
439 	/* Construct ImportablePoolBean */
440 	new_ImportablePoolBean(env, bean);
441 
442 	result = populate_ImportablePoolBean(
443 	    env, bean, name, guid, pool_state, health);
444 	if (result) {
445 		/* Must not call any more Java methods to preserve exception */
446 		return (NULL);
447 	}
448 
449 	return (((zjni_Object_t *)bean)->object);
450 }
451 
452 static jobject
453 create_DiskVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp, nvlist_t *vdev)
454 {
455 	int result;
456 	DiskVirtualDeviceBean_t bean_obj = {0};
457 	DiskVirtualDeviceBean_t *bean = &bean_obj;
458 
459 	/* Construct DiskVirtualDeviceBean */
460 	new_DiskVirtualDeviceBean(env, bean);
461 
462 	result = populate_DiskVirtualDeviceBean(env, zhp, vdev, bean);
463 	if (result) {
464 		/* Must not call any more Java methods to preserve exception */
465 		return (NULL);
466 	}
467 
468 	return (((zjni_Object_t *)bean)->object);
469 }
470 
471 static jobject
472 create_FileVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp, nvlist_t *vdev)
473 {
474 	int result;
475 	FileVirtualDeviceBean_t bean_obj = {0};
476 	FileVirtualDeviceBean_t *bean = &bean_obj;
477 
478 	/* Construct FileVirtualDeviceBean */
479 	new_FileVirtualDeviceBean(env, bean);
480 
481 	result = populate_FileVirtualDeviceBean(env, zhp, vdev, bean);
482 	if (result) {
483 		/* Must not call any more Java methods to preserve exception */
484 		return (NULL);
485 	}
486 
487 	return (((zjni_Object_t *)bean)->object);
488 }
489 
490 static jobject
491 create_RAIDVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp, nvlist_t *vdev)
492 {
493 	int result;
494 	RAIDVirtualDeviceBean_t bean_obj = {0};
495 	RAIDVirtualDeviceBean_t *bean = &bean_obj;
496 
497 	((zjni_Object_t *)bean)->object = NULL;
498 
499 	/* Construct RAIDVirtualDeviceBean */
500 	new_RAIDVirtualDeviceBean(env, bean);
501 
502 	result = populate_RAIDVirtualDeviceBean(env, zhp, vdev, bean);
503 	if (result) {
504 		/* Must not call any more Java methods to preserve exception */
505 		return (NULL);
506 	}
507 
508 	return (((zjni_Object_t *)bean)->object);
509 }
510 
511 static jobject
512 create_MirrorVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp, nvlist_t *vdev)
513 {
514 	int result;
515 	MirrorVirtualDeviceBean_t bean_obj = {0};
516 	MirrorVirtualDeviceBean_t *bean = &bean_obj;
517 
518 	/* Construct MirrorVirtualDeviceBean */
519 	new_MirrorVirtualDeviceBean(env, bean);
520 
521 	result = populate_MirrorVirtualDeviceBean(env, zhp, vdev, bean);
522 	if (result) {
523 		/* Must not call any more Java methods to preserve exception */
524 		return (NULL);
525 	}
526 
527 	return (((zjni_Object_t *)bean)->object);
528 }
529 
530 /*
531  * Package-private functions
532  */
533 
534 /*
535  * Gets the root vdev (an nvlist_t *) for the given pool.
536  */
537 nvlist_t *
538 zjni_get_root_vdev(zpool_handle_t *zhp)
539 {
540 	nvlist_t *root = NULL;
541 
542 	if (zhp != NULL) {
543 		nvlist_t *attrs = zpool_get_config(zhp, NULL);
544 
545 		if (attrs != NULL) {
546 			int result = nvlist_lookup_nvlist(
547 			    attrs, ZPOOL_CONFIG_VDEV_TREE, &root);
548 			if (result != 0) {
549 				root = NULL;
550 			}
551 		}
552 	}
553 
554 	return (root);
555 }
556 
557 /*
558  * Gets the vdev (an nvlist_t *) with the given vdev_id, below the
559  * given vdev.  If the given vdev is NULL, all vdevs within the given
560  * pool are searched.
561  */
562 nvlist_t *
563 zjni_get_vdev(zpool_handle_t *zhp, nvlist_t *vdev_parent,
564     uint64_t vdev_id_to_find)
565 {
566 	int result;
567 
568 	/* Was a vdev specified? */
569 	if (vdev_parent == NULL) {
570 		/* No -- retrieve the top-level pool vdev */
571 		vdev_parent = zjni_get_root_vdev(zhp);
572 	} else {
573 		/* Get index of this vdev and compare with vdev_id_to_find */
574 		uint64_t id;
575 		result = nvlist_lookup_uint64(
576 		    vdev_parent, ZPOOL_CONFIG_GUID, &id);
577 		if (result == 0 && id == vdev_id_to_find) {
578 			return (vdev_parent);
579 		}
580 	}
581 
582 	if (vdev_parent != NULL) {
583 
584 		nvlist_t **children;
585 		uint_t nelem = 0;
586 
587 		/* Get the vdevs under this vdev */
588 		result = nvlist_lookup_nvlist_array(
589 		    vdev_parent, ZPOOL_CONFIG_CHILDREN, &children, &nelem);
590 
591 		if (result == 0) {
592 
593 			int i;
594 			nvlist_t *child;
595 
596 			/* For each vdev child... */
597 			for (i = 0; i < nelem; i++) {
598 				child = zjni_get_vdev(zhp, children[i],
599 				    vdev_id_to_find);
600 				if (child != NULL) {
601 					return (child);
602 				}
603 			}
604 		}
605 	}
606 
607 	return (NULL);
608 }
609 
610 jobject
611 zjni_get_VirtualDevice_from_vdev(JNIEnv *env, zpool_handle_t *zhp,
612     nvlist_t *vdev)
613 {
614 	jobject obj = NULL;
615 	char *type = NULL;
616 	int result = nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE, &type);
617 
618 	if (result == 0) {
619 		if (strcmp(type, VDEV_TYPE_DISK) == 0) {
620 			obj = create_DiskVirtualDeviceBean(env, zhp, vdev);
621 		} else if (strcmp(type, VDEV_TYPE_FILE) == 0) {
622 			obj = create_FileVirtualDeviceBean(env, zhp, vdev);
623 		} else if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
624 			obj = create_RAIDVirtualDeviceBean(env, zhp, vdev);
625 		} else if (strcmp(type, VDEV_TYPE_MIRROR) == 0) {
626 			obj = create_MirrorVirtualDeviceBean(env, zhp, vdev);
627 		} else if (strcmp(type, VDEV_TYPE_REPLACING) == 0) {
628 
629 			/* Get the vdevs under this vdev */
630 			nvlist_t **children;
631 			uint_t nelem = 0;
632 			int result = nvlist_lookup_nvlist_array(
633 			    vdev, ZPOOL_CONFIG_CHILDREN, &children, &nelem);
634 
635 			if (result == 0 && nelem > 0) {
636 
637 				/* Get last vdev child (replacement device) */
638 				nvlist_t *child = children[nelem - 1];
639 
640 				obj = zjni_get_VirtualDevice_from_vdev(env,
641 				    zhp, child);
642 			}
643 		}
644 	}
645 
646 	return (obj);
647 }
648 
649 jobject
650 zjni_get_VirtualDevices_from_vdev(JNIEnv *env, zpool_handle_t *zhp,
651     nvlist_t *vdev_parent)
652 {
653 	/* Create an array list for the vdevs */
654 	zjni_ArrayList_t list_class = {0};
655 	zjni_ArrayList_t *list_class_p = &list_class;
656 	zjni_new_ArrayList(env, list_class_p);
657 
658 	/* Was a vdev specified? */
659 	if (vdev_parent == NULL) {
660 		/* No -- retrieve the top-level pool vdev */
661 		vdev_parent = zjni_get_root_vdev(zhp);
662 	}
663 
664 	if (vdev_parent != NULL) {
665 
666 		/* Get the vdevs under this vdev */
667 		nvlist_t **children;
668 		uint_t nelem = 0;
669 		int result = nvlist_lookup_nvlist_array(
670 		    vdev_parent, ZPOOL_CONFIG_CHILDREN, &children, &nelem);
671 
672 		if (result == 0) {
673 
674 			/* For each vdev child... */
675 			int i;
676 			for (i = 0; i < nelem; i++) {
677 				nvlist_t *child = children[i];
678 
679 				/* Create a Java object from this vdev */
680 				jobject obj =
681 				    zjni_get_VirtualDevice_from_vdev(env,
682 					zhp, child);
683 
684 				if ((*env)->ExceptionOccurred(env) != NULL) {
685 					/*
686 					 * Must not call any more Java methods
687 					 * to preserve exception
688 					 */
689 					return (NULL);
690 				}
691 
692 				if (obj != NULL) {
693 				    /* Add child to child vdev list */
694 				    (*env)->CallBooleanMethod(env,
695 					((zjni_Object_t *)list_class_p)->object,
696 					((zjni_Collection_t *)list_class_p)->
697 					method_add, obj);
698 				}
699 			}
700 		}
701 	}
702 
703 	return (zjni_Collection_to_array(
704 	    env, (zjni_Collection_t *)list_class_p,
705 	    ZFSJNI_PACKAGE_DATA "VirtualDevice"));
706 }
707 
708 int
709 zjni_create_add_ImportablePool(char *name,
710     uint64_t guid, uint64_t pool_state, char *health, void *data) {
711 
712 	JNIEnv *env = ((zjni_ArrayCallbackData_t *)data)->env;
713 	zjni_Collection_t *list = ((zjni_ArrayCallbackData_t *)data)->list;
714 
715 	/* Construct ImportablePool object */
716 	jobject bean = create_ImportablePoolBean(
717 	    env, name, guid, pool_state, health);
718 	if (bean == NULL) {
719 		return (-1);
720 	}
721 
722 	/* Add bean to list */
723 	(*env)->CallBooleanMethod(env, ((zjni_Object_t *)list)->object,
724 	    ((zjni_Collection_t *)list)->method_add, bean);
725 
726 	return (0);
727 }
728 
729 /*
730  * Extern functions
731  */
732 
733 /*
734  * Iterates through each importable pool on the system.  For each
735  * importable pool, runs the given function with the given void as the
736  * last arg.
737  */
738 int
739 zjni_ipool_iter(int argc, char **argv, zjni_ipool_iter_f func, void *data)
740 {
741 	nvlist_t *pools = zpool_find_import(argc, argv);
742 
743 	if (pools != NULL) {
744 
745 		nvpair_t *elem = NULL;
746 		while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
747 			nvlist_t *config;
748 			char *name;
749 			uint64_t guid;
750 			uint64_t pool_state;
751 			char *health;
752 
753 			if (nvpair_value_nvlist(elem, &config) != 0 ||
754 			    nvlist_lookup_string(config,
755 				ZPOOL_CONFIG_POOL_NAME, &name) != 0 ||
756 			    nvlist_lookup_uint64(config,
757 				ZPOOL_CONFIG_POOL_GUID, &guid) != 0 ||
758 			    nvlist_lookup_uint64(config,
759 				ZPOOL_CONFIG_POOL_STATE, &pool_state) != 0 ||
760 			    nvlist_lookup_string(config,
761 				ZPOOL_CONFIG_POOL_HEALTH, &health) != 0) {
762 
763 				return (-1);
764 			}
765 
766 			/* Run the given function */
767 			if (func(name, guid, pool_state, health, data)) {
768 				return (-1);
769 			}
770 		}
771 	}
772 
773 	return (0);
774 }
775 
776 char *
777 zjni_get_state_str(uint64_t pool_state)
778 {
779 	char *str = NULL;
780 	switch (pool_state) {
781 		case POOL_STATE_ACTIVE:
782 			str = "POOL_STATE_ACTIVE";
783 			break;
784 
785 		case POOL_STATE_EXPORTED:
786 			str = "POOL_STATE_EXPORTED";
787 			break;
788 
789 		case POOL_STATE_DESTROYED:
790 			str = "POOL_STATE_DESTROYED";
791 			break;
792 
793 		case POOL_STATE_UNINITIALIZED:
794 			str = "POOL_STATE_UNINITIALIZED";
795 			break;
796 
797 		case POOL_STATE_UNAVAIL:
798 			str = "POOL_STATE_UNAVAIL";
799 			break;
800 	}
801 
802 	return (str);
803 }
804