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