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