Print this page
2882 implement libzfs_core
2883 changing "canmount" property to "on" should not always remount dataset
2900 "zfs snapshot" should be able to create multiple, arbitrary snapshots at once
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Chris Siden <christopher.siden@delphix.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Bill Pijewski <wdp@joyent.com>
Reviewed by: Dan Kruchinin <dan.kruchinin@gmail.com>

@@ -183,13 +183,13 @@
         { "set",        zpool_do_set,           HELP_SET                },
 };
 
 #define NCOMMAND        (sizeof (command_table) / sizeof (command_table[0]))
 
-zpool_command_t *current_command;
+static zpool_command_t *current_command;
 static char history_str[HIS_MAX_RECORD_LEN];
-
+static boolean_t log_history = B_TRUE;
 static uint_t timestamp_fmt = NODATE;
 
 static const char *
 get_usage(zpool_help_t idx) {
         switch (idx) {

@@ -933,11 +933,14 @@
                 (void) fprintf(stderr, gettext("could not destroy '%s': "
                     "could not unmount datasets\n"), zpool_get_name(zhp));
                 return (1);
         }
 
-        ret = (zpool_destroy(zhp) != 0);
+        /* The history must be logged as part of the export */
+        log_history = B_FALSE;
+
+        ret = (zpool_destroy(zhp, history_str) != 0);
 
         zpool_close(zhp);
 
         return (ret);
 }

@@ -997,14 +1000,17 @@
                         ret = 1;
                         zpool_close(zhp);
                         continue;
                 }
 
+                /* The history must be logged as part of the export */
+                log_history = B_FALSE;
+
                 if (hardforce) {
-                        if (zpool_export_force(zhp) != 0)
+                        if (zpool_export_force(zhp, history_str) != 0)
                                 ret = 1;
-                } else if (zpool_export(zhp, force) != 0) {
+                } else if (zpool_export(zhp, force, history_str) != 0) {
                         ret = 1;
                 }
 
                 zpool_close(zhp);
         }

@@ -4267,10 +4273,18 @@
                         ret = zpool_upgrade(zhp, cbp->cb_version);
                         if (!ret) {
                                 (void) printf(gettext("Successfully upgraded "
                                     "'%s'\n\n"), zpool_get_name(zhp));
                         }
+                        /*
+                         * If they did "zpool upgrade -a", then we could
+                         * be doing ioctls to different pools.  We need
+                         * to log this history once to each pool, and bypass
+                         * the normal history logging that happens in main().
+                         */
+                        (void) zpool_log_history(g_zfs, history_str);
+                        log_history = B_FALSE;
                 }
         } else if (cbp->cb_newer && !SPA_VERSION_IS_SUPPORTED(version)) {
                 assert(!cbp->cb_all);
 
                 if (cbp->cb_first) {

@@ -4489,12 +4503,12 @@
         return (ret);
 }
 
 typedef struct hist_cbdata {
         boolean_t first;
-        int longfmt;
-        int internal;
+        boolean_t longfmt;
+        boolean_t internal;
 } hist_cbdata_t;
 
 /*
  * Print out the command history for a specific pool.
  */

@@ -4502,25 +4516,12 @@
 get_history_one(zpool_handle_t *zhp, void *data)
 {
         nvlist_t *nvhis;
         nvlist_t **records;
         uint_t numrecords;
-        char *cmdstr;
-        char *pathstr;
-        uint64_t dst_time;
-        time_t tsec;
-        struct tm t;
-        char tbuf[30];
         int ret, i;
-        uint64_t who;
-        struct passwd *pwd;
-        char *hostname;
-        char *zonename;
-        char internalstr[MAXPATHLEN];
         hist_cbdata_t *cb = (hist_cbdata_t *)data;
-        uint64_t txg;
-        uint64_t ievent;
 
         cb->first = B_FALSE;
 
         (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
 

@@ -4528,68 +4529,98 @@
                 return (ret);
 
         verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
             &records, &numrecords) == 0);
         for (i = 0; i < numrecords; i++) {
-                if (nvlist_lookup_uint64(records[i], ZPOOL_HIST_TIME,
-                    &dst_time) != 0)
-                        continue;
+                nvlist_t *rec = records[i];
+                char tbuf[30] = "";
 
-                /* is it an internal event or a standard event? */
-                if (nvlist_lookup_string(records[i], ZPOOL_HIST_CMD,
-                    &cmdstr) != 0) {
-                        if (cb->internal == 0)
-                                continue;
+                if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
+                        time_t tsec;
+                        struct tm t;
+
+                        tsec = fnvlist_lookup_uint64(records[i],
+                            ZPOOL_HIST_TIME);
+                        (void) localtime_r(&tsec, &t);
+                        (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
+                }
 
-                        if (nvlist_lookup_uint64(records[i],
-                            ZPOOL_HIST_INT_EVENT, &ievent) != 0)
+                if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
+                        (void) printf("%s %s", tbuf,
+                            fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
+                } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
+                        int ievent =
+                            fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
+                        if (!cb->internal)
                                 continue;
-                        verify(nvlist_lookup_uint64(records[i],
-                            ZPOOL_HIST_TXG, &txg) == 0);
-                        verify(nvlist_lookup_string(records[i],
-                            ZPOOL_HIST_INT_STR, &pathstr) == 0);
-                        if (ievent >= LOG_END)
+                        if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
+                                (void) printf("%s unrecognized record:\n",
+                                    tbuf);
+                                dump_nvlist(rec, 4);
                                 continue;
-                        (void) snprintf(internalstr,
-                            sizeof (internalstr),
-                            "[internal %s txg:%lld] %s",
-                            zfs_history_event_names[ievent], txg,
-                            pathstr);
-                        cmdstr = internalstr;
                 }
-                tsec = dst_time;
-                (void) localtime_r(&tsec, &t);
-                (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
-                (void) printf("%s %s", tbuf, cmdstr);
+                        (void) printf("%s [internal %s txg:%lld] %s", tbuf,
+                            zfs_history_event_names[ievent],
+                            fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
+                            fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
+                } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
+                        if (!cb->internal)
+                                continue;
+                        (void) printf("%s [txg:%lld] %s", tbuf,
+                            fnvlist_lookup_uint64(rec, ZPOOL_HIST_TXG),
+                            fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
+                        if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
+                                (void) printf(" %s (%llu)",
+                                    fnvlist_lookup_string(rec,
+                                    ZPOOL_HIST_DSNAME),
+                                    fnvlist_lookup_uint64(rec,
+                                    ZPOOL_HIST_DSID));
+                        }
+                        (void) printf(" %s", fnvlist_lookup_string(rec,
+                            ZPOOL_HIST_INT_STR));
+                } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
+                        if (!cb->internal)
+                                continue;
+                        (void) printf("%s ioctl %s\n", tbuf,
+                            fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
+                        if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
+                                (void) printf("    input:\n");
+                                dump_nvlist(fnvlist_lookup_nvlist(rec,
+                                    ZPOOL_HIST_INPUT_NVL), 8);
+                        }
+                        if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
+                                (void) printf("    output:\n");
+                                dump_nvlist(fnvlist_lookup_nvlist(rec,
+                                    ZPOOL_HIST_OUTPUT_NVL), 8);
+                        }
+                } else {
+                        if (!cb->internal)
+                                continue;
+                        (void) printf("%s unrecognized record:\n", tbuf);
+                        dump_nvlist(rec, 4);
+                }
 
                 if (!cb->longfmt) {
                         (void) printf("\n");
                         continue;
                 }
                 (void) printf(" [");
