Commit 7a1bd398 authored by Michal Berger's avatar Michal Berger Committed by Tomasz Zawadzki
Browse files

scripts/setup: Interactive mode



Present a "hook" which allows setup.sh to enter interactive mode.
In this mode user can inspect setups.sh's view of the system and
adjust it if needed before falling back to one of the main modes
(config, reset).

Change-Id: Ia945172fc7d50ffebc2da80310411c85b3957a99
Signed-off-by: default avatarMichal Berger <michal.berger@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/18356


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarBen Walker <benwalker@nvidia.com>
Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Community-CI: Mellanox Build Bot
parent 3fc3519e
Loading
Loading
Loading
Loading
+234 −0
Original line number Diff line number Diff line
#!/usr/bin/env bash
#  SPDX-License-Identifier: BSD-3-Clause
#  Copyright (C) 2023 Intel Corporation
#  All rights reserved.
#
set +e

yn() {
	local -A yn=()
	local _yn

	yn["y"]=0 yn["n"]=1

	while read -rp "$* (y|N)> " _yn || true; do
		_yn=${_yn::1} _yn=${_yn,,} _yn=${_yn:-n}
		[[ -n ${yn["$_yn"]} ]] && return "${yn["$_yn"]}"
	done
}

elevate() {
	((UID != 0)) || return 0

	if yn "You ($UID) need to be root to commit any changes. Elevate privileges?"; then
		exec sudo -E "$rootdir/scripts/setup.sh" interactive
	fi
}

stdin() {
	[[ ! -t 0 ]] || return 0

	echo "Requested interactive mode but stdin is not attached to a terminal, bailing" >&2
	return 1
}

main_menu() {
	local type=all answer

	stdin || return 1
	elevate

	while ((1)); do
		cat <<- MENU

			1) List PCI Devices [Currently Listing: "$type"]
			2) Change Devices To List
			3) Mark Device As Blocked (${PCI_BLOCKED:-none})
			4) Mark Device As Allowed (${PCI_ALLOWED:-none})
			5) Override Device In-Use Status
			$([[ $os == Linux ]] && echo "6) Bind Device")

			c) configure
			s) status
			r) reset
			$([[ $os == Linux ]] && echo "hp) hugepages")

			Q) Quit
			U) Update Devices View

		MENU

		read -rp "> " answer || answer=q

		case "${answer,,}" in
			1) pdevices ;;
			2) ctype && pdevices ;;
			3) fdevices 0 ;;
			4) fdevices 1 ;;
			5) odevices ;;
			6) bdevices ;;
			q) yn "Are you sure you want to quit?" && return 1 ;;
			c | commit | config)
				yn "Are you sure you want jump to config mode?" || continue
				mode=config
				return
				;;
			s | status) status ;;
			r | reset)
				yn "Are you sure you want jump to reset mode?" || continue
				mode=reset
				return
				;;
			u | update)
				CMD=reset cache_pci_bus
				collect_devices
				;;
			hp) hugepages ;;
		esac
	done
}

gdevices() {
	if [[ $type == all ]]; then
		local -gn dev_ref=all_devices_d
	else
		local -gn dev_ref=${type}_d
	fi
}

