summaryrefslogtreecommitdiffstats
path: root/module/zfs/spa_history.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs/spa_history.c')
-rw-r--r--module/zfs/spa_history.c228
1 files changed, 140 insertions, 88 deletions
diff --git a/module/zfs/spa_history.c b/module/zfs/spa_history.c
index 9fb75f391..79d48620c 100644
--- a/module/zfs/spa_history.c
+++ b/module/zfs/spa_history.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011 by Delphix. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
*/
#include <sys/spa.h>
@@ -30,9 +30,12 @@
#include <sys/dsl_synctask.h>
#include <sys/dmu_tx.h>
#include <sys/dmu_objset.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_dir.h>
#include <sys/utsname.h>
#include <sys/cmn_err.h>
#include <sys/sunddi.h>
+#include <sys/cred.h>
#include "zfs_comutil.h"
#ifdef _KERNEL
#include <sys/zone.h>
@@ -185,7 +188,7 @@ spa_history_zone(void)
return (curproc->p_zone->zone_name);
#endif
#else
- return ("global");
+ return (NULL);
#endif
}
@@ -197,14 +200,12 @@ static void
spa_history_log_sync(void *arg1, void *arg2, dmu_tx_t *tx)
{
spa_t *spa = arg1;
- history_arg_t *hap = arg2;
- const char *history_str = hap->ha_history_str;
+ nvlist_t *nvl = arg2;
objset_t *mos = spa->spa_meta_objset;
dmu_buf_t *dbp;
spa_history_phys_t *shpp;
size_t reclen;
uint64_t le_len;
- nvlist_t *nvrecord;
char *record_packed = NULL;
int ret;
@@ -234,46 +235,36 @@ spa_history_log_sync(void *arg1, void *arg2, dmu_tx_t *tx)
}
#endif
- VERIFY(nvlist_alloc(&nvrecord, NV_UNIQUE_NAME, KM_PUSHPAGE) == 0);
- VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_TIME,
- gethrestime_sec()) == 0);
- VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_WHO, hap->ha_uid) == 0);
- if (hap->ha_zone != NULL)
- VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_ZONE,
- hap->ha_zone) == 0);
+ fnvlist_add_uint64(nvl, ZPOOL_HIST_TIME, gethrestime_sec());
#ifdef _KERNEL
- VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_HOST,
- utsname.nodename) == 0);
+ fnvlist_add_string(nvl, ZPOOL_HIST_HOST, utsname.nodename);
#endif
- if (hap->ha_log_type == LOG_CMD_POOL_CREATE ||
- hap->ha_log_type == LOG_CMD_NORMAL) {
- VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_CMD,
- history_str) == 0);
-
- zfs_dbgmsg("command: %s", history_str);
- } else {
- VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_INT_EVENT,
- hap->ha_event) == 0);
- VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_TXG,
- tx->tx_txg) == 0);
- VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_INT_STR,
- history_str) == 0);
-
- zfs_dbgmsg("internal %s pool:%s txg:%llu %s",
- zfs_history_event_names[hap->ha_event], spa_name(spa),
- (longlong_t)tx->tx_txg, history_str);
-
+ if (nvlist_exists(nvl, ZPOOL_HIST_CMD)) {
+ zfs_dbgmsg("command: %s",
+ fnvlist_lookup_string(nvl, ZPOOL_HIST_CMD));
+ } else if (nvlist_exists(nvl, ZPOOL_HIST_INT_NAME)) {
+ if (nvlist_exists(nvl, ZPOOL_HIST_DSNAME)) {
+ zfs_dbgmsg("txg %lld %s %s (id %llu) %s",
+ fnvlist_lookup_uint64(nvl, ZPOOL_HIST_TXG),
+ fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME),
+ fnvlist_lookup_string(nvl, ZPOOL_HIST_DSNAME),
+ fnvlist_lookup_uint64(nvl, ZPOOL_HIST_DSID),
+ fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR));
+ } else {
+ zfs_dbgmsg("txg %lld %s %s",
+ fnvlist_lookup_uint64(nvl, ZPOOL_HIST_TXG),
+ fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME),
+ fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR));
+ }
+ } else if (nvlist_exists(nvl, ZPOOL_HIST_IOCTL)) {
+ zfs_dbgmsg("ioctl %s",
+ fnvlist_lookup_string(nvl, ZPOOL_HIST_IOCTL));
}
- VERIFY(nvlist_size(nvrecord, &reclen, NV_ENCODE_XDR) == 0);
- record_packed = kmem_alloc(reclen, KM_PUSHPAGE);
-
- VERIFY(nvlist_pack(nvrecord, &record_packed, &reclen,
- NV_ENCODE_XDR, KM_PUSHPAGE) == 0);
+ VERIFY3U(nvlist_pack(nvl, &record_packed, &reclen, NV_ENCODE_NATIVE,
+ KM_PUSHPAGE), ==, 0);
mutex_enter(&spa->spa_history_lock);
- if (hap->ha_log_type == LOG_CMD_POOL_CREATE)
- VERIFY(shpp->sh_eof == shpp->sh_pool_create_len);
/* write out the packed length as little endian */
le_len = LE_64((uint64_t)reclen);
@@ -281,33 +272,44 @@ spa_history_log_sync(void *arg1, void *arg2, dmu_tx_t *tx)
if (!ret)
ret = spa_history_write(spa, record_packed, reclen, shpp, tx);
- if (!ret && hap->ha_log_type == LOG_CMD_POOL_CREATE) {
- shpp->sh_pool_create_len += sizeof (le_len) + reclen;
- shpp->sh_bof = shpp->sh_pool_create_len;
+ /* The first command is the create, which we keep forever */
+ if (ret == 0 && shpp->sh_pool_create_len == 0 &&
+ nvlist_exists(nvl, ZPOOL_HIST_CMD)) {
+ shpp->sh_pool_create_len = shpp->sh_bof = shpp->sh_eof;
}
mutex_exit(&spa->spa_history_lock);
- nvlist_free(nvrecord);
- kmem_free(record_packed, reclen);
+ fnvlist_pack_free(record_packed, reclen);
dmu_buf_rele(dbp, FTAG);
-
- strfree(hap->ha_history_str);
- if (hap->ha_zone != NULL)
- strfree(hap->ha_zone);
- kmem_free(hap, sizeof (history_arg_t));
+ fnvlist_free(nvl);
}
/*
* Write out a history event.
*/
int
-spa_history_log(spa_t *spa, const char *history_str, history_log_type_t what)
+spa_history_log(spa_t *spa, const char *msg)
+{
+ int err;
+ nvlist_t *nvl;
+
+ VERIFY0(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_PUSHPAGE));
+
+ fnvlist_add_string(nvl, ZPOOL_HIST_CMD, msg);
+ err = spa_history_log_nvl(spa, nvl);
+ fnvlist_free(nvl);
+ return (err);
+}
+
+int
+spa_history_log_nvl(spa_t *spa, nvlist_t *nvl)
{
- history_arg_t *ha;
int err = 0;
dmu_tx_t *tx;
+ nvlist_t *nvarg;
- ASSERT(what != LOG_INTERNAL);
+ if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY || !spa_writeable(spa))
+ return (EINVAL);
tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir);
err = dmu_tx_assign(tx, TXG_WAIT);
@@ -316,19 +318,21 @@ spa_history_log(spa_t *spa, const char *history_str, history_log_type_t what)
return (err);
}
- ha = kmem_alloc(sizeof (history_arg_t), KM_PUSHPAGE);
- ha->ha_history_str = strdup(history_str);
- ha->ha_zone = strdup(spa_history_zone());
- ha->ha_log_type = what;
- ha->ha_uid = crgetuid(CRED());
+ VERIFY0(nvlist_dup(nvl, &nvarg, KM_PUSHPAGE));
+ if (spa_history_zone() != NULL) {
+ fnvlist_add_string(nvarg, ZPOOL_HIST_ZONE,
+ spa_history_zone());
+ }
+ fnvlist_add_uint64(nvarg, ZPOOL_HIST_WHO, crgetruid(CRED()));
/* Kick this off asynchronously; errors are ignored. */
dsl_sync_task_do_nowait(spa_get_dsl(spa), NULL,
- spa_history_log_sync, spa, ha, 0, tx);
+ spa_history_log_sync, spa, nvarg, 0, tx);
dmu_tx_commit(tx);
- /* spa_history_log_sync will free ha and strings */
+ /* spa_history_log_sync will free nvl */
return (err);
+
}
/*
@@ -345,7 +349,7 @@ spa_history_get(spa_t *spa, uint64_t *offp, uint64_t *len, char *buf)
int err;
/*
- * If the command history doesn't exist (older pool),
+ * If the command history doesn't exist (older pool),
* that's ok, just return ENOENT.
*/
if (!spa->spa_history)
@@ -428,44 +432,54 @@ spa_history_get(spa_t *spa, uint64_t *offp, uint64_t *len, char *buf)
return (err);
}
+/*
+ * The nvlist will be consumed by this call.
+ */
static void
-log_internal(history_internal_events_t event, spa_t *spa,
+log_internal(nvlist_t *nvl, const char *operation, spa_t *spa,
dmu_tx_t *tx, const char *fmt, va_list adx)
{
- history_arg_t *ha;
- va_list adx_copy;
+ char *msg;
+ va_list adx1;
/*
* If this is part of creating a pool, not everything is
* initialized yet, so don't bother logging the internal events.
+ * Likewise if the pool is not writeable.
*/
- if (tx->tx_txg == TXG_INITIAL)
+ if (tx->tx_txg == TXG_INITIAL || !spa_writeable(spa)) {
+ fnvlist_free(nvl);
return;
+ }
- ha = kmem_alloc(sizeof (history_arg_t), KM_PUSHPAGE);
- va_copy(adx_copy, adx);
- ha->ha_history_str = kmem_vasprintf(fmt, adx_copy);
- va_end(adx_copy);
- ha->ha_log_type = LOG_INTERNAL;
- ha->ha_event = event;
- ha->ha_zone = NULL;
- ha->ha_uid = 0;
+ va_copy(adx1, adx);
+ msg = kmem_alloc(vsnprintf(NULL, 0, fmt, adx1) + 1, KM_PUSHPAGE);
+ va_end(adx1);
+ va_copy(adx1, adx);
+ (void) vsprintf(msg, fmt, adx1);
+ va_end(adx1);
+ fnvlist_add_string(nvl, ZPOOL_HIST_INT_STR, msg);
+ strfree(msg);
+
+ fnvlist_add_string(nvl, ZPOOL_HIST_INT_NAME, operation);
+ fnvlist_add_uint64(nvl, ZPOOL_HIST_TXG, tx->tx_txg);
if (dmu_tx_is_syncing(tx)) {
- spa_history_log_sync(spa, ha, tx);
+ spa_history_log_sync(spa, nvl, tx);
} else {
dsl_sync_task_do_nowait(spa_get_dsl(spa), NULL,
- spa_history_log_sync, spa, ha, 0, tx);
+ spa_history_log_sync, spa, nvl, 0, tx);
}
- /* spa_history_log_sync() will free ha and strings */
+ /* spa_history_log_sync() will free nvl */
}
void
-spa_history_log_internal(history_internal_events_t event, spa_t *spa,
+spa_history_log_internal(spa_t *spa, const char *operation,
dmu_tx_t *tx, const char *fmt, ...)
{
dmu_tx_t *htx = tx;
va_list adx;
+ nvlist_t *nvl;
/* create a tx if we didn't get one */
if (tx == NULL) {
@@ -477,7 +491,8 @@ spa_history_log_internal(history_internal_events_t event, spa_t *spa,
}
va_start(adx, fmt);
- log_internal(event, spa, htx, fmt, adx);
+ VERIFY0(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_PUSHPAGE));
+ log_internal(nvl, operation, spa, htx, fmt, adx);
va_end(adx);
/* if we didn't get a tx from the caller, commit the one we made */
@@ -486,21 +501,58 @@ spa_history_log_internal(history_internal_events_t event, spa_t *spa,
}
void
-spa_history_log_version(spa_t *spa, history_internal_events_t event)
+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];
+ nvlist_t *nvl;
+
+ ASSERT(tx != NULL);
+
+ dsl_dataset_name(ds, namebuf);
+ VERIFY0(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_PUSHPAGE));
+ fnvlist_add_string(nvl, ZPOOL_HIST_DSNAME, namebuf);
+ fnvlist_add_uint64(nvl, ZPOOL_HIST_DSID, ds->ds_object);
+
+ va_start(adx, fmt);
+ log_internal(nvl, operation, dsl_dataset_get_spa(ds), tx, fmt, adx);
+ va_end(adx);
+}
+
+void
+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];
+ nvlist_t *nvl;
+
+ ASSERT(tx != NULL);
+
+ dsl_dir_name(dd, namebuf);
+ VERIFY0(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_PUSHPAGE));
+ fnvlist_add_string(nvl, ZPOOL_HIST_DSNAME, namebuf);
+ fnvlist_add_uint64(nvl, ZPOOL_HIST_DSID,
+ dd->dd_phys->dd_head_dataset_obj);
+
+ va_start(adx, fmt);
+ log_internal(nvl, operation, dd->dd_pool->dp_spa, tx, fmt, adx);
+ va_end(adx);
+}
+
+void
+spa_history_log_version(spa_t *spa, const char *operation)
{
#ifdef _KERNEL
uint64_t current_vers = spa_version(spa);
- if (current_vers >= SPA_VERSION_ZPOOL_HISTORY) {
- spa_history_log_internal(event, spa, NULL,
- "pool spa %llu; zfs spa %llu; zpl %d; uts %s %s %s %s",
- (u_longlong_t)current_vers, SPA_VERSION, ZPL_VERSION,
- utsname.nodename, utsname.release, utsname.version,
- utsname.machine);
- }
- cmn_err(CE_CONT, "!%s version %llu pool %s using %llu",
- event == LOG_POOL_IMPORT ? "imported" :
- event == LOG_POOL_CREATE ? "created" : "accessed",
+ spa_history_log_internal(spa, operation, NULL,
+ "pool version %llu; software version %llu/%d; uts %s %s %s %s",
+ (u_longlong_t)current_vers, SPA_VERSION, ZPL_VERSION,
+ utsname.nodename, utsname.release, utsname.version,
+ utsname.machine);
+ cmn_err(CE_CONT, "!%s version %llu pool %s using %llu", operation,
(u_longlong_t)current_vers, spa_name(spa), SPA_VERSION);
#endif
}