summaryrefslogtreecommitdiffstats
path: root/src/spdk/test/pmem
diff options
context:
space:
mode:
Diffstat (limited to 'src/spdk/test/pmem')
-rw-r--r--src/spdk/test/pmem/common.sh107
-rwxr-xr-xsrc/spdk/test/pmem/json_config/json_config.sh25
-rwxr-xr-xsrc/spdk/test/pmem/pmem.sh701
-rw-r--r--src/spdk/test/pmem/test_plan.md310
4 files changed, 1143 insertions, 0 deletions
diff --git a/src/spdk/test/pmem/common.sh b/src/spdk/test/pmem/common.sh
new file mode 100644
index 00000000..add36719
--- /dev/null
+++ b/src/spdk/test/pmem/common.sh
@@ -0,0 +1,107 @@
+BASE_DIR=$(readlink -f $(dirname $0))
+[[ -z "$TEST_DIR" ]] && TEST_DIR="$(cd $BASE_DIR/../../ && pwd)"
+rpc_py="$TEST_DIR/scripts/rpc.py "
+
+source $TEST_DIR/test/common/autotest_common.sh
+
+# Prints error message and return error code, closes vhost app and remove
+# pmem pool file
+# input: error message, error code
+function error()
+{
+ local error_code=${2:-1}
+ echo "==========="
+ echo -e "ERROR: $1"
+ echo "error code: $error_code"
+ echo "==========="
+ vhost_kill
+ pmem_clean_pool_file
+ return $error_code
+}
+
+# check if there is pool file & remove it
+# input: path to pool file
+# default: $TEST_DIR/test/pmem/pool_file
+function pmem_clean_pool_file()
+{
+ local pool_file=${1:-$TEST_DIR/test/pmem/pool_file}
+
+ if [ -f $pool_file ]; then
+ echo "Deleting old pool_file"
+ rm $pool_file
+ fi
+}
+
+# create new pmem file
+# input: path to pool file, size in MB, block_size
+# default: $TEST_DIR/test/pmem/pool_file 32 512
+function pmem_create_pool_file()
+{
+ local pool_file=${1:-$TEST_DIR/test/pmem/pool_file}
+ local size=${2:-32}
+ local block_size=${3:-512}
+
+ pmem_clean_pool_file $pool_file
+ echo "Creating new pool file"
+ if ! $rpc_py create_pmem_pool $pool_file $size $block_size; then
+ error "Creating pool_file failed!"
+ fi
+
+ if [ ! -f $pool_file ]; then
+ error "Creating pool_file failed!"
+ fi
+}
+
+function pmem_unmount_ramspace
+{
+ if [ -d "$TEST_DIR/test/pmem/ramspace" ]; then
+ if mount | grep -q "$TEST_DIR/test/pmem/ramspace"; then
+ umount $TEST_DIR/test/pmem/ramspace
+ fi
+
+ rm -rf $TEST_DIR/test/pmem/ramspace
+ fi
+}
+
+function pmem_print_tc_name
+{
+ echo ""
+ echo "==============================================================="
+ echo "Now running: $1"
+ echo "==============================================================="
+}
+
+function vhost_start()
+{
+ local vhost_pid
+
+ $TEST_DIR/app/vhost/vhost &
+ if [ $? != 0 ]; then
+ echo -e "ERROR: Failed to launch vhost!"
+ return 1
+ fi
+
+ vhost_pid=$!
+ echo $vhost_pid > $TEST_DIR/test/pmem/vhost.pid
+ waitforlisten $vhost_pid
+}
+
+function vhost_kill()
+{
+ local vhost_pid_file="$TEST_DIR/test/pmem/vhost.pid"
+ local vhost_pid="$(cat $vhost_pid_file)"
+
+ if [[ ! -f $TEST_DIR/test/pmem/vhost.pid ]]; then
+ echo -e "ERROR: No vhost pid file found!"
+ return 1
+ fi
+
+ if ! kill -s INT $vhost_pid; then
+ echo -e "ERROR: Failed to exit vhost / invalid pid!"
+ rm $vhost_pid_file
+ return 1
+ fi
+
+ sleep 1
+ rm $vhost_pid_file
+}
diff --git a/src/spdk/test/pmem/json_config/json_config.sh b/src/spdk/test/pmem/json_config/json_config.sh
new file mode 100755
index 00000000..bd232b8f
--- /dev/null
+++ b/src/spdk/test/pmem/json_config/json_config.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+set -ex
+VHOST_JSON_DIR=$(readlink -f $(dirname $0))
+. $VHOST_JSON_DIR/../../json_config/common.sh
+
+function test_subsystems() {
+ run_spdk_tgt
+
+ rpc_py="$spdk_rpc_py"
+ clear_config_py="$spdk_clear_config_py"
+ $rpc_py start_subsystem_init
+
+ create_pmem_bdev_subsytem_config
+ test_json_config
+ clear_pmem_bdev_subsystem_config
+
+ kill_targets
+}
+
+trap 'on_error_exit "${FUNCNAME}" "${LINENO}"' ERR
+timing_enter json_config_pmem
+
+test_subsystems
+timing_exit json_config_pmem
+report_test_completion json_config_pmem
diff --git a/src/spdk/test/pmem/pmem.sh b/src/spdk/test/pmem/pmem.sh
new file mode 100755
index 00000000..15188635
--- /dev/null
+++ b/src/spdk/test/pmem/pmem.sh
@@ -0,0 +1,701 @@
+#!/usr/bin/env bash
+
+BASE_DIR=$(readlink -f $(dirname $0))
+[[ -z "$TEST_DIR" ]] && TEST_DIR="$(cd $BASE_DIR/../../ && pwd)"
+
+enable_script_debug=false
+test_info=false
+test_create=false
+test_delete=false
+test_construct_bdev=false
+test_delete_bdev=false
+test_all=true
+test_all_get=false
+default_pool_file=$TEST_DIR/test/pmem/pool_file
+obj_pool_file=$TEST_DIR/test/pmem/obj_pool_file
+bdev_name=pmem0
+
+function usage()
+{
+ [[ ! -z $2 ]] && ( echo "$2"; echo ""; )
+ echo "Shortcut script for automated RPC tests for PMEM"
+ echo "For test details, check test_plan.md or"
+ echo "https://review.gerrithub.io/#/c/378618/18/test/pmem/test_plan.md"
+ echo
+ echo "Usage: $(basename $1) [OPTIONS]"
+ echo
+ echo "-h, --help Print help and exit"
+ echo "-x set -x for script debug"
+ echo " --info Run test cases for pmem_pool_info"
+ echo " --create Run test cases for create_pmem_pool"
+ echo " --delete Run test cases for delete_pmem_pool"
+ echo " --construct_bdev Run test cases for constructing pmem bdevs"
+ echo " --delete_bdev Run test cases for deleting pmem bdevs"
+ echo " --all Run all test cases (default)"
+ exit 0
+}
+
+while getopts 'xh-:' optchar; do
+ case "$optchar" in
+ -)
+ case "$OPTARG" in
+ help) usage $0 ;;
+ info) test_info=true; test_all=false;;
+ create) test_create=true; test_all=false;;
+ delete) test_delete=true; test_all=false;;
+ construct_bdev) test_construct_bdev=true; test_all=false;;
+ delete_bdev) test_delete_bdev=true; test_all=false;;
+ all) test_all_get=true;;
+ *) usage $0 "Invalid argument '$OPTARG'" ;;
+ esac
+ ;;
+ h) usage $0 ;;
+ x) enable_script_debug=true ;;
+ *) usage $0 "Invalid argument '$OPTARG'"
+ esac
+done
+
+if $test_all_get; then
+ test_all=true
+fi
+
+if [[ $EUID -ne 0 ]]; then
+ echo "Go away user come back as root"
+ exit 1
+fi
+
+source $TEST_DIR/test/pmem/common.sh
+source $TEST_DIR/test/common/autotest_common.sh
+
+#================================================
+# pmem_pool_info tests
+#================================================
+function pmem_pool_info_tc1()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+
+ if $rpc_py pmem_pool_info; then
+ error "pmem_pool_info passed with missing argument!"
+ fi
+
+ return 0
+}
+
+function pmem_pool_info_tc2()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+
+ if $rpc_py pmem_pool_info $TEST_DIR/non/existing/path/non_existent_file; then
+ error "pmem_pool_info passed with invalid path!"
+ fi
+
+ return 0
+}
+
+function pmem_pool_info_tc3()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file $TEST_DIR/test/pmem/obj_pool_file
+
+ echo "Creating new type OBJ pool file"
+ if hash pmempool; then
+ pmempool create -s 32000000 obj $obj_pool_file
+ else
+ echo "Warning: pmempool package not found! Creating stub file."
+ truncate -s "32M" $obj_pool_file
+ fi
+
+ if $rpc_py pmem_pool_info $TEST_DIR/test/pmem/obj_pool_file; then
+ pmem_clean_pool_file $TEST_DIR/test/pmem/obj_pool_file
+ error "Pmem_pool_info passed with invalid pool_file type!"
+ fi
+
+ pmem_clean_pool_file $TEST_DIR/test/pmem/obj_pool_file
+ return 0
+}
+
+function pmem_pool_info_tc4()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+
+ pmem_create_pool_file
+ if ! $rpc_py pmem_pool_info $default_pool_file; then
+ error "Failed to get pmem_pool_info!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+#================================================
+# create_pmem_pool tests
+#================================================
+function create_pmem_pool_tc1()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+
+ if $rpc_py create_pmem_pool 32 512; then
+ error "Mem pool file created w/out given path!"
+ fi
+
+ if $rpc_py create_pmem_pool $default_pool_file; then
+ error "Mem pool file created w/out size & block size arguments!"
+ fi
+
+ if $rpc_py pmem_pool_info $default_pool_file; then
+ error "create_pmem_pool created invalid pool file!"
+ fi
+
+ if $rpc_py create_pmem_pool $default_pool_file 32; then
+ error "Mem pool file created w/out block size argument!"
+ fi
+
+ if $rpc_py pmem_pool_info $default_pool_file; then
+ error "create_pmem_pool created invalid pool file!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+function create_pmem_pool_tc2()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+
+ if $rpc_py create_pmem_pool $TEST_DIR/non/existing/path/non_existent_file 32 512; then
+ error "Mem pool file created with incorrect path!"
+ fi
+
+ if $rpc_py pmem_pool_info $TEST_DIR/non/existing/path/non_existent_file; then
+ error "create_pmem_pool created invalid pool file!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+function create_pmem_pool_tc3()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+
+ if ! $rpc_py create_pmem_pool $default_pool_file 256 512; then
+ error "Failed to create pmem pool!"
+ fi
+
+ if ! $rpc_py pmem_pool_info $default_pool_file; then
+ error "Failed to get pmem info"
+ fi
+
+ if ! $rpc_py delete_pmem_pool $default_pool_file; then
+ error "Failed to delete pool file!"
+ fi
+
+ if $rpc_py pmem_pool_info $default_pool_file; then
+ error "Got pmem file info but file should be deleted"
+ fi
+
+ if [ -f $default_pool_file ]; then
+ error "Failed to delete pmem file!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+function create_pmem_pool_tc4()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+
+ pmem_unmount_ramspace
+ mkdir $TEST_DIR/test/pmem/ramspace
+ mount -t tmpfs -o size=300m tmpfs $TEST_DIR/test/pmem/ramspace
+ if ! $rpc_py create_pmem_pool $TEST_DIR/test/pmem/ramspace/pool_file 256 512; then
+ pmem_unmount_ramspace
+ error "Failed to create pmem pool!"
+ fi
+
+ if ! $rpc_py pmem_pool_info $TEST_DIR/test/pmem/ramspace/pool_file; then
+ pmem_unmount_ramspace
+ error "Failed to get pmem info"
+ fi
+
+ if ! $rpc_py delete_pmem_pool $TEST_DIR/test/pmem/ramspace/pool_file; then
+ pmem_unmount_ramspace
+ error "Failed to delete pool file!"
+ fi
+
+ if [ -f $TEST_DIR/test/pmem/ramspace/pool_file ]; then
+ pmem_unmount_ramspace
+ error "Failed to delete pmem file / file still exists!"
+ fi
+
+ pmem_unmount_ramspace
+ return 0
+}
+
+function create_pmem_pool_tc5()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+ local pmem_block_size
+ local pmem_num_block
+
+ if ! $rpc_py create_pmem_pool $default_pool_file 256 512; then
+ error "Failed to create pmem pool!"
+ fi
+
+ if $rpc_py pmem_pool_info $default_pool_file; then
+ pmem_block_size=$($rpc_py pmem_pool_info $default_pool_file | jq -r '.[] .block_size')
+ pmem_num_block=$($rpc_py pmem_pool_info $default_pool_file | jq -r '.[] .num_blocks')
+ else
+ error "Failed to get pmem info!"
+ fi
+
+ if $rpc_py create_pmem_pool $default_pool_file 512 4096; then
+ error "Pmem pool with already occupied path has been created!"
+ fi
+
+ if $rpc_py pmem_pool_info $default_pool_file; then
+ if [ $pmem_block_size != $($rpc_py pmem_pool_info $default_pool_file | jq -r '.[] .block_size') ]; then
+ error "Invalid block size of pmem pool!"
+ fi
+
+ if [ $pmem_num_block != $($rpc_py pmem_pool_info $default_pool_file | jq -r '.[] .num_blocks') ]; then
+ error "Invalid number of blocks of pmem pool!"
+ fi
+ else
+ error "Failed to get pmem info!"
+ fi
+
+ if ! $rpc_py delete_pmem_pool $default_pool_file; then
+ error "Failed to delete pmem file!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+function create_pmem_pool_tc6()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+ local created_pmem_block_size
+
+ for i in 511 512 1024 2048 4096 131072 262144
+ do
+ if ! $rpc_py create_pmem_pool $default_pool_file 256 $i; then
+ error "Failed to create pmem pool!"
+ fi
+
+ created_pmem_block_size=$($rpc_py pmem_pool_info $default_pool_file | jq -r '.[] .block_size')
+ if [ $? != 0 ]; then
+ error "Failed to get pmem info!"
+ fi
+
+ if [ $i != $created_pmem_block_size ]; then
+ error "Invalid block size of pmem pool!"
+ fi
+
+ if ! $rpc_py delete_pmem_pool $default_pool_file; then
+ error "Failed to delete pmem file!"
+ fi
+ done
+
+ pmem_clean_pool_file
+ return 0
+}
+
+function create_pmem_pool_tc7()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+
+ if $rpc_py create_pmem_pool $default_pool_file 15 512; then
+ error "Created pmem pool with invalid size!"
+ fi
+
+ if $rpc_py pmem_pool_info $default_pool_file; then
+ error "Pmem file shouldn' exist!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+function create_pmem_pool_tc8()
+{
+ pmem_print_tc_name "create_pmem_pool_tc8"
+ pmem_clean_pool_file
+
+ if $rpc_py create_pmem_pool $default_pool_file 32 65536; then
+ error "Created pmem pool with invalid block number!"
+ fi
+
+ if $rpc_py pmem_pool_info $default_pool_file; then
+ error "Pmem file shouldn' exist!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+function create_pmem_pool_tc9()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+
+ if $rpc_py create_pmem_pool $default_pool_file 256 -1; then
+ error "Created pmem pool with negative block size number!"
+ fi
+
+ if $rpc_py pmem_pool_info $default_pool_file; then
+ error "create_pmem_pool create invalid pool file!"
+ fi
+
+ if $rpc_py create_pmem_pool $default_pool_file -1 512; then
+ error "Created pmem pool with negative size number!"
+ fi
+
+ if $rpc_py pmem_pool_info $default_pool_file; then
+ error "create_pmem_pool create invalid pool file!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+#================================================
+# delete_pmem_pool tests
+#================================================
+function delete_pmem_pool_tc1()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+
+ if $rpc_py delete_pmem_pool $default_pool_file; then
+ error "delete_pmem_pool deleted inexistant pool file!"
+ fi
+
+ return 0
+}
+
+function delete_pmem_pool_tc2()
+{
+ pmem_print_tc_name "delete_pmem_pool_tc2"
+ pmem_clean_pool_file $TEST_DIR/test/pmem/obj_pool_file
+
+ echo "Creating new type OBJ pool file"
+ if hash pmempool; then
+ pmempool create -s 32000000 obj $obj_pool_file
+ else
+ echo "Warning: pmempool package not found! Creating stub file."
+ truncate -s "32M" $obj_pool_file
+ fi
+
+ if $rpc_py delete_pmem_pool $TEST_DIR/test/pmem/obj_pool_file; then
+ pmem_clean_pool_file $TEST_DIR/test/pmem/obj_pool_file
+ error "delete_pmem_pool deleted invalid pmem pool type!"
+ fi
+
+ pmem_clean_pool_file $TEST_DIR/test/pmem/obj_pool_file
+ return 0
+}
+
+function delete_pmem_pool_tc3()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+
+ pmem_create_pool_file
+ if ! $rpc_py pmem_pool_info $default_pool_file; then
+ error "Failed to get info on pmem pool file!"
+ fi
+
+ if ! $rpc_py delete_pmem_pool $default_pool_file; then
+ error "Failed to delete pmem pool file!"
+ fi
+
+ if $rpc_py pmem_pool_info $default_pool_file; then
+ error "Pmem pool file exists after using pmem_pool_info!"
+ fi
+
+ return 0
+}
+
+function delete_pmem_pool_tc4()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+
+ delete_pmem_pool_tc3
+ if $rpc_py delete_pmem_pool $default_pool_file; then
+ error "Deleted pmem pool file that shouldn't exist!"
+ fi
+
+ return 0
+}
+
+#================================================
+# construct_pmem_bdev tests
+#================================================
+function construct_pmem_bdev_tc1()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+
+ pmem_create_pool_file
+ if $rpc_py construct_pmem_bdev; then
+ error "construct_pmem_bdev passed with missing argument!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+function construct_pmem_bdev_tc2()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+
+ pmem_create_pool_file
+ if $rpc_py construct_pmem_bdev -n $bdev_name $TEST_DIR/non/existing/path/non_existent_file; then
+ error "Created pmem bdev w/out valid pool file!"
+ fi
+
+ if $rpc_py get_bdevs | jq -r '.[] .name' | grep -qi pmem; then
+ error "construct_pmem_bdev passed with invalid argument!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+function construct_pmem_bdev_tc3()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+
+ truncate -s 32M $TEST_DIR/test/pmem/random_file
+ if $rpc_py construct_pmem_bdev -n $bdev_name $TEST_DIR/test/pmem/random_file; then
+ error "Created pmem bdev from random file!"
+ fi
+
+ if [ -f $TEST_DIR/test/pmem/random_file ]; then
+ echo "Deleting previously created random file"
+ rm $TEST_DIR/test/pmem/random_file
+ fi
+
+ return 0
+}
+
+function construct_pmem_bdev_tc4()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file $TEST_DIR/test/pmem/obj_pool_file
+
+ echo "Creating new type OBJ pool file"
+ if hash pmempool; then
+ pmempool create -s 32000000 obj $obj_pool_file
+ else
+ echo "Warning: pmempool package not found! Creating stub file."
+ truncate -s "32M" $obj_pool_file
+ fi
+
+ if $rpc_py construct_pmem_bdev -n $bdev_name $TEST_DIR/test/pmem/obj_pool_file; then
+ pmem_clean_pool_file $TEST_DIR/test/pmem/obj_pool_file
+ error "Created pmem bdev from obj type pmem file!"
+ fi
+
+ pmem_clean_pool_file $TEST_DIR/test/pmem/obj_pool_file
+ return 0
+}
+
+function construct_pmem_bdev_tc5()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+ pmem_create_pool_file
+ local pmem_bdev_name
+
+ if ! $rpc_py pmem_pool_info $default_pool_file; then
+ error "Failed to get pmem info!"
+ fi
+
+ pmem_bdev_name=$($rpc_py construct_pmem_bdev -n $bdev_name $default_pool_file)
+ if [ $? != 0 ]; then
+ error "Failed to create pmem bdev"
+ fi
+
+ if ! $rpc_py get_bdevs | jq -r '.[] .name' | grep -qi $pmem_bdev_name; then
+ error "Pmem bdev not found!"
+ fi
+
+ if ! $rpc_py delete_pmem_bdev $pmem_bdev_name; then
+ error "Failed to delete pmem bdev!"
+ fi
+
+ if ! $rpc_py delete_pmem_pool $default_pool_file; then
+ error "Failed to delete pmem pool file!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+function construct_pmem_bdev_tc6()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ local pmem_bdev_name
+ pmem_clean_pool_file
+
+ pmem_create_pool_file
+ if ! $rpc_py pmem_pool_info $default_pool_file; then
+ error "Failed to get info on pmem pool file!"
+ fi
+
+ pmem_bdev_name=$($rpc_py construct_pmem_bdev -n $bdev_name $default_pool_file)
+ if [ $? != 0 ]; then
+ error "Failed to create pmem bdev!"
+ fi
+
+ if ! $rpc_py get_bdevs | jq -r '.[] .name' | grep -qi $pmem_bdev_name; then
+ error "Pmem bdev not found!"
+ fi
+
+ if $rpc_py construct_pmem_bdev -n $bdev_name $default_pool_file; then
+ error "Constructed pmem bdev with occupied path!"
+ fi
+
+ if ! $rpc_py delete_pmem_bdev $pmem_bdev_name; then
+ error "Failed to delete pmem bdev!"
+ fi
+
+ if ! $rpc_py delete_pmem_pool $default_pool_file; then
+ error "Failed to delete pmem pool file!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+#================================================
+# delete_pmem_bdev tests
+#================================================
+function delete_bdev_tc1()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ local pmem_bdev_name
+ local bdevs_names
+ pmem_clean_pool_file
+
+ pmem_create_pool_file $default_pool_file 256 512
+ if ! $rpc_py pmem_pool_info $default_pool_file; then
+ error "Failed to get pmem info!"
+ fi
+
+ pmem_bdev_name=$($rpc_py construct_pmem_bdev -n $bdev_name $default_pool_file)
+ if [ $? != 0 ]; then
+ error "Failed to create pmem bdev!"
+ fi
+
+ if ! $rpc_py get_bdevs | jq -r '.[] .name' | grep -qi $pmem_bdev_name; then
+ error "$pmem_bdev_name bdev not found!"
+ fi
+
+ if ! $rpc_py delete_pmem_bdev $pmem_bdev_name; then
+ error "Failed to delete $pmem_bdev_name bdev!"
+ fi
+
+ bdevs_names=$($rpc_py get_bdevs | jq -r '.[] .name')
+ if echo $bdevs_names | grep -qi $pmem_bdev_name; then
+ error "$pmem_bdev_name bdev is not deleted!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+function delete_bdev_tc2()
+{
+ pmem_print_tc_name ${FUNCNAME[0]}
+ pmem_clean_pool_file
+ pmem_create_pool_file $default_pool_file 256 512
+ local pmem_bdev_name
+
+ if ! $rpc_py pmem_pool_info $default_pool_file; then
+ error "Failed to get pmem info!"
+ fi
+
+ pmem_bdev_name=$($rpc_py construct_pmem_bdev -n $bdev_name $default_pool_file)
+ if [ $? != 0 ]; then
+ error "Failed to create pmem bdev"
+ fi
+
+ if ! $rpc_py get_bdevs | jq -r '.[] .name' | grep -qi $pmem_bdev_name; then
+ error "Pmem bdev not found!"
+ fi
+
+ if ! $rpc_py delete_pmem_bdev $pmem_bdev_name; then
+ error "Failed to delete pmem bdev!"
+ fi
+
+ if $rpc_py delete_pmem_bdev $pmem_bdev_name; then
+ error "delete_pmem_bdev deleted pmem bdev for second time!"
+ fi
+
+ pmem_clean_pool_file
+ return 0
+}
+
+timing_enter pmem
+vhost_start
+if ! $enable_script_debug; then
+ set +x
+fi
+
+if $test_info || $test_all; then
+ pmem_pool_info_tc1
+ pmem_pool_info_tc2
+ pmem_pool_info_tc3
+ pmem_pool_info_tc4
+fi
+
+if $test_create || $test_all; then
+ create_pmem_pool_tc1
+ create_pmem_pool_tc2
+ create_pmem_pool_tc3
+ create_pmem_pool_tc4
+ create_pmem_pool_tc5
+ create_pmem_pool_tc6
+ create_pmem_pool_tc7
+ create_pmem_pool_tc8
+ create_pmem_pool_tc9
+fi
+
+if $test_delete || $test_all; then
+ delete_pmem_pool_tc1
+ delete_pmem_pool_tc2
+ delete_pmem_pool_tc3
+ delete_pmem_pool_tc4
+fi
+
+if $test_construct_bdev || $test_all; then
+ construct_pmem_bdev_tc1
+ construct_pmem_bdev_tc2
+ construct_pmem_bdev_tc3
+ construct_pmem_bdev_tc4
+ construct_pmem_bdev_tc5
+ construct_pmem_bdev_tc6
+fi
+
+if $test_delete_bdev || $test_all; then
+ delete_bdev_tc1
+ delete_bdev_tc2
+fi
+
+pmem_clean_pool_file
+report_test_completion "pmem"
+vhost_kill
+timing_exit pmem
diff --git a/src/spdk/test/pmem/test_plan.md b/src/spdk/test/pmem/test_plan.md
new file mode 100644
index 00000000..18e99f36
--- /dev/null
+++ b/src/spdk/test/pmem/test_plan.md
@@ -0,0 +1,310 @@
+# PMEM bdev feature test plan
+
+## Objective
+The purpose of these tests is to verify possibility of using pmem bdev
+configuration in SPDK by running functional tests FIO traffic verification
+tests.
+
+## Configuration
+Configuration in tests is to be done using example stub application
+(spdk/example/bdev/io/bdev_io).
+All possible management is done using RPC calls with the exception of
+use of split bdevs which have to be configured in .conf file.
+
+Functional tests are executed as scenarios - sets of smaller test steps
+in which results and return codes of RPC calls are validated.
+Some configuration calls may also additionally be validated
+by use of "get" (e.g. get_bdevs) RPC calls, which provide additional
+information for veryfing results.
+In some steps additional write/read operations will be performed on
+PMEM bdevs in order to check IO path correct behavior.
+
+FIO traffic verification tests will serve as integration tests and will
+be executed to config correct behavior of PMEM bdev when working with vhost,
+nvmf_tgt and iscsi_tgt applications.
+
+## Functional tests
+
+### pmem_pool_info
+
+#### pmem_pool_info_tc1
+Negative test for checking pmem pool file.
+Call with missing path argument.
+Steps & expected results:
+- Call pmem_pool_info with missing path argument
+- Check that return code != 0 and error code =
+
+#### pmem_pool_info_tc2
+Negative test for checking pmem pool file.
+Call with non-existant path argument.
+Steps & expected results:
+- Call pmem_pool_info with path argument that points to not existing file.
+- Check that return code != 0 and error code = ENODEV
+
+#### pmem_pool_info_tc3
+Negative test for checking pmem pool file.
+Call with other type of pmem pool file.
+Steps & expected results:
+- Using pmem utility tools create pool of OBJ type instead of BLK
+(if needed utility tools are not available - create random file in filesystem)
+- Call pmem_pool_info and point to file created in previous step.
+- Check that return code != 0 and error code = ENODEV
+
+#### pmem_pool_info_tc4
+Positive test for checking pmem pool file.
+Call with existing pmem pool file.
+Steps & expected results:
+- Call pmem_pool_info with path argument that points to existing file.
+- Check that return code == 0
+
+### create_pmem_pool
+From libpmemblk documentation:
+- PMEM block size has to be bigger than 512 internal blocks; if lower value
+is used then PMEM library will silently round it up to 512 which is defined
+in pmem/libpmemblk.h file as PMEMBLK_MIN_BLK.
+- Total pool size cannot be less than 16MB which is defined i
+pmem/libpmemblk.h file as PMEMBLK_MIN_POOL
+- Total number of segments in PMEP pool file cannot be less than 256
+
+#### create_pmem_pool_tc1
+Negative test case for creating a new pmem.
+Call create_pmem_pool with missing arguments.
+Steps & expected results:
+- call create_pmem_pool without path argument
+- call return code != 0
+- call pmem_pool_info and check that pmem pool file was not created
+- call return code != 0
+- call create_pmem_pool with path but without size and block size arguments
+- call return code != 0
+- call pmem_pool_info and check that pmem pool file was not created
+- call return code != 0
+- call create_pmem_pool with path and size but without block size arguments
+- call return code != 0
+- call pmem_pool_info and check that pmem pool file was not created
+- call return code != 0
+
+#### create_pmem_pool_tc2
+Negative test case for creating a new pmem.
+Call create_pmem_pool with non existing path argument.
+Steps & expected results:
+- call create_pmem_pool with path that does not exist
+- call return code != 0
+- call pmem_pool_info and check that pmem pool file was not created
+- call return code != 0
+
+#### create_pmem_pool_tc3
+Positive test case for creating a new pmem pool on disk space.
+Steps & expected results:
+- call create_pmem_pool with correct path argument,
+blocksize=512 and total size=256MB
+- call return code = 0
+- call pmem_pool_info and check that pmem file was created
+- call return code = 0
+- call delete_pmem_pool on previously created pmem
+- return code = 0 and no error code
+
+#### create_pmem_pool_tc4
+Positive test case for creating a new pmem pool in RAM space.
+# TODO: Research test steps for creating a pool in RAM!!!
+Steps & expected results:
+- call create_pmem_pool with correct path argument,
+blocksize=512 and total size=256MB
+- call return code = 0
+- call pmem_pool_info and check that pmem file was created
+- call return code = 0
+- call delete_pmem_pool on previously created pmem
+- return code = 0 and no error code
+
+#### create_pmem_pool_tc5
+Negative test case for creating two pmems with same path.
+Steps & expected results:
+- call create_pmem_pool with correct path argument,
+blocksize=512 and total size=256MB
+- call return code = 0
+- call pmem_pool_info and check that pmem file was created
+- call return code = 0
+- call create_pmem_pool with the same path argument as before,
+blocksize=4096 and total size=512MB
+- call return code != 0, error code = EEXIST
+- call create_pmem_pool and check that first pmem pool file is still
+available and not modified (block size and total size stay the same)
+- call return code = 0
+- call delete_pmem_pool on first created pmem pool
+- return code =0 and no error code
+
+#### create_pmem_pool_tc6
+Positive test case for creating pmem pool file with various block sizes.
+Steps & expected results:
+- call create_pmem_pool with correct path argument, total size=256MB
+with different block size arguments - 1, 511, 512, 513, 1024, 4096, 128k and 256k
+- call pmem_pool_info on each of created pmem pool and check if it was created;
+For pool files created with block size <512 their block size should be rounded up
+to 512; other pool files should have the same block size as specified in create
+command
+- call return code = 0; block sizes as expected
+- call delete_pmem_pool on all created pool files
+
+#### create_pmem_pool_tc7
+Negative test case for creating pmem pool file with total size of less than 16MB.
+Steps & expected results:
+- call create_pmem_pool with correct path argument, block size=512 and
+total size less than 16MB
+- return code !=0 and error code !=0
+- call pmem_pool_info to verify pmem pool file was not created
+- return code = 0
+
+#### create_pmem_pool_tc8
+Negative test case for creating pmem pool file with less than 256 blocks.
+Steps & expected results:
+- call create_pmem_pool with correct path argument, block size=128k and
+total size=30MB
+- return code !=0 and error code !=0
+- call pmem_pool_info to verify pmem pool file was not created
+- return code = 0
+
+### delete_pmem_pool
+
+#### delete_pmem_pool_tc1
+Negative test case for deleting a pmem.
+Call delete_pmem_pool on non-exisiting pmem.
+Steps & expected results:
+- call delete_pmem_pool on non-existing pmem.
+- return code !=0 and error code = ENOENT
+
+#### delete_pmem_pool_tc2
+Negative test case for deleting a pmem.
+Call delete_pmem_pool on a file of wrong type
+Steps & expected results:
+- Using pmem utility tools create pool of OBJ type instead of BLK
+(if needed utility tools are not available - create random file in filesystem)
+- Call delete_pmem_pool and point to file created in previous step.
+- return code !=0 and error code = ENOTBLK
+
+#### delete_pmem_pool_tc3
+Positive test case for creating and deleting a pemem.
+Steps & expected results:
+- call create_pmem_pool with correct arguments
+- return code = 0 and no error code
+- using pmem_pool_info check that pmem was created
+- return code = 0 and no error code
+- call delete_pmem_pool on previously created pmem
+- return code = 0 and no error code
+- using pmem_pool_info check that pmem no longer exists
+- return code !=0 and error code = ENODEV
+
+#### delete_pmem_pool_tc4
+Negative test case for creating and deleting a pemem.
+Steps & expected results:
+- run scenario from test case 3
+- call delete_pmem_pool on already deleted pmem pool
+- return code !=0 and error code = ENODEV
+
+### construct_pmem_bdev
+
+#### construct_pmem_bdev_tc1
+Negative test for constructing new pmem bdev.
+Call create_pmem_bdev with missing argument.
+Steps & expected results:
+- Call construct_pmem_bdev with missing path argument.
+- Check that return code != 0
+
+#### construct_pmem_bdev_tc2
+Negative test for constructing new pmem bdev.
+Call construct_pmem_bdev with not existing path argument.
+Steps & expected results:
+- call construct_pmem_bdev with incorrect (not existing) path
+- call return code != 0 and error code = ENODEV
+- using get_bdevs check that no pmem bdev was created
+
+#### construct_pmem_bdev_tc3
+Negative test for constructing pmem bdevs with random file instead of pmemblk pool.
+Steps & expected results:
+- using a system tool (like dd) create a random file
+- call construct_pmem_bdev with path pointing to that file
+- return code != 0, error code = ENOTBLK
+
+#### construct_pmem_bdev_tc4
+Negative test for constructing pmem bdevs with pmemobj instead of pmemblk pool.
+Steps & expected results:
+- Using pmem utility tools create pool of OBJ type instead of BLK
+(if needed utility tools are not available - create random file in filesystem)
+- call construct_pmem_bdev with path pointing to that pool
+- return code != 0, error code = ENOTBLK
+
+#### construct_pmem_bdev_tc5
+Positive test for constructing pmem bdev.
+Steps & expected results:
+- call create_pmem_pool with correct arguments
+- return code = 0, no errors
+- call pmem_pool_info and check if pmem files exists
+- return code = 0, no errors
+- call construct_pmem_bdev with with correct arguments to create a pmem bdev
+- return code = 0, no errors
+- using get_bdevs check that pmem bdev was created
+- delete pmem bdev using delete_bdev
+- return code = 0, no error code
+- delete previously created pmem pool
+- return code = 0, no error code
+
+#### construct_pmem_bdev_tc6
+Negative test for constructing pmem bdevs twice on the same pmem.
+Steps & expected results:
+- call create_pmem_pool with correct arguments
+- return code = 0, no errors
+- call pmem_pool_info and check if pmem files exists
+- return code = 0, no errors
+- call construct_pmem_bdev with with correct arguments to create a pmem bdev
+- return code = 0, no errors
+- using get_bdevs check that pmem bdev was created
+- call construct_pmem_bdev again on the same pmem file
+- return code != 0, error code = EEXIST
+- delete pmem bdev using delete_bdev
+- return code = 0, no error code
+- delete previously created pmem pool
+- return code = 0, no error code
+
+### delete_bdev
+
+#### delete_bdev_tc1
+Positive test for deleting pmem bdevs using common delete_bdev call.
+Steps & expected results:
+- construct malloc and aio bdevs (also NVMe if possible)
+- all calls - return code = 0, no errors; bdevs created
+- call create_pmem_pool with correct path argument,
+block size=512, total size=256M
+- return code = 0, no errors
+- call pmem_pool_info and check if pmem file exists
+- return code = 0, no errors
+- call construct_pmem_bdev and create a pmem bdev
+- return code = 0, no errors
+- using get_bdevs check that pmem bdev was created
+- delete pmem bdev using delete_bdev
+- return code = 0, no errors
+- using get_bdevs confirm that pmem bdev was deleted and other bdevs
+were unaffected.
+
+#### delete_bdev_tc2
+Negative test for deleting pmem bdev twice.
+Steps & expected results:
+- call create_pmem_pool with correct path argument,
+block size=512, total size=256M
+- return code = 0, no errors
+- call pmem_pool_info and check if pmem file exists
+- return code = 0, no errors
+- call construct_pmem_bdev and create a pmem bdev
+- return code = 0, no errors
+- using get_bdevs check that pmem bdev was created
+- delete pmem bdev using delete_bdev
+- return code = 0, no errors
+- using get_bdevs confirm that pmem bdev was deleted
+- delete pmem bdev using delete_bdev second time
+- return code != 0, error code = ENODEV
+
+
+## Integration tests
+Description of integration tests which run FIO verification traffic against
+pmem_bdevs used in vhost, iscsi_tgt and nvmf_tgt applications can be found in
+test directories for these components:
+- spdk/test/vhost
+- spdk/test/nvmf
+- spdk/test/iscsi_tgt