--- a/usr/src/lib/libtd/Makefile Tue Nov 02 18:25:00 2010 +0100
+++ b/usr/src/lib/libtd/Makefile Thu Nov 04 10:08:30 2010 +0000
@@ -37,12 +37,14 @@
td_dd.o \
td_dd_svm.o \
td_iscsi.o \
+ td_zpool.o \
test_td.o
PRIVHDRS = \
td_lib.h \
td_version.h \
- td_dd.h
+ td_dd.h \
+ td_zpool.h
EXPHDRS = \
td_api.h
HDRS = $(EXPHDRS) $(PRIVHDRS)
@@ -59,7 +61,7 @@
LDFLAGS +=
SOFLAGS += -L$(ROOTADMINLIB) -R$(ROOTADMINLIB:$(ROOT)%=%) \
-L$(ROOTUSRLIB) -R$(ROOTUSRLIB:$(ROOT)%=%) \
- -ldiskmgt -lfstyp -lnvpair -llogsvc -linstzones -lima
+ -ldiskmgt -lfstyp -lnvpair -llogsvc -linstzones -lima -lzfs -lm
ROOT_TEST_PROGS = $(TEST_PROGS:%=$(ROOTOPTINSTALLTESTBIN)/%)
CLEANFILES = $(TEST_PROGS)
@@ -74,7 +76,7 @@
$(LINK.c) -o tdmgtst tdmgtst.o \
-R$(ROOTADMINLIB:$(ROOT)%=%) \
-L$(ROOTADMINLIB) -Lpics/$(ARCH) \
- -ltd -lfstyp -llogsvc -lnvpair
+ -ltd -lfstyp -llogsvc -lnvpair -lzfs -lm
# statically built Target Discovery Manager test program
tdmgtst_static: static tdmgtst.o
@@ -84,14 +86,14 @@
-ltd -llogsvc \
-Bdynamic \
-ldiskmgt -lfstyp -lnvpair -ldevinfo -ladm \
- -linstzones -lzonecfg -lcontract -lgen -lima
+ -linstzones -lzonecfg -lcontract -lgen -lima -lzfs -lm
# Target Discovery test program
test_td: dynamic test_td.o
$(LINK.c) -o test_td test_td.o \
-R$(ROOTADMINLIB:$(ROOT)%=%) \
-L$(ROOTADMINLIB) -Lpics/$(ARCH) \
- -ltd -lfstyp -llogsvc -lnvpair
+ -ltd -lfstyp -llogsvc -lnvpair -lzfs -lm
# statically built Target Discovery test program
test_td_static: static test_td.o
@@ -101,7 +103,7 @@
-ltd -llogsvc \
-Bdynamic \
-ldiskmgt -lfstyp -lnvpair -ldevinfo -ladm \
- -linstzones -lzonecfg -lcontract -lgen -lima
+ -linstzones -lzonecfg -lcontract -lgen -lima -lzfs -lm
static: $(LIBS)
--- a/usr/src/lib/libtd/td_api.h Tue Nov 02 18:25:00 2010 +0100
+++ b/usr/src/lib/libtd/td_api.h Thu Nov 04 10:08:30 2010 +0000
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _TD_API_H
@@ -38,7 +37,6 @@
#endif
/* type definitions */
-
typedef uint64_t td_handle_t;
typedef enum {
@@ -64,7 +62,8 @@
TD_OT_DISK = 0, /* writeable disk - install candidate */
TD_OT_PARTITION, /* disk partition */
TD_OT_SLICE, /* ufs file system slice */
- TD_OT_OS /* Solaris OS instance/BE */
+ TD_OT_OS, /* Solaris OS instance/BE */
+ TD_OT_ZPOOL /* ZFS Pool */
} td_object_type_t;
#define TD_IOCTL_TIMEOUT 10 /* seconds to timeout blocking ioctls */
@@ -238,6 +237,30 @@
#define INSTISCSI_MAX_LUN_LEN 32
#define INSTISCSI_MAX_INITIATOR_LEN INSTISCSI_MAX_ISCSI_NAME_LEN
+/* nv attribute names for zpools */
+#define TD_ZPOOL_ATTR_NAME "zpool_name"
+#define TD_ZPOOL_ATTR_HEALTH "zpool_health"
+#define TD_ZPOOL_ATTR_STATUS "zpool_status"
+#define TD_ZPOOL_ATTR_GUID "zpool_guid"
+#define TD_ZPOOL_ATTR_SIZE "zpool_size"
+#define TD_ZPOOL_ATTR_CAPACITY "zpool_capacity"
+#define TD_ZPOOL_ATTR_VERSION "zpool_version"
+#define TD_ZPOOL_ATTR_BOOTFS "zpool_bootfs"
+#define TD_ZPOOL_ATTR_IMPORT "zpool_import"
+#define TD_ZPOOL_ATTR_NUM_TARGETS "zpool_num_targets"
+#define TD_ZPOOL_ATTR_TARGETS "zpool_targets"
+#define TD_ZPOOL_ATTR_NUM_LOGS "zpool_num_logs"
+#define TD_ZPOOL_ATTR_LOGS "zpool_logs"
+#define TD_ZPOOL_ATTR_NUM_SPARES "zpool_num_spares"
+#define TD_ZPOOL_ATTR_SPARES "zpool_spares"
+#define TD_ZPOOL_ATTR_NUM_L2CACHE "zpool_num_l2cache"
+#define TD_ZPOOL_ATTR_L2CACHE "zpool_l2cache"
+#define TD_ZPOOL_ATTR_TARGET_NAME "zpool_target_name"
+#define TD_ZPOOL_ATTR_TARGET_HEALTH "zpool_target_health"
+#define TD_ZPOOL_ATTR_TARGET_READ_ERRORS "zpool_target_read_errors"
+#define TD_ZPOOL_ATTR_TARGET_WRITE_ERRORS "zpool_target_write_errors"
+#define TD_ZPOOL_ATTR_TARGET_CHECKSUM_ERRORS "zpool_target_checksum_errors"
+
/*
* bitfields indicate reasons for upgrade failure
*/
--- a/usr/src/lib/libtd/td_dd.c Tue Nov 02 18:25:00 2010 +0100
+++ b/usr/src/lib/libtd/td_dd.c Thu Nov 04 10:08:30 2010 +0000
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <assert.h>
@@ -624,7 +623,7 @@
/* if leading /a, strip it */
if (strncmp(fsp->fs_fsmnt, slasha, strlen(slasha)) == 0) {
- return (fsp->fs_fsmnt + 2);
+ return (fsp->fs_fsmnt + 2);
}
return (fsp->fs_fsmnt);
@@ -1320,6 +1319,33 @@
return (device_path);
}
+/*
+ * ddm_count_handles()
+ * Cycle through array of ddm_handles and return count
+ *
+ * Parameters:
+ * ddm_handle_t *dh : Array of handles to count
+ * Return:
+ * retcnt : Number of items in array, 0 for none.
+ * Scope:
+ * private
+ */
+static int
+ddm_count_handles(ddm_handle_t *dh)
+{
+ int retcnt = 0;
+ ddm_handle_t *tmpdh;
+
+ if (dh == NULL) {
+ return (retcnt);
+ }
+
+ for (retcnt = 0, tmpdh = dh; *tmpdh != NULL;
+ tmpdh++, retcnt++)
+ ;
+
+ return (retcnt);
+}
/* ----------------------- public functions --------------------------- */
@@ -1377,14 +1403,14 @@
* Disk discovery
*
* Parameters:
- * none
+ * ndisks Return number of disks discovered
* Return:
* ddm_handle_t * - list of drive handles
* Status:
* public
*/
ddm_handle_t *
-ddm_get_disks(void)
+ddm_get_disks(int *ndisks)
{
ddm_handle_t *df;
int errn;
@@ -1400,6 +1426,10 @@
assert(ddm_drive_desc == NULL);
+ /* Initialize number of disks discovered to 0 */
+ if (ndisks != NULL)
+ *ndisks = 0;
+
ddm_drive_desc = dm_get_descriptors(DM_DRIVE, NULL, &errn);
if (ddm_drive_desc == NULL) {
@@ -1418,6 +1448,9 @@
"Couldn't filter the disks\n");
}
+ if (ndisks != NULL)
+ *ndisks = ddm_count_handles(df);
+
return (df);
}
@@ -1728,19 +1761,24 @@
/*
* ddm_get_partitions()
* Discovers partitions for particular disk
- * Parameters: d handle of drive, which is subject of partition discovery
- * process. If set to DDM_DISCOVER_ALL, all partitions for
- * all drives are reported.
+ * Parameters:
+ * d handle of drive, which is subject of partition discovery
+ * process. If set to DDM_DISCOVER_ALL, all partitions for
+ * all drives are reported.
+ * nparts Number of partitions discovered.
*/
ddm_handle_t *
-ddm_get_partitions(ddm_handle_t d)
+ddm_get_partitions(ddm_handle_t d, int *nparts)
{
dm_descriptor_t *am;
dm_descriptor_t *ddm_part_desc;
int errn;
+ /* Initialize number discovered to 0 */
+ if (nparts != NULL)
+ *nparts = 0;
+
/* discover all partitions for all drives */
-
if (d == DDM_DISCOVER_ALL) {
ddm_part_desc = dm_get_descriptors(DM_PARTITION, NULL, &errn);
@@ -1752,6 +1790,10 @@
return (NULL);
}
+ if (nparts != NULL) {
+ *nparts =
+ ddm_count_handles((ddm_handle_t *)ddm_part_desc);
+ }
return ((ddm_handle_t *)ddm_part_desc);
}
@@ -1791,6 +1833,8 @@
}
dm_free_descriptors(am);
+ if (nparts != NULL)
+ *nparts = ddm_count_handles((ddm_handle_t *)ddm_part_desc);
return ((ddm_handle_t *)ddm_part_desc);
}
@@ -1900,21 +1944,24 @@
* ddm_get_slices()
* Discovers slices for particular disk/partition or discover all
* slices
- * Parameters: h handle of drive/partition, for which slices will be
- * discovered. If NULL, all slices are reported.
+ * Parameters:
+ * h handle of drive/partition, for which slices will be
+ * discovered. If NULL, all slices are reported.
+ * nslices Return number of slices discovered.
*/
ddm_handle_t *
-ddm_get_slices(ddm_handle_t h)
+ddm_get_slices(ddm_handle_t h, int *nslices)
{
dm_descriptor_t *ddm_slice_desc;
dm_descriptor_t *am;
dm_desc_type_t desc_type;
-
int errn;
+ /* Initialize number of slices found to 0 */
+ if (nslices != NULL)
+ *nslices = 0;
/* discover all slices */
-
if (h == DDM_DISCOVER_ALL) {
ddm_slice_desc = dm_get_descriptors(DM_SLICE, NULL, &errn);
@@ -1926,6 +1973,10 @@
return (NULL);
}
+ if (nslices != NULL) {
+ *nslices =
+ ddm_count_handles((ddm_handle_t *)ddm_slice_desc);
+ }
return ((ddm_handle_t *)ddm_slice_desc);
}
@@ -1934,11 +1985,9 @@
* first check, if slice type is associated with
* the type provided by handle
*/
-
desc_type = dm_get_type((dm_descriptor_t)h);
/* slice can be only discovered for particular disk or partition */
-
if ((desc_type != DM_DRIVE) && (desc_type != DM_PARTITION)) {
DDM_DEBUG(DDM_DBGLVL_ERROR, "%s",
"ddm_get_slices(): This handle is not assoc with slice\n");
@@ -1962,6 +2011,10 @@
return (NULL);
}
+ if (nslices != NULL) {
+ *nslices =
+ ddm_count_handles((ddm_handle_t *)ddm_slice_desc);
+ }
return ((ddm_handle_t *)ddm_slice_desc);
}
@@ -1994,6 +2047,8 @@
}
dm_free_descriptors(am);
+ if (nslices != NULL)
+ *nslices = ddm_count_handles((ddm_handle_t *)ddm_slice_desc);
return ((ddm_handle_t *)ddm_slice_desc);
}
@@ -2136,10 +2191,10 @@
dm_get_slice_stats(name, &slice_stats, &errn);
if (errn != 0) {
- DDM_DEBUG(DDM_DBGLVL_ERROR,
- "ddm_get_slice_stats(): Can't get slice inuse data, "
- "for %s, err=%d\n", name, errn);
- return (errn);
+ DDM_DEBUG(DDM_DBGLVL_ERROR,
+ "ddm_get_slice_stats(): Can't get slice inuse data, "
+ "for %s, err=%d\n", name, errn);
+ return (errn);
}
/*
@@ -2155,10 +2210,10 @@
* No inuse data available
*/
if (used_by == NULL || used_name == NULL) {
- DDM_DEBUG(DDM_DBGLVL_NOTICE, "ddm_get_slice_inuse_stats(): "
- "No inuse data available for %s\n", name);
- nvlist_free(slice_stats);
- return (0);
+ DDM_DEBUG(DDM_DBGLVL_NOTICE, "ddm_get_slice_inuse_stats(): "
+ "No inuse data available for %s\n", name);
+ nvlist_free(slice_stats);
+ return (0);
}
/*
@@ -2166,10 +2221,10 @@
*/
if ((strcmp(nvpair_name(used_by), DM_USED_BY) != 0) ||
(strcmp(nvpair_name(used_name), DM_USED_NAME) != 0)) {
- DDM_DEBUG(DDM_DBGLVL_ERROR, "ddm_get_slice_inuse_stats(): "
- "Problem with inuse data for %s\n", name);
- nvlist_free(slice_stats);
- return (1);
+ DDM_DEBUG(DDM_DBGLVL_ERROR, "ddm_get_slice_inuse_stats(): "
+ "Problem with inuse data for %s\n", name);
+ nvlist_free(slice_stats);
+ return (1);
}
/*
@@ -2179,10 +2234,10 @@
nvpair_value_string(used_name, &data);
if (by == NULL || data == NULL) {
- DDM_DEBUG(DDM_DBGLVL_ERROR, "ddm_get_slice_inuse_stats(): "
- "NULL value for inuse data for %s\n", name);
- nvlist_free(slice_stats);
- return (1);
+ DDM_DEBUG(DDM_DBGLVL_ERROR, "ddm_get_slice_inuse_stats(): "
+ "NULL value for inuse data for %s\n", name);
+ nvlist_free(slice_stats);
+ return (1);
}
DDM_DEBUG(DDM_DBGLVL_NOTICE,
@@ -2194,18 +2249,18 @@
* the inuse data to the attribute list.
*/
for (i = 0; ddm_slice_inuse_conv_tbl[i][0] != NULL; i++) {
- if (strcmp(by, ddm_slice_inuse_conv_tbl[i][0]) == 0) {
- name_src = ddm_slice_inuse_conv_tbl[i][0];
- name_dst = ddm_slice_inuse_conv_tbl[i][1];
- break;
- }
+ if (strcmp(by, ddm_slice_inuse_conv_tbl[i][0]) == 0) {
+ name_src = ddm_slice_inuse_conv_tbl[i][0];
+ name_dst = ddm_slice_inuse_conv_tbl[i][1];
+ break;
+ }
}
if (name_src == NULL) {
- DDM_DEBUG(DDM_DBGLVL_ERROR,
- "ddm_get_slice_inuse_stats(): %s not in table\n", by);
- nvlist_free(slice_stats);
- return (1);
+ DDM_DEBUG(DDM_DBGLVL_ERROR,
+ "ddm_get_slice_inuse_stats(): %s not in table\n", by);
+ nvlist_free(slice_stats);
+ return (1);
}
DDM_DEBUG(DDM_DBGLVL_NOTICE,
--- a/usr/src/lib/libtd/td_dd.h Tue Nov 02 18:25:00 2010 +0100
+++ b/usr/src/lib/libtd/td_dd.h Thu Nov 04 10:08:30 2010 +0000
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _TD_DD_H
@@ -80,11 +79,11 @@
/* function prototypes */
-extern ddm_handle_t *ddm_get_disks(void);
+extern ddm_handle_t *ddm_get_disks(int *ndisks);
extern nvlist_t *ddm_get_disk_attributes(ddm_handle_t d);
-extern ddm_handle_t *ddm_get_partitions(ddm_handle_t d);
+extern ddm_handle_t *ddm_get_partitions(ddm_handle_t d, int *nparts);
extern nvlist_t *ddm_get_partition_attributes(ddm_handle_t p);
-extern ddm_handle_t *ddm_get_slices(ddm_handle_t h);
+extern ddm_handle_t *ddm_get_slices(ddm_handle_t h, int *nslices);
extern nvlist_t *ddm_get_slice_attributes(ddm_handle_t s);
extern void ddm_free_handle_list(ddm_handle_t *h);
extern void ddm_free_attr_list(nvlist_t *attrs);
--- a/usr/src/lib/libtd/td_mg.c Tue Nov 02 18:25:00 2010 +0100
+++ b/usr/src/lib/libtd/td_mg.c Thu Nov 04 10:08:30 2010 +0000
@@ -54,6 +54,7 @@
#include <td_api.h> /* TD user definitions */
#include <td_dd.h> /* TD disk module definitions */
#include <td_version.h> /* version info */
+#include <td_zpool.h> /* Zpool module definitions */
#include <ls_api.h> /* logging service */
#include <assert.h>
@@ -77,6 +78,7 @@
ddm_handle_t handle; /* disk module handle */
nvlist_t *attrib; /* attribute list for disk */
boolean_t discovery_done; /* discovery performed for object */
+ const char *compare_attr_name; /* nvpair comparison attribute */
};
/* class for TD objects */
@@ -87,21 +89,18 @@
struct td_obj *objcur; /* current object */
ddm_handle_t *pddm; /* disk module handle */
boolean_t issorted; /* object list has been sorted */
- int (*compare_routine)(const void *, const void *); /* sorting */
};
-/* sort comparison routines for objects */
-static int compare_disk_objs(const void *p1, const void *p2);
-static int compare_partition_objs(const void *p1, const void *p2);
-static int compare_slice_objs(const void *p1, const void *p2);
-static int compare_os_objs(const void *p1, const void *p2);
+/* sort comparison routine for all td objects objects */
+static int compare_td_objs(const void *p1, const void *p2);
/* object type declarations */
static struct td_class objlist[] = {
- {TD_OT_DISK, 0, NULL, NULL, NULL, B_FALSE, compare_disk_objs},
- {TD_OT_PARTITION, 0, NULL, NULL, NULL, B_FALSE, compare_partition_objs},
- {TD_OT_SLICE, 0, NULL, NULL, NULL, B_FALSE, compare_slice_objs},
- {TD_OT_OS, 0, NULL, NULL, NULL, B_FALSE, compare_os_objs}
+ {TD_OT_DISK, 0, NULL, NULL, NULL, B_FALSE},
+ {TD_OT_PARTITION, 0, NULL, NULL, NULL, B_FALSE},
+ {TD_OT_SLICE, 0, NULL, NULL, NULL, B_FALSE},
+ {TD_OT_OS, 0, NULL, NULL, NULL, B_FALSE},
+ {TD_OT_ZPOOL, 0, NULL, NULL, NULL, B_FALSE}
};
#define is_valid_td_object_type(ot) \
((ot) >= 0 && (ot) < sizeof (objlist) / sizeof (objlist[0]))
@@ -116,23 +115,27 @@
#define PDDMDISKS (objlist[TD_OT_DISK].pddm)
#define PDDMPARTS (objlist[TD_OT_PARTITION].pddm)
#define PDDMSLICES (objlist[TD_OT_SLICE].pddm)
+#define PDDMZPOOLS (objlist[TD_OT_ZPOOL].pddm)
/* arrays of TD objects shorthand */
#define PDISKARR (objlist[TD_OT_DISK].objarr)
#define PPARTARR (objlist[TD_OT_PARTITION].objarr)
#define PSLICEARR (objlist[TD_OT_SLICE].objarr)
+#define PZPOOLARR (objlist[TD_OT_ZPOOL].objarr)
/* count of objects per type shorthand */
#define NDISKS (objlist[TD_OT_DISK].objcnt)
#define NPARTS (objlist[TD_OT_PARTITION].objcnt)
#define NSLICES (objlist[TD_OT_SLICE].objcnt)
#define NOS (objlist[TD_OT_OS].objcnt)
+#define NZPOOLS (objlist[TD_OT_ZPOOL].objcnt)
/* user current object pointers shorthand */
#define CURDISK (objlist[TD_OT_DISK].objcur)
#define CURPART (objlist[TD_OT_PARTITION].objcur)
#define CURSLICE (objlist[TD_OT_SLICE].objcur)
#define CUROS (objlist[TD_OT_OS].objcur)
+#define CURZPOOL (objlist[TD_OT_ZPOOL].objcur)
static td_errno_t set_td_errno(int);
static void clear_td_errno();
@@ -209,14 +212,12 @@
switch (otype) {
case TD_OT_DISK: /* get disks */
if (PDDMDISKS == NULL) {
- PDDMDISKS = ddm_get_disks();
+ NDISKS = 0;
+ PDDMDISKS = ddm_get_disks(&NDISKS);
if (PDDMDISKS == NULL) {
return (set_td_errno(TD_E_NO_DEVICE));
}
}
- for (NDISKS = 0, pddm = PDDMDISKS; *pddm != NULL;
- pddm++, NDISKS++)
- ;
if (number_found != NULL)
*number_found = NDISKS;
@@ -240,6 +241,7 @@
ptdobj->handle = *pddm;
ptdobj->attrib = NULL;
ptdobj->discovery_done = B_FALSE;
+ ptdobj->compare_attr_name = TD_DISK_ATTR_NAME;
}
/* mark end of array */
ptdobj->handle = NULL;
@@ -248,17 +250,15 @@
break;
case TD_OT_PARTITION:
if (PDDMPARTS == NULL) {
- PDDMPARTS = ddm_get_partitions(DDM_DISCOVER_ALL);
+ NPARTS = 0;
+ PDDMPARTS =
+ ddm_get_partitions(DDM_DISCOVER_ALL, &NPARTS);
if (PDDMPARTS == NULL) {
return (set_td_errno(TD_E_END));
}
}
if (TLI)
td_debug_print(LS_DBGLVL_INFO, "got partitions\n");
-
- for (NPARTS = 0, pddm = PDDMPARTS; *pddm != NULL;
- pddm++, NPARTS++)
- ;
if (number_found != NULL)
*number_found = NPARTS;
if (TLI)
@@ -281,6 +281,7 @@
ptdobj->handle = *pddm;
ptdobj->attrib = NULL;
ptdobj->discovery_done = B_FALSE;
+ ptdobj->compare_attr_name = TD_PART_ATTR_NAME;
}
/* mark end of array */
ptdobj->handle = NULL;
@@ -289,16 +290,14 @@
break;
case TD_OT_SLICE:
if (PDDMSLICES == NULL) {
- PDDMSLICES = ddm_get_slices(DDM_DISCOVER_ALL);
+ NSLICES = 0;
+ PDDMSLICES = ddm_get_slices(DDM_DISCOVER_ALL, &NSLICES);
if (PDDMSLICES == NULL)
return (set_td_errno(TD_E_END));
}
if (TLI)
td_debug_print(LS_DBGLVL_INFO, "got slices\n");
- for (NSLICES = 0, pddm = PDDMSLICES; *pddm != NULL;
- pddm++, NSLICES++)
- ;
if (number_found != NULL)
*number_found = NSLICES;
if (TLI)
@@ -317,6 +316,7 @@
ptdobj->handle = *pddm;
ptdobj->attrib = NULL;
ptdobj->discovery_done = B_FALSE;
+ ptdobj->compare_attr_name = TD_SLICE_ATTR_NAME;
}
/* mark end of array */
ptdobj->handle = NULL;
@@ -325,22 +325,57 @@
break;
case TD_OT_OS: /* get OS instances */
if (PDDMSLICES == NULL) {
- PDDMSLICES = ddm_get_slices(NULL); /* get all slices */
+ NSLICES = 0;
+ PDDMSLICES =
+ ddm_get_slices(NULL, &NSLICES); /* get all slices */
if (PDDMSLICES == NULL)
return (set_td_errno(TD_E_END));
}
- NSLICES = 0;
- pddm = PDDMSLICES;
- while (*pddm != NULL) { /* count slices */
- pddm++;
- NSLICES++;
- }
NOS = 0; /* reset master count */
ret = os_discover();
if (number_found != NULL)
*number_found = NOS;
CUROS = NULL; /* reset current to first */
break;
+ case TD_OT_ZPOOL: /* get zpools */
+ if (PDDMZPOOLS == NULL) {
+ NZPOOLS = 0;
+ PDDMZPOOLS = ddm_get_zpools(&NZPOOLS); /* get zpools */
+ if (PDDMZPOOLS == NULL) {
+ return (set_td_errno(TD_E_END));
+ }
+ }
+ if (number_found != NULL)
+ *number_found = NZPOOLS;
+
+ if (TLI)
+ td_debug_print(LS_DBGLVL_INFO,
+ "got zpools nfound=%d\n", NZPOOLS);
+
+ /* allocate space for all ZFS pools plus terminator element */
+ PZPOOLARR =
+ realloc(PZPOOLARR, (NZPOOLS + 1) * sizeof (struct td_obj));
+ if (PZPOOLARR == NULL)
+ return (set_td_errno(TD_E_MEMORY));
+
+ pddm = PDDMZPOOLS;
+ ptdobj = PZPOOLARR;
+ for (iobj = 0; iobj < NZPOOLS; iobj++, pddm++, ptdobj++) {
+ if (TLI)
+ td_debug_print(LS_DBGLVL_INFO,
+ "zpools %d nfound=%d\n", iobj, NZPOOLS);
+
+ ptdobj->handle = *pddm;
+ ptdobj->attrib = NULL;
+ ptdobj->discovery_done = B_FALSE;
+ ptdobj->compare_attr_name = TD_ZPOOL_ATTR_NAME;
+ }
+ /* mark end of array */
+ ptdobj->handle = NULL;
+ ptdobj->attrib = NULL;
+ CURZPOOL = NULL;
+ break;
+
default:
ret = TD_E_NO_OBJECT;
break;
@@ -510,6 +545,23 @@
return (NULL);
}
return (dup_attr_set_errno(CUROS));
+ case TD_OT_ZPOOL:
+ if (CURZPOOL == NULL || CURZPOOL->handle == NULL) {
+ (void) set_td_errno(TD_E_END);
+ return (NULL);
+ }
+ if (CURZPOOL->discovery_done)
+ return (dup_attr_set_errno(CURZPOOL));
+ /* discover attributes */
+ CURZPOOL->attrib = ddm_get_zpool_attributes(CURZPOOL->handle);
+ CURZPOOL->discovery_done = B_TRUE;
+ if (CURZPOOL->attrib == NULL) {
+ if (TLI)
+ td_debug_print(LS_DBGLVL_INFO,
+ "zpool attribute not found\n");
+ return (NULL);
+ }
+ return (dup_attr_set_errno(CURZPOOL));
default:
break;
}
@@ -720,6 +772,7 @@
free_td_obj_list(TD_OT_PARTITION);
free_td_obj_list(TD_OT_SLICE);
free_td_obj_list(TD_OT_OS);
+ free_td_obj_list(TD_OT_ZPOOL);
if (TLI)
td_debug_print(LS_DBGLVL_INFO, "td_discovery_release ends \n");
return (TD_E_SUCCESS);
@@ -911,6 +964,23 @@
pobja->attrib = onvl;
pobja->handle = (ddm_handle_t)onvl;
pobja->discovery_done = B_TRUE;
+ switch (objtype) {
+ case TD_OT_DISK :
+ pobja->compare_attr_name = TD_DISK_ATTR_NAME;
+ break;
+ case TD_OT_PARTITION :
+ pobja->compare_attr_name = TD_PART_ATTR_NAME;
+ break;
+ case TD_OT_SLICE :
+ pobja->compare_attr_name = TD_SLICE_ATTR_NAME;
+ break;
+ case TD_OT_OS :
+ pobja->compare_attr_name = TD_OS_ATTR_SLICE_NAME;
+ break;
+ case TD_OT_ZPOOL :
+ pobja->compare_attr_name = TD_ZPOOL_ATTR_NAME;
+ break;
+ }
if (TLI)
td_debug_print(LS_DBGLVL_INFO, "added to td_obj list!!!\n");
objlist[objtype].objcnt++;
@@ -918,6 +988,7 @@
pobja->attrib = NULL;
pobja->handle = 0L;
pobja->discovery_done = B_FALSE;
+ pobja->compare_attr_name = NULL;
return (TD_E_SUCCESS);
}
@@ -1325,7 +1396,8 @@
/* for each slice, evaluate it for OS instance */
if (PDDMSLICES == NULL) { /* get all slices */
- PDDMSLICES = ddm_get_slices(DDM_DISCOVER_ALL);
+ NSLICES = 0;
+ PDDMSLICES = ddm_get_slices(DDM_DISCOVER_ALL, &NSLICES);
if (PDDMSLICES == NULL)
return (TD_E_END);
}
@@ -2149,8 +2221,12 @@
if (pobl->objarr != NULL) {
/* release attribute data */
for (pobj = pobl->objarr; pobj->handle != 0; pobj++)
- if (pobj->attrib != NULL)
+ if (pobj->attrib != NULL) {
nvlist_free(pobj->attrib);
+ pobj->compare_attr_name = NULL;
+ pobj->discovery_done = B_FALSE;
+ pobj->attrib = NULL;
+ }
/* release object instance list */
free(pobl->objarr);
pobl->objarr = NULL;
@@ -2159,10 +2235,15 @@
pobl->objcur = NULL;
pobl->objcnt = 0;
pobl->issorted = B_FALSE;
- /* free handle lists from lower-level modules */
- if (pobl->pddm != NULL) {
- (void) ddm_free_handle_list(pobl->pddm);
- pobl->pddm = NULL;
+ if (ot != TD_OT_ZPOOL) {
+ /* free handle lists from lower-level modules */
+ if (pobl->pddm != NULL) {
+ (void) ddm_free_handle_list(pobl->pddm);
+ pobl->pddm = NULL;
+ }
+ } else {
+ /* free zpool handle list and internal zpool linked list */
+ (void) ddm_free_zpool_list(pobl->pddm);
}
}
@@ -2316,87 +2397,37 @@
return (search_disks_for_slices(pslicepar));
}
+/*
+ * Function: compare_td_objs
+ * Description: Compare two td objects based on the object attr name.
+ * Return values are similar to that of strcmp()
+ * Scope: private
+ * Parameters:
+ * const void *p1 : zpool object one
+ * const void *p2 : zpool object two
+ * Return:
+ * -1 : pd1 < pd2
+ * 0 : pd1 == pd2
+ * 1 : pd1 > pd2
+ */
static int
-compare_os_objs(const void *p1, const void *p2)
+compare_td_objs(const void *p1, const void *p2)
{
-
struct td_obj *o1 = (struct td_obj *)p1;
struct td_obj *o2 = (struct td_obj *)p2;
char *pd1 = NULL, *pd2 = NULL;
if (o1->attrib != NULL)
- nvlist_lookup_string(o1->attrib, TD_OS_ATTR_SLICE_NAME, &pd1);
+ nvlist_lookup_string(o1->attrib, o1->compare_attr_name, &pd1);
if (o2->attrib != NULL)
- nvlist_lookup_string(o2->attrib, TD_OS_ATTR_SLICE_NAME, &pd2);
- if (pd1 == NULL && pd2 == NULL)
- return (0);
- if (pd1 == NULL)
- return (-1);
- if (pd2 == NULL)
- return (1);
- return (strcmp(pd1, pd2));
-}
-
-static int
-compare_disk_objs(const void *p1, const void *p2)
-{
-
- struct td_obj *o1 = (struct td_obj *)p1;
- struct td_obj *o2 = (struct td_obj *)p2;
- char *pd1 = NULL, *pd2 = NULL;
-
- if (o1->attrib != NULL)
- nvlist_lookup_string(o1->attrib, TD_DISK_ATTR_NAME, &pd1);
- if (o2->attrib != NULL)
- nvlist_lookup_string(o2->attrib, TD_DISK_ATTR_NAME, &pd2);
+ nvlist_lookup_string(o2->attrib, o2->compare_attr_name, &pd2);
if (pd1 == NULL && pd2 == NULL)
return (0);
if (pd1 == NULL)
return (-1);
if (pd2 == NULL)
return (1);
- return (strcmp(pd1, pd2));
-}
-static int
-compare_slice_objs(const void *p1, const void *p2)
-{
-
- struct td_obj *o1 = (struct td_obj *)p1;
- struct td_obj *o2 = (struct td_obj *)p2;
- char *pd1 = NULL, *pd2 = NULL;
-
- if (o1->attrib != NULL)
- nvlist_lookup_string(o1->attrib, TD_SLICE_ATTR_NAME, &pd1);
- if (o2->attrib != NULL)
- nvlist_lookup_string(o2->attrib, TD_SLICE_ATTR_NAME, &pd2);
- if (pd1 == NULL && pd2 == NULL)
- return (0);
- if (pd1 == NULL)
- return (-1);
- if (pd2 == NULL)
- return (1);
- return (strcmp(pd1, pd2));
-}
-
-static int
-compare_partition_objs(const void *p1, const void *p2)
-{
-
- struct td_obj *o1 = (struct td_obj *)p1;
- struct td_obj *o2 = (struct td_obj *)p2;
- char *pd1 = NULL, *pd2 = NULL;
-
- if (o1->attrib != NULL)
- nvlist_lookup_string(o1->attrib, TD_PART_ATTR_NAME, &pd1);
- if (o2->attrib != NULL)
- nvlist_lookup_string(o2->attrib, TD_PART_ATTR_NAME, &pd2);
- if (pd1 == NULL && pd2 == NULL)
- return (0);
- if (pd1 == NULL)
- return (-1);
- if (pd2 == NULL)
- return (1);
return (strcmp(pd1, pd2));
}
@@ -2479,7 +2510,7 @@
if (pobjlist->issorted)
return;
qsort(pobjlist->objarr, pobjlist->objcnt,
- sizeof (struct td_obj), pobjlist->compare_routine);
+ sizeof (struct td_obj), compare_td_objs);
pobjlist->issorted = B_TRUE;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtd/td_zpool.c Thu Nov 04 10:08:30 2010 +0000
@@ -0,0 +1,1858 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * ZFS Pools discovery for Target Discovery module
+ */
+#include <unistd.h>
+#include <libnvpair.h>
+#include <strings.h>
+#include <td_lib.h>
+#include <td_api.h>
+#include <ls_api.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libdiskmgt.h>
+
+#include <td_dd.h>
+#include <td_zpool.h>
+
+/* Library wide variables */
+static libzfs_handle_t *g_zfs;
+static td_zpool_info_t *g_zpools_list = NULL;
+
+static void td_zpool_info_list_release(td_zpool_info_t *list);
+static ddm_handle_t *td_zpool_discover(int *nzpools);
+static td_zpool_target_t *td_zpool_target_allocate(zpool_handle_t *zhp,
+ nvlist_t *child, int *logcnt, int *errn, boolean_t do_logs,
+ boolean_t is_spare);
+static int td_zpool_iter_callback(zpool_handle_t *zhp, void *data);
+static void td_zpool_info_list_add(td_zpool_info_t **list,
+ td_zpool_info_t *new);
+static void td_zpool_target_free(td_zpool_target_t *zt);
+static void td_zpool_info_free(td_zpool_info_t *zi);
+static void td_zpool_allocate_target_nvlist(td_zpool_target_t **zts,
+ uint32_t num_nvtargets,
+ nvlist_t *nvtarget,
+ const char *attr_name,
+ const char *attr_num,
+ int *errn);
+static nvlist_t *td_zpool_get_attributes(td_zpool_info_t *zi, int *errn);
+static void td_zpool_target_print(td_zpool_target_t *zt,
+ int depth, boolean_t is_spare);
+static void td_zpool_info_print(td_zpool_info_t *zi, int num);
+static void td_zpool_info_print_ptrs(td_zpool_info_t **ptrs);
+static void td_zpool_info_print_list(td_zpool_info_t *start);
+static ddm_handle_t *td_zpool_info_ptrs_to_ddm_handle(td_zpool_info_t **ptrs);
+static td_zpool_info_t **td_zpool_info_get_ptrs(
+ td_zpool_info_t *zpools_list, int *nzpools);
+static void free_nvlist_array(nvlist_t **nv, int count);
+static nvlist_t *allocate_target_nvlist(td_zpool_target_t *zt, int *errn);
+static int td_zpool_import_find(libzfs_handle_t *zh,
+ td_zpool_info_t **zi_list);
+static int td_zpool_import_add(nvlist_t *pool,
+ td_zpool_info_t **zi_list);
+
+/*
+ * *******************************************************************
+ * Public Functions
+ * *******************************************************************
+ */
+
+/*
+ * Function: ddm_free_zpool_list()
+ *
+ * Description: Release zpool list for td_mg.c
+ *
+ * Parameters:
+ * ddm_handle_t *dh : Handler list to free
+ *
+ * Returns:
+ * Nothing
+ *
+ * Scope:
+ * Public
+ */
+void
+ddm_free_zpool_list(ddm_handle_t *dh)
+{
+ free(dh);
+ td_zpool_info_list_release(g_zpools_list);
+ g_zpools_list = NULL;
+}
+
+/*
+ * Function: ddm_get_zpools()
+ *
+ * Description: Get zpool list for td_mg.c
+ *
+ * Parameters:
+ * int *nzpools : Container for number of zpools
+ *
+ * Returns:
+ * ddm_handle_t * : Array of zpools handles discovered
+ * int *nzpools : Sets to number of zpools found
+ *
+ * Scope:
+ * Public
+ */
+ddm_handle_t *
+ddm_get_zpools(int *nzpools)
+{
+ ddm_handle_t *dh;
+
+ /* Initialize number of zpools found to 0 */
+ if (nzpools != NULL)
+ *nzpools = 0;
+
+ DDM_DEBUG(DDM_DBGLVL_NOTICE, "%s", "-> ddm_get_zpools()\n");
+
+ dh = (ddm_handle_t *)td_zpool_discover(nzpools);
+
+ if (dh == NULL) {
+ DDM_DEBUG(DDM_DBGLVL_ERROR, "%s",
+ "Can't get zpool info\n");
+ }
+
+ return (dh);
+}
+
+/*
+ * Function: ddm_get_zpool_attributes()
+ *
+ * Description: Get attributes of Zpools.
+ *
+ * Parameters:
+ * ddm_handle_t zpool : zpool handle to get attributes for
+ *
+ * Returns:
+ * nvlist_t pointer containing attributes
+ *
+ * Scope:
+ * Public
+ */
+nvlist_t *
+ddm_get_zpool_attributes(ddm_handle_t zpool)
+{
+ td_zpool_info_t *zi;
+ nvlist_t *attrs;
+ int errn = 0;
+
+ zi = (td_zpool_info_t *)(uintptr_t)zpool;
+
+ attrs = td_zpool_get_attributes(zi, &errn);
+ if (errn != 0) {
+ DDM_DEBUG(DDM_DBGLVL_ERROR, "ddm_get_zpool_attributes():"
+ " Can't get attr. for Zpool, err=%d\n", errn);
+ return (NULL);
+ }
+
+ return (attrs);
+}
+
+/*
+ * ********************************************************************
+ * Private Functions
+ * ********************************************************************
+ */
+
+/*
+ * Function: td_zpool_info_list_release()
+ *
+ * Description: Release all internally allocated memory for
+ * already discovered zpools
+ *
+ * Parameters:
+ * td_zpool_info_t *list : Internal linked list to be freed
+ *
+ * Returns:
+ * void
+ *
+ * Scope:
+ * Private
+ */
+static void
+td_zpool_info_list_release(td_zpool_info_t *list)
+{
+ td_zpool_info_t *cur;
+ td_zpool_info_t *tofree;
+
+ if (list == NULL) {
+ return;
+ }
+
+ for (cur = list; cur != NULL; ) {
+ tofree = cur;
+ cur = cur->next;
+ td_zpool_info_free(tofree);
+ }
+}
+
+/*
+ * Function: td_zpool_discover()
+ *
+ * Description: Discover zpools in the system by using libzfs's
+ * zpool_iter() function. The attributes of the zpools are
+ * stored in the linked list of td_zpool_info_t.
+ *
+ * Parameters:
+ * int *nzpools : Return number of zpools found
+ *
+ * Returns:
+ * ddm_handle_t * : Array of ddm_handle_t for all pools
+ * int *nzpools : Number of zpools discovered
+ *
+ * Scope:
+ * Private
+ */
+static ddm_handle_t *
+td_zpool_discover(int *nzpools)
+{
+ ddm_handle_t *df = NULL;
+ td_zpool_info_t **zpools_ptrs = NULL;
+
+ /* Initialize libzfs handle */
+ if ((g_zfs = libzfs_init()) == NULL) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_discover():"
+ " failed to initialize ZFS library\n");
+ return (NULL);
+ }
+
+ if (g_zpools_list != NULL) {
+ td_zpool_info_list_release(g_zpools_list);
+ g_zpools_list = NULL;
+ }
+
+ if ((zpool_iter(g_zfs, td_zpool_iter_callback, &g_zpools_list)) != 0) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_discover()"
+ " failed to iterate zpools\n");
+ libzfs_fini(g_zfs);
+ return (NULL);
+ }
+
+ if ((td_zpool_import_find(g_zfs, &g_zpools_list)) == 0) {
+ zpools_ptrs = td_zpool_info_get_ptrs(g_zpools_list, nzpools);
+ td_zpool_info_print_list(g_zpools_list);
+ td_zpool_info_print_ptrs(zpools_ptrs);
+ df = td_zpool_info_ptrs_to_ddm_handle(zpools_ptrs);
+ free(zpools_ptrs);
+ } else {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_discover()"
+ " failed to iterate import candidates\n");
+ libzfs_fini(g_zfs);
+ return (NULL);
+ }
+
+ libzfs_fini(g_zfs);
+
+ return (df);
+}
+
+/*
+ * Function: td_zpool_target_allocate
+ *
+ * Description: Allocate a td_zpool_target_t for target if
+ * this target has children recursively call this function
+ * to allocate further targets.
+ *
+ * Parameters:
+ * zpool_handle_t *zhp : zpool handle
+ * nvlist_t *child : nvlist for this target
+ * int *logcnt : Return log count
+ * int *errn : Return error number
+ * boolean_t do_logs : Process logs or not
+ * boolean_t is_spare : Is this a spare
+ *
+ * Returns:
+ * td_zpool_target_t * : Allocated td_zpool_target_t
+ *
+ * Scope:
+ * Private
+ */
+static td_zpool_target_t *
+td_zpool_target_allocate(zpool_handle_t *zhp,
+ nvlist_t *child,
+ int *logcnt,
+ int *errn,
+ boolean_t do_logs,
+ boolean_t is_spare)
+{
+ nvlist_t **nvchild;
+ td_zpool_target_t *top_target = NULL;
+ char *vname;
+ uint_t vsc;
+ vdev_stat_t *vs;
+ uint64_t islog = B_FALSE;
+ uint64_t ishole = B_FALSE;
+ int cnt1 = 0;
+
+ *errn = 0;
+
+ /*
+ * Determine if this target device is a ZFS Log or a ZFS Hole.
+ * If a ZFS Log device and we do not want to process logs then
+ * return NULL.
+ * ZFS Holes occur when you remove a slog after having add more
+ * stripes, we always want to ignore these.
+ */
+ (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_IS_LOG, &islog);
+ (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_IS_HOLE, &ishole);
+
+ if (ishole) {
+ return (NULL);
+ }
+
+ if (islog) {
+ *logcnt = *logcnt + 1;
+ if (!do_logs) {
+ return (NULL);
+ }
+ } else {
+ if (do_logs) {
+ return (NULL);
+ }
+ }
+
+ top_target = calloc(1, sizeof (td_zpool_target_t));
+ if (top_target == NULL) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_target_allocate():"
+ " failed to allocate memory for top target,"
+ " err=%d\n", ENOMEM);
+ *errn = ENOMEM;
+ return (NULL);
+ }
+
+ vname = zpool_vdev_name(g_zfs, zhp, child, B_TRUE);
+ if (vname == NULL) {
+ td_debug_print(LS_DBGLVL_WARN, "td_zpool_target_allocate():"
+ " failed to get device name\n");
+ td_debug_print(LS_DBGLVL_WARN,
+ "%d : %s\n", libzfs_errno(g_zfs),
+ libzfs_error_description(g_zfs));
+ td_zpool_target_free(top_target);
+ *errn = -1;
+ return (NULL);
+ }
+ top_target->name = strdup(vname);
+
+ if (nvlist_lookup_uint64_array(child,
+ ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &vsc) != 0) {
+ td_debug_print(LS_DBGLVL_WARN, "td_zpool_target_allocate():"
+ " failed to get device stats\n");
+ top_target->health = strdup("UNKNOWN");
+ top_target->read_errors = 0;
+ top_target->write_errors = 0;
+ top_target->checksum_errors = 0;
+ } else {
+ if (is_spare) {
+ if (vs->vs_aux == VDEV_AUX_SPARED) {
+ top_target->health = strdup("INUSE");
+ } else if (vs->vs_state == VDEV_STATE_HEALTHY) {
+ top_target->health = strdup("AVAIL");
+ } else {
+ top_target->health = zpool_state_to_name(
+ vs->vs_state, vs->vs_aux);
+ }
+ top_target->read_errors = 0;
+ top_target->write_errors = 0;
+ top_target->checksum_errors = 0;
+ } else {
+ top_target->health =
+ zpool_state_to_name(vs->vs_state, vs->vs_aux);
+ top_target->read_errors = vs->vs_read_errors;
+ top_target->write_errors = vs->vs_write_errors;
+ top_target->checksum_errors = vs->vs_checksum_errors;
+ }
+ }
+
+ top_target->num_targets = 0;
+ (void) nvlist_lookup_nvlist_array(child,
+ ZPOOL_CONFIG_CHILDREN,
+ &nvchild, &top_target->num_targets);
+
+ if (top_target->num_targets > 0) {
+ top_target->targets =
+ calloc(top_target->num_targets,
+ sizeof (td_zpool_target_t *));
+ if (top_target->targets == NULL) {
+ td_debug_print(LS_DBGLVL_ERR,
+ "td_zpool_target_allocate():"
+ " failed to allocate memory for targets,"
+ " err=%d\n", ENOMEM);
+ *errn = ENOMEM;
+ top_target->num_targets = 0;
+ td_zpool_target_free(top_target);
+ return (NULL);
+ }
+
+ for (cnt1 = 0; cnt1 < top_target->num_targets; cnt1++) {
+ top_target->targets[cnt1] =
+ td_zpool_target_allocate(zhp, nvchild[cnt1],
+ logcnt, errn, B_FALSE, is_spare);
+
+ if (*errn != 0) {
+ td_debug_print(LS_DBGLVL_ERR,
+ "td_zpool_target_allocate():"
+ " failed to allocate memory for targets,"
+ " err=%d\n", *errn);
+ /* Free any previously allocated targets */
+ td_zpool_target_free(top_target);
+ return (NULL);
+ }
+ }
+ } else {
+ top_target->targets = NULL;
+ }
+
+ return (top_target);
+}
+
+
+/*
+ * Function: td_zpool_import_add
+ *
+ * Description: Found importable zpool, generate zpool_info_t structure
+ * and add to linked list of discovered zpools.
+ *
+ * Parameters:
+ * nvlist_t *pool : nvlist of importable pool
+ * td_zpool_info_t *zi_list : td_zpool_info_t linked list
+ *
+ * Returns:
+ * 0 : Success
+ * 1 : Failure
+ *
+ * Scope:
+ * Private
+ */
+static int
+td_zpool_import_add(nvlist_t *pool, td_zpool_info_t **zi_list)
+{
+ td_zpool_info_t *list = *zi_list;
+ int cnt1 = 0, logcnt = 0;
+ uint32_t targetcnt = 0;
+ nvlist_t **l2cache, **spares;
+ uint_t nl2cache, nspares;
+ char *msgid;
+ nvlist_t *nvroot, **child;
+ uint32_t num_children = 0;
+ uint_t vsc;
+ vdev_stat_t *vs;
+ td_zpool_info_t *zi = NULL;
+ char *name;
+ uint64_t guid;
+
+ /* name */
+ if (nvlist_lookup_string(pool, ZPOOL_CONFIG_POOL_NAME, &name) != 0) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_import_add():"
+ " failed to get pool name.\n");
+ return (1);
+ }
+
+ /* GUID */
+ if (nvlist_lookup_uint64(pool, ZPOOL_CONFIG_POOL_GUID, &guid) != 0) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_import_add():"
+ " failed to get pool GUID.\n");
+ return (1);
+ }
+
+ /* VDEV Tree */
+ if (nvlist_lookup_nvlist(pool,
+ ZPOOL_CONFIG_VDEV_TREE, &nvroot) != 0) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_import_add():"
+ " failed to get vdev tree\n");
+ return (1);
+ }
+
+ /* VDEV STATS */
+ if (nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &vsc) != 0) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_import_add():"
+ " failed to get vdev stats\n");
+ return (1);
+ }
+
+ /* Construct td_zpool_info_t of attributes for this zpool */
+ zi = calloc(1, sizeof (td_zpool_info_t));
+ if (zi == NULL) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_import_add():"
+ " failed to allocate memory for zpool,"
+ " err=%d\n", ENOMEM);
+ return (1);
+ }
+
+ zi->attributes.name = strdup(name);
+ zi->attributes.health =
+ zpool_state_to_name(vs->vs_state, vs->vs_aux);
+ zi->attributes.status = zpool_import_status(pool, &msgid);
+ zi->attributes.guid = guid;
+ zi->attributes.size = 0;
+ zi->attributes.capacity = 0;
+ zi->attributes.version = 0;
+ zi->attributes.bootfs = NULL;
+
+ /* Import or not */
+ /* As this zpool was reported via import search it is an import */
+ zi->attributes.import = B_TRUE;
+
+
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ &child, &num_children) != 0) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_import_add():"
+ " failed to traverse vdev tree\n");
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ zi->attributes.targets =
+ calloc(num_children,
+ sizeof (td_zpool_target_t *));
+
+ if (zi->attributes.targets == NULL) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_import_add():"
+ " failed to allocate memory for toplevel targets,"
+ " err=%d\n", ENOMEM);
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ /* Process all normal non log/hole targets */
+ logcnt = 0;
+ targetcnt = 0;
+ for (cnt1 = 0; cnt1 < num_children; cnt1++) {
+ int errn = 0;
+ td_zpool_target_t *zt =
+ td_zpool_target_allocate(NULL, child[cnt1],
+ &logcnt, &errn, B_FALSE, B_FALSE);
+
+ if (errn != 0) {
+ /* Error already written via td_debug_print() */
+ /* So just return error from iter function */
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ if (zt != NULL) {
+ zi->attributes.targets[targetcnt++] = zt;
+ }
+ }
+ zi->attributes.num_targets = targetcnt;
+
+ /* Process all logs and add them as targets */
+ if (logcnt > 0) {
+ zi->attributes.num_logs = logcnt;
+ zi->attributes.logs =
+ calloc(zi->attributes.num_logs,
+ sizeof (td_zpool_target_t *));
+ if (zi->attributes.logs == NULL) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_import_add():"
+ " failed to allocate memory for zpool logs,"
+ " err=%d\n", ENOMEM);
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ targetcnt = 0;
+ for (cnt1 = 0; cnt1 < num_children; cnt1++) {
+ int errn = 0;
+ int dummycnt;
+ td_zpool_target_t *zt =
+ td_zpool_target_allocate(NULL, child[cnt1],
+ &dummycnt, &errn, B_TRUE, B_FALSE);
+
+ if (errn != 0) {
+ /* Error already written via td_debug_print() */
+ /* So just return error from iter function */
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ if (zt != NULL) {
+ zi->attributes.logs[targetcnt++] = zt;
+ }
+ }
+ } else {
+ zi->attributes.num_logs = 0;
+ zi->attributes.logs = NULL;
+ }
+
+
+ /* Process All Cache and add them as targets */
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+ &l2cache, &nl2cache) == 0) {
+ zi->attributes.num_l2cache = nl2cache;
+ zi->attributes.l2cache =
+ calloc(zi->attributes.num_l2cache,
+ sizeof (td_zpool_target_t *));
+ if (zi->attributes.l2cache == NULL) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_import_add():"
+ " failed to allocate memory for zpool cache,"
+ " err=%d\n", ENOMEM);
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ targetcnt = 0;
+ for (cnt1 = 0; cnt1 < zi->attributes.num_l2cache; cnt1++) {
+ int errn = 0;
+ int dummycnt;
+ td_zpool_target_t *zt =
+ td_zpool_target_allocate(NULL, l2cache[cnt1],
+ &dummycnt, &errn, B_FALSE, B_FALSE);
+
+ if (errn != 0) {
+ /* Error already written via td_debug_print() */
+ /* So just return error from iter function */
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ if (zt != NULL) {
+ zi->attributes.l2cache[targetcnt++] = zt;
+ }
+ }
+ } else {
+ zi->attributes.num_l2cache = 0;
+ zi->attributes.l2cache = NULL;
+ }
+
+ /* Process All spares and add them as targets */
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+ &spares, &nspares) == 0) {
+ zi->attributes.num_spares = nspares;
+ zi->attributes.spares =
+ calloc(zi->attributes.num_spares,
+ sizeof (td_zpool_target_t *));
+ if (zi->attributes.l2cache == NULL) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_import_add():"
+ " failed to allocate memory for zpool l2cache,"
+ " err=%d\n", ENOMEM);
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ targetcnt = 0;
+ for (cnt1 = 0; cnt1 < zi->attributes.num_spares; cnt1++) {
+ int errn = 0;
+ int dummycnt;
+ td_zpool_target_t *zt =
+ td_zpool_target_allocate(NULL, spares[cnt1],
+ &dummycnt, &errn, B_FALSE, B_TRUE);
+
+ if (errn != 0) {
+ /* Error already written via td_debug_print() */
+ /* So just return error from iter function */
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ if (zt != NULL) {
+ zi->attributes.spares[targetcnt++] = zt;
+ }
+ }
+ } else {
+ zi->attributes.num_spares = 0;
+ zi->attributes.spares = NULL;
+ }
+
+ td_zpool_info_list_add(&list, zi);
+ if (*zi_list == NULL) {
+ *zi_list = list;
+ }
+ return (0);
+}
+
+/*
+ * Function: td_zpool_import_find
+ *
+ * Description: Find all importable zpools currently not imported.
+ * Equivalent to calling CLI "zpool import" with no arguments.
+ *
+ * Parameters:
+ * libzfs_handle_t *zh : libzfs handle
+ *
+ * Returns:
+ * 0 : Success
+ * 1 : Fail
+ *
+ * Scope:
+ * Private
+ */
+static int
+td_zpool_import_find(libzfs_handle_t *zh, td_zpool_info_t **zi_list)
+{
+ char **searchdirs = NULL;
+ importargs_t idata = { 0 };
+ nvlist_t *nv_pools = NULL;
+ nvpair_t *elem;
+ nvlist_t *config;
+ uint64_t pool_state = -1ULL;
+
+ searchdirs = calloc(1, sizeof (char *));
+
+ if (searchdirs == NULL) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_import_find():"
+ " failed to allocate memory for import search path,"
+ " err=%d\n", ENOMEM);
+ return (1);
+ }
+
+ searchdirs[0] = "/dev/dsk";
+
+ idata.path = searchdirs;
+ idata.paths = 1;
+ idata.poolname = NULL;
+ idata.guid = 0;
+ idata.cachefile = NULL;
+
+ nv_pools = zpool_search_import(zh, &idata);
+
+ if (nv_pools != NULL) {
+ elem = NULL;
+ while ((elem = nvlist_next_nvpair(nv_pools, elem)) != NULL) {
+ if (nvpair_value_nvlist(elem, &config) != 0) {
+ td_debug_print(LS_DBGLVL_WARN,
+ "td_zpool_import_find():"
+ " nvpair_value_nvlist failed.\n");
+ printf("nvpair_valu_nvlist failed\n");
+ continue;
+ }
+ if (nvlist_lookup_uint64(config,
+ ZPOOL_CONFIG_POOL_STATE, &pool_state) != 0) {
+ td_debug_print(LS_DBGLVL_WARN,
+ "td_zpool_import_find():"
+ " failed to get pool state.\n");
+ printf("pool state failed\n");
+ continue;
+ }
+
+ if (pool_state == POOL_STATE_DESTROYED) {
+ printf("pool is destroyed\n");
+ td_debug_print(LS_DBGLVL_INFO,
+ "td_zpool_import_find():"
+ " Skipping destroyed pool.\n");
+ continue;
+ }
+
+ if (td_zpool_import_add(config, zi_list) != 0) {
+ free(searchdirs);
+ return (1);
+ }
+ }
+ }
+
+ free(searchdirs);
+ return (0);
+}
+
+/*
+ * Function: td_zpool_iter_callback
+ *
+ * Description: Callback triggered by zpool_iter(), called for
+ * each zpool discovered, pool is queried for various
+ * properties and vdev structure, and results are stored
+ * in internal linked list of td_zpool_info_t's.
+ *
+ * Parameters:
+ * zpool_handle_t *zlp : Current zpool handler
+ * void *data : List of discovered zpools
+ *
+ * Returns:
+ * 0 : Success
+ * 1 : Fail
+ *
+ * Scope:
+ * Private
+ */
+static int
+td_zpool_iter_callback(zpool_handle_t *zhp, void *data)
+{
+ td_zpool_info_t **_list = data;
+ td_zpool_info_t *list = *_list;
+ char prop_buf[ZFS_MAXPROPLEN];
+ td_zpool_info_t *zi = NULL;
+ char *status;
+ nvlist_t *config, *nvroot, **child;
+ int cnt1 = 0, logcnt = 0, targetcnt = 0;
+ uint_t vsc;
+ vdev_stat_t *vs;
+ nvlist_t **l2cache, **spares;
+ uint_t nl2cache, nspares;
+ uint32_t num_children = 0;
+
+ /* Construct td_zpool_info_t of attributes for this zpool */
+ zi = calloc(1, sizeof (td_zpool_info_t));
+ if (zi == NULL) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_iter_callback():"
+ " failed to allocate memory for zpool,"
+ " err=%d\n", ENOMEM);
+ return (1);
+ }
+
+ /* name */
+ zi->attributes.name = strdup(zpool_get_name(zhp));
+ if (zi->attributes.name == NULL) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_iter_callback():"
+ " failed to get pool name\n");
+ td_zpool_info_free(zi);
+ return (0);
+ }
+
+ /* Pool status */
+ zi->attributes.status = zpool_get_status(zhp, &status);
+
+ /* GUID */
+ zi->attributes.guid = zpool_get_prop_int(zhp, ZPOOL_PROP_GUID, NULL);
+
+ /* Health */
+ zpool_get_prop(zhp, ZPOOL_PROP_HEALTH, prop_buf, ZFS_MAXPROPLEN, NULL);
+ if (prop_buf == NULL) {
+ td_debug_print(LS_DBGLVL_WARN, "td_zpool_iter_callback():"
+ " failed to get health property for pool: %s\n",
+ zi->attributes.name);
+ zi->attributes.health = strdup("UNKNOWN");
+ } else {
+ zi->attributes.health = strdup(prop_buf);
+ }
+
+ /* Pool size */
+ zi->attributes.size =
+ zpool_get_prop_int(zhp, ZPOOL_PROP_SIZE, NULL);
+
+ /* Pool capacity */
+ zi->attributes.capacity =
+ zpool_get_prop_int(zhp, ZPOOL_PROP_CAPACITY, NULL);
+
+ /* Pool version */
+ zi->attributes.version =
+ zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
+
+ /* Import or not */
+ /* As this zpool was reported via zpool_iter, not an import */
+ zi->attributes.import = B_FALSE;
+
+ /* Get vdev configuration for this pool */
+ if ((config = zpool_get_config(zhp, NULL)) == NULL) {
+ td_debug_print(LS_DBGLVL_WARN, "td_zpool_iter_callback():"
+ " failed to get pool configuration for pool : %s\n",
+ zi->attributes.name);
+ td_debug_print(LS_DBGLVL_WARN,
+ "%d : %s\n", libzfs_errno(g_zfs),
+ libzfs_error_description(g_zfs));
+ goto add_pool;
+ }
+
+ /* Boot Filesystem */
+ zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, prop_buf, ZFS_MAXPROPLEN, NULL);
+ if (prop_buf == NULL) {
+ td_debug_print(LS_DBGLVL_WARN, "td_zpool_iter_callback():"
+ " failed to get boot filesystem property for pool: %s\n",
+ zi->attributes.name);
+ zi->attributes.bootfs = NULL;
+ } else {
+ zi->attributes.bootfs = strdup(prop_buf);
+ }
+
+ if (nvlist_lookup_nvlist(config,
+ ZPOOL_CONFIG_VDEV_TREE, &nvroot) != 0) {
+ td_debug_print(LS_DBGLVL_WARN, "td_zpool_iter_callback():"
+ " failed to get vdev tree\n");
+ goto add_pool;
+ }
+
+ if (nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
+ (uint64_t **)&vs, &vsc) != 0) {
+ td_debug_print(LS_DBGLVL_WARN, "td_zpool_iter_callback():"
+ " failed to get vdev stats\n");
+ goto add_pool;
+ }
+
+ /* State reported via VDEV_STATS is more accurate, replace */
+ free(zi->attributes.health);
+ zi->attributes.health =
+ zpool_state_to_name(vs->vs_state, vs->vs_aux);
+
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+ &child, &num_children) != 0) {
+ td_debug_print(LS_DBGLVL_WARN, "td_zpool_iter_callback():"
+ " failed to traverse vdev tree\n");
+ goto add_pool;
+ }
+
+ zi->attributes.targets =
+ calloc(num_children,
+ sizeof (td_zpool_target_t *));
+
+ if (zi->attributes.targets == NULL) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_iter_callback():"
+ " failed to allocate memory for toplevel targets,"
+ " err=%d\n", ENOMEM);
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ /* Process all normal non log/hole targets */
+ logcnt = 0;
+ targetcnt = 0;
+ for (cnt1 = 0; cnt1 < num_children; cnt1++) {
+ int errn = 0;
+ td_zpool_target_t *zt =
+ td_zpool_target_allocate(zhp, child[cnt1],
+ &logcnt, &errn, B_FALSE, B_FALSE);
+
+ if (errn != 0) {
+ /* Error already written via td_debug_print() */
+ /* So just return error from iter function */
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ if (zt != NULL) {
+ zi->attributes.targets[targetcnt++] = zt;
+ }
+ }
+ zi->attributes.num_targets = (uint32_t)targetcnt;
+
+ /* Process all logs and add them as targets */
+ if (logcnt > 0) {
+ zi->attributes.num_logs = logcnt;
+ zi->attributes.logs =
+ calloc(zi->attributes.num_logs,
+ sizeof (td_zpool_target_t *));
+ if (zi->attributes.l2cache == NULL) {
+ td_debug_print(LS_DBGLVL_ERR,
+ "td_zpool_iter_callback():"
+ " failed to allocate memory for zpool logs,"
+ " err=%d\n", ENOMEM);
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ targetcnt = 0;
+ for (cnt1 = 0; cnt1 < num_children; cnt1++) {
+ int errn = 0;
+ int dummycnt;
+ td_zpool_target_t *zt =
+ td_zpool_target_allocate(zhp, child[cnt1],
+ &dummycnt, &errn, B_TRUE, B_FALSE);
+
+ if (errn != 0) {
+ /* Error already written via td_debug_print() */
+ /* So just return error from iter function */
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ if (zt != NULL) {
+ zi->attributes.logs[targetcnt++] = zt;
+ }
+ }
+ } else {
+ zi->attributes.num_logs = 0;
+ zi->attributes.logs = NULL;
+ }
+
+
+ /* Process All Cache and add them as targets */
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+ &l2cache, &nl2cache) == 0) {
+ zi->attributes.num_l2cache = nl2cache;
+ zi->attributes.l2cache =
+ calloc(zi->attributes.num_l2cache,
+ sizeof (td_zpool_target_t *));
+ if (zi->attributes.l2cache == NULL) {
+ td_debug_print(LS_DBGLVL_ERR,
+ "td_zpool_iter_callback():"
+ " failed to allocate memory for zpool cache,"
+ " err=%d\n", ENOMEM);
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ targetcnt = 0;
+ for (cnt1 = 0; cnt1 < zi->attributes.num_l2cache; cnt1++) {
+ int errn = 0;
+ int dummycnt;
+ td_zpool_target_t *zt =
+ td_zpool_target_allocate(zhp, l2cache[cnt1],
+ &dummycnt, &errn, B_FALSE, B_FALSE);
+
+ if (errn != 0) {
+ /* Error already written via td_debug_print() */
+ /* So just return error from iter function */
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ if (zt != NULL) {
+ zi->attributes.l2cache[targetcnt++] = zt;
+ }
+ }
+ } else {
+ zi->attributes.num_l2cache = 0;
+ zi->attributes.l2cache = NULL;
+ }
+
+ /* Process All spares and add them as targets */
+ if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+ &spares, &nspares) == 0) {
+ zi->attributes.num_spares = nspares;
+ zi->attributes.spares =
+ calloc(zi->attributes.num_spares,
+ sizeof (td_zpool_target_t *));
+ if (zi->attributes.l2cache == NULL) {
+ td_debug_print(LS_DBGLVL_ERR,
+ "td_zpool_iter_callback():"
+ " failed to allocate memory for zpool spares,"
+ " err=%d\n", ENOMEM);
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ targetcnt = 0;
+ for (cnt1 = 0; cnt1 < zi->attributes.num_spares; cnt1++) {
+ int errn = 0;
+ int dummycnt;
+ td_zpool_target_t *zt =
+ td_zpool_target_allocate(zhp, spares[cnt1],
+ &dummycnt, &errn, B_FALSE, B_TRUE);
+
+ if (errn != 0) {
+ /* Error already written via td_debug_print() */
+ /* So just return error from iter function */
+ td_zpool_info_free(zi);
+ return (1);
+ }
+
+ if (zt != NULL) {
+ zi->attributes.spares[targetcnt++] = zt;
+ }
+ }
+ } else {
+ zi->attributes.num_spares = 0;
+ zi->attributes.spares = NULL;
+ }
+
+add_pool:
+ td_zpool_info_list_add(&list, zi);
+ if (*_list == NULL) {
+ *_list = list;
+ }
+ zpool_close(zhp);
+ return (0);
+}
+
+/*
+ * Function: td_zpool_info_list_add
+ *
+ * Description: Adds a new td_zpool_info to global linked list of discovered
+ * zpools.
+ *
+ * Parameters:
+ * td_zpool_info_t **list : List to add new item to
+ * td_zpool_info_t *new : New zpool to add to linked list
+ *
+ * Returns:
+ * void
+ *
+ * Scope:
+ * Private
+ */
+static void
+td_zpool_info_list_add(td_zpool_info_t **list, td_zpool_info_t *new)
+{
+ td_zpool_info_t *cur;
+
+ if (new == NULL)
+ return;
+
+ if (*list == NULL) {
+ /* First item on list */
+ *list = new;
+ } else {
+ /* Traverse to end of list and add item */
+ for (cur = *list; cur->next != NULL; cur = cur->next)
+ ;
+
+ /* Add new td_zpool_info to end of list */
+ cur->next = new;
+ }
+}
+
+
+/*
+ * Function: td_zpool_target_free
+ *
+ * Description: Frees memory allocated for td_zpool_target_t
+ *
+ * Parameters:
+ * td_zpool_target_t *zt : td_zpool_target_t to be freed
+ *
+ * Returns:
+ * void
+ *
+ * Scope:
+ * Private
+ */
+static void
+td_zpool_target_free(td_zpool_target_t *zt)
+{
+ int i = 0;
+
+ if (zt == NULL) {
+ return;
+ }
+
+ for (i = 0; i < zt->num_targets; i++) {
+ td_zpool_target_free(zt->targets[i]);
+ }
+ free(zt->targets);
+ free(zt->name);
+ free(zt->health);
+ free(zt);
+}
+
+/*
+ * Function: td_zpool_info_free
+ *
+ * Description: Frees memory allocated for td_zpool_info
+ *
+ * Parameters:
+ * td_zpool_info_t *zi : td_zpool_info_t to be freed
+ *
+ * Returns:
+ * void
+ *
+ * Scope:
+ * Private
+ */
+static void
+td_zpool_info_free(td_zpool_info_t *zi)
+{
+ int i = 0;
+
+ if (zi == NULL) {
+ return;
+ }
+
+ /* Free all targets */
+ for (i = 0; i < zi->attributes.num_targets; i++) {
+ td_zpool_target_free(zi->attributes.targets[i]);
+ }
+ free(zi->attributes.targets);
+
+ /* Free all logs */
+ for (i = 0; i < zi->attributes.num_logs; i++) {
+ td_zpool_target_free(zi->attributes.logs[i]);
+ }
+ free(zi->attributes.logs);
+
+ /* Free all l2cache */
+ for (i = 0; i < zi->attributes.num_l2cache; i++) {
+ td_zpool_target_free(zi->attributes.l2cache[i]);
+ }
+ free(zi->attributes.l2cache);
+
+ /* Free all spares */
+ for (i = 0; i < zi->attributes.num_spares; i++) {
+ td_zpool_target_free(zi->attributes.spares[i]);
+ }
+ free(zi->attributes.spares);
+
+ free(zi->attributes.name);
+ free(zi->attributes.health);
+ free(zi->attributes.bootfs);
+ free(zi);
+}
+/*
+ * Function: free_nvlist_array
+ *
+ * Description: Frees all elements of an nvlist array and the
+ * main array pointer itself.
+ *
+ * Parameters:
+ * nvlist **nv : nvlist_t array to free
+ *
+ * Returns:
+ * void
+ *
+ * Scope:
+ * Private
+ */
+static void
+free_nvlist_array(nvlist_t **nv, int count)
+{
+ int i = 0;
+
+ if (nv == NULL) {
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ nvlist_free(nv[i]);
+ }
+ free(nv);
+}
+
+/*
+ * Function: td_zpool_allocate_target_nvlist
+ *
+ * Description: Allocates nvlist for this target.
+ * potentially called recursively to allocate targets
+ * of this target.
+ *
+ * Parameters:
+ * td_zpool_target_t **zts : targets array
+ * uint32_t num_nvtargets : Number of targets
+ * nvlist_t *nvtarget : top level nvlist
+ * const char *attr_name : NV attribute name
+ * const char *attr_num : NV attribute number
+ * int *errn : Error number to return
+ *
+ * Returns:
+ * errn : sets to error value;
+ *
+ * Scope:
+ * Private
+ */
+static void
+td_zpool_allocate_target_nvlist(td_zpool_target_t **zts,
+ uint32_t num_nvtargets,
+ nvlist_t *nvtarget,
+ const char *attr_name,
+ const char *attr_num,
+ int *errn)
+{
+ int cnt1 = 0;
+ uint32_t num_targets = 0;
+ nvlist_t **targets;
+ nvlist_t *tmptarget = NULL;
+
+ if (num_nvtargets == 0) {
+ return;
+ }
+
+ /* Generate nvlist array of each target grouping */
+ targets = calloc(num_nvtargets, sizeof (nvlist_t *));
+ if (targets == NULL) {
+ td_debug_print(LS_DBGLVL_ERR,
+ "td_zpool_allocate_target_nvlist():"
+ " Failed to allocate target nvlist.\n");
+ *errn = ENOMEM;
+ return;
+ }
+
+ num_targets = 0;
+ for (cnt1 = 0; cnt1 < num_nvtargets; cnt1++) {
+ tmptarget = allocate_target_nvlist(zts[cnt1], errn);
+
+ if (*errn != 0) {
+ free_nvlist_array(targets, cnt1);
+ return;
+ }
+ targets[num_targets++] = tmptarget;
+ }
+
+ /* Add TD_ZPOOL_ATTR_NUM_TARGETS attribute */
+ if (nvlist_add_uint32(nvtarget,
+ attr_num, num_targets) != 0) {
+ td_debug_print(LS_DBGLVL_ERR,
+ "td_zpool_allocate_target_nvlist():"
+ " Failed to add number of targets to target nvlist.\n");
+ free_nvlist_array(targets, cnt1);
+ *errn = ENOMEM;
+ return;
+ }
+
+ /* Add TD_ZPOOL_ATTR_TARGETS attribute */
+ if (nvlist_add_nvlist_array(nvtarget,
+ attr_name, targets,
+ num_targets) != 0) {
+ td_debug_print(LS_DBGLVL_ERR,
+ "td_zpool_allocate_target_nvlist():"
+ " Failed to add targets to target nvlist.\n");
+ free_nvlist_array(targets, cnt1);
+ *errn = ENOMEM;
+ return;
+ }
+
+ /* Free up targets nvlists */
+ free_nvlist_array(targets, num_targets);
+}
+
+/*
+ * Function: allocate_target_nvlist
+ *
+ * Description: Allocates nvlist for this target.
+ * potentially called recursively to allocate targets
+ * of this target.
+ *
+ * Parameters:
+ * td_zpool_target_t *zt : td_zpool_target_t to allocate
+ * int *errn : Error number to return
+ *
+ * Returns:
+ * nvlist_t * : nvpair list of attributes
+ * errn : sets to error value;
+ *
+ * Scope:
+ * Private
+ */
+static nvlist_t *
+allocate_target_nvlist(td_zpool_target_t *zt, int *errn)
+{
+ nvlist_t *nvtarget = NULL;
+
+ if (zt == NULL) {
+ return (NULL);
+ }
+
+ /* Allocate NV_LIST for this target */
+ if (nvlist_alloc(&nvtarget, NV_UNIQUE_NAME, 0) != 0) {
+ td_debug_print(LS_DBGLVL_ERR, "allocate_target_nvlist():"
+ " Failed to allocate target nvlist.\n");
+ *errn = ENOMEM;
+ return (NULL);
+ }
+
+ /* For each target build up nvlist */
+ /* Add TD_ZPOOL_ATTR_TARGET_NAME attribute */
+ if (nvlist_add_string(nvtarget,
+ TD_ZPOOL_ATTR_TARGET_NAME, zt->name) != 0) {
+ td_debug_print(LS_DBGLVL_ERR, "allocate_target_nvlist():"
+ " Failed to add target name to nvlist.\n");
+ nvlist_free(nvtarget);
+ *errn = ENOMEM;
+ return (NULL);
+ }
+
+ /* Add TD_ZPOOL_ATTR_TARGET_HEALTH attribute */
+ if (nvlist_add_string(nvtarget,
+ TD_ZPOOL_ATTR_TARGET_HEALTH, zt->health) != 0) {
+ td_debug_print(LS_DBGLVL_ERR, "allocate_target_nvlist():"
+ " Failed to add target health to nvlist.\n");
+ nvlist_free(nvtarget);
+ *errn = ENOMEM;
+ return (NULL);
+ }
+
+ /* Add TD_ZPOOL_ATTR_TARGET_READ_ERRORS attribute */
+ if (nvlist_add_uint64(nvtarget,
+ TD_ZPOOL_ATTR_TARGET_READ_ERRORS, zt->read_errors) != 0) {
+ td_debug_print(LS_DBGLVL_ERR, "allocate_target_nvlist():"
+ " Failed to add target read errors to nvlist.\n");
+ nvlist_free(nvtarget);
+ *errn = ENOMEM;
+ return (NULL);
+ }
+
+ /* Add TD_ZPOOL_ATTR_TARGET_WRITE_ERRORS attribute */
+ if (nvlist_add_uint64(nvtarget,
+ TD_ZPOOL_ATTR_TARGET_WRITE_ERRORS, zt->write_errors) != 0) {
+ td_debug_print(LS_DBGLVL_ERR, "allocate_target_nvlist():"
+ " Failed to add target write errors to nvlist.\n");
+ nvlist_free(nvtarget);
+ *errn = ENOMEM;
+ return (NULL);
+ }
+
+ /* Add TD_ZPOOL_ATTR_TARGET_CHECKSUM_ERRORS attribute */
+ if (nvlist_add_uint64(nvtarget,
+ TD_ZPOOL_ATTR_TARGET_CHECKSUM_ERRORS,
+ zt->checksum_errors) != 0) {
+ td_debug_print(LS_DBGLVL_ERR, "allocate_target_nvlist():"
+ " Failed to add target checksum errors to nvlist.\n");
+ nvlist_free(nvtarget);
+ *errn = ENOMEM;
+ return (NULL);
+ }
+
+ td_zpool_allocate_target_nvlist(zt->targets,
+ zt->num_targets, nvtarget, TD_ZPOOL_ATTR_TARGETS,
+ TD_ZPOOL_ATTR_NUM_TARGETS, errn);
+ if (*errn != 0) {
+ td_debug_print(LS_DBGLVL_ERR, "allocate_target_nvlist():"
+ " Failed to add targets to nvlist.\n");
+ nvlist_free(nvtarget);
+ return (NULL);
+ }
+
+ return (nvtarget);
+}
+
+/*
+ * Function: td_zpool_get_attributes
+ *
+ * Description: Gets the attributes of a specific Zpool.
+ * nvlist_t is populated with all the attributes for this
+ * td_zpool_info_t and returned.
+ *
+ * Parameters:
+ * td_zpool_info_t *zi : zpool to get attributes for
+ * int *errn : Error number to return
+ *
+ * Returns:
+ * nvlist_t * : nvpair list of attributes for zpool
+ *
+ * Scope:
+ * Private
+ */
+static nvlist_t *
+td_zpool_get_attributes(td_zpool_info_t *zi, int *errn)
+{
+ nvlist_t *attrs = NULL;
+
+ if (zi == NULL) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_get_attributes():"
+ " zpool handle not set.\n");
+ *errn = ENODEV;
+ return (NULL);
+ }
+
+ /* Allocate NV_LIST */
+ if (nvlist_alloc(&attrs, NV_UNIQUE_NAME, 0) != 0) {
+ *errn = ENOMEM;
+ return (NULL);
+ }
+
+ /* Add TD_ZPOOL_ATTR_NAME attribute */
+ if (nvlist_add_string(attrs, TD_ZPOOL_ATTR_NAME,
+ zi->attributes.name) != 0) {
+ *errn = ENOMEM;
+ nvlist_free(attrs);
+ return (NULL);
+ }
+
+ /* Add TD_ZPOOL_ATTR_HEALTH attribute */
+ if (nvlist_add_string(attrs, TD_ZPOOL_ATTR_HEALTH,
+ zi->attributes.health) != 0) {
+ *errn = ENOMEM;
+ nvlist_free(attrs);
+ return (NULL);
+ }
+
+ /* Add TD_ZPOOL_ATTR_STATUS attribute */
+ if (nvlist_add_uint32(attrs, TD_ZPOOL_ATTR_STATUS,
+ zi->attributes.status) != 0) {
+ *errn = ENOMEM;
+ nvlist_free(attrs);
+ return (NULL);
+ }
+
+ /* Add TD_ZPOOL_ATTR_GUID attribute */
+ if (nvlist_add_uint64(attrs, TD_ZPOOL_ATTR_GUID,
+ zi->attributes.guid) != 0) {
+ *errn = ENOMEM;
+ nvlist_free(attrs);
+ return (NULL);
+ }
+
+ /* Add TD_ZPOOL_ATTR_SIZE attribute */
+ if (nvlist_add_uint64(attrs, TD_ZPOOL_ATTR_SIZE,
+ zi->attributes.size) != 0) {
+ *errn = ENOMEM;
+ nvlist_free(attrs);
+ return (NULL);
+ }
+
+ /* Add TD_ZPOOL_ATTR_CAPACITY attribute */
+ if (nvlist_add_uint64(attrs, TD_ZPOOL_ATTR_CAPACITY,
+ zi->attributes.capacity) != 0) {
+ *errn = ENOMEM;
+ nvlist_free(attrs);
+ return (NULL);
+ }
+
+ /* Add TD_ZPOOL_ATTR_VERSION attribute */
+ if (nvlist_add_uint32(attrs, TD_ZPOOL_ATTR_VERSION,
+ zi->attributes.version) != 0) {
+ *errn = ENOMEM;
+ nvlist_free(attrs);
+ return (NULL);
+ }
+
+ /* Add TD_ZPOOL_ATTR_BOOTFS attribute */
+ if (zi->attributes.bootfs != NULL) {
+ if (nvlist_add_string(attrs, TD_ZPOOL_ATTR_BOOTFS,
+ zi->attributes.bootfs) != 0) {
+ *errn = ENOMEM;
+ nvlist_free(attrs);
+ return (NULL);
+ }
+ }
+
+ /* Add TD_ZPOOL_ATTR_IMPORT attribute */
+ if (nvlist_add_boolean_value(attrs, TD_ZPOOL_ATTR_IMPORT,
+ zi->attributes.import) != 0) {
+ *errn = ENOMEM;
+ nvlist_free(attrs);
+ return (NULL);
+ }
+
+ /* Generate nvlist array of each target grouping */
+ td_zpool_allocate_target_nvlist(zi->attributes.targets,
+ zi->attributes.num_targets, attrs, TD_ZPOOL_ATTR_TARGETS,
+ TD_ZPOOL_ATTR_NUM_TARGETS, errn);
+ if (*errn != 0) {
+ nvlist_free(attrs);
+ return (NULL);
+ }
+
+ /* Process logs */
+ td_zpool_allocate_target_nvlist(zi->attributes.logs,
+ zi->attributes.num_logs, attrs, TD_ZPOOL_ATTR_LOGS,
+ TD_ZPOOL_ATTR_NUM_LOGS, errn);
+ if (*errn != 0) {
+ nvlist_free(attrs);
+ return (NULL);
+ }
+
+
+ /* Process l2cache */
+ td_zpool_allocate_target_nvlist(zi->attributes.l2cache,
+ zi->attributes.num_l2cache, attrs, TD_ZPOOL_ATTR_L2CACHE,
+ TD_ZPOOL_ATTR_NUM_L2CACHE,
+ errn);
+ if (*errn != 0) {
+ nvlist_free(attrs);
+ return (NULL);
+ }
+
+ /* Process spares */
+ td_zpool_allocate_target_nvlist(zi->attributes.spares,
+ zi->attributes.num_spares, attrs, TD_ZPOOL_ATTR_SPARES,
+ TD_ZPOOL_ATTR_NUM_SPARES,
+ errn);
+ if (*errn != 0) {
+ nvlist_free(attrs);
+ return (NULL);
+ }
+
+ return (attrs);
+}
+
+/*
+ * Function: td_zpool_target_print
+ *
+ * Description: Print contents of td_zpool_target_t
+ *
+ * Parameters:
+ * td_zpool_target_t *zt : zpool_target to print
+ * int depth : depth nesting to print
+ * boolean_t is_spare : Is spare device
+ *
+ * Returns:
+ * void
+ *
+ * Scope:
+ * Private
+ */
+static void
+td_zpool_target_print(td_zpool_target_t *zt,
+ int depth,
+ boolean_t is_spare)
+{
+ int i = 0;
+
+ if (zt == NULL) {
+ return;
+ }
+
+ if (is_spare) {
+ td_debug_print(LS_DBGLVL_INFO,
+ " | %*s%-*s| "
+ "%9s| | %4s| %5s| %3s|\n",
+ depth, "", 31 - depth,
+ zt->name, zt->health, "", "", "");
+ } else {
+ td_debug_print(LS_DBGLVL_INFO,
+ " | %*s%-*s| "
+ "%9s| | %4llu| %5llu| %3llu|\n",
+ depth, "", 31 - depth,
+ zt->name, zt->health,
+ zt->read_errors, zt->write_errors,
+ zt->checksum_errors);
+ }
+
+ for (i = 0; i < zt->num_targets; i++) {
+ td_zpool_target_print(zt->targets[i], depth+2, is_spare);
+ }
+}
+
+/*
+ * Function: td_zpool_info_print
+ *
+ * Description: Print contents of td_zpool_info_t
+ *
+ * Parameters:
+ * td_zpool_info_t *zi : zpool to print
+ * int num : zpool count printed
+ *
+ * Returns:
+ * void
+ *
+ * Scope:
+ * Private
+ */
+static void
+td_zpool_info_print(td_zpool_info_t *zi, int num)
+{
+ int i = 0;
+ double size_mb = 0;
+ double size_gb = 0;
+
+ size_mb = BYTES_TO_MB(zi->attributes.size);
+ if (size_mb > MB_IN_GB) {
+ size_gb = MB_TO_GB(size_mb);
+ size_mb = 0;
+ }
+
+ td_debug_print(LS_DBGLVL_INFO, " %3d | %-33s| "
+ "%9s| %7.2lf%c| %4llu| %5d| %2d|\n", num, zi->attributes.name,
+ zi->attributes.health,
+ size_mb > 0 ? size_mb : size_gb,
+ size_mb > 0 ? 'M' : 'G',
+ zi->attributes.capacity,
+ zi->attributes.status,
+ zi->attributes.version);
+
+ td_debug_print(LS_DBGLVL_INFO, " %3s | %33llu| "
+ "%9s| %8s| %4s| %5s| %2s|\n", "",
+ zi->attributes.guid, "", "", "", "", "", "");
+
+ if (zi->attributes.bootfs != NULL) {
+ td_debug_print(LS_DBGLVL_INFO, " %3s | %33s| "
+ "%9s| %8s| %4s| %5s| %2s|\n", "",
+ zi->attributes.bootfs, "", "", "", "", "", "");
+ }
+
+ if (zi->attributes.import) {
+ td_debug_print(LS_DBGLVL_INFO, " %3s | %33s| "
+ "%9s| %8s| %4s| %5s| %2s|\n", "",
+ "Importable pool", "", "", "", "", "", "");
+ }
+
+ for (i = 0; i < zi->attributes.num_targets; i++) {
+ td_zpool_target_print(zi->attributes.targets[i], 0, B_FALSE);
+ }
+
+ if (zi->attributes.num_logs > 0) {
+ td_debug_print(LS_DBGLVL_INFO, " %3s | %-33s| "
+ "%9s| %8s| %4s| %5s| %2s|\n", "", "logs",
+ "", "", "", "", "");
+ for (i = 0; i < zi->attributes.num_logs; i++) {
+ td_zpool_target_print(zi->attributes.logs[i],
+ 0, B_FALSE);
+ }
+ }
+
+ if (zi->attributes.num_l2cache > 0) {
+ td_debug_print(LS_DBGLVL_INFO, " %3s | %-33s| "
+ "%9s| %8s| %4s| %5s| %2s|\n", "", "cache",
+ "", "", "", "", "");
+ for (i = 0; i < zi->attributes.num_l2cache; i++) {
+ td_zpool_target_print(zi->attributes.l2cache[i],
+ 0, B_FALSE);
+ }
+ }
+
+ if (zi->attributes.num_spares > 0) {
+ td_debug_print(LS_DBGLVL_INFO, " %3s | %-33s| "
+ "%9s| %8s| %4s| %5s| %2s|\n", "", "spares",
+ "", "", "", "", "");
+ for (i = 0; i < zi->attributes.num_spares; i++) {
+ td_zpool_target_print(zi->attributes.spares[i],
+ 0, B_TRUE);
+ }
+ }
+}
+
+/*
+ * Function: td_zpool_info_print_ptrs
+ *
+ * Description:
+ * Print all td_zpool_info_t's in ptr array
+ *
+ * Parameters:
+ * td_zpool_info_t **ptrs : Array of pointers to print from
+ *
+ * Returns:
+ * void
+ *
+ * Scope:
+ * Private
+ */
+static void
+td_zpool_info_print_ptrs(td_zpool_info_t **ptrs)
+{
+ int i = 0;
+ int num = 0;
+
+ if (ptrs == NULL || ptrs[0] == NULL) {
+ td_debug_print(LS_DBGLVL_INFO,
+ "zpool ptrs array is empty.\n");
+ return;
+ }
+
+ for (i = 0; ptrs[i]; i++) {
+ td_zpool_info_print(ptrs[i], ++num);
+ }
+}
+
+/*
+ * Function: td_zpool_info_print_list
+ *
+ * Description: Runs through the linked list of zpool attributes printing all
+ * the stored information.
+ *
+ * Parameters:
+ * td_zpool_info_t start : Linked list of zpools to print
+ *
+ * Returns:
+ * NULL
+ *
+ * Scope:
+ * Private
+ */
+static void
+td_zpool_info_print_list(td_zpool_info_t *start)
+{
+ int num = 0;
+ td_zpool_info_t *cur = start;
+
+ if (cur == NULL) {
+ td_debug_print(LS_DBGLVL_INFO,
+ "zpool list is empty.\n");
+ return;
+ }
+
+ while (cur != NULL) {
+ td_zpool_info_print(cur, ++num);
+ cur = cur->next;
+ }
+}
+
+/*
+ * Function: td_zpool_info_ptrs_to_ddm_handle
+ *
+ * Description: Convert array of td_zpool_info_t ptrs to an
+ * array of ddm_handle_t's for returning to TD
+ *
+ * Parameters:
+ * td_zpool_info_t **ptrs : Array of td_zpool_info_t pointers
+ *
+ * Returns:
+ * ddm_handle_t * : Array of ddm_handle_t pointers
+ *
+ * Scope:
+ * Private
+ */
+static ddm_handle_t *
+td_zpool_info_ptrs_to_ddm_handle(td_zpool_info_t **ptrs)
+{
+#ifdef _LP64
+ return ((ddm_handle_t *)ptrs);
+#else
+ /* convert the 32 bit ptrs to the 64 bit descriptors */
+ int cnt;
+ int i;
+ ddm_handle_t *dh;
+
+ if (ptrs == NULL) {
+ td_debug_print(LS_DBGLVL_WARN,
+ "td_zpool_info_ptrs_to_ddm_handle():"
+ " zpool ptr array NULL cannot convert to ddm_handle_t\n");
+ return (NULL);
+ }
+
+ for (cnt = 0; ptrs[cnt]; cnt++)
+ ;
+
+ dh = (ddm_handle_t *)calloc(cnt + 1, sizeof (ddm_handle_t));
+ if (dh == NULL) {
+ td_debug_print(LS_DBGLVL_ERR,
+ "td_zpool_info_ptrs_to_ddm_handle():"
+ " Failed to allocate memory for ddm_handle_t array\n");
+ return (NULL);
+ }
+
+ for (i = 0; ptrs[i]; i++) {
+ dh[i] = (uintptr_t)ptrs[i];
+ }
+
+ return (dh);
+#endif
+}
+
+/*
+ * Function: td_zpool_info_get_ptrs
+ *
+ * Description: Take a linked list of zpools and generate an array
+ * of pointers for each element in the list.
+ *
+ * Parameters:
+ * td_zpool_info_t * : Linked list of zpools
+ * int *nzpools : Num Zpools discovered
+ *
+ * Returns:
+ * td_zpool_info_t ** : Array of td_zpool_info_t pointers
+ * int *nzpools : Number of zpools discovered
+ *
+ * Scope:
+ * Private
+ */
+static td_zpool_info_t **
+td_zpool_info_get_ptrs(td_zpool_info_t *zpools_list, int *nzpools)
+{
+ td_zpool_info_t **ptrs;
+ td_zpool_info_t *cur;
+ int pos = 0;
+ int zpoolcnt = 0;
+
+ for (zpoolcnt = 0, cur = zpools_list;
+ cur != NULL;
+ cur = cur->next)
+ zpoolcnt++;
+
+ /* Set return paramater for number of zpools found */
+ if (nzpools != NULL)
+ *nzpools = zpoolcnt;
+
+ ptrs = (td_zpool_info_t **)
+ calloc(zpoolcnt + 1, sizeof (td_zpool_info_t *));
+ if (ptrs == NULL) {
+ td_debug_print(LS_DBGLVL_ERR, "td_zpool_info_get_ptrs():"
+ " Failed to allocate memory for zpool ptr array\n");
+ return (NULL);
+ }
+
+ for (pos = 0, cur = zpools_list; cur != NULL; cur = cur->next) {
+ ptrs[pos++] = cur;
+ }
+
+ return (ptrs);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libtd/td_zpool.h Thu Nov 04 10:08:30 2010 +0000
@@ -0,0 +1,107 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _TD_ZPOOL_H
+#define _TD_ZPOOL_H
+
+/*
+ * Module: td_zpool.h
+ * Group:
+ * Description: This module contains the Target Discovery ZFS Pool
+ * module data structures, constants, and function
+ * prototypes.
+ */
+
+#include <ctype.h>
+#include <libzfs.h>
+#include <math.h>
+#include <sys/types.h>
+#include <sys/nvpair.h>
+
+#include "td_api.h"
+#include "td_dd.h"
+#include "ls_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* type definition / macros */
+#define MB_IN_GB 1024
+#define BYTES_TO_MB(size) ((size) / (MB_IN_GB * MB_IN_GB))
+#define ONE_DECIMAL(val) ((round((val) * 10)) / 10.0)
+#define MB_TO_GB(size_mb) ONE_DECIMAL((size_mb) / MB_IN_GB)
+
+/* zpool targets */
+typedef struct td_zpool_target {
+ char *name;
+ char *health;
+ uint64_t read_errors;
+ uint64_t write_errors;
+ uint64_t checksum_errors;
+ uint32_t num_targets;
+ struct td_zpool_target **targets;
+} td_zpool_target_t;
+
+/*
+ * Structure for zpool attributes.
+ * Used for zpool_iter callback data.
+ */
+typedef struct td_zpool_attributes {
+ char *name;
+ char *health;
+ zpool_status_t status;
+ uint64_t guid;
+ uint64_t size; /* Size in Bytes */
+ uint64_t capacity;
+ uint32_t version;
+ boolean_t import;
+ char *bootfs;
+ uint32_t num_targets;
+ td_zpool_target_t **targets;
+ uint32_t num_logs;
+ td_zpool_target_t **logs;
+ uint32_t num_spares;
+ td_zpool_target_t **spares;
+ uint32_t num_l2cache;
+ td_zpool_target_t **l2cache;
+} td_zpool_attributes_t;
+
+/* Linked list of zpool attributes */
+typedef struct td_zpool_info {
+ td_zpool_attributes_t attributes;
+ struct td_zpool_info *next;
+} td_zpool_info_t;
+
+/* function prototypes */
+extern ddm_handle_t *ddm_get_zpools(int *nzpools);
+extern void ddm_free_zpool_list(ddm_handle_t *dh);
+extern nvlist_t *ddm_get_zpool_attributes(ddm_handle_t zpool);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TD_ZPOOL_H */
--- a/usr/src/lib/libtd/test_td.c Tue Nov 02 18:25:00 2010 +0100
+++ b/usr/src/lib/libtd/test_td.c Thu Nov 04 10:08:30 2010 +0000
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <assert.h>
@@ -41,6 +40,7 @@
#include <sys/nvpair.h>
#include <td_dd.h>
#include <td_api.h>
+#include <td_zpool.h>
#include <ls_api.h>
@@ -55,7 +55,8 @@
REPORT_DISK,
REPORT_PART,
REPORT_SLICE,
- REPORT_OS
+ REPORT_OS,
+ REPORT_ZPOOL
} rep_object_t;
/*
@@ -193,7 +194,7 @@
/* " name| idx| flg| tag| 1st block|#of blocks|size [MB]| " */
" - | - | - | - | - | - | - |"
/* " inuse by| inuse| " */
- " - | - |\n"
+ " - | - |\n"
}
};
@@ -227,6 +228,33 @@
},
};
+static const char *report_zpool[REPORT_PART_END][REPORT_VERB_END] = {
+/* header */
+{
+ "--------------------------------------------------------------------------------\n"
+ " num | name/guid/bootfs/import| health| size| cap%| state| ver|\n"
+ "--------------------------------------------------------------------------------\n",
+
+ "--------------------------------------------------------------------------------\n"
+ " num | name/guid/bootfs/import| health| size| cap%| state| ver|\n"
+ "--------------------------------------------------------------------------------\n",
+},
+
+/* footer */
+{
+ "--------------------------------------------------------------------------------\n",
+ "--------------------------------------------------------------------------------\n",
+},
+
+/* zpool instance w/o attributes */
+{
+/* " num | name/guid/bootfs/import| health| size| cap%| state| ver|\n" */
+ " | | | | | | |\n",
+
+/* " num | name/guid/bootfs/import| health| size| cap%| state| ver|\n" */
+ " | | | | | | |\n",
+},
+};
/* local variables */
static char *root_slice_name = "";
@@ -240,10 +268,11 @@
/* discovery of fdisk partitions is not supported on Sparc */
#ifdef sparc
- (void) printf("usage: test_dd [-x level] [-v] [-d] [-s all]\n");
+ (void) printf("usage: test_dd [-x level] [-v] [-d] [-s all]"
+ "[-o all] [-z all]\n");
#else
(void) printf("usage: test_dd [-x level] [-v] [-d] [-p all]"
- "[-s all]\n");
+ "[-o all] [-z all] [-s all]\n");
#endif
}
@@ -269,6 +298,10 @@
case REPORT_OS:
(void) printf("%s", report_os[part][verb]);
break;
+
+ case REPORT_ZPOOL:
+ (void) printf("%s", report_zpool[part][verb]);
+ break;
}
}
@@ -869,6 +902,362 @@
}
/*
+ * td_zpool_show_target()
+ */
+static void
+td_zpool_show_target(nvlist_t *target,
+ int depth,
+ boolean_t is_spare)
+{
+ nvlist_t **targets;
+ int cnt1 = 0;
+ char *str;
+ uint64_t ui64;
+ uint32_t ui32;
+ uint_t ret;
+
+ if (target == NULL) {
+ return;
+ }
+
+ if (nvlist_lookup_string(target,
+ TD_ZPOOL_ATTR_TARGET_NAME, &str) != 0) {
+ (void) printf(
+ " | %*s%-*s",
+ depth, "", 31 - depth, "- ");
+ } else {
+ (void) printf(
+ " | %*s%-*s",
+ depth, "", 31 - depth, str);
+ }
+
+ if (nvlist_lookup_string(target,
+ TD_ZPOOL_ATTR_TARGET_HEALTH, &str) != 0) {
+ (void) printf(
+ "| %9s| ", "- ");
+ } else {
+ (void) printf(
+ "| %9s| ", str);
+ }
+
+ if (is_spare == B_TRUE) {
+ (void) printf("| %4s| %5s| %3s|\n", "- ", "- ", "- ");
+ } else {
+ if (nvlist_lookup_uint64(target,
+ TD_ZPOOL_ATTR_TARGET_READ_ERRORS, &ui64) != 0) {
+ (void) printf("| %4s", "- ");
+ } else {
+ (void) printf("| %4llu", ui64);
+ }
+
+ if (nvlist_lookup_uint64(target,
+ TD_ZPOOL_ATTR_TARGET_WRITE_ERRORS, &ui64) != 0) {
+ (void) printf("| %5s", "- ");
+ } else {
+ (void) printf("| %5llu", ui64);
+ }
+
+ if (nvlist_lookup_uint64(target,
+ TD_ZPOOL_ATTR_TARGET_CHECKSUM_ERRORS, &ui64) != 0) {
+ (void) printf("| %3s|\n", "- ");
+ } else {
+ (void) printf("| %3llu|\n", ui64);
+ }
+ }
+
+ if (nvlist_lookup_uint32(target,
+ TD_ZPOOL_ATTR_NUM_TARGETS,
+ &ui32) != 0) {
+ return;
+ }
+
+ if (ui32 > 0) {
+ if (nvlist_lookup_nvlist_array(target,
+ TD_ZPOOL_ATTR_TARGETS,
+ &targets, &ret) != 0) {
+ return;
+ }
+
+ for (cnt1 = 0; cnt1 < ret; cnt1++) {
+ td_zpool_show_target(targets[cnt1],
+ depth + 2, is_spare);
+ }
+ }
+}
+
+
+/*
+ * td_zpool_show_attr()
+ */
+static void
+td_zpool_show_attr(nvlist_t *attrs, rep_verbosity_t verbosity)
+{
+ char *str;
+ uint32_t ui32;
+ uint64_t ui64;
+ uint32_t num_targets = 0, num_logs = 0;
+ uint32_t num_l2cache = 0, num_spares = 0;
+ nvlist_t **targets, **logs, **l2cache, **spares;
+ int cnt1 = 0;
+ uint_t ret;
+ boolean_t import = B_FALSE;
+
+ if (nvlist_lookup_string(attrs, TD_ZPOOL_ATTR_NAME, &str) == 0) {
+ (void) printf(" %-33s| ", str);
+ } else {
+ (void) printf(" %-33s| ", "- ");
+ }
+
+ if (nvlist_lookup_string(attrs, TD_ZPOOL_ATTR_HEALTH, &str) == 0) {
+ (void) printf("%9s| ", str);
+ } else {
+ (void) printf("%9s| ", "- ");
+ }
+
+ if (nvlist_lookup_uint64(attrs, TD_ZPOOL_ATTR_SIZE, &ui64) == 0) {
+ double size_mb = 0, size_gb = 0;
+
+ if (ui64 > 0) {
+ size_mb = BYTES_TO_MB(ui64);
+ } else {
+ size_mb = 0;
+ size_gb = 0;
+ }
+
+ if (size_mb > MB_IN_GB) {
+ size_gb = MB_TO_GB(size_mb);
+ size_mb = 0;
+ } else {
+ size_gb = 0;
+ }
+
+ (void) printf("%7.2lf%c| ",
+ size_mb > 0 ? size_mb : size_gb,
+ size_mb > 0 ? 'M' : 'G');
+ } else {
+ (void) printf("%8s| ", "- ");
+ }
+
+ if (nvlist_lookup_uint64(attrs, TD_ZPOOL_ATTR_CAPACITY, &ui64) == 0) {
+ (void) printf("%3llu%%| ", ui64);
+ } else {
+ (void) printf("%4s| ", "- ");
+ }
+
+ if (nvlist_lookup_uint32(attrs, TD_ZPOOL_ATTR_STATUS, &ui32) == 0) {
+ (void) printf("%5d|", ui32);
+ } else {
+ (void) printf("%5s|", "- ");
+ }
+
+ if (nvlist_lookup_uint32(attrs, TD_ZPOOL_ATTR_VERSION, &ui32) == 0) {
+ (void) printf(" %2d|\n", ui32);
+ } else {
+ (void) printf(" %2s|\n", "h ");
+ }
+
+ if (nvlist_lookup_uint64(attrs, TD_ZPOOL_ATTR_GUID, &ui64) == 0) {
+ (void) printf("%4s |", "");
+ (void) printf("%34llu| ", ui64);
+ (void) printf("%9s| ", " ");
+ (void) printf("%8s| ", " ");
+ (void) printf("%4s| ", " ");
+ (void) printf("%5s|", " ");
+ (void) printf(" %2s|\n", " ");
+ } else {
+ (void) printf("%4s |", "");
+ (void) printf(" %34s| ", "- ");
+ (void) printf("%9s| ", " ");
+ (void) printf("%8s| ", " ");
+ (void) printf("%4s| ", " ");
+ (void) printf("%5s|", " ");
+ (void) printf(" %2s|\n", " ");
+ }
+
+ if (nvlist_lookup_string(attrs, TD_ZPOOL_ATTR_BOOTFS, &str) == 0) {
+ (void) printf("%4s |", "");
+ (void) printf(" %33s| ", str != NULL ? str : "m");
+ (void) printf("%9s| ", " ");
+ (void) printf("%8s| ", " ");
+ (void) printf("%4s| ", " ");
+ (void) printf("%5s|", " ");
+ (void) printf(" %2s|\n", " ");
+ }
+
+ if (nvlist_lookup_boolean_value(attrs,
+ TD_ZPOOL_ATTR_IMPORT, &import) == 0) {
+ if (import) {
+ (void) printf("%4s |", "");
+ (void) printf(" %33s| ", "Importable pool");
+ (void) printf("%9s| ", " ");
+ (void) printf("%8s| ", " ");
+ (void) printf("%4s| ", " ");
+ (void) printf("%5s|", " ");
+ (void) printf(" %2s|\n", " ");
+ }
+ }
+
+ if (verbosity == REPORT_VERB_HIGH) {
+ /* High verbosity just print number of targets */
+ num_targets = 0;
+ if (nvlist_lookup_uint32(attrs, TD_ZPOOL_ATTR_NUM_TARGETS,
+ &num_targets) != 0) {
+ num_targets = 0;
+ }
+
+ /* Print targets */
+ if (num_targets > 0) {
+ if (nvlist_lookup_nvlist_array(attrs,
+ TD_ZPOOL_ATTR_TARGETS, &targets, &ret) != 0) {
+ (void) printf(" | %72s|\n",
+ "Failed to retrieve targets");
+ } else {
+ for (cnt1 = 0; cnt1 < ret; cnt1++) {
+ td_zpool_show_target(targets[cnt1],
+ 0, B_FALSE);
+ }
+ }
+ }
+
+ /* Print logs */
+ num_logs = 0;
+ if (nvlist_lookup_uint32(attrs, TD_ZPOOL_ATTR_NUM_LOGS,
+ &num_logs) != 0) {
+ num_logs = 0;
+ }
+
+ if (num_logs > 0) {
+ (void) printf("%4s |", "");
+ (void) printf(" %-33s| ", "logs");
+ (void) printf("%9s| ", " ");
+ (void) printf("%8s| ", " ");
+ (void) printf("%4s| ", " ");
+ (void) printf("%5s|", " ");
+ (void) printf(" %2s|\n", " ");
+
+ if (nvlist_lookup_nvlist_array(attrs,
+ TD_ZPOOL_ATTR_LOGS, &logs, &ret) != 0) {
+ (void) printf(" | %72s|\n",
+ "Failed to retrieve logs");
+ } else {
+ for (cnt1 = 0; cnt1 < ret; cnt1++) {
+ td_zpool_show_target(logs[cnt1],
+ 0, B_FALSE);
+ }
+ }
+ }
+
+ /* Print l2cache */
+ num_l2cache = 0;
+ if (nvlist_lookup_uint32(attrs, TD_ZPOOL_ATTR_NUM_L2CACHE,
+ &num_l2cache) != 0) {
+ num_l2cache = 0;
+ }
+
+ if (num_l2cache > 0) {
+ (void) printf("%4s |", "");
+ (void) printf(" %-33s| ", "cache");
+ (void) printf("%9s| ", " ");
+ (void) printf("%8s| ", " ");
+ (void) printf("%4s| ", " ");
+ (void) printf("%5s|", " ");
+ (void) printf(" %2s|\n", " ");
+
+ if (nvlist_lookup_nvlist_array(attrs,
+ TD_ZPOOL_ATTR_L2CACHE, &l2cache, &ret) != 0) {
+ (void) printf(" | %72s|\n",
+ "Failed to retrieve l2cache");
+ } else {
+ for (cnt1 = 0; cnt1 < ret; cnt1++) {
+ td_zpool_show_target(l2cache[cnt1],
+ 0, B_FALSE);
+ }
+ }
+ }
+
+ /* Print spares */
+ num_spares = 0;
+ if (nvlist_lookup_uint32(attrs, TD_ZPOOL_ATTR_NUM_SPARES,
+ &num_spares) != 0) {
+ num_spares = 0;
+ }
+
+ if (num_spares > 0) {
+ (void) printf("%4s |", "");
+ (void) printf(" %-33s| ", "spares");
+ (void) printf("%9s| ", " ");
+ (void) printf("%8s| ", " ");
+ (void) printf("%4s| ", " ");
+ (void) printf("%5s|", " ");
+ (void) printf(" %2s|\n", " ");
+
+ if (nvlist_lookup_nvlist_array(attrs,
+ TD_ZPOOL_ATTR_SPARES, &spares, &ret) != 0) {
+ (void) printf(" | %72s|\n",
+ "Failed to retrieve spares");
+ } else {
+ for (cnt1 = 0; cnt1 < ret; cnt1++) {
+ td_zpool_show_target(spares[cnt1],
+ 0, B_TRUE);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * discover_zpool()
+ */
+static int
+discover_zpool(rep_verbosity_t verbosity)
+{
+ nvlist_t *zpool_attr;
+ int i;
+ int nozpools;
+
+ if (td_discover(TD_OT_ZPOOL, &nozpools) != 0) {
+ (void) printf("Couldn't discover zpools\n");
+
+ return (-1);
+ }
+
+ /* if there is no Solaris, do not display empty table */
+ if (nozpools == 0)
+ return (0);
+
+ (void) printf("Total number of zpools: %d\n", nozpools);
+
+ /* list os attributes */
+ display_report(REPORT_ZPOOL, REPORT_HEADER, verbosity);
+
+ for (i = 0; i < nozpools; i++) {
+ if (td_get_next(TD_OT_ZPOOL) != 0) {
+ (void) printf("Couldn't get next zpool\n");
+
+ return (-1);
+ }
+
+ (void) printf("%4d |", i + 1);
+
+ zpool_attr = td_attributes_get(TD_OT_ZPOOL);
+
+ if (zpool_attr == NULL) {
+ display_report(REPORT_ZPOOL, REPORT_BODY_NOATTR,
+ verbosity);
+ } else {
+ (void) td_zpool_show_attr(zpool_attr, verbosity);
+
+ nvlist_free(zpool_attr);
+ }
+ display_report(REPORT_ZPOOL, REPORT_BODY_NOATTR, verbosity);
+ }
+
+ display_report(REPORT_ZPOOL, REPORT_FOOTER, verbosity);
+
+ return (0);
+}
+
+/*
* main()
*/
int
@@ -884,6 +1273,8 @@
char *slice_object_to_discover = NULL;
int fl_discover_os = 0;
char *os_object_to_discover = NULL;
+ int fl_discover_zpools = 0;
+ char *zpool_object_to_discover = NULL;
/* init logging/debugging service */
@@ -895,14 +1286,15 @@
* s - slice discovery
* o - discovery of Solaris instances
* v - verbose output
+ * z - zpool discovery
*/
/* -p is not supported for Sparc */
#ifdef sparc
- while ((opt = getopt(argc, argv, "x:vds:o:")) != EOF) {
+ while ((opt = getopt(argc, argv, "x:vds:o:z:")) != EOF) {
#else
- while ((opt = getopt(argc, argv, "x:vdp:s:o:")) != EOF) {
+ while ((opt = getopt(argc, argv, "x:vdp:s:o:z:")) != EOF) {
#endif
switch (opt) {
@@ -946,6 +1338,12 @@
os_object_to_discover = optarg;
break;
+ case 'z':
+ fl_discover_zpools = 1;
+
+ zpool_object_to_discover = optarg;
+ break;
+
case 'v':
verbosity = REPORT_VERB_HIGH;
break;
@@ -956,7 +1354,7 @@
* if there is nothing to discover, display help and exit
*/
if (!fl_discover_disks && !fl_discover_parts && !fl_discover_slices &&
- !fl_discover_os) {
+ !fl_discover_os && !fl_discover_zpools) {
display_help();
return (0);
@@ -1018,5 +1416,19 @@
}
}
+ /* discover zpools */
+
+ if (fl_discover_zpools) {
+ /* determine if all zpools are to be discovered */
+
+ if (strncmp(zpool_object_to_discover, "all",
+ sizeof ("all") - 1) == 0) {
+ (void) printf("\nZpool discovery\n");
+
+ (void) discover_zpool(verbosity);
+ } else {
+ (void) printf("\n-z <zpool> not supported for now\n");
+ }
+ }
return (0);
}