xref: /illumos-gate/usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c (revision 34a0f871d192b33b865455a8812a3d34c1866315)
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 2007 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 } 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_UNINITIALIZED, "POOL_STATE_UNINITIALIZED" },
113 	{ POOL_STATE_UNAVAIL, "POOL_STATE_UNAVAIL" },
114 	{ -1, NULL },
115 };
116 
117 /* zpool_status_t to PoolStats$PoolStatus map */
118 static zjni_field_mapping_t zpool_status_map[] = {
119 	{ ZPOOL_STATUS_CORRUPT_CACHE,
120 	    "ZPOOL_STATUS_CORRUPT_CACHE" },
121 	{ ZPOOL_STATUS_MISSING_DEV_R,
122 	    "ZPOOL_STATUS_MISSING_DEV_R" },
123 	{ ZPOOL_STATUS_MISSING_DEV_NR,
124 	    "ZPOOL_STATUS_MISSING_DEV_NR" },
125 	{ ZPOOL_STATUS_CORRUPT_LABEL_R,
126 	    "ZPOOL_STATUS_CORRUPT_LABEL_R" },
127 	{ ZPOOL_STATUS_CORRUPT_LABEL_NR,
128 	    "ZPOOL_STATUS_CORRUPT_LABEL_NR" },
129 	{ ZPOOL_STATUS_BAD_GUID_SUM, "ZPOOL_STATUS_BAD_GUID_SUM" },
130 	{ ZPOOL_STATUS_CORRUPT_POOL, "ZPOOL_STATUS_CORRUPT_POOL" },
131 	{ ZPOOL_STATUS_CORRUPT_DATA, "ZPOOL_STATUS_CORRUPT_DATA" },
132 	{ ZPOOL_STATUS_FAILING_DEV, "ZPOOL_STATUS_FAILING_DEV" },
133 	{ ZPOOL_STATUS_VERSION_OLDER,
134 	    "ZPOOL_STATUS_VERSION_OLDER" },
135 	{ ZPOOL_STATUS_VERSION_NEWER,
136 	    "ZPOOL_STATUS_VERSION_NEWER" },
137 	{ ZPOOL_STATUS_RESILVERING, "ZPOOL_STATUS_RESILVERING" },
138 	{ ZPOOL_STATUS_OFFLINE_DEV, "ZPOOL_STATUS_OFFLINE_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 
352 /* Create a MirrorVirtualDeviceBean */
353 static void
354 new_MirrorVirtualDeviceBean(JNIEnv *env, MirrorVirtualDeviceBean_t *bean)
355 {
356 	zjni_Object_t *object = (zjni_Object_t *)bean;
357 
358 	if (object->object == NULL) {
359 		object->class = (*env)->FindClass(
360 		    env, ZFSJNI_PACKAGE_DATA "MirrorVirtualDeviceBean");
361 
362 		object->constructor =
363 		    (*env)->GetMethodID(env, object->class, "<init>", "()V");
364 
365 		object->object =
366 		    (*env)->NewObject(env, object->class, object->constructor);
367 	}
368 
369 	new_VirtualDevice(env, (VirtualDeviceBean_t *)bean);
370 }
371 
372 static int
373 populate_ImportablePoolBean(JNIEnv *env, ImportablePoolBean_t *bean,
374     nvlist_t *config)
375 {
376 	char *c;
377 	char *name;
378 	uint64_t guid;
379 	uint64_t state;
380 	nvlist_t *devices;
381 
382 	zjni_Object_t *object = (zjni_Object_t *)bean;
383 	PoolStatsBean_t *pool_stats = &(bean->interface_PoolStats);
384 	DeviceStatsBean_t *dev_stats = (DeviceStatsBean_t *)pool_stats;
385 
386 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, &name) ||
387 	    nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, &guid) ||
388 	    nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE, &state) ||
389 	    nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &devices) ||
390 	    populate_DeviceStatsBean(env, devices, dev_stats, object)) {
391 		return (-1);
392 	}
393 
394 	(*env)->CallVoidMethod(env, object->object,
395 	    bean->method_setName, (*env)->NewStringUTF(env, name));
396 
397 	(*env)->CallVoidMethod(env, object->object,
398 	    bean->method_setId, (jlong)guid);
399 
400 	(*env)->CallVoidMethod(env, object->object,
401 	    pool_stats->method_setPoolState,
402 	    zjni_pool_state_to_obj(env, (pool_state_t)state));
403 
404 	(*env)->CallVoidMethod(env, object->object,
405 	    pool_stats->method_setPoolStatus,
406 	    zjni_pool_status_to_obj(env, zpool_import_status(config, &c)));
407 
408 	return (0);
409 }
410 
411 static int
412 populate_VirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
413     nvlist_t *vdev, uint64_t *p_vdev_id, VirtualDeviceBean_t *bean)
414 {
415 	int result;
416 	uint64_t vdev_id;
417 	jstring poolUTF;
418 
419 	zjni_Object_t *object = (zjni_Object_t *)bean;
420 	DeviceStatsBean_t *stats = &(bean->interface_DeviceStats);
421 
422 	result = populate_DeviceStatsBean(env, vdev, stats, object);
423 	if (result != 0) {
424 		return (1);
425 	}
426 
427 	/* Set pool name */
428 	poolUTF = (*env)->NewStringUTF(env, zpool_get_name(zhp));
429 	(*env)->CallVoidMethod(
430 	    env, object->object, bean->method_setPoolName, poolUTF);
431 
432 	/* Set parent vdev index */
433 	(*env)->CallVoidMethod(
434 	    env, object->object, bean->method_setParentIndex,
435 	    p_vdev_id == NULL ? NULL :
436 	    zjni_long_to_Long(env, *p_vdev_id));
437 
438 	/* Get index */
439 	result = nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &vdev_id);
440 	if (result != 0) {
441 		zjni_throw_exception(env,
442 		    "could not retrieve virtual device ID (pool %s)",
443 		    zpool_get_name(zhp));
444 		return (1);
445 	}
446 
447 	(*env)->CallVoidMethod(
448 	    env, object->object, bean->method_setIndex, (jlong)vdev_id);
449 
450 	return (0);
451 }
452 
453 static int
454 populate_LeafVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
455     nvlist_t *vdev, uint64_t *p_vdev_id, LeafVirtualDeviceBean_t *bean)
456 {
457 	return (populate_VirtualDeviceBean(
458 	    env, zhp, vdev, p_vdev_id, (VirtualDeviceBean_t *)bean));
459 }
460 
461 static int
462 populate_DiskVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
463     nvlist_t *vdev, uint64_t *p_vdev_id, DiskVirtualDeviceBean_t *bean)
464 {
465 	char *path;
466 	int result = populate_LeafVirtualDeviceBean(
467 	    env, zhp, vdev, p_vdev_id, (LeafVirtualDeviceBean_t *)bean);
468 
469 	if (result) {
470 		/* Must not call any more Java methods to preserve exception */
471 		return (-1);
472 	}
473 
474 	/* Set path */
475 	result = nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path);
476 	if (result != 0) {
477 		zjni_throw_exception(env,
478 		    "could not retrieve path from disk virtual device "
479 		    "(pool %s)", zpool_get_name(zhp));
480 	} else {
481 
482 		regex_t re;
483 		regmatch_t matches[2];
484 		jstring pathUTF = NULL;
485 
486 		/* Strip off slice portion of name, if applicable */
487 		if (regcomp(&re, "^(/dev/dsk/.*)s[0-9]+$", REG_EXTENDED) == 0) {
488 			if (regexec(&re, path, 2, matches, 0) == 0) {
489 				regmatch_t *match = matches + 1;
490 				if (match->rm_so != -1 && match->rm_eo != -1) {
491 					char *tmp = strdup(path);
492 					if (tmp != NULL) {
493 						char *end = tmp + match->rm_eo;
494 						*end = '\0';
495 						pathUTF = (*env)->NewStringUTF(
496 						    env, tmp);
497 						free(tmp);
498 					}
499 				}
500 			}
501 			regfree(&re);
502 		}
503 
504 		if (pathUTF == NULL) {
505 		    pathUTF = (*env)->NewStringUTF(env, path);
506 		}
507 
508 		(*env)->CallVoidMethod(env, ((zjni_Object_t *)bean)->object,
509 		    ((LeafVirtualDeviceBean_t *)bean)->method_setName, pathUTF);
510 	}
511 
512 	return (result != 0);
513 }
514 
515 static int
516 populate_SliceVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
517     nvlist_t *vdev, uint64_t *p_vdev_id, SliceVirtualDeviceBean_t *bean)
518 {
519 	char *path;
520 	int result = populate_LeafVirtualDeviceBean(
521 	    env, zhp, vdev, p_vdev_id, (LeafVirtualDeviceBean_t *)bean);
522 
523 	if (result) {
524 		/* Must not call any more Java methods to preserve exception */
525 		return (-1);
526 	}
527 
528 	/* Set path */
529 	result = nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path);
530 	if (result != 0) {
531 		zjni_throw_exception(env,
532 		    "could not retrieve path from slice virtual device (pool "
533 		    "%s)", zpool_get_name(zhp));
534 	} else {
535 
536 		jstring pathUTF = (*env)->NewStringUTF(env, path);
537 		(*env)->CallVoidMethod(env, ((zjni_Object_t *)bean)->object,
538 		    ((LeafVirtualDeviceBean_t *)bean)->method_setName,
539 		    pathUTF);
540 	}
541 
542 	return (result != 0);
543 }
544 
545 static int
546 populate_FileVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
547     nvlist_t *vdev, uint64_t *p_vdev_id, FileVirtualDeviceBean_t *bean)
548 {
549 	char *path;
550 	int result = populate_LeafVirtualDeviceBean(
551 	    env, zhp, vdev, p_vdev_id, (LeafVirtualDeviceBean_t *)bean);
552 
553 	if (result) {
554 		/* Must not call any more Java methods to preserve exception */
555 		return (-1);
556 	}
557 
558 	/* Set path */
559 	result = nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path);
560 	if (result != 0) {
561 		zjni_throw_exception(env,
562 		    "could not retrieve path from disk virtual device "
563 		    "(pool %s)", zpool_get_name(zhp));
564 	} else {
565 
566 		jstring pathUTF = (*env)->NewStringUTF(env, path);
567 		(*env)->CallVoidMethod(env, ((zjni_Object_t *)bean)->object,
568 		    ((LeafVirtualDeviceBean_t *)bean)->method_setName, pathUTF);
569 	}
570 
571 	return (result != 0);
572 }
573 
574 static int
575 populate_RAIDVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
576     nvlist_t *vdev, uint64_t *p_vdev_id, RAIDVirtualDeviceBean_t *bean)
577 {
578 	return (populate_VirtualDeviceBean(env, zhp, vdev, p_vdev_id,
579 	    (VirtualDeviceBean_t *)bean));
580 }
581 
582 static int
583 populate_MirrorVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
584     nvlist_t *vdev, uint64_t *p_vdev_id, MirrorVirtualDeviceBean_t *bean)
585 {
586 	return (populate_VirtualDeviceBean(env, zhp, vdev, p_vdev_id,
587 	    (VirtualDeviceBean_t *)bean));
588 }
589 
590 static jobject
591 create_ImportablePoolBean(JNIEnv *env, nvlist_t *config)
592 {
593 	int result;
594 	ImportablePoolBean_t bean_obj = {0};
595 	ImportablePoolBean_t *bean = &bean_obj;
596 
597 	/* Construct ImportablePoolBean */
598 	new_ImportablePoolBean(env, bean);
599 
600 	result = populate_ImportablePoolBean(env, bean, config);
601 	if (result) {
602 		/* Must not call any more Java methods to preserve exception */
603 		return (NULL);
604 	}
605 
606 	return (((zjni_Object_t *)bean)->object);
607 }
608 
609 static jobject
610 create_DiskVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
611     nvlist_t *vdev, uint64_t *p_vdev_id)
612 {
613 	int result;
614 	DiskVirtualDeviceBean_t bean_obj = {0};
615 	DiskVirtualDeviceBean_t *bean = &bean_obj;
616 
617 	/* Construct DiskVirtualDeviceBean */
618 	new_DiskVirtualDeviceBean(env, bean);
619 
620 	result = populate_DiskVirtualDeviceBean(
621 	    env, zhp, vdev, p_vdev_id, bean);
622 	if (result) {
623 		/* Must not call any more Java methods to preserve exception */
624 		return (NULL);
625 	}
626 
627 	return (((zjni_Object_t *)bean)->object);
628 }
629 
630 static jobject
631 create_SliceVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
632     nvlist_t *vdev, uint64_t *p_vdev_id)
633 {
634 	int result;
635 	SliceVirtualDeviceBean_t bean_obj = {0};
636 	SliceVirtualDeviceBean_t *bean = &bean_obj;
637 
638 	/* Construct SliceVirtualDeviceBean */
639 	new_SliceVirtualDeviceBean(env, bean);
640 
641 	result = populate_SliceVirtualDeviceBean(
642 	    env, zhp, vdev, p_vdev_id, bean);
643 	if (result) {
644 		/* Must not call any more Java methods to preserve exception */
645 		return (NULL);
646 	}
647 
648 	return (((zjni_Object_t *)bean)->object);
649 }
650 
651 static jobject
652 create_FileVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
653     nvlist_t *vdev, uint64_t *p_vdev_id)
654 {
655 	int result;
656 	FileVirtualDeviceBean_t bean_obj = {0};
657 	FileVirtualDeviceBean_t *bean = &bean_obj;
658 
659 	/* Construct FileVirtualDeviceBean */
660 	new_FileVirtualDeviceBean(env, bean);
661 
662 	result = populate_FileVirtualDeviceBean(
663 	    env, zhp, vdev, p_vdev_id, bean);
664 	if (result) {
665 		/* Must not call any more Java methods to preserve exception */
666 		return (NULL);
667 	}
668 
669 	return (((zjni_Object_t *)bean)->object);
670 }
671 
672 static jobject
673 create_RAIDVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
674     nvlist_t *vdev, uint64_t *p_vdev_id)
675 {
676 	int result;
677 	RAIDVirtualDeviceBean_t bean_obj = {0};
678 	RAIDVirtualDeviceBean_t *bean = &bean_obj;
679 
680 	((zjni_Object_t *)bean)->object = NULL;
681 
682 	/* Construct RAIDVirtualDeviceBean */
683 	new_RAIDVirtualDeviceBean(env, bean);
684 
685 	result = populate_RAIDVirtualDeviceBean(
686 	    env, zhp, vdev, p_vdev_id, bean);
687 	if (result) {
688 		/* Must not call any more Java methods to preserve exception */
689 		return (NULL);
690 	}
691 
692 	return (((zjni_Object_t *)bean)->object);
693 }
694 
695 static jobject
696 create_MirrorVirtualDeviceBean(JNIEnv *env, zpool_handle_t *zhp,
697     nvlist_t *vdev, uint64_t *p_vdev_id)
698 {
699 	int result;
700 	MirrorVirtualDeviceBean_t bean_obj = {0};
701 	MirrorVirtualDeviceBean_t *bean = &bean_obj;
702 
703 	/* Construct MirrorVirtualDeviceBean */
704 	new_MirrorVirtualDeviceBean(env, bean);
705 
706 	result = populate_MirrorVirtualDeviceBean(
707 	    env, zhp, vdev, p_vdev_id, bean);
708 	if (result) {
709 		/* Must not call any more Java methods to preserve exception */
710 		return (NULL);
711 	}
712 
713 	return (((zjni_Object_t *)bean)->object);
714 }
715 
716 static char *
717 find_field(const zjni_field_mapping_t *mapping, int value) {
718 	int i;
719 	for (i = 0; mapping[i].name != NULL; i++) {
720 		if (value == mapping[i].value) {
721 			return (mapping[i].name);
722 		}
723 	}
724 	return (NULL);
725 }
726 
727 /*
728  * Converts a vdev_state_t to a Java DeviceStats$DeviceState object.
729  */
730 static jobject
731 zjni_vdev_state_to_obj(JNIEnv *env, vdev_state_t state)
732 {
733 	return (zjni_int_to_enum(env, state,
734 	    ZFSJNI_PACKAGE_DATA "DeviceStats$DeviceState",
735 	    "VDEV_STATE_UNKNOWN", vdev_state_map));
736 }
737 
738 /*
739  * Converts a vdev_aux_t to a Java DeviceStats$DeviceStatus object.
740  */
741 static jobject
742 zjni_vdev_aux_to_obj(JNIEnv *env, vdev_aux_t aux)
743 {
744 	return (zjni_int_to_enum(env, aux,
745 	    ZFSJNI_PACKAGE_DATA "DeviceStats$DeviceStatus",
746 	    "VDEV_AUX_NONE", vdev_aux_map));
747 }
748 
749 /*
750  * Package-private functions
751  */
752 
753 /* Create a DeviceStatsBean */
754 void
755 new_DeviceStats(JNIEnv *env, DeviceStatsBean_t *bean, zjni_Object_t *object)
756 {
757 	bean->method_setSize = (*env)->GetMethodID(
758 	    env, object->class, "setSize", "(J)V");
759 
760 	bean->method_setReplacementSize = (*env)->GetMethodID(
761 	    env, object->class, "setReplacementSize", "(J)V");
762 
763 	bean->method_setUsed = (*env)->GetMethodID(
764 	    env, object->class, "setUsed", "(J)V");
765 
766 	bean->method_setReadBytes = (*env)->GetMethodID(
767 	    env, object->class, "setReadBytes", "(J)V");
768 
769 	bean->method_setWriteBytes = (*env)->GetMethodID(
770 	    env, object->class, "setWriteBytes", "(J)V");
771 
772 	bean->method_setReadOperations = (*env)->GetMethodID(
773 	    env, object->class, "setReadOperations", "(J)V");
774 
775 	bean->method_setWriteOperations = (*env)->GetMethodID(
776 	    env, object->class, "setWriteOperations", "(J)V");
777 
778 	bean->method_setReadErrors = (*env)->GetMethodID(
779 	    env, object->class, "setReadErrors", "(J)V");
780 
781 	bean->method_setWriteErrors = (*env)->GetMethodID(
782 	    env, object->class, "setWriteErrors", "(J)V");
783 
784 	bean->method_setChecksumErrors = (*env)->GetMethodID(
785 	    env, object->class, "setChecksumErrors", "(J)V");
786 
787 	bean->method_setDeviceState = (*env)->GetMethodID(
788 	    env, object->class, "setDeviceState",
789 	    "(L" ZFSJNI_PACKAGE_DATA "DeviceStats$DeviceState;)V");
790 
791 	bean->method_setDeviceStatus = (*env)->GetMethodID(
792 	    env, object->class, "setDeviceStatus",
793 	    "(L" ZFSJNI_PACKAGE_DATA "DeviceStats$DeviceStatus;)V");
794 }
795 
796 /* Create a PoolStatsBean */
797 void
798 new_PoolStats(JNIEnv *env, PoolStatsBean_t *bean, zjni_Object_t *object)
799 {
800 	new_DeviceStats(env, (DeviceStatsBean_t *)bean, object);
801 
802 	bean->method_setPoolState = (*env)->GetMethodID(
803 	    env, object->class, "setPoolState",
804 	    "(L" ZFSJNI_PACKAGE_DATA "PoolStats$PoolState;)V");
805 
806 	bean->method_setPoolStatus = (*env)->GetMethodID(
807 	    env, object->class, "setPoolStatus",
808 	    "(L" ZFSJNI_PACKAGE_DATA "PoolStats$PoolStatus;)V");
809 }
810 
811 /*
812  * Gets the root vdev (an nvlist_t *) for the given pool.
813  */
814 nvlist_t *
815 zjni_get_root_vdev(zpool_handle_t *zhp)
816 {
817 	nvlist_t *root = NULL;
818 
819 	if (zhp != NULL) {
820 		nvlist_t *attrs = zpool_get_config(zhp, NULL);
821 
822 		if (attrs != NULL) {
823 			int result = nvlist_lookup_nvlist(
824 			    attrs, ZPOOL_CONFIG_VDEV_TREE, &root);
825 			if (result != 0) {
826 				root = NULL;
827 			}
828 		}
829 	}
830 
831 	return (root);
832 }
833 
834 /*
835  * Gets the vdev (an nvlist_t *) with the given vdev_id, below the
836  * given vdev.  If the given vdev is NULL, all vdevs within the given
837  * pool are searched.
838  *
839  * If p_vdev_id is not NULL, it will be set to the ID of the parent
840  * vdev, if any, or to vdev_id_to_find if the searched-for vdev is a
841  * toplevel vdev.
842  */
843 nvlist_t *
844 zjni_get_vdev(zpool_handle_t *zhp, nvlist_t *vdev_parent,
845     uint64_t vdev_id_to_find, uint64_t *p_vdev_id)
846 {
847 	int result;
848 	uint64_t id = vdev_id_to_find;
849 
850 	/* Was a vdev specified? */
851 	if (vdev_parent == NULL) {
852 		/* No -- retrieve the top-level pool vdev */
853 		vdev_parent = zjni_get_root_vdev(zhp);
854 	} else {
855 		/* Get index of this vdev and compare with vdev_id_to_find */
856 		result = nvlist_lookup_uint64(
857 		    vdev_parent, ZPOOL_CONFIG_GUID, &id);
858 		if (result == 0 && id == vdev_id_to_find) {
859 			return (vdev_parent);
860 		}
861 	}
862 
863 	if (vdev_parent != NULL) {
864 
865 		nvlist_t **children;
866 		uint_t nelem = 0;
867 
868 		/* Get the vdevs under this vdev */
869 		result = nvlist_lookup_nvlist_array(
870 		    vdev_parent, ZPOOL_CONFIG_CHILDREN, &children, &nelem);
871 
872 		if (result == 0) {
873 
874 			int i;
875 			nvlist_t *child;
876 
877 			/* For each vdev child... */
878 			for (i = 0; i < nelem; i++) {
879 				if (p_vdev_id != NULL) {
880 					/* Save parent vdev id */
881 					*p_vdev_id = id;
882 				}
883 
884 				child = zjni_get_vdev(zhp, children[i],
885 				    vdev_id_to_find, p_vdev_id);
886 				if (child != NULL) {
887 					return (child);
888 				}
889 			}
890 		}
891 	}
892 
893 	return (NULL);
894 }
895 
896 jobject
897 zjni_get_VirtualDevice_from_vdev(JNIEnv *env, zpool_handle_t *zhp,
898     nvlist_t *vdev, uint64_t *p_vdev_id)
899 {
900 	jobject obj = NULL;
901 	char *type = NULL;
902 	int result = nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE, &type);
903 
904 	if (result == 0) {
905 		if (strcmp(type, VDEV_TYPE_DISK) == 0) {
906 			uint64_t wholedisk;
907 			if (nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
908 			    &wholedisk) == 0 && wholedisk) {
909 				obj = create_DiskVirtualDeviceBean(
910 				    env, zhp, vdev, p_vdev_id);
911 			} else {
912 				obj = create_SliceVirtualDeviceBean(
913 				    env, zhp, vdev, p_vdev_id);
914 			}
915 		} else if (strcmp(type, VDEV_TYPE_FILE) == 0) {
916 			obj = create_FileVirtualDeviceBean(
917 			    env, zhp, vdev, p_vdev_id);
918 		} else if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
919 			obj = create_RAIDVirtualDeviceBean(
920 			    env, zhp, vdev, p_vdev_id);
921 		} else if (strcmp(type, VDEV_TYPE_MIRROR) == 0) {
922 			obj = create_MirrorVirtualDeviceBean(
923 			    env, zhp, vdev, p_vdev_id);
924 		} else if (strcmp(type, VDEV_TYPE_REPLACING) == 0) {
925 
926 			/* Get the vdevs under this vdev */
927 			nvlist_t **children;
928 			uint_t nelem = 0;
929 			int result = nvlist_lookup_nvlist_array(
930 			    vdev, ZPOOL_CONFIG_CHILDREN, &children, &nelem);
931 
932 			if (result == 0 && nelem > 0) {
933 
934 				/* Get last vdev child (replacement device) */
935 				nvlist_t *child = children[nelem - 1];
936 
937 				obj = zjni_get_VirtualDevice_from_vdev(env,
938 				    zhp, child, p_vdev_id);
939 			}
940 		}
941 	}
942 
943 	return (obj);
944 }
945 
946 jobject
947 zjni_get_VirtualDevices_from_vdev(JNIEnv *env, zpool_handle_t *zhp,
948     nvlist_t *vdev_parent, uint64_t *p_vdev_id)
949 {
950 	/* Create an array list for the vdevs */
951 	zjni_ArrayList_t list_class = {0};
952 	zjni_ArrayList_t *list_class_p = &list_class;
953 	zjni_new_ArrayList(env, list_class_p);
954 
955 	/* Was a vdev specified? */
956 	if (vdev_parent == NULL) {
957 		/* No -- retrieve the top-level pool vdev */
958 		vdev_parent = zjni_get_root_vdev(zhp);
959 	}
960 
961 	if (vdev_parent != NULL) {
962 
963 		/* Get the vdevs under this vdev */
964 		nvlist_t **children;
965 		uint_t nelem = 0;
966 		int result = nvlist_lookup_nvlist_array(
967 		    vdev_parent, ZPOOL_CONFIG_CHILDREN, &children, &nelem);
968 
969 		if (result == 0) {
970 
971 			/* For each vdev child... */
972 			int i;
973 			for (i = 0; i < nelem; i++) {
974 				nvlist_t *child = children[i];
975 
976 				/* Create a Java object from this vdev */
977 				jobject obj =
978 				    zjni_get_VirtualDevice_from_vdev(env,
979 					zhp, child, p_vdev_id);
980 
981 				if ((*env)->ExceptionOccurred(env) != NULL) {
982 					/*
983 					 * Must not call any more Java methods
984 					 * to preserve exception
985 					 */
986 					return (NULL);
987 				}
988 
989 				if (obj != NULL) {
990 				    /* Add child to child vdev list */
991 				    (*env)->CallBooleanMethod(env,
992 					((zjni_Object_t *)list_class_p)->object,
993 					((zjni_Collection_t *)list_class_p)->
994 					method_add, obj);
995 				}
996 			}
997 		}
998 	}
999 
1000 	return (zjni_Collection_to_array(
1001 	    env, (zjni_Collection_t *)list_class_p,
1002 	    ZFSJNI_PACKAGE_DATA "VirtualDevice"));
1003 }
1004 
1005 int
1006 zjni_create_add_ImportablePool(nvlist_t *config, void *data) {
1007 
1008 	JNIEnv *env = ((zjni_ArrayCallbackData_t *)data)->env;
1009 	zjni_Collection_t *list = ((zjni_ArrayCallbackData_t *)data)->list;
1010 
1011 	/* Construct ImportablePool object */
1012 	jobject bean = create_ImportablePoolBean(env, config);
1013 	if (bean == NULL) {
1014 		return (-1);
1015 	}
1016 
1017 	/* Add bean to list */
1018 	(*env)->CallBooleanMethod(env, ((zjni_Object_t *)list)->object,
1019 	    ((zjni_Collection_t *)list)->method_add, bean);
1020 
1021 	return (0);
1022 }
1023 
1024 int
1025 populate_DeviceStatsBean(JNIEnv *env, nvlist_t *vdev,
1026     DeviceStatsBean_t *bean, zjni_Object_t *object)
1027 {
1028 	uint_t c;
1029 	vdev_stat_t *vs;
1030 
1031 	int result = nvlist_lookup_uint64_array(
1032 	    vdev, ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &c);
1033 	if (result != 0) {
1034 		zjni_throw_exception(env,
1035 		    "could not retrieve virtual device statistics");
1036 		return (1);
1037 	}
1038 
1039 	(*env)->CallVoidMethod(env, object->object,
1040 	    bean->method_setUsed, (jlong)vs->vs_alloc);
1041 
1042 	(*env)->CallVoidMethod(env, object->object,
1043 	    bean->method_setSize, (jlong)vs->vs_space);
1044 
1045 	(*env)->CallVoidMethod(env, object->object,
1046 	    bean->method_setReplacementSize, (jlong)vs->vs_rsize);
1047 
1048 	(*env)->CallVoidMethod(env, object->object,
1049 	    bean->method_setReadBytes, (jlong)vs->vs_bytes[ZIO_TYPE_READ]);
1050 
1051 	(*env)->CallVoidMethod(env, object->object,
1052 	    bean->method_setWriteBytes, (jlong)vs->vs_bytes[ZIO_TYPE_WRITE]);
1053 
1054 	(*env)->CallVoidMethod(env, object->object,
1055 	    bean->method_setReadOperations, (jlong)vs->vs_ops[ZIO_TYPE_READ]);
1056 
1057 	(*env)->CallVoidMethod(env, object->object,
1058 	    bean->method_setWriteOperations, (jlong)vs->vs_ops[ZIO_TYPE_WRITE]);
1059 
1060 	(*env)->CallVoidMethod(env, object->object,
1061 	    bean->method_setReadErrors, (jlong)vs->vs_read_errors);
1062 
1063 	(*env)->CallVoidMethod(env, object->object,
1064 	    bean->method_setWriteErrors, (jlong)vs->vs_write_errors);
1065 
1066 	(*env)->CallVoidMethod(env, object->object,
1067 	    bean->method_setChecksumErrors, (jlong)vs->vs_checksum_errors);
1068 
1069 	(*env)->CallVoidMethod(env, object->object,
1070 	    bean->method_setDeviceState,
1071 	    zjni_vdev_state_to_obj(env, vs->vs_state));
1072 
1073 	(*env)->CallVoidMethod(env, object->object,
1074 	    bean->method_setDeviceStatus,
1075 	    zjni_vdev_aux_to_obj(env, vs->vs_aux));
1076 
1077 	return (0);
1078 }
1079 
1080 /*
1081  * Converts a pool_state_t to a Java PoolStats$PoolState object.
1082  */
1083 jobject
1084 zjni_pool_state_to_obj(JNIEnv *env, pool_state_t state)
1085 {
1086 	return (zjni_int_to_enum(env, state,
1087 	    ZFSJNI_PACKAGE_DATA "PoolStats$PoolState",
1088 	    "POOL_STATE_ACTIVE", pool_state_map));
1089 }
1090 
1091 /*
1092  * Converts a zpool_status_t to a Java PoolStats$PoolStatus object.
1093  */
1094 jobject
1095 zjni_pool_status_to_obj(JNIEnv *env, zpool_status_t status)
1096 {
1097 	return (zjni_int_to_enum(env, status,
1098 	    ZFSJNI_PACKAGE_DATA "PoolStats$PoolStatus",
1099 	    "ZPOOL_STATUS_OK", zpool_status_map));
1100 }
1101 
1102 /*
1103  * Extern functions
1104  */
1105 
1106 /*
1107  * Iterates through each importable pool on the system.  For each
1108  * importable pool, runs the given function with the given void as the
1109  * last arg.
1110  */
1111 int
1112 zjni_ipool_iter(int argc, char **argv, zjni_ipool_iter_f func, void *data)
1113 {
1114 	nvlist_t *pools = zpool_find_import(g_zfs, argc, argv);
1115 
1116 	if (pools != NULL) {
1117 		nvpair_t *elem = NULL;
1118 
1119 		while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
1120 			nvlist_t *config;
1121 
1122 			if (nvpair_value_nvlist(elem, &config) != 0 ||
1123 			    func(config, data)) {
1124 				return (-1);
1125 			}
1126 		}
1127 	}
1128 
1129 	return (0);
1130 }
1131 
1132 char *
1133 zjni_vdev_state_to_str(vdev_state_t state) {
1134 	return (find_field(vdev_state_map, state));
1135 }
1136 
1137 char *
1138 zjni_vdev_aux_to_str(vdev_aux_t aux) {
1139 	return (find_field(vdev_aux_map, aux));
1140 }
1141 
1142 char *
1143 zjni_pool_state_to_str(pool_state_t state) {
1144 	return (find_field(pool_state_map, state));
1145 }
1146 
1147 char *
1148 zjni_pool_status_to_str(zpool_status_t status) {
1149 	return (find_field(zpool_status_map, status));
1150 }
1151