def run_once(self): if os.geteuid() != 0: raise error.TestNAError('This test needs to be run under root') for path in [self._CGPT_PATH, self._ROOTDEV_PATH]: if not os.path.isfile(path): raise error.TestNAError('%s not found' % path) root_device = site_utils.get_root_device() if not root_device: raise error.TestNAError('Could not find the root device') logging.debug('Root device: %s' % root_device) root_partitions = self.get_root_partitions(root_device) if not root_partitions: raise error.TestNAError('Could not find any root partition') logging.debug('Root partitions: %s' % ', '.join(root_partitions)) processes = self.get_process_list([self._UPDATE_ENGINE_PATH]) if not processes: raise error.TestNAError('Could not find any process') logging.debug('Active processes: %s' % ', '.join(processes)) for process in processes: process_exe = self.get_process_executable(process) mounts_file = '/proc/%s/mounts' % process mounted_devices = self.get_mounted_devices(mounts_file) for partition in root_partitions: if partition in mounted_devices: raise error.TestFail( 'Root partition "%s" is mounted by process %s (%s)' % (partition, process, process_exe))
def run_once(self, check_link_speed=()): # Use rootdev to find the underlying block device even if the # system booted to /dev/dm-0. device = site_utils.get_root_device() # Check the device is fixed def IsFixed(dev): sysfs_path = '/sys/block/%s/removable' % dev return (os.path.exists(sysfs_path) and open(sysfs_path).read().strip() == '0') alpha_re = re.compile(r'^/dev/([a-zA-Z]+)$') alnum_re = re.compile(r'^/dev/([a-zA-Z]+[0-9]+)$') dev = alpha_re.findall(device) + alnum_re.findall(device) if len(dev) != 1 or not IsFixed(dev[0]): raise error.TestFail('The main disk %s is not fixed' % dev) # If it is an mmcblk device, then it is SSD. # Else run hdparm to check for SSD. if re.search("mmcblk", device): return hdparm = utils.run('/sbin/hdparm -I %s' % device) # Check if device is a SSD match = re.search(r'Nominal Media Rotation Rate: (.+)$', hdparm.stdout, re.MULTILINE) if match and match.group(1): if match.group(1) != 'Solid State Device': if utils.get_board() in self.boards_with_hdd: return raise error.TestFail('The main disk is not a SSD, ' 'Rotation Rate: %s' % match.group(1)) else: raise error.TestFail('Rotation Rate not reported from the device, ' 'unable to ensure it is a SSD') # Check if SSD is > 8GB in size match = re.search("device size with M = 1000\*1000: (.+) MBytes", hdparm.stdout, re.MULTILINE) if match and match.group(1): size = int(match.group(1)) self.write_perf_keyval({"mb_ssd_device_size": size}) else: raise error.TestFail('Device size info missing from the device') # Check supported link speed. # # check_link_speed is an empty tuple by default, which does not perform # link speed checking. You can run the test while specifying # check_link_speed=('1.5Gb/s', '3.0Gb/s') to check the 2 signaling # speeds are both supported. for link_speed in check_link_speed: if not re.search(r'Gen. signaling speed \(%s\)' % link_speed, hdparm.stdout, re.MULTILINE): raise error.TestFail('Link speed %s not supported' % link_speed)
def run_once(self, dev='/dev/sda'): """ Measure write performance before and after trim. This test use an entire disk so we need to boot from usb. @param dev: block device to test """ logging.info('Target device: %s', dev) # Check that device exist. if not os.path.exists(dev): msg = 'Test failed with error: %s not exist' % dev raise error.TestFail(msg) # Check that device is not rootdev. rootdev = site_utils.get_root_device() if dev == rootdev: raise error.TestFail('Can not test on root device') # Use fio to fill device first. self.job.run_test('hardware_StorageFio', disable_sysinfo=True, dev=dev, filesize=0, requirements=[('disk_fill', [])], tag='disk_fill') # Use 4k random write with queue depth = 32 because manufacture usually # uses this use case in the SSD specification. # Also, print result every minute to look at the performance drop trend # over time. Result reported by autotest will be the last minute one. requirements = [('4k_write_qd32', ['--status-interval=60'])] # Check write performance self.job.run_test('hardware_StorageFio', disable_sysinfo=True, dev=dev, filesize=0, requirements=requirements, tag='before_trim') # Unmount drive to make it possible to format. utils.run('umount %s*' % dev, ignore_status=True) # Format whole drive to ext4. Mkfs will trim the drive before format. utils.run('mkfs.ext4 -F %s' % dev, ignore_status=True) # Check write performance self.job.run_test('hardware_StorageFio', disable_sysinfo=True, dev=dev, filesize=0, requirements=requirements, tag='after_trim')
def run_once(self, iters=1, tmout=60 * 60): """ Executes test. @param iters: Number of times to run badblocks. @param tmout: Time allowed badblocks to run before killing it. (Default time is 60 minutes.) """ # Log starting message. logging.info('Statring hardware_Badblocks Test.') logging.info('Iterations: %d', iters) logging.info('badblocks Timeout (sec): %d', tmout) # Determine which device and partition to use. logging.info('Determine unused root partition to test on:') dev = site_utils.get_free_root_partition() logging.info('Testing on ' + dev) # Get block device's sector size. logging.info('Determine block device sector size:') sector_size = self._get_sector_size(site_utils.get_root_device()) logging.info('Sector size (bytes): ' + sector_size) # Get partition size. logging.info('Determine partition size:') part_size = utils.get_disk_size(dev) logging.info('Partition size (bytes): %s', part_size) # Run badblocks. for i in range(iters): logging.info('Starting iteration %d', i) self._run_badblocks(dev, sector_size, tmout) # Report statistics. logging.info('Total pass: %d', self._pass_count) logging.info('Total fail: %d', self._fail_count) stats = {} stats['ea_badblocks_runs'] = iters stats['ea_passed_count'] = self._pass_count stats['ea_failed_count'] = self._fail_count stats['sec_longest_run'] = self._longest_runtime # TODO: change write_perf_keyval() to output_perf_value() as soon as # autotest is ready for it. self.write_perf_keyval(stats) # Report test pass/fail. if self._pass_count != iters: raise error.TestFail('One or more runs found bad blocks on' ' storage device.')
def initialize(self, dev='', filesize=DEFAULT_FILE_SIZE): """ Set up local variables. @param dev: block device / file to test. Spare partition on root device by default @param filesize: size of the file. 0 means whole partition. by default, 1GB. """ if dev != '' and (os.path.isfile(dev) or not os.path.exists(dev)): if filesize == 0: raise error.TestError( 'Nonzero file size is required to test file systems') self.__filename = dev self.__filesize = filesize self.__description = '' return if not dev: dev = site_utils.get_fixed_dst_drive() if dev == site_utils.get_root_device(): if filesize == 0: raise error.TestError( 'Using the root device as a whole is not allowed') else: self.__filename = site_utils.get_free_root_partition() elif filesize != 0: # Use the first partition of the external drive if dev[5:7] == 'sd': self.__filename = dev + '1' else: self.__filename = dev + 'p1' else: self.__filename = dev self.__get_disk_size() self.__get_device_description() # Restrict test to use a given file size, default 1GiB if filesize != 0: self.__filesize = min(self.__filesize, filesize) self.__verify_only = False logging.info('filename: %s', self.__filename) logging.info('filesize: %d', self.__filesize)
def run_once(self): root_dev = site_utils.get_root_device() self._device = os.path.basename(root_dev) disk_size = utils.get_disk_size(root_dev) if not disk_size: raise error.TestError('Unable to determine main disk size') # Capacity of a hard disk is quoted with SI prefixes, incrementing by # powers of 1000, instead of powers of 1024. gb = float(disk_size) / (10 ** 9) self.write_perf_keyval({"gb_main_disk_size": gb}) min_gb = self._compute_min_gb() logging.info("DiskSize: %.3f GB MinDiskSize: %.3f GB", gb, min_gb) if (gb < min_gb): raise error.TestError("DiskSize %.3f GB below minimum (%.3f GB)" \ % (gb, min_gb))
def run_once(self, dev='', quicktest=False, requirements=None, integrity=False, wait=60 * 60 * 72): """ Runs several fio jobs and reports results. @param dev: block device to test @param quicktest: short test @param requirements: list of jobs for fio to run @param integrity: test to check data integrity @param wait: seconds to wait between a write and subsequent verify """ if requirements is not None: pass elif quicktest: requirements = [('1m_write', []), ('16k_read', [])] elif integrity: requirements = [('8k_async_randwrite', []), ('8k_async_randwrite', [self.VERIFY_OPTION])] elif dev in ['', site_utils.get_root_device()]: requirements = [ ('surfing', []), ('boot', []), ('login', []), ('seq_read', []), ('seq_write', []), ('16k_read', []), ('16k_write', []), ('1m_stress', []), ] else: # TODO(waihong@): Add more test cases for external storage requirements = [ ('seq_read', []), ('seq_write', []), ('16k_read', []), ('16k_write', []), ('1m_stress', []), ] results = {} for job, options in requirements: # Keys are labeled according to the test case name, which is # unique per run, so they cannot clash if self.VERIFY_OPTION in options: time.sleep(wait) self.__verify_only = True else: self.__verify_only = False env_vars = ' '.join([ 'FILENAME=' + self.__filename, 'FILESIZE=' + str(self.__filesize), 'VERIFY_ONLY=' + str(int(self.__verify_only)) ]) job_file = os.path.join(self.bindir, job) results.update(fio_util.fio_runner(self, job_file, env_vars)) # Output keys relevant to the performance, larger filesize will run # slower, and sda5 should be slightly slower than sda3 on a rotational # disk self.write_test_keyval({ 'filesize': self.__filesize, 'filename': self.__filename, 'device': self.__description }) logging.info('Device Description: %s', self.__description) self.write_perf_keyval(results) for k, v in results.iteritems(): if k.endswith('_error'): self._fail_count += int(v) if self._fail_count > 0: raise error.TestFail('%s failed verifications' % str(self._fail_count))
def run_once(self, iteration=1, dev=''): """ Read S.M.A.R.T attribute from target device @param dev: target device """ if dev == '': logging.info('Run rootdev to determine boot device') dev = site_utils.get_root_device() logging.info(str('dev: %s' % dev)) # Skip this test if dev is an eMMC device without raising an error if re.match('.*mmc.*', dev): logging.info('Target device is an eMMC device. Skip testing') self.write_perf_keyval({'device_model': 'eMMC'}) return last_result = '' # run multiple time to test the firmware part that retrieve SMART value for loop in range(1, iteration + 1): cmd = 'smartctl -a -f brief %s' % dev result = utils.run(cmd, ignore_status=True) exit_status = result.exit_status result_text = result.stdout result_lines = result_text.split('\n') # log all line if line count is different # otherwise log only changed line if result_text != last_result: logging.info(str('Iteration #%d' % loop)) last_result_lines = last_result.split('\n') if len(last_result_lines) != len(result_lines): for line in result_lines: logging.info(line) else: for i, line in enumerate(result_lines): if line != last_result_lines[i]: logging.info(line) last_result = result_text # Ignore error other than first two bits if exit_status & 0x3: # Error message should be in 4th line of the output msg = 'Test failed with error: %s' % result_lines[3] raise error.TestFail(msg) logging.info(str('smartctl exit status: 0x%x' % exit_status)) # find drive model lookup_table = {} pattern = re.compile(self._SMARTCTL_DEVICE_MODEL_PATTERN) for line in result_lines: if pattern.match(line): model = pattern.match(line).group('model') for known_model in self._SMARTCTL_LOOKUP_TABLE: if model.startswith(known_model): lookup_table = self._SMARTCTL_LOOKUP_TABLE[known_model] break break else: raise error.TestFail('Can not find drive model') # Example of smart ctl result # ID# ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE # 12 Power_Cycle_Count -O---- 100 100 000 - 204 # use flag field to find a valid line pattern = re.compile(self._SMARTCTL_RESULT_PATTERN) keyval = {} fail = [] for line in result_lines: if not pattern.match(line): continue field = line.split() id = int(field[0]) if id in lookup_table: # look up table overwrite smartctl name key = lookup_table[id] else: key = field[1] # ATTRIBUTE_NAME if key == 'Unknown_Attribute': key = "Smart_Attribute_ID_%d" % id keyval[key] = field[7] # RAW_VALUE # check for failing attribute if field[6] != '-': fail += [key] if len(keyval) == 0: raise error.TestFail( 'Test failed with error: Can not parse smartctl keyval') if len(fail) > 0: keyval['fail'] = fail keyval['exit_status'] = exit_status keyval['device_model'] = model self.write_perf_keyval(keyval)