1
0
Fork 0

controller: transfer devices between instances

Enable the transfer of devices from one instance to another without
(temporarily) unapplying the tuning.

Signed-off-by: Adriaan Schmidt <adriaan.schmidt@siemens.com>
This commit is contained in:
Adriaan Schmidt 2026-06-08 11:24:48 +02:00
parent 0eb28ac3d8
commit 47f4e78e96
13 changed files with 122 additions and 85 deletions

View file

@ -383,18 +383,18 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
return (False, "Invalid devices")
if not self._cmd.is_valid_name(instance_name):
return (False, "Invalid instance_name")
found = False
plugin = None
for instance_target in self._daemon._unit_manager.instances:
if instance_target.name == instance_name:
log.debug("Found instance '%s'." % instance_target.name)
found = True
plugin = instance_target.plugin
break
if not found:
if plugin is None:
rets = "Instance '%s' not found" % instance_name
log.error(rets)
return (False, rets)
if not isinstance(instance_target.plugin, hotplug.Plugin):
rets = "Plugin '%s' does not support hotplugging or dynamic instances." % instance_target.plugin.name
if not isinstance(plugin, hotplug.Plugin):
rets = "Plugin '%s' does not support hotplugging or dynamic instances." % plugin.name
log.error(rets)
return (False, rets)
devs = set(self._cmd.devstr2devs(devices))
@ -405,14 +405,14 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
devs -= devs_moving
log.info("Moving devices '%s' from instance '%s' to instance '%s'." % (str(devs_moving),
instance.name, instance_target.name))
if (instance.plugin.name != instance_target.plugin.name):
if (instance.plugin.name != plugin.name):
rets = "Target instance '%s' is of type '%s', but devices '%s' are currently handled by " \
"instance '%s' which is of type '%s'." % (instance_target.name,
instance_target.plugin.name, str(devs_moving), instance.name, instance.plugin.name)
plugin.name, str(devs_moving), instance.name, instance.plugin.name)
log.error(rets)
return (False, rets)
instance.plugin._remove_devices_nocheck(instance, devs_moving)
instance_target.plugin._add_devices_nocheck(instance_target, devs_moving)
for dev in devs_moving:
plugin._transfer_device(instance, instance_target, dev)
if (len(devs)):
rets = "Ignoring devices not handled by any instance '%s'." % str(devs)
log.info(rets)
@ -518,17 +518,15 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
plugin.instance_apply_tuning(instance)
# transfer matching devices from other instances, if the priority of the new
# instance is equal or higher (equal or lower priority value)
for other_instance in self._daemon._unit_manager.instances:
if (other_instance == instance or
other_instance.plugin != plugin or
instance.priority > other_instance.priority):
for other_instance in plugin._instances.values():
if (other_instance == instance or instance.priority > other_instance.priority):
continue
devs_moving = plugin._get_matching_devices(instance, other_instance.processed_devices)
if len(devs_moving):
log.info("Moving devices '%s' from instance '%s' to instance '%s'." % (str(devs_moving),
other_instance.name, instance.name))
plugin._remove_devices_nocheck(other_instance, devs_moving)
plugin._add_devices_nocheck(instance, devs_moving)
for dev in devs_moving:
plugin._transfer_device(other_instance, instance, dev)
return (True, "OK")
@exports.export("s", "(bs)")
@ -557,6 +555,17 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
rets = "Plugin '%s' does not support hotplugging or dynamic instances." % plugin.name
log.error(rets)
return (False, rets)
# transfer devices to other instances that want them
for other_instance in plugin._instances.values():
if other_instance == instance:
continue
devs_moving = plugin._get_matching_devices(other_instance, instance.processed_devices)
if len(devs_moving):
log.info("Moving devices '%s' from instance '%s' to instance '%s'." % (str(devs_moving),
instance.name, other_instance.name))
for dev in devs_moving:
plugin._transfer_device(instance, other_instance, dev)
# any devices left?
devices = instance.processed_devices.copy()
try:
plugin._remove_devices_nocheck(instance, devices)
@ -569,6 +578,6 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
return (False, rets)
log.info("Deleted instance '%s'" % instance_name)
for device in devices:
# _add_device() will find a suitable plugin instance
# return the devices not claimed by instances to the plugins's free_devices
plugin._add_device(device)
return (True, "OK")

View file

