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