1fa9e4066Sahrens /*
2fa9e4066Sahrens * CDDL HEADER START
3fa9e4066Sahrens *
4fa9e4066Sahrens * The contents of this file are subject to the terms of the
532f884e0Stalley * Common Development and Distribution License (the "License").
632f884e0Stalley * 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 */
2132f884e0Stalley
22fa9e4066Sahrens /*
2332f884e0Stalley * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24fa9e4066Sahrens * Use is subject to license terms.
25fa9e4066Sahrens */
26fa9e4066Sahrens
27f83b46baSPaul Dagnelie /*
28f83b46baSPaul Dagnelie * Copyright (c) 2015 by Delphix. All rights reserved.
29f83b46baSPaul Dagnelie */
30fa9e4066Sahrens
31fa9e4066Sahrens #include "libzfs_jni_diskmgt.h"
32fa9e4066Sahrens #include "libzfs_jni_util.h"
33fa9e4066Sahrens #include <strings.h>
34fa9e4066Sahrens #include <libzfs.h>
35fa9e4066Sahrens #include <sys/mnttab.h>
36fa9e4066Sahrens
37fa9e4066Sahrens /*
38fa9e4066Sahrens * Function prototypes
39fa9e4066Sahrens */
40fa9e4066Sahrens
41fa9e4066Sahrens static char *get_device_name(dm_descriptor_t device, int *error);
42fa9e4066Sahrens static dmgt_disk_t *get_disk(dm_descriptor_t disk, int *error);
43fa9e4066Sahrens static char **get_disk_aliases(dm_descriptor_t disk, char *name, int *error);
44fa9e4066Sahrens static int get_disk_online(dm_descriptor_t disk, int *error);
45fa9e4066Sahrens static void remove_slice_from_list(dmgt_slice_t **slices, int index);
46fa9e4066Sahrens static dmgt_slice_t **get_disk_slices(dm_descriptor_t media,
47fa9e4066Sahrens const char *name, uint32_t blocksize, int *error);
48fa9e4066Sahrens static dmgt_slice_t **get_disk_usable_slices(dm_descriptor_t media,
49fa9e4066Sahrens const char *name, uint32_t blocksize, int *in_use, int *error);
50fa9e4066Sahrens static void get_disk_size(dm_descriptor_t media, char *name,
51fa9e4066Sahrens uint64_t *size, uint32_t *blocksize, int *error);
52fa9e4066Sahrens static void get_slice_use(dm_descriptor_t slice, char *name,
53fa9e4066Sahrens char **used_name, char **used_by, int *error);
54fa9e4066Sahrens static dmgt_slice_t *get_slice(
55fa9e4066Sahrens dm_descriptor_t slice, uint32_t blocksize, int *error);
56fa9e4066Sahrens static void handle_error(const char *format, ...);
5732f884e0Stalley static int slice_in_use(dmgt_slice_t *slice, int *error);
58fa9e4066Sahrens static int slice_too_small(dmgt_slice_t *slice);
59fa9e4066Sahrens
60fa9e4066Sahrens /*
61fa9e4066Sahrens * Static data
62fa9e4066Sahrens */
63fa9e4066Sahrens
64fa9e4066Sahrens static void (*error_func)(const char *, va_list);
65fa9e4066Sahrens
66fa9e4066Sahrens /*
67fa9e4066Sahrens * Static functions
68fa9e4066Sahrens */
69fa9e4066Sahrens
70fa9e4066Sahrens static char *
get_device_name(dm_descriptor_t device,int * error)71fa9e4066Sahrens get_device_name(dm_descriptor_t device, int *error)
72fa9e4066Sahrens {
73f83b46baSPaul Dagnelie char *dup = NULL;
74fa9e4066Sahrens char *name;
75fa9e4066Sahrens
76fa9e4066Sahrens *error = 0;
77fa9e4066Sahrens name = dm_get_name(device, error);
78fa9e4066Sahrens if (*error) {
79fa9e4066Sahrens handle_error("could not determine name of device");
80fa9e4066Sahrens } else {
81fa9e4066Sahrens dup = strdup(name);
82fa9e4066Sahrens if (dup == NULL) {
83fa9e4066Sahrens handle_error("out of memory");
84fa9e4066Sahrens *error = -1;
85fa9e4066Sahrens }
86fa9e4066Sahrens
87fa9e4066Sahrens dm_free_name(name);
88fa9e4066Sahrens }
89fa9e4066Sahrens
90fa9e4066Sahrens return (dup);
91fa9e4066Sahrens }
92fa9e4066Sahrens
93fa9e4066Sahrens /*
94fa9e4066Sahrens * Gets a dmgt_disk_t for the given disk dm_descriptor_t.
95fa9e4066Sahrens *
96fa9e4066Sahrens * Results:
97fa9e4066Sahrens *
98fa9e4066Sahrens * 1. Success: error is set to 0 and a dmgt_disk_t is returned
99fa9e4066Sahrens *
100fa9e4066Sahrens * 2. Failure: error is set to -1 and NULL is returned
101fa9e4066Sahrens */
102fa9e4066Sahrens static dmgt_disk_t *
get_disk(dm_descriptor_t disk,int * error)103fa9e4066Sahrens get_disk(dm_descriptor_t disk, int *error)
104fa9e4066Sahrens {
105fa9e4066Sahrens dmgt_disk_t *dp;
106fa9e4066Sahrens *error = 0;
107fa9e4066Sahrens
108fa9e4066Sahrens dp = (dmgt_disk_t *)calloc(1, sizeof (dmgt_disk_t));
109fa9e4066Sahrens if (dp == NULL) {
110fa9e4066Sahrens handle_error("out of memory");
111fa9e4066Sahrens *error = -1;
112fa9e4066Sahrens } else {
113fa9e4066Sahrens
114fa9e4066Sahrens /* Get name */
115fa9e4066Sahrens dp->name = get_device_name(disk, error);
116fa9e4066Sahrens if (!*error) {
117fa9e4066Sahrens
118fa9e4066Sahrens /* Get aliases */
119fa9e4066Sahrens dp->aliases = get_disk_aliases(disk, dp->name, error);
120fa9e4066Sahrens if (!*error) {
121fa9e4066Sahrens
122fa9e4066Sahrens /* Get media */
123fa9e4066Sahrens dm_descriptor_t *media =
124fa9e4066Sahrens dm_get_associated_descriptors(disk,
125f83b46baSPaul Dagnelie DM_MEDIA, error);
126fa9e4066Sahrens if (*error != 0 || media == NULL ||
127*48ac33d9SToomas Soome *media == 0) {
128fa9e4066Sahrens handle_error(
129fa9e4066Sahrens "could not get media from disk %s",
130fa9e4066Sahrens dp->name);
131fa9e4066Sahrens *error = -1;
132fa9e4066Sahrens } else {
133fa9e4066Sahrens /* Get size */
134fa9e4066Sahrens get_disk_size(media[0], dp->name,
135fa9e4066Sahrens &(dp->size), &(dp->blocksize),
136fa9e4066Sahrens error);
137fa9e4066Sahrens if (!*error) {
138fa9e4066Sahrens /* Get free slices */
139fa9e4066Sahrens dp->slices =
140fa9e4066Sahrens get_disk_usable_slices(
141f83b46baSPaul Dagnelie media[0], dp->name,
142f83b46baSPaul Dagnelie dp->blocksize,
143f83b46baSPaul Dagnelie &(dp->in_use), error);
144fa9e4066Sahrens }
145fa9e4066Sahrens dm_free_descriptors(media);
146fa9e4066Sahrens }
147fa9e4066Sahrens }
148fa9e4066Sahrens }
149fa9e4066Sahrens }
150fa9e4066Sahrens
151fa9e4066Sahrens if (*error) {
152dc307942Stalley /* Normalize error */
153dc307942Stalley *error = -1;
154fa9e4066Sahrens
155fa9e4066Sahrens if (dp != NULL) {
156fa9e4066Sahrens dmgt_free_disk(dp);
157fa9e4066Sahrens dp = NULL;
158fa9e4066Sahrens }
159fa9e4066Sahrens }
160fa9e4066Sahrens
161fa9e4066Sahrens return (dp);
162fa9e4066Sahrens }
163fa9e4066Sahrens
164fa9e4066Sahrens static char **
get_disk_aliases(dm_descriptor_t disk,char * name,int * error)165fa9e4066Sahrens get_disk_aliases(dm_descriptor_t disk, char *name, int *error)
166fa9e4066Sahrens {
167fa9e4066Sahrens char **names = NULL;
168fa9e4066Sahrens dm_descriptor_t *aliases;
169fa9e4066Sahrens
170fa9e4066Sahrens *error = 0;
171fa9e4066Sahrens aliases = dm_get_associated_descriptors(disk, DM_ALIAS, error);
172fa9e4066Sahrens if (*error || aliases == NULL) {
173fa9e4066Sahrens *error = -1;
174fa9e4066Sahrens handle_error("could not get aliases for disk %s", name);
175fa9e4066Sahrens } else {
176fa9e4066Sahrens
177fa9e4066Sahrens int j;
178fa9e4066Sahrens
179fa9e4066Sahrens /* Count aliases */
180*48ac33d9SToomas Soome for (j = 0; aliases[j] != 0; j++)
181f83b46baSPaul Dagnelie ;
182fa9e4066Sahrens
183fa9e4066Sahrens names = (char **)calloc(j + 1, sizeof (char *));
184fa9e4066Sahrens if (names == NULL) {
185fa9e4066Sahrens *error = -1;
186fa9e4066Sahrens handle_error("out of memory");
187fa9e4066Sahrens } else {
188fa9e4066Sahrens
189fa9e4066Sahrens /* For each alias... */
190*48ac33d9SToomas Soome for (j = 0; *error == 0 && aliases[j] != 0; j++) {
191fa9e4066Sahrens
192fa9e4066Sahrens dm_descriptor_t alias = aliases[j];
193fa9e4066Sahrens char *aname = dm_get_name(alias, error);
194fa9e4066Sahrens if (*error) {
195fa9e4066Sahrens handle_error("could not get alias %d "
196fa9e4066Sahrens "for disk %s", (j + 1), name);
197fa9e4066Sahrens } else {
198fa9e4066Sahrens names[j] = strdup(aname);
199fa9e4066Sahrens if (names[j] == NULL) {
200fa9e4066Sahrens *error = -1;
201fa9e4066Sahrens handle_error("out of memory");
202fa9e4066Sahrens }
203fa9e4066Sahrens
204fa9e4066Sahrens dm_free_name(aname);
205fa9e4066Sahrens }
206fa9e4066Sahrens }
207fa9e4066Sahrens }
208fa9e4066Sahrens
209fa9e4066Sahrens dm_free_descriptors(aliases);
210fa9e4066Sahrens }
211fa9e4066Sahrens
212fa9e4066Sahrens if (*error && names != NULL) {
213fa9e4066Sahrens /* Free previously-allocated names */
214c8e9ed14Stalley zjni_free_array((void **)names, free);
215fa9e4066Sahrens }
216fa9e4066Sahrens
217fa9e4066Sahrens return (names);
218fa9e4066Sahrens }
219fa9e4066Sahrens
220fa9e4066Sahrens static int
get_disk_online(dm_descriptor_t disk,int * error)221fa9e4066Sahrens get_disk_online(dm_descriptor_t disk, int *error)
222fa9e4066Sahrens {
223fa9e4066Sahrens uint32_t status = 0;
224fa9e4066Sahrens
225fa9e4066Sahrens nvlist_t *attrs;
226fa9e4066Sahrens *error = 0;
227fa9e4066Sahrens attrs = dm_get_attributes(disk, error);
228fa9e4066Sahrens if (*error) {
229fa9e4066Sahrens handle_error("could not get disk attributes for disk");
230fa9e4066Sahrens } else {
231fa9e4066Sahrens
232fa9e4066Sahrens /* Try to get the status */
233fa9e4066Sahrens nvpair_t *match = zjni_nvlist_walk_nvpair(
234fa9e4066Sahrens attrs, DM_STATUS, DATA_TYPE_UINT32, NULL);
235fa9e4066Sahrens
236fa9e4066Sahrens if (match == NULL || nvpair_value_uint32(match, &status)) {
237fa9e4066Sahrens
238fa9e4066Sahrens handle_error("could not get status of disk");
239fa9e4066Sahrens *error = 1;
240fa9e4066Sahrens }
241fa9e4066Sahrens
242fa9e4066Sahrens nvlist_free(attrs);
243fa9e4066Sahrens }
244fa9e4066Sahrens
245fa9e4066Sahrens return (status != 0);
246fa9e4066Sahrens }
247fa9e4066Sahrens
248fa9e4066Sahrens /*
249fa9e4066Sahrens * Gets the slices for the given disk.
250fa9e4066Sahrens *
251fa9e4066Sahrens * Results:
252fa9e4066Sahrens *
253fa9e4066Sahrens * 1. Success: error is set to 0 and slices are returned
254fa9e4066Sahrens *
255fa9e4066Sahrens * 2. Failure: error is set to -1 and NULL is returned
256fa9e4066Sahrens */
257fa9e4066Sahrens static dmgt_slice_t **
get_disk_slices(dm_descriptor_t media,const char * name,uint32_t blocksize,int * error)258fa9e4066Sahrens get_disk_slices(dm_descriptor_t media, const char *name, uint32_t blocksize,
259fa9e4066Sahrens int *error)
260fa9e4066Sahrens {
261fa9e4066Sahrens dm_descriptor_t *slices;
262fa9e4066Sahrens dmgt_slice_t **sap = NULL;
263fa9e4066Sahrens
264fa9e4066Sahrens *error = 0;
265fa9e4066Sahrens slices = dm_get_associated_descriptors(media, DM_SLICE, error);
266fa9e4066Sahrens if (*error != 0) {
267fa9e4066Sahrens handle_error("could not get slices of disk %s", name);
268fa9e4066Sahrens } else {
269fa9e4066Sahrens int j;
270fa9e4066Sahrens int nslices = 0;
271fa9e4066Sahrens
272fa9e4066Sahrens /* For each slice... */
273fa9e4066Sahrens for (j = 0; *error == 0 &&
274*48ac33d9SToomas Soome slices != NULL && slices[j] != 0; j++) {
275fa9e4066Sahrens
276fa9e4066Sahrens /* Get slice */
277fa9e4066Sahrens dmgt_slice_t *slice =
278fa9e4066Sahrens get_slice(slices[j], blocksize, error);
279fa9e4066Sahrens if (!*error) {
280fa9e4066Sahrens
28132f884e0Stalley dmgt_slice_t **mem =
28232f884e0Stalley (dmgt_slice_t **)realloc(sap,
283fa9e4066Sahrens (nslices + 2) * sizeof (dmgt_slice_t *));
28432f884e0Stalley
28532f884e0Stalley if (mem == NULL) {
286fa9e4066Sahrens handle_error("out of memory");
287fa9e4066Sahrens *error = -1;
288fa9e4066Sahrens } else {
289fa9e4066Sahrens
29032f884e0Stalley sap = mem;
29132f884e0Stalley
292fa9e4066Sahrens /* NULL-terminated array */
293fa9e4066Sahrens sap[nslices] = slice;
294fa9e4066Sahrens sap[nslices + 1] = NULL;
295fa9e4066Sahrens
296fa9e4066Sahrens nslices++;
297fa9e4066Sahrens }
298fa9e4066Sahrens }
299fa9e4066Sahrens }
300fa9e4066Sahrens
301fa9e4066Sahrens dm_free_descriptors(slices);
302fa9e4066Sahrens }
303fa9e4066Sahrens
304fa9e4066Sahrens if (*error) {
305fa9e4066Sahrens /* Normalize error */
306fa9e4066Sahrens *error = -1;
307fa9e4066Sahrens
30832f884e0Stalley if (sap != NULL) {
30932f884e0Stalley zjni_free_array((void **)sap,
31032f884e0Stalley (zjni_free_f)dmgt_free_slice);
31132f884e0Stalley sap = NULL;
31232f884e0Stalley }
313fa9e4066Sahrens }
314fa9e4066Sahrens
315fa9e4066Sahrens return (sap);
316fa9e4066Sahrens }
317fa9e4066Sahrens
318fa9e4066Sahrens static void
remove_slice_from_list(dmgt_slice_t ** slices,int index)319fa9e4066Sahrens remove_slice_from_list(dmgt_slice_t **slices, int index)
320fa9e4066Sahrens {
321fa9e4066Sahrens int i;
322fa9e4066Sahrens for (i = index; slices[i] != NULL; i++) {
323fa9e4066Sahrens slices[i] = slices[i + 1];
324fa9e4066Sahrens }
325fa9e4066Sahrens }
326fa9e4066Sahrens
327fa9e4066Sahrens static int
slices_overlap(dmgt_slice_t * slice1,dmgt_slice_t * slice2)328fa9e4066Sahrens slices_overlap(dmgt_slice_t *slice1, dmgt_slice_t *slice2)
329fa9e4066Sahrens {
330fa9e4066Sahrens
331fa9e4066Sahrens uint64_t start1 = slice1->start;
332fa9e4066Sahrens uint64_t end1 = start1 + slice1->size - 1;
333fa9e4066Sahrens uint64_t start2 = slice2->start;
334c8e9ed14Stalley uint64_t end2 = start2 + slice2->size - 1;
335fa9e4066Sahrens
336fa9e4066Sahrens int overlap = (start2 <= end1 && start1 <= end2);
337fa9e4066Sahrens
338fa9e4066Sahrens #ifdef DEBUG
339fa9e4066Sahrens if (overlap) {
340fa9e4066Sahrens (void) fprintf(stderr, "can't use %s: overlaps with %s\n",
341fa9e4066Sahrens slice2->name, slice1->name);
342fa9e4066Sahrens (void) fprintf(stderr, " 1: start: %llu - %llu\n",
343fa9e4066Sahrens (unsigned long long)start1, (unsigned long long)end1);
344fa9e4066Sahrens (void) fprintf(stderr, " 2: start: %llu - %llu\n",
345fa9e4066Sahrens (unsigned long long)start2, (unsigned long long)end2);
346fa9e4066Sahrens }
347fa9e4066Sahrens #endif
348fa9e4066Sahrens
349fa9e4066Sahrens return (overlap);
350fa9e4066Sahrens }
351fa9e4066Sahrens
352fa9e4066Sahrens /*
353fa9e4066Sahrens * Gets the slices for the given disk.
354fa9e4066Sahrens *
355fa9e4066Sahrens * Results:
356fa9e4066Sahrens *
357fa9e4066Sahrens * 1. Success: error is set to 0 and slices are returned
358fa9e4066Sahrens *
359fa9e4066Sahrens * 2. Failure: error is set to -1 and NULL is returned
360fa9e4066Sahrens */
361fa9e4066Sahrens static dmgt_slice_t **
get_disk_usable_slices(dm_descriptor_t media,const char * name,uint32_t blocksize,int * in_use,int * error)362fa9e4066Sahrens get_disk_usable_slices(dm_descriptor_t media, const char *name,
363fa9e4066Sahrens uint32_t blocksize, int *in_use, int *error)
364fa9e4066Sahrens {
365fa9e4066Sahrens dmgt_slice_t **slices = get_disk_slices(media, name, blocksize, error);
36632f884e0Stalley if (*error) {
36732f884e0Stalley slices = NULL;
36832f884e0Stalley }
369fa9e4066Sahrens
370fa9e4066Sahrens *in_use = 0;
371fa9e4066Sahrens
37232f884e0Stalley if (slices != NULL) {
373fa9e4066Sahrens int i, nslices;
374fa9e4066Sahrens
375f83b46baSPaul Dagnelie for (nslices = 0; slices[nslices] != NULL; nslices++)
376f83b46baSPaul Dagnelie ;
377fa9e4066Sahrens
378fa9e4066Sahrens /* Prune slices based on use */
379fa9e4066Sahrens for (i = nslices - 1; i >= 0; i--) {
380fa9e4066Sahrens dmgt_slice_t *slice = slices[i];
38132f884e0Stalley int s_in_use;
38232f884e0Stalley
38332f884e0Stalley /*
38432f884e0Stalley * Slice at this index could be NULL if
38532f884e0Stalley * removed in earlier iteration
38632f884e0Stalley */
387fa9e4066Sahrens if (slice == NULL) {
388fa9e4066Sahrens continue;
389fa9e4066Sahrens }
390fa9e4066Sahrens
39132f884e0Stalley s_in_use = slice_in_use(slice, error);
39232f884e0Stalley if (*error) {
393f83b46baSPaul Dagnelie break;
39432f884e0Stalley }
39532f884e0Stalley
39632f884e0Stalley if (s_in_use) {
397fa9e4066Sahrens int j;
398fa9e4066Sahrens remove_slice_from_list(slices, i);
399fa9e4066Sahrens
40032f884e0Stalley /* Disk is in use */
401fa9e4066Sahrens *in_use = 1;
402fa9e4066Sahrens
403fa9e4066Sahrens /*
404fa9e4066Sahrens * Remove any slice that overlaps with this
405fa9e4066Sahrens * in-use slice
406fa9e4066Sahrens */
407fa9e4066Sahrens for (j = nslices - 1; j >= 0; j--) {
40832f884e0Stalley dmgt_slice_t *slice2 = slices[j];
40932f884e0Stalley
41032f884e0Stalley if (slice2 != NULL &&
41132f884e0Stalley slices_overlap(slice, slice2)) {
412fa9e4066Sahrens remove_slice_from_list(slices,
413fa9e4066Sahrens j);
41432f884e0Stalley dmgt_free_slice(slice2);
415fa9e4066Sahrens }
416fa9e4066Sahrens }
41732f884e0Stalley
41832f884e0Stalley dmgt_free_slice(slice);
41932f884e0Stalley } else if (slice_too_small(slice)) {
42032f884e0Stalley remove_slice_from_list(slices, i);
42132f884e0Stalley dmgt_free_slice(slice);
422dc307942Stalley }
423fa9e4066Sahrens }
424fa9e4066Sahrens }
425fa9e4066Sahrens
42632f884e0Stalley if (*error) {
42732f884e0Stalley /* Normalize error */
42832f884e0Stalley *error = -1;
42932f884e0Stalley
43032f884e0Stalley if (slices != NULL) {
43132f884e0Stalley zjni_free_array((void **)slices,
43232f884e0Stalley (zjni_free_f)dmgt_free_slice);
43332f884e0Stalley slices = NULL;
43432f884e0Stalley }
43532f884e0Stalley }
43632f884e0Stalley
437fa9e4066Sahrens return (slices);
438fa9e4066Sahrens }
439fa9e4066Sahrens
440fa9e4066Sahrens static void
get_disk_size(dm_descriptor_t media,char * name,uint64_t * size,uint32_t * blocksize,int * error)441fa9e4066Sahrens get_disk_size(dm_descriptor_t media, char *name, uint64_t *size,
442fa9e4066Sahrens uint32_t *blocksize, int *error)
443fa9e4066Sahrens {
444fa9e4066Sahrens nvlist_t *attrs;
445fa9e4066Sahrens
446fa9e4066Sahrens *size = 0;
447fa9e4066Sahrens *error = 0;
448fa9e4066Sahrens
449fa9e4066Sahrens attrs = dm_get_attributes(media, error);
450fa9e4066Sahrens
451fa9e4066Sahrens if (*error) {
452fa9e4066Sahrens handle_error("could not get media attributes from disk: %s",
453fa9e4066Sahrens name);
454fa9e4066Sahrens } else {
455fa9e4066Sahrens /* Try to get the number of accessible blocks */
456fa9e4066Sahrens nvpair_t *match = zjni_nvlist_walk_nvpair(
457fa9e4066Sahrens attrs, DM_NACCESSIBLE, DATA_TYPE_UINT64, NULL);
458fa9e4066Sahrens if (match == NULL || nvpair_value_uint64(match, size)) {
459fa9e4066Sahrens
460fa9e4066Sahrens /* Disk is probably not labeled, get raw size instead */
461fa9e4066Sahrens match = zjni_nvlist_walk_nvpair(
462fa9e4066Sahrens attrs, DM_SIZE, DATA_TYPE_UINT64, NULL);
463fa9e4066Sahrens if (match == NULL || nvpair_value_uint64(match, size)) {
464fa9e4066Sahrens handle_error("could not get size of disk: %s",
465fa9e4066Sahrens name);
466fa9e4066Sahrens *error = 1;
467fa9e4066Sahrens }
468fa9e4066Sahrens }
469fa9e4066Sahrens
470fa9e4066Sahrens if (*error == 0) {
471fa9e4066Sahrens match = zjni_nvlist_walk_nvpair(
472fa9e4066Sahrens attrs, DM_BLOCKSIZE, DATA_TYPE_UINT32, NULL);
473fa9e4066Sahrens if (match == NULL ||
474fa9e4066Sahrens nvpair_value_uint32(match, blocksize)) {
475fa9e4066Sahrens handle_error("could not get "
476fa9e4066Sahrens "block size of disk: %s", name);
477fa9e4066Sahrens *error = 1;
478fa9e4066Sahrens } else {
479fa9e4066Sahrens *size *= *blocksize;
480fa9e4066Sahrens }
481fa9e4066Sahrens }
482fa9e4066Sahrens
483fa9e4066Sahrens nvlist_free(attrs);
484fa9e4066Sahrens }
485fa9e4066Sahrens }
486fa9e4066Sahrens
487fa9e4066Sahrens static void
get_slice_use(dm_descriptor_t slice,char * name,char ** used_name,char ** used_by,int * error)488fa9e4066Sahrens get_slice_use(dm_descriptor_t slice, char *name, char **used_name,
489fa9e4066Sahrens char **used_by, int *error)
490fa9e4066Sahrens {
491fa9e4066Sahrens /* Get slice use statistics */
492fa9e4066Sahrens nvlist_t *stats = dm_get_stats(slice, DM_SLICE_STAT_USE, error);
493fa9e4066Sahrens if (*error != 0) {
494fa9e4066Sahrens handle_error("could not get stats of slice %s", name);
495fa9e4066Sahrens } else {
496fa9e4066Sahrens
497fa9e4066Sahrens *used_name = NULL;
498fa9e4066Sahrens *used_by = NULL;
499fa9e4066Sahrens
500fa9e4066Sahrens if (stats != NULL) {
501fa9e4066Sahrens char *tmp;
502fa9e4066Sahrens nvpair_t *match;
503fa9e4066Sahrens
504fa9e4066Sahrens /* Get the type of usage for this slice */
505fa9e4066Sahrens match = zjni_nvlist_walk_nvpair(
506fa9e4066Sahrens stats, DM_USED_BY, DATA_TYPE_STRING, NULL);
507fa9e4066Sahrens
508fa9e4066Sahrens if (match != NULL &&
509fa9e4066Sahrens nvpair_value_string(match, &tmp) == 0) {
510fa9e4066Sahrens
511fa9e4066Sahrens *used_name = strdup(tmp);
512fa9e4066Sahrens if (*used_name == NULL) {
513fa9e4066Sahrens *error = -1;
514fa9e4066Sahrens handle_error("out of memory");
515fa9e4066Sahrens } else {
516fa9e4066Sahrens
517fa9e4066Sahrens /* Get the object using this slice */
518fa9e4066Sahrens match =
519fa9e4066Sahrens zjni_nvlist_walk_nvpair(stats,
520fa9e4066Sahrens DM_USED_NAME, DATA_TYPE_STRING,
521fa9e4066Sahrens NULL);
522fa9e4066Sahrens
523fa9e4066Sahrens if (match != NULL &&
524fa9e4066Sahrens nvpair_value_string(match, &tmp) ==
525fa9e4066Sahrens 0) {
526fa9e4066Sahrens *used_by = strdup(tmp);
527fa9e4066Sahrens if (*used_by == NULL) {
528fa9e4066Sahrens *error = -1;
529fa9e4066Sahrens handle_error(
530fa9e4066Sahrens "out of memory");
531fa9e4066Sahrens }
532fa9e4066Sahrens }
533fa9e4066Sahrens }
534fa9e4066Sahrens }
535fa9e4066Sahrens nvlist_free(stats);
536fa9e4066Sahrens }
537fa9e4066Sahrens }
538fa9e4066Sahrens }
539fa9e4066Sahrens
540fa9e4066Sahrens static dmgt_slice_t *
get_slice(dm_descriptor_t slice,uint32_t blocksize,int * error)541fa9e4066Sahrens get_slice(dm_descriptor_t slice, uint32_t blocksize, int *error)
542fa9e4066Sahrens {
543fa9e4066Sahrens dmgt_slice_t *sp;
544fa9e4066Sahrens *error = 0;
545fa9e4066Sahrens sp = (dmgt_slice_t *)calloc(1, sizeof (dmgt_slice_t));
546fa9e4066Sahrens if (sp == NULL) {
547fa9e4066Sahrens *error = -1;
548fa9e4066Sahrens handle_error("out of memory");
549fa9e4066Sahrens } else {
550fa9e4066Sahrens
551fa9e4066Sahrens /* Get name */
552fa9e4066Sahrens sp->name = get_device_name(slice, error);
553fa9e4066Sahrens if (!*error) {
554fa9e4066Sahrens
555fa9e4066Sahrens nvlist_t *attrs = dm_get_attributes(slice, error);
556fa9e4066Sahrens if (*error) {
557fa9e4066Sahrens handle_error("could not get "
558fa9e4066Sahrens "attributes from slice: %s", sp->name);
559fa9e4066Sahrens } else {
560fa9e4066Sahrens /* Get the size in blocks */
561fa9e4066Sahrens nvpair_t *match = zjni_nvlist_walk_nvpair(
562fa9e4066Sahrens attrs, DM_SIZE, DATA_TYPE_UINT64, NULL);
563fa9e4066Sahrens uint64_t size_blocks;
564fa9e4066Sahrens
565fa9e4066Sahrens sp->size = 0;
566fa9e4066Sahrens
567fa9e4066Sahrens if (match == NULL ||
568fa9e4066Sahrens nvpair_value_uint64(match, &size_blocks)) {
569fa9e4066Sahrens handle_error("could not get "
570fa9e4066Sahrens "size of slice: %s", sp->name);
571fa9e4066Sahrens *error = 1;
572fa9e4066Sahrens } else {
573fa9e4066Sahrens uint64_t start_blocks;
574fa9e4066Sahrens
575fa9e4066Sahrens /* Convert to bytes */
576fa9e4066Sahrens sp->size = blocksize * size_blocks;
577fa9e4066Sahrens
578fa9e4066Sahrens /* Get the starting block */
579fa9e4066Sahrens match = zjni_nvlist_walk_nvpair(
580fa9e4066Sahrens attrs, DM_START, DATA_TYPE_UINT64,
581fa9e4066Sahrens NULL);
582fa9e4066Sahrens
583fa9e4066Sahrens if (match == NULL ||
584fa9e4066Sahrens nvpair_value_uint64(match,
585fa9e4066Sahrens &start_blocks)) {
586fa9e4066Sahrens handle_error(
587fa9e4066Sahrens "could not get "
588fa9e4066Sahrens "start block of slice: %s",
589fa9e4066Sahrens sp->name);
590fa9e4066Sahrens *error = 1;
591fa9e4066Sahrens } else {
592fa9e4066Sahrens /* Convert to bytes */
593fa9e4066Sahrens sp->start =
594fa9e4066Sahrens blocksize * start_blocks;
595fa9e4066Sahrens
596fa9e4066Sahrens /* Set slice use */
597fa9e4066Sahrens get_slice_use(slice, sp->name,
598fa9e4066Sahrens &(sp->used_name),
599fa9e4066Sahrens &(sp->used_by), error);
600fa9e4066Sahrens }
601fa9e4066Sahrens }
602fa9e4066Sahrens }
603fa9e4066Sahrens }
604fa9e4066Sahrens }
605fa9e4066Sahrens
606fa9e4066Sahrens if (*error && sp != NULL) {
607fa9e4066Sahrens dmgt_free_slice(sp);
608fa9e4066Sahrens }
609fa9e4066Sahrens
610fa9e4066Sahrens return (sp);
611fa9e4066Sahrens }
612fa9e4066Sahrens
613fa9e4066Sahrens static void
handle_error(const char * format,...)614fa9e4066Sahrens handle_error(const char *format, ...)
615fa9e4066Sahrens {
616fa9e4066Sahrens va_list ap;
617fa9e4066Sahrens va_start(ap, format);
618fa9e4066Sahrens
619fa9e4066Sahrens if (error_func != NULL) {
620fa9e4066Sahrens error_func(format, ap);
621fa9e4066Sahrens }
622fa9e4066Sahrens
623fa9e4066Sahrens va_end(ap);
624fa9e4066Sahrens }
625fa9e4066Sahrens
626fa9e4066Sahrens /* Should go away once 6285992 is fixed */
627fa9e4066Sahrens static int
slice_too_small(dmgt_slice_t * slice)628fa9e4066Sahrens slice_too_small(dmgt_slice_t *slice)
629fa9e4066Sahrens {
630fa9e4066Sahrens /* Check size */
631fa9e4066Sahrens if (slice->size < SPA_MINDEVSIZE) {
632fa9e4066Sahrens #ifdef DEBUG
633fa9e4066Sahrens (void) fprintf(stderr, "can't use %s: slice too small: %llu\n",
634f83b46baSPaul Dagnelie slice->name, (unsigned long long)slice->size);
635fa9e4066Sahrens #endif
636fa9e4066Sahrens return (1);
637fa9e4066Sahrens }
638fa9e4066Sahrens
639fa9e4066Sahrens return (0);
640fa9e4066Sahrens }
641fa9e4066Sahrens
642fa9e4066Sahrens static int
slice_in_use(dmgt_slice_t * slice,int * error)64332f884e0Stalley slice_in_use(dmgt_slice_t *slice, int *error)
644fa9e4066Sahrens {
64532f884e0Stalley char *msg = NULL;
64632f884e0Stalley int in_use;
647fa9e4066Sahrens
64832f884e0Stalley /* Determine whether this slice could be passed to "zpool -f" */
64932f884e0Stalley in_use = dm_inuse(slice->name, &msg, DM_WHO_ZPOOL_FORCE, error);
65032f884e0Stalley if (*error) {
65132f884e0Stalley handle_error("%s: could not determine usage", slice->name);
652fa9e4066Sahrens }
653fa9e4066Sahrens
654fa9e4066Sahrens #ifdef DEBUG
655fa9e4066Sahrens if (in_use) {
656fa9e4066Sahrens (void) fprintf(stderr,
65732f884e0Stalley "can't use %s: used name: %s: used by: %s\n message: %s\n",
65832f884e0Stalley slice->name, slice->used_name, slice->used_by, msg);
659fa9e4066Sahrens }
660fa9e4066Sahrens #endif
661fa9e4066Sahrens
66232f884e0Stalley if (msg != NULL) {
66332f884e0Stalley free(msg);
66432f884e0Stalley }
66532f884e0Stalley
666fa9e4066Sahrens return (in_use);
667fa9e4066Sahrens }
668fa9e4066Sahrens
669fa9e4066Sahrens /*
670fa9e4066Sahrens * Extern functions
671fa9e4066Sahrens */
672fa9e4066Sahrens
673fa9e4066Sahrens /*
674fa9e4066Sahrens * Iterates through each available disk on the system. For each free
675fa9e4066Sahrens * dmgt_disk_t *, runs the given function with the dmgt_disk_t * as
676fa9e4066Sahrens * the first arg and the given void * as the second arg.
677fa9e4066Sahrens */
678fa9e4066Sahrens int
dmgt_avail_disk_iter(dmgt_disk_iter_f func,void * data)679fa9e4066Sahrens dmgt_avail_disk_iter(dmgt_disk_iter_f func, void *data)
680fa9e4066Sahrens {
681fa9e4066Sahrens int error = 0;
682fa9e4066Sahrens int filter[] = { DM_DT_FIXED, -1 };
683fa9e4066Sahrens
684fa9e4066Sahrens /* Search for fixed disks */
685fa9e4066Sahrens dm_descriptor_t *disks = dm_get_descriptors(DM_DRIVE, filter, &error);
686fa9e4066Sahrens
687fa9e4066Sahrens if (error) {
688fa9e4066Sahrens handle_error("unable to communicate with libdiskmgt");
689fa9e4066Sahrens } else {
690fa9e4066Sahrens int i;
691fa9e4066Sahrens
692fa9e4066Sahrens /* For each disk... */
693*48ac33d9SToomas Soome for (i = 0; disks != NULL && disks[i] != 0; i++) {
694fa9e4066Sahrens dm_descriptor_t disk = (dm_descriptor_t)disks[i];
69532f884e0Stalley int online;
69632f884e0Stalley
69732f884e0Stalley /* Reset error flag for each disk */
69832f884e0Stalley error = 0;
69932f884e0Stalley
70032f884e0Stalley /* Is this disk online? */
70132f884e0Stalley online = get_disk_online(disk, &error);
702fa9e4066Sahrens if (!error && online) {
70332f884e0Stalley
70432f884e0Stalley /* Get a dmgt_disk_t for this dm_descriptor_t */
705fa9e4066Sahrens dmgt_disk_t *dp = get_disk(disk, &error);
706dc307942Stalley if (!error) {
70732f884e0Stalley
708dc307942Stalley /*
709dc307942Stalley * If this disk or any of its
710dc307942Stalley * slices is usable...
711dc307942Stalley */
712dc307942Stalley if (!dp->in_use ||
713dc307942Stalley zjni_count_elements(
714dc307942Stalley (void **)dp->slices) != 0) {
715dc307942Stalley
716fa9e4066Sahrens /* Run the given function */
717fa9e4066Sahrens if (func(dp, data)) {
718fa9e4066Sahrens error = -1;
719fa9e4066Sahrens }
720fa9e4066Sahrens dmgt_free_disk(dp);
721dc307942Stalley #ifdef DEBUG
722dc307942Stalley } else {
723dc307942Stalley (void) fprintf(stderr, "disk "
724dc307942Stalley "has no available slices: "
725dc307942Stalley "%s\n", dp->name);
726dc307942Stalley #endif
727fa9e4066Sahrens }
728dc307942Stalley
729dc307942Stalley }
730fa9e4066Sahrens }
731fa9e4066Sahrens }
732fa9e4066Sahrens dm_free_descriptors(disks);
733fa9e4066Sahrens }
734fa9e4066Sahrens return (error);
735fa9e4066Sahrens }
736fa9e4066Sahrens
737fa9e4066Sahrens void
dmgt_free_disk(dmgt_disk_t * disk)738fa9e4066Sahrens dmgt_free_disk(dmgt_disk_t *disk)
739fa9e4066Sahrens {
740fa9e4066Sahrens if (disk != NULL) {
741fa9e4066Sahrens free(disk->name);
742c8e9ed14Stalley zjni_free_array((void **)disk->aliases, free);
743c8e9ed14Stalley zjni_free_array((void **)disk->slices,
744c8e9ed14Stalley (zjni_free_f)dmgt_free_slice);
745fa9e4066Sahrens free(disk);
746fa9e4066Sahrens }
747fa9e4066Sahrens }
748fa9e4066Sahrens
749fa9e4066Sahrens void
dmgt_free_slice(dmgt_slice_t * slice)750fa9e4066Sahrens dmgt_free_slice(dmgt_slice_t *slice)
751fa9e4066Sahrens {
752fa9e4066Sahrens if (slice != NULL) {
753fa9e4066Sahrens free(slice->name);
754fa9e4066Sahrens free(slice->used_name);
755fa9e4066Sahrens free(slice->used_by);
756fa9e4066Sahrens free(slice);
757fa9e4066Sahrens }
758fa9e4066Sahrens }
759fa9e4066Sahrens
760fa9e4066Sahrens /*
761fa9e4066Sahrens * For clients that need to capture error output.
762fa9e4066Sahrens */
763fa9e4066Sahrens void
dmgt_set_error_handler(void (* func)(const char *,va_list))764fa9e4066Sahrens dmgt_set_error_handler(void (*func)(const char *, va_list))
765fa9e4066Sahrens {
766fa9e4066Sahrens error_func = func;
767fa9e4066Sahrens }
768