diff --git a/cinder/exception.py b/cinder/exception.py index 6e39ae15ed2..14119f3cb75 100644 --- a/cinder/exception.py +++ b/cinder/exception.py @@ -1154,6 +1154,10 @@ class ISCSITargetDetachFailed(CinderException): message = _("Failed to detach iSCSI target for volume %(volume_id)s.") +class TargetUpdateFailed(CinderException): + message = _("Failed to update target for volume %(volume_id)s.") + + class ISCSITargetHelperCommandFailed(CinderException): message = "%(error_message)s" diff --git a/cinder/volume/drivers/lvm.py b/cinder/volume/drivers/lvm.py index a4e732a334f..06631acddae 100644 --- a/cinder/volume/drivers/lvm.py +++ b/cinder/volume/drivers/lvm.py @@ -589,6 +589,11 @@ class LVMVolumeDriver(driver.VolumeDriver): """Extend an existing volume's size.""" self.vg.extend_volume(volume['name'], self._sizestr(new_size)) + try: + self.target_driver.extend_target(volume) + except Exception: + LOG.exception('Error extending target after volume resize.') + raise exception.TargetUpdateFailed(volume_id=volume.id) def manage_existing(self, volume, existing_ref): """Manages an existing LV. diff --git a/cinder/volume/manager.py b/cinder/volume/manager.py index c86eb6d8dcd..1b897f5cd4a 100644 --- a/cinder/volume/manager.py +++ b/cinder/volume/manager.py @@ -2591,6 +2591,9 @@ class VolumeManager(manager.CleanableManager, self._notify_about_volume_usage(context, volume, "resize.start") try: self.driver.extend_volume(volume, new_size) + except exception.TargetUpdateFailed: + # We just want to log this but continue on with quota commit + LOG.warning('Volume extended but failed to update target.') except Exception: LOG.exception("Extend volume failed.", resource=volume) diff --git a/cinder/volume/targets/iscsi.py b/cinder/volume/targets/iscsi.py index 7488797c41c..15a228d92eb 100644 --- a/cinder/volume/targets/iscsi.py +++ b/cinder/volume/targets/iscsi.py @@ -327,6 +327,17 @@ class ISCSITarget(driver.Target): except exception.NotFound: LOG.debug('Failed to get CHAP auth from DB for %s.', volume['id']) + def extend_target(self, volume): + """Reinitializes a target after the LV has been extended. + + Note: This will cause IO disruption in most cases. + """ + iscsi_name = "%s%s" % (self.configuration.target_prefix, + volume['name']) + + if volume.volume_attachment: + self._do_tgt_update(iscsi_name, force=True) + @abc.abstractmethod def _get_target_and_lun(self, context, volume): """Get iscsi target and lun.""" @@ -349,6 +360,9 @@ class ISCSITarget(driver.Target): def _get_target(self, iqn): pass + def _do_tgt_update(self, name, force=False): + pass + class SanISCSITarget(ISCSITarget): """iSCSI target for san devices. diff --git a/cinder/volume/targets/tgt.py b/cinder/volume/targets/tgt.py index b54a7a83c55..3945e883d42 100644 --- a/cinder/volume/targets/tgt.py +++ b/cinder/volume/targets/tgt.py @@ -111,9 +111,13 @@ class TgtAdm(iscsi.ISCSITarget): return iscsi_target, lun @utils.retry(putils.ProcessExecutionError) - def _do_tgt_update(self, name): - (out, err) = utils.execute('tgt-admin', '--update', name, - run_as_root=True) + def _do_tgt_update(self, name, force=False): + args = ['tgt-admin', '--update', name] + if force: + # Note: force may fail if there is active IO, but retry decorator + # should allow it to succeed on second attempt + args.append('-f') + (out, err) = utils.execute(*args, run_as_root=True) LOG.debug("StdOut from tgt-admin --update: %s", out) LOG.debug("StdErr from tgt-admin --update: %s", err)