Print this page
NEX-5063 Passing invalid trim rate to zpool(1M) coredumps
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
6328 Fix cstyle errors in zfs codebase (fix studio)
6328 Fix cstyle errors in zfs codebase
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Alex Reece <alex@delphix.com>
Reviewed by: Richard Elling <Richard.Elling@RichardElling.com>
Reviewed by: Jorgen Lundman <lundman@lundman.net>
Approved by: Robert Mustacchi <rm@joyent.com>
5745 zfs set allows only one dataset property to be set at a time
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
Reviewed by: George Wilson <george@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Bayard Bell <buffer.g.overflow@gmail.com>
Reviewed by: Richard PALO <richard@NetBSD.org>
Reviewed by: Steven Hartland <killing@multiplay.co.uk>
Approved by: Rich Lowe <richlowe@richlowe.net>
5692 expose the number of hole blocks in a file
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Reviewed by: Boris Protopopov <bprotopopov@hotmail.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
NEX-4336 zpool vdev-get with an unsuported prop name core dumps
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-3558 KRRP Integration
OS-103 handle CoS descriptor persistent references across vdev operations
OS-102 add man page info and tests for vdev/CoS properties and ZFS meta features
Moved closed ZFS files to open repo, changed Makefiles accordingly
Removed unneeded weak symbols
re #8279 rb3915 need a mechanism to notify NMS about ZFS config changes (fix lint -courtesy of Yuri Pankov)
re #12584 rb4049 zfsxx latest code merge (fix lint - courtesy of Yuri Pankov)
re #12585 rb4049 ZFS++ work port - refactoring to improve separation of open/closed code, bug fixes, performance improvements - open code
re #8279 rb3915 need a mechanism to notify NMS about ZFS config changes (Opened code)
Bug 11205: add missing libzfs_closed_stubs.c to fix opensource-only build.
ZFS plus work: special vdevs, cos, cos/vdev properties

@@ -20,10 +20,11 @@
  */
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
  * Copyright (c) 2017 Datto Inc.
  */
 

@@ -233,13 +234,19 @@
                 return (dgettext(TEXT_DOMAIN, "unable to generate diffs"));
         case EZFS_DIFFDATA:
                 return (dgettext(TEXT_DOMAIN, "invalid diff data"));
         case EZFS_POOLREADONLY:
                 return (dgettext(TEXT_DOMAIN, "pool is read-only"));
-        case EZFS_NO_PENDING:
-                return (dgettext(TEXT_DOMAIN, "operation is not "
-                    "in progress"));
+        case EZFS_PROPNOTSUP:
+                return (dgettext(TEXT_DOMAIN, "property is not supported"));
+        case EZFS_COSNOTFOUND:
+                return (dgettext(TEXT_DOMAIN, "CoS descriptor not found"));
+        case EZFS_COSEXIST:
+                return (dgettext(TEXT_DOMAIN, "CoS descriptor already exists"));
+        case EZFS_COSREF:
+                return (dgettext(TEXT_DOMAIN,
+                        "CoS descriptor is still referenced"));
         case EZFS_UNKNOWN:
                 return (dgettext(TEXT_DOMAIN, "unknown error"));
         default:
                 assert(hdl->libzfs_error == 0);
                 return (dgettext(TEXT_DOMAIN, "no error"));

@@ -387,10 +394,13 @@
                 zfs_verror(hdl, EZFS_BUSY, fmt, ap);
                 break;
         case EROFS:
                 zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap);
                 break;
+        case EINVAL:
+                zfs_verror(hdl, EZFS_INVALIDNAME, fmt, ap);
+                break;
         case ENAMETOOLONG:
                 zfs_verror(hdl, EZFS_NAMETOOLONG, fmt, ap);
                 break;
         case ENOTSUP:
                 zfs_verror(hdl, EZFS_BADVERSION, fmt, ap);

@@ -409,10 +419,54 @@
         va_end(ap);
         return (-1);
 }
 
 int
