From 9eb6be46cdbc75c93f6700ba570e3ad737b26309 Mon Sep 17 00:00:00 2001 From: Harish Date: Fri, 10 Jan 2020 14:18:55 +0530 Subject: [PATCH] ndctl fixes and enhancements ndctl tests has few enhancements which include 1) w.r.t size alignment with namespace counts 2) renaming to suitable method names 3) Remove namespace count and size inputs which might not meet the alignment requirements 4) pylint issues Signed-off-by: Harish --- memory/ndctl.py | 211 +++++++++++++++----------------- memory/ndctl.py.data/ndctl.yaml | 3 - 2 files changed, 102 insertions(+), 112 deletions(-) diff --git a/memory/ndctl.py b/memory/ndctl.py index f45669837..6555786d1 100644 --- a/memory/ndctl.py +++ b/memory/ndctl.py @@ -41,7 +41,7 @@ class NdctlTest(Test): Ndctl user space tooling for Linux, which handles NVDIMM devices. """ - def get_json(self, option=''): + def run_ndctl_list(self, option=''): """ Get the json of each provided options @@ -56,7 +56,7 @@ def get_json(self, option=''): return json_op @staticmethod - def get_json_val(json_op, field): + def run_ndctl_list_val(json_op, field): """ Get the value of a field in given json """ @@ -73,27 +73,20 @@ def get_default_region(self): region = self.params.get('region', default=None) if region: return region - regions = self.get_json('-R') + regions = self.run_ndctl_list('-R') regions = sorted(regions, key=lambda i: i['size'], reverse=True) - return self.get_json_val(regions[0], 'dev') + return self.run_ndctl_list_val(regions[0], 'dev') - def get_aligned_count(self, size): + @staticmethod + def get_size_alignval(): """ - Return count based on default alignemnt + Return the size align restriction based on platform """ if 'Hash' in genio.read_file('/proc/cpuinfo').rstrip('\t\r\n\0'): def_align = 16 * 1024 * 1024 else: def_align = 2 * 1024 * 1024 - if ((size // self.cnt) % def_align) != 0: - self.log.warn("Namespace would fail as it is not %sM " - "aligned! Changing the number of " - "namespaces", def_align // (1024 * 1024)) - for count in range(self.cnt, 1, -1): - if ((size // count) % def_align) == 0: - self.log.info("Changing namespaces to %s", count) - return count - return self.cnt + return def_align def get_slot_count(self, region): """ @@ -107,8 +100,8 @@ def get_slot_count(self, region): except ValueError: json_op = [] first_dict = json_op[0] - index_dict = self.get_json_val(first_dict, 'index')[0] - return self.get_json_val(index_dict, 'nslot') + index_dict = self.run_ndctl_list_val(first_dict, 'index')[0] + return self.run_ndctl_list_val(index_dict, 'nslot') - 1 def build_fio(self): """ @@ -247,19 +240,14 @@ def setUp(self): deps = [] self.dist = distro.detect() self.package = self.params.get('package', default='upstream') - self.cnt = self.params.get('namespace_cnt', default=4) self.preserve_setup = self.params.get('preserve_change', default=False) - self.size = self.params.get('size', default=None) self.mode_to_use = self.params.get('modes', default='fsdax') - self.reflink = '' if self.dist.name not in ['SuSE', 'rhel']: self.cancel('Unsupported OS %s' % self.dist.name) - else: - if self.dist.name == 'rhel': - # DAX wont work with reflink, disabling here - self.reflink = '-m reflink=0' + # DAX wont work with reflink, disabling here + self.reflink = '-m reflink=0' if not self.check_buses(): self.cancel("Test needs atleast one region") @@ -311,8 +299,8 @@ def test_bus_ids(self): """ Test the bus id info """ - vals = self.get_json('-B') - if not len(vals): + vals = self.run_ndctl_list('-B') + if not vals: self.fail('Failed to fetch bus IDs') self.log.info('Available Bus provider IDs: %s', vals) @@ -320,8 +308,8 @@ def test_dimms(self): """ Test the dimms info """ - vals = self.get_json('-D') - if not len(vals): + vals = self.run_ndctl_list('-D') + if not vals: self.fail('Failed to fetch DIMMs') self.log.info('Available DIMMs: %s', vals) @@ -330,9 +318,9 @@ def test_regions(self): Test the regions info """ self.disable_region() - old = self.get_json('-R') + old = self.run_ndctl_list('-R') self.enable_region() - new = self.get_json('-R') + new = self.run_ndctl_list('-R') if len(new) <= len(old): self.fail('Failed to fetch regions') self.log.info('Available regions: %s', new) @@ -342,14 +330,14 @@ def test_namespace(self): Test namespace """ self.enable_region() - regions = self.get_json('-R') + regions = self.run_ndctl_list('-R') for val in regions: - region = self.get_json_val(val, 'dev') + region = self.run_ndctl_list_val(val, 'dev') self.disable_namespace(region=region) self.destroy_namespace(region=region) self.create_namespace(region=region) - namespaces = self.get_json('-N') + namespaces = self.run_ndctl_list('-N') self.log.info('Created namespace %s', namespaces) def test_disable_enable_ns(self): @@ -359,10 +347,10 @@ def test_disable_enable_ns(self): region = self.get_default_region() for _ in range(0, 3): self.create_namespace(region=region, size='128M') - namespaces = self.get_json('-N') + namespaces = self.run_ndctl_list('-N') ns_names = [] for ns in namespaces: - ns_names.append(self.get_json_val(ns, 'dev')) + ns_names.append(self.run_ndctl_list_val(ns, 'dev')) ns_names.append('all') for namespace in ns_names: @@ -380,41 +368,69 @@ def test_namespace_modes(self): self.destroy_namespace(region=region) for mode in self.modes: self.create_namespace(region=region, mode=mode) - ns_json = self.get_json()[0] - created_mode = self.get_json_val(ns_json, 'mode') + ns_json = self.run_ndctl_list()[0] + created_mode = self.run_ndctl_list_val(ns_json, 'mode') if mode != created_mode: failed_modes.append(mode) self.log.error("Expected mode %s, Got %s", mode, created_mode) else: - self.log.info("Namespace with %s mode: %s" % (mode, ns_json)) - ns_name = self.get_json_val(ns_json, 'dev') + self.log.info("Namespace with %s mode: %s", mode, ns_json) + ns_name = self.run_ndctl_list_val(ns_json, 'dev') self.disable_namespace(namespace=ns_name, region=region) self.destroy_namespace(namespace=ns_name, region=region) if failed_modes: self.fail("Namespace for %s mode failed!" % failed_modes) - def test_multiple_namespaces_region(self): + def multiple_namespaces_region(self, region): """ Test multiple namespace with single region """ - region = self.get_default_region() + namespace_size = self.params.get('size', default=None) + size_align = self.get_size_alignval() + slot_count = self.get_slot_count(region) self.log.info("Using %s for muliple namespace regions", region) self.disable_namespace(region=region) self.destroy_namespace(region=region) - self.log.info("Creating %s namespaces", self.cnt) - if not self.size: - self.size = self.get_json_val(self.get_json( - '-r %s' % region)[0], 'size') - ch_cnt = self.get_aligned_count(self.size) - self.size = self.size // ch_cnt + if namespace_size and ((namespace_size % size_align) != 0): + self.cancel("Size value not %d aligned %d \n", + size_align, namespace_size) + + region_size = self.run_ndctl_list_val(self.run_ndctl_list( + '-r %s' % region)[0], 'size') + if not namespace_size: + namespace_size = region_size // slot_count + # Now align the namespace size + namespace_size = (namespace_size // size_align) * size_align else: - # Assuming self.cnt is aligned - ch_cnt = self.cnt - for nid in range(0, ch_cnt): + slot_count = region_size // namespace_size + + self.log.info("Creating %s namespaces", slot_count) + for count in range(0, slot_count): self.create_namespace( - region=region, mode=self.mode_to_use, size=self.size) - self.log.info("Namespace %s created", nid + 1) + region=region, mode=self.mode_to_use, size=namespace_size) + self.log.info("Namespace %s created", count + 1) + + def test_multiple_namespaces_region(self): + """ + Test multiple namespace with single region + """ + region = self.get_default_region() + self.multiple_namespaces_region(region) + + def test_multiple_ns_multiple_region(self): + """ + Test multiple namespace with multiple region + """ + self.enable_region() + if len(self.run_ndctl_list('-R')) <= 1: + self.cancel("Test not applicable without multiple regions") + regions = self.run_ndctl_list('-R') + self.disable_namespace() + self.destroy_namespace() + for val in regions: + region = self.run_ndctl_list_val(val, 'dev') + self.multiple_namespaces_region(region) def test_multiple_ns_modes_region(self): """ @@ -424,7 +440,7 @@ def test_multiple_ns_modes_region(self): self.log.info("Using %s for muliple namespace regions", region) self.disable_namespace(region=region) self.destroy_namespace(region=region) - size = self.get_json_val(self.get_json( + size = self.run_ndctl_list_val(self.run_ndctl_list( '-r %s' % region)[0], 'size') if size < (len(self.modes) * 64 * 1024 * 1024): self.cancel('Not enough memory to create namespaces') @@ -433,52 +449,26 @@ def test_multiple_ns_modes_region(self): region=region, mode=mode, size='64M') self.log.info("Namespace of type %s created", mode) - def test_multiple_ns_multiple_region(self): - """ - Test multiple namespace with multiple region - """ - self.enable_region() - if len(self.get_json('-R')) <= 1: - self.cancel("Test not applicable without multiple regions") - regions = self.get_json('-R') - self.disable_namespace() - self.destroy_namespace() - for val in regions: - ns_size = None - region = self.get_json_val(val, 'dev') - self.log.info("Using %s for muliple namespaces", region) - self.log.info("Creating %s namespaces", self.cnt) - if not self.size: - ns_size = self.get_json_val(self.get_json( - '-r %s' % region)[0], 'size') - ch_cnt = self.get_aligned_count(ns_size) - ns_size = ns_size // ch_cnt - else: - # Assuming size is aligned - ns_size = self.size - ch_cnt = self.cnt - for nid in range(0, ch_cnt): - self.create_namespace( - region=region, mode=self.mode_to_use, size=ns_size) - self.log.info("Namespace %s created", nid + 1) - def test_nslot_namespace(self): """ Test max namespace with nslot value """ region = self.get_default_region() + size_align = self.get_size_alignval() + slot_count = self.get_slot_count(region) self.log.info("Using %s for max namespace creation", region) self.disable_namespace() self.destroy_namespace() - region_size = self.get_json_val(self.get_json( + region_size = self.run_ndctl_list_val(self.run_ndctl_list( '-r %s' % region)[0], 'size') - namespace_size = 1 << 30 - count = region_size // namespace_size - count = min(count, self.get_slot_count(region)) - 1 - self.log.info("Creating %s namespace", count) - for nid in range(1, count + 1): + namespace_size = region_size // slot_count + # Now align the namespace size + namespace_size = (namespace_size // size_align) * size_align + + self.log.info("Creating %s namespace", slot_count) + for count in range(0, slot_count): self.create_namespace(region=region, mode='fsdax', size='1G') - self.log.info("Namespace %s created", nid) + self.log.info("Namespace %s created", count) def test_namespace_reconfigure(self): """ @@ -489,12 +479,12 @@ def test_namespace_reconfigure(self): self.disable_namespace() self.destroy_namespace() self.create_namespace(region=region, mode='fsdax', align='64k') - old_ns = self.get_json()[0] - old_ns_dev = self.get_json_val(old_ns, 'dev') + old_ns = self.run_ndctl_list()[0] + old_ns_dev = self.run_ndctl_list_val(old_ns, 'dev') self.log.info("Re-configuring namespace %s", old_ns_dev) self.create_namespace(region=region, mode='fsdax', name='test_ns', reconfig=old_ns_dev, force=True) - new_ns = self.get_json()[0] + new_ns = self.run_ndctl_list()[0] self.log.info("Checking namespace changes") failed_vals = [] for key, val in new_ns.items(): @@ -515,7 +505,7 @@ def test_check_namespace(self): self.destroy_namespace() self.log.info("Creating sector namespace using %s", region) self.create_namespace(region=region, mode='sector') - ns_sec_dev = self.get_json_val(self.get_json()[0], 'dev') + ns_sec_dev = self.run_ndctl_list_val(self.run_ndctl_list()[0], 'dev') self.disable_namespace(namespace=ns_sec_dev) self.log.info("Checking BTT metadata") if process.system("%s check-namespace %s" % (self.binary, ns_sec_dev), @@ -524,13 +514,13 @@ def test_check_namespace(self): def test_check_numa(self): self.enable_region() - regions = self.get_json('-R') + regions = self.run_ndctl_list('-R') for val in regions: - reg = self.get_json_val(val, 'dev') + reg = self.run_ndctl_list_val(val, 'dev') numa = genio.read_one_line('/sys/devices/ndbus%s/%s/numa_node' % (re.findall(r'\d+', reg)[0], reg)) # Check numa config in ndctl and sys interface - if len(self.get_json('-r %s -U %s' % (reg, numa))) != 1: + if len(self.run_ndctl_list('-r %s -U %s' % (reg, numa))) != 1: self.fail('Region mismatch between ndctl and sys interface') def test_label_read_write(self): @@ -546,7 +536,8 @@ def test_label_read_write(self): self.enable_region(name=region) self.create_namespace(region=region) self.log.info("Storing labels with a namespace") - old_op = process.system_output('%s check-labels %s' % (self.binary, nmem), shell=True) + old_op = process.system_output( + '%s check-labels %s' % (self.binary, nmem), shell=True) if process.system('%s read-labels %s -o output' % (self.binary, nmem), shell=True): self.fail("Label read failed") @@ -563,12 +554,13 @@ def test_label_read_write(self): self.enable_region(name=region) self.log.info("Checking mismatch after restore") - new_op = process.system_output('%s check-labels %s' % (self.binary, nmem), shell=True) + new_op = process.system_output( + '%s check-labels %s' % (self.binary, nmem), shell=True) if new_op != old_op: self.fail("Label read and write mismatch") self.log.info("Checking created namespace after restore") - if len(self.get_json('-r %s' % region)) != 1: + if len(self.run_ndctl_list('-r %s' % region)) != 1: self.fail("Created namespace not found after label restore") def test_daxctl_list(self): @@ -593,9 +585,9 @@ def test_sector_write(self): self.disable_namespace(region=region) self.destroy_namespace(region=region) self.create_namespace(region=region, mode='sector', sector_size='512') - self.disk = '/dev/%s' % self.get_json_val( - self.get_json("-N -r %s" % region)[0], 'blockdev') - size = self.get_json_val(self.get_json( + self.disk = '/dev/%s' % self.run_ndctl_list_val( + self.run_ndctl_list("-N -r %s" % region)[0], 'blockdev') + size = self.run_ndctl_list_val(self.run_ndctl_list( "-N -r %s" % region)[0], 'size') self.part = partition.Partition(self.disk) self.part.mkfs(fstype='xfs', args='-b size=%s -s size=512' % @@ -617,9 +609,9 @@ def test_fsdax_write(self): """ region = self.get_default_region() self.create_namespace(region=region, mode='fsdax') - self.disk = '/dev/%s' % self.get_json_val( - self.get_json("-N -r %s" % region)[0], 'blockdev') - size = self.get_json_val(self.get_json( + self.disk = '/dev/%s' % self.run_ndctl_list_val( + self.run_ndctl_list("-N -r %s" % region)[0], 'blockdev') + size = self.run_ndctl_list_val(self.run_ndctl_list( "-N -r %s" % region)[0], 'size') self.part = partition.Partition(self.disk) self.part.mkfs(fstype='xfs', args='-b size=%s -s size=512 %s' % @@ -641,9 +633,10 @@ def test_devdax_write(self): """ region = self.get_default_region() self.create_namespace(region=region, mode='devdax') - daxdev = "/dev/%s" % self.get_json_val( - self.get_json("-N -r %s" % region)[0], 'chardev') - if process.system("%s -b no -i /dev/urandom -o %s" % (self.get_data("daxio.static"), daxdev), ignore_status=True): + daxdev = "/dev/%s" % self.run_ndctl_list_val( + self.run_ndctl_list("-N -r %s" % region)[0], 'chardev') + if process.system("%s -b no -i /dev/urandom " + "-o %s" % (self.get_data("daxio.static"), daxdev), ignore_status=True): self.fail("DAXIO write on devdax failed") def tearDown(self): @@ -656,7 +649,7 @@ def tearDown(self): self.fail("Failed to delete filesystem on %s" % self.disk) if not self.preserve_setup: - if len(self.get_json('-N')): + if self.run_ndctl_list('-N'): self.destroy_namespace(force=True) self.disable_region() diff --git a/memory/ndctl.py.data/ndctl.yaml b/memory/ndctl.py.data/ndctl.yaml index 1187055d8..521a3b46e 100644 --- a/memory/ndctl.py.data/ndctl.yaml +++ b/memory/ndctl.py.data/ndctl.yaml @@ -1,5 +1,4 @@ config: - namespace_cnt: 4 region: 'region0' preserve_change: True mnt_point: '/mnt/pmem' @@ -12,7 +11,5 @@ config: mode_types: !mux fsdax: modes: 'fsdax' - size: '1G' sector: modes: 'sector' - size: '300M'