@ -463,13 +463,13 @@ class Plugin(object):
if new_value is not None:
self._execute_non_device_command(instance, command, new_value)
def _execute_all_device_commands(self, instance, devices):
def _execute_all_device_commands(self, instance, devices, transfer_from_instance=None):
for command in [command for command in list(self._commands.values()) if command["per_device"]]:
new_value = self._variables.expand(instance.options.get(command["name"], None))
if new_value is None:
continue
for device in devices:
self._execute_device_command(instance, command, device, new_value)
self._execute_device_command(instance, command, device, new_value, transfer_from_instance)
def _verify_all_non_device_commands(self, instance, ignore_missing):
ret = True
@ -521,24 +521,30 @@ class Plugin(object):
else:
return command["get"](instance)
def _check_and_save_value(self, instance, command, device = None, new_value = None):
current_value = self._get_current_value(instance, command, device)
def _check_and_save_value(self, instance, command, device = None, new_value = None, transfer_from_instance=None):
if transfer_from_instance is not None and transfer_from_instance.options.get(command["name"], None) is not None:
# we're transfering: base new value calculation on the stored original
# and take over ownership of the stored value from the source instance
current_value = self._storage_get(transfer_from_instance, command, device)
self._storage_unset(transfer_from_instance, command, device)
else:
current_value = self._get_current_value(instance, command, device)
new_value = self._process_assignment_modifiers(new_value, current_value)
if new_value is not None and current_value is not None:
self._storage_set(instance, command, current_value, device)
return new_value
def _execute_device_command(self, instance, command, device, new_value):
def _execute_device_command(self, instance, command, device, new_value, transfer_from_instance=None):
if command["custom"] is not None:
command["custom"](True, new_value, device, False, False, instance)
command["custom"](True, new_value, device, False, False, instance, transfer_from_instance)
else:
new_value = self._check_and_save_value(instance, command, device, new_value)
new_value = self._check_and_save_value(instance, command, device, new_value, transfer_from_instance)
if new_value is not None:
command["set"](new_value, device, instance, sim = False, remove = False)
def _execute_non_device_command(self, instance, command, new_value):
if command["custom"] is not None:
command["custom"](True, new_value, False, False, instance)
command["custom"](True, new_value, False, False, instance, None)
else:
new_value = self._check_and_save_value(instance, command, None, new_value)
if new_value is not None:
@ -599,7 +605,7 @@ class Plugin(object):
def _verify_device_command(self, instance, command, device, new_value, ignore_missing):
if command["custom"] is not None:
return command["custom"](True, new_value, device, True, ignore_missing, instance)
return command["custom"](True, new_value, device, True, ignore_missing, instance, None)
current_value = self._get_current_value(instance, command, device, ignore_missing=ignore_missing)
new_value = self._process_assignment_modifiers(new_value, current_value)
if new_value is None:
@ -609,7 +615,7 @@ class Plugin(object):
def _verify_non_device_command(self, instance, command, new_value, ignore_missing):
if command["custom"] is not None:
return command["custom"](True, new_value, True, ignore_missing, instance)
return command["custom"](True, new_value, True, ignore_missing, instance, None)
current_value = self._get_current_value(instance, command)
new_value = self._process_assignment_modifiers(new_value, current_value)
if new_value is None:
@ -622,24 +628,29 @@ class Plugin(object):
if (instance.options.get(command["name"], None) is not None) or (command["name"] in self._options_used_by_dynamic):
self._cleanup_non_device_command(instance, command)
def _cleanup_all_device_commands(self, instance, devices, remove = False):
def _cleanup_all_device_commands(self, instance, devices, remove = False, transfer_to_instance=None):
for command in reversed([command for command in list(self._commands.values()) if command["per_device"]]):
if transfer_to_instance is not None and transfer_to_instance.options.get(command["name"], None) is not None:
transfer_this_command = transfer_to_instance
else:
transfer_this_command = None
if (instance.options.get(command["name"], None) is not None) or (command["name"] in self._options_used_by_dynamic):
for device in devices:
self._cleanup_device_command(instance, command, device, remove)
self._cleanup_device_command(instance, command, device, remove, transfer_this_command)
def _cleanup_device_command(self, instance, command, device, remove = False):
def _cleanup_device_command(self, instance, command, device, remove = False, transfer_to_instance=None):
if command["custom"] is not None:
command["custom"](False, None, device, False, False, instance)
command["custom"](False, None, device, False, False, instance, transfer_to_instance)
else:
old_value = self._storage_get(instance, command, device)
if old_value is not None:
if old_value is not None and transfer_to_instance is None:
command["set"](old_value, device, instance, sim = False, remove = remove)
self._storage_unset(instance, command, device)
if transfer_to_instance is None:
self._storage_unset(instance, command, device)
def _cleanup_non_device_command(self, instance, command):
if command["custom"] is not None:
command["custom"](False, None, False, False, instance)
command["custom"](False, None, False, False, instance, None)
else:
old_value = self._storage_get(instance, command)
if old_value is not None:

