1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5*32f884e0Stalley * Common Development and Distribution License (the "License"). 6*32f884e0Stalley * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21*32f884e0Stalley 22fa9e4066Sahrens /* 23*32f884e0Stalley * Copyright 2006 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, ...); 55*32f884e0Stalley static int slice_in_use(dmgt_slice_t *slice, int *error); 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) { 150dc307942Stalley /* Normalize error */ 151dc307942Stalley *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 278*32f884e0Stalley dmgt_slice_t **mem = 279*32f884e0Stalley (dmgt_slice_t **)realloc(sap, 280fa9e4066Sahrens (nslices + 2) * sizeof (dmgt_slice_t *)); 281*32f884e0Stalley 282*32f884e0Stalley if (mem == NULL) { 283fa9e4066Sahrens handle_error("out of memory"); 284fa9e4066Sahrens *error = -1; 285fa9e4066Sahrens } else { 286fa9e4066Sahrens 287*32f884e0Stalley sap = mem; 288*32f884e0Stalley 289fa9e4066Sahrens /* NULL-terminated array */ 290fa9e4066Sahrens sap[nslices] = slice; 291fa9e4066Sahrens sap[nslices + 1] = NULL; 292fa9e4066Sahrens 293fa9e4066Sahrens nslices++; 294fa9e4066Sahrens } 295fa9e4066Sahrens } 296fa9e4066Sahrens } 297fa9e4066Sahrens 298fa9e4066Sahrens dm_free_descriptors(slices); 299fa9e4066Sahrens } 300fa9e4066Sahrens 301fa9e4066Sahrens if (*error) { 302fa9e4066Sahrens /* Normalize error */ 303fa9e4066Sahrens *error = -1; 304fa9e4066Sahrens 305*32f884e0Stalley if (sap != NULL) { 306*32f884e0Stalley zjni_free_array((void **)sap, 307*32f884e0Stalley (zjni_free_f)dmgt_free_slice); 308*32f884e0Stalley sap = NULL; 309*32f884e0Stalley } 310fa9e4066Sahrens } 311fa9e4066Sahrens 312fa9e4066Sahrens return (sap); 313fa9e4066Sahrens } 314fa9e4066Sahrens 315fa9e4066Sahrens static void 316fa9e4066Sahrens remove_slice_from_list(dmgt_slice_t **slices, int index) 317fa9e4066Sahrens { 318fa9e4066Sahrens int i; 319fa9e4066Sahrens for (i = index; slices[i] != NULL; i++) { 320fa9e4066Sahrens slices[i] = slices[i + 1]; 321fa9e4066Sahrens } 322fa9e4066Sahrens } 323fa9e4066Sahrens 324fa9e4066Sahrens static int 325fa9e4066Sahrens slices_overlap(dmgt_slice_t *slice1, dmgt_slice_t *slice2) 326fa9e4066Sahrens { 327fa9e4066Sahrens 328fa9e4066Sahrens uint64_t start1 = slice1->start; 329fa9e4066Sahrens uint64_t end1 = start1 + slice1->size - 1; 330fa9e4066Sahrens uint64_t start2 = slice2->start; 331c8e9ed14Stalley uint64_t end2 = start2 + slice2->size - 1; 332fa9e4066Sahrens 333fa9e4066Sahrens int overlap = (start2 <= end1 && start1 <= end2); 334fa9e4066Sahrens 335fa9e4066Sahrens #ifdef DEBUG 336fa9e4066Sahrens if (overlap) { 337fa9e4066Sahrens (void) fprintf(stderr, "can't use %s: overlaps with %s\n", 338fa9e4066Sahrens slice2->name, slice1->name); 339fa9e4066Sahrens (void) fprintf(stderr, " 1: start: %llu - %llu\n", 340fa9e4066Sahrens (unsigned long long)start1, (unsigned long long)end1); 341fa9e4066Sahrens (void) fprintf(stderr, " 2: start: %llu - %llu\n", 342fa9e4066Sahrens (unsigned long long)start2, (unsigned long long)end2); 343fa9e4066Sahrens } 344fa9e4066Sahrens #endif 345fa9e4066Sahrens 346fa9e4066Sahrens return (overlap); 347fa9e4066Sahrens } 348fa9e4066Sahrens 349fa9e4066Sahrens /* 350fa9e4066Sahrens * Gets the slices for the given disk. 351fa9e4066Sahrens * 352fa9e4066Sahrens * Results: 353fa9e4066Sahrens * 354fa9e4066Sahrens * 1. Success: error is set to 0 and slices are returned 355fa9e4066Sahrens * 356fa9e4066Sahrens * 2. Failure: error is set to -1 and NULL is returned 357fa9e4066Sahrens */ 358fa9e4066Sahrens static dmgt_slice_t ** 359fa9e4066Sahrens get_disk_usable_slices(dm_descriptor_t media, const char *name, 360fa9e4066Sahrens uint32_t blocksize, int *in_use, int *error) 361fa9e4066Sahrens { 362fa9e4066Sahrens dmgt_slice_t **slices = get_disk_slices(media, name, blocksize, error); 363*32f884e0Stalley if (*error) { 364*32f884e0Stalley slices = NULL; 365*32f884e0Stalley } 366fa9e4066Sahrens 367fa9e4066Sahrens *in_use = 0; 368fa9e4066Sahrens 369*32f884e0Stalley if (slices != NULL) { 370fa9e4066Sahrens int i, nslices; 371fa9e4066Sahrens 372fa9e4066Sahrens for (nslices = 0; slices[nslices] != NULL; nslices++); 373fa9e4066Sahrens 374fa9e4066Sahrens /* Prune slices based on use */ 375fa9e4066Sahrens for (i = nslices - 1; i >= 0; i--) { 376fa9e4066Sahrens dmgt_slice_t *slice = slices[i]; 377*32f884e0Stalley int s_in_use; 378*32f884e0Stalley 379*32f884e0Stalley /* 380*32f884e0Stalley * Slice at this index could be NULL if 381*32f884e0Stalley * removed in earlier iteration 382*32f884e0Stalley */ 383fa9e4066Sahrens if (slice == NULL) { 384fa9e4066Sahrens continue; 385fa9e4066Sahrens } 386fa9e4066Sahrens 387*32f884e0Stalley s_in_use = slice_in_use(slice, error); 388*32f884e0Stalley if (*error) { 389*32f884e0Stalley break; 390*32f884e0Stalley } 391*32f884e0Stalley 392*32f884e0Stalley if (s_in_use) { 393fa9e4066Sahrens int j; 394fa9e4066Sahrens remove_slice_from_list(slices, i); 395fa9e4066Sahrens 396*32f884e0Stalley /* Disk is in use */ 397fa9e4066Sahrens *in_use = 1; 398fa9e4066Sahrens 399fa9e4066Sahrens /* 400fa9e4066Sahrens * Remove any slice that overlaps with this 401fa9e4066Sahrens * in-use slice 402fa9e4066Sahrens */ 403fa9e4066Sahrens for (j = nslices - 1; j >= 0; j--) { 404*32f884e0Stalley dmgt_slice_t *slice2 = slices[j]; 405*32f884e0Stalley 406*32f884e0Stalley if (slice2 != NULL && 407*32f884e0Stalley slices_overlap(slice, slice2)) { 408fa9e4066Sahrens remove_slice_from_list(slices, 409fa9e4066Sahrens j); 410*32f884e0Stalley dmgt_free_slice(slice2); 411fa9e4066Sahrens } 412fa9e4066Sahrens } 413*32f884e0Stalley 414*32f884e0Stalley dmgt_free_slice(slice); 415*32f884e0Stalley } else if (slice_too_small(slice)) { 416*32f884e0Stalley remove_slice_from_list(slices, i); 417*32f884e0Stalley dmgt_free_slice(slice); 418dc307942Stalley } 419fa9e4066Sahrens } 420fa9e4066Sahrens } 421fa9e4066Sahrens 422*32f884e0Stalley if (*error) { 423*32f884e0Stalley /* Normalize error */ 424*32f884e0Stalley *error = -1; 425*32f884e0Stalley 426*32f884e0Stalley if (slices != NULL) { 427*32f884e0Stalley zjni_free_array((void **)slices, 428*32f884e0Stalley (zjni_free_f)dmgt_free_slice); 429*32f884e0Stalley slices = NULL; 430*32f884e0Stalley } 431*32f884e0Stalley } 432*32f884e0Stalley 433fa9e4066Sahrens return (slices); 434fa9e4066Sahrens } 435fa9e4066Sahrens 436fa9e4066Sahrens static void 437fa9e4066Sahrens get_disk_size(dm_descriptor_t media, char *name, uint64_t *size, 438fa9e4066Sahrens uint32_t *blocksize, int *error) 439fa9e4066Sahrens { 440fa9e4066Sahrens nvlist_t *attrs; 441fa9e4066Sahrens 442fa9e4066Sahrens *size = 0; 443fa9e4066Sahrens *error = 0; 444fa9e4066Sahrens 445fa9e4066Sahrens attrs = dm_get_attributes(media, error); 446fa9e4066Sahrens 447fa9e4066Sahrens if (*error) { 448fa9e4066Sahrens handle_error("could not get media attributes from disk: %s", 449fa9e4066Sahrens name); 450fa9e4066Sahrens } else { 451fa9e4066Sahrens /* Try to get the number of accessible blocks */ 452fa9e4066Sahrens nvpair_t *match = zjni_nvlist_walk_nvpair( 453fa9e4066Sahrens attrs, DM_NACCESSIBLE, DATA_TYPE_UINT64, NULL); 454fa9e4066Sahrens if (match == NULL || nvpair_value_uint64(match, size)) { 455fa9e4066Sahrens 456fa9e4066Sahrens /* Disk is probably not labeled, get raw size instead */ 457fa9e4066Sahrens match = zjni_nvlist_walk_nvpair( 458fa9e4066Sahrens attrs, DM_SIZE, DATA_TYPE_UINT64, NULL); 459fa9e4066Sahrens if (match == NULL || nvpair_value_uint64(match, size)) { 460fa9e4066Sahrens handle_error("could not get size of disk: %s", 461fa9e4066Sahrens name); 462fa9e4066Sahrens *error = 1; 463fa9e4066Sahrens } 464fa9e4066Sahrens } 465fa9e4066Sahrens 466fa9e4066Sahrens if (*error == 0) { 467fa9e4066Sahrens match = zjni_nvlist_walk_nvpair( 468fa9e4066Sahrens attrs, DM_BLOCKSIZE, DATA_TYPE_UINT32, NULL); 469fa9e4066Sahrens if (match == NULL || 470fa9e4066Sahrens nvpair_value_uint32(match, blocksize)) { 471fa9e4066Sahrens handle_error("could not get " 472fa9e4066Sahrens "block size of disk: %s", name); 473fa9e4066Sahrens *error = 1; 474fa9e4066Sahrens } else { 475fa9e4066Sahrens *size *= *blocksize; 476fa9e4066Sahrens } 477fa9e4066Sahrens } 478fa9e4066Sahrens 479fa9e4066Sahrens nvlist_free(attrs); 480fa9e4066Sahrens } 481fa9e4066Sahrens } 482fa9e4066Sahrens 483fa9e4066Sahrens static void 484fa9e4066Sahrens get_slice_use(dm_descriptor_t slice, char *name, char **used_name, 485fa9e4066Sahrens char **used_by, int *error) 486fa9e4066Sahrens { 487fa9e4066Sahrens /* Get slice use statistics */ 488fa9e4066Sahrens nvlist_t *stats = dm_get_stats(slice, DM_SLICE_STAT_USE, error); 489fa9e4066Sahrens if (*error != 0) { 490fa9e4066Sahrens handle_error("could not get stats of slice %s", name); 491fa9e4066Sahrens } else { 492fa9e4066Sahrens 493fa9e4066Sahrens *used_name = NULL; 494fa9e4066Sahrens *used_by = NULL; 495fa9e4066Sahrens 496fa9e4066Sahrens if (stats != NULL) { 497fa9e4066Sahrens char *tmp; 498fa9e4066Sahrens nvpair_t *match; 499fa9e4066Sahrens 500fa9e4066Sahrens /* Get the type of usage for this slice */ 501fa9e4066Sahrens match = zjni_nvlist_walk_nvpair( 502fa9e4066Sahrens stats, DM_USED_BY, DATA_TYPE_STRING, NULL); 503fa9e4066Sahrens 504fa9e4066Sahrens if (match != NULL && 505fa9e4066Sahrens nvpair_value_string(match, &tmp) == 0) { 506fa9e4066Sahrens 507fa9e4066Sahrens *used_name = strdup(tmp); 508fa9e4066Sahrens if (*used_name == NULL) { 509fa9e4066Sahrens *error = -1; 510fa9e4066Sahrens handle_error("out of memory"); 511fa9e4066Sahrens } else { 512fa9e4066Sahrens 513fa9e4066Sahrens /* Get the object using this slice */ 514fa9e4066Sahrens match = 515fa9e4066Sahrens zjni_nvlist_walk_nvpair(stats, 516fa9e4066Sahrens DM_USED_NAME, DATA_TYPE_STRING, 517fa9e4066Sahrens NULL); 518fa9e4066Sahrens 519fa9e4066Sahrens if (match != NULL && 520fa9e4066Sahrens nvpair_value_string(match, &tmp) == 521fa9e4066Sahrens 0) { 522fa9e4066Sahrens *used_by = strdup(tmp); 523fa9e4066Sahrens if (*used_by == NULL) { 524fa9e4066Sahrens *error = -1; 525fa9e4066Sahrens handle_error( 526fa9e4066Sahrens "out of memory"); 527fa9e4066Sahrens } 528fa9e4066Sahrens } 529fa9e4066Sahrens } 530fa9e4066Sahrens } 531fa9e4066Sahrens nvlist_free(stats); 532fa9e4066Sahrens } 533fa9e4066Sahrens } 534fa9e4066Sahrens } 535fa9e4066Sahrens 536fa9e4066Sahrens static dmgt_slice_t * 537fa9e4066Sahrens get_slice(dm_descriptor_t slice, uint32_t blocksize, int *error) 538fa9e4066Sahrens { 539fa9e4066Sahrens dmgt_slice_t *sp; 540fa9e4066Sahrens *error = 0; 541fa9e4066Sahrens sp = (dmgt_slice_t *)calloc(1, sizeof (dmgt_slice_t)); 542fa9e4066Sahrens if (sp == NULL) { 543fa9e4066Sahrens *error = -1; 544fa9e4066Sahrens handle_error("out of memory"); 545fa9e4066Sahrens } else { 546fa9e4066Sahrens 547fa9e4066Sahrens /* Get name */ 548fa9e4066Sahrens sp->name = get_device_name(slice, error); 549fa9e4066Sahrens if (!*error) { 550fa9e4066Sahrens 551fa9e4066Sahrens nvlist_t *attrs = dm_get_attributes(slice, error); 552fa9e4066Sahrens if (*error) { 553fa9e4066Sahrens handle_error("could not get " 554fa9e4066Sahrens "attributes from slice: %s", sp->name); 555fa9e4066Sahrens } else { 556fa9e4066Sahrens /* Get the size in blocks */ 557fa9e4066Sahrens nvpair_t *match = zjni_nvlist_walk_nvpair( 558fa9e4066Sahrens attrs, DM_SIZE, DATA_TYPE_UINT64, NULL); 559fa9e4066Sahrens uint64_t size_blocks; 560fa9e4066Sahrens 561fa9e4066Sahrens sp->size = 0; 562fa9e4066Sahrens 563fa9e4066Sahrens if (match == NULL || 564fa9e4066Sahrens nvpair_value_uint64(match, &size_blocks)) { 565fa9e4066Sahrens handle_error("could not get " 566fa9e4066Sahrens "size of slice: %s", sp->name); 567fa9e4066Sahrens *error = 1; 568fa9e4066Sahrens } else { 569fa9e4066Sahrens uint64_t start_blocks; 570fa9e4066Sahrens 571fa9e4066Sahrens /* Convert to bytes */ 572fa9e4066Sahrens sp->size = blocksize * size_blocks; 573fa9e4066Sahrens 574fa9e4066Sahrens /* Get the starting block */ 575fa9e4066Sahrens match = zjni_nvlist_walk_nvpair( 576fa9e4066Sahrens attrs, DM_START, DATA_TYPE_UINT64, 577fa9e4066Sahrens NULL); 578fa9e4066Sahrens 579fa9e4066Sahrens if (match == NULL || 580fa9e4066Sahrens nvpair_value_uint64(match, 581fa9e4066Sahrens &start_blocks)) { 582fa9e4066Sahrens handle_error( 583fa9e4066Sahrens "could not get " 584fa9e4066Sahrens "start block of slice: %s", 585fa9e4066Sahrens sp->name); 586fa9e4066Sahrens *error = 1; 587fa9e4066Sahrens } else { 588fa9e4066Sahrens /* Convert to bytes */ 589fa9e4066Sahrens sp->start = 590fa9e4066Sahrens blocksize * start_blocks; 591fa9e4066Sahrens 592fa9e4066Sahrens /* Set slice use */ 593fa9e4066Sahrens get_slice_use(slice, sp->name, 594fa9e4066Sahrens &(sp->used_name), 595fa9e4066Sahrens &(sp->used_by), error); 596fa9e4066Sahrens } 597fa9e4066Sahrens } 598fa9e4066Sahrens } 599fa9e4066Sahrens } 600fa9e4066Sahrens } 601fa9e4066Sahrens 602fa9e4066Sahrens if (*error && sp != NULL) { 603fa9e4066Sahrens dmgt_free_slice(sp); 604fa9e4066Sahrens } 605fa9e4066Sahrens 606fa9e4066Sahrens return (sp); 607fa9e4066Sahrens } 608fa9e4066Sahrens 609fa9e4066Sahrens static void 610fa9e4066Sahrens handle_error(const char *format, ...) 611fa9e4066Sahrens { 612fa9e4066Sahrens va_list ap; 613fa9e4066Sahrens va_start(ap, format); 614fa9e4066Sahrens 615fa9e4066Sahrens if (error_func != NULL) { 616fa9e4066Sahrens error_func(format, ap); 617fa9e4066Sahrens } 618fa9e4066Sahrens 619fa9e4066Sahrens va_end(ap); 620fa9e4066Sahrens } 621fa9e4066Sahrens 622fa9e4066Sahrens /* Should go away once 6285992 is fixed */ 623fa9e4066Sahrens static int 624fa9e4066Sahrens slice_too_small(dmgt_slice_t *slice) 625fa9e4066Sahrens { 626fa9e4066Sahrens /* Check size */ 627fa9e4066Sahrens if (slice->size < SPA_MINDEVSIZE) { 628fa9e4066Sahrens #ifdef DEBUG 629fa9e4066Sahrens (void) fprintf(stderr, "can't use %s: slice too small: %llu\n", 630fa9e4066Sahrens slice->name, (unsigned long long)slice->size); 631fa9e4066Sahrens #endif 632fa9e4066Sahrens return (1); 633fa9e4066Sahrens } 634fa9e4066Sahrens 635fa9e4066Sahrens return (0); 636fa9e4066Sahrens } 637fa9e4066Sahrens 638fa9e4066Sahrens static int 639*32f884e0Stalley slice_in_use(dmgt_slice_t *slice, int *error) 640fa9e4066Sahrens { 641*32f884e0Stalley char *msg = NULL; 642*32f884e0Stalley int in_use; 643fa9e4066Sahrens 644*32f884e0Stalley /* Determine whether this slice could be passed to "zpool -f" */ 645*32f884e0Stalley in_use = dm_inuse(slice->name, &msg, DM_WHO_ZPOOL_FORCE, error); 646*32f884e0Stalley if (*error) { 647*32f884e0Stalley handle_error("%s: could not determine usage", slice->name); 648fa9e4066Sahrens } 649fa9e4066Sahrens 650fa9e4066Sahrens #ifdef DEBUG 651fa9e4066Sahrens if (in_use) { 652fa9e4066Sahrens (void) fprintf(stderr, 653*32f884e0Stalley "can't use %s: used name: %s: used by: %s\n message: %s\n", 654*32f884e0Stalley slice->name, slice->used_name, slice->used_by, msg); 655fa9e4066Sahrens } 656fa9e4066Sahrens #endif 657fa9e4066Sahrens 658*32f884e0Stalley if (msg != NULL) { 659*32f884e0Stalley free(msg); 660*32f884e0Stalley } 661*32f884e0Stalley 662fa9e4066Sahrens return (in_use); 663fa9e4066Sahrens } 664fa9e4066Sahrens 665fa9e4066Sahrens /* 666fa9e4066Sahrens * Extern functions 667fa9e4066Sahrens */ 668fa9e4066Sahrens 669fa9e4066Sahrens /* 670fa9e4066Sahrens * Iterates through each available disk on the system. For each free 671fa9e4066Sahrens * dmgt_disk_t *, runs the given function with the dmgt_disk_t * as 672fa9e4066Sahrens * the first arg and the given void * as the second arg. 673fa9e4066Sahrens */ 674fa9e4066Sahrens int 675fa9e4066Sahrens dmgt_avail_disk_iter(dmgt_disk_iter_f func, void *data) 676fa9e4066Sahrens { 677fa9e4066Sahrens int error = 0; 678fa9e4066Sahrens int filter[] = { DM_DT_FIXED, -1 }; 679fa9e4066Sahrens 680fa9e4066Sahrens /* Search for fixed disks */ 681fa9e4066Sahrens dm_descriptor_t *disks = dm_get_descriptors(DM_DRIVE, filter, &error); 682fa9e4066Sahrens 683fa9e4066Sahrens if (error) { 684fa9e4066Sahrens handle_error("unable to communicate with libdiskmgt"); 685fa9e4066Sahrens } else { 686fa9e4066Sahrens int i; 687fa9e4066Sahrens 688fa9e4066Sahrens /* For each disk... */ 689*32f884e0Stalley for (i = 0; disks != NULL && disks[i] != NULL; i++) { 690fa9e4066Sahrens dm_descriptor_t disk = (dm_descriptor_t)disks[i]; 691*32f884e0Stalley int online; 692*32f884e0Stalley 693*32f884e0Stalley /* Reset error flag for each disk */ 694*32f884e0Stalley error = 0; 695*32f884e0Stalley 696*32f884e0Stalley /* Is this disk online? */ 697*32f884e0Stalley online = get_disk_online(disk, &error); 698fa9e4066Sahrens if (!error && online) { 699*32f884e0Stalley 700*32f884e0Stalley /* Get a dmgt_disk_t for this dm_descriptor_t */ 701fa9e4066Sahrens dmgt_disk_t *dp = get_disk(disk, &error); 702dc307942Stalley if (!error) { 703*32f884e0Stalley 704dc307942Stalley /* 705dc307942Stalley * If this disk or any of its 706dc307942Stalley * slices is usable... 707dc307942Stalley */ 708dc307942Stalley if (!dp->in_use || 709dc307942Stalley zjni_count_elements( 710dc307942Stalley (void **)dp->slices) != 0) { 711dc307942Stalley 712fa9e4066Sahrens /* Run the given function */ 713fa9e4066Sahrens if (func(dp, data)) { 714fa9e4066Sahrens error = -1; 715fa9e4066Sahrens } 716fa9e4066Sahrens dmgt_free_disk(dp); 717dc307942Stalley #ifdef DEBUG 718dc307942Stalley } else { 719dc307942Stalley (void) fprintf(stderr, "disk " 720dc307942Stalley "has no available slices: " 721dc307942Stalley "%s\n", dp->name); 722dc307942Stalley #endif 723fa9e4066Sahrens } 724dc307942Stalley 725dc307942Stalley } 726fa9e4066Sahrens } 727fa9e4066Sahrens } 728fa9e4066Sahrens dm_free_descriptors(disks); 729fa9e4066Sahrens } 730fa9e4066Sahrens return (error); 731fa9e4066Sahrens } 732fa9e4066Sahrens 733fa9e4066Sahrens void 734fa9e4066Sahrens dmgt_free_disk(dmgt_disk_t *disk) 735fa9e4066Sahrens { 736fa9e4066Sahrens if (disk != NULL) { 737fa9e4066Sahrens free(disk->name); 738c8e9ed14Stalley zjni_free_array((void **)disk->aliases, free); 739c8e9ed14Stalley zjni_free_array((void **)disk->slices, 740c8e9ed14Stalley (zjni_free_f)dmgt_free_slice); 741fa9e4066Sahrens free(disk); 742fa9e4066Sahrens } 743fa9e4066Sahrens } 744fa9e4066Sahrens 745fa9e4066Sahrens void 746fa9e4066Sahrens dmgt_free_slice(dmgt_slice_t *slice) 747fa9e4066Sahrens { 748fa9e4066Sahrens if (slice != NULL) { 749fa9e4066Sahrens free(slice->name); 750fa9e4066Sahrens free(slice->used_name); 751fa9e4066Sahrens free(slice->used_by); 752fa9e4066Sahrens free(slice); 753fa9e4066Sahrens } 754fa9e4066Sahrens } 755fa9e4066Sahrens 756fa9e4066Sahrens /* 757fa9e4066Sahrens * For clients that need to capture error output. 758fa9e4066Sahrens */ 759fa9e4066Sahrens void 760fa9e4066Sahrens dmgt_set_error_handler(void (*func)(const char *, va_list)) 761fa9e4066Sahrens { 762fa9e4066Sahrens error_func = func; 763fa9e4066Sahrens } 764