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