+zpool_vprop_standard_error(libzfs_handle_t *hdl, int error, const char *msg)
+{
+        return (zpool_vprop_standard_error_fmt(hdl, error, "%s", msg));
+}
+
+/*PRINTFLIKE3*/
+int
+zpool_vprop_standard_error_fmt(libzfs_handle_t *hdl, int error,
+    const char *fmt, ...)
+{
+        va_list ap;
+
+        va_start(ap, fmt);
+
+        if (zfs_common_error(hdl, error, fmt, ap) != 0) {
+                va_end(ap);
+                return (-1);
+        }
+
+        switch (error) {
+        case ENOENT:
+                zfs_verror(hdl, EZFS_COSNOTFOUND, fmt, ap);
+                break;
+        case ENOTSUP:
+                zfs_verror(hdl, EZFS_PROPNOTSUP, fmt, ap);
+                break;
+
+        case EEXIST:
+                zfs_verror(hdl, EZFS_COSEXIST, fmt, ap);
+                break;
+        case EBUSY:
+                zfs_verror(hdl, EZFS_COSREF, fmt, ap);
+                break;
+        default:
+                zfs_error_aux(hdl, strerror(error));
+                zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
+                break;
+        }
+
+        va_end(ap);
+        return (-1);
+}
+
+int
 zpool_standard_error(libzfs_handle_t *hdl, int error, const char *msg)
 {
         return (zpool_standard_error_fmt(hdl, error, "%s", msg));
 }
 

@@ -445,11 +499,12 @@
                     "pool already exists"));
                 zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
                 break;
 
         case EBUSY:
-                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool is busy"));
+                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                    "pool or device is busy"));
                 zfs_verror(hdl, EZFS_BUSY, fmt, ap);
                 break;
 
         case ENXIO:
                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,

@@ -481,14 +536,10 @@
                 break;
 
         case EROFS:
                 zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap);
                 break;
-        /* There is no pending operation to cancel */
-        case ENOTACTIVE:
-                zfs_verror(hdl, EZFS_NO_PENDING, fmt, ap);
-                break;
 
         default:
                 zfs_error_aux(hdl, strerror(error));
                 zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
         }

@@ -620,10 +671,12 @@
         }
 
         zfs_prop_init();
         zpool_prop_init();
         zpool_feature_init();
+        vdev_prop_init();
+        cos_prop_init();
         libzfs_mnttab_init(hdl);
 
         if (getenv("ZFS_PROP_DEBUG") != NULL) {
                 hdl->libzfs_prop_debug = B_TRUE;
         }

@@ -637,10 +690,12 @@
         (void) close(hdl->libzfs_fd);
         if (hdl->libzfs_mnttab)
                 (void) fclose(hdl->libzfs_mnttab);
         if (hdl->libzfs_sharetab)
                 (void) fclose(hdl->libzfs_sharetab);
+        if (hdl->libzfs_log_str)
+                free(hdl->libzfs_log_str);
         zfs_uninit_libshare(hdl);
         zpool_free_handles(hdl);
         libzfs_fru_clear(hdl, B_TRUE);
         namespace_clear(hdl);
         libzfs_mnttab_fini(hdl);

@@ -805,14 +860,28 @@
                 return (no_memory(hdl));
 
         return (0);
 }
 
+#pragma weak libzfs_log_event = libzfs_log_event_stub
+
+/* ARGSUSED hdl zc */
+void
+libzfs_log_event_stub(libzfs_handle_t *hdl, const char *zc)
+{
+}
+
 int
 zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
 {
-        return (ioctl(hdl->libzfs_fd, request, zc));
+        int error;
+
+        error = ioctl(hdl->libzfs_fd, request, zc);
+        if (error == 0)
+                libzfs_log_event(hdl, zc->zc_name);
+
+        return (error);
 }
 
 /*
  * ================================================================
  * API shared by zfs and zpool property management

@@ -1044,10 +1113,11 @@
         for (i = 0; i < strlen(ends); i++) {
                 if (toupper(buf[0]) == ends[i])
                         break;
         }
         if (i == strlen(ends)) {
+                if (hdl)
                 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                     "invalid numeric suffix '%s'"), buf);
                 return (-1);
         }
 

@@ -1057,10 +1127,11 @@
          */
         if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0' &&
             toupper(buf[0]) != 'B'))
                 return (10*i);
 
+        if (hdl)
         zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
             "invalid numeric suffix '%s'"), buf);
         return (-1);
 }
 

@@ -1158,14 +1229,24 @@
         zprop_type_t proptype;
         const char *propname;
         char *value;
         boolean_t isnone = B_FALSE;
 
