scripts/nvmf_perf: add allowlist and blocklist

Use "allowlist" and "blocklist" options in JSON
configuration file to specify which NVMe drives
are OK to use when setting up Target side. If no
list is specified the user can continue with the
test and use all available NVMe drives by passing
"-f" option when running the script.

Previously the default behaviour was to use all
NVMe drives available in the system for test, which
could cause data loss on those drives.

This is a failsafe primarily aimed at KernelTarget
class, as SPDKTarget is already safer to use because
of existing checks in "setup.sh" script which must
be run prior to executing NVMe-oF performance test
script.

Change-Id: I5ff93672a92cb09f2aef8355542ad197d96e14e1
Signed-off-by: Karol Latecki <karol.latecki@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/14854
Reviewed-by: Pawel Piatek <pawelx.piatek@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Karol Latecki 2022-10-04 14:11:56 +02:00 committed by Tomasz Zawadzki
parent 241d9c0a8a
commit f5d6d59482

View File

@ -393,6 +393,8 @@ class Target(Server):
self.pm_delay = 0
self.pm_interval = 0
self.pm_count = 1
self.nvme_allowlist = []
self.nvme_blocklist = []
if "null_block_devices" in target_config:
self.null_block = target_config["null_block_devices"]
@ -415,6 +417,15 @@ class Target(Server):
self.enable_pm, self.pm_delay, self.pm_interval, self.pm_count = target_config["pm_settings"]
# Normalize pm_count - <= 0 means to loop indefinitely so let's avoid that to not block forever
self.pm_count = self.pm_count if self.pm_count > 0 else 1
if "blocklist" in target_config:
self.nvme_blocklist = target_config["blocklist"]
if "allowlist" in target_config:
self.nvme_allowlist = target_config["allowlist"]
# Blocklist takes precedence, remove common elements from allowlist
self.nvme_allowlist = list(set(self.nvme_allowlist) - set(self.nvme_blocklist))
self.log.info("Items now on allowlist: %s" % self.nvme_allowlist)
self.log.info("Items now on blocklist: %s" % self.nvme_blocklist)
self.script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
self.spdk_dir = os.path.abspath(os.path.join(self.script_dir, "../../../"))
@ -872,10 +883,24 @@ class KernelTarget(Target):
def stop(self):
self.nvmet_command(self.nvmet_bin, "clear")
def get_nvme_device_bdf(self, nvme_dev_path):
nvme_name = os.path.basename(nvme_dev_path)
return self.exec_cmd(["cat", "/sys/block/%s/device/address" % nvme_name]).strip()
def get_nvme_devices(self):
output = self.exec_cmd(["lsblk", "-o", "NAME", "-nlpd"])
output = [x for x in output.split("\n") if "nvme" in x]
return output
dev_list = self.exec_cmd(["lsblk", "-o", "NAME", "-nlpd"]).split("\n")
nvme_list = []
for dev in dev_list:
if "nvme" not in dev:
continue
if self.get_nvme_device_bdf(dev) in self.nvme_blocklist:
continue
if len(self.nvme_allowlist) == 0:
nvme_list.append(dev)
continue
if self.get_nvme_device_bdf(dev) in self.nvme_allowlist:
nvme_list.append(dev)
return dev_list
def nvmet_command(self, nvmet_bin, command):
return self.exec_cmd([nvmet_bin, *(command.split(" "))])
@ -995,7 +1020,15 @@ class SPDKTarget(Target):
def get_nvme_devices(self):
bdev_subsys_json_obj = json.loads(self.exec_cmd([os.path.join(self.spdk_dir, "scripts/gen_nvme.sh")]))
bdev_bdfs = [bdev["params"]["traddr"] for bdev in bdev_subsys_json_obj["config"]]
bdev_bdfs = []
for bdev in bdev_subsys_json_obj["config"]:
bdev_traddr = bdev["params"]["traddr"]
if bdev_traddr in self.nvme_blocklist:
continue
if len(self.nvme_allowlist) == 0:
bdev_bdfs.append(bdev_traddr)
if bdev_traddr in self.nvme_allowlist:
bdev_bdfs.append(bdev_traddr)
return bdev_bdfs
@staticmethod
@ -1421,6 +1454,10 @@ if __name__ == "__main__":
help='Results directory.')
parser.add_argument('-s', '--csv-filename', type=str, default='nvmf_results.csv',
help='CSV results filename.')
parser.add_argument('-f', '--force', default=False, action='store_true',
dest='force', help="""Force script to continue and try to use all
available NVMe devices during test.
WARNING: Might result in data loss on used NVMe drives""")
args = parser.parse_args()
@ -1438,6 +1475,16 @@ if __name__ == "__main__":
target_config = data["target"]
initiator_configs = [data[x] for x in data.keys() if "initiator" in x]
if "null_block_devices" not in data["target"] and \
(args.force is False and
"allowlist" not in data["target"] and
"blocklist" not in data["target"]):
# TODO: Also check if allowlist or blocklist are not empty.
logging.warning("""WARNING: This script requires allowlist and blocklist to be defined.
You can choose to use all available NVMe drives on your system, which may potentially
lead to data loss. If you wish to proceed with all attached NVMes, use "-f" option.""")
exit(1)
for k, v in data.items():
if "target" in k:
v.update({"results_dir": args.results})