View file

@ -36,11 +36,11 @@ class Plugin(base.Plugin):
log.info("device: '%s', rename event, reported new name" % device.sys_name)
self._move_device(device.sys_name)
def _add_device_process(self, instance, device_name):
def _add_device_process(self, instance, device_name, transfer_from_instance=None):
log.info("instance %s: adding new device %s" % (instance.name, device_name))
self._assigned_devices.add(device_name)
self._call_device_script(instance, instance.script_pre, "apply", [device_name])
self._added_device_apply_tuning(instance, device_name)
self._added_device_apply_tuning(instance, device_name, transfer_from_instance)
self._call_device_script(instance, instance.script_post, "apply", [device_name])
instance.processed_devices.add(device_name)
@ -68,11 +68,14 @@ class Plugin(base.Plugin):
instance.active = len(instance.processed_devices) \
+ len(instance.assigned_devices) > 0
def _remove_device_process(self, instance, device_name):
def _remove_device_process(self, instance, device_name, transfer_to_instance=None):
if device_name in instance.processed_devices:
self._call_device_script(instance, instance.script_post, "unapply", [device_name])
self._removed_device_unapply_tuning(instance, device_name)
self._call_device_script(instance, instance.script_pre, "unapply", [device_name])
if transfer_to_instance is not None:
self._removed_device_unapply_tuning(instance, device_name, transfer_to_instance)
else:
self._call_device_script(instance, instance.script_post, "unapply", [device_name])
self._removed_device_unapply_tuning(instance, device_name, transfer_to_instance)
self._call_device_script(instance, instance.script_pre, "unapply", [device_name])
instance.processed_devices.remove(device_name)
# This can be a bit racy (we can overcount),
# but it shouldn't affect the boolean result
@ -122,12 +125,26 @@ class Plugin(base.Plugin):
for dev in device_names:
self._remove_device_process(instance, dev)
def _added_device_apply_tuning(self, instance, device_name):
self._execute_all_device_commands(instance, [device_name])
def _transfer_device(self, from_instance, to_instance, device_name):
"""Transfer a device between instances
Apply the tuning of the target instance without the intermediate step
of rolling back to the original tuning.
"""
if device_name not in (self._assigned_devices | self._free_devices):
return
if not self._remove_device_process(from_instance, device_name, to_instance):
return
self._add_device_process(to_instance, device_name, transfer_from_instance=from_instance)
def _added_device_apply_tuning(self, instance, device_name, transfer_from_instance):
self._execute_all_device_commands(instance, [device_name], transfer_from_instance)
if instance.has_dynamic_tuning and self._global_cfg.get(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING):
self._instance_apply_dynamic(instance, device_name)
def _removed_device_unapply_tuning(self, instance, device_name):
def _removed_device_unapply_tuning(self, instance, device_name, transfer_to_instance):
if instance.has_dynamic_tuning and self._global_cfg.get(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING):
self._instance_unapply_dynamic(instance, device_name)
self._cleanup_all_device_commands(instance, [device_name], remove = True)
self._cleanup_all_device_commands(instance, [device_name], remove = True, transfer_to_instance=transfer_to_instance)

View file