-                if (nvlist_lookup_uint64(records[i],
-                    ZPOOL_HIST_WHO, &who) == 0) {
-                        pwd = getpwuid((uid_t)who);
-                        if (pwd)
-                                (void) printf("user %s on",
-                                    pwd->pw_name);
-                        else
-                                (void) printf("user %d on",
-                                    (int)who);
-                } else {
-                        (void) printf(gettext("no info]\n"));
-                        continue;
-                }
-                if (nvlist_lookup_string(records[i],
-                    ZPOOL_HIST_HOST, &hostname) == 0) {
-                        (void) printf(" %s", hostname);
-                }
-                if (nvlist_lookup_string(records[i],
-                    ZPOOL_HIST_ZONE, &zonename) == 0) {
-                        (void) printf(":%s", zonename);
+                if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
+                        uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
+                        struct passwd *pwd = getpwuid(who);
+                        (void) printf("user %d ", (int)who);
+                        if (pwd != NULL)
+                                (void) printf("(%s) ", pwd->pw_name);
+                }
+                if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
+                        (void) printf("on %s",
+                            fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
+                }
+                if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
+                        (void) printf(":%s",
+                            fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
                 }
-
                 (void) printf("]");
                 (void) printf("\n");
         }
         (void) printf("\n");
         nvlist_free(nvhis);

@@ -4600,12 +4631,10 @@
 /*
  * zpool history <pool>
  *
  * Displays the history of commands that modified pools.
  */
-
-
 int
 zpool_do_history(int argc, char **argv)
 {
         hist_cbdata_t cbdata = { 0 };
         int ret;

@@ -4614,14 +4643,14 @@
         cbdata.first = B_TRUE;
         /* check options */
         while ((c = getopt(argc, argv, "li")) != -1) {
                 switch (c) {
                 case 'l':
-                        cbdata.longfmt = 1;
+                        cbdata.longfmt = B_TRUE;
                         break;
                 case 'i':
-                        cbdata.internal = 1;
+                        cbdata.internal = B_TRUE;
                         break;
                 case '?':
                         (void) fprintf(stderr, gettext("invalid option '%c'\n"),
                             optopt);
                         usage(B_FALSE);

@@ -4842,12 +4871,11 @@
          * Special case '-?'
          */
         if (strcmp(cmdname, "-?") == 0)
                 usage(B_TRUE);
 
-        zpool_set_history_str("zpool", argc, argv, history_str);
-        verify(zpool_stage_history(g_zfs, history_str) == 0);
+        zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
 
         /*
          * Run the appropriate command.
          */
         if (find_command_idx(cmdname, &i) == 0) {

@@ -4870,10 +4898,13 @@
                 (void) fprintf(stderr, gettext("unrecognized "
                     "command '%s'\n"), cmdname);
                 usage(B_FALSE);
         }
 
+        if (ret == 0 && log_history)
+                (void) zpool_log_history(g_zfs, history_str);
+
         libzfs_fini(g_zfs);
 
         /*
          * The 'ZFS_ABORT' environment variable causes us to dump core on exit
          * for the purposes of running ::findleaks.