Author: markj
Date: Thu Aug  6 14:07:49 2020
New Revision: 363952
URL: https://svnweb.freebsd.org/changeset/base/363952

Log:
  MFC r363447:
  MFOpenZFS: Fix zpool history unbounded memory usage
  
  PR:   247557

Modified:
  stable/12/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
  stable/12/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
  stable/12/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c
==============================================================================
--- stable/12/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c   Thu Aug  6 
13:41:42 2020        (r363951)
+++ stable/12/cddl/contrib/opensolaris/cmd/zpool/zpool_main.c   Thu Aug  6 
14:07:49 2020        (r363952)
@@ -6226,25 +6226,13 @@ typedef struct hist_cbdata {
        boolean_t internal;
 } hist_cbdata_t;
 
-/*
- * Print out the command history for a specific pool.
- */
-static int
-get_history_one(zpool_handle_t *zhp, void *data)
+static void
+print_history_records(nvlist_t *nvhis, hist_cbdata_t *cb)
 {
-       nvlist_t *nvhis;
        nvlist_t **records;
        uint_t numrecords;
-       int ret, i;
-       hist_cbdata_t *cb = (hist_cbdata_t *)data;
+       int i;
 
-       cb->first = B_FALSE;
-
-       (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
-
-       if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
-               return (ret);
-
        verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
            &records, &numrecords) == 0);
        for (i = 0; i < numrecords; i++) {
@@ -6344,8 +6332,32 @@ get_history_one(zpool_handle_t *zhp, void *data)
                (void) printf("]");
                (void) printf("\n");
        }
+}
+
+/*
+ * Print out the command history for a specific pool.
+ */
+static int
+get_history_one(zpool_handle_t *zhp, void *data)
+{
+       nvlist_t *nvhis;
+       int ret;
+       hist_cbdata_t *cb = (hist_cbdata_t *)data;
+       uint64_t off = 0;
+       boolean_t eof = B_FALSE;
+
+       cb->first = B_FALSE;
+
+       (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
+
+       while (!eof) {
+               if ((ret = zpool_get_history(zhp, &nvhis, &off, &eof)) != 0)
+                       return (ret);
+
+               print_history_records(nvhis, cb);
+               nvlist_free(nvhis);
+       }
        (void) printf("\n");
-       nvlist_free(nvhis);
 
        return (ret);
 }

Modified: stable/12/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
==============================================================================
--- stable/12/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h       Thu Aug 
 6 13:41:42 2020        (r363951)
+++ stable/12/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h       Thu Aug 
 6 14:07:49 2020        (r363952)
@@ -440,7 +440,8 @@ typedef enum {
 extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *,
     int name_flags);
 extern int zpool_upgrade(zpool_handle_t *, uint64_t);
-extern int zpool_get_history(zpool_handle_t *, nvlist_t **);
+extern int zpool_get_history(zpool_handle_t *, nvlist_t **, uint64_t *,
+    boolean_t *);
 extern int zpool_history_unpack(char *, uint64_t, uint64_t *,
     nvlist_t ***, uint_t *);
 extern void zpool_obj_to_path(zpool_handle_t *, uint64_t, uint64_t, char *,

Modified: stable/12/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
==============================================================================
--- stable/12/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c  Thu Aug 
 6 13:41:42 2020        (r363951)
+++ stable/12/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c  Thu Aug 
 6 14:07:49 2020        (r363952)
@@ -4124,33 +4124,37 @@ zpool_history_unpack(char *buf, uint64_t bytes_read, u
  * Retrieve the command history of a pool.
  */
 int
-zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
+zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp, uint64_t *off,
+    boolean_t *eof)
 {
        char *buf;
        uint64_t buflen = HIS_BUF_LEN_DEF;
-       uint64_t off = 0;
        nvlist_t **records = NULL;
        uint_t numrecords = 0;
        int err, i;
+       uint64_t start = *off;
 
        buf = malloc(buflen);
        if (buf == NULL)
                return (ENOMEM);
-       do {
+       /* process about 1MB at a time */
+       while (*off - start < 1024 * 1024) {
                uint64_t bytes_read = buflen;
                uint64_t leftover;
 
-               if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
+               if ((err = get_history(zhp, buf, off, &bytes_read)) != 0)
                        break;
 
                /* if nothing else was read in, we're at EOF, just return */
-               if (bytes_read == 0)
+               if (bytes_read == 0) {
+                       *eof = B_TRUE;
                        break;
+               }
 
                if ((err = zpool_history_unpack(buf, bytes_read,
                    &leftover, &records, &numrecords)) != 0)
                        break;
-               off -= leftover;
+               *off -= leftover;
                if (leftover == bytes_read) {
                        /*
                         * no progress made, because buffer is not big enough
@@ -4165,9 +4169,7 @@ zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhi
                                break;
                        }
                }
-
-               /* CONSTCOND */
-       } while (1);
+       }
 
        free(buf);
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to