]> git.proxmox.com Git - mirror_zfs-debian.git/blobdiff - module/zfs/spa_history.c
New upstream version 0.7.2
[mirror_zfs-debian.git] / module / zfs / spa_history.c
index 01aa4641e63fe50483fc949973e5ccbf3d2d785f..73571c03259832170bc7070b53cefcc389687e70 100644 (file)
@@ -21,7 +21,9 @@
 
 /*
  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2014 Integros [integros.com]
+ * Copyright 2017 Joyent, Inc.
  */
 
 #include <sys/spa.h>
@@ -46,7 +48,7 @@
  * The history log is stored as a dmu object containing
  * <packed record length, record nvlist> tuples.
  *
- * Where "record nvlist" is a nvlist containing uint64_ts and strings, and
+ * Where "record nvlist" is an nvlist containing uint64_ts and strings, and
  * "packed record length" is the packed length of the "record nvlist" stored
  * as a little endian uint64_t.
  *
@@ -191,6 +193,71 @@ spa_history_zone(void)
 #endif
 }
 
+/*
+ * Post a history sysevent.
+ *
+ * The nvlist_t* passed into this function will be transformed into a new
+ * nvlist where:
+ *
+ * 1. Nested nvlists will be flattened to a single level
+ * 2. Keys will have their names normalized (to remove any problematic
+ * characters, such as whitespace)
+ *
+ * The nvlist_t passed into this function will duplicated and should be freed
+ * by caller.
+ *
+ */
+static void
+spa_history_log_notify(spa_t *spa, nvlist_t *nvl)
+{
+       nvlist_t *hist_nvl = fnvlist_alloc();
+       uint64_t uint64;
+       char *string;
+
+       if (nvlist_lookup_string(nvl, ZPOOL_HIST_CMD, &string) == 0)
+               fnvlist_add_string(hist_nvl, ZFS_EV_HIST_CMD, string);
+
+       if (nvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME, &string) == 0)
+               fnvlist_add_string(hist_nvl, ZFS_EV_HIST_INT_NAME, string);
+
+       if (nvlist_lookup_string(nvl, ZPOOL_HIST_ZONE, &string) == 0)
+               fnvlist_add_string(hist_nvl, ZFS_EV_HIST_ZONE, string);
+
+       if (nvlist_lookup_string(nvl, ZPOOL_HIST_HOST, &string) == 0)
+               fnvlist_add_string(hist_nvl, ZFS_EV_HIST_HOST, string);
+
+       if (nvlist_lookup_string(nvl, ZPOOL_HIST_DSNAME, &string) == 0)
+               fnvlist_add_string(hist_nvl, ZFS_EV_HIST_DSNAME, string);
+
+       if (nvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR, &string) == 0)
+               fnvlist_add_string(hist_nvl, ZFS_EV_HIST_INT_STR, string);
+
+       if (nvlist_lookup_string(nvl, ZPOOL_HIST_IOCTL, &string) == 0)
+               fnvlist_add_string(hist_nvl, ZFS_EV_HIST_IOCTL, string);
+
+       if (nvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME, &string) == 0)
+               fnvlist_add_string(hist_nvl, ZFS_EV_HIST_INT_NAME, string);
+
+       if (nvlist_lookup_uint64(nvl, ZPOOL_HIST_DSID, &uint64) == 0)
+               fnvlist_add_uint64(hist_nvl, ZFS_EV_HIST_DSID, uint64);
+
+       if (nvlist_lookup_uint64(nvl, ZPOOL_HIST_TXG, &uint64) == 0)
+               fnvlist_add_uint64(hist_nvl, ZFS_EV_HIST_TXG, uint64);
+
+       if (nvlist_lookup_uint64(nvl, ZPOOL_HIST_TIME, &uint64) == 0)
+               fnvlist_add_uint64(hist_nvl, ZFS_EV_HIST_TIME, uint64);
+
+       if (nvlist_lookup_uint64(nvl, ZPOOL_HIST_WHO, &uint64) == 0)
+               fnvlist_add_uint64(hist_nvl, ZFS_EV_HIST_WHO, uint64);
+
+       if (nvlist_lookup_uint64(nvl, ZPOOL_HIST_INT_EVENT, &uint64) == 0)
+               fnvlist_add_uint64(hist_nvl, ZFS_EV_HIST_INT_EVENT, uint64);
+
+       spa_event_notify(spa, NULL, hist_nvl, ESC_ZFS_HISTORY_EVENT);
+
+       nvlist_free(hist_nvl);
+}
+
 /*
  * Write out a history event.
  */
@@ -254,6 +321,22 @@ spa_history_log_sync(void *arg, dmu_tx_t *tx)
                            fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME),
                            fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR));
                }
+               /*
+                * The history sysevent is posted only for internal history
+                * messages to show what has happened, not how it happened. For
+                * example, the following command:
+                *
+                * # zfs destroy -r tank/foo
+                *
+                * will result in one sysevent posted per dataset that is
+                * destroyed as a result of the command - which could be more
+                * than one event in total.  By contrast, if the sysevent was
+                * posted as a result of the ZPOOL_HIST_CMD key being present
+                * it would result in only one sysevent being posted with the
+                * full command line arguments, requiring the consumer to know
+                * how to parse and understand zfs(1M) command invocations.
+                */
+               spa_history_log_notify(spa, nvl);
        } else if (nvlist_exists(nvl, ZPOOL_HIST_IOCTL)) {
                zfs_dbgmsg("ioctl %s",
                    fnvlist_lookup_string(nvl, ZPOOL_HIST_IOCTL));
@@ -493,7 +576,7 @@ spa_history_log_internal_ds(dsl_dataset_t *ds, const char *operation,
     dmu_tx_t *tx, const char *fmt, ...)
 {
        va_list adx;
-       char namebuf[MAXNAMELEN];
+       char namebuf[ZFS_MAX_DATASET_NAME_LEN];
        nvlist_t *nvl = fnvlist_alloc();
 
        ASSERT(tx != NULL);
@@ -512,7 +595,7 @@ spa_history_log_internal_dd(dsl_dir_t *dd, const char *operation,
     dmu_tx_t *tx, const char *fmt, ...)
 {
        va_list adx;
-       char namebuf[MAXNAMELEN];
+       char namebuf[ZFS_MAX_DATASET_NAME_LEN];
        nvlist_t *nvl = fnvlist_alloc();
 
        ASSERT(tx != NULL);
@@ -533,7 +616,7 @@ spa_history_log_version(spa_t *spa, const char *operation)
        utsname_t *u = utsname();
 
        spa_history_log_internal(spa, operation, NULL,
-           "pool version %llu; software version %llu/%d; uts %s %s %s %s",
+           "pool version %llu; software version %llu/%llu; uts %s %s %s %s",
            (u_longlong_t)spa_version(spa), SPA_VERSION, ZPL_VERSION,
            u->nodename, u->release, u->version, u->machine);
 }