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