Author: delphij
Date: Mon Apr 14 18:38:14 2014
New Revision: 264467
URL: http://svnweb.freebsd.org/changeset/base/264467

Log:
  Take into account when zpool history block grows exceeding 128KB in zpool(8)
  and zdb(8) by growing the buffer on demand with a cap of 1GB (specified in
  spa_history_create_obj()).
  
  PR:           bin/186574
  Submitted by: Andrew Childs <lorne cons org nz> (with changes)
  MFC after:    2 weeks

Modified:
  head/cddl/contrib/opensolaris/cmd/zdb/zdb.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c

Modified: head/cddl/contrib/opensolaris/cmd/zdb/zdb.c
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zdb/zdb.c Mon Apr 14 18:14:09 2014        
(r264466)
+++ head/cddl/contrib/opensolaris/cmd/zdb/zdb.c Mon Apr 14 18:38:14 2014        
(r264467)
@@ -929,11 +929,16 @@ dump_dtl(vdev_t *vd, int indent)
                dump_dtl(vd->vdev_child[c], indent + 4);
 }
 
+/* from spa_history.c: spa_history_create_obj() */
+#define        HIS_BUF_LEN_DEF (128 << 10)
+#define        HIS_BUF_LEN_MAX (1 << 30)
+
 static void
 dump_history(spa_t *spa)
 {
        nvlist_t **events = NULL;
-       char buf[SPA_MAXBLOCKSIZE];
+       char *buf = NULL;
+       uint64_t bufsize = HIS_BUF_LEN_DEF;
        uint64_t resid, len, off = 0;
        uint_t num = 0;
        int error;
@@ -942,8 +947,11 @@ dump_history(spa_t *spa)
        char tbuf[30];
        char internalstr[MAXPATHLEN];
 
+       if ((buf = malloc(bufsize)) == NULL)
+               (void) fprintf(stderr, "Unable to read history: "
+                   "out of memory\n");
        do {
-               len = sizeof (buf);
+               len = bufsize;
 
                if ((error = spa_history_get(spa, &off, &len, buf)) != 0) {
                        (void) fprintf(stderr, "Unable to read history: "
@@ -953,9 +961,26 @@ dump_history(spa_t *spa)
 
                if (zpool_history_unpack(buf, len, &resid, &events, &num) != 0)
                        break;
-
                off -= resid;
+
+               /*
+                * If the history block is too big, double the buffer
+                * size and try again.
+                */
+               if (resid == len) {
+                       free(buf);
+                       buf = NULL;
+
+                       bufsize <<= 1;
+                       if ((bufsize >= HIS_BUF_LEN_MAX) ||
+                           ((buf = malloc(bufsize)) == NULL)) {
+                               (void) fprintf(stderr, "Unable to read history: 
"
+                                   "out of memory\n");
+                               return;
+                       }
+               }
        } while (len != 0);
+       free(buf);
 
        (void) printf("\nHistory:\n");
        for (int i = 0; i < num; i++) {

Modified: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c       Mon Apr 
14 18:14:09 2014        (r264466)
+++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_pool.c       Mon Apr 
14 18:38:14 2014        (r264467)
@@ -3744,7 +3744,9 @@ zpool_history_unpack(char *buf, uint64_t
        return (0);
 }
 
-#define        HIS_BUF_LEN     (128*1024)
+/* from spa_history.c: spa_history_create_obj() */
+#define        HIS_BUF_LEN_DEF (128 << 10)
+#define        HIS_BUF_LEN_MAX (1 << 30)
 
 /*
  * Retrieve the command history of a pool.
@@ -3752,21 +3754,24 @@ zpool_history_unpack(char *buf, uint64_t
 int
 zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
 {
-       char buf[HIS_BUF_LEN];
+       char *buf = NULL;
+       uint64_t bufsize = HIS_BUF_LEN_DEF;
        uint64_t off = 0;
        nvlist_t **records = NULL;
        uint_t numrecords = 0;
        int err, i;
 
+       if ((buf = malloc(bufsize)) == NULL)
+               return (ENOMEM);
        do {
-               uint64_t bytes_read = sizeof (buf);
+               uint64_t bytes_read = bufsize;
                uint64_t leftover;
 
                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)
+               if (bytes_read == 0)
                        break;
 
                if ((err = zpool_history_unpack(buf, bytes_read,
@@ -3774,8 +3779,25 @@ zpool_get_history(zpool_handle_t *zhp, n
                        break;
                off -= leftover;
 
+               /*
+                * If the history block is too big, double the buffer
+                * size and try again.
+                */
+               if (leftover == bytes_read) {
+                       free(buf);
+                       buf = NULL;
+
+                       bufsize <<= 1;
+                       if ((bufsize >= HIS_BUF_LEN_MAX) ||
+                           ((buf = malloc(bufsize)) == NULL)) {
+                               err = ENOMEM;
+                               break;
+                       }
+               }
+
                /* CONSTCOND */
        } while (1);
+       free(buf);
 
        if (!err) {
                verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to