1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5fa9e4066Sahrens * Common Development and Distribution License, Version 1.0 only 6fa9e4066Sahrens * (the "License"). You may not use this file except in compliance 7fa9e4066Sahrens * with the License. 8fa9e4066Sahrens * 9fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 11fa9e4066Sahrens * See the License for the specific language governing permissions 12fa9e4066Sahrens * and limitations under the License. 13fa9e4066Sahrens * 14fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 15fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 17fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 18fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 19fa9e4066Sahrens * 20fa9e4066Sahrens * CDDL HEADER END 21fa9e4066Sahrens */ 22fa9e4066Sahrens /* 23fa9e4066Sahrens * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28fa9e4066Sahrens 29fa9e4066Sahrens #include "libzfs_jni_diskmgt.h" 30fa9e4066Sahrens #include "libzfs_jni_util.h" 31fa9e4066Sahrens #include <strings.h> 32fa9e4066Sahrens #include <libzfs.h> 33fa9e4066Sahrens #include <sys/mnttab.h> 34fa9e4066Sahrens 35fa9e4066Sahrens /* 36fa9e4066Sahrens * Function prototypes 37fa9e4066Sahrens */ 38fa9e4066Sahrens 39fa9e4066Sahrens static char *get_device_name(dm_descriptor_t device, int *error); 40fa9e4066Sahrens static dmgt_disk_t *get_disk(dm_descriptor_t disk, int *error); 41fa9e4066Sahrens static char **get_disk_aliases(dm_descriptor_t disk, char *name, int *error); 42fa9e4066Sahrens static int get_disk_online(dm_descriptor_t disk, int *error); 43fa9e4066Sahrens static void remove_slice_from_list(dmgt_slice_t **slices, int index); 44fa9e4066Sahrens static dmgt_slice_t **get_disk_slices(dm_descriptor_t media, 45fa9e4066Sahrens const char *name, uint32_t blocksize, int *error); 46fa9e4066Sahrens static dmgt_slice_t **get_disk_usable_slices(dm_descriptor_t media, 47fa9e4066Sahrens const char *name, uint32_t blocksize, int *in_use, int *error); 48fa9e4066Sahrens static void get_disk_size(dm_descriptor_t media, char *name, 49fa9e4066Sahrens uint64_t *size, uint32_t *blocksize, int *error); 50fa9e4066Sahrens static void get_slice_use(dm_descriptor_t slice, char *name, 51fa9e4066Sahrens char **used_name, char **used_by, int *error); 52fa9e4066Sahrens static dmgt_slice_t *get_slice( 53fa9e4066Sahrens dm_descriptor_t slice, uint32_t blocksize, int *error); 54fa9e4066Sahrens static void handle_error(const char *format, ...); 55fa9e4066Sahrens static int slice_in_use(dmgt_slice_t *slice); 56fa9e4066Sahrens static int slice_too_small(dmgt_slice_t *slice); 57fa9e4066Sahrens 58fa9e4066Sahrens /* 59fa9e4066Sahrens * Static data 60fa9e4066Sahrens */ 61fa9e4066Sahrens 62fa9e4066Sahrens static void (*error_func)(const char *, va_list); 63fa9e4066Sahrens 64fa9e4066Sahrens /* 65fa9e4066Sahrens * Static functions 66fa9e4066Sahrens */ 67fa9e4066Sahrens 68fa9e4066Sahrens static char * 69fa9e4066Sahrens get_device_name(dm_descriptor_t device, int *error) 70fa9e4066Sahrens { 71fa9e4066Sahrens char *dup; 72fa9e4066Sahrens char *name; 73fa9e4066Sahrens 74fa9e4066Sahrens *error = 0; 75fa9e4066Sahrens name = dm_get_name(device, error); 76fa9e4066Sahrens if (*error) { 77fa9e4066Sahrens handle_error("could not determine name of device"); 78fa9e4066Sahrens } else { 79fa9e4066Sahrens dup = strdup(name); 80fa9e4066Sahrens if (dup == NULL) { 81fa9e4066Sahrens handle_error("out of memory"); 82fa9e4066Sahrens *error = -1; 83fa9e4066Sahrens } 84fa9e4066Sahrens 85fa9e4066Sahrens dm_free_name(name); 86fa9e4066Sahrens } 87fa9e4066Sahrens 88fa9e4066Sahrens return (dup); 89fa9e4066Sahrens } 90fa9e4066Sahrens 91fa9e4066Sahrens /* 92fa9e4066Sahrens * Gets a dmgt_disk_t for the given disk dm_descriptor_t. 93fa9e4066Sahrens * 94fa9e4066Sahrens * Results: 95fa9e4066Sahrens * 96fa9e4066Sahrens * 1. Success: error is set to 0 and a dmgt_disk_t is returned 97fa9e4066Sahrens * 98fa9e4066Sahrens * 2. Failure: error is set to -1 and NULL is returned 99fa9e4066Sahrens */ 100fa9e4066Sahrens static dmgt_disk_t * 101fa9e4066Sahrens get_disk(dm_descriptor_t disk, int *error) 102fa9e4066Sahrens { 103fa9e4066Sahrens dmgt_disk_t *dp; 104fa9e4066Sahrens *error = 0; 105fa9e4066Sahrens 106fa9e4066Sahrens dp = (dmgt_disk_t *)calloc(1, sizeof (dmgt_disk_t)); 107fa9e4066Sahrens if (dp == NULL) { 108fa9e4066Sahrens handle_error("out of memory"); 109fa9e4066Sahrens *error = -1; 110fa9e4066Sahrens } else { 111fa9e4066Sahrens 112fa9e4066Sahrens /* Get name */ 113fa9e4066Sahrens dp->name = get_device_name(disk, error); 114fa9e4066Sahrens if (!*error) { 115fa9e4066Sahrens 116fa9e4066Sahrens /* Get aliases */ 117fa9e4066Sahrens dp->aliases = get_disk_aliases(disk, dp->name, error); 118fa9e4066Sahrens if (!*error) { 119fa9e4066Sahrens 120fa9e4066Sahrens /* Get media */ 121fa9e4066Sahrens dm_descriptor_t *media = 122fa9e4066Sahrens dm_get_associated_descriptors(disk, 123fa9e4066Sahrens DM_MEDIA, error); 124fa9e4066Sahrens if (*error != 0 || media == NULL || 125fa9e4066Sahrens *media == NULL) { 126fa9e4066Sahrens handle_error( 127fa9e4066Sahrens "could not get media from disk %s", 128fa9e4066Sahrens dp->name); 129fa9e4066Sahrens *error = -1; 130fa9e4066Sahrens } else { 131fa9e4066Sahrens /* Get size */ 132fa9e4066Sahrens get_disk_size(media[0], dp->name, 133fa9e4066Sahrens &(dp->size), &(dp->blocksize), 134fa9e4066Sahrens error); 135fa9e4066Sahrens if (!*error) { 136fa9e4066Sahrens /* Get free slices */ 137fa9e4066Sahrens dp->slices = 138fa9e4066Sahrens get_disk_usable_slices( 139fa9e4066Sahrens media[0], dp->name, 140fa9e4066Sahrens dp->blocksize, 141fa9e4066Sahrens &(dp->in_use), error); 142fa9e4066Sahrens } 143fa9e4066Sahrens dm_free_descriptors(media); 144fa9e4066Sahrens } 145fa9e4066Sahrens } 146fa9e4066Sahrens } 147fa9e4066Sahrens } 148fa9e4066Sahrens 149fa9e4066Sahrens if (*error) { 150*dc307942Stalley /* Normalize error */ 151*dc307942Stalley *error = -1; 152fa9e4066Sahrens 153fa9e4066Sahrens if (dp != NULL) { 154fa9e4066Sahrens dmgt_free_disk(dp); 155fa9e4066Sahrens dp = NULL; 156fa9e4066Sahrens } 157fa9e4066Sahrens } 158fa9e4066Sahrens 159fa9e4066Sahrens return (dp); 160fa9e4066Sahrens } 161fa9e4066Sahrens 162fa9e4066Sahrens static char ** 163fa9e4066Sahrens get_disk_aliases(dm_descriptor_t disk, char *name, int *error) 164fa9e4066Sahrens { 165fa9e4066Sahrens char **names = NULL; 166fa9e4066Sahrens dm_descriptor_t *aliases; 167fa9e4066Sahrens 168fa9e4066Sahrens *error = 0; 169fa9e4066Sahrens aliases = dm_get_associated_descriptors(disk, DM_ALIAS, error); 170fa9e4066Sahrens if (*error || aliases == NULL) { 171fa9e4066Sahrens *error = -1; 172fa9e4066Sahrens handle_error("could not get aliases for disk %s", name); 173fa9e4066Sahrens } else { 174fa9e4066Sahrens 175fa9e4066Sahrens int j; 176fa9e4066Sahrens 177fa9e4066Sahrens /* Count aliases */ 178fa9e4066Sahrens for (j = 0; aliases[j] != NULL; j++); 179fa9e4066Sahrens 180fa9e4066Sahrens names = (char **)calloc(j + 1, sizeof (char *)); 181fa9e4066Sahrens if (names == NULL) { 182fa9e4066Sahrens *error = -1; 183fa9e4066Sahrens handle_error("out of memory"); 184fa9e4066Sahrens } else { 185fa9e4066Sahrens 186fa9e4066Sahrens /* For each alias... */ 187fa9e4066Sahrens for (j = 0; *error == 0 && aliases[j] != NULL; j++) { 188fa9e4066Sahrens 189fa9e4066Sahrens dm_descriptor_t alias = aliases[j]; 190fa9e4066Sahrens char *aname = dm_get_name(alias, error); 191fa9e4066Sahrens if (*error) { 192fa9e4066Sahrens handle_error("could not get alias %d " 193fa9e4066Sahrens "for disk %s", (j + 1), name); 194fa9e4066Sahrens } else { 195fa9e4066Sahrens names[j] = strdup(aname); 196fa9e4066Sahrens if (names[j] == NULL) { 197fa9e4066Sahrens *error = -1; 198fa9e4066Sahrens handle_error("out of memory"); 199fa9e4066Sahrens } 200fa9e4066Sahrens 201fa9e4066Sahrens dm_free_name(aname); 202fa9e4066Sahrens } 203fa9e4066Sahrens } 204fa9e4066Sahrens } 205fa9e4066Sahrens 206fa9e4066Sahrens dm_free_descriptors(aliases); 207fa9e4066Sahrens } 208fa9e4066Sahrens 209fa9e4066Sahrens if (*error && names != NULL) { 210fa9e4066Sahrens /* Free previously-allocated names */ 211c8e9ed14Stalley zjni_free_array((void **)names, free); 212fa9e4066Sahrens } 213fa9e4066Sahrens 214fa9e4066Sahrens return (names); 215fa9e4066Sahrens } 216fa9e4066Sahrens 217fa9e4066Sahrens static int 218fa9e4066Sahrens get_disk_online(dm_descriptor_t disk, int *error) 219fa9e4066Sahrens { 220fa9e4066Sahrens uint32_t status = 0; 221fa9e4066Sahrens 222fa9e4066Sahrens nvlist_t *attrs; 223fa9e4066Sahrens *error = 0; 224fa9e4066Sahrens attrs = dm_get_attributes(disk, error); 225fa9e4066Sahrens if (*error) { 226fa9e4066Sahrens handle_error("could not get disk attributes for disk"); 227fa9e4066Sahrens } else { 228fa9e4066Sahrens 229fa9e4066Sahrens /* Try to get the status */ 230fa9e4066Sahrens nvpair_t *match = zjni_nvlist_walk_nvpair( 231fa9e4066Sahrens attrs, DM_STATUS, DATA_TYPE_UINT32, NULL); 232fa9e4066Sahrens 233fa9e4066Sahrens if (match == NULL || nvpair_value_uint32(match, &status)) { 234fa9e4066Sahrens 235fa9e4066Sahrens handle_error("could not get status of disk"); 236fa9e4066Sahrens *error = 1; 237fa9e4066Sahrens } 238fa9e4066Sahrens 239fa9e4066Sahrens nvlist_free(attrs); 240fa9e4066Sahrens } 241fa9e4066Sahrens 242fa9e4066Sahrens return (status != 0); 243fa9e4066Sahrens } 244fa9e4066Sahrens 245fa9e4066Sahrens /* 246fa9e4066Sahrens * Gets the slices for the given disk. 247fa9e4066Sahrens * 248fa9e4066Sahrens * Results: 249fa9e4066Sahrens * 250fa9e4066Sahrens * 1. Success: error is set to 0 and slices are returned 251fa9e4066Sahrens * 252fa9e4066Sahrens * 2. Failure: error is set to -1 and NULL is returned 253fa9e4066Sahrens */ 254fa9e4066Sahrens static dmgt_slice_t ** 255fa9e4066Sahrens get_disk_slices(dm_descriptor_t media, const char *name, uint32_t blocksize, 256fa9e4066Sahrens int *error) 257fa9e4066Sahrens { 258fa9e4066Sahrens dm_descriptor_t *slices; 259fa9e4066Sahrens dmgt_slice_t **sap = NULL; 260fa9e4066Sahrens 261fa9e4066Sahrens *error = 0; 262fa9e4066Sahrens slices = dm_get_associated_descriptors(media, DM_SLICE, error); 263fa9e4066Sahrens if (*error != 0) { 264fa9e4066Sahrens handle_error("could not get slices of disk %s", name); 265fa9e4066Sahrens } else { 266fa9e4066Sahrens int j; 267fa9e4066Sahrens int nslices = 0; 268fa9e4066Sahrens 269fa9e4066Sahrens /* For each slice... */ 270fa9e4066Sahrens for (j = 0; *error == 0 && 271fa9e4066Sahrens slices != NULL && slices[j] != NULL; j++) { 272fa9e4066Sahrens 273fa9e4066Sahrens /* Get slice */ 274fa9e4066Sahrens dmgt_slice_t *slice = 275fa9e4066Sahrens get_slice(slices[j], blocksize, error); 276fa9e4066Sahrens if (!*error) { 277fa9e4066Sahrens 278fa9e4066Sahrens sap = (dmgt_slice_t **)realloc(sap, 279fa9e4066Sahrens (nslices + 2) * sizeof (dmgt_slice_t *)); 280fa9e4066Sahrens if (sap == NULL) { 281fa9e4066Sahrens handle_error("out of memory"); 282fa9e4066Sahrens *error = -1; 283fa9e4066Sahrens } else { 284fa9e4066Sahrens 285fa9e4066Sahrens /* NULL-terminated array */ 286fa9e4066Sahrens sap[nslices] = slice; 287fa9e4066Sahrens sap[nslices + 1] = NULL; 288fa9e4066Sahrens 289fa9e4066Sahrens nslices++; 290fa9e4066Sahrens } 291fa9e4066Sahrens } 292fa9e4066Sahrens } 293fa9e4066Sahrens 294fa9e4066Sahrens dm_free_descriptors(slices); 295fa9e4066Sahrens } 296fa9e4066Sahrens 297fa9e4066Sahrens if (*error) { 298fa9e4066Sahrens /* Normalize error */ 299fa9e4066Sahrens *error = -1; 300fa9e4066Sahrens } 301fa9e4066Sahrens 302fa9e4066Sahrens if (*error && sap != NULL) { 303c8e9ed14Stalley zjni_free_array((void **)sap, (zjni_free_f)dmgt_free_slice); 304fa9e4066Sahrens sap = NULL; 305fa9e4066Sahrens } 306fa9e4066Sahrens 307fa9e4066Sahrens return (sap); 308fa9e4066Sahrens } 309fa9e4066Sahrens 310fa9e4066Sahrens static void 311fa9e4066Sahrens remove_slice_from_list(dmgt_slice_t **slices, int index) 312fa9e4066Sahrens { 313fa9e4066Sahrens int i; 314fa9e4066Sahrens for (i = index; slices[i] != NULL; i++) { 315fa9e4066Sahrens slices[i] = slices[i + 1]; 316fa9e4066Sahrens } 317fa9e4066Sahrens } 318fa9e4066Sahrens 319fa9e4066Sahrens static int 320fa9e4066Sahrens slices_overlap(dmgt_slice_t *slice1, dmgt_slice_t *slice2) 321fa9e4066Sahrens { 322fa9e4066Sahrens 323fa9e4066Sahrens uint64_t start1 = slice1->start; 324fa9e4066Sahrens uint64_t end1 = start1 + slice1->size - 1; 325fa9e4066Sahrens uint64_t start2 = slice2->start; 326c8e9ed14Stalley uint64_t end2 = start2 + slice2->size - 1; 327fa9e4066Sahrens 328fa9e4066Sahrens int overlap = (start2 <= end1 && start1 <= end2); 329fa9e4066Sahrens 330fa9e4066Sahrens #ifdef DEBUG 331fa9e4066Sahrens if (overlap) { 332fa9e4066Sahrens (void) fprintf(stderr, "can't use %s: overlaps with %s\n", 333fa9e4066Sahrens slice2->name, slice1->name); 334fa9e4066Sahrens (void) fprintf(stderr, " 1: start: %llu - %llu\n", 335fa9e4066Sahrens (unsigned long long)start1, (unsigned long long)end1); 336fa9e4066Sahrens (void) fprintf(stderr, " 2: start: %llu - %llu\n", 337fa9e4066Sahrens (unsigned long long)start2, (unsigned long long)end2); 338fa9e4066Sahrens } 339fa9e4066Sahrens #endif 340fa9e4066Sahrens 341fa9e4066Sahrens return (overlap); 342fa9e4066Sahrens } 343fa9e4066Sahrens 344fa9e4066Sahrens /* 345fa9e4066Sahrens * Gets the slices for the given disk. 346fa9e4066Sahrens * 347fa9e4066Sahrens * Results: 348fa9e4066Sahrens * 349fa9e4066Sahrens * 1. Success: error is set to 0 and slices are returned 350fa9e4066Sahrens * 351fa9e4066Sahrens * 2. Failure: error is set to -1 and NULL is returned 352fa9e4066Sahrens */ 353fa9e4066Sahrens static dmgt_slice_t ** 354fa9e4066Sahrens get_disk_usable_slices(dm_descriptor_t media, const char *name, 355fa9e4066Sahrens uint32_t blocksize, int *in_use, int *error) 356fa9e4066Sahrens { 357fa9e4066Sahrens dmgt_slice_t **slices = get_disk_slices(media, name, blocksize, error); 358fa9e4066Sahrens 359fa9e4066Sahrens *in_use = 0; 360fa9e4066Sahrens 361fa9e4066Sahrens if (!*error && slices != NULL) { 362fa9e4066Sahrens int i, nslices; 363fa9e4066Sahrens 364fa9e4066Sahrens for (nslices = 0; slices[nslices] != NULL; nslices++); 365fa9e4066Sahrens 366fa9e4066Sahrens /* Prune slices based on use */ 367fa9e4066Sahrens for (i = nslices - 1; i >= 0; i--) { 368fa9e4066Sahrens dmgt_slice_t *slice = slices[i]; 369fa9e4066Sahrens if (slice == NULL) { 370fa9e4066Sahrens continue; 371fa9e4066Sahrens } 372fa9e4066Sahrens 373fa9e4066Sahrens if (slice_in_use(slice)) { 374fa9e4066Sahrens int j; 375fa9e4066Sahrens remove_slice_from_list(slices, i); 376fa9e4066Sahrens 377fa9e4066Sahrens *in_use = 1; 378fa9e4066Sahrens 379fa9e4066Sahrens /* 380fa9e4066Sahrens * Remove any slice that overlaps with this 381fa9e4066Sahrens * in-use slice 382fa9e4066Sahrens */ 383fa9e4066Sahrens for (j = nslices - 1; j >= 0; j--) { 384fa9e4066Sahrens if (slices[j] == NULL) { 385fa9e4066Sahrens continue; 386fa9e4066Sahrens } 387fa9e4066Sahrens if (slices_overlap(slice, slices[j])) { 388fa9e4066Sahrens remove_slice_from_list(slices, 389fa9e4066Sahrens j); 390fa9e4066Sahrens } 391fa9e4066Sahrens } 392*dc307942Stalley } else { 393fa9e4066Sahrens if (slice_too_small(slice)) { 394fa9e4066Sahrens remove_slice_from_list(slices, i); 395fa9e4066Sahrens } 396*dc307942Stalley } 397fa9e4066Sahrens } 398fa9e4066Sahrens } 399fa9e4066Sahrens 400fa9e4066Sahrens return (slices); 401fa9e4066Sahrens } 402fa9e4066Sahrens 403fa9e4066Sahrens static void 404fa9e4066Sahrens get_disk_size(dm_descriptor_t media, char *name, uint64_t *size, 405fa9e4066Sahrens uint32_t *blocksize, int *error) 406fa9e4066Sahrens { 407fa9e4066Sahrens nvlist_t *attrs; 408fa9e4066Sahrens 409fa9e4066Sahrens *size = 0; 410fa9e4066Sahrens *error = 0; 411fa9e4066Sahrens 412fa9e4066Sahrens attrs = dm_get_attributes(media, error); 413fa9e4066Sahrens 414fa9e4066Sahrens if (*error) { 415fa9e4066Sahrens handle_error("could not get media attributes from disk: %s", 416fa9e4066Sahrens name); 417fa9e4066Sahrens } else { 418fa9e4066Sahrens /* Try to get the number of accessible blocks */ 419fa9e4066Sahrens nvpair_t *match = zjni_nvlist_walk_nvpair( 420fa9e4066Sahrens attrs, DM_NACCESSIBLE, DATA_TYPE_UINT64, NULL); 421fa9e4066Sahrens if (match == NULL || nvpair_value_uint64(match, size)) { 422fa9e4066Sahrens 423fa9e4066Sahrens /* Disk is probably not labeled, get raw size instead */ 424fa9e4066Sahrens match = zjni_nvlist_walk_nvpair( 425fa9e4066Sahrens attrs, DM_SIZE, DATA_TYPE_UINT64, NULL); 426fa9e4066Sahrens if (match == NULL || nvpair_value_uint64(match, size)) { 427fa9e4066Sahrens handle_error("could not get size of disk: %s", 428fa9e4066Sahrens name); 429fa9e4066Sahrens *error = 1; 430fa9e4066Sahrens } 431fa9e4066Sahrens } 432fa9e4066Sahrens 433fa9e4066Sahrens if (*error == 0) { 434fa9e4066Sahrens match = zjni_nvlist_walk_nvpair( 435fa9e4066Sahrens attrs, DM_BLOCKSIZE, DATA_TYPE_UINT32, NULL); 436fa9e4066Sahrens if (match == NULL || 437fa9e4066Sahrens nvpair_value_uint32(match, blocksize)) { 438fa9e4066Sahrens handle_error("could not get " 439fa9e4066Sahrens "block size of disk: %s", name); 440fa9e4066Sahrens *error = 1; 441fa9e4066Sahrens } else { 442fa9e4066Sahrens *size *= *blocksize; 443fa9e4066Sahrens } 444fa9e4066Sahrens } 445fa9e4066Sahrens 446fa9e4066Sahrens nvlist_free(attrs); 447fa9e4066Sahrens } 448fa9e4066Sahrens } 449fa9e4066Sahrens 450fa9e4066Sahrens static void 451fa9e4066Sahrens get_slice_use(dm_descriptor_t slice, char *name, char **used_name, 452fa9e4066Sahrens char **used_by, int *error) 453fa9e4066Sahrens { 454fa9e4066Sahrens /* Get slice use statistics */ 455fa9e4066Sahrens nvlist_t *stats = dm_get_stats(slice, DM_SLICE_STAT_USE, error); 456fa9e4066Sahrens if (*error != 0) { 457fa9e4066Sahrens handle_error("could not get stats of slice %s", name); 458fa9e4066Sahrens } else { 459fa9e4066Sahrens 460fa9e4066Sahrens *used_name = NULL; 461fa9e4066Sahrens *used_by = NULL; 462fa9e4066Sahrens 463fa9e4066Sahrens if (stats != NULL) { 464fa9e4066Sahrens char *tmp; 465fa9e4066Sahrens nvpair_t *match; 466fa9e4066Sahrens 467fa9e4066Sahrens /* Get the type of usage for this slice */ 468fa9e4066Sahrens match = zjni_nvlist_walk_nvpair( 469fa9e4066Sahrens stats, DM_USED_BY, DATA_TYPE_STRING, NULL); 470fa9e4066Sahrens 471fa9e4066Sahrens if (match != NULL && 472fa9e4066Sahrens nvpair_value_string(match, &tmp) == 0) { 473fa9e4066Sahrens 474fa9e4066Sahrens *used_name = strdup(tmp); 475fa9e4066Sahrens if (*used_name == NULL) { 476fa9e4066Sahrens *error = -1; 477fa9e4066Sahrens handle_error("out of memory"); 478fa9e4066Sahrens } else { 479fa9e4066Sahrens 480fa9e4066Sahrens /* Get the object using this slice */ 481fa9e4066Sahrens match = 482fa9e4066Sahrens zjni_nvlist_walk_nvpair(stats, 483fa9e4066Sahrens DM_USED_NAME, DATA_TYPE_STRING, 484fa9e4066Sahrens NULL); 485fa9e4066Sahrens 486fa9e4066Sahrens if (match != NULL && 487fa9e4066Sahrens nvpair_value_string(match, &tmp) == 488fa9e4066Sahrens 0) { 489fa9e4066Sahrens *used_by = strdup(tmp); 490fa9e4066Sahrens if (*used_by == NULL) { 491fa9e4066Sahrens *error = -1; 492fa9e4066Sahrens handle_error( 493fa9e4066Sahrens "out of memory"); 494fa9e4066Sahrens } 495fa9e4066Sahrens } 496fa9e4066Sahrens } 497fa9e4066Sahrens } 498fa9e4066Sahrens nvlist_free(stats); 499fa9e4066Sahrens } 500fa9e4066Sahrens } 501fa9e4066Sahrens } 502fa9e4066Sahrens 503fa9e4066Sahrens static dmgt_slice_t * 504fa9e4066Sahrens get_slice(dm_descriptor_t slice, uint32_t blocksize, int *error) 505fa9e4066Sahrens { 506fa9e4066Sahrens dmgt_slice_t *sp; 507fa9e4066Sahrens *error = 0; 508fa9e4066Sahrens sp = (dmgt_slice_t *)calloc(1, sizeof (dmgt_slice_t)); 509fa9e4066Sahrens if (sp == NULL) { 510fa9e4066Sahrens *error = -1; 511fa9e4066Sahrens handle_error("out of memory"); 512fa9e4066Sahrens } else { 513fa9e4066Sahrens 514fa9e4066Sahrens /* Get name */ 515fa9e4066Sahrens sp->name = get_device_name(slice, error); 516fa9e4066Sahrens if (!*error) { 517fa9e4066Sahrens 518fa9e4066Sahrens nvlist_t *attrs = dm_get_attributes(slice, error); 519fa9e4066Sahrens if (*error) { 520fa9e4066Sahrens handle_error("could not get " 521fa9e4066Sahrens "attributes from slice: %s", sp->name); 522fa9e4066Sahrens } else { 523fa9e4066Sahrens /* Get the size in blocks */ 524fa9e4066Sahrens nvpair_t *match = zjni_nvlist_walk_nvpair( 525fa9e4066Sahrens attrs, DM_SIZE, DATA_TYPE_UINT64, NULL); 526fa9e4066Sahrens uint64_t size_blocks; 527fa9e4066Sahrens 528fa9e4066Sahrens sp->size = 0; 529fa9e4066Sahrens 530fa9e4066Sahrens if (match == NULL || 531fa9e4066Sahrens nvpair_value_uint64(match, &size_blocks)) { 532fa9e4066Sahrens handle_error("could not get " 533fa9e4066Sahrens "size of slice: %s", sp->name); 534fa9e4066Sahrens *error = 1; 535fa9e4066Sahrens } else { 536fa9e4066Sahrens uint64_t start_blocks; 537fa9e4066Sahrens 538fa9e4066Sahrens /* Convert to bytes */ 539fa9e4066Sahrens sp->size = blocksize * size_blocks; 540fa9e4066Sahrens 541fa9e4066Sahrens /* Get the starting block */ 542fa9e4066Sahrens match = zjni_nvlist_walk_nvpair( 543fa9e4066Sahrens attrs, DM_START, DATA_TYPE_UINT64, 544fa9e4066Sahrens NULL); 545fa9e4066Sahrens 546fa9e4066Sahrens if (match == NULL || 547fa9e4066Sahrens nvpair_value_uint64(match, 548fa9e4066Sahrens &start_blocks)) { 549fa9e4066Sahrens handle_error( 550fa9e4066Sahrens "could not get " 551fa9e4066Sahrens "start block of slice: %s", 552fa9e4066Sahrens sp->name); 553fa9e4066Sahrens *error = 1; 554fa9e4066Sahrens } else { 555fa9e4066Sahrens /* Convert to bytes */ 556fa9e4066Sahrens sp->start = 557fa9e4066Sahrens blocksize * start_blocks; 558fa9e4066Sahrens 559fa9e4066Sahrens /* Set slice use */ 560fa9e4066Sahrens get_slice_use(slice, sp->name, 561fa9e4066Sahrens &(sp->used_name), 562fa9e4066Sahrens &(sp->used_by), error); 563fa9e4066Sahrens } 564fa9e4066Sahrens } 565fa9e4066Sahrens } 566fa9e4066Sahrens } 567fa9e4066Sahrens } 568fa9e4066Sahrens 569fa9e4066Sahrens if (*error && sp != NULL) { 570fa9e4066Sahrens dmgt_free_slice(sp); 571fa9e4066Sahrens } 572fa9e4066Sahrens 573fa9e4066Sahrens return (sp); 574fa9e4066Sahrens } 575fa9e4066Sahrens 576fa9e4066Sahrens static void 577fa9e4066Sahrens handle_error(const char *format, ...) 578fa9e4066Sahrens { 579fa9e4066Sahrens va_list ap; 580fa9e4066Sahrens va_start(ap, format); 581fa9e4066Sahrens 582fa9e4066Sahrens if (error_func != NULL) { 583fa9e4066Sahrens error_func(format, ap); 584fa9e4066Sahrens } 585fa9e4066Sahrens 586fa9e4066Sahrens va_end(ap); 587fa9e4066Sahrens } 588fa9e4066Sahrens 589fa9e4066Sahrens /* Should go away once 6285992 is fixed */ 590fa9e4066Sahrens static int 591fa9e4066Sahrens slice_too_small(dmgt_slice_t *slice) 592fa9e4066Sahrens { 593fa9e4066Sahrens /* Check size */ 594fa9e4066Sahrens if (slice->size < SPA_MINDEVSIZE) { 595fa9e4066Sahrens #ifdef DEBUG 596fa9e4066Sahrens (void) fprintf(stderr, "can't use %s: slice too small: %llu\n", 597fa9e4066Sahrens slice->name, (unsigned long long)slice->size); 598fa9e4066Sahrens #endif 599fa9e4066Sahrens return (1); 600fa9e4066Sahrens } 601fa9e4066Sahrens 602fa9e4066Sahrens return (0); 603fa9e4066Sahrens } 604fa9e4066Sahrens 605fa9e4066Sahrens /* Should go away once 6285992 is fixed */ 606fa9e4066Sahrens static int 607fa9e4066Sahrens slice_in_use(dmgt_slice_t *slice) 608fa9e4066Sahrens { 609fa9e4066Sahrens int in_use = 0; 610fa9e4066Sahrens 611fa9e4066Sahrens /* Check use */ 612fa9e4066Sahrens if (slice->used_name != NULL) { 613fa9e4066Sahrens 614fa9e4066Sahrens in_use = 1; 615fa9e4066Sahrens 616fa9e4066Sahrens /* If the slice contains an unmounted file system... */ 617fa9e4066Sahrens if (strcmp(DM_USE_FS, slice->used_name) == 0) { 618fa9e4066Sahrens 619fa9e4066Sahrens /* Allow only if file system is not ZFS */ 620fa9e4066Sahrens if (strcmp(slice->used_by, "zfs") != 0) { 621fa9e4066Sahrens in_use = 0; 622fa9e4066Sahrens } 623fa9e4066Sahrens } else 624fa9e4066Sahrens 625fa9e4066Sahrens /* Uses that don't preclude slice from use by ZFS */ 626fa9e4066Sahrens if (strcmp(DM_USE_SVM, slice->used_name) == 0 || 627fa9e4066Sahrens strcmp(DM_USE_VXVM, slice->used_name) == 0 || 628fa9e4066Sahrens strcmp(DM_USE_LU, slice->used_name) == 0) { 629fa9e4066Sahrens in_use = 0; 630fa9e4066Sahrens } 631fa9e4066Sahrens } 632fa9e4066Sahrens 633fa9e4066Sahrens #ifdef DEBUG 634fa9e4066Sahrens if (in_use) { 635fa9e4066Sahrens (void) fprintf(stderr, 636fa9e4066Sahrens "can't use %s: used name: %s: used by: %s\n", 637fa9e4066Sahrens slice->name, slice->used_name, slice->used_by); 638fa9e4066Sahrens } 639fa9e4066Sahrens #endif 640fa9e4066Sahrens 641fa9e4066Sahrens return (in_use); 642fa9e4066Sahrens } 643fa9e4066Sahrens 644fa9e4066Sahrens /* 645fa9e4066Sahrens * Extern functions 646fa9e4066Sahrens */ 647fa9e4066Sahrens 648fa9e4066Sahrens /* 649fa9e4066Sahrens * Iterates through each available disk on the system. For each free 650fa9e4066Sahrens * dmgt_disk_t *, runs the given function with the dmgt_disk_t * as 651fa9e4066Sahrens * the first arg and the given void * as the second arg. 652fa9e4066Sahrens */ 653fa9e4066Sahrens int 654fa9e4066Sahrens dmgt_avail_disk_iter(dmgt_disk_iter_f func, void *data) 655fa9e4066Sahrens { 656fa9e4066Sahrens int error = 0; 657fa9e4066Sahrens int filter[] = { DM_DT_FIXED, -1 }; 658fa9e4066Sahrens 659fa9e4066Sahrens /* Search for fixed disks */ 660fa9e4066Sahrens dm_descriptor_t *disks = dm_get_descriptors(DM_DRIVE, filter, &error); 661fa9e4066Sahrens 662fa9e4066Sahrens if (error) { 663fa9e4066Sahrens handle_error("unable to communicate with libdiskmgt"); 664fa9e4066Sahrens } else { 665fa9e4066Sahrens int i; 666fa9e4066Sahrens 667fa9e4066Sahrens /* For each disk... */ 668fa9e4066Sahrens for (i = 0; disks != NULL && error == 0 && disks[i] != NULL; 669fa9e4066Sahrens i++) { 670fa9e4066Sahrens /* Is this disk online? */ 671fa9e4066Sahrens dm_descriptor_t disk = (dm_descriptor_t)disks[i]; 672fa9e4066Sahrens int online = get_disk_online(disk, &error); 673fa9e4066Sahrens if (!error && online) { 674fa9e4066Sahrens dmgt_disk_t *dp = get_disk(disk, &error); 675*dc307942Stalley if (!error) { 676*dc307942Stalley /* 677*dc307942Stalley * If this disk or any of its 678*dc307942Stalley * slices is usable... 679*dc307942Stalley */ 680*dc307942Stalley if (!dp->in_use || 681*dc307942Stalley zjni_count_elements( 682*dc307942Stalley (void **)dp->slices) != 0) { 683*dc307942Stalley 684fa9e4066Sahrens /* Run the given function */ 685fa9e4066Sahrens if (func(dp, data)) { 686fa9e4066Sahrens error = -1; 687fa9e4066Sahrens } 688fa9e4066Sahrens dmgt_free_disk(dp); 689*dc307942Stalley #ifdef DEBUG 690*dc307942Stalley } else { 691*dc307942Stalley (void) fprintf(stderr, "disk " 692*dc307942Stalley "has no available slices: " 693*dc307942Stalley "%s\n", dp->name); 694*dc307942Stalley #endif 695fa9e4066Sahrens } 696*dc307942Stalley 697*dc307942Stalley } 698fa9e4066Sahrens } 699fa9e4066Sahrens } 700fa9e4066Sahrens dm_free_descriptors(disks); 701fa9e4066Sahrens } 702fa9e4066Sahrens return (error); 703fa9e4066Sahrens } 704fa9e4066Sahrens 705fa9e4066Sahrens void 706fa9e4066Sahrens dmgt_free_disk(dmgt_disk_t *disk) 707fa9e4066Sahrens { 708fa9e4066Sahrens if (disk != NULL) { 709fa9e4066Sahrens free(disk->name); 710c8e9ed14Stalley zjni_free_array((void **)disk->aliases, free); 711c8e9ed14Stalley zjni_free_array((void **)disk->slices, 712c8e9ed14Stalley (zjni_free_f)dmgt_free_slice); 713fa9e4066Sahrens free(disk); 714fa9e4066Sahrens } 715fa9e4066Sahrens } 716fa9e4066Sahrens 717fa9e4066Sahrens void 718fa9e4066Sahrens dmgt_free_slice(dmgt_slice_t *slice) 719fa9e4066Sahrens { 720fa9e4066Sahrens if (slice != NULL) { 721fa9e4066Sahrens free(slice->name); 722fa9e4066Sahrens free(slice->used_name); 723fa9e4066Sahrens free(slice->used_by); 724fa9e4066Sahrens free(slice); 725fa9e4066Sahrens } 726fa9e4066Sahrens } 727fa9e4066Sahrens 728fa9e4066Sahrens /* 729fa9e4066Sahrens * For clients that need to capture error output. 730fa9e4066Sahrens */ 731fa9e4066Sahrens void 732fa9e4066Sahrens dmgt_set_error_handler(void (*func)(const char *, va_list)) 733fa9e4066Sahrens { 734fa9e4066Sahrens error_func = func; 735fa9e4066Sahrens } 736