pdevices() {
	gdevices

	local use_map=()
	use_map[0]="not used" use_map[1]="used"

	if ((${#dev_ref[@]} == 0)); then
		echo "No devices found"
	else
		for dev in "${!dev_ref[@]}"; do
			echo "- $dev [${use_map[all_devices_d["$dev"]]}, ${drivers_d["$dev"]:-none}]"
		done
	fi
}

ctype() {
	local type_to_set
	local -n types_ref=types_d

	while read -rp "(${!types_ref[*]} all)> " type_to_set; do
		type_to_set=${type_to_set,,}
		if [[ -z $type_to_set ]]; then
			return
		elif [[ -n ${types_ref["$type_to_set"]} || $type_to_set == all ]]; then
			type=$type_to_set
			return
		fi
	done
}

fdevices() {
	local action=${1:-0} bdf
	local am=()
	local -gA action_0 action_1

	am[0]=PCI_BLOCKED am[1]=PCI_ALLOWED

	gdevices
	local -n action_ref=action_${action}
	local -n action_ref_rev=action_$((!action))

	while read -rp "(${!am[action]:-BDF})> " bdf; do
		bdf=${bdf,,}
		if [[ -z $bdf ]]; then
			return
		elif [[ -n ${dev_ref["$bdf"]} ]]; then
			if [[ -n ${action_ref["$bdf"]} ]]; then
				unset -v "action_ref[$bdf]"
			else
				action_ref["$bdf"]=1
				unset -v "action_ref_rev[$bdf]"
			fi
			eval "${am[action]}='${!action_ref[*]}'"
			eval "${am[!action]}='${!action_ref_rev[*]}'"
		elif [[ -z ${dev_ref["$bdf"]} ]]; then
			unset -v "action_ref[$bdf]"
			eval "${am[action]}='${!action_ref[*]}'"
		fi
	done
}

odevices() {
	local bdf

	type=all gdevices

	while read -rp "(BDF)> " bdf; do
		bdf=${bdf,,}
		if [[ -z $bdf ]]; then
			return
		elif [[ -n ${dev_ref["$bdf"]} ]]; then
			dev_ref["$bdf"]=$((!dev_ref["$bdf"]))
		fi
	done
}

bdevices() {
	[[ $os == Linux ]] || return 0

	local bdfd bdf driver

	gdevices

	while read -rp "(BDF->driver)> " bdfd; do
		bdfd=${bdfd,,}
		if [[ -z $bdfd ]]; then
			return
		fi

		bdf=${bdfd/->*/} driver=${bdfd/*->/}

		if [[ $driver == "${drivers_d["$bdf"]}" ]]; then
			echo "$bdf already bound to $driver"
			continue
		fi

		if [[ -n ${dev_ref["$bdf"]} && -n $driver ]]; then
			if yn "$bdf currently bound to ${drivers_d["$bdf"]:-none}. Bind to $driver?"; then
				linux_bind_driver "$bdf" "$driver"
			fi
		fi
	done
}

status() {
	local _os=${os,,}

	if [[ $(type -t "status_${_os}") == function ]]; then
		"status_${_os}"
	fi
}

hugepages() {
	[[ $os == Linux ]] || return 0
	local hp

	HUGE_EVEN_ALLOC=no
	while read -rp "('clear' 'even' 'commit' HUGEMEM[=$HUGEMEM MB])> " hp; do
		hp=${hp,,}
		if [[ -z $hp ]]; then
			return
		elif [[ $hp == clear ]]; then
			clear_hugepages
			return
		elif [[ $hp == even ]]; then
			HUGE_EVEN_ALLOC=yes
		elif [[ $hp =~ ^[1-9][0-9]*$ ]]; then
			NRHUGE=""
			HUGEMEM=$hp
		elif [[ $hp == commit ]]; then
			set_hp
			configure_linux_hugepages
			return
		fi
	done
}
+27 −12
Original line number Diff line number Diff line
@@ -18,9 +18,9 @@ source "$rootdir/scripts/common.sh"

function usage() {
	if [[ $os == Linux ]]; then
		options="[config|reset|status|cleanup|help]"
		options="[config|reset|status|cleanup|interactive|help]"
	else
		options="[config|reset|help]"
		options="[config|reset|interactive|help]"
	fi

	[[ -n $2 ]] && (
@@ -44,6 +44,7 @@ function usage() {
	if [[ $os == Linux ]]; then
		echo "status            Print status of all SPDK-compatible devices on the system."
	fi
	echo "interactive       Executes script in interactive mode."
	echo "help              Print this help message."
	echo
	echo "The following environment variables can be specified."
@@ -291,13 +292,14 @@ function collect_devices() {
	ids+="|PCI_DEVICE_ID_INTEL_VMD"
	ids+="|SPDK_PCI_CLASS_NVME"

	local -gA nvme_d ioat_d dsa_d iaa_d virtio_d vmd_d all_devices_d drivers_d
	local -gA nvme_d ioat_d dsa_d iaa_d virtio_d vmd_d all_devices_d drivers_d types_d

	while read -r _ dev_type dev_id; do
		bdfs=(${pci_bus_cache["0x8086:$dev_id"]})
		[[ $dev_type == *NVME* ]] && bdfs=(${pci_bus_cache["$dev_id"]})
		[[ $dev_type == *VIRT* ]] && bdfs=(${pci_bus_cache["0x1af4:$dev_id"]})
		[[ $dev_type =~ (NVME|IOAT|DSA|IAA|VIRTIO|VMD) ]] && dev_type=${BASH_REMATCH[1],,}
		types_d["$dev_type"]=1
		for bdf in "${bdfs[@]}"; do
			in_use=0
			if [[ $1 != status ]]; then
@@ -333,6 +335,8 @@ function collect_devices() {
			if [[ -e /sys/bus/pci/devices/$bdf/driver ]]; then
				driver=$(readlink -f "/sys/bus/pci/devices/$bdf/driver")
				drivers_d["$bdf"]=${driver##*/}
			else
				drivers_d["$bdf"]=""
			fi
		done
	done < <(grep -E "$ids" "$rootdir/include/spdk/pci_ids.h")
@@ -815,6 +819,17 @@ function reset_freebsd() {
	kldunload nic_uio.ko || true
}

function set_hp() {
	if [[ -n $HUGEPGSZ && ! -e /sys/kernel/mm/hugepages/hugepages-${HUGEPGSZ}kB ]]; then
		echo "${HUGEPGSZ}kB is not supported by the running kernel, ignoring" >&2
		unset -v HUGEPGSZ
	fi

	HUGEPGSZ=${HUGEPGSZ:-$(grep Hugepagesize /proc/meminfo | cut -d : -f 2 | tr -dc '0-9')}
	HUGEPGSZ_MB=$((HUGEPGSZ / 1024))
	NRHUGE=${NRHUGE:-$(((HUGEMEM + HUGEPGSZ_MB - 1) / HUGEPGSZ_MB))}
}

CMD=reset cache_pci_bus

mode=$1
@@ -844,6 +859,15 @@ fi

collect_devices "$mode"

if [[ $os == Linux ]]; then
	set_hp
fi

if [[ $mode == interactive ]]; then
	source "$rootdir/scripts/common/setup/interactive.sh"
	main_menu || exit 0
fi

if [[ $mode == reset && $PCI_BLOCK_SYNC_ON_RESET == yes ]]; then
	# Note that this will wait only for the first block device attached to
	# a given storage controller. For nvme this may miss some of the devs
@@ -870,15 +894,6 @@ if [[ $mode == reset && $PCI_BLOCK_SYNC_ON_RESET == yes ]]; then
fi

if [[ $os == Linux ]]; then
	if [[ -n $HUGEPGSZ && ! -e /sys/kernel/mm/hugepages/hugepages-${HUGEPGSZ}kB ]]; then
		echo "${HUGEPGSZ}kB is not supported by the running kernel, ignoring" >&2
		unset -v HUGEPGSZ
	fi

	HUGEPGSZ=${HUGEPGSZ:-$(grep Hugepagesize /proc/meminfo | cut -d : -f 2 | tr -dc '0-9')}
	HUGEPGSZ_MB=$((HUGEPGSZ / 1024))
	: ${NRHUGE=$(((HUGEMEM + HUGEPGSZ_MB - 1) / HUGEPGSZ_MB))}

	if [ "$mode" == "config" ]; then
		configure_linux
	elif [ "$mode" == "cleanup" ]; then