xref: /onnv-gate/usr/src/lib/libzfs_jni/common/libzfs_jni_diskmgt.c (revision 1643:21525dad072d)
1789Sahrens /*
2789Sahrens  * CDDL HEADER START
3789Sahrens  *
4789Sahrens  * The contents of this file are subject to the terms of the
5*1643Stalley  * Common Development and Distribution License (the "License").
6*1643Stalley  * You may not use this file except in compliance with the License.
7789Sahrens  *
8789Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9789Sahrens  * or http://www.opensolaris.org/os/licensing.
10789Sahrens  * See the License for the specific language governing permissions
11789Sahrens  * and limitations under the License.
12789Sahrens  *
13789Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14789Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15789Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16789Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17789Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18789Sahrens  *
19789Sahrens  * CDDL HEADER END
20789Sahrens  */
21*1643Stalley 
22789Sahrens /*
23*1643Stalley  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24789Sahrens  * Use is subject to license terms.
25789Sahrens  */
26789Sahrens 
27789Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28789Sahrens 
29789Sahrens #include "libzfs_jni_diskmgt.h"
30789Sahrens #include "libzfs_jni_util.h"
31789Sahrens #include <strings.h>
32789Sahrens #include <libzfs.h>
33789Sahrens #include <sys/mnttab.h>
34789Sahrens 
35789Sahrens /*
36789Sahrens  * Function prototypes
37789Sahrens  */
38789Sahrens 
39789Sahrens static char *get_device_name(dm_descriptor_t device, int *error);
40789Sahrens static dmgt_disk_t *get_disk(dm_descriptor_t disk, int *error);
41789Sahrens static char **get_disk_aliases(dm_descriptor_t disk, char *name, int *error);
42789Sahrens static int get_disk_online(dm_descriptor_t disk, int *error);
43789Sahrens static void remove_slice_from_list(dmgt_slice_t **slices, int index);
44789Sahrens static dmgt_slice_t **get_disk_slices(dm_descriptor_t media,
45789Sahrens     const char *name, uint32_t blocksize, int *error);
46789Sahrens static dmgt_slice_t **get_disk_usable_slices(dm_descriptor_t media,
47789Sahrens     const char *name, uint32_t blocksize, int *in_use, int *error);
48789Sahrens static void get_disk_size(dm_descriptor_t media, char *name,
49789Sahrens     uint64_t *size, uint32_t *blocksize, int *error);
50789Sahrens static void get_slice_use(dm_descriptor_t slice, char *name,
51789Sahrens     char **used_name, char **used_by, int *error);
52789Sahrens static dmgt_slice_t *get_slice(
53789Sahrens     dm_descriptor_t slice, uint32_t blocksize, int *error);
54789Sahrens static void handle_error(const char *format, ...);
55*1643Stalley static int slice_in_use(dmgt_slice_t *slice, int *error);
56789Sahrens static int slice_too_small(dmgt_slice_t *slice);
57789Sahrens 
58789Sahrens /*
59789Sahrens  * Static data
60789Sahrens  */
61789Sahrens 
62789Sahrens static void (*error_func)(const char *, va_list);
63789Sahrens 
64789Sahrens /*
65789Sahrens  * Static functions
66789Sahrens  */
67789Sahrens 
68789Sahrens static char *
get_device_name(dm_descriptor_t device,int * error)69789Sahrens get_device_name(dm_descriptor_t device, int *error)
70789Sahrens {
71789Sahrens 	char *dup;
72789Sahrens 	char *name;
73789Sahrens 
74789Sahrens 	*error = 0;
75789Sahrens 	name = dm_get_name(device, error);
76789Sahrens 	if (*error) {
77789Sahrens 		handle_error("could not determine name of device");
78789Sahrens 	} else {
79789Sahrens 		dup = strdup(name);
80789Sahrens 		if (dup == NULL) {
81789Sahrens 			handle_error("out of memory");
82789Sahrens 			*error = -1;
83789Sahrens 		}
84789Sahrens 
85789Sahrens 		dm_free_name(name);
86789Sahrens 	}
87789Sahrens 
88789Sahrens 	return (dup);
89789Sahrens }
90789Sahrens 
91789Sahrens /*
92789Sahrens  * Gets a dmgt_disk_t for the given disk dm_descriptor_t.
93789Sahrens  *
94789Sahrens  * Results:
95789Sahrens  *
96789Sahrens  *  1. Success: error is set to 0 and a dmgt_disk_t is returned
97789Sahrens  *
98789Sahrens  *  2. Failure: error is set to -1 and NULL is returned
99789Sahrens  */
100789Sahrens static dmgt_disk_t *
get_disk(dm_descriptor_t disk,int * error)101789Sahrens get_disk(dm_descriptor_t disk, int *error)
102789Sahrens {
103789Sahrens 	dmgt_disk_t *dp;
104789Sahrens 	*error = 0;
105789Sahrens 
106789Sahrens 	dp = (dmgt_disk_t *)calloc(1, sizeof (dmgt_disk_t));
107789Sahrens 	if (dp == NULL) {
108789Sahrens 		handle_error("out of memory");
109789Sahrens 		*error = -1;
110789Sahrens 	} else {
111789Sahrens 
112789Sahrens 		/* Get name */
113789Sahrens 		dp->name = get_device_name(disk, error);
114789Sahrens 		if (!*error) {
115789Sahrens 
116789Sahrens 			/* Get aliases */
117789Sahrens 			dp->aliases = get_disk_aliases(disk, dp->name, error);
118789Sahrens 			if (!*error) {
119789Sahrens 
120789Sahrens 				/* Get media */
121789Sahrens 				dm_descriptor_t *media =
122789Sahrens 				    dm_get_associated_descriptors(disk,
123789Sahrens 					DM_MEDIA, error);
124789Sahrens 				if (*error != 0 || media == NULL ||
125789Sahrens 				    *media == NULL) {
126789Sahrens 					handle_error(
127789Sahrens 					    "could not get media from disk %s",
128789Sahrens 					    dp->name);
129789Sahrens 					*error = -1;
130789Sahrens 				} else {
131789Sahrens 					/* Get size */
132789Sahrens 					get_disk_size(media[0], dp->name,
133789Sahrens 					    &(dp->size), &(dp->blocksize),
134789Sahrens 					    error);
135789Sahrens 					if (!*error) {
136789Sahrens 						/* Get free slices */
137789Sahrens 						dp->slices =
138789Sahrens 						    get_disk_usable_slices(
139789Sahrens 							media[0], dp->name,
140789Sahrens 							dp->blocksize,
141789Sahrens 							&(dp->in_use), error);
142789Sahrens 					}
143789Sahrens 					dm_free_descriptors(media);
144789Sahrens 				}
145789Sahrens 			}
146789Sahrens 		}
147789Sahrens 	}
148789Sahrens 
149789Sahrens 	if (*error) {
1501066Stalley 		/* Normalize error */
1511066Stalley 		*error = -1;
152789Sahrens 
153789Sahrens 		if (dp != NULL) {
154789Sahrens 			dmgt_free_disk(dp);
155789Sahrens 			dp = NULL;
156789Sahrens 		}
157789Sahrens 	}
158789Sahrens 
159789Sahrens 	return (dp);
160789Sahrens }
161789Sahrens 
162789Sahrens static char **
get_disk_aliases(dm_descriptor_t disk,char * name,int * error)163789Sahrens get_disk_aliases(dm_descriptor_t disk, char *name, int *error)
164789Sahrens {
165789Sahrens 	char **names = NULL;
166789Sahrens 	dm_descriptor_t *aliases;
167789Sahrens 
168789Sahrens 	*error = 0;
169789Sahrens 	aliases = dm_get_associated_descriptors(disk, DM_ALIAS, error);
170789Sahrens 	if (*error || aliases == NULL) {
171789Sahrens 		*error = -1;
172789Sahrens 		handle_error("could not get aliases for disk %s", name);
173789Sahrens 	} else {
174789Sahrens 
175789Sahrens 		int j;
176789Sahrens 
177789Sahrens 		/* Count aliases */
178789Sahrens 		for (j = 0; aliases[j] != NULL; j++);
179789Sahrens 
180789Sahrens 		names = (char **)calloc(j + 1, sizeof (char *));
181789Sahrens 		if (names == NULL) {
182789Sahrens 			*error = -1;
183789Sahrens 			handle_error("out of memory");
184789Sahrens 		} else {
185789Sahrens 
186789Sahrens 			/* For each alias... */
187789Sahrens 			for (j = 0; *error == 0 && aliases[j] != NULL; j++) {
188789Sahrens 
189789Sahrens 				dm_descriptor_t alias = aliases[j];
190789Sahrens 				char *aname = dm_get_name(alias, error);
191789Sahrens 				if (*error) {
192789Sahrens 					handle_error("could not get alias %d "
193789Sahrens 					    "for disk %s", (j + 1), name);
194789Sahrens 				} else {
195789Sahrens 					names[j] = strdup(aname);
196789Sahrens 					if (names[j] == NULL) {
197789Sahrens 						*error = -1;
198789Sahrens 						handle_error("out of memory");
199789Sahrens 					}
200789Sahrens 
201789Sahrens 					dm_free_name(aname);
202789Sahrens 				}
203789Sahrens 			}
204789Sahrens 		}
205789Sahrens 
206789Sahrens 		dm_free_descriptors(aliases);
207789Sahrens 	}
208789Sahrens 
209789Sahrens 	if (*error && names != NULL) {
210789Sahrens 		/* Free previously-allocated names */
211894Stalley 		zjni_free_array((void **)names, free);
212789Sahrens 	}
213789Sahrens 
214789Sahrens 	return (names);
215789Sahrens }
216789Sahrens 
217789Sahrens static int
get_disk_online(dm_descriptor_t disk,int * error)218789Sahrens get_disk_online(dm_descriptor_t disk, int *error)
219789Sahrens {
220789Sahrens 	uint32_t status = 0;
221789Sahrens 
222789Sahrens 	nvlist_t *attrs;
223789Sahrens 	*error = 0;
224789Sahrens 	attrs = dm_get_attributes(disk, error);
225789Sahrens 	if (*error) {
226789Sahrens 		handle_error("could not get disk attributes for disk");
227789Sahrens 	} else {
228789Sahrens 
229789Sahrens 		/* Try to get the status */
230789Sahrens 		nvpair_t *match = zjni_nvlist_walk_nvpair(
231789Sahrens 		    attrs, DM_STATUS, DATA_TYPE_UINT32, NULL);
232789Sahrens 
233789Sahrens 		if (match == NULL || nvpair_value_uint32(match, &status)) {
234789Sahrens 
235789Sahrens 			handle_error("could not get status of disk");
236789Sahrens 			*error = 1;
237789Sahrens 		}
238789Sahrens 
239789Sahrens 		nvlist_free(attrs);
240789Sahrens 	}
241789Sahrens 
242789Sahrens 	return (status != 0);
243789Sahrens }
244789Sahrens 
245789Sahrens /*
246789Sahrens  * Gets the slices for the given disk.
247789Sahrens  *
248789Sahrens  * Results:
249789Sahrens  *
250789Sahrens  *  1. Success: error is set to 0 and slices are returned
251789Sahrens  *
252789Sahrens  *  2. Failure: error is set to -1 and NULL is returned
253789Sahrens  */
254789Sahrens static dmgt_slice_t **
get_disk_slices(dm_descriptor_t media,const char * name,uint32_t blocksize,int * error)255789Sahrens get_disk_slices(dm_descriptor_t media, const char *name, uint32_t blocksize,
256789Sahrens     int *error)
257789Sahrens {
258789Sahrens 	dm_descriptor_t *slices;
259789Sahrens 	dmgt_slice_t **sap = NULL;
260789Sahrens 
261789Sahrens 	*error = 0;
262789Sahrens 	slices = dm_get_associated_descriptors(media, DM_SLICE, error);
263789Sahrens 	if (*error != 0) {
264789Sahrens 		handle_error("could not get slices of disk %s", name);
265789Sahrens 	} else {
266789Sahrens 		int j;
267789Sahrens 		int nslices = 0;
268789Sahrens 
269789Sahrens 		/* For each slice... */
270789Sahrens 		for (j = 0; *error == 0 &&
271789Sahrens 		    slices != NULL && slices[j] != NULL; j++) {
272789Sahrens 
273789Sahrens 			/* Get slice */
274789Sahrens 			dmgt_slice_t *slice =
275789Sahrens 			    get_slice(slices[j], blocksize, error);
276789Sahrens 			if (!*error) {
277789Sahrens 
278*1643Stalley 				dmgt_slice_t **mem =
279*1643Stalley 				    (dmgt_slice_t **)realloc(sap,
280789Sahrens 				    (nslices + 2) * sizeof (dmgt_slice_t *));
281*1643Stalley 
282*1643Stalley 				if (mem == NULL) {
283789Sahrens 					handle_error("out of memory");
284789Sahrens 					*error = -1;
285789Sahrens 				} else {
286789Sahrens 
287*1643Stalley 					sap = mem;
288*1643Stalley 
289789Sahrens 					/* NULL-terminated array */
290789Sahrens 					sap[nslices] = slice;
291789Sahrens 					sap[nslices + 1] = NULL;
292789Sahrens 
293789Sahrens 					nslices++;
294789Sahrens 				}
295789Sahrens 			}
296789Sahrens 		}
297789Sahrens 
298789Sahrens 		dm_free_descriptors(slices);
299789Sahrens 	}
300789Sahrens 
301789Sahrens 	if (*error) {
302789Sahrens 		/* Normalize error */
303789Sahrens 		*error = -1;
304789Sahrens 
305*1643Stalley 		if (sap != NULL) {
306*1643Stalley 			zjni_free_array((void **)sap,
307*1643Stalley 			    (zjni_free_f)dmgt_free_slice);
308*1643Stalley 			sap = NULL;
309*1643Stalley 		}
310789Sahrens 	}
311789Sahrens 
312789Sahrens 	return (sap);
313789Sahrens }
314789Sahrens 
315789Sahrens static void
remove_slice_from_list(dmgt_slice_t ** slices,int index)316789Sahrens remove_slice_from_list(dmgt_slice_t **slices, int index)
317789Sahrens {
318789Sahrens 	int i;
319789Sahrens 	for (i = index; slices[i] != NULL; i++) {
320789Sahrens 		slices[i] = slices[i + 1];
321789Sahrens 	}
322789Sahrens }
323789Sahrens 
324789Sahrens static int
slices_overlap(dmgt_slice_t * slice1,dmgt_slice_t * slice2)325789Sahrens slices_overlap(dmgt_slice_t *slice1, dmgt_slice_t *slice2)
326789Sahrens {
327789Sahrens 
328789Sahrens 	uint64_t start1 = slice1->start;
329789Sahrens 	uint64_t end1 = start1 + slice1->size - 1;
330789Sahrens 	uint64_t start2 = slice2->start;
331894Stalley 	uint64_t end2 = start2 + slice2->size - 1;
332789Sahrens 
333789Sahrens 	int overlap = (start2 <= end1 && start1 <= end2);
334789Sahrens 
335789Sahrens #ifdef DEBUG
336789Sahrens 	if (overlap) {
337789Sahrens 		(void) fprintf(stderr, "can't use %s: overlaps with %s\n",
338789Sahrens 		    slice2->name, slice1->name);
339789Sahrens 		(void) fprintf(stderr, "  1: start: %llu - %llu\n",
340789Sahrens 		    (unsigned long long)start1, (unsigned long long)end1);
341789Sahrens 		(void) fprintf(stderr, "  2: start: %llu - %llu\n",
342789Sahrens 		    (unsigned long long)start2, (unsigned long long)end2);
343789Sahrens 	}
344789Sahrens #endif
345789Sahrens 
346789Sahrens 	return (overlap);
347789Sahrens }
348789Sahrens 
349789Sahrens /*
350789Sahrens  * Gets the slices for the given disk.
351789Sahrens  *
352789Sahrens  * Results:
353789Sahrens  *
354789Sahrens  *  1. Success: error is set to 0 and slices are returned
355789Sahrens  *
356789Sahrens  *  2. Failure: error is set to -1 and NULL is returned
357789Sahrens  */
358789Sahrens static dmgt_slice_t **
get_disk_usable_slices(dm_descriptor_t media,const char * name,uint32_t blocksize,int * in_use,int * error)359789Sahrens get_disk_usable_slices(dm_descriptor_t media, const char *name,
360789Sahrens     uint32_t blocksize, int *in_use, int *error)
361789Sahrens {
362789Sahrens 	dmgt_slice_t **slices = get_disk_slices(media, name, blocksize, error);
363*1643Stalley 	if (*error) {
364*1643Stalley 		slices = NULL;
365*1643Stalley 	}
366789Sahrens 
367789Sahrens 	*in_use = 0;
368789Sahrens 
369*1643Stalley 	if (slices != NULL) {
370789Sahrens 		int i, nslices;
371789Sahrens 
372789Sahrens 		for (nslices = 0; slices[nslices] != NULL; nslices++);
373789Sahrens 
374789Sahrens 		/* Prune slices based on use */
375789Sahrens 		for (i = nslices - 1; i >= 0; i--) {
376789Sahrens 			dmgt_slice_t *slice = slices[i];
377*1643Stalley 			int s_in_use;
378*1643Stalley 
379*1643Stalley 			/*
380*1643Stalley 			 * Slice at this index could be NULL if
381*1643Stalley 			 * removed in earlier iteration
382*1643Stalley 			 */
383789Sahrens 			if (slice == NULL) {
384789Sahrens 				continue;
385789Sahrens 			}
386789Sahrens 
387*1643Stalley 			s_in_use = slice_in_use(slice, error);
388*1643Stalley 			if (*error) {
389*1643Stalley 			    break;
390*1643Stalley 			}
391*1643Stalley 
392*1643Stalley 			if (s_in_use) {
393789Sahrens 				int j;
394789Sahrens 				remove_slice_from_list(slices, i);
395789Sahrens 
396*1643Stalley 				/* Disk is in use */
397789Sahrens 				*in_use = 1;
398789Sahrens 
399789Sahrens 				/*
400789Sahrens 				 * Remove any slice that overlaps with this
401789Sahrens 				 * in-use slice
402789Sahrens 				 */
403789Sahrens 				for (j = nslices - 1; j >= 0; j--) {
404*1643Stalley 					dmgt_slice_t *slice2 = slices[j];
405*1643Stalley 
406*1643Stalley 					if (slice2 != NULL &&
407*1643Stalley 					    slices_overlap(slice, slice2)) {
408789Sahrens 						remove_slice_from_list(slices,
409789Sahrens 						    j);
410*1643Stalley 						dmgt_free_slice(slice2);
411789Sahrens 					}
412789Sahrens 				}
413*1643Stalley 
414*1643Stalley 				dmgt_free_slice(slice);
415*1643Stalley 			} else if (slice_too_small(slice)) {
416*1643Stalley 				remove_slice_from_list(slices, i);
417*1643Stalley 				dmgt_free_slice(slice);
4181066Stalley 			}
419789Sahrens 		}
420789Sahrens 	}
421789Sahrens 
422*1643Stalley 	if (*error) {
423*1643Stalley 		/* Normalize error */
424*1643Stalley 		*error = -1;
425*1643Stalley 
426*1643Stalley 		if (slices != NULL) {
427*1643Stalley 			zjni_free_array((void **)slices,
428*1643Stalley 			    (zjni_free_f)dmgt_free_slice);
429*1643Stalley 			slices = NULL;
430*1643Stalley 		}
431*1643Stalley 	}
432*1643Stalley 
433789Sahrens 	return (slices);
434789Sahrens }
435789Sahrens 
436789Sahrens static void
get_disk_size(dm_descriptor_t media,char * name,uint64_t * size,uint32_t * blocksize,int * error)437789Sahrens get_disk_size(dm_descriptor_t media, char *name, uint64_t *size,
438789Sahrens     uint32_t *blocksize, int *error)
439789Sahrens {
440789Sahrens 	nvlist_t *attrs;
441789Sahrens 
442789Sahrens 	*size = 0;
443789Sahrens 	*error = 0;
444789Sahrens 
445789Sahrens 	attrs = dm_get_attributes(media, error);
446789Sahrens 
447789Sahrens 	if (*error) {
448789Sahrens 		handle_error("could not get media attributes from disk: %s",
449789Sahrens 		    name);
450789Sahrens 	} else {
451789Sahrens 		/* Try to get the number of accessible blocks */
452789Sahrens 		nvpair_t *match = zjni_nvlist_walk_nvpair(
453789Sahrens 		    attrs, DM_NACCESSIBLE, DATA_TYPE_UINT64, NULL);
454789Sahrens 		if (match == NULL || nvpair_value_uint64(match, size)) {
455789Sahrens 
456789Sahrens 			/* Disk is probably not labeled, get raw size instead */
457789Sahrens 			match = zjni_nvlist_walk_nvpair(
458789Sahrens 			    attrs, DM_SIZE, DATA_TYPE_UINT64, NULL);
459789Sahrens 			if (match == NULL || nvpair_value_uint64(match, size)) {
460789Sahrens 				handle_error("could not get size of disk: %s",
461789Sahrens 				    name);
462789Sahrens 				*error = 1;
463789Sahrens 			}
464789Sahrens 		}
465789Sahrens 
466789Sahrens 		if (*error == 0) {
467789Sahrens 			match = zjni_nvlist_walk_nvpair(
468789Sahrens 			    attrs, DM_BLOCKSIZE, DATA_TYPE_UINT32, NULL);
469789Sahrens 			if (match == NULL ||
470789Sahrens 			    nvpair_value_uint32(match, blocksize)) {
471789Sahrens 				handle_error("could not get "
472789Sahrens 				    "block size of disk: %s", name);
473789Sahrens 				*error = 1;
474789Sahrens 			} else {
475789Sahrens 				*size *= *blocksize;
476789Sahrens 			}
477789Sahrens 		}
478789Sahrens 
479789Sahrens 		nvlist_free(attrs);
480789Sahrens 	}
481789Sahrens }
482789Sahrens 
483789Sahrens static void
get_slice_use(dm_descriptor_t slice,char * name,char ** used_name,char ** used_by,int * error)484789Sahrens get_slice_use(dm_descriptor_t slice, char *name, char **used_name,
485789Sahrens     char **used_by, int *error)
486789Sahrens {
487789Sahrens 	/* Get slice use statistics */
488789Sahrens 	nvlist_t *stats = dm_get_stats(slice, DM_SLICE_STAT_USE, error);
489789Sahrens 	if (*error != 0) {
490789Sahrens 		handle_error("could not get stats of slice %s", name);
491789Sahrens 	} else {
492789Sahrens 
493789Sahrens 		*used_name = NULL;
494789Sahrens 		*used_by = NULL;
495789Sahrens 
496789Sahrens 		if (stats != NULL) {
497789Sahrens 			char *tmp;
498789Sahrens 			nvpair_t *match;
499789Sahrens 
500789Sahrens 			/* Get the type of usage for this slice */
501789Sahrens 			match = zjni_nvlist_walk_nvpair(
502789Sahrens 			    stats, DM_USED_BY, DATA_TYPE_STRING, NULL);
503789Sahrens 
504789Sahrens 			if (match != NULL &&
505789Sahrens 			    nvpair_value_string(match, &tmp) == 0) {
506789Sahrens 
507789Sahrens 				*used_name = strdup(tmp);
508789Sahrens 				if (*used_name == NULL) {
509789Sahrens 					*error = -1;
510789Sahrens 					handle_error("out of memory");
511789Sahrens 				} else {
512789Sahrens 
513789Sahrens 					/* Get the object using this slice */
514789Sahrens 					match =
515789Sahrens 					    zjni_nvlist_walk_nvpair(stats,
516789Sahrens 					    DM_USED_NAME, DATA_TYPE_STRING,
517789Sahrens 					    NULL);
518789Sahrens 
519789Sahrens 					if (match != NULL &&
520789Sahrens 					    nvpair_value_string(match, &tmp) ==
521789Sahrens 					    0) {
522789Sahrens 						*used_by = strdup(tmp);
523789Sahrens 						if (*used_by == NULL) {
524789Sahrens 							*error = -1;
525789Sahrens 							handle_error(
526789Sahrens 							    "out of memory");
527789Sahrens 						}
528789Sahrens 					}
529789Sahrens 				}
530789Sahrens 			}
531789Sahrens 			nvlist_free(stats);
532789Sahrens 		}
533789Sahrens 	}
534789Sahrens }
535789Sahrens 
536789Sahrens static dmgt_slice_t *
get_slice(dm_descriptor_t slice,uint32_t blocksize,int * error)537789Sahrens get_slice(dm_descriptor_t slice, uint32_t blocksize, int *error)
538789Sahrens {
539789Sahrens 	dmgt_slice_t *sp;
540789Sahrens 	*error = 0;
541789Sahrens 	sp = (dmgt_slice_t *)calloc(1, sizeof (dmgt_slice_t));
542789Sahrens 	if (sp == NULL) {
543789Sahrens 		*error = -1;
544789Sahrens 		handle_error("out of memory");
545789Sahrens 	} else {
546789Sahrens 
547789Sahrens 		/* Get name */
548789Sahrens 		sp->name = get_device_name(slice, error);
549789Sahrens 		if (!*error) {
550789Sahrens 
551789Sahrens 			nvlist_t *attrs = dm_get_attributes(slice, error);
552789Sahrens 			if (*error) {
553789Sahrens 				handle_error("could not get "
554789Sahrens 				    "attributes from slice: %s", sp->name);
555789Sahrens 			} else {
556789Sahrens 				/* Get the size in blocks */
557789Sahrens 				nvpair_t *match = zjni_nvlist_walk_nvpair(
558789Sahrens 				    attrs, DM_SIZE, DATA_TYPE_UINT64, NULL);
559789Sahrens 				uint64_t size_blocks;
560789Sahrens 
561789Sahrens 				sp->size = 0;
562789Sahrens 
563789Sahrens 				if (match == NULL ||
564789Sahrens 				    nvpair_value_uint64(match, &size_blocks)) {
565789Sahrens 					handle_error("could not get "
566789Sahrens 					    "size of slice: %s", sp->name);
567789Sahrens 					*error = 1;
568789Sahrens 				} else {
569789Sahrens 					uint64_t start_blocks;
570789Sahrens 
571789Sahrens 					/* Convert to bytes */
572789Sahrens 					sp->size = blocksize * size_blocks;
573789Sahrens 
574789Sahrens 					/* Get the starting block */
575789Sahrens 					match = zjni_nvlist_walk_nvpair(
576789Sahrens 					    attrs, DM_START, DATA_TYPE_UINT64,
577789Sahrens 					    NULL);
578789Sahrens 
579789Sahrens 					if (match == NULL ||
580789Sahrens 					    nvpair_value_uint64(match,
581789Sahrens 					    &start_blocks)) {
582789Sahrens 						handle_error(
583789Sahrens 						    "could not get "
584789Sahrens 						    "start block of slice: %s",
585789Sahrens 						    sp->name);
586789Sahrens 						*error = 1;
587789Sahrens 					} else {
588789Sahrens 						/* Convert to bytes */
589789Sahrens 						sp->start =
590789Sahrens 						    blocksize * start_blocks;
591789Sahrens 
592789Sahrens 						/* Set slice use */
593789Sahrens 						get_slice_use(slice, sp->name,
594789Sahrens 						    &(sp->used_name),
595789Sahrens 						    &(sp->used_by), error);
596789Sahrens 					}
597789Sahrens 				}
598789Sahrens 			}
599789Sahrens 		}
600789Sahrens 	}
601789Sahrens 
602789Sahrens 	if (*error && sp != NULL) {
603789Sahrens 		dmgt_free_slice(sp);
604789Sahrens 	}
605789Sahrens 
606789Sahrens 	return (sp);
607789Sahrens }
608789Sahrens 
609789Sahrens static void
handle_error(const char * format,...)610789Sahrens handle_error(const char *format, ...)
611789Sahrens {
612789Sahrens 	va_list ap;
613789Sahrens 	va_start(ap, format);
614789Sahrens 
615789Sahrens 	if (error_func != NULL) {
616789Sahrens 		error_func(format, ap);
617789Sahrens 	}
618789Sahrens 
619789Sahrens 	va_end(ap);
620789Sahrens }
621789Sahrens 
622789Sahrens /* Should go away once 6285992 is fixed */
623789Sahrens static int
slice_too_small(dmgt_slice_t * slice)624789Sahrens slice_too_small(dmgt_slice_t *slice)
625789Sahrens {
626789Sahrens 	/* Check size */
627789Sahrens 	if (slice->size < SPA_MINDEVSIZE) {
628789Sahrens #ifdef DEBUG
629789Sahrens 		(void) fprintf(stderr, "can't use %s: slice too small: %llu\n",
630789Sahrens 			slice->name, (unsigned long long)slice->size);
631789Sahrens #endif
632789Sahrens 		return (1);
633789Sahrens 	}
634789Sahrens 
635789Sahrens 	return (0);
636789Sahrens }
637789Sahrens 
638789Sahrens static int
slice_in_use(dmgt_slice_t * slice,int * error)639*1643Stalley slice_in_use(dmgt_slice_t *slice, int *error)
640789Sahrens {
641*1643Stalley 	char *msg = NULL;
642*1643Stalley 	int in_use;
643789Sahrens 
644*1643Stalley 	/* Determine whether this slice could be passed to "zpool -f" */
645*1643Stalley 	in_use = dm_inuse(slice->name, &msg, DM_WHO_ZPOOL_FORCE, error);
646*1643Stalley 	if (*error) {
647*1643Stalley 		handle_error("%s: could not determine usage", slice->name);
648789Sahrens 	}
649789Sahrens 
650789Sahrens #ifdef DEBUG
651789Sahrens 	if (in_use) {
652789Sahrens 		(void) fprintf(stderr,
653*1643Stalley 		    "can't use %s: used name: %s: used by: %s\n  message: %s\n",
654*1643Stalley 		    slice->name, slice->used_name, slice->used_by, msg);
655789Sahrens 	}
656789Sahrens #endif
657789Sahrens 
658*1643Stalley 	if (msg != NULL) {
659*1643Stalley 		free(msg);
660*1643Stalley 	}
661*1643Stalley 
662789Sahrens 	return (in_use);
663789Sahrens }
664789Sahrens 
665789Sahrens /*
666789Sahrens  * Extern functions
667789Sahrens  */
668789Sahrens 
669789Sahrens /*
670789Sahrens  * Iterates through each available disk on the system.  For each free
671789Sahrens  * dmgt_disk_t *, runs the given function with the dmgt_disk_t * as
672789Sahrens  * the first arg and the given void * as the second arg.
673789Sahrens  */
674789Sahrens int
dmgt_avail_disk_iter(dmgt_disk_iter_f func,void * data)675789Sahrens dmgt_avail_disk_iter(dmgt_disk_iter_f func, void *data)
676789Sahrens {
677789Sahrens 	int error = 0;
678789Sahrens 	int filter[] = { DM_DT_FIXED, -1 };
679789Sahrens 
680789Sahrens 	/* Search for fixed disks */
681789Sahrens 	dm_descriptor_t *disks = dm_get_descriptors(DM_DRIVE, filter, &error);
682789Sahrens 
683789Sahrens 	if (error) {
684789Sahrens 		handle_error("unable to communicate with libdiskmgt");
685789Sahrens 	} else {
686789Sahrens 		int i;
687789Sahrens 
688789Sahrens 		/* For each disk... */
689*1643Stalley 		for (i = 0; disks != NULL && disks[i] != NULL; i++) {
690*1643Stalley 			dm_descriptor_t disk = (dm_descriptor_t)disks[i];
691*1643Stalley 			int online;
692*1643Stalley 
693*1643Stalley 			/* Reset error flag for each disk */
694*1643Stalley 			error = 0;
695*1643Stalley 
696789Sahrens 			/* Is this disk online? */
697*1643Stalley 			online = get_disk_online(disk, &error);
698789Sahrens 			if (!error && online) {
699*1643Stalley 
700*1643Stalley 				/* Get a dmgt_disk_t for this dm_descriptor_t */
701789Sahrens 				dmgt_disk_t *dp = get_disk(disk, &error);
7021066Stalley 				if (!error) {
703*1643Stalley 
7041066Stalley 					/*
7051066Stalley 					 * If this disk or any of its
7061066Stalley 					 * slices is usable...
7071066Stalley 					 */
7081066Stalley 					if (!dp->in_use ||
7091066Stalley 					    zjni_count_elements(
7101066Stalley 					    (void **)dp->slices) != 0) {
7111066Stalley 
712789Sahrens 						/* Run the given function */
713789Sahrens 						if (func(dp, data)) {
714789Sahrens 							error = -1;
715789Sahrens 						}
716789Sahrens 						dmgt_free_disk(dp);
7171066Stalley #ifdef DEBUG
7181066Stalley 					} else {
7191066Stalley 						(void) fprintf(stderr, "disk "
7201066Stalley 						    "has no available slices: "
7211066Stalley 						    "%s\n", dp->name);
7221066Stalley #endif
723789Sahrens 					}
7241066Stalley 
7251066Stalley 				}
726789Sahrens 			}
727789Sahrens 		}
728789Sahrens 		dm_free_descriptors(disks);
729789Sahrens 	}
730789Sahrens 	return (error);
731789Sahrens }
732789Sahrens 
733789Sahrens void
dmgt_free_disk(dmgt_disk_t * disk)734789Sahrens dmgt_free_disk(dmgt_disk_t *disk)
735789Sahrens {
736789Sahrens 	if (disk != NULL) {
737789Sahrens 		free(disk->name);
738894Stalley 		zjni_free_array((void **)disk->aliases, free);
739894Stalley 		zjni_free_array((void **)disk->slices,
740894Stalley 		    (zjni_free_f)dmgt_free_slice);
741789Sahrens 		free(disk);
742789Sahrens 	}
743789Sahrens }
744789Sahrens 
745789Sahrens void
dmgt_free_slice(dmgt_slice_t * slice)746789Sahrens dmgt_free_slice(dmgt_slice_t *slice)
747789Sahrens {
748789Sahrens 	if (slice != NULL) {
749789Sahrens 		free(slice->name);
750789Sahrens 		free(slice->used_name);
751789Sahrens 		free(slice->used_by);
752789Sahrens 		free(slice);
753789Sahrens 	}
754789Sahrens }
755789Sahrens 
756789Sahrens /*
757789Sahrens  * For clients that need to capture error output.
758789Sahrens  */
759789Sahrens void
dmgt_set_error_handler(void (* func)(const char *,va_list))760789Sahrens dmgt_set_error_handler(void (*func)(const char *, va_list))
761789Sahrens {
762789Sahrens 	error_func = func;
763789Sahrens }
764