diff --git a/tuned/daemon/controller.py b/tuned/daemon/controller.py index ced5c1b5..1eb457ed 100644 --- a/tuned/daemon/controller.py +++ b/tuned/daemon/controller.py @@ -383,18 +383,18 @@ def instance_acquire_devices(self, devices, instance_name, caller = None): 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 @@ def instance_acquire_devices(self, devices, instance_name, caller = None): 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 @@ def instance_create(self, plugin_name, instance_name, options, caller = None): 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 @@ def instance_destroy(self, instance_name, caller = None): 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 @@ def instance_destroy(self, instance_name, caller = None): 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") diff --git a/tuned/plugins/base.py b/tuned/plugins/base.py index b6ac8ddb..f0d8d9ac 100644 --- a/tuned/plugins/base.py +++ b/tuned/plugins/base.py @@ -452,13 +452,13 @@ def _execute_all_non_device_commands(self, instance): 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 @@ -510,24 +510,28 @@ def _get_current_value(self, instance, command, device = None, ignore_missing=Fa 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 + current_value = self._storage_get(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: @@ -588,7 +592,7 @@ def _log_verification_result(self, name, success, new_value, 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: @@ -598,7 +602,7 @@ def _verify_device_command(self, instance, command, device, new_value, ignore_mi 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: @@ -611,24 +615,29 @@ def _cleanup_all_non_device_commands(self, instance): 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: diff --git a/tuned/plugins/hotplug.py b/tuned/plugins/hotplug.py index 71974e98..9195d9ca 100644 --- a/tuned/plugins/hotplug.py +++ b/tuned/plugins/hotplug.py @@ -36,11 +36,11 @@ def _hardware_events_callback(self, event, device): 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 @@ def _add_devices_nocheck(self, instance, device_names): 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 @@ def _remove_devices_nocheck(self, instance, device_names): 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) diff --git a/tuned/plugins/plugin_bootloader.py b/tuned/plugins/plugin_bootloader.py index 2711e116..2dc04016 100644 --- a/tuned/plugins/plugin_bootloader.py +++ b/tuned/plugins/plugin_bootloader.py @@ -535,7 +535,7 @@ def _install_initrd(self, img): 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 @@ -543,7 +543,7 @@ def _grub2_cfg_file(self, enabling, value, verify, ignore_missing, instance): 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 @@ -558,7 +558,7 @@ def _initrd_dst_img(self, enabling, value, verify, ignore_missing, instance): 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 @@ -568,7 +568,7 @@ def _initrd_remove_dir(self, enabling, value, verify, ignore_missing, instance): 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 @@ -583,7 +583,7 @@ def _initrd_add_img(self, enabling, value, verify, ignore_missing, instance): 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 @@ -615,7 +615,7 @@ def _initrd_add_dir(self, enabling, value, verify, ignore_missing, instance): 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: @@ -649,7 +649,7 @@ def _cmdline(self, enabling, value, verify, ignore_missing, instance): 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: diff --git a/tuned/plugins/plugin_disk.py b/tuned/plugins/plugin_disk.py index 497af2f2..c8a64dc1 100644 --- a/tuned/plugins/plugin_disk.py +++ b/tuned/plugins/plugin_disk.py @@ -147,15 +147,15 @@ def _hardware_events_callback(self, event, device): 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 @@ def _get_readahead(self, device, instance, ignore_missing=False): 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( diff --git a/tuned/plugins/plugin_irq.py b/tuned/plugins/plugin_irq.py index 7ffdea5f..ceb8d331 100644 --- a/tuned/plugins/plugin_irq.py +++ b/tuned/plugins/plugin_irq.py @@ -182,18 +182,21 @@ def _set_irq_affinity(self, irq, affinity, restoring): # # "high-level" methods: apply tuning while saving original affinities # - def _apply_irq_affinity(self, irqinfo, affinity, mode): + def _apply_irq_affinity(self, irqinfo, affinity, mode, transfer): """Apply IRQ affinity tuning Args: irqinfo (IrqInfo): IRQ that should be tuned affinity (set): desired affinity """ - original = self._get_irq_affinity(irqinfo.irq) + if transfer: + original = irqinfo.original_affinity + else: + original = self._get_irq_affinity(irqinfo.irq) if mode == "intersect": # intersection of affinity and original, if that is empty fall back to configured affinity affinity = affinity & original or affinity - if irqinfo.unchangeable or affinity == original: + if irqinfo.unchangeable or (not transfer and affinity == original): return res = self._set_irq_affinity(irqinfo.irq, affinity, False) if res == 0: @@ -202,13 +205,13 @@ def _apply_irq_affinity(self, irqinfo, affinity, mode): elif res == -2: irqinfo.unchangeable = True - def _restore_irq_affinity(self, irqinfo): + def _restore_irq_affinity(self, irqinfo, transfer): """Restore IRQ affinity Args: irqinfo (IrqInfo): IRQ that should be restored """ - if irqinfo.unchangeable or irqinfo.original_affinity is None: + if transfer or irqinfo.unchangeable or irqinfo.original_affinity is None: return self._set_irq_affinity(irqinfo.irq, irqinfo.original_affinity, True) irqinfo.original_affinity = None @@ -248,7 +251,7 @@ def _verify_irq_affinity(self, irqinfo, affinity, mode): # 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 +259,8 @@ def _mode(self, enabling, value, verify, ignore_missing, instance): 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): + transfer = transfer_instance is not None irq = "DEFAULT" if device == "DEFAULT" else device[len("irq"):] if irq not in self._irqs: log.error("Unknown device: %s" % device) @@ -267,6 +271,6 @@ def _affinity(self, enabling, value, device, verify, ignore_missing, instance): return self._verify_irq_affinity(irqinfo, affinity, self._mode_val) if enabling: affinity = set(self._cmd.cpulist_unpack(value)) - return self._apply_irq_affinity(irqinfo, affinity, self._mode_val) + return self._apply_irq_affinity(irqinfo, affinity, self._mode_val, transfer) else: - return self._restore_irq_affinity(irqinfo) + return self._restore_irq_affinity(irqinfo, transfer) diff --git a/tuned/plugins/plugin_irqbalance.py b/tuned/plugins/plugin_irqbalance.py index d6275334..f9349da9 100644 --- a/tuned/plugins/plugin_irqbalance.py +++ b/tuned/plugins/plugin_irqbalance.py @@ -100,7 +100,7 @@ def _restore_banned_cpus(self): 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)) diff --git a/tuned/plugins/plugin_mounts.py b/tuned/plugins/plugin_mounts.py index 62c8e2c3..9960c879 100644 --- a/tuned/plugins/plugin_mounts.py +++ b/tuned/plugins/plugin_mounts.py @@ -129,7 +129,7 @@ def _remount_partition(self, partition, options): 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) diff --git a/tuned/plugins/plugin_net.py b/tuned/plugins/plugin_net.py index 6d291b29..4759f569 100644 --- a/tuned/plugins/plugin_net.py +++ b/tuned/plugins/plugin_net.py @@ -203,15 +203,15 @@ def _hardware_events_callback(self, event, device): 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): @@ -778,21 +778,21 @@ def _custom_parameters(self, context, start, value, device, verify, instance): 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) diff --git a/tuned/plugins/plugin_scheduler.py b/tuned/plugins/plugin_scheduler.py index ca0b8ebc..37fce8f8 100644 --- a/tuned/plugins/plugin_scheduler.py +++ b/tuned/plugins/plugin_scheduler.py @@ -1161,7 +1161,7 @@ def _thread_code(self, instance): 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 @@ def _cgroup_ps_blacklist(self, enabling, value, verify, ignore_missing, instance self._cgroup_ps_blacklist_re = "|".join(["(%s)" % v for v in re.split(r"(?