diff -Nru ndctl-60.1/autogen.sh ndctl-61.2/autogen.sh --- ndctl-60.1/autogen.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/autogen.sh 2018-07-06 23:33:14.000000000 +0000 @@ -24,5 +24,5 @@ echo "Initialized build system. For a common configuration please run:" echo "----------------------------------------------------------------" echo -echo "./configure CFLAGS='-g -O0' $args" +echo "./configure CFLAGS='-g -O2' $args" echo diff -Nru ndctl-60.1/configure.ac ndctl-61.2/configure.ac --- ndctl-60.1/configure.ac 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/configure.ac 2018-07-06 23:33:14.000000000 +0000 @@ -42,16 +42,29 @@ ]) AM_CONDITIONAL([ENABLE_DOCS], [test "x$enable_docs" = "xyes"]) -AC_CHECK_PROG(ASCIIDOC, [asciidoc], [$(which asciidoc)], [missing]) +AC_ARG_ENABLE([asciidoctor], + AS_HELP_STRING([--enable-asciidoctor], + [use asciidoctor for documentation build]), + [], enable_asciidoctor=no) +AM_CONDITIONAL([USE_ASCIIDOCTOR], [test "x$enable_asciidoctor" = "xyes"]) +if test "x$enable_asciidoctor" = "xyes"; then + asciidoc="asciidoctor" +else + asciidoc="asciidoc" +fi +AC_CHECK_PROG(ASCIIDOC, [$asciidoc], [$(which $asciidoc)], [missing]) if test "x$ASCIIDOC" = xmissing -a "x$enable_docs" = "xyes"; then - AC_MSG_ERROR([asciidoc needed to build documentation]) + AC_MSG_ERROR([$asciidoc needed to build documentation]) fi AC_SUBST([ASCIIDOC]) + +if test x"$asciidoc" = x"asciidoc"; then AC_CHECK_PROG(XMLTO, [xmlto], [$(which xmlto)], [missing]) if test "x$XMLTO" = xmissing -a "x$enable_docs" = "xyes"; then AC_MSG_ERROR([xmlto needed to build documentation]) fi AC_SUBST([XMLTO]) +fi AC_C_TYPEOF AC_DEFINE([HAVE_STATEMENT_EXPR], 1, [Define to 1 if you have statement expressions.]) @@ -89,6 +102,14 @@ [AC_DEFINE([ENABLE_TEST], [1], [ndctl test support])]) AM_CONDITIONAL([ENABLE_TEST], [test "x$enable_test" = "xyes"]) +AC_CHECK_DECLS([BUS_MCEERR_AR], [enable_bus_mc_err=yes], [], [[#include ]]) +AC_CHECK_DECLS([MAP_SYNC], [enable_map_sync=yes], [], [[#include ]]) + +AS_IF([test "x$enable_bus_mc_err" = "xyes" -a "x$enable_map_sync" = "xyes"], + [AC_DEFINE([ENABLE_POISON], [1], [ndctl test poison support])]) +AM_CONDITIONAL([ENABLE_POISON], + [test "x$enable_bus_mc_err" = "xyes" -a "x$enable_map_sync" = "xyes"]) + PKG_CHECK_MODULES([KMOD], [libkmod]) PKG_CHECK_MODULES([UDEV], [libudev]) PKG_CHECK_MODULES([UUID], [uuid]) @@ -134,7 +155,11 @@ -Wsign-compare \ -Wstrict-prototypes \ -Wtype-limits \ --Wmaybe-uninitialized +-Wmaybe-uninitialized \ +-Wdeclaration-after-statement \ +-Wunused-result \ +-D_FORTIFY_SOURCE=2 \ +-O2 " AC_SUBST([my_CFLAGS]) diff -Nru ndctl-60.1/contrib/do_abidiff ndctl-61.2/contrib/do_abidiff --- ndctl-60.1/contrib/do_abidiff 1970-01-01 00:00:00.000000000 +0000 +++ ndctl-61.2/contrib/do_abidiff 2018-07-06 23:33:14.000000000 +0000 @@ -0,0 +1,73 @@ +#!/bin/bash -e + +range="$*" +old="${range%%..*}" +new="${range##*..}" + +err() +{ + echo "$1" + exit 1 +} + +build_rpm() +{ + local cur=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) + local ref="$1" + local version="" + + # prepare ndctl tree + rm -rf results_ndctl + git checkout -b rel_${ref} $ref + ./autogen.sh + ./configure CFLAGS='-g -O2' --prefix=/usr --sysconfdir=/etc --libdir=/usr/lib64 + make clean + make rhel/ndctl.spec + cp rhel/ndctl.spec . + + # build and copy RPMs + version="$(./git-version)" + git archive --format=tar --prefix="ndctl-${version}/" HEAD | gzip > ndctl-${version}.tar.gz + fedpkg --release master --module-name ndctl mockbuild + mkdir -p release/rel_${ref}/ + cp results_ndctl/*/*/*.x86_64.rpm release/rel_${ref}/ + + # restore ndctl branch and cleanup + git checkout $cur + git branch -D rel_${ref} + rm ndctl-${version}.tar.gz + rm ndctl-${version}*.src.rpm + rm -rf results_ndctl + rm -f ndctl.spec +} + +do_diff() +{ + local pkg="$1" + local old_base="$(find . -regex "./release/rel_${old}/${pkg}-[0-9]+.*" | head -1)" + local new_base="$(find . -regex "./release/rel_${new}/${pkg}-[0-9]+.*" | head -1)" + local old_dev="$(find . -regex "./release/rel_${old}/${pkg}-devel-[0-9]+.*" | head -1)" + local new_dev="$(find . -regex "./release/rel_${new}/${pkg}-devel-[0-9]+.*" | head -1)" + local old_lib="$(find . -regex "./release/rel_${old}/${pkg}-libs-[0-9]+.*" | head -1)" + local new_lib="$(find . -regex "./release/rel_${new}/${pkg}-libs-[0-9]+.*" | head -1)" + + [ -n "$pkg" ] || err "specify a package for diff (ndctl, daxctl)" + + abipkgdiff --dso-only --no-added-syms --harmless --drop-private-types \ + --devel1 "$old_dev" --devel2 "$new_dev" \ + "$old_base" "$new_base" + abipkgdiff --no-added-syms --harmless --drop-private-types \ + --devel1 "$old_dev" --devel2 "$new_dev" \ + "$old_lib" "$new_lib" +} + +[ -e "COPYING" ] || err "Run from the top level of an ndctl tree" +if ! command -v "abipkgdiff" >/dev/null; then + err "missing abipkgdiff. Please install libabigail" +fi +rm -rf release/rel* + +build_rpm $old > release/buildlog_$old 2>&1 +build_rpm $new > release/buildlog_$new 2>&1 +do_diff ndctl +do_diff daxctl diff -Nru ndctl-60.1/contrib/prepare-release.sh ndctl-61.2/contrib/prepare-release.sh --- ndctl-60.1/contrib/prepare-release.sh 1970-01-01 00:00:00.000000000 +0000 +++ ndctl-61.2/contrib/prepare-release.sh 2018-07-06 23:33:14.000000000 +0000 @@ -0,0 +1,198 @@ +#!/bin/bash -e + +# Arguments: +# fix - fixup release instead of a full release +# ignore_rev - ignore the check for _REVISION in libtool versioning checks + +# Notes: +# - Checkout to the appropriate branch beforehand +# master - for major release +# ndctl-xx.y - for fixup release +# This is important for generating the shortlog +# - Add a temporary commit that updates the libtool versions as needed. +# This will later become the release commit. Use --amend to add in the +# git-version update and the message body. + +# Pre-reqs: +# - libabigail (for abipkgdiff) +# - fedpkg (for mock build) + +# TODO +# - auto generate a release commit/tag message template +# - determine the most recent kernel release and add it to the above +# - perform documentation update for pmem.io/ndctl + +cleanup() +{ + rm -rf release + mkdir release/ +} + +err() +{ + echo "$1" + exit 1 +} + +parse_args() +{ + local args="$*" + grep -q "fix" <<< "$args" && rel_fix="1" || rel_fix="" + grep -q "ignore_rev" <<< "$args" && ignore_rev="1" || ignore_rev="" +} + +check_branch() +{ + local cur=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) + if [ -n "$rel_fix" ]; then + # fixup release, expect ndctl-xx.y branch + if ! grep -Eq "^ndctl.[0-9]+\.y$" <<< "$cur"; then + err "expected an ndctl-xx.y branch for fixup release" + fi + else + # major release, expect master branch + if ! grep -Eq "^master$" <<< "$cur"; then + err "expected master branch for a major release" + fi + fi + if ! git diff-index --quiet HEAD --; then + err "$cur has uncommitted/unstaged changes" + fi +} + +last_maj() +{ + git tag | sort -V | grep -E "v[0-9]+$" | tail -1 +} + +last_fix() +{ + local base="$1" + git tag | sort -V | grep -E "$base\.?[0-9]*$" | tail -1 +} + +next_maj() +{ + local last="$1" + local num=${last#v} + + newnum="$((num + 1))" + echo "v$newnum" +} + +next_fix() +{ + local last="$1" + local num=${last##*.} + local base=${last%%.*} + + newnum=$((num + 1)) + echo "$base.$newnum" +} + +gen_lists() +{ + local range="$1" + + git shortlog "$range" > release/shortlog + git log --pretty=format:"%s" "$range" > release/commits + c_count=$(git log --pretty=format:"%s" "$range" | wc -l) +} + +# Check libtool versions in Makefile.am.in +# $1: lib name (currently libndctl or libdaxctl) +check_libtool_vers() +{ + local lib="$1" + local lib_u="${lib^^}" + local libdir="${lib##lib}" + local symfile="${libdir}/lib/${lib}.sym" + local last_cur=$(git show $last_ref:Makefile.am.in | grep -E "^${lib_u}_CURRENT" | cut -d'=' -f2) + local last_rev=$(git show $last_ref:Makefile.am.in | grep -E "^${lib_u}_REVISION" | cut -d'=' -f2) + local last_age=$(git show $last_ref:Makefile.am.in | grep -E "^${lib_u}_AGE" | cut -d'=' -f2) + local last_soname=$((last_cur - last_age)) + local next_cur=$(git show HEAD:Makefile.am.in | grep -E "^${lib_u}_CURRENT" | cut -d'=' -f2) + local next_rev=$(git show HEAD:Makefile.am.in | grep -E "^${lib_u}_REVISION" | cut -d'=' -f2) + local next_age=$(git show HEAD:Makefile.am.in | grep -E "^${lib_u}_AGE" | cut -d'=' -f2) + local next_soname=$((next_cur - next_age)) + local soname_diff=$((next_soname - last_soname)) + + # generally libtool versions either reset to zero or increase only by one + # _CURRENT monotonically increases (by one) + if [ "$((next_cur - last_cur))" -gt 1 ]; then + err "${lib_u}_CURRENT can increase at most by 1" + fi + if [ "$next_rev" -ne 0 ]; then + if [ "$((next_rev - last_rev))" -gt 1 ]; then + err "${lib_u}_REVISION can increase at most by 1" + fi + fi + if [ "$next_age" -ne 0 ]; then + if [ "$((next_age - last_age))" -gt 1 ]; then + err "${lib_u}_AGE can increase at most by 1" + fi + fi + + # test for soname change + if [ "$soname_diff" -ne 0 ]; then + err "${lib}: expected soname to stay unchanged" + fi + + # tests based on whether symfile changed + # compatibility breaking changes are left for libabigail to detect + test -s "$symfile" || err "$symfile: not found" + if [ -n "$(git diff --name-only $last_ref..HEAD $symfile)" ]; then + # symfile has changed, cur and age should increase + if [ "$((next_cur - last_cur))" -ne 1 ]; then + err "based on $symfile, ${lib_u}_CURRENT should've increased by 1" + fi + if [ "$((next_age - last_age))" -ne 1 ]; then + err "based on $symfile, ${lib_u}_AGE should've increased by 1" + fi + else + # no changes to symfile, revision should've increased if source changed + if [ -n "$ignore_rev" ]; then + : # skip + elif [ -n "$(git diff --name-only $last_ref..HEAD $libdir/)" ]; then + if [ "$((next_rev - last_rev))" -ne 1 ]; then + err "based on $symfile, ${lib_u}_REVISION should've increased by 1" + fi + fi + fi +} + + +# main +cleanup +parse_args "$*" +check_branch +[ -e "COPYING" ] || err "Run from the top level of an ndctl tree" + +last_maj=$(last_maj) +test -n "$last_maj" || err "Unable to determine last release" + +last_fix=$(last_fix $last_maj) +test -n "$last_fix" || err "Unable to determine last fixup tag for $last_maj" + +next_maj=$(next_maj "$last_maj") +next_fix=$(next_fix "$last_fix") +[ -n "$rel_fix" ] && last_ref="$last_fix" || last_ref="$last_maj" +[ -n "$rel_fix" ] && next_ref="$next_fix" || next_ref="$next_maj" + +check_libtool_vers "libndctl" +check_libtool_vers "libdaxctl" + +gen_lists ${last_ref}..HEAD + +# For ABI diff purposes, use the latest fixes tag +contrib/do_abidiff ${last_fix}..HEAD + +# once everything passes, update the git-version +sed -i -e "s/DEF_VER=[0-9]\+.*/DEF_VER=${next_ref#v}/" git-version + +echo "Ready to release ndctl-$next_ref with $c_count new commits." +echo "Add git-version to the top commit to get the updated version." +echo "Use release/commits and release/shortlog to compose the release message" +echo "The release commit typically contains the Makefile.am.in libtool version" +echo "update, and the git-version update." +echo "Finally, ensure the release commit as well as the tag are PGP signed." diff -Nru ndctl-60.1/debian/changelog ndctl-61.2/debian/changelog --- ndctl-60.1/debian/changelog 2018-05-24 12:46:06.000000000 +0000 +++ ndctl-61.2/debian/changelog 2018-07-12 15:00:59.000000000 +0000 @@ -1,3 +1,12 @@ +ndctl (61.2-0ubuntu1) cosmic; urgency=medium + + * New upstream release + * d/libndctl6.symbols: added new symbols for version 61.2 + * d/control: updated Standards-Version to 4.1.5, no changes necessary. + Verified that the package isn't affected by the FHS 2.3->3.0 bump. + + -- Andreas Hasenack Thu, 12 Jul 2018 12:00:59 -0300 + ndctl (60.1-0ubuntu1) cosmic; urgency=medium * Initial release. Closes: LP: #1752378. diff -Nru ndctl-60.1/debian/control ndctl-61.2/debian/control --- ndctl-60.1/debian/control 2018-05-24 12:46:06.000000000 +0000 +++ ndctl-61.2/debian/control 2018-07-12 15:00:59.000000000 +0000 @@ -11,7 +11,7 @@ pkg-config, uuid-dev, xmlto -Standards-Version: 4.1.4 +Standards-Version: 4.1.5 Homepage: https://github.com/pmem/ndctl Vcs-Git: https://git.launchpad.net/ubuntu/+source/ndctl Vcs-Browser: https://code.launchpad.net/ubuntu/+source/ndctl/+git diff -Nru ndctl-60.1/debian/libndctl6.symbols ndctl-61.2/debian/libndctl6.symbols --- ndctl-60.1/debian/libndctl6.symbols 2018-05-22 11:41:28.000000000 +0000 +++ ndctl-61.2/debian/libndctl6.symbols 2018-07-12 15:00:59.000000000 +0000 @@ -2,6 +2,7 @@ LIBNDCTL_13@LIBNDCTL_13 60.1 LIBNDCTL_14@LIBNDCTL_14 60.1 LIBNDCTL_15@LIBNDCTL_15 60.1 + LIBNDCTL_16@LIBNDCTL_16 61.2 LIBNDCTL_1@LIBNDCTL_1 60.1 LIBNDCTL_3@LIBNDCTL_3 60.1 ndctl_bb_get_block@LIBNDCTL_14 60.1 @@ -55,12 +56,14 @@ ndctl_bus_start_scrub@LIBNDCTL_15 60.1 ndctl_bus_wait_for_scrub_completion@LIBNDCTL_14 60.1 ndctl_bus_wait_probe@LIBNDCTL_3 60.1 + ndctl_cmd_ars_cap_get_clear_unit@LIBNDCTL_16 61.2 ndctl_cmd_ars_cap_get_range@LIBNDCTL_3 60.1 ndctl_cmd_ars_cap_get_size@LIBNDCTL_3 60.1 ndctl_cmd_ars_get_record_addr@LIBNDCTL_3 60.1 ndctl_cmd_ars_get_record_len@LIBNDCTL_3 60.1 ndctl_cmd_ars_in_progress@LIBNDCTL_3 60.1 ndctl_cmd_ars_num_records@LIBNDCTL_3 60.1 + ndctl_cmd_ars_stat_get_flag_overflow@LIBNDCTL_16 61.2 ndctl_cmd_cfg_read_get_data@LIBNDCTL_3 60.1 ndctl_cmd_cfg_read_get_size@LIBNDCTL_3 60.1 ndctl_cmd_cfg_size_get_size@LIBNDCTL_3 60.1 @@ -259,6 +262,7 @@ ndctl_namespace_get_type@LIBNDCTL_3 60.1 ndctl_namespace_get_type_name@LIBNDCTL_3 60.1 ndctl_namespace_get_uuid@LIBNDCTL_3 60.1 + ndctl_namespace_inject_error2@LIBNDCTL_16 61.2 ndctl_namespace_inject_error@LIBNDCTL_14 60.1 ndctl_namespace_injection_get_first_bb@LIBNDCTL_14 60.1 ndctl_namespace_injection_get_next_bb@LIBNDCTL_14 60.1 @@ -273,6 +277,7 @@ ndctl_namespace_set_sector_size@LIBNDCTL_3 60.1 ndctl_namespace_set_size@LIBNDCTL_3 60.1 ndctl_namespace_set_uuid@LIBNDCTL_3 60.1 + ndctl_namespace_uninject_error2@LIBNDCTL_16 61.2 ndctl_namespace_uninject_error@LIBNDCTL_14 60.1 ndctl_namespace_write_cache_is_enabled@LIBNDCTL_15 60.1 ndctl_new@LIBNDCTL_1 60.1 diff -Nru ndctl-60.1/Documentation/asciidoctor-extensions.rb.in ndctl-61.2/Documentation/asciidoctor-extensions.rb.in --- ndctl-60.1/Documentation/asciidoctor-extensions.rb.in 1970-01-01 00:00:00.000000000 +0000 +++ ndctl-61.2/Documentation/asciidoctor-extensions.rb.in 2018-07-06 23:33:14.000000000 +0000 @@ -0,0 +1,30 @@ +require 'asciidoctor' +require 'asciidoctor/extensions' + +module @Utility@ + module Documentation + class Link@Utility@Processor < Asciidoctor::Extensions::InlineMacroProcessor + use_dsl + + named :chrome + + def process(parent, target, attrs) + if parent.document.basebackend? 'html' + prefix = parent.document.attr('@utility@-relative-html-prefix') + %(#{target}(#{attrs[1]})\n) + elsif parent.document.basebackend? 'manpage' + "#{target}(#{attrs[1]})" + elsif parent.document.basebackend? 'docbook' + "\n" \ + "#{target}" \ + "#{attrs[1]}\n" \ + "\n" + end + end + end + end +end + +Asciidoctor::Extensions.register do + inline_macro @Utility@::Documentation::Link@Utility@Processor, :link@utility@ +end diff -Nru ndctl-60.1/Documentation/daxctl/daxctl-list.txt ndctl-61.2/Documentation/daxctl/daxctl-list.txt --- ndctl-60.1/Documentation/daxctl/daxctl-list.txt 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Documentation/daxctl/daxctl-list.txt 2018-07-06 23:33:14.000000000 +0000 @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 daxctl-list(1) -============= +============== NAME ---- @@ -24,10 +24,9 @@ EXAMPLE ------- -[verse] +---- # daxctl list --regions --devices -["literal"] { "id":1, "devices":[ @@ -37,6 +36,7 @@ } ] } +---- OPTIONS ------- @@ -54,14 +54,14 @@ tuple, or keyword 'all' to filter the listing. For example to list the first device instance in region1: -[verse] +---- # daxctl list --dev=1.0 -["literal"] { "chardev":"dax1.0", "size":3233808384 } +---- -D:: --devices:: @@ -82,7 +82,7 @@ will be formatted as human readable strings with units, other fields are converted to hexadecimal strings. Example: -[verse] +---- # daxctl list { "chardev":"dax1.0", @@ -94,5 +94,6 @@ "chardev":"dax1.0", "size":"30.57 GiB (32.83 GB)" } +---- include::../copyright.txt[] diff -Nru ndctl-60.1/Documentation/daxctl/Makefile.am ndctl-61.2/Documentation/daxctl/Makefile.am --- ndctl-60.1/Documentation/daxctl/Makefile.am 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Documentation/daxctl/Makefile.am 2018-07-06 23:33:14.000000000 +0000 @@ -9,11 +9,22 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -do_subst = sed -e 's,UTILITY,daxctl,g' +if USE_ASCIIDOCTOR + +do_subst = sed -e 's,@Utility@,Daxctl,g' -e's,@utility@,daxctl,g' +CONFFILE = asciidoctor-extensions.rb +asciidoctor-extensions.rb: ../asciidoctor-extensions.rb.in + $(AM_V_GEN) $(do_subst) < $< > $@ +else + +do_subst = sed -e 's,UTILITY,daxctl,g' +CONFFILE = asciidoc.conf asciidoc.conf: ../asciidoc.conf.in $(AM_V_GEN) $(do_subst) < $< > $@ +endif + man1_MANS = \ daxctl.1 \ daxctl-list.1 @@ -24,10 +35,22 @@ ../../version.m4 \ ../copyright.txt \ Makefile \ - asciidoc.conf + $(CONFFILE) RM ?= rm -f +if USE_ASCIIDOCTOR + +%.1: %.txt $(XML_DEPS) + $(AM_V_GEN)$(RM) $@+ $@ && \ + $(ASCIIDOC) -b manpage -d manpage -acompat-mode \ + -I. -rasciidoctor-extensions \ + -amansource=daxctl -amanmanual="daxctl Manual" \ + -andctl_version=$(VERSION) -o $@+ $< && \ + mv $@+ $@ + +else + %.xml: %.txt $(XML_DEPS) $(AM_V_GEN)$(RM) $@+ $@ && \ $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \ @@ -37,3 +60,5 @@ %.1: %.xml $(XML_DEPS) $(AM_V_GEN)$(RM) $@ && \ $(XMLTO) -o . -m ../manpage-normal.xsl man $< + +endif diff -Nru ndctl-60.1/Documentation/ndctl/Makefile.am ndctl-61.2/Documentation/ndctl/Makefile.am --- ndctl-60.1/Documentation/ndctl/Makefile.am 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Documentation/ndctl/Makefile.am 2018-07-06 23:33:14.000000000 +0000 @@ -9,11 +9,22 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -do_subst = sed -e 's,UTILITY,ndctl,g' +if USE_ASCIIDOCTOR + +do_subst = sed -e 's,@Utility@,Ndctl,g' -e's,@utility@,ndctl,g' +CONFFILE = asciidoctor-extensions.rb +asciidoctor-extensions.rb: ../asciidoctor-extensions.rb.in + $(AM_V_GEN) $(do_subst) < $< > $@ +else + +do_subst = sed -e 's,UTILITY,ndctl,g' +CONFFILE = asciidoc.conf asciidoc.conf: ../asciidoc.conf.in $(AM_V_GEN) $(do_subst) < $< > $@ +endif + man1_MANS = \ ndctl.1 \ ndctl-wait-scrub.1 \ @@ -42,7 +53,7 @@ XML_DEPS = \ ../../version.m4 \ Makefile \ - asciidoc.conf \ + $(CONFFILE) \ ../copyright.txt \ region-description.txt \ xable-region-options.txt \ @@ -55,6 +66,18 @@ RM ?= rm -f +if USE_ASCIIDOCTOR + +%.1: %.txt $(XML_DEPS) + $(AM_V_GEN)$(RM) $@+ $@ && \ + $(ASCIIDOC) -b manpage -d manpage -acompat-mode \ + -I. -rasciidoctor-extensions \ + -amansource=ndctl -amanmanual="ndctl Manual" \ + -andctl_version=$(VERSION) -o $@+ $< && \ + mv $@+ $@ + +else + %.xml: %.txt $(XML_DEPS) $(AM_V_GEN)$(RM) $@+ $@ && \ $(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \ @@ -64,3 +87,5 @@ %.1: %.xml $(XML_DEPS) $(AM_V_GEN)$(RM) $@ && \ $(XMLTO) -o . -m ../manpage-normal.xsl man $< + +endif diff -Nru ndctl-60.1/Documentation/ndctl/namespace-description.txt ndctl-61.2/Documentation/ndctl/namespace-description.txt --- ndctl-60.1/Documentation/ndctl/namespace-description.txt 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Documentation/ndctl/namespace-description.txt 2018-07-06 23:33:14.000000000 +0000 @@ -1,8 +1,52 @@ // SPDX-License-Identifier: GPL-2.0 -DESCRIPTION ------------ -A REGION, after resolving DPA aliasing and LABEL specified boundaries, -surfaces one or more "namespace" devices. The arrival of a "namespace" -device currently triggers either the nd_blk or nd_pmem driver to load -and register a disk/block device. +THEORY OF OPERATION +------------------- +The capacity of an NVDIMM REGION (contiguous span of persistent memory) +is accessed via one or more NAMESPACE devices. REGION is the Linux term +for what ACPI and UEFI call a DIMM-interleave-set, or a +system-physical-address-range that is striped (by the memory controller) +across one or more memory modules. + +The UEFI specification defines the 'NVDIMM Label Protocol' as the +combination of label area access methods and a data format for +provisioning one or more NAMESPACE objects from a REGION. Note that +label support is optional and if Linux does not detect the label +capability it will automatically instantiate a "label-less" namespace +per region. Examples of label-less namespaces are the ones created by +the kernel's 'memmap=ss!nn' command line option (see the nvdimm wiki on +kernel.org), or NVDIMMs without a valid 'namespace index' in their label +area. + +A namespace can be provisioned to operate in one of 4 modes, 'fsdax', +'devdax', 'sector', and 'raw'. Here are the expected usage models for +these modes: + - fsdax: Filesystem-DAX mode is the default mode of a namespace + when specifying 'ndctl create-namespace' with no options. It creates + a block device (/dev/pmemX[.Y]) that supports the DAX capabilities + of Linux filesystems (xfs and ext4 to date). DAX removes the page + cache from the I/O path and allows mmap(2) to establish direct + mappings to persistent memory media. The DAX capability enables + workloads / working-sets that would exceed the capacity of the page + cache to scale up to the capacity of persistent memory. Workloads + that fit in page cache or perform bulk data transfers may not see + benefit from DAX. When in doubt, pick this mode. + + - devdax: Device-DAX mode enables similar mmap(2) DAX mapping + capabilities as Filesystem-DAX. However, instead of a block-device + that can support a DAX-enabled filesystem, this mode emits a single + character device file (/dev/daxX.Y). Use this mode to assign + persistent memory to a virtual-machine, register persistent memory + for RDMA, or when gigantic mappings are needed. + + - sector: Use this mode to host legacy filesystems that do + not checksum metadata or applications that are not prepared for torn + sectors after a crash. Expected usage for this mode is for small + boot volumes. This mode is compatible with other operating systems. + + - raw: Raw mode is effectively just a memory disk that does + not support DAX. Typically this indicates a namespace that was + created by tooling or another operating system that did not know how + to create a Linux 'fsdax' or 'devdax' mode namespace. This mode is + compatible with other operating systems, but again, does not support + DAX operation. diff -Nru ndctl-60.1/Documentation/ndctl/ndctl-create-namespace.txt ndctl-61.2/Documentation/ndctl/ndctl-create-namespace.txt --- ndctl-60.1/Documentation/ndctl/ndctl-create-namespace.txt 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Documentation/ndctl/ndctl-create-namespace.txt 2018-07-06 23:33:14.000000000 +0000 @@ -219,3 +219,4 @@ linkndctl:ndctl-disable-namespace[1], linkndctl:ndctl-enable-namespace[1], http://www.uefi.org/sites/default/files/resources/UEFI_Spec_2_7.pdf[UEFI NVDIMM Label Protocol] +https://nvdimm.wiki.kernel.org[Linux Persistent Memory Wiki] diff -Nru ndctl-60.1/Documentation/ndctl/ndctl-disable-dimm.txt ndctl-61.2/Documentation/ndctl/ndctl-disable-dimm.txt --- ndctl-60.1/Documentation/ndctl/ndctl-disable-dimm.txt 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Documentation/ndctl/ndctl-disable-dimm.txt 2018-07-06 23:33:14.000000000 +0000 @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 ndctl-disable-dimm(1) -======================= +===================== NAME ---- diff -Nru ndctl-60.1/Documentation/ndctl/ndctl-enable-region.txt ndctl-61.2/Documentation/ndctl/ndctl-enable-region.txt --- ndctl-60.1/Documentation/ndctl/ndctl-enable-region.txt 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Documentation/ndctl/ndctl-enable-region.txt 2018-07-06 23:33:14.000000000 +0000 @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 ndctl-enable-region(1) -==================== +====================== NAME ---- diff -Nru ndctl-60.1/Documentation/ndctl/ndctl-init-labels.txt ndctl-61.2/Documentation/ndctl/ndctl-init-labels.txt --- ndctl-60.1/Documentation/ndctl/ndctl-init-labels.txt 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Documentation/ndctl/ndctl-init-labels.txt 2018-07-06 23:33:14.000000000 +0000 @@ -26,7 +26,7 @@ EXAMPLE ------- Find the DIMMs that comprise a given region: -[verse] +---- # ndctl list -RD --region=region1 { "dimms":[ @@ -51,23 +51,28 @@ } ] } +---- Disable that region so the DIMM label area can be written from userspace: -[verse] +---- # ndctl disable-region region1 +---- Initialize labels: -[verse] +---- # ndctl init-labels nmem0 +---- Re-enable the region: -[verse] +---- # ndctl enable-region region1 +---- Create a namespace in that region: -[verse] +---- # ndctl create-namespace --region=region1 +---- OPTIONS ------- diff -Nru ndctl-60.1/Documentation/ndctl/ndctl-inject-error.txt ndctl-61.2/Documentation/ndctl/ndctl-inject-error.txt --- ndctl-60.1/Documentation/ndctl/ndctl-inject-error.txt 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Documentation/ndctl/ndctl-inject-error.txt 2018-07-06 23:33:14.000000000 +0000 @@ -18,6 +18,15 @@ in the NVDIMM address space to aid debugging and development of features related to error handling. +By default, injecting an error actually only injects an error to the first 'n' +bytes of the block, where 'n' is the output of ndctl_cmd_ars_cap_get_size(). +In other words, we only inject one 'ars_unit' per sector. This is sufficient +for Linux to mark the whole sector as bad, and will show up as such in the +various 'badblocks' lists in the kernel. If multiple blocks are being injected, +only the first 'n' bytes of each block specified will be injected as errors. +This can be overridden by the --saturate option, which will force the entire +block to be injected as an error. + WARNING: These commands are DANGEROUS and can cause data loss. They are only provided for testing and debugging purposes. @@ -88,6 +97,11 @@ when the location is accessed. If the platform firmware does not support this feature, this will have no effect. +-S:: +--saturate:: + This option forces error injection or un-injection to cover the entire + address range covered by the specified block(s). + -v:: --verbose:: Emit debug messages for the error injection process diff -Nru ndctl-60.1/Documentation/ndctl/ndctl-list.txt ndctl-61.2/Documentation/ndctl/ndctl-list.txt --- ndctl-60.1/Documentation/ndctl/ndctl-list.txt 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Documentation/ndctl/ndctl-list.txt 2018-07-06 23:33:14.000000000 +0000 @@ -23,10 +23,9 @@ EXAMPLE ------- -[verse] +---- # ndctl list --buses --namespaces -["literal"] { "provider":"nfit_test.1", "dev":"ndbus2", @@ -55,6 +54,7 @@ } ] } +---- OPTIONS ------- @@ -67,8 +67,9 @@ An 'nmemX' device name, or dimm id number. Filter listing by devices that reference the given dimm. For example to see all namespaces comprised of storage capacity on nmem0: -[verse] +---- # ndctl list --dimm=nmem0 --namespaces +---- -n:: --namespace=:: @@ -201,7 +202,7 @@ include::human-option.txt[] -[verse] +---- # ndctl list --region=7 { "dev":"region7", @@ -211,8 +212,9 @@ "iset_id":-6382611090938810793, "badblock_count":8 } +---- -[verse] +---- # ndctl list --human --region=7 { "dev":"region7", @@ -222,6 +224,7 @@ "iset_id":"0xa76c6907811fae57", "badblock_count":8 } +---- include::../copyright.txt[] diff -Nru ndctl-60.1/Documentation/ndctl/ndctl-start-scrub.txt ndctl-61.2/Documentation/ndctl/ndctl-start-scrub.txt --- ndctl-60.1/Documentation/ndctl/ndctl-start-scrub.txt 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Documentation/ndctl/ndctl-start-scrub.txt 2018-07-06 23:33:14.000000000 +0000 @@ -24,7 +24,7 @@ ------- Start a scrub on all nvdimm buses in the system. The json listing report only includes the buses that support ARS operations. -[verse] +---- # ndctl start-scrub [ @@ -39,12 +39,14 @@ "scrub_state":"active" } ] +---- When specifying an individual bus, or if there is only one bus in the system, the command reports whether ARS support is available. -[verse] +---- # ndctl start-scrub e820 error starting scrub: Operation not supported +---- OPTIONS ------- diff -Nru ndctl-60.1/Documentation/ndctl/ndctl-wait-scrub.txt ndctl-61.2/Documentation/ndctl/ndctl-wait-scrub.txt --- ndctl-60.1/Documentation/ndctl/ndctl-wait-scrub.txt 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Documentation/ndctl/ndctl-wait-scrub.txt 2018-07-06 23:33:14.000000000 +0000 @@ -25,7 +25,7 @@ ------- Wait for scrub on all nvdimm buses in the system. The json listing report at the end only includes the buses that support ARS operations. -[verse] +---- # ndctl wait-scrub [ { @@ -39,12 +39,14 @@ "scrub_state":"idle" } ] +---- When specifying an individual bus, or if there is only one bus in the system, the command reports whether ARS support is available. -[verse] +---- # ndctl wait-scrub e820 error waiting for scrub completion: Operation not supported +---- OPTIONS ------- diff -Nru ndctl-60.1/.gitignore ndctl-61.2/.gitignore --- ndctl-60.1/.gitignore 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/.gitignore 2018-07-06 23:33:14.000000000 +0000 @@ -15,6 +15,8 @@ *.1 Documentation/daxctl/asciidoc.conf Documentation/ndctl/asciidoc.conf +Documentation/daxctl/asciidoctor-extensions.rb +Documentation/ndctl/asciidoctor-extensions.rb .dirstamp daxctl/daxctl daxctl/lib/libdaxctl.la @@ -53,3 +55,4 @@ test/smart-notify test/fio.job test/local-write-0-verify.state +test/ack-shutdown-count-set diff -Nru ndctl-60.1/git-version ndctl-61.2/git-version --- ndctl-60.1/git-version 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/git-version 2018-07-06 23:33:14.000000000 +0000 @@ -19,7 +19,7 @@ fi } -DEF_VER=60.1 +DEF_VER=61.2 LF=' ' diff -Nru ndctl-60.1/Makefile.am ndctl-61.2/Makefile.am --- ndctl-60.1/Makefile.am 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Makefile.am 2018-07-06 23:33:14.000000000 +0000 @@ -69,6 +69,7 @@ util/strbuf.c \ util/wrapper.c \ util/filter.c \ - util/bitmap.c + util/bitmap.c \ + util/abspath.c nobase_include_HEADERS = daxctl/libdaxctl.h diff -Nru ndctl-60.1/Makefile.am.in ndctl-61.2/Makefile.am.in --- ndctl-60.1/Makefile.am.in 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/Makefile.am.in 2018-07-06 23:33:14.000000000 +0000 @@ -35,9 +35,9 @@ -e 's,@includedir\@,$(includedir),g' \ < $< > $@ || rm $@ -LIBNDCTL_CURRENT=15 -LIBNDCTL_REVISION=0 -LIBNDCTL_AGE=9 +LIBNDCTL_CURRENT=16 +LIBNDCTL_REVISION=1 +LIBNDCTL_AGE=10 LIBDAXCTL_CURRENT=3 LIBDAXCTL_REVISION=0 diff -Nru ndctl-60.1/ndctl/inject-error.c ndctl-61.2/ndctl/inject-error.c --- ndctl-60.1/ndctl/inject-error.c 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/ndctl/inject-error.c 2018-07-06 23:33:14.000000000 +0000 @@ -47,6 +47,7 @@ bool clear; bool status; bool no_notify; + bool saturate; bool human; } param; @@ -54,8 +55,8 @@ u64 block; u64 count; unsigned int op_mask; - unsigned long flags; - bool notify; + unsigned long json_flags; + unsigned int inject_flags; } ictx; #define BASE_OPTIONS() \ @@ -74,6 +75,8 @@ "un-inject a previously injected error"), \ OPT_BOOLEAN('t', "status", ¶m.status, "get error injection status"), \ OPT_BOOLEAN('N', "no-notify", ¶m.no_notify, "firmware should not notify OS"), \ +OPT_BOOLEAN('S', "saturate", ¶m.saturate, \ + "inject full sector, not just 'ars_unit' bytes"), \ OPT_BOOLEAN('u', "human", ¶m.human, "use human friendly number formats ") static const struct option inject_options[] = { @@ -92,9 +95,9 @@ { if (!param.clear && !param.status) { ictx.op_mask |= 1 << OP_INJECT; - ictx.notify = true; + ictx.inject_flags |= (1 << NDCTL_NS_INJECT_NOTIFY); if (param.no_notify) - ictx.notify = false; + ictx.inject_flags &= ~(1 << NDCTL_NS_INJECT_NOTIFY); } if (param.clear) { if (param.status) { @@ -104,7 +107,7 @@ ictx.op_mask |= 1 << OP_CLEAR; } if (param.status) { - if (param.block || param.count) { + if (param.block || param.count || param.saturate) { error("status is invalid with inject or uninject\n"); return -EINVAL; } @@ -144,7 +147,9 @@ } if (param.human) - ictx.flags |= UTIL_JSON_HUMAN; + ictx.json_flags |= UTIL_JSON_HUMAN; + if (param.saturate) + ictx.inject_flags |= 1 << NDCTL_NS_INJECT_SATURATE; return 0; } @@ -152,14 +157,15 @@ static int ns_errors_to_json(struct ndctl_namespace *ndns, unsigned int start_count) { - unsigned long flags = ictx.flags | UTIL_JSON_MEDIA_ERRORS; + unsigned long json_flags = ictx.json_flags | UTIL_JSON_MEDIA_ERRORS; struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns); struct json_object *jndns; unsigned int count; int rc, tmo = 30; /* only wait for scrubs for the inject and notify case */ - if ((ictx.op_mask & (1 << OP_INJECT)) && ictx.notify) { + if ((ictx.op_mask & (1 << OP_INJECT)) && + (ictx.inject_flags & (1 << NDCTL_NS_INJECT_NOTIFY))) { do { /* wait for a scrub to start */ count = ndctl_bus_get_scrub_count(bus); @@ -177,7 +183,7 @@ } } - jndns = util_namespace_to_json(ndns, flags); + jndns = util_namespace_to_json(ndns, json_flags); if (jndns) printf("%s\n", json_object_to_json_string_ext(jndns, JSON_C_TO_STRING_PRETTY)); @@ -185,7 +191,7 @@ } static int inject_error(struct ndctl_namespace *ndns, u64 offset, u64 length, - bool notify) + unsigned int flags) { struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns); unsigned int scrub_count; @@ -197,7 +203,7 @@ return -ENXIO; } - rc = ndctl_namespace_inject_error(ndns, offset, length, notify); + rc = ndctl_namespace_inject_error2(ndns, offset, length, flags); if (rc) { fprintf(stderr, "Unable to inject error: %s (%d)\n", strerror(abs(rc)), rc); @@ -207,11 +213,12 @@ return ns_errors_to_json(ndns, scrub_count); } -static int uninject_error(struct ndctl_namespace *ndns, u64 offset, u64 length) +static int uninject_error(struct ndctl_namespace *ndns, u64 offset, u64 length, + unsigned int flags) { int rc; - rc = ndctl_namespace_uninject_error(ndns, offset, length); + rc = ndctl_namespace_uninject_error2(ndns, offset, length, flags); if (rc) { fprintf(stderr, "Unable to uninject error: %s (%d)\n", strerror(abs(rc)), rc); @@ -254,7 +261,7 @@ block = ndctl_bb_get_block(bb); count = ndctl_bb_get_count(bb); - jbb = util_badblock_rec_to_json(block, count, ictx.flags); + jbb = util_badblock_rec_to_json(block, count, ictx.json_flags); if (!jbb) break; json_object_array_add(jbbs, jbb); @@ -280,13 +287,14 @@ while (op_mask) { if (op_mask & (1 << OP_INJECT)) { rc = inject_error(ndns, ictx.block, ictx.count, - ictx.notify); + ictx.inject_flags); if (rc) return rc; op_mask &= ~(1 << OP_INJECT); } if (op_mask & (1 << OP_CLEAR)) { - rc = uninject_error(ndns, ictx.block, ictx.count); + rc = uninject_error(ndns, ictx.block, ictx.count, + ictx.inject_flags); if (rc) return rc; op_mask &= ~(1 << OP_CLEAR); diff -Nru ndctl-60.1/ndctl/lib/ars.c ndctl-61.2/ndctl/lib/ars.c --- ndctl-60.1/ndctl/lib/ars.c 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/ndctl/lib/ars.c 2018-07-06 23:33:14.000000000 +0000 @@ -180,36 +180,61 @@ return -EINVAL; } +NDCTL_EXPORT unsigned int ndctl_cmd_ars_cap_get_clear_unit( + struct ndctl_cmd *ars_cap) +{ + struct ndctl_ctx *ctx = ndctl_bus_get_ctx(cmd_to_bus(ars_cap)); + + if (ars_cap->type == ND_CMD_ARS_CAP && ars_cap->status == 0) { + dbg(ctx, "clear_err_unit: %d\n", + ars_cap->ars_cap->clear_err_unit); + return ars_cap->ars_cap->clear_err_unit; + } + + dbg(ctx, "invalid ars_cap\n"); + return 0; +} + +static bool __validate_ars_stat(struct ndctl_cmd *ars_stat) +{ + /* + * A positive status indicates an underrun, but that is fine since + * the firmware is not expected to completely fill the max_ars_out + * sized buffer. + */ + if (ars_stat->type != ND_CMD_ARS_STATUS || ars_stat->status < 0) + return false; + if ((ndctl_cmd_get_firmware_status(ars_stat) & ARS_STATUS_MASK) != 0) + return false; + return true; +} + +#define validate_ars_stat(ctx, ars_stat) \ +({ \ + bool __valid = __validate_ars_stat(ars_stat); \ + if (!__valid) \ + dbg(ctx, "expected sucessfully completed ars_stat command\n"); \ + __valid; \ +}) + NDCTL_EXPORT int ndctl_cmd_ars_in_progress(struct ndctl_cmd *cmd) { struct ndctl_ctx *ctx = ndctl_bus_get_ctx(cmd_to_bus(cmd)); - if (cmd->type == ND_CMD_ARS_STATUS && cmd->status == 0) { - if (cmd->ars_status->status == 1 << 16) { - /* - * If in-progress, invalidate the ndctl_cmd, so - * that if we're called again without a fresh - * ars_status command, we fail. - */ - cmd->status = 1; - return 1; - } + if (!validate_ars_stat(ctx, cmd)) return 0; - } - dbg(ctx, "invalid ars_status\n"); - return 0; + return (ndctl_cmd_get_firmware_status(cmd) == 1 << 16); } NDCTL_EXPORT unsigned int ndctl_cmd_ars_num_records(struct ndctl_cmd *ars_stat) { struct ndctl_ctx *ctx = ndctl_bus_get_ctx(cmd_to_bus(ars_stat)); - if (ars_stat->type == ND_CMD_ARS_STATUS && ars_stat->status == 0) - return ars_stat->ars_status->num_records; + if (!validate_ars_stat(ctx, ars_stat)) + return 0; - dbg(ctx, "invalid ars_status\n"); - return 0; + return ars_stat->ars_status->num_records; } NDCTL_EXPORT unsigned long long ndctl_cmd_ars_get_record_addr( @@ -217,16 +242,15 @@ { struct ndctl_ctx *ctx = ndctl_bus_get_ctx(cmd_to_bus(ars_stat)); + if (!validate_ars_stat(ctx, ars_stat)) + return 0; + if (rec_index >= ars_stat->ars_status->num_records) { dbg(ctx, "invalid record index\n"); return 0; } - if (ars_stat->type == ND_CMD_ARS_STATUS && ars_stat->status == 0) - return ars_stat->ars_status->records[rec_index].err_address; - - dbg(ctx, "invalid ars_status\n"); - return 0; + return ars_stat->ars_status->records[rec_index].err_address; } NDCTL_EXPORT unsigned long long ndctl_cmd_ars_get_record_len( @@ -234,16 +258,26 @@ { struct ndctl_ctx *ctx = ndctl_bus_get_ctx(cmd_to_bus(ars_stat)); + if (!validate_ars_stat(ctx, ars_stat)) + return 0; + if (rec_index >= ars_stat->ars_status->num_records) { dbg(ctx, "invalid record index\n"); return 0; } - if (ars_stat->type == ND_CMD_ARS_STATUS && ars_stat->status == 0) - return ars_stat->ars_status->records[rec_index].length; + return ars_stat->ars_status->records[rec_index].length; +} - dbg(ctx, "invalid ars_status\n"); - return 0; +NDCTL_EXPORT int ndctl_cmd_ars_stat_get_flag_overflow( + struct ndctl_cmd *ars_stat) +{ + struct ndctl_ctx *ctx = ndctl_bus_get_ctx(cmd_to_bus(ars_stat)); + + if (!validate_ars_stat(ctx, ars_stat)) + return -EINVAL; + + return !!(ars_stat->ars_status->flags & ND_ARS_STAT_FLAG_OVERFLOW); } NDCTL_EXPORT struct ndctl_cmd *ndctl_bus_cmd_new_clear_error( diff -Nru ndctl-60.1/ndctl/lib/inject.c ndctl-61.2/ndctl/lib/inject.c --- ndctl-60.1/ndctl/lib/inject.c 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/ndctl/lib/inject.c 2018-07-06 23:33:14.000000000 +0000 @@ -89,90 +89,191 @@ return 0; } -NDCTL_EXPORT int ndctl_namespace_inject_error(struct ndctl_namespace *ndns, - unsigned long long block, unsigned long long count, bool notify) +static int ndctl_namespace_get_clear_unit(struct ndctl_namespace *ndns) +{ + struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns); + struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus); + unsigned long long ns_offset, ns_size; + unsigned int clear_unit; + struct ndctl_cmd *cmd; + int rc; + + ndctl_namespace_get_injection_bounds(ndns, &ns_offset, + &ns_size); + cmd = ndctl_bus_cmd_new_ars_cap(bus, ns_offset, ns_size); + rc = ndctl_cmd_submit(cmd); + if (rc) { + dbg(ctx, "Error submitting ars_cap: %d\n", rc); + return rc; + } + clear_unit = ndctl_cmd_ars_cap_get_clear_unit(cmd); + if (clear_unit == 0) { + dbg(ctx, "Got an invalid clear_err_unit from ars_cap\n"); + return -EINVAL; + } + + ndctl_cmd_unref(cmd); + return clear_unit; +} + +static int ndctl_namespace_inject_one_error(struct ndctl_namespace *ndns, + unsigned long long block, unsigned int flags) { struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns); struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus); struct nd_cmd_ars_err_inj *err_inj; struct nd_cmd_pkg *pkg; struct ndctl_cmd *cmd; - int rc = -EOPNOTSUPP; + u64 offset, length; + int rc, clear_unit; - if (!ndctl_bus_has_error_injection(bus)) - return -EOPNOTSUPP; + rc = block_to_spa_offset(ndns, block, 1, &offset, &length); + if (rc) + return rc; + + clear_unit = ndctl_namespace_get_clear_unit(ndns); + if (clear_unit < 0) + return clear_unit; + + if (!(flags & (1 << NDCTL_NS_INJECT_SATURATE))) { + /* clamp injection length per block to the clear_unit */ + if (length > (unsigned int)clear_unit) + length = clear_unit; + } - if (ndctl_bus_has_nfit(bus)) { - u64 offset, length; + cmd = ndctl_bus_cmd_new_err_inj(bus); + if (!cmd) + return -ENOMEM; + + pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0]; + err_inj = (struct nd_cmd_ars_err_inj *)&pkg->nd_payload[0]; + err_inj->err_inj_spa_range_base = offset; + err_inj->err_inj_spa_range_length = length; + if (flags & (1 << NDCTL_NS_INJECT_NOTIFY)) + err_inj->err_inj_options |= + (1 << ND_ARS_ERR_INJ_OPT_NOTIFY); + + rc = ndctl_cmd_submit(cmd); + if (rc) { + dbg(ctx, "Error submitting command: %d\n", rc); + goto out; + } + rc = translate_status(err_inj->status); + out: + ndctl_cmd_unref(cmd); + return rc; +} - rc = block_to_spa_offset(ndns, block, count, &offset, &length); - if (rc) - return rc; - cmd = ndctl_bus_cmd_new_err_inj(bus); - if (!cmd) - return -ENOMEM; - - pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0]; - err_inj = (struct nd_cmd_ars_err_inj *)&pkg->nd_payload[0]; - err_inj->err_inj_spa_range_base = offset; - err_inj->err_inj_spa_range_length = length; - if (notify) - err_inj->err_inj_options |= - (1 << ND_ARS_ERR_INJ_OPT_NOTIFY); +NDCTL_EXPORT int ndctl_namespace_inject_error2(struct ndctl_namespace *ndns, + unsigned long long block, unsigned long long count, + unsigned int flags) +{ + struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns); + struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus); + unsigned long long i; + int rc = -EINVAL; - rc = ndctl_cmd_submit(cmd); + if (!ndctl_bus_has_error_injection(bus)) + return -EOPNOTSUPP; + if (!ndctl_bus_has_nfit(bus)) + return -EOPNOTSUPP; + + for (i = 0; i < count; i++) { + rc = ndctl_namespace_inject_one_error(ndns, block + i, flags); if (rc) { - dbg(ctx, "Error submitting command: %d\n", rc); - goto out; + err(ctx, "Injection failed at block %llx\n", + block + i); + return rc; } - rc = translate_status(err_inj->status); - out: - ndctl_cmd_unref(cmd); } return rc; } -NDCTL_EXPORT int ndctl_namespace_uninject_error(struct ndctl_namespace *ndns, - unsigned long long block, unsigned long long count) +NDCTL_EXPORT int ndctl_namespace_inject_error(struct ndctl_namespace *ndns, + unsigned long long block, unsigned long long count, bool notify) +{ + return ndctl_namespace_inject_error2(ndns, block, count, + notify ? (1 << NDCTL_NS_INJECT_NOTIFY) : 0); +} + +static int ndctl_namespace_uninject_one_error(struct ndctl_namespace *ndns, + unsigned long long block, unsigned int flags) { struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns); struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus); struct nd_cmd_ars_err_inj_clr *err_inj_clr; struct nd_cmd_pkg *pkg; struct ndctl_cmd *cmd; - int rc = -EOPNOTSUPP; + u64 offset, length; + int rc, clear_unit; - if (!ndctl_bus_has_error_injection(bus)) - return -EOPNOTSUPP; + rc = block_to_spa_offset(ndns, block, 1, &offset, &length); + if (rc) + return rc; + + clear_unit = ndctl_namespace_get_clear_unit(ndns); + if (clear_unit < 0) + return clear_unit; + + if (!(flags & (1 << NDCTL_NS_INJECT_SATURATE))) { + /* clamp injection length per block to the clear_unit */ + if (length > (unsigned int)clear_unit) + length = clear_unit; + } - if (ndctl_bus_has_nfit(bus)) { - u64 offset, length; + cmd = ndctl_bus_cmd_new_err_inj_clr(bus); + if (!cmd) + return -ENOMEM; + + pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0]; + err_inj_clr = + (struct nd_cmd_ars_err_inj_clr *)&pkg->nd_payload[0]; + err_inj_clr->err_inj_clr_spa_range_base = offset; + err_inj_clr->err_inj_clr_spa_range_length = length; + + rc = ndctl_cmd_submit(cmd); + if (rc) { + dbg(ctx, "Error submitting command: %d\n", rc); + goto out; + } + rc = translate_status(err_inj_clr->status); + out: + ndctl_cmd_unref(cmd); + return rc; +} - rc = block_to_spa_offset(ndns, block, count, &offset, &length); - if (rc) - return rc; - cmd = ndctl_bus_cmd_new_err_inj_clr(bus); - if (!cmd) - return -ENOMEM; - - pkg = (struct nd_cmd_pkg *)&cmd->cmd_buf[0]; - err_inj_clr = - (struct nd_cmd_ars_err_inj_clr *)&pkg->nd_payload[0]; - err_inj_clr->err_inj_clr_spa_range_base = offset; - err_inj_clr->err_inj_clr_spa_range_length = length; +NDCTL_EXPORT int ndctl_namespace_uninject_error2(struct ndctl_namespace *ndns, + unsigned long long block, unsigned long long count, + unsigned int flags) +{ + struct ndctl_bus *bus = ndctl_namespace_get_bus(ndns); + struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus); + unsigned long long i; + int rc = -EINVAL; + + if (!ndctl_bus_has_error_injection(bus)) + return -EOPNOTSUPP; + if (!ndctl_bus_has_nfit(bus)) + return -EOPNOTSUPP; - rc = ndctl_cmd_submit(cmd); + for (i = 0; i < count; i++) { + rc = ndctl_namespace_uninject_one_error(ndns, block + i, + flags); if (rc) { - dbg(ctx, "Error submitting command: %d\n", rc); - goto out; + err(ctx, "Un-injection failed at block %llx\n", + block + i); + return rc; } - rc = translate_status(err_inj_clr->status); - out: - ndctl_cmd_unref(cmd); } return rc; } +NDCTL_EXPORT int ndctl_namespace_uninject_error(struct ndctl_namespace *ndns, + unsigned long long block, unsigned long long count) +{ + return ndctl_namespace_uninject_error2(ndns, block, count, 0); +} + static int bb_add_record(struct list_head *h, u64 block, u64 count) { struct ndctl_bb *bb, *bb_iter, *bb_next, *bb_prev; diff -Nru ndctl-60.1/ndctl/lib/libndctl.c ndctl-61.2/ndctl/lib/libndctl.c --- ndctl-60.1/ndctl/lib/libndctl.c 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/ndctl/lib/libndctl.c 2018-07-06 23:33:14.000000000 +0000 @@ -1243,12 +1243,19 @@ break; } dbg(ctx, "poll wake: revents: %d\n", fds.revents); - pread(fd, buf, 1, 0); + if (pread(fd, buf, 1, 0) == -1) { + rc = -errno; + break; + } fds.revents = 0; } } - dbg(ctx, "bus%d: scrub complete\n", ndctl_bus_get_id(bus)); + if (rc == 0) + dbg(ctx, "bus%d: scrub complete\n", ndctl_bus_get_id(bus)); + else + dbg(ctx, "bus%d: error waiting for scrub completion: %s\n", + ndctl_bus_get_id(bus), strerror(-rc)); if (fd) close (fd); return rc; @@ -3991,10 +3998,10 @@ { struct ndctl_ctx *ctx = ndctl_namespace_get_ctx(ndns); struct ndctl_pfn *pfn = ndctl_namespace_get_pfn(ndns); + char *path = ndns->ndns_buf; char buf[SYSFS_ATTR_SIZE]; int len = ndns->buf_len; const char *bdev; - char path[50]; if (state != 1 && state != 0) return -ENXIO; @@ -4034,9 +4041,9 @@ struct ndctl_ctx *ctx = ndctl_namespace_get_ctx(ndns); struct ndctl_pfn *pfn = ndctl_namespace_get_pfn(ndns); int len = ndns->buf_len, wc; + char *path = ndns->ndns_buf; char buf[SYSFS_ATTR_SIZE]; const char *bdev; - char path[50]; if (pfn) bdev = ndctl_pfn_get_block_device(pfn); diff -Nru ndctl-60.1/ndctl/lib/libndctl.sym ndctl-61.2/ndctl/lib/libndctl.sym --- ndctl-60.1/ndctl/lib/libndctl.sym 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/ndctl/lib/libndctl.sym 2018-07-06 23:33:14.000000000 +0000 @@ -359,3 +359,11 @@ ndctl_bus_start_scrub; ndctl_region_deep_flush; } LIBNDCTL_14; + +LIBNDCTL_16 { +global: + ndctl_cmd_ars_cap_get_clear_unit; + ndctl_namespace_inject_error2; + ndctl_namespace_uninject_error2; + ndctl_cmd_ars_stat_get_flag_overflow; +} LIBNDCTL_15; diff -Nru ndctl-60.1/ndctl/lib/private.h ndctl-61.2/ndctl/lib/private.h --- ndctl-60.1/ndctl/lib/private.h 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/ndctl/lib/private.h 2018-07-06 23:33:14.000000000 +0000 @@ -278,6 +278,9 @@ struct list_node list; }; +/* ars_status flags */ +#define ND_ARS_STAT_FLAG_OVERFLOW (1 << 0) + struct ndctl_dimm_ops { const char *(*cmd_desc)(int); struct ndctl_cmd *(*new_smart)(struct ndctl_dimm *); diff -Nru ndctl-60.1/ndctl/libndctl.h ndctl-61.2/ndctl/libndctl.h --- ndctl-60.1/ndctl/libndctl.h 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/ndctl/libndctl.h 2018-07-06 23:33:14.000000000 +0000 @@ -209,6 +209,8 @@ unsigned long long len, struct ndctl_cmd *ars_cap); unsigned long long ndctl_cmd_clear_error_get_cleared( struct ndctl_cmd *clear_err); +unsigned int ndctl_cmd_ars_cap_get_clear_unit(struct ndctl_cmd *ars_cap); +int ndctl_cmd_ars_stat_get_flag_overflow(struct ndctl_cmd *ars_stat); /* * Note: ndctl_cmd_smart_get_temperature is an alias for @@ -478,9 +480,19 @@ int ndctl_namespace_inject_error(struct ndctl_namespace *ndns, unsigned long long block, unsigned long long count, bool notify); +int ndctl_namespace_inject_error2(struct ndctl_namespace *ndns, + unsigned long long block, unsigned long long count, + unsigned int flags); int ndctl_namespace_uninject_error(struct ndctl_namespace *ndns, unsigned long long block, unsigned long long count); +int ndctl_namespace_uninject_error2(struct ndctl_namespace *ndns, + unsigned long long block, unsigned long long count, + unsigned int flags); int ndctl_namespace_injection_status(struct ndctl_namespace *ndns); +enum ndctl_namespace_inject_flags { + NDCTL_NS_INJECT_NOTIFY = 0, + NDCTL_NS_INJECT_SATURATE, +}; struct ndctl_bb; unsigned long long ndctl_bb_get_block(struct ndctl_bb *bb); diff -Nru ndctl-60.1/ndctl/util/json-smart.c ndctl-61.2/ndctl/util/json-smart.c --- ndctl-60.1/ndctl/util/json-smart.c 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/ndctl/util/json-smart.c 2018-07-06 23:33:14.000000000 +0000 @@ -47,6 +47,18 @@ "temperature_threshold", jobj); } + if (alarm_control & ND_SMART_CTEMP_TRIP) { + unsigned int temp; + double t; + + temp = ndctl_cmd_smart_threshold_get_ctrl_temperature(cmd); + t = ndctl_decode_smart_temperature(temp); + jobj = json_object_new_double(t); + if (jobj) + json_object_object_add(jhealth, + "controller_temperature_threshold", jobj); + } + if (alarm_control & ND_SMART_SPARE_TRIP) { unsigned int spares; @@ -109,6 +121,16 @@ json_object_object_add(jhealth, "temperature_celsius", jobj); } + if (flags & ND_SMART_CTEMP_VALID) { + unsigned int temp = ndctl_cmd_smart_get_ctrl_temperature(cmd); + double t = ndctl_decode_smart_temperature(temp); + + jobj = json_object_new_double(t); + if (jobj) + json_object_object_add(jhealth, + "controller_temperature_celsius", jobj); + } + if (flags & ND_SMART_SPARES_VALID) { unsigned int spares = ndctl_cmd_smart_get_spares(cmd); @@ -120,12 +142,17 @@ if (flags & ND_SMART_ALARM_VALID) { unsigned int alarm_flags = ndctl_cmd_smart_get_alarm_flags(cmd); bool temp_flag = !!(alarm_flags & ND_SMART_TEMP_TRIP); + bool ctrl_temp_flag = !!(alarm_flags & ND_SMART_CTEMP_TRIP); bool spares_flag = !!(alarm_flags & ND_SMART_SPARE_TRIP); jobj = json_object_new_boolean(temp_flag); if (jobj) json_object_object_add(jhealth, "alarm_temperature", jobj); + jobj = json_object_new_boolean(ctrl_temp_flag); + if (jobj) + json_object_object_add(jhealth, "alarm_controller_temperature", jobj); + jobj = json_object_new_boolean(spares_flag); if (jobj) json_object_object_add(jhealth, "alarm_spares", jobj); diff -Nru ndctl-60.1/README.md ndctl-61.2/README.md --- ndctl-60.1/README.md 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/README.md 2018-07-06 23:33:14.000000000 +0000 @@ -5,11 +5,14 @@ Build ===== -`./autogen.sh` -`./configure CFLAGS='-g -O0' --prefix=/usr --sysconfdir=/etc --libdir=/usr/lib64` -`make` -`make check` -`sudo make install` + +``` +./autogen.sh +./configure CFLAGS='-g -O2' --prefix=/usr --sysconfdir=/etc --libdir=/usr/lib64 +make +make check +sudo make install +``` There are a number of packages required for the build steps that may not be installed by default. For information about the required packages, @@ -23,45 +26,56 @@ https://git.kernel.org/cgit/linux/kernel/git/nvdimm/nvdimm.git/tree/Documentation/nvdimm/nvdimm.txt?h=libnvdimm-for-next +A getting started guide is also available on the kernel.org nvdimm wiki: + +https://nvdimm.wiki.kernel.org/start + Unit Tests ========== The unit tests run by `make check` require the nfit_test.ko module to be loaded. To build and install nfit_test.ko: 1. Obtain the kernel source. For example, -`git clone -b libnvdimm-for-next -git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git` + `git clone -b libnvdimm-for-next git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm.git` -2. Skip to step 3 if the kernel version is >= v4.8. Otherwise, for +1. Skip to step 3 if the kernel version is >= v4.8. Otherwise, for kernel versions < v4.8, configure the kernel to make some memory available to CMA (contiguous memory allocator). This will be used to emulate DAX. -`CONFIG_DMA_CMA=y` -`CONFIG_CMA_SIZE_MBYTES=200` -**or** -`cma=200M` on the kernel command line. + ``` + CONFIG_DMA_CMA=y + CONFIG_CMA_SIZE_MBYTES=200 + ``` + **or** + `cma=200M` on the kernel command line. -3. Compile the libnvdimm sub-system as a module, make sure "zone device" +1. Compile the libnvdimm sub-system as a module, make sure "zone device" memory is enabled, and enable the btt, pfn, and dax features of the sub-system: -`CONFIG_X86_PMEM_LEGACY=m` -`CONFIG_ZONE_DEVICE=y` -`CONFIG_LIBNVDIMM=m` -`CONFIG_BLK_DEV_PMEM=m` -`CONFIG_ND_BLK=m` -`CONFIG_BTT=y` -`CONFIG_NVDIMM_PFN=y` -`CONFIG_NVDIMM_DAX=y` -`CONFIG_DEV_DAX_PMEM=m` -4. Build and install the unit test enabled libnvdimm modules in the + ``` + CONFIG_X86_PMEM_LEGACY=m + CONFIG_ZONE_DEVICE=y + CONFIG_LIBNVDIMM=m + CONFIG_BLK_DEV_PMEM=m + CONFIG_ND_BLK=m + CONFIG_BTT=y + CONFIG_NVDIMM_PFN=y + CONFIG_NVDIMM_DAX=y + CONFIG_DEV_DAX_PMEM=m + ``` + +1. Build and install the unit test enabled libnvdimm modules in the following order. The unit test modules need to be in place prior to the `depmod` that runs during the final `modules_install` -`make M=tools/testing/nvdimm` -`sudo make M=tools/testing/nvdimm modules_install` -`sudo make modules_install` -5. Now run `make check` in the ndctl source directory, or `ndctl test`, + ``` + make M=tools/testing/nvdimm + sudo make M=tools/testing/nvdimm modules_install + sudo make modules_install + ``` + +1. Now run `make check` in the ndctl source directory, or `ndctl test`, if ndctl was built with `--enable-test`. Troubleshooting @@ -73,23 +87,29 @@ superseded by the "in-tree/production" version of the modules `make check` will skip tests and report a message like the following in test/test-suite.log: -`SKIP: libndctl` -`==============` -`test/init: nfit_test_init: nfit.ko: appears to be production version: /lib/modules/4.8.8-200.fc24.x86_64/kernel/drivers/acpi/nfit/nfit.ko.xz` -`__ndctl_test_skip: explicit skip test_libndctl:2684` -`nfit_test unavailable skipping tests` + +``` +SKIP: libndctl +============== +test/init: nfit_test_init: nfit.ko: appears to be production version: /lib/modules/4.8.8-200.fc24.x86_64/kernel/drivers/acpi/nfit/nfit.ko.xz +__ndctl_test_skip: explicit skip test_libndctl:2684 +nfit_test unavailable skipping tests +``` If the unit test modules are indeed available in the modules 'extra' directory the default depmod policy can be overridden by adding a file to /etc/depmod.d with the following contents: -`override nfit * extra` -`override device_dax * extra` -`override dax_pmem * extra` -`override libnvdimm * extra` -`override nd_blk * extra` -`override nd_btt * extra` -`override nd_e820 * extra` -`override nd_pmem * extra` + +``` +override nfit * extra +override device_dax * extra +override dax_pmem * extra +override libnvdimm * extra +override nd_blk * extra +override nd_btt * extra +override nd_e820 * extra +override nd_pmem * extra +``` The nfit_test module emulates pmem with memory allocated via vmalloc(). One of the side effects is that this breaks 'physically contiguous' diff -Nru ndctl-60.1/test/blk-exhaust.sh ndctl-61.2/test/blk-exhaust.sh --- ndctl-60.1/test/blk-exhaust.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/blk-exhaust.sh 2018-07-06 23:33:14.000000000 +0000 @@ -11,49 +11,31 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -NDCTL="../ndctl/ndctl" -BUS="-b nfit_test.0" -BUS1="-b nfit_test.1" -rc=77 - set -e -err() { - echo "test/label-compat.sh: failed at line $1" - exit $rc -} - -check_min_kver() -{ - local ver="$1" - : "${KVER:=$(uname -r)}" - - [ -n "$ver" ] || return 1 - [[ "$ver" == "$(echo -e "$ver\n$KVER" | sort -V | head -1)" ]] -} +rc=77 -check_min_kver "4.11" || { echo "kernel $KVER may lack blk-exhaustion fix"; exit $rc; } +. ./common + +check_min_kver "4.11" || do_skip "may lack blk-exhaustion fix" -set -e trap 'err $LINENO' ERR # setup (reset nfit_test dimms) modprobe nfit_test -$NDCTL disable-region $BUS all -$NDCTL zero-labels $BUS all -$NDCTL enable-region $BUS all +$NDCTL disable-region -b $NFIT_TEST_BUS0 all +$NDCTL zero-labels -b $NFIT_TEST_BUS0 all +$NDCTL enable-region -b $NFIT_TEST_BUS0 all # if the kernel accounting is correct we should be able to create two # pmem and two blk namespaces on nfit_test.0 rc=1 -$NDCTL create-namespace $BUS -t pmem -$NDCTL create-namespace $BUS -t pmem -$NDCTL create-namespace $BUS -t blk -m raw -$NDCTL create-namespace $BUS -t blk -m raw +$NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem +$NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem +$NDCTL create-namespace -b $NFIT_TEST_BUS0 -t blk -m raw +$NDCTL create-namespace -b $NFIT_TEST_BUS0 -t blk -m raw # clearnup and exit -$NDCTL disable-region $BUS all -$NDCTL disable-region $BUS1 all -modprobe -r nfit_test +_cleanup exit 0 diff -Nru ndctl-60.1/test/btt-check.sh ndctl-61.2/test/btt-check.sh --- ndctl-60.1/test/btt-check.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/btt-check.sh 2018-07-06 23:33:14.000000000 +0000 @@ -11,11 +11,6 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -[ -f "../ndctl/ndctl" ] && [ -x "../ndctl/ndctl" ] && ndctl="../ndctl/ndctl" -[ -f "./ndctl/ndctl" ] && [ -x "./ndctl/ndctl" ] && ndctl="./ndctl/ndctl" -[ -z "$ndctl" ] && echo "Couldn't find an ndctl binary" && exit 1 -bus="nfit_test.0" -json2var="s/[{}\",]//g; s/:/=/g" dev="" mode="" size="" @@ -24,6 +19,8 @@ bs=4096 rc=77 +. ./common + trap 'err $LINENO' ERR # sample json: @@ -36,43 +33,26 @@ # "blockdev":"pmem5s" # } -# $1: Line number -# $2: exit code -err() -{ - [ -n "$2" ] && rc="$2" - echo "test/btt-check: failed at line $1" - exit "$rc" -} - -check_min_kver() -{ - local ver="$1" - : "${KVER:=$(uname -r)}" - - [ -n "$ver" ] || return 1 - [[ "$ver" == "$(echo -e "$ver\n$KVER" | sort -V | head -1)" ]] -} - -check_min_kver "4.14" || { echo "kernel $KVER may not support badblocks clearing on pmem via btt"; exit $rc; } +check_min_kver "4.14" || do_skip "may not support badblocks clearing on pmem via btt" create() { - json=$($ndctl create-namespace -b "$bus" -t pmem -m sector) - eval "$(echo "$json" | sed -e "$json2var")" - [ -n "$dev" ] || err "$LINENO" 2 - [ "$mode" = "sector" ] || err "$LINENO" 2 - [ -n "$size" ] || err "$LINENO" 2 - [ -n "$sector_size" ] || err "$LINENO" 2 - [ -n "$blockdev" ] || err "$LINENO" 2 - [ $size -gt 0 ] || err "$LINENO" 2 + json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m sector) + rc=2 + eval "$(echo "$json" | json2var)" + [ -n "$dev" ] || err "$LINENO" + [ "$mode" = "sector" ] || err "$LINENO" + [ -n "$size" ] || err "$LINENO" + [ -n "$sector_size" ] || err "$LINENO" + [ -n "$blockdev" ] || err "$LINENO" + [ $size -gt 0 ] || err "$LINENO" } reset() { - $ndctl disable-region -b "$bus" all - $ndctl zero-labels -b "$bus" all - $ndctl enable-region -b "$bus" all + $NDCTL disable-region -b $NFIT_TEST_BUS0 all + $NDCTL zero-labels -b $NFIT_TEST_BUS0 all + $NDCTL enable-region -b $NFIT_TEST_BUS0 all } # re-enable the BTT namespace, and do IO to it in an attempt to @@ -93,25 +73,25 @@ { echo "=== ${FUNCNAME[0]} ===" # disable the namespace - $ndctl disable-namespace $dev - $ndctl check-namespace $dev - $ndctl enable-namespace $dev + $NDCTL disable-namespace $dev + $NDCTL check-namespace $dev + $NDCTL enable-namespace $dev post_repair_test } test_force() { echo "=== ${FUNCNAME[0]} ===" - $ndctl check-namespace --force $dev + $NDCTL check-namespace --force $dev post_repair_test } set_raw() { - $ndctl disable-namespace $dev + $NDCTL disable-namespace $dev echo -n "set raw_mode: " echo 1 | tee /sys/bus/nd/devices/$dev/force_raw - $ndctl enable-namespace $dev + $NDCTL enable-namespace $dev raw_bdev="${blockdev%%s}" test -b /dev/$raw_bdev raw_size="$(cat /sys/bus/nd/devices/$dev/size)" @@ -119,10 +99,10 @@ unset_raw() { - $ndctl disable-namespace $dev + $NDCTL disable-namespace $dev echo -n "set raw_mode: " echo 0 | tee /sys/bus/nd/devices/$dev/force_raw - $ndctl enable-namespace $dev + $NDCTL enable-namespace $dev raw_bdev="" } @@ -134,10 +114,10 @@ echo "wiping info2 block (offset = $seek blocks)" dd if=/dev/zero of=/dev/$raw_bdev bs=$bs count=1 seek=$seek unset_raw - $ndctl disable-namespace $dev - $ndctl check-namespace $dev 2>&1 | grep "info2 needs to be restored" - $ndctl check-namespace --repair $dev - $ndctl enable-namespace $dev + $NDCTL disable-namespace $dev + $NDCTL check-namespace $dev 2>&1 | grep "info2 needs to be restored" + $NDCTL check-namespace --repair $dev + $NDCTL enable-namespace $dev post_repair_test } @@ -148,10 +128,10 @@ echo "wiping info block" dd if=/dev/zero of=/dev/$raw_bdev bs=$bs count=2 seek=0 unset_raw - $ndctl disable-namespace $dev - $ndctl check-namespace $dev 2>&1 | grep -E "info block at offset .* needs to be restored" - $ndctl check-namespace --repair $dev - $ndctl enable-namespace $dev + $NDCTL disable-namespace $dev + $NDCTL check-namespace $dev 2>&1 | grep -E "info block at offset .* needs to be restored" + $NDCTL check-namespace --repair $dev + $NDCTL enable-namespace $dev post_repair_test } @@ -170,8 +150,8 @@ dd if=/tmp/scribble of=/dev/$raw_bdev bs=$bs seek=$seek rm -f /tmp/scribble unset_raw - $ndctl disable-namespace $dev - $ndctl check-namespace $dev 2>&1 | grep "bitmap error" + $NDCTL disable-namespace $dev + $NDCTL check-namespace $dev 2>&1 | grep "bitmap error" # This is not repairable reset && create } @@ -191,4 +171,5 @@ reset && create do_tests reset +_cleanup exit 0 diff -Nru ndctl-60.1/test/btt-errors.sh ndctl-61.2/test/btt-errors.sh --- ndctl-60.1/test/btt-errors.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/btt-errors.sh 2018-07-06 23:33:14.000000000 +0000 @@ -11,18 +11,15 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -NDCTL="../ndctl/ndctl" -BUS="nfit_test.0" MNT=test_btt_mnt FILE=image -json2var="s/[{}\",]//g; s/:/=/g" blockdev="" rc=77 -err() { - rc=1 - echo "test/btt-errors: failed at line $1" +. ./common +cleanup() +{ rm -f $FILE rm -f $MNT/$FILE if [ -n "$blockdev" ]; then @@ -31,16 +28,6 @@ rc=77 fi rmdir $MNT - exit $rc -} - -check_min_kver() -{ - local ver="$1" - : "${KVER:=$(uname -r)}" - - [ -n "$ver" ] || return 1 - [[ "$ver" == "$(echo -e "$ver\n$KVER" | sort -V | head -1)" ]] } force_raw() @@ -59,24 +46,24 @@ fi } -check_min_kver "4.15" || { echo "kernel $KVER may lack BTT error handling"; exit $rc; } +check_min_kver "4.15" || do_skip "may lack BTT error handling" set -e mkdir -p $MNT -trap 'err $LINENO' ERR +trap 'err $LINENO cleanup' ERR # setup (reset nfit_test dimms) modprobe nfit_test -$NDCTL disable-region -b "$BUS" all -$NDCTL zero-labels -b "$BUS" all -$NDCTL enable-region -b "$BUS" all +$NDCTL disable-region -b $NFIT_TEST_BUS0 all +$NDCTL zero-labels -b $NFIT_TEST_BUS0 all +$NDCTL enable-region -b $NFIT_TEST_BUS0 all rc=1 # create a btt namespace and clear errors (if any) dev="x" -json=$($NDCTL create-namespace -b "$BUS" -t pmem -m sector) -eval "$(echo "$json" | sed -e "$json2var")" +json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m sector) +eval "$(echo "$json" | json2var)" [ $dev = "x" ] && echo "fail: $LINENO" && exit 1 force_raw 1 @@ -147,12 +134,12 @@ # reset everything to get a clean log if grep -q "$MNT" /proc/mounts; then umount $MNT; fi -$NDCTL disable-region -b "$BUS" all -$NDCTL zero-labels -b "$BUS" all -$NDCTL enable-region -b "$BUS" all +$NDCTL disable-region -b $NFIT_TEST_BUS0 all +$NDCTL zero-labels -b $NFIT_TEST_BUS0 all +$NDCTL enable-region -b $NFIT_TEST_BUS0 all dev="x" -json=$($NDCTL create-namespace -b "$BUS" -t pmem -m sector) -eval "$(echo "$json" | sed -e "$json2var")" +json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m sector) +eval "$(echo "$json" | json2var)" [ $dev = "x" ] && echo "fail: $LINENO" && exit 1 # insert error at an arbitrary offset in the map (sector 0) @@ -168,7 +155,8 @@ dd if=/dev/$blockdev of=/dev/null iflag=direct bs=4096 count=1 && err $LINENO || true # done, exit -$NDCTL disable-region -b "$BUS" all -$NDCTL zero-labels -b "$BUS" all -$NDCTL enable-region -b "$BUS" all +$NDCTL disable-region -b $NFIT_TEST_BUS0 all +$NDCTL zero-labels -b $NFIT_TEST_BUS0 all +$NDCTL enable-region -b $NFIT_TEST_BUS0 all +_cleanup exit 0 diff -Nru ndctl-60.1/test/btt-pad-compat.sh ndctl-61.2/test/btt-pad-compat.sh --- ndctl-60.1/test/btt-pad-compat.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/btt-pad-compat.sh 2018-07-06 23:33:14.000000000 +0000 @@ -11,16 +11,13 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -[ -f "../ndctl/ndctl" ] && [ -x "../ndctl/ndctl" ] && ndctl="../ndctl/ndctl" -[ -f "./ndctl/ndctl" ] && [ -x "./ndctl/ndctl" ] && ndctl="./ndctl/ndctl" -[ -z "$ndctl" ] && echo "Couldn't find an ndctl binary" && exit 1 -bus="nfit_test.0" -json2var="s/[{}\",]//g; s/:/=/g" dev="" size="" blockdev="" rc=77 +. ./common + trap 'err $LINENO' ERR # sample json: @@ -32,44 +29,27 @@ # "blockdev":"pmem7", #} -# $1: Line number -# $2: exit code -err() -{ - [ -n "$2" ] && rc="$2" - echo "test/btt-pad-compat.sh: failed at line $1" - exit "$rc" -} - -check_prereq() -{ - if ! command -v "$1" >/dev/null; then - echo "missing '$1', skipping.." - exit "$rc" - fi -} - create() { - json=$($ndctl create-namespace -b "$bus" -t pmem -m sector) - eval "$(echo "$json" | sed -e "$json2var")" - [ -n "$dev" ] || err "$LINENO" 2 - [ -n "$size" ] || err "$LINENO" 2 - [ -n "$blockdev" ] || err "$LINENO" 2 - [ $size -gt 0 ] || err "$LINENO" 2 + json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m sector) + rc=2 + eval "$(echo "$json" | json2var)" + [ -n "$dev" ] || err "$LINENO" + [ -n "$size" ] || err "$LINENO" + [ -n "$blockdev" ] || err "$LINENO" + [ $size -gt 0 ] || err "$LINENO" bttdev=$(cat /sys/bus/nd/devices/$dev/holder) - [ -n "$bttdev" ] || err "$LINENO" 2 + [ -n "$bttdev" ] || err "$LINENO" if [ ! -e /sys/kernel/debug/btt/$bttdev/arena0/log_index_0 ]; then - echo "kernel $(uname -r) seems to be missing the BTT compatibility fixes, skipping" - exit 77 + do_skip "seems to be missing the BTT compatibility fixes, skipping." fi } reset() { - $ndctl disable-region -b "$bus" all - $ndctl zero-labels -b "$bus" all - $ndctl enable-region -b "$bus" all + $NDCTL disable-region -b $NFIT_TEST_BUS0 all + $NDCTL zero-labels -b $NFIT_TEST_BUS0 all + $NDCTL enable-region -b $NFIT_TEST_BUS0 all } verify_idx() @@ -105,16 +85,16 @@ { local ns="$1" - $ndctl disable-namespace $ns - $ndctl enable-namespace $ns + $NDCTL disable-namespace $ns + $NDCTL enable-namespace $ns } force_raw() { raw="$1" - $ndctl disable-namespace "$dev" + $NDCTL disable-namespace "$dev" echo "$raw" > "/sys/bus/nd/devices/$dev/force_raw" - $ndctl enable-namespace "$dev" + $NDCTL enable-namespace "$dev" echo "Set $dev to raw mode: $raw" if [[ "$raw" == "1" ]]; then raw_bdev=${blockdev%s} @@ -140,23 +120,24 @@ # that supports a raw namespace with a 4K sector size, prior to # v4.13 raw namespaces are limited to 512-byte sector size. rc=77 - json=$($ndctl create-namespace -b "$bus" -s 64M -t pmem -m raw -l 4096 -u 00000000-0000-0000-0000-000000000000) - rc=1 - eval "$(echo "$json" | sed -e "$json2var")" - [ -n "$dev" ] || err "$LINENO" 2 - [ -n "$size" ] || err "$LINENO" 2 - [ $size -gt 0 ] || err "$LINENO" 2 + json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -s 64M -t pmem -m raw -l 4096 -u 00000000-0000-0000-0000-000000000000) + rc=2 + eval "$(echo "$json" | json2var)" + [ -n "$dev" ] || err "$LINENO" + [ -n "$size" ] || err "$LINENO" + [ $size -gt 0 ] || err "$LINENO" # reconfig it to sector mode - json=$($ndctl create-namespace -b "$bus" -e $dev -m sector --force) - eval "$(echo "$json" | sed -e "$json2var")" - [ -n "$dev" ] || err "$LINENO" 2 - [ -n "$size" ] || err "$LINENO" 2 - [ -n "$blockdev" ] || err "$LINENO" 2 - [ $size -gt 0 ] || err "$LINENO" 2 + json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -e $dev -m sector --force) + eval "$(echo "$json" | json2var)" + [ -n "$dev" ] || err "$LINENO" + [ -n "$size" ] || err "$LINENO" + [ -n "$blockdev" ] || err "$LINENO" + [ $size -gt 0 ] || err "$LINENO" bttdev=$(cat /sys/bus/nd/devices/$dev/holder) - [ -n "$bttdev" ] || err "$LINENO" 2 + [ -n "$bttdev" ] || err "$LINENO" + rc=1 # copy old-padding-format btt image, and try to re-enable the resulting btt force_raw 1 copy_xxd_img "/dev/$raw_bdev" @@ -192,13 +173,13 @@ verify_idx 0 2 # rewrite log using ndctl, verify conversion to new format - $ndctl check-namespace --rewrite-log --repair --force --verbose $dev + $NDCTL check-namespace --rewrite-log --repair --force --verbose $dev do_random_io "/dev/$blockdev" cycle_ns "$dev" verify_idx 0 1 # check-namespace again to make sure everything is ok - $ndctl check-namespace --force --verbose $dev + $NDCTL check-namespace --force --verbose $dev # the old format btt metadata was created with a null parent uuid, # making it 'stickier' than a normally created btt. Be sure to clean @@ -212,4 +193,5 @@ reset do_tests reset +_cleanup exit 0 diff -Nru ndctl-60.1/test/clear.sh ndctl-61.2/test/clear.sh --- ndctl-60.1/test/clear.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/clear.sh 2018-07-06 23:33:14.000000000 +0000 @@ -11,46 +11,28 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -DEV="" -NDCTL="../ndctl/ndctl" -BUS="-b nfit_test.0" -BUS1="-b nfit_test.1" -json2var="s/[{}\",]//g; s/:/=/g" -rc=77 - set -e -err() { - echo "test/clear: failed at line $1" - exit $rc -} - -check_min_kver() -{ - local ver="$1" - : "${KVER:=$(uname -r)}" - - [ -n "$ver" ] || return 1 - [[ "$ver" == "$(echo -e "$ver\n$KVER" | sort -V | head -1)" ]] -} +rc=77 -check_min_kver "4.6" || { echo "kernel $KVER lacks clear poison support"; exit $rc; } +. ./common + +check_min_kver "4.6" || do_skip "lacks clear poison support" -set -e trap 'err $LINENO' ERR # setup (reset nfit_test dimms) modprobe nfit_test -$NDCTL disable-region $BUS all -$NDCTL zero-labels $BUS all -$NDCTL enable-region $BUS all +$NDCTL disable-region -b $NFIT_TEST_BUS0 all +$NDCTL zero-labels -b $NFIT_TEST_BUS0 all +$NDCTL enable-region -b $NFIT_TEST_BUS0 all rc=1 # create pmem dev="x" -json=$($NDCTL create-namespace $BUS -t pmem -m raw) -eval $(echo $json | sed -e "$json2var") +json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m raw) +eval $(echo $json | json2var) [ $dev = "x" ] && echo "fail: $LINENO" && exit 1 [ $mode != "raw" ] && echo "fail: $LINENO" && exit 1 @@ -71,7 +53,7 @@ # convert pmem to fsdax mode json=$($NDCTL create-namespace -m fsdax -f -e $dev) -eval $(echo $json | sed -e "$json2var") +eval $(echo $json | json2var) [ $mode != "fsdax" ] && echo "fail: $LINENO" && exit 1 # check for errors relative to the offset injected by the pfn device @@ -88,10 +70,10 @@ echo "fail: $LINENO" && exit 1 fi -if check_min_kver "4.9.0"; then +if check_min_kver "4.9"; then # check for re-appearance of stale badblocks from poison_list - $NDCTL disable-region $BUS all - $NDCTL enable-region $BUS all + $NDCTL disable-region -b $NFIT_TEST_BUS0 all + $NDCTL enable-region -b $NFIT_TEST_BUS0 all # since we have cleared the errors, a disable/reenable shouldn't bring them back if read sector len < /sys/block/$blockdev/badblocks; then @@ -100,8 +82,6 @@ fi fi -$NDCTL disable-region $BUS all -$NDCTL disable-region $BUS1 all -modprobe -r nfit_test +_cleanup exit 0 diff -Nru ndctl-60.1/test/common ndctl-61.2/test/common --- ndctl-60.1/test/common 1970-01-01 00:00:00.000000000 +0000 +++ ndctl-61.2/test/common 2018-07-06 23:33:14.000000000 +0000 @@ -0,0 +1,83 @@ + +# SPDX-License-Identifier: GPL-2.0 +# Copyright(c) 2018, FUJITSU LIMITED. All rights reserved. + +# Global variables + +# NDCTL +# +if [ -f "../ndctl/ndctl" ] && [ -x "../ndctl/ndctl" ]; then + export NDCTL=../ndctl/ndctl +elif [ -f "./ndctl/ndctl" ] && [ -x "./ndctl/ndctl" ]; then + export NDCTL=./ndctl/ndctl +else + echo "Couldn't find an ndctl binary" + exit 1 +fi + +# NFIT_TEST_BUS[01] +# +NFIT_TEST_BUS0=nfit_test.0 +NFIT_TEST_BUS1=nfit_test.1 + + +# Functions + +# err +# $1: line number which error detected +# $2: cleanup function (optional) +# +err() +{ + echo test/$(basename $0): failed at line $1 + [ -n "$2" ] && "$2" + exit $rc +} + +# check_min_kver +# $1: Supported kernel version. format: X.Y +# +check_min_kver() +{ + local ver="$1" + : "${KVER:=$(uname -r)}" + + [ -n "$ver" ] || return 1 + [[ "$ver" == "$(echo -e "$ver\n$KVER" | sort -V | head -1)" ]] +} + +# do_skip +# $1: Skip message +# +do_skip() +{ + echo kernel $(uname -r): $1 + exit 77 +} + +# check_prereq +# $1: command to check +# +check_prereq() +{ + if ! command -v "$1" >/dev/null; then + do_skip "missing $1, skipping..." + fi +} + +# _cleanup +# +_cleanup() +{ + $NDCTL disable-region -b $NFIT_TEST_BUS0 all + $NDCTL disable-region -b $NFIT_TEST_BUS1 all + modprobe -r nfit_test +} + +# json2var +# stdin: json +# +json2var() +{ + sed -e "s/[{}\",]//g; s/:/=/g" +} diff -Nru ndctl-60.1/test/create.sh ndctl-61.2/test/create.sh --- ndctl-60.1/test/create.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/create.sh 2018-07-06 23:33:14.000000000 +0000 @@ -11,57 +11,40 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -DEV="" -NDCTL="../ndctl/ndctl" -BUS="-b nfit_test.0" -json2var="s/[{}\",]//g; s/:/=/g" +set -e + SECTOR_SIZE="4096" rc=77 -set -e - -err() { - echo "test/create: failed at line $1" - exit $rc -} - -check_min_kver() -{ - local ver="$1" - : "${KVER:=$(uname -r)}" - - [ -n "$ver" ] || return 1 - [[ "$ver" == "$(echo -e "$ver\n$KVER" | sort -V | head -1)" ]] -} +. ./common -check_min_kver "4.5" || { echo "kernel $KVER may lack namespace mode attribute"; exit $rc; } +check_min_kver "4.5" || do_skip "may lack namespace mode attribute" -set -e trap 'err $LINENO' ERR # setup (reset nfit_test dimms) modprobe nfit_test -$NDCTL disable-region $BUS all -$NDCTL zero-labels $BUS all -$NDCTL enable-region $BUS all +$NDCTL disable-region -b $NFIT_TEST_BUS0 all +$NDCTL zero-labels -b $NFIT_TEST_BUS0 all +$NDCTL enable-region -b $NFIT_TEST_BUS0 all rc=1 # create pmem dev="x" -json=$($NDCTL create-namespace $BUS -t pmem -m raw) -eval $(echo $json | sed -e "$json2var") +json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m raw) +eval $(echo $json | json2var ) [ $dev = "x" ] && echo "fail: $LINENO" && exit 1 [ $mode != "raw" ] && echo "fail: $LINENO" && exit 1 # convert pmem to fsdax mode json=$($NDCTL create-namespace -m fsdax -f -e $dev) -eval $(echo $json | sed -e "$json2var") +eval $(echo $json | json2var) [ $mode != "fsdax" ] && echo "fail: $LINENO" && exit 1 # convert pmem to sector mode json=$($NDCTL create-namespace -m sector -l $SECTOR_SIZE -f -e $dev) -eval $(echo $json | sed -e "$json2var") +eval $(echo $json | json2var) [ $sector_size != $SECTOR_SIZE ] && echo "fail: $LINENO" && exit 1 [ $mode != "sector" ] && echo "fail: $LINENO" && exit 1 @@ -70,15 +53,17 @@ # create blk dev="x" -json=$($NDCTL create-namespace $BUS -t blk -m raw -v) -eval $(echo $json | sed -e "$json2var") +json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t blk -m raw -v) +eval $(echo $json | json2var) [ $dev = "x" ] && echo "fail: $LINENO" && exit 1 [ $mode != "raw" ] && echo "fail: $LINENO" && exit 1 # convert blk to sector mode json=$($NDCTL create-namespace -m sector -l $SECTOR_SIZE -f -e $dev) -eval $(echo $json | sed -e "$json2var") +eval $(echo $json | json2var) [ $sector_size != $SECTOR_SIZE ] && echo "fail: $LINENO" && exit 1 [ $mode != "sector" ] && echo "fail: $LINENO" && exit 1 +_cleanup + exit 0 diff -Nru ndctl-60.1/test/daxdev-errors.sh ndctl-61.2/test/daxdev-errors.sh --- ndctl-60.1/test/daxdev-errors.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/daxdev-errors.sh 2018-07-06 23:33:14.000000000 +0000 @@ -11,45 +11,28 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -DEV="" -NDCTL="../ndctl/ndctl" -DAXCTL="../daxctl/daxctl" -BUS="-b nfit_test.0" -BUS1="-b nfit_test.1" -json2var="s/[{}\",]//g; s/:/=/g" +set -e + rc=77 -err() { - echo "test/daxdev-errors: failed at line $1" - exit $rc -} - -check_min_kver() -{ - local ver="$1" - : "${KVER:=$(uname -r)}" - - [ -n "$ver" ] || return 1 - [[ "$ver" == "$(echo -e "$ver\n$KVER" | sort -V | head -1)" ]] -} +. ./common -check_min_kver "4.12" || { echo "kernel $KVER lacks dax dev error handling"; exit $rc; } +check_min_kver "4.12" || do_skip "lacks dax dev error handling" -set -e trap 'err $LINENO' ERR # setup (reset nfit_test dimms) modprobe nfit_test -$NDCTL disable-region $BUS all -$NDCTL zero-labels $BUS all -$NDCTL enable-region $BUS all +$NDCTL disable-region -b $NFIT_TEST_BUS0 all +$NDCTL zero-labels -b $NFIT_TEST_BUS0 all +$NDCTL enable-region -b $NFIT_TEST_BUS0 all rc=1 query=". | sort_by(.available_size) | reverse | .[0].dev" -region=$($NDCTL list $BUS -t pmem -Ri | jq -r "$query") +region=$($NDCTL list -b $NFIT_TEST_BUS0 -t pmem -Ri | jq -r "$query") -json=$($NDCTL create-namespace $BUS -r $region -t pmem -m devdax -a 4096) +json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -r $region -t pmem -m devdax -a 4096) chardev=$(echo $json | jq ". | select(.mode == \"devdax\") | .daxregion.devices[0].chardev") #{ @@ -70,12 +53,12 @@ # } #} -json1=$($NDCTL list $BUS --mode=devdax --namespaces) -eval $(echo $json1 | sed -e "$json2var") +json1=$($NDCTL list -b $NFIT_TEST_BUS0 --mode=devdax --namespaces) +eval $(echo $json1 | json2var) nsdev=$dev -json1=$($NDCTL list $BUS) -eval $(echo $json1 | sed -e "$json2var") +json1=$($NDCTL list -b $NFIT_TEST_BUS0) +eval $(echo $json1 | json2var) busdev=$dev # inject errors in the middle of the namespace @@ -98,9 +81,6 @@ fi [ -n "$sector" ] && echo "fail: $LINENO" && exit 1 -# cleanup -$NDCTL disable-region $BUS all -$NDCTL disable-region $BUS1 all -modprobe -r nfit_test +_cleanup exit 0 diff -Nru ndctl-60.1/test/dax-pmd.c ndctl-61.2/test/dax-pmd.c --- ndctl-60.1/test/dax-pmd.c 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/dax-pmd.c 2018-07-06 23:33:14.000000000 +0000 @@ -12,6 +12,7 @@ */ #include #include +#include #include #include #include @@ -125,7 +126,10 @@ rc = -ENXIO; } ((char *) buf)[0] = 0; - pread(fd2, buf, 4096, 0); + if (pread(fd2, buf, 4096, 0) != 4096) { + faili(i); + rc = -ENXIO; + } if (strcmp(buf, "odirect data") != 0) { faili(i); rc = -ENXIO; @@ -190,14 +194,15 @@ } /* test_pmd assumes that fd references a pre-allocated + dax-capable file */ -static int test_pmd(int fd) +static int test_pmd(struct ndctl_test *test, int fd) { - unsigned long long m_align, p_align; + unsigned long long m_align, p_align, pmd_off; + static const bool fsdax = true; struct fiemap_extent *ext; + void *base, *pmd_addr; struct fiemap *map; int rc = -ENXIO; unsigned long i; - void *base; if (fd < 0) { fail(); @@ -246,9 +251,15 @@ m_align = ALIGN(base, HPAGE_SIZE) - ((unsigned long) base); p_align = ALIGN(ext->fe_physical, HPAGE_SIZE) - ext->fe_physical; - rc = test_dax_directio(fd, HPAGE_SIZE, (char *) base + m_align, - ext->fe_logical + p_align); + pmd_addr = (char *) base + m_align; + pmd_off = ext->fe_logical + p_align; + rc = test_dax_directio(fd, HPAGE_SIZE, pmd_addr, pmd_off); + if (rc) + goto err_directio; + + rc = test_dax_poison(test, fd, HPAGE_SIZE, pmd_addr, pmd_off, fsdax); + err_directio: err_extent: err_mmap: free(map); @@ -257,14 +268,20 @@ int __attribute__((weak)) main(int argc, char *argv[]) { + struct ndctl_test *test = ndctl_test_new(0); int fd, rc; + if (!test) { + fprintf(stderr, "failed to initialize test\n"); + return EXIT_FAILURE; + } + if (argc < 1) return -EINVAL; fd = open(argv[1], O_RDWR); - rc = test_pmd(fd); + rc = test_pmd(test, fd); if (fd >= 0) close(fd); - return rc; + return ndctl_test_result(test, rc); } diff -Nru ndctl-60.1/test/dax-poison.c ndctl-61.2/test/dax-poison.c --- ndctl-60.1/test/dax-poison.c 1970-01-01 00:00:00.000000000 +0000 +++ ndctl-61.2/test/dax-poison.c 2018-07-06 23:33:14.000000000 +0000 @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2018 Intel Corporation. All rights reserved. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define fail() fprintf(stderr, "%s: failed at: %d (%s)\n", \ + __func__, __LINE__, strerror(errno)) + +static sigjmp_buf sj_env; +static int sig_mcerr_ao, sig_mcerr_ar, sig_count; + +static void sigbus_hdl(int sig, siginfo_t *si, void *ptr) +{ + switch (si->si_code) { + case BUS_MCEERR_AO: + fprintf(stderr, "%s: BUS_MCEERR_AO addr: %p len: %d\n", + __func__, si->si_addr, 1 << si->si_addr_lsb); + sig_mcerr_ao++; + break; + case BUS_MCEERR_AR: + fprintf(stderr, "%s: BUS_MCEERR_AR addr: %p len: %d\n", + __func__, si->si_addr, 1 << si->si_addr_lsb); + sig_mcerr_ar++; + break; + default: + sig_count++; + break; + } + + siglongjmp(sj_env, 1); +} + +int test_dax_poison(struct ndctl_test *test, int dax_fd, unsigned long align, + void *dax_addr, off_t offset, bool fsdax) +{ + unsigned char *addr = MAP_FAILED; + struct sigaction act; + unsigned x = x; + void *buf; + int rc; + + if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 19, 0))) + return 77; + + /* + * MADV_HWPOISON must be page aligned, and this routine assumes + * align is >= 8K + */ + if (align < SZ_2M) + return 0; + + if (posix_memalign(&buf, 4096, 4096) != 0) + return -ENOMEM; + + memset(&act, 0, sizeof(act)); + act.sa_sigaction = sigbus_hdl; + act.sa_flags = SA_SIGINFO; + + if (sigaction(SIGBUS, &act, 0)) { + fail(); + rc = -errno; + goto out; + } + + /* dirty the block on disk to bypass the default zero page */ + if (fsdax) { + rc = pwrite(dax_fd, buf, 4096, offset + align / 2); + if (rc < 4096) { + fail(); + rc = -ENXIO; + goto out; + } + fsync(dax_fd); + } + + addr = mmap(dax_addr, 2*align, PROT_READ|PROT_WRITE, + MAP_SHARED_VALIDATE|MAP_POPULATE|MAP_SYNC, dax_fd, offset); + if (addr == MAP_FAILED) { + fail(); + rc = -errno; + goto out; + } + + if (sigsetjmp(sj_env, 1)) { + if (sig_mcerr_ar) { + fprintf(stderr, "madvise triggered 'action required' sigbus\n"); + goto clear_error; + } else if (sig_count) { + fail(); + return -ENXIO; + } + } + + rc = madvise(addr + align / 2, 4096, MADV_HWPOISON); + if (rc) { + fail(); + rc = -errno; + goto out; + } + + /* clear the error */ +clear_error: + if (!sig_mcerr_ar) { + fail(); + rc = -ENXIO; + goto out; + } + + if (!fsdax) { + rc = 0; + goto out; + } + + rc = fallocate(dax_fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, + offset + align / 2, 4096); + if (rc) { + fail(); + rc = -errno; + goto out; + } + + rc = pwrite(dax_fd, buf, 4096, offset + align / 2); + if (rc < 4096) { + fail(); + rc = -ENXIO; + goto out; + } + fsync(dax_fd); + + /* check that we can fault in the poison page */ + x = *(volatile unsigned *) addr + align / 2; + rc = 0; + +out: + if (addr != MAP_FAILED) + munmap(addr, 2 * align); + free(buf); + return rc; +} diff -Nru ndctl-60.1/test/dax.sh ndctl-61.2/test/dax.sh --- ndctl-60.1/test/dax.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/dax.sh 2018-07-06 23:33:14.000000000 +0000 @@ -28,6 +28,15 @@ exit $rc } +run_test() { + if ! ./dax-pmd $MNT/$FILE; then + rc=$? + if [ $rc -ne 77 -a $rc -ne 0 ]; then + err + fi + fi +} + set -e mkdir -p $MNT trap 'err $LINENO' ERR @@ -40,7 +49,7 @@ mkfs.ext4 /dev/$blockdev mount /dev/$blockdev $MNT -o dax fallocate -l 1GiB $MNT/$FILE -./dax-pmd $MNT/$FILE +run_test umount $MNT # convert pmem to put the memmap on the device @@ -52,7 +61,7 @@ mkfs.ext4 /dev/$blockdev mount /dev/$blockdev $MNT -o dax fallocate -l 1GiB $MNT/$FILE -./dax-pmd $MNT/$FILE +run_test umount $MNT json=$($NDCTL create-namespace -m raw -f -e $dev) @@ -62,7 +71,7 @@ mkfs.xfs -f /dev/$blockdev mount /dev/$blockdev $MNT -o dax fallocate -l 1GiB $MNT/$FILE -./dax-pmd $MNT/$FILE +run_test umount $MNT # convert pmem to put the memmap on the device @@ -73,7 +82,7 @@ mkfs.xfs -f /dev/$blockdev mount /dev/$blockdev $MNT -o dax fallocate -l 1GiB $MNT/$FILE -./dax-pmd $MNT/$FILE +run_test umount $MNT # revert namespace to raw mode @@ -81,4 +90,4 @@ eval $(echo $json | sed -e "$json2var") [ $mode != "fsdax" ] && echo "fail: $LINENO" && exit 1 -exit 0 +exit $rc diff -Nru ndctl-60.1/test/device-dax.c ndctl-61.2/test/device-dax.c --- ndctl-60.1/test/device-dax.c 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/device-dax.c 2018-07-06 23:33:14.000000000 +0000 @@ -151,15 +151,6 @@ struct daxctl_region *dax_region; char *buf, path[100], data[VERIFY_BUF_SIZE]; - memset (&act, 0, sizeof(act)); - act.sa_sigaction = sigbus; - act.sa_flags = SA_SIGINFO; - - if (sigaction(SIGBUS, &act, 0)) { - perror("sigaction"); - return 1; - } - ndctl_set_log_priority(ctx, loglevel); ndns = ndctl_get_test_dev(ctx); @@ -276,6 +267,7 @@ * otherwise not supported. */ if (ndctl_test_attempt(test, KERNEL_VERSION(4, 9, 0))) { + static const bool devdax = false; int fd2; rc = test_dax_directio(fd, align, NULL, 0); @@ -285,6 +277,15 @@ goto out; } + fprintf(stderr, "%s: test dax poison\n", + ndctl_namespace_get_devname(ndns)); + rc = test_dax_poison(test, fd, align, NULL, 0, devdax); + if (rc) { + fprintf(stderr, "%s: failed dax poison\n", + ndctl_namespace_get_devname(ndns)); + goto out; + } + fd2 = open("/proc/self/smaps", O_RDONLY); if (fd2 < 0) { fprintf(stderr, "%s: failed smaps open\n", @@ -312,6 +313,15 @@ goto out; } + memset(&act, 0, sizeof(act)); + act.sa_sigaction = sigbus; + act.sa_flags = SA_SIGINFO; + if (sigaction(SIGBUS, &act, 0)) { + perror("sigaction"); + rc = EXIT_FAILURE; + goto out; + } + /* test fault after device-dax instance disabled */ if (sigsetjmp(sj_env, 1)) { /* got sigbus, success */ diff -Nru ndctl-60.1/test/dsm-fail.c ndctl-61.2/test/dsm-fail.c --- ndctl-60.1/test/dsm-fail.c 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/dsm-fail.c 2018-07-06 23:33:14.000000000 +0000 @@ -24,12 +24,13 @@ #include #include +#include #include #include #define DIMM_PATH "/sys/devices/platform/nfit_test.0/nfit_test_dimm/test_dimm0" -static void reset_bus(struct ndctl_bus *bus) +static int reset_bus(struct ndctl_bus *bus) { struct ndctl_region *region; struct ndctl_dimm *dimm; @@ -38,20 +39,154 @@ ndctl_region_foreach(bus, region) ndctl_region_disable_invalidate(region); - ndctl_dimm_foreach(bus, dimm) - ndctl_dimm_zero_labels(dimm); + ndctl_dimm_foreach(bus, dimm) { + if (!ndctl_dimm_read_labels(dimm)) + return -ENXIO; + ndctl_dimm_disable(dimm); + ndctl_dimm_init_labels(dimm, NDCTL_NS_VERSION_1_2); + ndctl_dimm_enable(dimm); + } /* set regions back to their default state */ ndctl_region_foreach(bus, region) ndctl_region_enable(region); + return 0; +} + +static int set_dimm_response(const char *dimm_path, int cmd, int error_code, + struct log_ctx *log_ctx) +{ + char path[1024], buf[SYSFS_ATTR_SIZE]; + int rc; + + if (error_code) { + sprintf(path, "%s/fail_cmd", dimm_path); + sprintf(buf, "%#x\n", 1 << cmd); + rc = __sysfs_write_attr(log_ctx, path, buf); + if (rc) + goto out; + sprintf(path, "%s/fail_cmd_code", dimm_path); + sprintf(buf, "%d\n", error_code); + rc = __sysfs_write_attr(log_ctx, path, buf); + if (rc) + goto out; + } else { + sprintf(path, "%s/fail_cmd", dimm_path); + sprintf(buf, "0\n"); + rc = __sysfs_write_attr(log_ctx, path, buf); + if (rc) + goto out; + } +out: + if (rc < 0) + fprintf(stderr, "%s failed, cmd: %d code: %d\n", + __func__, cmd, error_code); + return 0; +} + +static int dimms_disable(struct ndctl_bus *bus) +{ + struct ndctl_dimm *dimm; + + ndctl_dimm_foreach(bus, dimm) { + int rc = ndctl_dimm_disable(dimm); + + if (rc) { + fprintf(stderr, "dimm: %s failed to disable: %d\n", + ndctl_dimm_get_devname(dimm), rc); + return rc; + } + } + return 0; +} + +static int test_dimms_enable(struct ndctl_bus *bus, struct ndctl_dimm *victim, + bool expect) +{ + struct ndctl_dimm *dimm; + + ndctl_dimm_foreach(bus, dimm) { + int rc = ndctl_dimm_enable(dimm); + + if (((expect != (rc == 0)) && (dimm == victim)) + || (rc && dimm != victim)) { + bool __expect = true; + + if (dimm == victim) + __expect = expect; + fprintf(stderr, "fail expected %s enable %s victim: %s rc: %d\n", + ndctl_dimm_get_devname(dimm), + __expect ? "success" : "failure", + ndctl_dimm_get_devname(victim), rc); + return -ENXIO; + } + } + return 0; +} + +static int test_regions_enable(struct ndctl_bus *bus, + struct ndctl_dimm *victim, struct ndctl_region *victim_region, + bool region_expect, int namespace_count) +{ + struct ndctl_region *region; + + ndctl_region_foreach(bus, region) { + struct ndctl_namespace *ndns; + struct ndctl_dimm *dimm; + bool has_victim = false; + int rc, count = 0; + + ndctl_dimm_foreach_in_region(region, dimm) { + if (dimm == victim) { + has_victim = true; + break; + } + } + + rc = ndctl_region_enable(region); + fprintf(stderr, "region: %s enable: %d has_victim: %d\n", + ndctl_region_get_devname(region), rc, has_victim); + if (((region_expect != (rc == 0)) && has_victim) + || (rc && !has_victim)) { + bool __expect = true; + + if (has_victim) + __expect = region_expect; + fprintf(stderr, "%s: fail expected enable: %s with %s\n", + ndctl_region_get_devname(region), + __expect ? "success" : "failure", + ndctl_dimm_get_devname(victim)); + return -ENXIO; + } + if (region != victim_region) + continue; + ndctl_namespace_foreach(region, ndns) { + if (ndctl_namespace_is_enabled(ndns)) { + fprintf(stderr, "%s: enabled, expected disabled\n", + ndctl_namespace_get_devname(ndns)); + return -ENXIO; + } + fprintf(stderr, "%s: %s: size: %lld\n", __func__, + ndctl_namespace_get_devname(ndns), + ndctl_namespace_get_size(ndns)); + count++; + } + if (count != namespace_count) { + fprintf(stderr, "%s: fail expected %d namespaces got %d\n", + ndctl_region_get_devname(region), + namespace_count, count); + return -ENXIO; + } + } + return 0; } static int do_test(struct ndctl_ctx *ctx, struct ndctl_test *test) { struct ndctl_bus *bus = ndctl_bus_get_by_provider(ctx, "nfit_test.0"); + struct ndctl_region *region, *victim_region = NULL; struct ndctl_dimm *dimm, *victim = NULL; char path[1024], buf[SYSFS_ATTR_SIZE]; - struct ndctl_region *region; struct log_ctx log_ctx; unsigned int handle; int rc, err = 0; @@ -64,11 +199,10 @@ log_init(&log_ctx, "test/dsm-fail", "NDCTL_TEST"); - ndctl_bus_wait_probe(bus); - - /* disable all regions so that we can disable a dimm */ - ndctl_region_foreach(bus, region) - ndctl_region_disable_invalidate(region); + if (reset_bus(bus)) { + fprintf(stderr, "failed to read labels\n"); + return -ENXIO; + } sprintf(path, "%s/handle", DIMM_PATH); rc = __sysfs_read_attr(&log_ctx, path, buf); @@ -79,16 +213,11 @@ handle = strtoul(buf, NULL, 0); - ndctl_dimm_foreach(bus, dimm) { - if (ndctl_dimm_get_handle(dimm) == handle) + ndctl_dimm_foreach(bus, dimm) + if (ndctl_dimm_get_handle(dimm) == handle) { victim = dimm; - - if (ndctl_dimm_disable(dimm)) { - fprintf(stderr, "failed to disable: %s\n", - ndctl_dimm_get_devname(dimm)); - return -ENXIO; + break; } - } if (!victim) { fprintf(stderr, "failed to find victim dimm\n"); @@ -96,67 +225,133 @@ } fprintf(stderr, "victim: %s\n", ndctl_dimm_get_devname(victim)); - sprintf(path, "%s/fail_cmd", DIMM_PATH); - sprintf(buf, "%#x\n", 1 << ND_CMD_GET_CONFIG_SIZE); - rc = __sysfs_write_attr(&log_ctx, path, buf); - if (rc) { - fprintf(stderr, "failed to set fail cmd mask\n"); - return -ENXIO; - } - - ndctl_dimm_foreach(bus, dimm) { - rc = ndctl_dimm_enable(dimm); - fprintf(stderr, "dimm: %s enable: %d\n", - ndctl_dimm_get_devname(dimm), rc); - if ((rc == 0) == (dimm == victim)) { - fprintf(stderr, "fail expected %s enable %s victim: %s\n", - ndctl_dimm_get_devname(dimm), - (dimm == victim) ? "failure" : "success", - ndctl_dimm_get_devname(victim)); - err = -ENXIO; - goto out; - } - } - ndctl_region_foreach(bus, region) { - bool has_victim = false; - + if (ndctl_region_get_type(region) != ND_DEVICE_REGION_PMEM) + continue; ndctl_dimm_foreach_in_region(region, dimm) { - if (dimm == victim) { - has_victim = true; - break; + const char *argv[] = { + "__func__", "-v", "-r", + ndctl_region_get_devname(region), + "-s", "4M", "-m", "raw", + }; + struct ndctl_namespace *ndns; + int count, i; + + if (dimm != victim) + continue; + /* + * Validate that we only have the one seed + * namespace, and then create one so that we can + * verify namespace enumeration while locked. + */ + count = 0; + ndctl_namespace_foreach(region, ndns) + count++; + if (count != 1) { + fprintf(stderr, "%s: found %d namespaces expected 1\n", + ndctl_region_get_devname(region), + count); + rc = -ENXIO; + goto out; } + if (ndctl_region_get_size(region) + != ndctl_region_get_available_size(region)) { + fprintf(stderr, "%s: expected empty region\n", + ndctl_region_get_devname(region)); + rc = -ENXIO; + goto out; + } + for (i = 0; i < 2; i++) { + builtin_xaction_namespace_reset(); + rc = cmd_create_namespace(ARRAY_SIZE(argv), argv, + ndctl_region_get_ctx(region)); + if (rc) { + fprintf(stderr, "%s: failed to create namespace\n", + ndctl_region_get_devname(region)); + rc = -ENXIO; + goto out; + } + } + victim_region = region; } - - rc = ndctl_region_enable(region); - fprintf(stderr, "region: %s enable: %d has_victim: %d\n", - ndctl_region_get_devname(region), rc, has_victim); - if ((rc == 0) == has_victim) { - fprintf(stderr, "fail expected %s enable %s with %s disabled\n", - ndctl_region_get_devname(region), - has_victim ? "failure" : "success", - ndctl_dimm_get_devname(victim)); - err = -ENXIO; - goto out; - } + if (victim_region) + break; } + /* disable all regions so that we can disable a dimm */ + ndctl_region_foreach(bus, region) + ndctl_region_disable_invalidate(region); + + rc = dimms_disable(bus); + if (rc) + goto out; + + + rc = set_dimm_response(DIMM_PATH, ND_CMD_GET_CONFIG_SIZE, -EACCES, + &log_ctx); + if (rc) + goto out; + fprintf(stderr, "%s:%d\n", __func__, __LINE__); + rc = test_dimms_enable(bus, victim, true); + if (rc) + goto out; + fprintf(stderr, "%s:%d\n", __func__, __LINE__); + rc = test_regions_enable(bus, victim, victim_region, true, 2); + if (rc) + goto out; + fprintf(stderr, "%s:%d\n", __func__, __LINE__); + rc = set_dimm_response(DIMM_PATH, ND_CMD_GET_CONFIG_SIZE, 0, &log_ctx); + if (rc) + goto out; + + ndctl_region_foreach(bus, region) + ndctl_region_disable_invalidate(region); + fprintf(stderr, "%s:%d\n", __func__, __LINE__); + rc = dimms_disable(bus); + if (rc) + goto out; + fprintf(stderr, "%s:%d\n", __func__, __LINE__); + + rc = set_dimm_response(DIMM_PATH, ND_CMD_GET_CONFIG_DATA, -EACCES, + &log_ctx); + if (rc) + goto out; + fprintf(stderr, "%s:%d\n", __func__, __LINE__); + rc = test_dimms_enable(bus, victim, false); + if (rc) + goto out; + fprintf(stderr, "%s:%d\n", __func__, __LINE__); + rc = test_regions_enable(bus, victim, victim_region, false, 0); + if (rc) + goto out; + fprintf(stderr, "%s:%d\n", __func__, __LINE__); + rc = set_dimm_response(DIMM_PATH, ND_CMD_GET_CONFIG_DATA, 0, &log_ctx); + if (rc) + goto out; + fprintf(stderr, "%s:%d\n", __func__, __LINE__); + rc = dimms_disable(bus); + if (rc) + goto out; + fprintf(stderr, "%s:%d\n", __func__, __LINE__); + out: + err = rc; + sprintf(path, "%s/fail_cmd", DIMM_PATH); sprintf(buf, "0\n"); rc = __sysfs_write_attr(&log_ctx, path, buf); - if (rc) { + if (rc) fprintf(stderr, "%s: failed to clear fail_cmd mask\n", ndctl_dimm_get_devname(victim)); - err = -ENXIO; - } rc = ndctl_dimm_enable(victim); if (rc) { fprintf(stderr, "failed to enable victim: %s after clearing error\n", ndctl_dimm_get_devname(victim)); - err = -ENXIO; + rc = -ENXIO; } reset_bus(bus); + if (rc) + err = rc; return err; } diff -Nru ndctl-60.1/test/firmware-update.sh ndctl-61.2/test/firmware-update.sh --- ndctl-60.1/test/firmware-update.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/firmware-update.sh 2018-07-06 23:33:14.000000000 +0000 @@ -2,70 +2,43 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright(c) 2018 Intel Corporation. All rights reserved. -[ -f "../ndctl/ndctl" ] && [ -x "../ndctl/ndctl" ] && ndctl="../ndctl/ndctl" -[ -f "./ndctl/ndctl" ] && [ -x "./ndctl/ndctl" ] && ndctl="./ndctl/ndctl" -[ -z "$ndctl" ] && echo "Couldn't find an ndctl binary" && exit 1 -bus="nfit_test.0" -bus1="nfit_test.1" -json2var="s/[{}\",]//g; s/:/=/g" rc=77 dev="" image="update-fw.img" -trap 'err $LINENO' ERR - -# $1: Line number -# $2: exit code -err() -{ - [ -n "$2" ] && rc="$2" - echo "test/firmware-update.sh: failed at line $1" - exit "$rc" -} - -check_min_kver() -{ - local ver="$1" - : "${KVER:=$(uname -r)}" +. ./common - [ -n "$ver" ] || return 1 - [[ "$ver" == "$(echo -e "$ver\n$KVER" | sort -V | head -1)" ]] -} +trap 'err $LINENO' ERR reset() { - $ndctl disable-region -b "$bus" all - $ndctl zero-labels -b "$bus" all - $ndctl enable-region -b "$bus" all + $NDCTL disable-region -b $NFIT_TEST_BUS0 all + $NDCTL zero-labels -b $NFIT_TEST_BUS0 all + $NDCTL enable-region -b $NFIT_TEST_BUS0 all if [ -f $image ]; then rm -f $image fi } -cleanup() -{ - $ndctl disable-region -b "$bus" all - $ndctl disable-region -b "$bus1" all - modprobe -r nfit_test -} - detect() { - dev=$($ndctl list -b "$bus" -D | jq .[0].dev | tr -d '"') - [ -n "$dev" ] || err "$LINENO" 2 + dev=$($NDCTL list -b $NFIT_TEST_BUS0 -D | jq .[0].dev | tr -d '"') + [ -n "$dev" ] || err "$LINENO" } do_tests() { truncate -s 196608 $image - $ndctl update-firmware -f $image $dev + $NDCTL update-firmware -f $image $dev } -check_min_kver "4.16" || { echo "kernel $KVER may lack firmware update test handling"; exit $rc; } +check_min_kver "4.16" || do_skip "may lack firmware update test handling" + modprobe nfit_test rc=1 reset +rc=2 detect do_tests -cleanup +_cleanup exit 0 diff -Nru ndctl-60.1/test/inject-error.sh ndctl-61.2/test/inject-error.sh --- ndctl-60.1/test/inject-error.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/inject-error.sh 2018-07-06 23:33:14.000000000 +0000 @@ -11,11 +11,6 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -[ -f "../ndctl/ndctl" ] && [ -x "../ndctl/ndctl" ] && ndctl="../ndctl/ndctl" -[ -f "./ndctl/ndctl" ] && [ -x "./ndctl/ndctl" ] && ndctl="./ndctl/ndctl" -[ -z "$ndctl" ] && echo "Couldn't find an ndctl binary" && exit 1 -bus="nfit_test.0" -json2var="s/[{}\",]//g; s/:/=/g" dev="" size="" blockdev="" @@ -23,6 +18,8 @@ err_block=42 err_count=8 +. ./common + trap 'err $LINENO' ERR # sample json: @@ -34,41 +31,24 @@ # "blockdev":"pmem7", #} -# $1: Line number -# $2: exit code -err() -{ - [ -n "$2" ] && rc="$2" - echo "test/inject-error.sh: failed at line $1" - exit "$rc" -} - -check_min_kver() -{ - local ver="$1" - : "${KVER:=$(uname -r)}" - - [ -n "$ver" ] || return 1 - [[ "$ver" == "$(echo -e "$ver\n$KVER" | sort -V | head -1)" ]] -} - -check_min_kver "4.15" || { echo "kernel $KVER may not support error injection"; exit "$rc"; } +check_min_kver "4.15" || do_skip "kernel $KVER may not support error injection" create() { - json=$($ndctl create-namespace -b "$bus" -t pmem --align=4k) - eval "$(echo "$json" | sed -e "$json2var")" - [ -n "$dev" ] || err "$LINENO" 2 - [ -n "$size" ] || err "$LINENO" 2 - [ -n "$blockdev" ] || err "$LINENO" 2 - [ $size -gt 0 ] || err "$LINENO" 2 + json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem --align=4k) + rc=2 + eval "$(echo "$json" | json2var)" + [ -n "$dev" ] || err "$LINENO" + [ -n "$size" ] || err "$LINENO" + [ -n "$blockdev" ] || err "$LINENO" + [ $size -gt 0 ] || err "$LINENO" } reset() { - $ndctl disable-region -b "$bus" all - $ndctl zero-labels -b "$bus" all - $ndctl enable-region -b "$bus" all + $NDCTL disable-region -b $NFIT_TEST_BUS0 all + $NDCTL zero-labels -b $NFIT_TEST_BUS0 all + $NDCTL enable-region -b $NFIT_TEST_BUS0 all } check_status() @@ -76,7 +56,7 @@ local sector="$1" local count="$2" - json="$($ndctl inject-error --status $dev)" + json="$($NDCTL inject-error --status $dev)" [[ "$sector" == "$(jq ".badblocks[0].block" <<< "$json")" ]] [[ "$count" == "$(jq ".badblocks[0].count" <<< "$json")" ]] } @@ -84,7 +64,7 @@ do_tests() { # inject without notification - $ndctl inject-error --block=$err_block --count=$err_count --no-notify $dev + $NDCTL inject-error --block=$err_block --count=$err_count --no-notify $dev check_status "$err_block" "$err_count" if read -r sector len < /sys/block/$blockdev/badblocks; then # fail if reading badblocks returns data @@ -92,11 +72,11 @@ fi # clear via err-inj-clear - $ndctl inject-error --block=$err_block --count=$err_count --uninject $dev + $NDCTL inject-error --block=$err_block --count=$err_count --uninject $dev check_status # inject normally - $ndctl inject-error --block=$err_block --count=$err_count $dev + $NDCTL inject-error --block=$err_block --count=$err_count $dev check_status "$err_block" "$err_count" if read -r sector len < /sys/block/$blockdev/badblocks; then test "$sector" -eq "$err_block" @@ -117,4 +97,5 @@ reset && create do_tests reset +_cleanup exit 0 diff -Nru ndctl-60.1/test/label-compat.sh ndctl-61.2/test/label-compat.sh --- ndctl-60.1/test/label-compat.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/label-compat.sh 2018-07-06 23:33:14.000000000 +0000 @@ -11,40 +11,24 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -NDCTL="../ndctl/ndctl" -BUS="-b nfit_test.0" -BUS1="-b nfit_test.1" -rc=77 - set -e -err() { - echo "test/label-compat.sh: failed at line $1" - exit $rc -} - -check_min_kver() -{ - local ver="$1" - : "${KVER:=$(uname -r)}" - - [ -n "$ver" ] || return 1 - [[ "$ver" == "$(echo -e "$ver\n$KVER" | sort -V | head -1)" ]] -} +rc=77 -check_min_kver "4.11" || { echo "kernel $KVER may not provide reliable isetcookie values"; exit $rc; } +. ./common + +check_min_kver "4.11" || do_skip "may not provide reliable isetcookie values" -set -e trap 'err $LINENO' ERR # setup (reset nfit_test dimms) modprobe nfit_test -$NDCTL disable-region $BUS all -$NDCTL zero-labels $BUS all +$NDCTL disable-region -b $NFIT_TEST_BUS0 all +$NDCTL zero-labels -b $NFIT_TEST_BUS0 all -# grab the largest pmem region on $BUS +# grab the largest pmem region on -b $NFIT_TEST_BUS0 query=". | sort_by(.available_size) | reverse | .[0].dev" -region=$($NDCTL list $BUS -t pmem -Ri | jq -r "$query") +region=$($NDCTL list -b $NFIT_TEST_BUS0 -t pmem -Ri | jq -r "$query") # we assume that $region is comprised of 4 dimms query=". | .regions[0].mappings | sort_by(.dimm) | .[].dimm" @@ -56,7 +40,7 @@ i=$((i+1)) done -$NDCTL enable-region $BUS all +$NDCTL enable-region -b $NFIT_TEST_BUS0 all len=$($NDCTL list -r $region -N | jq -r "length") @@ -66,8 +50,6 @@ exit 1 fi -$NDCTL disable-region $BUS all -$NDCTL disable-region $BUS1 all -modprobe -r nfit_test +_cleanup exit 0 diff -Nru ndctl-60.1/test/libndctl.c ndctl-61.2/test/libndctl.c --- ndctl-60.1/test/libndctl.c 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/libndctl.c 2018-07-06 23:33:14.000000000 +0000 @@ -2177,8 +2177,8 @@ return 0; } -#define __check_smart(dimm, cmd, field) ({ \ - if (ndctl_cmd_smart_get_##field(cmd) != smart_data.field) { \ +#define __check_smart(dimm, cmd, field, mask) ({ \ + if ((ndctl_cmd_smart_get_##field(cmd) & mask) != smart_data.field) { \ fprintf(stderr, "%s dimm: %#x expected \'" #field \ "\' %#x got: %#x\n", __func__, \ ndctl_dimm_get_handle(dimm), \ @@ -2230,14 +2230,14 @@ return rc; } - __check_smart(dimm, cmd, flags); - __check_smart(dimm, cmd, health); - __check_smart(dimm, cmd, temperature); - __check_smart(dimm, cmd, spares); - __check_smart(dimm, cmd, alarm_flags); - __check_smart(dimm, cmd, life_used); - __check_smart(dimm, cmd, shutdown_state); - __check_smart(dimm, cmd, vendor_size); + __check_smart(dimm, cmd, flags, ~ND_SMART_CTEMP_VALID); + __check_smart(dimm, cmd, health, -1); + __check_smart(dimm, cmd, temperature, -1); + __check_smart(dimm, cmd, spares, -1); + __check_smart(dimm, cmd, alarm_flags, -1); + __check_smart(dimm, cmd, life_used, -1); + __check_smart(dimm, cmd, shutdown_state, -1); + __check_smart(dimm, cmd, vendor_size, -1); check->cmd = cmd; return 0; diff -Nru ndctl-60.1/test/Makefile.am ndctl-61.2/test/Makefile.am --- ndctl-60.1/test/Makefile.am 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/Makefile.am 2018-07-06 23:33:14.000000000 +0000 @@ -69,9 +69,16 @@ dsm_fail_SOURCES =\ dsm-fail.c \ - $(testcore) + $(testcore) \ + ../ndctl/namespace.c \ + ../ndctl/check.c \ + ../util/json.c -dsm_fail_LDADD = $(LIBNDCTL_LIB) $(KMOD_LIBS) +dsm_fail_LDADD = $(LIBNDCTL_LIB) \ + $(KMOD_LIBS) \ + $(JSON_LIBS) \ + $(UUID_LIBS) \ + ../libutil.a ack_shutdown_count_set_SOURCES =\ ack-shutdown-count-set.c \ @@ -94,9 +101,12 @@ dax_dev_SOURCES = dax-dev.c $(testcore) dax_dev_LDADD = $(LIBNDCTL_LIB) $(KMOD_LIBS) -dax_pmd_SOURCES = dax-pmd.c +dax_pmd_SOURCES = dax-pmd.c \ + $(testcore) + hugetlb_SOURCES = hugetlb.c \ dax-pmd.c + mmap_SOURCES = mmap.c dax_errors_SOURCES = dax-errors.c daxdev_errors_SOURCES = daxdev-errors.c \ @@ -111,6 +121,13 @@ ../ndctl/namespace.c \ ../ndctl/check.c \ ../util/json.c + +if ENABLE_POISON +dax_pmd_SOURCES += dax-poison.c +hugetlb_SOURCES += dax-poison.c +device_dax_SOURCES += dax-poison.c +endif + device_dax_LDADD = \ $(LIBNDCTL_LIB) \ $(KMOD_LIBS) \ diff -Nru ndctl-60.1/test/multi-dax.sh ndctl-61.2/test/multi-dax.sh --- ndctl-60.1/test/multi-dax.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/multi-dax.sh 2018-07-06 23:33:14.000000000 +0000 @@ -11,51 +11,31 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -DEV="" -NDCTL="../ndctl/ndctl" -DAXCTL="../daxctl/daxctl" -BUS="-b nfit_test.0" -BUS1="-b nfit_test.1" -json2var="s/[{}\",]//g; s/:/=/g" +set -e + rc=77 -err() { - echo "test/multi-dax: failed at line $1" - exit $rc -} - -check_min_kver() -{ - local ver="$1" - : "${KVER:=$(uname -r)}" - - [ -n "$ver" ] || return 1 - [[ "$ver" == "$(echo -e "$ver\n$KVER" | sort -V | head -1)" ]] -} +. ./common -check_min_kver "4.13" || { echo "kernel $KVER may lack multi-dax support"; exit $rc; } +check_min_kver "4.13" || do_skip "may lack multi-dax support" -set -e trap 'err $LINENO' ERR # setup (reset nfit_test dimms) modprobe nfit_test -$NDCTL disable-region $BUS all -$NDCTL zero-labels $BUS all -$NDCTL enable-region $BUS all +$NDCTL disable-region -b $NFIT_TEST_BUS0 all +$NDCTL zero-labels -b $NFIT_TEST_BUS0 all +$NDCTL enable-region -b $NFIT_TEST_BUS0 all rc=1 query=". | sort_by(.available_size) | reverse | .[0].dev" -region=$($NDCTL list $BUS -t pmem -Ri | jq -r "$query") +region=$($NDCTL list -b $NFIT_TEST_BUS0 -t pmem -Ri | jq -r "$query") -json=$($NDCTL create-namespace $BUS -r $region -t pmem -m devdax -a 4096 -s 16M) +json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -r $region -t pmem -m devdax -a 4096 -s 16M) chardev1=$(echo $json | jq ". | select(.mode == \"devdax\") | .daxregion.devices[0].chardev") -json=$($NDCTL create-namespace $BUS -r $region -t pmem -m devdax -a 4096 -s 16M) +json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -r $region -t pmem -m devdax -a 4096 -s 16M) chardev2=$(echo $json | jq ". | select(.mode == \"devdax\") | .daxregion.devices[0].chardev") -# cleanup -$NDCTL disable-region $BUS all -$NDCTL disable-region $BUS1 all -modprobe -r nfit_test +_cleanup exit 0 diff -Nru ndctl-60.1/test/pmem-errors.sh ndctl-61.2/test/pmem-errors.sh --- ndctl-60.1/test/pmem-errors.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/pmem-errors.sh 2018-07-06 23:33:14.000000000 +0000 @@ -2,17 +2,14 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright(c) 2015-2017 Intel Corporation. All rights reserved. -DEV="" -NDCTL="../ndctl/ndctl" -BUS="-b nfit_test.0" -BUS1="-b nfit_test.1" MNT=test_dax_mnt FILE=image -json2var="s/[{}\",]//g; s/:/=/g" rc=77 -err() { - echo "test/dax-errors: failed at line $1" +. ./common + +cleanup() +{ rm -f $FILE rm -f $MNT/$FILE if [ -n "$blockdev" ]; then @@ -21,36 +18,26 @@ rc=77 fi rmdir $MNT - exit $rc -} - -check_min_kver() -{ - local ver="$1" - : "${KVER:=$(uname -r)}" - - [ -n "$ver" ] || return 1 - [[ "$ver" == "$(echo -e "$ver\n$KVER" | sort -V | head -1)" ]] } -check_min_kver "4.7" || { echo "kernel $KVER may lack dax error handling"; exit $rc; } +check_min_kver "4.7" || do_skip "may lack dax error handling" set -e mkdir -p $MNT -trap 'err $LINENO' ERR +trap 'err $LINENO cleanup' ERR # setup (reset nfit_test dimms) modprobe nfit_test -$NDCTL disable-region $BUS all -$NDCTL zero-labels $BUS all -$NDCTL enable-region $BUS all +$NDCTL disable-region -b $NFIT_TEST_BUS0 all +$NDCTL zero-labels -b $NFIT_TEST_BUS0 all +$NDCTL enable-region -b $NFIT_TEST_BUS0 all rc=1 # create pmem dev="x" -json=$($NDCTL create-namespace $BUS -t pmem -m raw) -eval $(echo $json | sed -e "$json2var") +json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m raw) +eval $(echo $json | json2var) [ $dev = "x" ] && echo "fail: $LINENO" && false [ $mode != "raw" ] && echo "fail: $LINENO" && false @@ -134,8 +121,6 @@ fi rmdir $MNT -$NDCTL disable-region $BUS all -$NDCTL disable-region $BUS1 all -modprobe -r nfit_test +_cleanup exit 0 diff -Nru ndctl-60.1/test/rescan-partitions.sh ndctl-61.2/test/rescan-partitions.sh --- ndctl-60.1/test/rescan-partitions.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/rescan-partitions.sh 2018-07-06 23:33:14.000000000 +0000 @@ -2,16 +2,13 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright(c) 2018 Intel Corporation. All rights reserved. -[ -f "../ndctl/ndctl" ] && [ -x "../ndctl/ndctl" ] && ndctl="../ndctl/ndctl" -[ -f "./ndctl/ndctl" ] && [ -x "./ndctl/ndctl" ] && ndctl="./ndctl/ndctl" -[ -z "$ndctl" ] && echo "Couldn't find an ndctl binary" && exit 1 -bus="nfit_test.0" -json2var="s/[{}\",]//g; s/:/=/g" dev="" size="" blockdev="" rc=77 +. ./common + trap 'err $LINENO' ERR # sample json: @@ -23,40 +20,16 @@ # "blockdev":"pmem5s", #} -# $1: Line number -# $2: exit code -err() -{ - [ -n "$2" ] && rc="$2" - echo "test/rescan-partitions.sh: failed at line $1" - exit "$rc" -} - -check_min_kver() -{ - local ver="$1" - : "${KVER:=$(uname -r)}" +check_min_kver "4.16" || do_skip "may not contain fixes for partition rescanning" - [ -n "$ver" ] || return 1 - [[ "$ver" == "$(echo -e "$ver\n$KVER" | sort -V | head -1)" ]] -} -check_min_kver "4.16" || { echo "kernel $KVER may not contain fixes for partition rescanning"; exit "$rc"; } - -check_prereq() -{ - if ! command -v "$1" >/dev/null; then - echo "missing '$1', skipping.." - exit "$rc" - fi -} check_prereq "parted" check_prereq "blockdev" reset() { - $ndctl disable-region -b "$bus" all - $ndctl zero-labels -b "$bus" all - $ndctl enable-region -b "$bus" all + $NDCTL disable-region -b $NFIT_TEST_BUS0 all + $NDCTL zero-labels -b $NFIT_TEST_BUS0 all + $NDCTL enable-region -b $NFIT_TEST_BUS0 all } test_mode() @@ -64,13 +37,15 @@ local mode="$1" # create namespace - json=$($ndctl create-namespace -b "$bus" -t pmem -m "$mode") - eval "$(echo "$json" | sed -e "$json2var")" - [ -n "$dev" ] || err "$LINENO" 2 - [ -n "$size" ] || err "$LINENO" 2 - [ -n "$blockdev" ] || err "$LINENO" 2 - [ $size -gt 0 ] || err "$LINENO" 2 + json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m "$mode") + rc=2 + eval "$(echo "$json" | json2var)" + [ -n "$dev" ] || err "$LINENO" + [ -n "$size" ] || err "$LINENO" + [ -n "$blockdev" ] || err "$LINENO" + [ $size -gt 0 ] || err "$LINENO" + rc=1 # create partition parted --script /dev/$blockdev mklabel gpt mkpart primary 1MiB 10MiB @@ -83,17 +58,18 @@ # cycle the namespace, and verify the partition is read # without needing to do a blockdev --rereadpt - $ndctl disable-namespace $dev - $ndctl enable-namespace $dev + $NDCTL disable-namespace $dev + $NDCTL enable-namespace $dev if [ -b /dev/$partdev ]; then echo "mode: $mode - partition read successful" else echo "mode: $mode - partition read failed" - err "$LINENO" 1 + rc=1 + err "$LINENO" fi - $ndctl disable-namespace $dev - $ndctl destroy-namespace $dev + $NDCTL disable-namespace $dev + $NDCTL destroy-namespace $dev } modprobe nfit_test @@ -102,5 +78,5 @@ test_mode "raw" test_mode "fsdax" test_mode "sector" - +_cleanup exit 0 diff -Nru ndctl-60.1/test/sector-mode.sh ndctl-61.2/test/sector-mode.sh --- ndctl-60.1/test/sector-mode.sh 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test/sector-mode.sh 2018-07-06 23:33:14.000000000 +0000 @@ -11,45 +11,32 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. -NDCTL="../ndctl/ndctl" -BUS="-b nfit_test.0" -BUS1="-b nfit_test.1" -TEST=$0 rc=77 -err() { - echo "$TEST: failed at line $1" - exit $rc -} +. ./common set -e trap 'err $LINENO' ERR # setup (reset nfit_test dimms) modprobe nfit_test -$NDCTL disable-region $BUS all -$NDCTL zero-labels $BUS all -$NDCTL enable-region $BUS all - -$NDCTL disable-region $BUS1 all -if $NDCTL zero-labels $BUS1 all; then - echo "DIMMs on $BUS1 support labels, skip..." - $NDCTL enable-region $BUS1 all - false -fi -$NDCTL enable-region $BUS1 all +$NDCTL disable-region -b $NFIT_TEST_BUS0 all +$NDCTL zero-labels -b $NFIT_TEST_BUS0 all +$NDCTL enable-region -b $NFIT_TEST_BUS0 all + +$NDCTL disable-region -b $NFIT_TEST_BUS1 all +$NDCTL zero-labels -b $NFIT_TEST_BUS1 all +$NDCTL enable-region -b $NFIT_TEST_BUS1 all rc=1 query=". | sort_by(.size) | reverse | .[0].dev" -NAMESPACE=$($NDCTL list $BUS1 -N | jq -r "$query") +NAMESPACE=$($NDCTL list -b $NFIT_TEST_BUS1 -N | jq -r "$query") REGION=$($NDCTL list -R --namespace=$NAMESPACE | jq -r ".dev") echo 0 > /sys/bus/nd/devices/$REGION/read_only -$NDCTL create-namespace -e $NAMESPACE -m sector -f -l 4K -$NDCTL create-namespace -e $NAMESPACE -m dax -f -a 4K -$NDCTL create-namespace -e $NAMESPACE -m sector -f -l 4K - -$NDCTL disable-region $BUS all -$NDCTL disable-region $BUS1 all -modprobe -r nfit_test +$NDCTL create-namespace --no-autolabel -e $NAMESPACE -m sector -f -l 4K +$NDCTL create-namespace --no-autolabel -e $NAMESPACE -m dax -f -a 4K +$NDCTL create-namespace --no-autolabel -e $NAMESPACE -m sector -f -l 4K + +_cleanup exit 0 diff -Nru ndctl-60.1/test.h ndctl-61.2/test.h --- ndctl-60.1/test.h 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/test.h 2018-07-06 23:33:14.000000000 +0000 @@ -12,6 +12,8 @@ */ #ifndef __TEST_H__ #define __TEST_H__ +#include + struct ndctl_test; struct ndctl_ctx; struct ndctl_test *ndctl_test_new(unsigned int kver); @@ -36,6 +38,16 @@ int test_parent_uuid(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx); int test_multi_pmem(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx); int test_dax_directio(int dax_fd, unsigned long align, void *dax_addr, off_t offset); +#ifdef ENABLE_POISON +int test_dax_poison(struct ndctl_test *test, int dax_fd, unsigned long align, + void *dax_addr, off_t offset, bool fsdax); +#else +static inline int test_dax_poison(struct ndctl_test *test, int dax_fd, + unsigned long align, void *dax_addr, off_t offset, bool fsdax) +{ + return 0; +} +#endif int test_dpa_alloc(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx); int test_dsm_fail(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx); int test_libndctl(int loglevel, struct ndctl_test *test, struct ndctl_ctx *ctx); diff -Nru ndctl-60.1/util/abspath.c ndctl-61.2/util/abspath.c --- ndctl-60.1/util/abspath.c 1970-01-01 00:00:00.000000000 +0000 +++ ndctl-61.2/util/abspath.c 2018-07-06 23:33:14.000000000 +0000 @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* originally copied from git/abspath.c */ + +#include +#include + +char *prefix_filename(const char *pfx, const char *arg) +{ + struct strbuf path = STRBUF_INIT; + size_t pfx_len = pfx ? strlen(pfx) : 0; + + if (!pfx_len) + ; + else if (is_absolute_path(arg)) + pfx_len = 0; + else + strbuf_add(&path, pfx, pfx_len); + + strbuf_addstr(&path, arg); + return strbuf_detach(&path, NULL); +} + +void fix_filename(const char *prefix, const char **file) +{ + if (!file || !*file || !prefix || is_absolute_path(*file) + || !strcmp("-", *file)) + return; + *file = prefix_filename(prefix, *file); +} diff -Nru ndctl-60.1/util/filter.c ndctl-61.2/util/filter.c --- ndctl-60.1/util/filter.c 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/util/filter.c 2018-07-06 23:33:14.000000000 +0000 @@ -25,101 +25,156 @@ #define NUMA_NO_NODE (-1) -struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *ident) +struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *__ident) { - char *end = NULL; + char *end = NULL, *ident, *save; unsigned long bus_id, id; - const char *provider, *devname; + const char *provider, *devname, *name; - if (!ident || strcmp(ident, "all") == 0) + if (!__ident) return bus; - bus_id = strtoul(ident, &end, 0); - if (end == ident || end[0]) - bus_id = ULONG_MAX; - - provider = ndctl_bus_get_provider(bus); - devname = ndctl_bus_get_devname(bus); - id = ndctl_bus_get_id(bus); + ident = strdup(__ident); + if (!ident) + return NULL; + + for (name = strtok_r(ident, " ", &save); name; + name = strtok_r(NULL, " ", &save)) { + if (strcmp(name, "all") == 0) + break; + + bus_id = strtoul(ident, &end, 0); + if (end == ident || end[0]) + bus_id = ULONG_MAX; + + provider = ndctl_bus_get_provider(bus); + devname = ndctl_bus_get_devname(bus); + id = ndctl_bus_get_id(bus); + + if (bus_id < ULONG_MAX && bus_id == id) + break; + + if (bus_id == ULONG_MAX && (strcmp(provider, name) == 0 + || strcmp(devname, name) == 0)) + break; + } + free(ident); - if (bus_id < ULONG_MAX && bus_id == id) + if (name) return bus; - - if (bus_id == ULONG_MAX && (strcmp(ident, provider) == 0 - || strcmp(ident, devname) == 0)) - return bus; - return NULL; } struct ndctl_region *util_region_filter(struct ndctl_region *region, - const char *ident) + const char *__ident) { - char *end = NULL; - const char *name; + char *end = NULL, *ident, *save; + const char *name, *region_name; unsigned long region_id, id; - if (!ident || strcmp(ident, "all") == 0) + if (!__ident) return region; - region_id = strtoul(ident, &end, 0); - if (end == ident || end[0]) - region_id = ULONG_MAX; + ident = strdup(__ident); + if (!ident) + return NULL; + + for (name = strtok_r(ident, " ", &save); name; + name = strtok_r(NULL, " ", &save)) { + if (strcmp(name, "all") == 0) + break; + + region_id = strtoul(ident, &end, 0); + if (end == ident || end[0]) + region_id = ULONG_MAX; + + region_name = ndctl_region_get_devname(region); + id = ndctl_region_get_id(region); + + if (region_id < ULONG_MAX && region_id == id) + break; + + if (region_id == ULONG_MAX && strcmp(region_name, name) == 0) + break; + } + free(ident); - name = ndctl_region_get_devname(region); - id = ndctl_region_get_id(region); - - if (region_id < ULONG_MAX && region_id == id) - return region; - - if (region_id == ULONG_MAX && strcmp(ident, name) == 0) + if (name) return region; - return NULL; } struct ndctl_namespace *util_namespace_filter(struct ndctl_namespace *ndns, - const char *ident) + const char *__ident) { struct ndctl_region *region = ndctl_namespace_get_region(ndns); unsigned long region_id, ndns_id; + const char *name; + char *ident, *save; - if (!ident || strcmp(ident, "all") == 0) + if (!__ident) return ndns; - if (strcmp(ident, ndctl_namespace_get_devname(ndns)) == 0) - return ndns; + ident = strdup(__ident); + if (!ident) + return NULL; + + for (name = strtok_r(ident, " ", &save); name; + name = strtok_r(NULL, " ", &save)) { + if (strcmp(name, "all") == 0) + break; + + if (strcmp(name, ndctl_namespace_get_devname(ndns)) == 0) + break; + + if (sscanf(name, "%ld.%ld", ®ion_id, &ndns_id) == 2 + && ndctl_region_get_id(region) == region_id + && ndctl_namespace_get_id(ndns) == ndns_id) + break; + } + free(ident); - if (sscanf(ident, "%ld.%ld", ®ion_id, &ndns_id) == 2 - && ndctl_region_get_id(region) == region_id - && ndctl_namespace_get_id(ndns) == ndns_id) + if (name) return ndns; - return NULL; } -struct ndctl_dimm *util_dimm_filter(struct ndctl_dimm *dimm, const char *ident) +struct ndctl_dimm *util_dimm_filter(struct ndctl_dimm *dimm, + const char *__ident) { - char *end = NULL; - const char *name; + char *end = NULL, *ident, *save; + const char *name, *dimm_name; unsigned long dimm_id, id; - if (!ident || strcmp(ident, "all") == 0) + if (!__ident) return dimm; - dimm_id = strtoul(ident, &end, 0); - if (end == ident || end[0]) - dimm_id = ULONG_MAX; + ident = strdup(__ident); + if (!ident) + return NULL; + + for (name = strtok_r(ident, " ", &save); name; + name = strtok_r(NULL, " ", &save)) { + if (strcmp(name, "all") == 0) + break; + + dimm_id = strtoul(ident, &end, 0); + if (end == ident || end[0]) + dimm_id = ULONG_MAX; + + dimm_name = ndctl_dimm_get_devname(dimm); + id = ndctl_dimm_get_id(dimm); + + if (dimm_id < ULONG_MAX && dimm_id == id) + break; + + if (dimm_id == ULONG_MAX && strcmp(dimm_name, name) == 0) + break; + } + free(ident); - name = ndctl_dimm_get_devname(dimm); - id = ndctl_dimm_get_id(dimm); - - if (dimm_id < ULONG_MAX && dimm_id == id) - return dimm; - - if (dimm_id == ULONG_MAX && strcmp(ident, name) == 0) + if (name) return dimm; - return NULL; } diff -Nru ndctl-60.1/util/help.c ndctl-61.2/util/help.c --- ndctl-60.1/util/help.c 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/util/help.c 2018-07-06 23:33:14.000000000 +0000 @@ -89,11 +89,6 @@ return *page; } -static int is_absolute_path(const char *path) -{ - return path[0] == '/'; -} - static const char *system_path(const char *path) { static const char *prefix = PREFIX; diff -Nru ndctl-60.1/util/json.c ndctl-61.2/util/json.c --- ndctl-60.1/util/json.c 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/util/json.c 2018-07-06 23:33:14.000000000 +0000 @@ -652,10 +652,12 @@ static struct json_object *util_raw_uuid(struct ndctl_namespace *ndns) { - uuid_t raw_uuid; char buf[40]; + uuid_t raw_uuid; ndctl_namespace_get_uuid(ndns, raw_uuid); + if (uuid_is_null(raw_uuid)) + return NULL; uuid_unparse(raw_uuid, buf); return json_object_new_string(buf); } @@ -664,7 +666,13 @@ unsigned long flags) { struct json_object *jndns = json_object_new_object(); + enum ndctl_pfn_loc loc = NDCTL_PFN_LOC_NONE; struct json_object *jobj, *jbbs = NULL; + const char *locations[] = { + [NDCTL_PFN_LOC_NONE] = "none", + [NDCTL_PFN_LOC_RAM] = "mem", + [NDCTL_PFN_LOC_PMEM] = "dev", + }; unsigned long long size = ULLONG_MAX; unsigned int sector_size = UINT_MAX; enum ndctl_namespace_mode mode; @@ -691,10 +699,13 @@ mode = ndctl_namespace_get_mode(ndns); switch (mode) { case NDCTL_NS_MODE_MEMORY: - if (pfn) /* dynamic memory mode */ + if (pfn) { /* dynamic memory mode */ size = ndctl_pfn_get_size(pfn); - else /* native/static memory mode */ + loc = ndctl_pfn_get_location(pfn); + } else { /* native/static memory mode */ size = ndctl_namespace_get_size(ndns); + loc = NDCTL_PFN_LOC_RAM; + } jobj = json_object_new_string("fsdax"); break; case NDCTL_NS_MODE_DAX: @@ -702,6 +713,7 @@ goto err; size = ndctl_dax_get_size(dax); jobj = json_object_new_string("devdax"); + loc = ndctl_dax_get_location(dax); break; case NDCTL_NS_MODE_SAFE: if (!btt) @@ -719,6 +731,12 @@ if (jobj) json_object_object_add(jndns, "mode", jobj); + if ((mode != NDCTL_NS_MODE_SAFE) && (mode != NDCTL_NS_MODE_RAW)) { + jobj = json_object_new_string(locations[loc]); + if (jobj) + json_object_object_add(jndns, "map", jobj); + } + if (size < ULLONG_MAX) { jobj = util_json_object_size(size, flags); if (jobj) @@ -734,9 +752,8 @@ json_object_object_add(jndns, "uuid", jobj); jobj = util_raw_uuid(ndns); - if (!jobj) - goto err; - json_object_object_add(jndns, "raw_uuid", jobj); + if (jobj) + json_object_object_add(jndns, "raw_uuid", jobj); bdev = ndctl_btt_get_block_device(btt); } else if (pfn) { ndctl_pfn_get_uuid(pfn, uuid); @@ -746,9 +763,8 @@ goto err; json_object_object_add(jndns, "uuid", jobj); jobj = util_raw_uuid(ndns); - if (!jobj) - goto err; - json_object_object_add(jndns, "raw_uuid", jobj); + if (jobj) + json_object_object_add(jndns, "raw_uuid", jobj); bdev = ndctl_pfn_get_block_device(pfn); } else if (dax) { struct daxctl_region *dax_region; @@ -761,9 +777,8 @@ goto err; json_object_object_add(jndns, "uuid", jobj); jobj = util_raw_uuid(ndns); - if (!jobj) - goto err; - json_object_object_add(jndns, "raw_uuid", jobj); + if (jobj) + json_object_object_add(jndns, "raw_uuid", jobj); if ((flags & UTIL_JSON_DAX) && dax_region) { jobj = util_daxctl_region_to_json(dax_region, NULL, flags); diff -Nru ndctl-60.1/util/parse-options.c ndctl-61.2/util/parse-options.c --- ndctl-60.1/util/parse-options.c 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/util/parse-options.c 2018-07-06 23:33:14.000000000 +0000 @@ -55,6 +55,7 @@ { const char *s, *arg = NULL; const int unset = flags & OPT_UNSET; + int err; if (unset && p->opt) return opterror(opt, "takes no value", flags); @@ -77,6 +78,7 @@ case OPTION_ARGUMENT: case OPTION_GROUP: case OPTION_STRING: + case OPTION_FILENAME: case OPTION_INTEGER: case OPTION_UINTEGER: case OPTION_LONG: @@ -121,6 +123,19 @@ return get_arg(p, opt, flags, (const char **)opt->value); return 0; + case OPTION_FILENAME: + err = 0; + if (unset) + *(const char **)opt->value = NULL; + else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) + *(const char **)opt->value = (const char *)opt->defval; + else + err = get_arg(p, opt, flags, (const char **)opt->value); + + if (!err) + fix_filename(p->prefix, (const char **)opt->value); + return err; + case OPTION_CALLBACK: if (unset) return (*opt->callback)(opt, NULL, 1) ? (-1) : 0; @@ -339,13 +354,14 @@ } } -void parse_options_start(struct parse_opt_ctx_t *ctx, - int argc, const char **argv, int flags) +void parse_options_start(struct parse_opt_ctx_t *ctx, int argc, + const char **argv, const char *prefix, int flags) { memset(ctx, 0, sizeof(*ctx)); ctx->argc = argc - 1; ctx->argv = argv + 1; ctx->out = argv; + ctx->prefix = prefix; ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0); ctx->flags = flags; if ((flags & PARSE_OPT_KEEP_UNKNOWN) && @@ -453,8 +469,10 @@ return ctx->cpidx + ctx->argc; } -int parse_options_subcommand(int argc, const char **argv, const struct option *options, - const char *const subcommands[], const char *usagestr[], int flags) +static int parse_options_subcommand_prefix(int argc, const char **argv, + const char *prefix, const struct option *options, + const char *const subcommands[], + const char *usagestr[], int flags) { struct parse_opt_ctx_t ctx; @@ -474,7 +492,7 @@ strbuf_release(&buf); } - parse_options_start(&ctx, argc, argv, flags); + parse_options_start(&ctx, argc, argv, prefix, flags); switch (parse_options_step(&ctx, options, usagestr)) { case PARSE_OPT_HELP: exit(129); @@ -503,10 +521,26 @@ return parse_options_end(&ctx); } +int parse_options_subcommand(int argc, const char **argv, + const struct option *options, const char *const subcommands[], + const char *usagestr[], int flags) +{ + return parse_options_subcommand_prefix(argc, argv, NULL, options, + subcommands, usagestr, flags); +} + +int parse_options_prefix(int argc, const char **argv, const char *prefix, + const struct option *options, + const char * const usagestr[], int flags) +{ + return parse_options_subcommand_prefix(argc, argv, prefix, options, + NULL, (const char **) usagestr, flags); +} + int parse_options(int argc, const char **argv, const struct option *options, const char * const usagestr[], int flags) { - return parse_options_subcommand(argc, argv, options, NULL, + return parse_options_subcommand_prefix(argc, argv, NULL, options, NULL, (const char **) usagestr, flags); } @@ -557,6 +591,7 @@ if (opts->flags & PARSE_OPT_NOARG) break; /* FALLTHROUGH */ + case OPTION_FILENAME: case OPTION_STRING: if (opts->argh) { if (opts->flags & PARSE_OPT_OPTARG) diff -Nru ndctl-60.1/util/parse-options.h ndctl-61.2/util/parse-options.h --- ndctl-60.1/util/parse-options.h 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/util/parse-options.h 2018-07-06 23:33:14.000000000 +0000 @@ -38,6 +38,7 @@ OPTION_CALLBACK, OPTION_U64, OPTION_UINTEGER, + OPTION_FILENAME, }; enum parse_opt_flags { @@ -135,6 +136,7 @@ #define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) } #define OPT_U64(s, l, v, h) { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) } #define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h) } +#define OPT_FILENAME(s, l, v, a, h) { .type = OPTION_FILENAME, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h) } #define OPT_DATE(s, l, v, h) \ { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb } #define OPT_CALLBACK(s, l, v, a, h, f) \ @@ -156,6 +158,10 @@ const struct option *options, const char * const usagestr[], int flags); +extern int parse_options_prefix(int argc, const char **argv, + const char *prefix, const struct option *options, + const char * const usagestr[], int flags); + extern int parse_options_subcommand(int argc, const char **argv, const struct option *options, const char *const subcommands[], @@ -185,6 +191,7 @@ int argc, cpidx; const char *opt; int flags; + const char *prefix; }; extern int parse_options_usage(const char * const *usagestr, @@ -192,8 +199,8 @@ const char *optstr, bool short_opt); -extern void parse_options_start(struct parse_opt_ctx_t *ctx, - int argc, const char **argv, int flags); +extern void parse_options_start(struct parse_opt_ctx_t *ctx, int argc, + const char **argv, const char *prefix, int flags); extern int parse_options_step(struct parse_opt_ctx_t *ctx, const struct option *options, diff -Nru ndctl-60.1/util/util.h ndctl-61.2/util/util.h --- ndctl-60.1/util/util.h 2018-04-23 19:15:18.000000000 +0000 +++ ndctl-61.2/util/util.h 2018-07-06 23:33:14.000000000 +0000 @@ -79,6 +79,11 @@ return strncmp(str, prefix, len) ? NULL : str + len; } +static inline int is_absolute_path(const char *path) +{ + return path[0] == '/'; +} + void usage(const char *err) NORETURN; void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); int error(const char *err, ...) __attribute__((format (printf, 1, 2))); @@ -87,5 +92,7 @@ char *xstrdup(const char *str); void *xrealloc(void *ptr, size_t size); int prefixcmp(const char *str, const char *prefix); +char *prefix_filename(const char *pfx, const char *arg); +void fix_filename(const char *prefix, const char **file); #endif /* __UTIL_H__ */