-
Notifications
You must be signed in to change notification settings - Fork 662
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
nvme-copy: support cross-namespace copy
Add support for NVMe TP4130 ("Cross-Namespace Copy") - Add Copy Descriptor Formats 2h and 3h - Add "--snsids" option to specify source namespaces to copy from - Add "--sopts" option to specify source options (Fast Copy Only) - Print new Host Behavior Support bits, new ONCS bits, and new Optional Copy Formats Supported bits - Extend unit test case to test cross-namespace copy formats
- Loading branch information
Showing
6 changed files
with
195 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,56 +4,124 @@ | |
# | ||
# Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved. | ||
# | ||
# Author: Arunpandian J <[email protected]> | ||
# Authors: Arunpandian J <[email protected]> | ||
# Joy Gu <[email protected]> | ||
|
||
""" | ||
NVMe Copy Testcase:- | ||
1. Issue copy command on set of block; shall pass. | ||
2. If cross-namespace copy formats are supported, enable and test | ||
cross-namespace copy formats. | ||
""" | ||
|
||
import subprocess | ||
|
||
from nvme_test import TestNVMe | ||
|
||
|
||
class TestNVMeCopy(TestNVMe): | ||
|
||
""" | ||
Represents NVMe Verify testcase. | ||
Represents NVMe Copy testcase. | ||
- Attributes: | ||
- start_block : starting block of to verify operation. | ||
- range : Range of blocks for DSM operation. | ||
- slbs : 64-bit addr of first block per range | ||
- ocfs : optional copy formats supported | ||
- host_behavior_data : host behavior support data to restore during teardown | ||
- test_log_dir : directory for logs, temp files. | ||
""" | ||
|
||
def setUp(self): | ||
""" Pre Section for TestNVMeCopy """ | ||
super().setUp() | ||
self.start_block = 0 | ||
self.range = 1 | ||
self.slbs = 1 | ||
self.namespace = 1 | ||
print("\nSetting up test...") | ||
self.ocfs = self.get_ocfs() | ||
cross_namespace_copy = self.ocfs & 0xc | ||
if cross_namespace_copy: | ||
# get host behavior support data | ||
get_features_cmd = "nvme get-feature " + self.ctrl + \ | ||
" --feature-id=0x16 -l 512 -b" | ||
print("Running command:", get_features_cmd) | ||
proc = subprocess.Popen(get_features_cmd, | ||
shell=True, | ||
stdout=subprocess.PIPE) | ||
self.host_behavior_data = proc.stdout.read() | ||
# enable cross-namespace copy formats | ||
data = list(self.host_behavior_data) | ||
if data[4] & cross_namespace_copy == cross_namespace_copy: | ||
# skip if already enabled | ||
print("Cross-namespace copy already enabled, skipping set-features") | ||
self.host_behavior_data = None | ||
else: | ||
data[4] = cross_namespace_copy | ||
data = bytes(data) | ||
set_features_cmd = "nvme set-feature " + self.ctrl + \ | ||
" --feature-id=0x16 -l 512" | ||
print("Running command:", set_features_cmd) | ||
proc = subprocess.Popen(set_features_cmd, | ||
shell=True, | ||
stdout=subprocess.PIPE, | ||
stdin=subprocess.PIPE) | ||
proc.communicate(input=data) | ||
get_ns_id_cmd = f"nvme get-ns-id {self.ns1}" | ||
print("Running command:", get_ns_id_cmd) | ||
proc = subprocess.Popen(get_ns_id_cmd, shell=True, stdout=subprocess.PIPE) | ||
self.ns1_nsid = int(proc.stdout.read().decode().strip().split(':')[-1]) | ||
self.setup_log_dir(self.__class__.__name__) | ||
|
||
def tearDown(self): | ||
""" Post Section for TestNVMeCopy """ | ||
print("Tearing down test...") | ||
if self.host_behavior_data: | ||
# restore saved host behavior support data | ||
set_features_cmd = "nvme set-feature " + self.ctrl + \ | ||
" --feature-id=0x16 -l 512" | ||
print("Running command:", set_features_cmd) | ||
proc = subprocess.Popen(set_features_cmd, | ||
shell=True, | ||
stdout=subprocess.PIPE, | ||
stdin=subprocess.PIPE) | ||
proc.communicate(input=self.host_behavior_data) | ||
super().tearDown() | ||
|
||
def copy(self): | ||
def copy(self, sdlba, blocks, slbs, **kwargs): | ||
""" Wrapper for nvme copy | ||
- Args: | ||
- None | ||
- sdlba : destination logical block address | ||
- blocks : number of logical blocks (0-based) | ||
- slbs : source range logical block address | ||
- descriptor_format : copy descriptor format (optional) | ||
- snsids : source namespace id (optional) | ||
- sopts : source options (optional) | ||
- Returns: | ||
- return code for nvme copy command. | ||
- None | ||
""" | ||
copy_cmd = "nvme copy " + self.ctrl + \ | ||
" --namespace-id=" + str(self.namespace) + \ | ||
" --sdlba=" + str(self.start_block) + \ | ||
" --blocks=" + str(self.range) + \ | ||
" --slbs=" + str(self.range) | ||
return self.exec_cmd(copy_cmd) | ||
# skip if descriptor format not supported (default format is 0) | ||
desc_format = kwargs.get("descriptor_format", 0) | ||
if not self.ocfs & (1 << desc_format): | ||
print(f"Skip copy because descriptor format {desc_format} is not supported") | ||
return | ||
# build copy command | ||
copy_cmd = "nvme copy " + self.ns1 + \ | ||
" --sdlba=" + str(sdlba) + \ | ||
" --blocks=" + str(blocks) + \ | ||
" --slbs=" + str(slbs) | ||
if kwargs.get("descriptor_format") is not None: | ||
copy_cmd += " --format=" + str(kwargs.get("descriptor_format")) | ||
if kwargs.get("snsids") is not None: | ||
copy_cmd += " --snsids=" + str(kwargs.get("snsids")) | ||
if kwargs.get("sopts") is not None: | ||
copy_cmd += " --sopts=" + str(kwargs.get("sopts")) | ||
# run and assert success | ||
print("Running command:", copy_cmd) | ||
self.assertEqual(self.exec_cmd(copy_cmd), 0) | ||
|
||
def test_copy(self): | ||
""" Testcase main """ | ||
self.assertEqual(self.copy(), 0) | ||
print("Running test...") | ||
self.copy(0, 1, 2, descriptor_format=0) | ||
self.copy(0, 1, 2, descriptor_format=1) | ||
self.copy(0, 1, 2, descriptor_format=2, snsids=self.ns1_nsid) | ||
self.copy(0, 1, 2, descriptor_format=2, snsids=self.ns1_nsid, sopts=0) | ||
self.copy(0, 1, 2, descriptor_format=3, snsids=self.ns1_nsid) | ||
self.copy(0, 1, 2, descriptor_format=3, snsids=self.ns1_nsid, sopts=0) |
Oops, something went wrong.