def test_sysfs_path_raise_strict_nopath(self, m_sysb_path, m_path_exists): """ sysfs_path raises OSError on strict=True and missing path. """ kname = self.random_string() m_sysb_path.return_value = '/sys/class/block/%s' % kname m_path_exists.return_value = False with self.assertRaises(OSError): bcache.sysfs_path(kname)
def test_sysfs_path_non_strict(self, m_sysb_path, m_path_exists): """ sysfs_path returns path if missing and strict=False.""" kname = self.random_string() m_sysb_path.return_value = '/sys/class/block/%s' % kname m_path_exists.return_value = False self.assertEqual('/sys/class/block/%s/bcache' % kname, bcache.sysfs_path(kname, strict=False))
def test_sysfs_path(self, m_sysb_path, m_path_exists): """ sysfs_path returns /sys/class/block/<device>/bcache for device.""" kname = self.random_string() m_sysb_path.return_value = '/sys/class/block/%s' % kname m_path_exists.return_value = True self.assertEqual('/sys/class/block/%s/bcache' % kname, bcache.sysfs_path(kname))
def shutdown_bcache(device): """ Shut down bcache for specified bcache device 1. wipe the bcache device contents 2. extract the cacheset uuid (if cached) 3. extract the backing device 4. stop cacheset (if present) 5. stop the bcacheN device 6. wait for removal of sysfs path to bcacheN, bcacheN/bcache and backing/bcache to go away """ if not device.startswith('/sys/class/block'): raise ValueError( 'Invalid Device (%s): ' 'Device path must start with /sys/class/block/', device) # bcache device removal should be fast but in an extreme # case, might require the cache device to flush large # amounts of data to a backing device. The strategy here # is to wait for approximately 30 seconds but to check # frequently since curtin cannot proceed until devices # cleared. bcache_shutdown_message = ('shutdown_bcache running on {} has determined ' 'that the device has already been shut down ' 'during handling of another bcache dev. ' 'skipping'.format(device)) if not os.path.exists(device): LOG.info(bcache_shutdown_message) return LOG.info('Wiping superblock on bcache device: %s', device) _wipe_superblock(block.sysfs_to_devpath(device), exclusive=False) # collect required information before stopping bcache device # UUID from /sys/fs/cache/UUID cset_uuid = bcache.get_attached_cacheset(device) # /sys/class/block/vdX which is a backing dev of device (bcacheN) backing_sysfs = bcache.get_backing_device(block.path_to_kname(device)) # /sys/class/block/bcacheN/bache bcache_sysfs = bcache.sysfs_path(device, strict=False) # stop cacheset if one is presennt if cset_uuid: LOG.info('%s was attached to cacheset %s, stopping cacheset', device, cset_uuid) bcache.stop_cacheset(cset_uuid) # let kernel settle before the next remove udev.udevadm_settle() LOG.info('bcache cacheset stopped: %s', cset_uuid) # test and log whether the device paths are still present to_check = [bcache_sysfs, backing_sysfs] found_devs = [os.path.exists(p) for p in to_check] LOG.debug('os.path.exists on blockdevs:\n%s', list(zip(to_check, found_devs))) if not any(found_devs): LOG.info('bcache backing device already removed: %s (%s)', bcache_sysfs, device) LOG.debug('bcache backing device checked: %s', backing_sysfs) else: LOG.info('stopping bcache backing device at: %s', bcache_sysfs) bcache.stop_device(bcache_sysfs) return