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