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 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 74 jmethodID method_setParity; 75 } RAIDVirtualDeviceBean_t; 76 77 typedef struct MirrorVirtualDeviceBean { 78 VirtualDeviceBean_t super; 79 } MirrorVirtualDeviceBean_t; 80 81 /* 82 * Data 83 */ 84 85 /* vdev_state_t to DeviceStats$DeviceState map */ 86 static 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 */ 97 static 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 */ 109 static 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 */ 121 static 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 148 static void new_ImportablePoolBean(JNIEnv *, ImportablePoolBean_t *); 149 static void new_VirtualDevice(JNIEnv *, VirtualDeviceBean_t *); 150 static void new_LeafVirtualDevice(JNIEnv *, LeafVirtualDeviceBean_t *); 151 static void new_DiskVirtualDeviceBean(JNIEnv *, DiskVirtualDeviceBean_t *); 152 static void new_SliceVirtualDeviceBean(JNIEnv *, SliceVirtualDeviceBean_t *); 153 static void new_FileVirtualDeviceBean(JNIEnv *, FileVirtualDeviceBean_t *); 154 static void new_RAIDVirtualDeviceBean(JNIEnv *, RAIDVirtualDeviceBean_t *); 155 static void new_MirrorVirtualDeviceBean(JNIEnv *, MirrorVirtualDeviceBean_t *); 156 static int populate_ImportablePoolBean( 157 JNIEnv *, ImportablePoolBean_t *, nvlist_t *); 158 static int populate_VirtualDeviceBean(JNIEnv *, zpool_handle_t *, 159 nvlist_t *, uint64_t *p_vdev_id, VirtualDeviceBean_t *); 160 static int populate_LeafVirtualDeviceBean(JNIEnv *, zpool_handle_t *, 161 nvlist_t *, uint64_t *p_vdev_id, LeafVirtualDeviceBean_t *); 162 static int populate_DiskVirtualDeviceBean(JNIEnv *, zpool_handle_t *, 163 nvlist_t *, uint64_t *p_vdev_id, DiskVirtualDeviceBean_t *); 164 static int populate_SliceVirtualDeviceBean(JNIEnv *, zpool_handle_t *, 165 nvlist_t *, uint64_t *p_vdev_id, SliceVirtualDeviceBean_t *); 166 static int populate_FileVirtualDeviceBean(JNIEnv *, zpool_handle_t *, 167 nvlist_t *, uint64_t *p_vdev_id, FileVirtualDeviceBean_t *); 168 static int populate_RAIDVirtualDeviceBean(JNIEnv *, zpool_handle_t *, 169 nvlist_t *, uint64_t *p_vdev_id, RAIDVirtualDeviceBean_t *); 170 static int populate_MirrorVirtualDeviceBean(JNIEnv *, zpool_handle_t *, 171 nvlist_t *, uint64_t *p_vdev_id, MirrorVirtualDeviceBean_t *); 172 static jobject create_ImportablePoolBean(JNIEnv *, nvlist_t *); 173 static jobject create_DiskVirtualDeviceBean( 174 JNIEnv *, zpool_handle_t *, nvlist_t *, uint64_t *p_vdev_id); 175 static jobject create_SliceVirtualDeviceBean( 176 JNIEnv *, zpool_handle_t *, nvlist_t *, uint64_t *p_vdev_id); 177 static jobject create_FileVirtualDeviceBean( 178 JNIEnv *, zpool_handle_t *, nvlist_t *, uint64_t *p_vdev_id); 179 static jobject create_RAIDVirtualDeviceBean( 180 JNIEnv *, zpool_handle_t *, nvlist_t *, uint64_t *p_vdev_id); 181 static jobject create_MirrorVirtualDeviceBean( 182 JNIEnv *, zpool_handle_t *, nvlist_t *, uint64_t *p_vdev_id); 183 static char *find_field(const zjni_field_mapping_t *, int); 184 static jobject zjni_vdev_state_to_obj(JNIEnv *, vdev_state_t); 185 static jobject zjni_vdev_aux_to_obj(JNIEnv *, vdev_aux_t); 186 187 /* 188 * Static functions 189 */ 190 191 /* Create a ImportablePoolBean */ 192 static void 193 new_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 */ 219 static void 220 new_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 */ 249 static void 250 new_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 */ 273 static void 274 new_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 */ 293 static void 294 new_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 */ 313 static void 314 new_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 */ 333 static void 334 new_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 */ 357 static void 358 new_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 376 static int 377 populate_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 421 static int 422 populate_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 463 static int 464 populate_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 471 static int 472 populate_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 542 static int 543 populate_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 572 static int 573 populate_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 601 static int 602 populate_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 609 static int 610 populate_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 617 static jobject 618 create_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 636 static jobject 637 create_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 657 static jobject 658 create_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 678 static jobject 679 create_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 699 static jobject 700 create_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 736 static jobject 737 create_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 757 static char * 758 find_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 */ 772 static jobject 773 zjni_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 */ 783 static jobject 784 zjni_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 */ 796 void 797 new_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 */ 839 void 840 new_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 */ 859 nvlist_t * 860 zjni_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 */ 888 nvlist_t * 889 zjni_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 941 jobject 942 zjni_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 991 jobject 992 zjni_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 1051 int 1052 zjni_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 1071 int 1072 populate_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 */ 1130 jobject 1131 zjni_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 */ 1141 jobject 1142 zjni_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 */ 1158 int 1159 zjni_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 1186 char * 1187 zjni_vdev_state_to_str(vdev_state_t state) 1188 { 1189 return (find_field(vdev_state_map, state)); 1190 } 1191 1192 char * 1193 zjni_vdev_aux_to_str(vdev_aux_t aux) 1194 { 1195 return (find_field(vdev_aux_map, aux)); 1196 } 1197 1198 char * 1199 zjni_pool_state_to_str(pool_state_t state) 1200 { 1201 return (find_field(pool_state_map, state)); 1202 } 1203 1204 char * 1205 zjni_pool_status_to_str(zpool_status_t status) 1206 { 1207 return (find_field(zpool_status_map, status)); 1208 } 1209