@ -541,7 +541,7 @@ class BootloaderPlugin(base.Plugin):
return True
@command_custom("grub2_cfg_file")
def _grub2_cfg_file(self, enabling, value, verify, ignore_missing, instance):
def _grub2_cfg_file(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
# nothing to verify
if verify:
return None
@ -549,7 +549,7 @@ class BootloaderPlugin(base.Plugin):
self._grub2_cfg_file_names = [str(value)]
@command_custom("initrd_dst_img")
def _initrd_dst_img(self, enabling, value, verify, ignore_missing, instance):
def _initrd_dst_img(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
# nothing to verify
if verify:
return None
@ -564,7 +564,7 @@ class BootloaderPlugin(base.Plugin):
return None
@command_custom("initrd_remove_dir")
def _initrd_remove_dir(self, enabling, value, verify, ignore_missing, instance):
def _initrd_remove_dir(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
# nothing to verify
if verify:
return None
@ -574,7 +574,7 @@ class BootloaderPlugin(base.Plugin):
return None
@command_custom("initrd_add_img", per_device = False, priority = 10)
def _initrd_add_img(self, enabling, value, verify, ignore_missing, instance):
def _initrd_add_img(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
# nothing to verify
if verify:
return None
@ -589,7 +589,7 @@ class BootloaderPlugin(base.Plugin):
return None
@command_custom("initrd_add_dir", per_device = False, priority = 10)
def _initrd_add_dir(self, enabling, value, verify, ignore_missing, instance):
def _initrd_add_dir(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
# nothing to verify
if verify:
return None
@ -640,7 +640,7 @@ class BootloaderPlugin(base.Plugin):
return None
@command_custom("cmdline", per_device = False, priority = 10)
def _cmdline(self, enabling, value, verify, ignore_missing, instance):
def _cmdline(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
v = self._variables.expand(self._cmd.unquote(value))
if verify:
if self._rpm_ostree:
@ -674,7 +674,7 @@ class BootloaderPlugin(base.Plugin):
return None
@command_custom("skip_grub_config", per_device = False, priority = 10)
def _skip_grub_config(self, enabling, value, verify, ignore_missing, instance):
def _skip_grub_config(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
if verify:
return None
if enabling and value is not None:

View file

@ -147,15 +147,15 @@ class DiskPlugin(hotplug.Plugin):
if self._device_is_supported(device) or event == "remove":
super(DiskPlugin, self)._hardware_events_callback(event, device)
def _added_device_apply_tuning(self, instance, device_name):
def _added_device_apply_tuning(self, instance, device_name, transfer_from_instance):
if instance._load_monitor is not None:
instance._load_monitor.add_device(device_name)
super(DiskPlugin, self)._added_device_apply_tuning(instance, device_name)
super(DiskPlugin, self)._added_device_apply_tuning(instance, device_name, transfer_from_instance)
def _removed_device_unapply_tuning(self, instance, device_name):
def _removed_device_unapply_tuning(self, instance, device_name, transfer_to_instance):
if instance._load_monitor is not None:
instance._load_monitor.remove_device(device_name)
super(DiskPlugin, self)._removed_device_unapply_tuning(instance, device_name)
super(DiskPlugin, self)._removed_device_unapply_tuning(instance, device_name, transfer_to_instance)
@classmethod
def _get_config_options(cls):
@ -450,7 +450,7 @@ class DiskPlugin(hotplug.Plugin):
return int(value)
@command_custom("readahead_multiply", per_device=True)
def _multiply_readahead(self, enabling, multiplier, device, verify, ignore_missing, instance):
def _multiply_readahead(self, enabling, multiplier, device, verify, ignore_missing, instance, transfer_instance):
if verify:
return None
storage_key = self._storage_key(

View file

@ -248,7 +248,7 @@ class IrqPlugin(hotplug.Plugin):
# command definitions: entry to device-specific tuning
#
@command_custom("mode", per_device=False, priority=-10)
def _mode(self, enabling, value, verify, ignore_missing, instance):
def _mode(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
if (enabling or verify) and value is not None:
# Store the operating mode of the current instance in the plugin
# object, from where it is read by the "affinity" command.
@ -256,7 +256,7 @@ class IrqPlugin(hotplug.Plugin):
self._mode_val = value
@command_custom("affinity", per_device=True)
def _affinity(self, enabling, value, device, verify, ignore_missing, instance):
def _affinity(self, enabling, value, device, verify, ignore_missing, instance, transfer_instance):
irq = "DEFAULT" if device == "DEFAULT" else device[len("irq"):]
if irq not in self._irqs:
log.error("Unknown device: %s" % device)

View file

@ -100,7 +100,7 @@ class IrqbalancePlugin(base.Plugin):
self._restart_irqbalance()
@command_custom("banned_cpus", per_device=False)
def _banned_cpus(self, enabling, value, verify, ignore_missing, instance):
def _banned_cpus(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
banned_cpulist_string = None
if value is not None:
banned = set(self._cmd.cpulist_unpack(value))

View file

@ -129,7 +129,7 @@ class MountsPlugin(base.Plugin):
cmd.execute(remount_command)
@command_custom("disable_barriers", per_device=True)
def _disable_barriers(self, start, value, mountpoint, verify, ignore_missing, instance):
def _disable_barriers(self, start, value, mountpoint, verify, ignore_missing, instance, transfer_instance):
storage_key = self._storage_key(
command_name = "disable_barriers",
device_name = mountpoint)

View file

@ -203,15 +203,15 @@ class NetTuningPlugin(hotplug.Plugin):
if self._device_is_supported(device):
super(NetTuningPlugin, self)._hardware_events_callback(event, device)
def _added_device_apply_tuning(self, instance, device_name):
def _added_device_apply_tuning(self, instance, device_name, transfer_from_instance):
if instance._load_monitor is not None:
instance._load_monitor.add_device(device_name)
super(NetTuningPlugin, self)._added_device_apply_tuning(instance, device_name)
super(NetTuningPlugin, self)._added_device_apply_tuning(instance, device_name, transfer_from_instance)
def _removed_device_unapply_tuning(self, instance, device_name):
def _removed_device_unapply_tuning(self, instance, device_name, transfer_to_instance):
if instance._load_monitor is not None:
instance._load_monitor.remove_device(device_name)
super(NetTuningPlugin, self)._removed_device_unapply_tuning(instance, device_name)
super(NetTuningPlugin, self)._removed_device_unapply_tuning(instance, device_name, transfer_to_instance)
# pyudev >= 0.21
def _get_device_property_1(self, pyudev_dev, prop):
@ -776,21 +776,21 @@ class NetTuningPlugin(hotplug.Plugin):
return None
@command_custom("features", per_device = True)
def _features(self, start, value, device, verify, ignore_missing, instance):
def _features(self, start, value, device, verify, ignore_missing, instance, transfer_instance):
return self._custom_parameters("features", start, value, device, verify, instance)
@command_custom("coalesce", per_device = True)
def _coalesce(self, start, value, device, verify, ignore_missing, instance):
def _coalesce(self, start, value, device, verify, ignore_missing, instance, transfer_instance):
return self._custom_parameters("coalesce", start, value, device, verify, instance)
@command_custom("pause", per_device = True)
def _pause(self, start, value, device, verify, ignore_missing, instance):
def _pause(self, start, value, device, verify, ignore_missing, instance, transfer_instance):
return self._custom_parameters("pause", start, value, device, verify, instance)
@command_custom("ring", per_device = True)
def _ring(self, start, value, device, verify, ignore_missing, instance):
def _ring(self, start, value, device, verify, ignore_missing, instance, transfer_instance):
return self._custom_parameters("ring", start, value, device, verify, instance)
@command_custom("channels", per_device = True)
def _channels(self, start, value, device, verify, ignore_missing, instance):
def _channels(self, start, value, device, verify, ignore_missing, instance, transfer_instance):
return self._custom_parameters("channels", start, value, device, verify, instance)

View file

@ -1161,7 +1161,7 @@ class SchedulerPlugin(base.Plugin):
self._remove_pid(instance, int(event.tid))
@command_custom("cgroup_ps_blacklist", per_device = False)
def _cgroup_ps_blacklist(self, enabling, value, verify, ignore_missing, instance):
def _cgroup_ps_blacklist(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
# currently unsupported
if verify:
return None
@ -1169,7 +1169,7 @@ class SchedulerPlugin(base.Plugin):
self._cgroup_ps_blacklist_re = "|".join(["(%s)" % v for v in re.split(r"(?<!\\);", str(value))])
@command_custom("ps_whitelist", per_device = False)
def _ps_whitelist(self, enabling, value, verify, ignore_missing, instance):
def _ps_whitelist(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
# currently unsupported
if verify:
return None
@ -1177,7 +1177,7 @@ class SchedulerPlugin(base.Plugin):
self._ps_whitelist = "|".join(["(%s)" % v for v in re.split(r"(?<!\\);", str(value))])
@command_custom("ps_blacklist", per_device = False)
def _ps_blacklist(self, enabling, value, verify, ignore_missing, instance):
def _ps_blacklist(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
# currently unsupported
if verify:
return None
@ -1185,7 +1185,7 @@ class SchedulerPlugin(base.Plugin):
self._ps_blacklist = "|".join(["(%s)" % v for v in re.split(r"(?<!\\);", str(value))])
@command_custom("kthread_process", per_device = False)
def _kthread_process(self, enabling, value, verify, ignore_missing, instance):
def _kthread_process(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
# currently unsupported
if verify:
return None
@ -1193,7 +1193,7 @@ class SchedulerPlugin(base.Plugin):
self._kthread_process = self._cmd.get_bool(value) == "1"
@command_custom("irq_process", per_device = False)
def _irq_process(self, enabling, value, verify, ignore_missing, instance):
def _irq_process(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
# currently unsupported
if verify:
return None
@ -1201,7 +1201,7 @@ class SchedulerPlugin(base.Plugin):
self._irq_process = self._cmd.get_bool(value) == "1"
@command_custom("default_irq_smp_affinity", per_device = False)
def _default_irq_smp_affinity(self, enabling, value, verify, ignore_missing, instance):
def _default_irq_smp_affinity(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
# currently unsupported
if verify:
return None
@ -1212,7 +1212,7 @@ class SchedulerPlugin(base.Plugin):
self._default_irq_smp_affinity_value = self._cmd.cpulist_unpack(value)
@command_custom("perf_process_fork", per_device = False)
def _perf_process_fork(self, enabling, value, verify, ignore_missing, instance):
def _perf_process_fork(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
# currently unsupported
if verify:
return None
@ -1429,7 +1429,7 @@ class SchedulerPlugin(base.Plugin):
return res
@command_custom("isolated_cores", per_device = False, priority = 10)
def _isolated_cores(self, enabling, value, verify, ignore_missing, instance):
def _isolated_cores(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
affinity = None
self._affinity = None
if value is not None:

View file

@ -61,11 +61,11 @@ class SCSIHostPlugin(hotplug.Plugin):
if self._device_is_supported(device):
super(SCSIHostPlugin, self)._hardware_events_callback(event, device)
def _added_device_apply_tuning(self, instance, device_name):
super(SCSIHostPlugin, self)._added_device_apply_tuning(instance, device_name)
def _added_device_apply_tuning(self, instance, device_name, transfer_from_instance):
super(SCSIHostPlugin, self)._added_device_apply_tuning(instance, device_name, transfer_from_instance)
def _removed_device_unapply_tuning(self, instance, device_name):
super(SCSIHostPlugin, self)._removed_device_unapply_tuning(instance, device_name)
def _removed_device_unapply_tuning(self, instance, device_name, transfer_to_instance):
super(SCSIHostPlugin, self)._removed_device_unapply_tuning(instance, device_name, transfer_to_instance)
@classmethod
def _get_config_options(cls):

View file

@ -120,7 +120,7 @@ class SystemdPlugin(base.Plugin):
return " ".join(str(v) for v in self._cmd.cpulist_unpack(re.sub(r"\s+", r",", re.sub(r",\s+", r",", cpulist))))
@command_custom("cpu_affinity", per_device = False)
def _cmdline(self, enabling, value, verify, ignore_missing, instance):
def _cmdline(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
conf_affinity = None
conf_affinity_unpacked = None
v = self._cmd.unescape(self._variables.expand(self._cmd.unquote(value)))

View file

@ -175,24 +175,24 @@ class VMPlugin(base.Plugin):
return True
@command_custom("dirty_bytes")
def _dirty_bytes(self, enabling, value, verify, ignore_missing, instance):
def _dirty_bytes(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
if value is not None and value.strip().endswith("%"):
return self._dirty_option("dirty_ratio", "dirty_bytes", self._check_ratio, enabling, value.strip().rstrip("%"), verify)
return self._dirty_option("dirty_bytes", "dirty_ratio", self._check_twice_pagesize, enabling, value, verify)
@command_custom("dirty_ratio")
def _dirty_ratio(self, enabling, value, verify, ignore_missing, instance):
def _dirty_ratio(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
log.warning("The 'dirty_ratio' option is deprecated and does not support inheritance, use 'dirty_bytes' with '%' instead.")
return self._dirty_option("dirty_ratio", "dirty_bytes", self._check_ratio, enabling, value, verify)
@command_custom("dirty_background_bytes")
def _dirty_background_bytes(self, enabling, value, verify, ignore_missing, instance):
def _dirty_background_bytes(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
if value is not None and value.strip().endswith("%"):
return self._dirty_option("dirty_background_ratio", "dirty_background_bytes", self._check_ratio, enabling, value.strip().rstrip("%"), verify)
return self._dirty_option("dirty_background_bytes", "dirty_background_ratio", self._check_positive, enabling, value, verify)
@command_custom("dirty_background_ratio")
def _dirty_background_ratio(self, enabling, value, verify, ignore_missing, instance):
def _dirty_background_ratio(self, enabling, value, verify, ignore_missing, instance, transfer_instance):
log.warning("The 'dirty_background_ratio' option is deprecated and does not support inheritance, use 'dirty_background_bytes' with '%' instead.")
return self._dirty_option("dirty_background_ratio", "dirty_background_bytes", self._check_ratio, enabling, value, verify)