Spdk/test/make/check_so_deps.sh

507 lines
14 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
if [ "$(uname -s)" = "FreeBSD" ]; then
echo "Not testing for shared object dependencies on FreeBSD."
exit 0
fi
rootdir=$(readlink -f $(dirname $0)/../..)
if [[ ! -f $1 ]]; then
echo "ERROR: SPDK test configuration not specified"
exit 1
fi
source $1
source "$rootdir/test/common/autotest_common.sh"
libdir="$rootdir/build/lib"
libdeps_file="$rootdir/mk/spdk.lib_deps.mk"
source_abi_dir="$HOME/spdk_20_04/build/lib"
suppression_file="$HOME/abigail_suppressions.ini"
function confirm_abi_deps() {
local processed_so=0
if ! hash abidiff; then
echo "Unable to check ABI compatibility. Please install abidiff."
return 1
fi
if [ ! -d $source_abi_dir ]; then
echo "No source ABI available, failing this test."
return 1
fi
cat << EOF > ${suppression_file}
[suppress_variable]
name = SPDK_LOG_IDXD
[suppress_variable]
name = SPDK_LOG_IOAT
[suppress_variable]
name = SPDK_LOG_JSON_UTIL
[suppress_variable]
name = SPDK_LOG_RPC
[suppress_variable]
name = SPDK_LOG_RPC_CLIENT
[suppress_function]
name = spdk_jsonrpc_server_handle_request
[suppress_function]
name = spdk_jsonrpc_server_handle_error
[suppress_function]
name = spdk_jsonrpc_server_send_response
[suppress_function]
name = spdk_jsonrpc_parse_request
[suppress_function]
name = spdk_jsonrpc_free_request
[suppress_function]
name = spdk_jsonrpc_parse_response
[suppress_variable]
name = SPDK_LOG_LOG_RPC
[suppress_variable]
name = SPDK_LOG_LOG
[suppress_variable]
name = SPDK_LOG_LVOL
[suppress_variable]
name = SPDK_LOG_NBD
[suppress_function]
name = spdk_nbd_disk_find_by_nbd_path
[suppress_function]
name = spdk_nbd_disk_first
[suppress_function]
name = spdk_nbd_disk_next
[suppress_function]
name = spdk_nbd_disk_get_nbd_path
[suppress_function]
name = spdk_nbd_disk_get_bdev_name
[suppress_variable]
name = SPDK_LOG_NET
[suppress_function]
name = spdk_interface_net_interface_add_ip_address
[suppress_function]
name = spdk_interface_net_interface_delete_ip_address
[suppress_function]
name = spdk_interface_get_list
[suppress_function]
name = spdk_get_uevent
[suppress_function]
name = spdk_uevent_connect
[suppress_function]
name = spdk_nvme_ctrlr_get_current_process
[suppress_function]
name = spdk_nvme_ctrlr_get_process
[suppress_function]
name = spdk_nvme_get_ctrlr_by_trid_unsafe
[suppress_function]
name = spdk_nvme_io_msg_process
[suppress_function]
name = spdk_nvme_wait_for_completion
[suppress_function]
name = spdk_nvme_wait_for_completion_robust_lock
[suppress_function]
name = spdk_nvme_wait_for_completion_timeout
[suppress_variable]
name = SPDK_LOG_NVME
[suppress_variable]
name = SPDK_LOG_OPAL
[suppress_variable]
name = spdk_opal_method
[suppress_variable]
name = spdk_opal_uid
[suppress_variable]
name = SPDK_LOG_REDUCE
[suppress_variable]
name = SPDK_LOG_THREAD
[suppress_variable]
name = SPDK_LOG_TRACE
[suppress_function]
name = spdk_crc32_table_init
[suppress_function]
name = spdk_crc32_update
[suppress_variable]
name = SPDK_LOG_VIRTIO_DEV
[suppress_variable]
name = SPDK_LOG_VIRTIO_PCI
[suppress_variable]
name = SPDK_LOG_VIRTIO_USER
[suppress_variable]
name = SPDK_LOG_VMD
[suppress_variable]
name = SPDK_LOG_ACCEL_IDXD
[suppress_variable]
name = SPDK_LOG_ACCEL_IOAT
[suppress_variable]
name = SPDK_LOG_AIO
[suppress_variable]
name = SPDK_LOG_VBDEV_COMPRESS
[suppress_variable]
name = SPDK_LOG_CRYPTO
[suppress_variable]
name = SPDK_LOG_VBDEV_DELAY
[suppress_function]
name = spdk_vbdev_error_create
[suppress_function]
name = spdk_vbdev_error_delete
[suppress_function]
name = spdk_vbdev_error_inject_error
[suppress_variable]
name = SPDK_LOG_BDEV_FTL
[suppress_variable]
name = SPDK_LOG_GPT_PARSE
[suppress_variable]
name = SPDK_LOG_VBDEV_GPT
[suppress_function]
name = spdk_gpt_parse_mbr
[suppress_function]
name = spdk_gpt_parse_partition_table
[suppress_variable]
name = SPDK_LOG_ISCSI_INIT
[suppress_variable]
name = SPDK_LOG_LVOL_RPC
[suppress_variable]
name = SPDK_LOG_VBDEV_LVOL
[suppress_variable]
name = SPDK_LOG_BDEV_MALLOC
[suppress_variable]
name = SPDK_LOG_BDEV_NULL
[suppress_variable]
name = SPDK_LOG_BDEV_NVME
[suppress_function]
name = spdk_bdev_nvme_create
[suppress_function]
name = spdk_bdev_nvme_delete
[suppress_function]
name = spdk_bdev_nvme_get_ctrlr
[suppress_function]
name = spdk_bdev_nvme_get_io_qpair
[suppress_function]
name = spdk_bdev_nvme_get_opts
[suppress_function]
name = spdk_bdev_nvme_set_hotplug
[suppress_function]
name = spdk_bdev_nvme_set_opts
[suppress_function]
name = spdk_vbdev_opal_create
[suppress_function]
name = spdk_vbdev_opal_destruct
[suppress_function]
name = spdk_vbdev_opal_enable_new_user
[suppress_function]
name = spdk_vbdev_opal_get_info_from_bdev
[suppress_function]
name = spdk_vbdev_opal_set_lock_state
[suppress_variable]
name = SPDK_LOG_BDEV_OCSSD
[suppress_variable]
name = SPDK_LOG_VBDEV_OPAL
[suppress_variable]
name = SPDK_LOG_OCFCTX
[suppress_variable]
name = SPDK_LOG_VBDEV_PASSTHRU
[suppress_variable]
name = SPDK_LOG_BDEV_PMEM
[suppress_function]
name = spdk_create_pmem_disk
[suppress_function]
name = spdk_delete_pmem_disk
[suppress_variable]
name = SPDK_LOG_BDEV_RAID
[suppress_variable]
name = SPDK_LOG_BDEV_RAID0
[suppress_variable]
name = SPDK_LOG_BDEV_RAID5
[suppress_variable]
name = SPDK_LOG_RAID_RPC
[suppress_variable]
name = SPDK_LOG_BDEV_RBD
[suppress_function]
name = spdk_bdev_rbd_create
[suppress_function]
name = spdk_bdev_rbd_delete
[suppress_function]
name = spdk_bdev_rbd_dup_config
[suppress_function]
name = spdk_bdev_rbd_free_config
[suppress_function]
name = spdk_bdev_rbd_resize
[suppress_variable]
name = SPDK_LOG_VBDEV_SPLIT
[suppress_function]
name = spdk_vbdev_split_destruct
[suppress_function]
name = spdk_vbdev_split_get_part_base
[suppress_variable]
name = SPDK_LOG_URING
[suppress_variable]
name = SPDK_LOG_VIRTIO
[suppress_variable]
name = SPDK_LOG_VIRTIO_BLK
[suppress_variable]
name = SPDK_LOG_VBDEV_ZONE_BLOCK
[suppress_function]
name = spdk_vbdev_zone_block_create
[suppress_function]
name = spdk_vbdev_zone_block_delete
[suppress_variable]
name = SPDK_LOG_BLOBFS_BDEV
[suppress_variable]
name = SPDK_LOG_BLOBFS_BDEV_RPC
[suppress_function]
name = spdk_blobfs_fuse_send_request
[suppress_function]
name = spdk_blobfs_fuse_start
[suppress_function]
name = spdk_blobfs_fuse_stop
[suppress_variable]
name = SPDK_LOG_APP_RPC
[suppress_function]
name = spdk_nvmf_parse_conf
[suppress_variable]
name = SPDK_LOG_VHOST
[suppress_variable]
name = SPDK_LOG_VHOST_BLK
[suppress_variable]
name = SPDK_LOG_VHOST_BLK_DATA
[suppress_variable]
name = SPDK_LOG_VHOST_RING
[suppress_variable]
name = SPDK_LOG_VHOST_RPC
[suppress_variable]
name = SPDK_LOG_VHOST_SCSI
[suppress_variable]
name = SPDK_LOG_VHOST_SCSI_DATA
[suppress_variable]
name = SPDK_LOG_VHOST_SCSI_QUEUE
[suppress_variable]
name = spdk_vhost_scsi_device_backend
[suppress_type]
name = spdk_net_impl
lib/bdev: Add spdk_bdev_abort API Add spdk_bdev_abort function as a new public API. This goes all the way down to the bdev driver module and attempts to abort all I/Os which has bio_cb_arg as its callback argument. We can separate when only a single I/O has bio_cb_arg and when multiple I/Os have bio_cb_arg, but unify both by using parent - children I/O relationship. To avoid confusion, return matched_ios by _bdev_abort() and store it into split_outstanding by the caller. Exclude any I/O submitted after this abort command because the same cb_arg may be used by all I/Os and abort may never complete. bdev_io needs to have both bio_cb_arg and bio_to_abort because bio_cb_arg is used to continue abort processing when it is stopped due to the capacity of bdev_io pool, and bio_to_abort is used to pass it to the underlying bdev module at submission. Parent I/O is not submitted directly, and is only used in the generic bdev layer, and parent I/O's bdev_io uses bio_cb_arg. Hence add bio_cb_arg to bdev structure and add bio_to_abort to abort structure. In the meantime of abort operation, target I/Os may be completed. Hence check if the target I/O still exists at completion, and set the completion status to false only if it still exists. Upon completion of this, i.e., this returned zero, the status SPDK_BDEV_IO_STATUS_SUCCESS indicates all I/Os were successfully aborted, or the status SPDK_BDEV_IO_STATUS_FAILED indicates any I/O was failed to abort by any reason. spdk_bdev_abort() does not support aborting abort or reset request due to the complexity for now. Following patches will support I/O split case. Add unit tests together to cover the basic paths. Besides, ABI compatibility check required us to bump up SO version of a few libraries or modules. Bump up SO version of blob bdev module simply because it does not have any out-of-tree consumer, and suppress bumping up SO version of lvol library because the affected struct spdk_lvol is not part of public APIs. Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Change-Id: I515da688503557615d491bf0bfb36322ce37df08 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/2014 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Community-CI: Mellanox Build Bot Community-CI: Broadcom CI Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
2020-06-03 01:11:28 +00:00
[suppress_type]
name = spdk_lvol
EOF
for object in "$libdir"/libspdk_*.so; do
so_file=$(basename $object)
if [ ! -f "$source_abi_dir/$so_file" ]; then
echo "No corresponding object for $so_file in canonical directory. Skipping."
continue
fi
if ! output=$(abidiff "$source_abi_dir/$so_file" "$libdir/$so_file" --leaf-changes-only --suppressions $suppression_file --stat); then
# remove any filtered out variables.
output=${output// [()][^)]*[)]/}
IFS="." read -r _ _ new_so_maj new_so_min < <(readlink "$libdir/$so_file")
IFS="." read -r _ _ old_so_maj old_so_min < <(readlink "$source_abi_dir/$so_file")
found_abi_change=false
so_name_changed=no
if [[ $output == *"ELF SONAME changed"* ]]; then
so_name_changed=yes
fi
changed_leaf_types=0
if [[ $output =~ "leaf types summary: "([0-9]+) ]]; then
changed_leaf_types=${BASH_REMATCH[1]}
fi
removed_functions=0 changed_functions=0 added_functions=0
if [[ $output =~ "functions summary: "([0-9]+)" Removed, "([0-9]+)" Changed, "([0-9]+)" Added" ]]; then
removed_functions=${BASH_REMATCH[1]} changed_functions=${BASH_REMATCH[2]} added_functions=${BASH_REMATCH[3]}
fi
removed_vars=0 changed_vars=0 added_vars=0
if [[ $output =~ "variables summary: "([0-9]+)" Removed, "([0-9]+)" Changed, "([0-9]+)" Added" ]]; then
removed_vars=${BASH_REMATCH[1]} changed_vars=${BASH_REMATCH[2]} added_vars=${BASH_REMATCH[3]}
fi
if ((changed_leaf_types != 0)); then
if ((new_so_maj == old_so_maj)); then
touch $fail_file
echo "Please update the major SO version for $so_file. A header accesible type has been modified since last release."
fi
found_abi_change=true
fi
if ((removed_functions != 0)) || ((removed_vars != 0)); then
if ((new_so_maj == old_so_maj)); then
touch $fail_file
echo "Please update the major SO version for $so_file. API functions or variables have been removed since last release."
fi
found_abi_change=true
fi
if ((changed_functions != 0)) || ((changed_vars != 0)); then
if ((new_so_maj == old_so_maj)); then
touch $fail_file
echo "Please update the major SO version for $so_file. API functions or variables have been changed since last release."
fi
found_abi_change=true
fi
if ((added_functions != 0)) || ((added_vars != 0)); then
if ((new_so_min == old_so_min && new_so_maj == old_so_maj)) && ! $found_abi_change; then
touch $fail_file
echo "Please update the minor SO version for $so_file. API functions or variables have been added since last release."
fi
found_abi_change=true
fi
if [[ $so_name_changed == yes ]]; then
if ! $found_abi_change; then
# Unfortunately, libspdk_idxd made it into 20.04 without an SO suffix. TODO:: remove after 20.07
if [ "$so_file" != "libspdk_idxd.so" ] && [ "$so_file" != "libspdk_accel_idxd.so" ]; then
echo "SO name for $so_file changed without a change to abi. please revert that change."
touch $fail_file
fi
fi
if ((new_so_maj != old_so_maj && new_so_min != 0)); then
echo "SO major version for $so_file was bumped. Please reset the minor version to 0."
touch $fail_file
fi
expected_new_so_min=$((old_so_min + 1))
if ((new_so_min > old_so_min && expected_new_so_min != new_so_min)); then
echo "SO minor version for $so_file was incremented more than once. Please revert minor version to $expected_new_so_min."
touch $fail_file
fi
fi
continue
fi
processed_so=$((processed_so + 1))
done
rm -f $suppression_file
echo "Processed $processed_so objects."
}
# This function is needed to properly evaluate the Make variables into actual dependencies.
function replace_defined_variables() {
local arr=("$@")
local bad_values=()
local good_values=()
local new_values
for dep in "${arr[@]}"; do
if [[ $dep == *'$'* ]]; then
raw_dep=${dep/$\(/}
raw_dep=${raw_dep/\)/ }
bad_values+=("$raw_dep")
else
good_values+=("$dep")
fi
done
for dep in "${bad_values[@]}"; do
dep_def_arr=($(grep -v "#" $libdeps_file | grep "${dep}" | cut -d "=" -f 2 | xargs))
new_values=($(replace_defined_variables "${dep_def_arr[@]}"))
good_values=("${good_values[@]}" "${new_values[@]}")
done
echo ${good_values[*]}
}
function confirm_deps() {
lib=$1
missing_syms=()
dep_names=()
found_symbol_lib=""
#keep the space here to differentiate bdev and bdev_*
lib_shortname=$(basename $lib | sed 's,libspdk_,,g' | sed 's,\.so, ,g')
lib_make_deps=($(grep "DEPDIRS-${lib_shortname}" $libdeps_file | cut -d "=" -f 2 | xargs))
lib_make_deps=($(replace_defined_variables "${lib_make_deps[@]}"))
for ign_dep in "${IGNORED_LIBS[@]}"; do
for i in "${!lib_make_deps[@]}"; do
if [[ ${lib_make_deps[i]} == "$ign_dep" ]]; then
unset 'lib_make_deps[i]'
fi
done
done
symbols=$(readelf -s $lib | grep -E "NOTYPE.*GLOBAL.*UND" | awk '{print $8}' | sort | uniq)
for symbol in $symbols; do
for deplib in $DEP_LIBS; do
if [ "$deplib" == "$lib" ]; then
continue
fi
found_symbol=$(readelf -s $deplib | grep -E "DEFAULT\s+[0-9]+\s$symbol$") || true
if [ "$found_symbol" != "" ]; then
found_symbol_lib=$(basename $deplib | sed 's,libspdk_,,g' | sed 's,\.so,,g')
break
fi
done
if [ "$found_symbol" == "" ]; then
missing_syms+=("$symbol")
else
dep_names+=("$found_symbol_lib")
fi
done
IFS=$'\n'
# Ignore any event_* dependencies. Those are based on the subsystem configuration and not readelf.
lib_make_deps=($(printf "%s\n" "${lib_make_deps[@]}" | sort | grep -v "event_"))
# Ignore the env_dpdk readelf dependency. We don't want people explicitly linking against it.
dep_names=($(printf "%s\n" "${dep_names[@]}" | sort | uniq | grep -v "env_dpdk"))
unset IFS
diff=$(echo "${dep_names[@]}" "${lib_make_deps[@]}" | tr ' ' '\n' | sort | uniq -u)
if [ "$diff" != "" ]; then
touch $fail_file
echo "there was a dependency mismatch in the library $lib_shortname"
echo "The makefile lists: '${lib_make_deps[*]}'"
echo "readelf outputs : '${dep_names[*]}'"
echo "---------------------------------------------------------------------"
fi
}
# By removing the spdk.lib_deps.mk file from spdk.lib.mk, we ensure that we won't
# create any link dependencies. Then we can be sure we get a valid accounting of the
# symbol dependencies we have.
sed -i -e 's,include $(SPDK_ROOT_DIR)/mk/spdk.lib_deps.mk,,g' "$rootdir/mk/spdk.lib.mk"
source ~/autorun-spdk.conf
config_params=$(get_config_params)
if [ "$SPDK_TEST_OCF" -eq 1 ]; then
config_params="$config_params --with-ocf=$rootdir/build/ocf.a"
fi
$MAKE $MAKEFLAGS clean
./configure $config_params --with-shared
$MAKE $MAKEFLAGS
xtrace_disable
fail_file=$output_dir/check_so_deps_fail
rm -f $fail_file
run_test "confirm_abi_deps" confirm_abi_deps
echo "---------------------------------------------------------------------"
# Exclude libspdk_env_dpdk.so from the library list. We don't link against this one so that
# users can define their own environment abstraction. However we do want to still check it
# for dependencies to avoid printing out a bunch of confusing symbols under the missing
# symbols section.
SPDK_LIBS=$(ls -1 $libdir/libspdk_*.so | grep -v libspdk_env_dpdk.so)
DEP_LIBS=$(ls -1 $libdir/libspdk_*.so)
IGNORED_LIBS=()
if grep -q 'CONFIG_VHOST_INTERNAL_LIB?=n' $rootdir/mk/config.mk; then
IGNORED_LIBS+=("rte_vhost")
fi
(
for lib in $SPDK_LIBS; do confirm_deps $lib & done
wait
)
$MAKE $MAKEFLAGS clean
git checkout "$rootdir/mk/spdk.lib.mk"
if [ -f $fail_file ]; then
rm -f $fail_file
echo "shared object test failed"
exit 1
fi
xtrace_restore