@@ -56,3 +56,4 @@ test/smart-notify
test/fio.job
test/local-write-0-verify.state
test/ack-shutdown-count-set
+test/list-smart-dimm
@@ -21,7 +21,8 @@ TESTS =\
btt-pad-compat.sh \
firmware-update.sh \
ack-shutdown-count-set \
- rescan-partitions.sh
+ rescan-partitions.sh \
+ monitor.sh
check_PROGRAMS =\
libndctl \
@@ -34,7 +35,8 @@ check_PROGRAMS =\
smart-listen \
hugetlb \
daxdev-errors \
- ack-shutdown-count-set
+ ack-shutdown-count-set \
+ list-smart-dimm
if ENABLE_DESTRUCTIVE
TESTS +=\
@@ -151,3 +153,11 @@ multi_pmem_LDADD = \
$(UUID_LIBS) \
$(KMOD_LIBS) \
../libutil.a
+
+list_smart_dimm_SOURCES = \
+ list-smart-dimm.c \
+ ../util/json.c
+list_smart_dimm_LDADD = \
+ $(LIBNDCTL_LIB) \
+ $(JSON_LIBS) \
+ ../libutil.a
new file mode 100644
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2018, FUJITSU LIMITED. All rights reserved. */
+
+#include <stdio.h>
+#include <errno.h>
+#include <util/json.h>
+#include <util/filter.h>
+#include <json-c/json.h>
+#include <ndctl/libndctl.h>
+#include <util/parse-options.h>
+#include <ndctl.h>
+
+struct util_filter_params param;
+static int did_fail;
+static int jflag = JSON_C_TO_STRING_PRETTY;
+
+#define fail(fmt, ...) \
+do { \
+ did_fail = 1; \
+ fprintf(stderr, "ndctl-%s:%s:%d: " fmt, \
+ VERSION, __func__, __LINE__, ##__VA_ARGS__); \
+} while (0)
+
+static bool filter_region(struct ndctl_region *region,
+ struct util_filter_ctx *ctx)
+{
+ return true;
+}
+
+static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx)
+{
+ struct list_filter_arg *lfa = ctx->list;
+ struct json_object *jdimm;
+
+ if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_SMART))
+ return;
+ if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_SMART_THRESHOLD))
+ return;
+ if (!ndctl_dimm_is_flag_supported(dimm, ND_SMART_ALARM_VALID))
+ return;
+
+ if (!lfa->jdimms) {
+ lfa->jdimms = json_object_new_array();
+ if (!lfa->jdimms) {
+ fail("\n");
+ return;
+ }
+ }
+
+ jdimm = util_dimm_to_json(dimm, lfa->flags);
+ if (!jdimm) {
+ fail("\n");
+ return;
+ }
+
+ json_object_array_add(lfa->jdimms, jdimm);
+}
+
+static bool filter_bus(struct ndctl_bus *bus, struct util_filter_ctx *ctx)
+{
+ return true;
+}
+
+static int list_display(struct list_filter_arg *lfa)
+{
+ struct json_object *jdimms = lfa->jdimms;
+
+ if (jdimms)
+ util_display_json_array(stdout, jdimms, jflag);
+ return 0;
+}
+
+int main(int argc, const char *argv[])
+{
+ struct ndctl_ctx *ctx;
+ int i, rc;
+ const struct option options[] = {
+ OPT_STRING('b', "bus", ¶m.bus, "bus-id", "filter by bus"),
+ OPT_STRING('r', "region", ¶m.region, "region-id",
+ "filter by region"),
+ OPT_STRING('d', "dimm", ¶m.dimm, "dimm-id",
+ "filter by dimm"),
+ OPT_STRING('n', "namespace", ¶m.namespace, "namespace-id",
+ "filter by namespace id"),
+ OPT_END(),
+ };
+ const char * const u[] = {
+ "list-smart-dimm [<options>]",
+ NULL
+ };
+ struct util_filter_ctx fctx = { 0 };
+ struct list_filter_arg lfa = { 0 };
+
+ rc = ndctl_new(&ctx);
+ if (rc < 0)
+ return EXIT_FAILURE;
+ argc = parse_options(argc, argv, options, u, 0);
+ for (i = 0; i < argc; i++)
+ error("unknown parameter \"%s\"\n", argv[i]);
+ if (argc)
+ usage_with_options(u, options);
+
+ fctx.filter_bus = filter_bus;
+ fctx.filter_dimm = filter_dimm;
+ fctx.filter_region = filter_region;
+ fctx.filter_namespace = NULL;
+ fctx.list = &lfa;
+ lfa.flags = 0;
+
+ rc = util_filter_walk(ctx, &fctx, ¶m);
+ if (rc)
+ return rc;
+
+ if (list_display(&lfa) || did_fail)
+ return -ENOMEM;
+ return 0;
+}
new file mode 100755
@@ -0,0 +1,176 @@
+#!/bin/bash -Ex
+
+# SPDX-License-Identifier: GPL-2.0
+# Copyright(c) 2018, FUJITSU LIMITED. All rights reserved.
+
+rc=77
+monitor_pid=65536
+logfile=""
+conf_file=""
+monitor_dimms=""
+monitor_regions=""
+monitor_namespace=""
+smart_supported_bus=""
+
+. ./common
+
+trap 'err $LINENO' ERR
+
+check_min_kver "4.15" || do_skip "kernel $KVER may not support monitor service"
+
+init()
+{
+ $NDCTL disable-region -b $NFIT_TEST_BUS0 all
+ $NDCTL zero-labels -b $NFIT_TEST_BUS0 all
+ $NDCTL enable-region -b $NFIT_TEST_BUS0 all
+}
+
+start_monitor()
+{
+ logfile=$(mktemp)
+ $NDCTL monitor -l $logfile $1 &
+ monitor_pid=$!
+ sync; sleep 3
+ truncate --size 0 $logfile #remove startup log
+}
+
+set_smart_supported_bus()
+{
+ smart_supported_bus=$NFIT_TEST_BUS0
+ monitor_dimms=$(./list-smart-dimm -b $smart_supported_bus | jq -r .[0].dev)
+ if [ -z $monitor_dimms ]; then
+ smart_supported_bus=$NFIT_TEST_BUS1
+ fi
+}
+
+get_monitor_dimm()
+{
+ jlist=$(./list-smart-dimm -b $smart_supported_bus $1)
+ monitor_dimms=$(jq '.[]."dev"?, ."dev"?' <<<$jlist | sort | uniq | xargs)
+ echo $monitor_dimms
+}
+
+call_notify()
+{
+ ./smart-notify $smart_supported_bus
+ sync; sleep 3
+}
+
+inject_smart()
+{
+ $NDCTL inject-smart $monitor_dimms $1
+ sync; sleep 3
+}
+
+check_result()
+{
+ jlog=$(cat $logfile)
+ notify_dimms=$(jq ."dimm"."dev" <<<$jlog | sort | uniq | xargs)
+ [[ $1 == $notify_dimms ]]
+}
+
+stop_monitor()
+{
+ kill $monitor_pid
+ rm $logfile
+}
+
+test_filter_dimm()
+{
+ monitor_dimms=$(get_monitor_dimm | awk '{print $1}')
+ start_monitor "-d $monitor_dimms"
+ call_notify
+ check_result "$monitor_dimms"
+ stop_monitor
+}
+
+test_filter_bus()
+{
+ monitor_dimms=$(get_monitor_dimm)
+ start_monitor "-b $smart_supported_bus"
+ call_notify
+ check_result "$monitor_dimms"
+ stop_monitor
+}
+
+test_filter_region()
+{
+ count=$($NDCTL list -R -b $smart_supported_bus | jq -r .[].dev | wc -l)
+ i=0
+ while [ $i -lt $count ]; do
+ monitor_region=$($NDCTL list -R -b $smart_supported_bus | jq -r .[$i].dev)
+ monitor_dimms=$(get_monitor_dimm "-r $monitor_region")
+ [ ! -z $monitor_dimms ] && break
+ i=$((i + 1))
+ done
+ start_monitor "-r $monitor_region"
+ call_notify
+ check_result "$monitor_dimms"
+ stop_monitor
+}
+
+test_filter_namespace()
+{
+ init
+ monitor_namespace=$($NDCTL create-namespace -b $smart_supported_bus | jq -r .dev)
+ monitor_dimms=$(get_monitor_dimm "-n $monitor_namespace")
+ start_monitor "-n $monitor_namespace"
+ call_notify
+ check_result "$monitor_dimms"
+ stop_monitor
+ $NDCTL destroy-namespace $monitor_namespace -f
+}
+
+test_conf_file()
+{
+ monitor_dimms=$(get_monitor_dimm)
+ conf_file=$(mktemp)
+ echo "dimm = $monitor_dimms" > $conf_file
+ start_monitor "-c $conf_file"
+ call_notify
+ check_result "$monitor_dimms"
+ stop_monitor
+ rm $conf_file
+}
+
+test_filter_dimmevent()
+{
+ monitor_dimms="$(get_monitor_dimm | awk '{print $1}')"
+
+ start_monitor "-d $monitor_dimms -D dimm-unclean-shutdown"
+ inject_smart "-U"
+ check_result "$monitor_dimms"
+ stop_monitor
+
+ inject_value=$($NDCTL list -H -d $monitor_dimms | jq -r .[]."health"."spares_threshold")
+ inject_value=$((inject_value - 1))
+ start_monitor "-d $monitor_dimms -D dimm-spares-remaining"
+ inject_smart "-s $inject_value"
+ check_result "$monitor_dimms"
+ stop_monitor
+
+ inject_value=$($NDCTL list -H -d $monitor_dimms | jq -r .[]."health"."temperature_threshold")
+ inject_value=$((inject_value + 1))
+ start_monitor "-d $monitor_dimms -D dimm-media-temperature"
+ inject_smart "-s $inject_value"
+ check_result "$monitor_dimms"
+ stop_monitor
+}
+
+do_tests()
+{
+ test_filter_dimm
+ test_filter_bus
+ test_filter_region
+ test_filter_namespace
+ test_conf_file
+ test_filter_dimmevent
+}
+
+modprobe nfit_test
+rc=1
+init
+set_smart_supported_bus
+do_tests
+_cleanup
+exit 0