-        if (type == ZFS_TYPE_POOL) {
+        switch (type) {
+        case ZFS_TYPE_POOL:
                 proptype = zpool_prop_get_type(prop);
                 propname = zpool_prop_to_name(prop);
-        } else {
+                break;
+        case ZFS_TYPE_VDEV:
+                proptype = vdev_prop_get_type(prop);
+                propname = vdev_prop_to_name(prop);
+                break;
+        case ZFS_TYPE_COS:
+                proptype = cos_prop_get_type(prop);
+                propname = cos_prop_to_name(prop);
+                break;
+        default:
                 proptype = zfs_prop_get_type(prop);
                 propname = zfs_prop_to_name(prop);
         }
 
         /*

@@ -1489,10 +1570,442 @@
     zfs_type_t type)
 {
         return (zprop_iter_common(func, cb, show_all, ordered, type));
 }
 
+int
+vdev_get_proplist(libzfs_handle_t *hdl, char *props, zprop_list_t **listp)
+{
+        *listp = NULL;
+
+        /*
+         * If 'all' is specified, return a NULL list.
+         */
+        if (strcmp(props, "all") == 0) {
+                vdev_prop_t prop;
+                for (prop = VDEV_PROP_PATH; prop < VDEV_NUM_PROPS; prop++) {
+                        const char *propname = vdev_prop_to_name(prop);
+                        if (addlist(hdl, (char *)propname, listp,
+                            ZFS_TYPE_VDEV))
+                                return (-1);
+                        listp = &(*listp)->pl_next;
+                }
+
+                return (0);
+        }
+
+        /*
+         * If no props were specified, return an error.
+         */
+        if (props[0] == '\0') {
+                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                    "no properties specified"));
+                return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN,
+                    "bad property list")));
+        }
+
+        /*
+         * It would be nice to use getsubopt() here, but the inclusion of column
+         * aliases makes this more effort than it's worth.
+         */
+        while (*props != '\0') {
+                size_t len;
+                char *p;
+                char c;
+
+                if ((p = strchr(props, ',')) == NULL) {
+                        len = strlen(props);
+                        p = props + len;
+                } else {
+                        len = p - props;
+                }
+
+                /*
+                 * Check for empty options.
+                 */
+                if (len == 0) {
+                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                            "empty property name"));
+                        return (zfs_error(hdl, EZFS_BADPROP,
+                            dgettext(TEXT_DOMAIN, "bad property list")));
+                }
+
+                /*
+                 * Check all regular property names.
+                 */
+                c = props[len];
+                props[len] = '\0';
+
+                /*
+                 * Make sure we're looking at a valid prop.
+                 */
+                if (vdev_name_to_prop(props) == ZPROP_INVAL) {
+                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                            "invalid property '%s'"), props);
+                        return (zfs_error(hdl, EZFS_BADPROP,
+                            dgettext(TEXT_DOMAIN, "bad property list")));
+                }
+
+                if (addlist(hdl, props, listp, ZFS_TYPE_VDEV))
+                        return (-1);
+                listp = &(*listp)->pl_next;
+
+                props = p;
+                if (c == ',')
+                        props++;
+        }
+
+        return (0);
+}
+
+int
+cos_get_proplist(libzfs_handle_t *hdl, char *props, zprop_list_t **listp)
+{
+        *listp = NULL;
+
+        /*
+         * If 'all' is specified, return a NULL list.
+         */
+        if (strcmp(props, "all") == 0) {
+                cos_prop_t prop;
+                for (prop = COS_PROP_GUID; prop < COS_NUM_PROPS; prop++) {
+                        const char *propname = cos_prop_to_name(prop);
+                        if (addlist(hdl, (char *)propname, listp,
+                            ZFS_TYPE_COS))
+                                return (-1);
+                        listp = &(*listp)->pl_next;
+                }
+
+                return (0);
+        }
+
+        /*
+         * If no props were specified, return an error.
+         */
+        if (props[0] == '\0') {
+                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                    "no properties specified"));
+                return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN,
+                    "bad property list")));
+        }
+
+        /*
+         * It would be nice to use getsubopt() here, but the inclusion of column
+         * aliases makes this more effort than it's worth.
+         */
+        while (*props != '\0') {
+                size_t len;
+                char *p;
+                char c;
+
+                if ((p = strchr(props, ',')) == NULL) {
+                        len = strlen(props);
+                        p = props + len;
+                } else {
+                        len = p - props;
+                }
+
+                /*
+                 * Check for empty options.
+                 */
+                if (len == 0) {
+                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                            "empty property name"));
+                        return (zfs_error(hdl, EZFS_BADPROP,
+                            dgettext(TEXT_DOMAIN, "bad property list")));
+                }
+
+                /*
+                 * Check all regular property names.
+                 */
+                c = props[len];
+                props[len] = '\0';
+
+                if (addlist(hdl, props, listp, ZFS_TYPE_COS))
+                        return (-1);
+                listp = &(*listp)->pl_next;
+
+                props = p;
+                if (c == ',')
+                        props++;
+        }
+
+        return (0);
+}
+
+void
+vdev_print_headers(zprop_get_cbdata_t *cbp)
+{
+        zprop_list_t *pl = cbp->cb_proplist;
+        int i;
+        char *title;
+        size_t len;
+
+        cbp->cb_first = B_FALSE;
+        if (cbp->cb_scripted)
+                return;
+
+        /*
+         * Start with the length of the column headers.
+         */
+        cbp->cb_colwidths[GET_COL_NAME] = strlen(dgettext(TEXT_DOMAIN,
+            "POOLNAME"));
+        cbp->cb_colwidths[GET_COL_SOURCE] = strlen(dgettext(TEXT_DOMAIN,
+            "c0t0d0s0"));
+        cbp->cb_colwidths[GET_COL_PROPERTY] = strlen(dgettext(TEXT_DOMAIN,
+            "PROPERTY"));
+        cbp->cb_colwidths[GET_COL_VALUE] = strlen(dgettext(TEXT_DOMAIN,
+            "VALUE"));
+
+        for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
+                /*
+                 * 'PROPERTY' column
+                 */
+                const char *propname = vdev_prop_to_name(pl->pl_prop);
+
+                len = strlen(propname);
+                if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
+                        cbp->cb_colwidths[GET_COL_PROPERTY] = len;
+
+                /*
+                 * 'VALUE' column.
+                 */
+                if (pl != cbp->cb_proplist &&
+                    pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE])
+                        cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width;
+
+                /*
+                 * 'NAME'
+                 */
+                if (pl->pl_prop == 0 &&
+                    pl->pl_width > cbp->cb_colwidths[GET_COL_NAME]) {
+                        cbp->cb_colwidths[GET_COL_NAME] = pl->pl_width;
+                }
+                /*
+                 * 'SOURCE'
+                 */
+                if (pl->pl_prop == 0 &&
+                    pl->pl_width > cbp->cb_colwidths[GET_COL_SOURCE]) {
+                        cbp->cb_colwidths[GET_COL_SOURCE] = pl->pl_width;
+                }
+        }
+
+        /*
+         * Now go through and print the headers.
+         */
+        for (i = 0; i < ZFS_GET_NCOLS-1; i++) {
+                switch (cbp->cb_columns[i]) {
+                case GET_COL_NAME:
+                        title = dgettext(TEXT_DOMAIN, "POOLNAME");
+                        break;
+                case GET_COL_SOURCE:
+                        title = dgettext(TEXT_DOMAIN, "VDEV");
+                        break;
+                case GET_COL_PROPERTY:
+                        title = dgettext(TEXT_DOMAIN, "PROPERTY");
+                        break;
+                case GET_COL_VALUE:
+                        title = dgettext(TEXT_DOMAIN, "VALUE");
+                        break;
+                default:
+                        title = NULL;
+                }
+
+                if (title != NULL) {
+                        if (i == (ZFS_GET_NCOLS - 1) ||
+                            cbp->cb_columns[i + 1] == GET_COL_NONE)
+                                (void) printf("%s", title);
+                        else
+                                (void) printf("%-*s  ",
+                                    cbp->cb_colwidths[cbp->cb_columns[i]],
+                                    title);
+                }
+        }
+        (void) printf("\n");
+}
+
+void
+cos_print_headers(zprop_get_cbdata_t *cbp)
+{
+        zprop_list_t *pl = cbp->cb_proplist;
+        int i;
+        char *title;
+        size_t len;
+
+        cbp->cb_first = B_FALSE;
+        if (cbp->cb_scripted)
+                return;
+
+        /*
+         * Start with the length of the column headers.
+         */
+        cbp->cb_colwidths[GET_COL_NAME] = strlen(dgettext(TEXT_DOMAIN,
+            "POOLNAME"));
+        cbp->cb_colwidths[GET_COL_SOURCE] = strlen(dgettext(TEXT_DOMAIN,
+            "c0t0d0s0"));
+        cbp->cb_colwidths[GET_COL_PROPERTY] = strlen(dgettext(TEXT_DOMAIN,
+            "PROPERTY"));
+        cbp->cb_colwidths[GET_COL_VALUE] = strlen(dgettext(TEXT_DOMAIN,
+            "VALUE"));
+
+        for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
+                /*
+                 * 'PROPERTY' column
+                 */
+                const char *propname = cos_prop_to_name(pl->pl_prop);
+
+                len = strlen(propname);
+                if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
+                        cbp->cb_colwidths[GET_COL_PROPERTY] = len;
+
+                /*
+                 * 'VALUE' column.
+                 */
+                if (pl != cbp->cb_proplist &&
+                    pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE])
+                        cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width;
+
+                /*
+                 * 'NAME'
+                 */
+                if (pl->pl_prop == 0 &&
+                    pl->pl_width > cbp->cb_colwidths[GET_COL_NAME]) {
+                        cbp->cb_colwidths[GET_COL_NAME] = pl->pl_width;
+                }
+                /*
+                 * 'SOURCE'
+                 */
+                if (pl->pl_prop == 0 &&
+                    pl->pl_width > cbp->cb_colwidths[GET_COL_SOURCE]) {
+                        cbp->cb_colwidths[GET_COL_SOURCE] = pl->pl_width;
+                }
+        }
+
+        /*
+         * Now go through and print the headers.
+         */
+        for (i = 0; i < ZFS_GET_NCOLS-1; i++) {
+                switch (cbp->cb_columns[i]) {
+                case GET_COL_NAME:
+                        title = dgettext(TEXT_DOMAIN, "POOLNAME");
+                        break;
+                case GET_COL_SOURCE:
+                        title = dgettext(TEXT_DOMAIN, "COS");
+                        break;
+                case GET_COL_PROPERTY:
+                        title = dgettext(TEXT_DOMAIN, "PROPERTY");
+                        break;
+                case GET_COL_VALUE:
+                        title = dgettext(TEXT_DOMAIN, "VALUE");
+                        break;
+                default:
+                        title = NULL;
+                }
+
+                if (title != NULL) {
+                        if (i == (ZFS_GET_NCOLS - 1) ||
+                            cbp->cb_columns[i + 1] == GET_COL_NONE)
+                                (void) printf("%s", title);
+                        else
+                                (void) printf("%-*s  ",
+                                    cbp->cb_colwidths[cbp->cb_columns[i]],
+                                    title);
+                }
+        }
+        (void) printf("\n");
+}
+
+void
+vdev_print_one_property(const char *poolname, const char *vdevname,
+    zprop_get_cbdata_t *cbp, const char *propname, const char *value)
+{
+        int i;
+        const char *str;
+
+        if (cbp->cb_first)
+                vdev_print_headers(cbp);
+
+        for (i = 0; i < ZFS_GET_NCOLS; i++) {
+                switch (cbp->cb_columns[i]) {
+                case GET_COL_NAME:
+                        str = poolname;
+                        break;
+
+                case GET_COL_SOURCE:
+                        str = vdevname;
+                        break;
+
+                case GET_COL_PROPERTY:
+                        str = propname;
+                        break;
+
+                case GET_COL_VALUE:
+                        str = value;
+                        break;
+
+                default:
+                        continue;
+                }
+
+                if (cbp->cb_columns[i + 1] == GET_COL_NONE)
+                        (void) printf("%s", str);
+                else if (cbp->cb_scripted)
+                        (void) printf("%s\t", str);
+                else
+                        (void) printf("%-*s  ",
+                            cbp->cb_colwidths[cbp->cb_columns[i]],
+                            str);
+        }
+
+        (void) printf("\n");
+}
+
+void
+cos_print_one_property(const char *poolname, const char *cosname,
+    zprop_get_cbdata_t *cbp, const char *propname, const char *value)
+{
+        int i;
+        const char *str;
+
+        if (cbp->cb_first)
+                cos_print_headers(cbp);
+
+        for (i = 0; i < ZFS_GET_NCOLS; i++) {
+                switch (cbp->cb_columns[i]) {
+                case GET_COL_NAME:
+                        str = poolname;
+                        break;
+
+                case GET_COL_SOURCE:
+                        str = cosname;
+                        break;
+
+                case GET_COL_PROPERTY:
+                        str = propname;
+                        break;
+
+                case GET_COL_VALUE:
+                        str = value;
+                        break;
+
+                default:
+                        continue;
+                }
+
+                if (cbp->cb_columns[i + 1] == GET_COL_NONE)
+                        (void) printf("%s", str);
+                else if (cbp->cb_scripted)
+                        (void) printf("%s\t", str);
+                else
+                        (void) printf("%-*s  ",
+                            cbp->cb_colwidths[cbp->cb_columns[i]],
+                            str);
+        }
+
+        (void) printf("\n");
+}
+
 /*
  * zfs_get_hole_count retrieves the number of holes (blocks which are
  * zero-filled) in the specified file using the _FIO_COUNT_FILLED ioctl. It
  * also optionally fetches the block size when bs is non-NULL. With hole count
  * and block size the full space consumed by the holes of a file can be