char *his_buf);
extern int spa_history_log(spa_t *spa, const char *his_buf);
extern int spa_history_log_nvl(spa_t *spa, nvlist_t *nvl);
-extern void spa_history_log_version(spa_t *spa, const char *operation);
+extern void spa_history_log_version(spa_t *spa, const char *operation,
+ dmu_tx_t *tx);
extern void spa_history_log_internal(spa_t *spa, const char *operation,
dmu_tx_t *tx, const char *fmt, ...);
extern void spa_history_log_internal_ds(struct dsl_dataset *ds, const char *op,
#define ESC_ZFS_POOL_CREATE "pool_create"
#define ESC_ZFS_POOL_DESTROY "pool_destroy"
#define ESC_ZFS_POOL_IMPORT "pool_import"
+#define ESC_ZFS_POOL_EXPORT "pool_export"
#define ESC_ZFS_VDEV_ADD "vdev_add"
#define ESC_ZFS_VDEV_ATTACH "vdev_attach"
#define ESC_ZFS_VDEV_CLEAR "vdev_clear"
* Log the fact that we booted up (so that we can detect if
* we rebooted in the middle of an operation).
*/
- spa_history_log_version(spa, "open");
+ spa_history_log_version(spa, "open", NULL);
/*
* Delete any inconsistent datasets.
tx = dmu_tx_create_assigned(dp, txg);
+ /*
+ * Create the pool's history object.
+ */
+ if (version >= SPA_VERSION_ZPOOL_HISTORY && !spa->spa_history)
+ spa_history_create_obj(spa, tx);
+
+ spa_event_notify(spa, NULL, NULL, ESC_ZFS_POOL_CREATE);
+ spa_history_log_version(spa, "create", tx);
+
/*
* Create the pool config object.
*/
VERIFY3U(0, ==, bpobj_open(&spa->spa_deferred_bpobj,
spa->spa_meta_objset, obj));
- /*
- * Create the pool's history object.
- */
- if (version >= SPA_VERSION_ZPOOL_HISTORY)
- spa_history_create_obj(spa, tx);
-
/*
* Generate some random noise for salted checksums to operate on.
*/
VERIFY0(spa_keystore_remove_mapping(spa, root_dsobj, FTAG));
spa_config_sync(spa, B_FALSE, B_TRUE);
- spa_event_notify(spa, NULL, NULL, ESC_ZFS_POOL_CREATE);
-
- spa_history_log_version(spa, "create");
/*
* Don't count references from objsets that are already closed
*/
spa_async_request(spa, SPA_ASYNC_AUTOEXPAND);
- spa_history_log_version(spa, "import");
+ spa_history_log_version(spa, "import", NULL);
spa_event_notify(spa, NULL, NULL, ESC_ZFS_POOL_IMPORT);
}
export_spa:
- spa_event_notify(spa, NULL, NULL, ESC_ZFS_POOL_DESTROY);
+ if (new_state == POOL_STATE_DESTROYED)
+ spa_event_notify(spa, NULL, NULL, ESC_ZFS_POOL_DESTROY);
+ else if (new_state == POOL_STATE_EXPORTED)
+ spa_event_notify(spa, NULL, NULL, ESC_ZFS_POOL_EXPORT);
if (spa->spa_state != POOL_STATE_UNINITIALIZED) {
spa_unload(spa);
spa_history_phys_t *shpp;
objset_t *mos = spa->spa_meta_objset;
- ASSERT(spa->spa_history == 0);
+ ASSERT0(spa->spa_history);
spa->spa_history = dmu_object_alloc(mos, DMU_OT_SPA_HISTORY,
SPA_OLD_MAXBLOCKSIZE, DMU_OT_SPA_HISTORY_OFFSETS,
sizeof (spa_history_phys_t), tx);
- VERIFY(zap_add(mos, DMU_POOL_DIRECTORY_OBJECT,
+ VERIFY0(zap_add(mos, DMU_POOL_DIRECTORY_OBJECT,
DMU_POOL_HISTORY, sizeof (uint64_t), 1,
- &spa->spa_history, tx) == 0);
+ &spa->spa_history, tx));
- VERIFY(0 == dmu_bonus_hold(mos, spa->spa_history, FTAG, &dbp));
- ASSERT(dbp->db_size >= sizeof (spa_history_phys_t));
+ VERIFY0(dmu_bonus_hold(mos, spa->spa_history, FTAG, &dbp));
+ ASSERT3U(dbp->db_size, >=, sizeof (spa_history_phys_t));
shpp = dbp->db_data;
dmu_buf_will_dirty(dbp, tx);
* initialized yet, so don't bother logging the internal events.
* Likewise if the pool is not writeable.
*/
- if (tx->tx_txg == TXG_INITIAL || !spa_writeable(spa)) {
+ if (spa_is_initializing(spa) || !spa_writeable(spa)) {
fnvlist_free(nvl);
return;
}
}
void
-spa_history_log_version(spa_t *spa, const char *operation)
+spa_history_log_version(spa_t *spa, const char *operation, dmu_tx_t *tx)
{
utsname_t *u = utsname();
- spa_history_log_internal(spa, operation, NULL,
+ spa_history_log_internal(spa, operation, tx,
"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);
DEV_MPATHDIR="/dev/mapper"
ZEDLET_DIR="/var/tmp/zed"
+ ZED_LOG="$ZEDLET_DIR/zed.log"
+ ZED_DEBUG_LOG="$ZEDLET_DIR/zed.debug.log"
VDEVID_CONF="$ZEDLET_DIR/vdev_id.conf"
VDEVID_CONF_ETC="/etc/zfs/vdev_id.conf"
fi
export unpack_opts pack_opts verbose unpack_preserve pack_preserve \
ZVOL_DEVDIR ZVOL_RDEVDIR NEWFS_DEFAULT_FS DEV_RDSKDIR DEV_MPATHDIR \
- ZEDLET_DIR VDEVID_CONF VDEVID_CONF_ETC
+ ZEDLET_DIR ZED_LOG ZED_DEBUG_LOG VDEVID_CONF VDEVID_CONF_ETC
# Customize the zed.rc file to enable the full debug log.
log_must sed -i '/\#ZED_DEBUG_LOG=.*/d' $ZEDLET_DIR/zed.rc
- echo "ZED_DEBUG_LOG=$ZEDLET_DIR/zed.debug.log" >>$ZEDLET_DIR/zed.rc
+ echo "ZED_DEBUG_LOG=$ZED_DEBUG_LOG" >>$ZEDLET_DIR/zed.rc
+ # Scripts must only be user writable.
+ saved_umask=$(umask)
+ log_must umask 0022
log_must cp ${ZEDLET_LIBEXEC_DIR}/all-syslog.sh $ZEDLET_DIR
log_must cp ${ZEDLET_LIBEXEC_DIR}/all-debug.sh $ZEDLET_DIR
- log_must touch $ZEDLET_DIR/zed.debug.log
+ log_must umask $saved_umask
}
#
log_must rm -f ${ZEDLET_DIR}/zed-functions.sh
log_must rm -f ${ZEDLET_DIR}/all-syslog.sh
log_must rm -f ${ZEDLET_DIR}/all-debug.sh
- log_must rm -f ${ZEDLET_DIR}/zed.pid
- log_must rm -f ${ZEDLET_DIR}/zedlog
- log_must rm -f ${ZEDLET_DIR}/zed.debug.log
log_must rm -f ${ZEDLET_DIR}/state
+ log_must rm -f $ZED_LOG
+ log_must rm -f $ZED_DEBUG_LOG
log_must rm -f $VDEVID_CONF_ETC
log_must rm -f $VDEVID_CONF
rmdir $ZEDLET_DIR
log_note "Starting ZED"
# run ZED in the background and redirect foreground logging
- # output to zedlog
+ # output to $ZED_LOG.
+ log_must truncate -s 0 $ZED_DEBUG_LOG
log_must eval "zed -vF -d $ZEDLET_DIR -p $ZEDLET_DIR/zed.pid" \
- "-s $ZEDLET_DIR/state 2>${ZEDLET_DIR}/zedlog &"
+ "-s $ZEDLET_DIR/state 2>$ZED_LOG &"
return 0
}
log_note "Stopping ZED"
if [[ -f ${ZEDLET_DIR}/zed.pid ]]; then
zedpid=$(cat ${ZEDLET_DIR}/zed.pid)
- log_must kill $zedpid
+ kill $zedpid
+ wait $zedpid
+ rm -f ${ZEDLET_DIR}/zed.pid
fi
return 0
log_onexit cleanup
log_must truncate -s $MINVDEVSIZE $VDEV1 $VDEV2 $VDEV3 $VDEV4
+
+log_must zpool events -c
log_must zed_start
# Create a mirrored pool with two devices.
run_and_verify -p "$MPOOL" \
- -e "sysevent.fs.zfs.config_sync" \
-e "sysevent.fs.zfs.pool_create" \
+ -e "sysevent.fs.zfs.history_event" \
+ -e "sysevent.fs.zfs.config_sync" \
"zpool create $MPOOL mirror $VDEV1 $VDEV2"
+# Set a pool property.
+run_and_verify -p "$MPOOL" \
+ -e "sysevent.fs.zfs.history_event" \
+ "zpool set comment=string $MPOOL"
+
# Add a cache device then remove it.
run_and_verify -p "$MPOOL" \
-e "sysevent.fs.zfs.config_sync" \
-e "resource.fs.zfs.statechange" \
-e "sysevent.fs.zfs.config_sync" \
"zpool offline $MPOOL $VDEV1"
-run_and_verify -p "$MPOOL" \
+run_and_verify -p "$MPOOL" -d 10 \
-e "resource.fs.zfs.statechange" \
-e "sysevent.fs.zfs.vdev_online" \
+ -e "sysevent.fs.zfs.resilver_start" \
+ -e "sysevent.fs.zfs.resilver_finish" \
+ -e "sysevent.fs.zfs.history_event" \
-e "sysevent.fs.zfs.config_sync" \
"zpool online $MPOOL $VDEV1"
# Attach then detach a device from the mirror.
-run_and_verify -p "$MPOOL" \
- -e "sysevent.fs.zfs.vdev_attach" \
+run_and_verify -p "$MPOOL" -d 10 \
+ -e "sysevent.fs.zfs.vdev_attach" \
+ -e "sysevent.fs.zfs.resilver_start" \
+ -e "sysevent.fs.zfs.resilver_finish" \
+ -e "sysevent.fs.zfs.history_event" \
+ -e "sysevent.fs.zfs.config_sync" \
"zpool attach $MPOOL $VDEV1 $VDEV4"
run_and_verify -p "$MPOOL" \
-e "sysevent.fs.zfs.vdev_remove" \
"zpool detach $MPOOL $VDEV4"
# Replace a device
-run_and_verify -p "$MPOOL" \
+run_and_verify -p "$MPOOL" -d 10 \
-e "sysevent.fs.zfs.vdev_attach" \
-e "sysevent.fs.zfs.resilver_start" \
-e "sysevent.fs.zfs.resilver_finish" \
+ -e "sysevent.fs.zfs.vdev_remove" \
+ -e "sysevent.fs.zfs.history_event" \
-e "sysevent.fs.zfs.config_sync" \
"zpool replace -f $MPOOL $VDEV1 $VDEV4"
# Scrub a pool.
-run_and_verify -p "$MPOOL" \
+run_and_verify -p "$MPOOL" -d 10 \
-e "sysevent.fs.zfs.scrub_start" \
-e "sysevent.fs.zfs.scrub_finish" \
+ -e "sysevent.fs.zfs.history_event" \
"zpool scrub $MPOOL"
-# Export then import a pool (may change to a pool_export event)
+# Export then import a pool
run_and_verify -p "$MPOOL" \
- -e "sysevent.fs.zfs.pool_destroy" \
+ -e "sysevent.fs.zfs.pool_export" \
-e "sysevent.fs.zfs.config_sync" \
"zpool export $MPOOL"
run_and_verify -p "$MPOOL" \
-e "sysevent.fs.zfs.pool_import" \
+ -e "sysevent.fs.zfs.history_event" \
-e "sysevent.fs.zfs.config_sync" \
"zpool import -d $TEST_BASE_DIR $MPOOL"
# Verify ZED handles missed events from a pool when starting.
#
# STRATEGY:
-# 1. Create a pool and generate some events.
+# 1. Clear the events and create a pool to generate some events.
# 2. Start the ZED and verify it handles missed events.
# 3. Stop the ZED
# 4. Generate additional events.
done
log_must rm -f $TMP_EVENTS_ZED $TMP_EVENTS_ZED
- log_must rm -f $ZEDLET_DIR/zed.debug.log.old
log_must zed_stop
}
log_must truncate -s $MINVDEVSIZE $VDEV1 $VDEV2
# 1. Create a pool and generate some events.
-log_must cp -f $ZEDLET_DIR/zed.debug.log $ZEDLET_DIR/zed.debug.log.old
+log_must truncate -s 0 $ZED_DEBUG_LOG
+log_must zpool events -c
log_must zpool create $MPOOL mirror $VDEV1 $VDEV2
# 2. Start the ZED and verify it handles missed events.
log_must zed_start
-log_must sleep 1
-diff $ZEDLET_DIR/zed.debug.log.old $ZEDLET_DIR/zed.debug.log | \
- grep "^> " | sed 's/^> //g' >$TMP_EVENTS_ZED
-log_must awk -v event="sysevent.fs.zfs.pool_create" \
+log_must file_wait $ZED_DEBUG_LOG
+log_must cp $ZED_DEBUG_LOG $TMP_EVENTS_ZED
+
+awk -v event="sysevent.fs.zfs.pool_create" \
'BEGIN{FS="\n"; RS=""} $0 ~ event { print $0 }' \
$TMP_EVENTS_ZED >$TMP_EVENT_ZED
log_must grep -q "^ZEVENT_POOL=$MPOOL" $TMP_EVENT_ZED
# 3. Stop the ZED
zed_stop
+log_must truncate -s 0 $ZED_DEBUG_LOG
# 4. Generate additional events.
-log_must cp -f $ZEDLET_DIR/zed.debug.log $ZEDLET_DIR/zed.debug.log.old
log_must zpool offline $MPOOL $VDEV1
log_must zpool online $MPOOL $VDEV1
log_must zpool scrub $MPOOL
# 5. Start the ZED and verify it only handled the new missed events.
log_must zed_start
-log_must sleep 20
-diff $ZEDLET_DIR/zed.debug.log.old $ZEDLET_DIR/zed.debug.log | \
- grep "^> " | sed 's/^> //g' >$TMP_EVENTS_ZED
+log_must file_wait $ZED_DEBUG_LOG 15
+log_must cp $ZED_DEBUG_LOG $TMP_EVENTS_ZED
log_mustnot grep -q "sysevent.fs.zfs.pool_create" $TMP_EVENTS_ZED
log_must grep -q "sysevent.fs.zfs.vdev_online" $TMP_EVENTS_ZED
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/events/events.cfg
+#
+# Wait for up to 'timeout' seconds for the 'file' to settle, i.e.
+# not be updated for a period of 'delay' seconds.
+#
+function file_wait # file delay timeout
+{
+ file=$1
+ delay=${2:-3}
+ timeout=${3:-120}
+
+ SECONDS=0
+
+ while [ $(( $(date +%s) - $(stat -c %Y $file) )) -lt $delay ]; do
+ if [[ $SECONDS -gt $timeout ]]; then
+ return 1
+ fi
+
+ sleep 1
+ done
+
+ return 0;
+}
+
function run_and_verify
{
- typeset event pool
+ typeset delay event pool zedlog
set -A events
- while getopts "e:p:z:" opt; do
+ while getopts "d:e:p:z:" opt; do
case $opt in
+ d)
+ delay=$OPTARG
+ ;;
e)
events[${#events[*]}+1]=$OPTARG
;;
shift $(($OPTIND - 1))
pool=${pool:-$TESTPOOL}
- zedlog=${zedlog:-$ZEDLET_DIR/zed.debug.log}
+ delay=${delay:-3}
+ zedlog=${zedlog:-$ZED_DEBUG_LOG}
fullcmd="$1"
cmd=$(echo $fullcmd | awk '{print $1}')
subcmd=$(echo $fullcmd | awk '{print $2}')
[[ $cmd == "zpool" || $cmd == "zfs" ]] || \
log_fail "run_and_verify called with \"$cmd ($fullcmd)\""
- # Run the command as provided and collect the new events.
+ log_note "Checking events for command: '$fullcmd'"
+
+ # Remove any previous events from the logs.
log_must zpool events -c
- if [[ -f $zedlog ]]; then
- cp -f $zedlog $zedlog.old
- fi
+ log_must truncate -s 0 $zedlog
+ # Run the command as provided.
log_must eval "$fullcmd"
- log_must zpool events > $TMP_EVENTS 2>/dev/null
- log_must zpool events -v > $TMP_EVENTS_FULL 2>/dev/null
- if [[ -f $zedlog ]]; then
- sleep 5 # Brief delay for the ZED to handle the event.
- diff $zedlog.old $zedlog | grep "^> " | sed 's/^> //g' \
- >$TMP_EVENTS_ZED
- fi
+ # Collect the new events and verify there are some.
+ log_must zpool sync -f
+ log_must file_wait $zedlog $delay
+ log_must cp $zedlog $TMP_EVENTS_ZED
+ log_must eval "zpool events >$TMP_EVENTS 2>/dev/null"
+ log_must eval "zpool events -v > $TMP_EVENTS_FULL 2>/dev/null"
+
+ log_must test -s $TMP_EVENTS
+ log_must test -s $TMP_EVENTS_FULL
+ log_must test -s $TMP_EVENTS_ZED
+
+ log_note "Events generated:"
+ cat $TMP_EVENTS
# Verify all the expected events appear in the log.
for event in ${events[*]}; do
log_must grep -q "$event" $TMP_EVENTS
# Verify the event is in the verbose output with pool name.
- log_must awk -v event="$event" \
+ awk -v event="$event" \
'BEGIN{FS="\n"; RS=""} $0 ~ event { print $0 }' \
$TMP_EVENTS_FULL >$TMP_EVENT_FULL
log_must grep -q "pool = \"$pool\"" $TMP_EVENT_FULL
# Verify the event was received by the ZED and logged.
- log_must awk -v event="$event" \
+ awk -v event="$event" \
'BEGIN{FS="\n"; RS=""} $0 ~ event { print $0 }' \
$TMP_EVENTS_ZED >$TMP_EVENT_ZED
log_must grep -q "^ZEVENT_POOL=$pool" $TMP_EVENT_ZED
-
done
- log_must rm -f $TMP_EVENTS $TMP_EVENTS_FULL $TMP_EVENT_FULL \
- $TMP_EVENTS_ZED $TMP_EVENT_ZED $zedlog.old
+ rm -f $TMP_EVENTS $TMP_EVENTS_FULL $TMP_EVENT_FULL \
+ $TMP_EVENTS_ZED $TMP_EVENT_ZED
}