312 lines
12 KiB
Diff
312 lines
12 KiB
Diff
From 91cb383ad7339873da3480463061500a308ba825 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pavol=20=C5=BD=C3=A1=C4=8Dik?= <zacik.pa@gmail.com>
|
|
Date: Fri, 31 Jan 2025 12:43:08 +0100
|
|
Subject: [PATCH 1/2] bootloader: Simplify tuning of rpm-ostree kargs
|
|
|
|
The bootloader plugin claims that it does not mess
|
|
with existing kernel parameters; make sure we adhere
|
|
to that also for rpm-ostree systems:
|
|
|
|
1. Only append a new karg if the same key=value pair
|
|
does not already appear in kernel parameters. If we would
|
|
duplicate it, it would not be possible to determine which
|
|
one to delete when unapplying the profile.
|
|
|
|
2. Do not delete existing key=value pairs when the profile
|
|
adds a karg with another value for the key. A single key can
|
|
appear multiple times in the kernel parameter list with different
|
|
values.
|
|
|
|
Also make sure new kargs are added exactly in the order in which
|
|
they appear in the profile. This is especially important for kargs
|
|
related to hugepages.
|
|
|
|
Resolves: RHEL-45836
|
|
---
|
|
tuned/consts.py | 1 -
|
|
tuned/plugins/plugin_bootloader.py | 142 +++++++++++------------------
|
|
2 files changed, 53 insertions(+), 90 deletions(-)
|
|
|
|
diff --git a/tuned/consts.py b/tuned/consts.py
|
|
index 577ad9583..a92c78060 100644
|
|
--- a/tuned/consts.py
|
|
+++ b/tuned/consts.py
|
|
@@ -43,7 +43,6 @@
|
|
INITRD_IMAGE_DIR = "/boot"
|
|
BOOT_CMDLINE_TUNED_VAR = "TUNED_BOOT_CMDLINE"
|
|
BOOT_CMDLINE_INITRD_ADD_VAR = "TUNED_BOOT_INITRD_ADD"
|
|
-BOOT_CMDLINE_KARGS_DELETED_VAR = "TUNED_BOOT_KARGS_DELETED"
|
|
BOOT_CMDLINE_FILE = "/etc/tuned/bootcmdline"
|
|
PETITBOOT_DETECT_DIR = "/sys/firmware/opal"
|
|
MACHINE_ID_FILE = "/etc/machine-id"
|
|
diff --git a/tuned/plugins/plugin_bootloader.py b/tuned/plugins/plugin_bootloader.py
|
|
index 4c66189fb..07a66d265 100644
|
|
--- a/tuned/plugins/plugin_bootloader.py
|
|
+++ b/tuned/plugins/plugin_bootloader.py
|
|
@@ -209,24 +209,6 @@ def _get_config_options(cls):
|
|
"skip_grub_config": None,
|
|
}
|
|
|
|
- @staticmethod
|
|
- def _options_to_dict(options, omit=""):
|
|
- """
|
|
- Returns dict created from options
|
|
- e.g.: _options_to_dict("A=A A=B A B=A C=A", "A=B B=A B=B") returns {'A': ['A', None], 'C': ['A']}
|
|
- """
|
|
- d = {}
|
|
- omit = omit.split()
|
|
- for o in options.split():
|
|
- if o not in omit:
|
|
- arr = o.split('=', 1)
|
|
- d.setdefault(arr[0], []).append(arr[1] if len(arr) > 1 else None)
|
|
- return d
|
|
-
|
|
- @staticmethod
|
|
- def _dict_to_options(d):
|
|
- return " ".join([k + "=" + v1 if v1 is not None else k for k, v in d.items() for v1 in v])
|
|
-
|
|
def _rpm_ostree_status(self):
|
|
"""
|
|
Returns status of rpm-ostree transactions or None if not run on rpm-ostree system
|
|
@@ -241,68 +223,45 @@ def _rpm_ostree_status(self):
|
|
return None
|
|
return splited[1]
|
|
|
|
- def _wait_till_idle(self):
|
|
+ def _wait_till_rpm_ostree_idle(self):
|
|
+ """Check that rpm-ostree is idle, allowing some waiting time."""
|
|
sleep_cycles = 10
|
|
sleep_secs = 1.0
|
|
- for i in range(sleep_cycles):
|
|
+ for _ in range(sleep_cycles):
|
|
if self._rpm_ostree_status() == "idle":
|
|
return True
|
|
sleep(sleep_secs)
|
|
- if self._rpm_ostree_status() == "idle":
|
|
- return True
|
|
- return False
|
|
+ return self._rpm_ostree_status() == "idle"
|
|
+
|
|
+ def _get_rpm_ostree_kargs(self):
|
|
+ """Retrieve the output of rpm-ostree kargs, i.e., current default kernel arguments."""
|
|
+ if not self._wait_till_rpm_ostree_idle():
|
|
+ log.error("Error getting rpm-ostree kargs: rpm-ostree is busy")
|
|
+ return None
|
|
+ (rc, out, err) = self._cmd.execute(["rpm-ostree", "kargs"], return_err=True)
|
|
+ if out:
|
|
+ log.debug("rpm-ostree kargs: %s" % out)
|
|
+ if rc != 0:
|
|
+ log.error("Error getting rpm-ostree kargs: %s" % err)
|
|
+ return None
|
|
+ return out
|
|
|
|
- def _rpm_ostree_kargs(self, append={}, delete={}):
|
|
+ def _modify_rpm_ostree_kargs(self, delete_kargs=[], append_kargs=[]):
|
|
"""
|
|
- Method for appending or deleting rpm-ostree karg
|
|
- returns None if rpm-ostree not present or is run on not ostree system
|
|
- or tuple with new kargs, appended kargs and deleted kargs
|
|
+ Modify (delete and append) kernel arguments in a rpm-ostree system.
|
|
+ Return a boolean indicating whether the operation was successful.
|
|
"""
|
|
- (rc, out, err) = self._cmd.execute(['rpm-ostree', 'kargs'], return_err=True)
|
|
- log.debug("rpm-ostree output stdout:\n%s\nstderr:\n%s" % (out, err))
|
|
- if rc != 0:
|
|
- return None, None, None
|
|
- kargs = self._options_to_dict(out)
|
|
-
|
|
- if not self._wait_till_idle():
|
|
- log.error("Cannot wait for transaction end")
|
|
- return None, None, None
|
|
-
|
|
- deleted = {}
|
|
- delete_params = self._dict_to_options(delete).split()
|
|
- # Deleting kargs, e.g. deleting added kargs by profile
|
|
- for k, val in delete.items():
|
|
- for v in val:
|
|
- kargs[k].remove(v)
|
|
- deleted[k] = val
|
|
-
|
|
- appended = {}
|
|
- append_params = self._dict_to_options(append).split()
|
|
- # Appending kargs, e.g. new kargs by profile or restoring kargs replaced by profile
|
|
- for k, val in append.items():
|
|
- if kargs.get(k):
|
|
- # If there is karg that we add with new value we want to delete it
|
|
- # and store old value for restoring after profile unload
|
|
- log.debug("adding rpm-ostree kargs %s: %s for delete" % (k, kargs[k]))
|
|
- deleted.setdefault(k, []).extend(kargs[k])
|
|
- delete_params.extend([k + "=" + v if v is not None else k for v in kargs[k]])
|
|
- kargs[k] = []
|
|
- kargs.setdefault(k, []).extend(val)
|
|
- appended[k] = val
|
|
-
|
|
- if append_params == delete_params:
|
|
- log.info("skipping rpm-ostree kargs - append == deleting (%s)" % append_params)
|
|
- return kargs, appended, deleted
|
|
-
|
|
- log.info("rpm-ostree kargs - appending: '%s'; deleting: '%s'" % (append_params, delete_params))
|
|
- (rc, _, err) = self._cmd.execute(['rpm-ostree', 'kargs'] +
|
|
- ['--append=%s' % v for v in append_params] +
|
|
- ['--delete=%s' % v for v in delete_params], return_err=True)
|
|
+ if not self._wait_till_rpm_ostree_idle():
|
|
+ log.error("Error modifying rpm-ostree kargs: rpm-ostree is busy")
|
|
+ return False
|
|
+ (rc, _, err) = self._cmd.execute(
|
|
+ ["rpm-ostree", "kargs"] +
|
|
+ ["--delete=%s" % karg for karg in delete_kargs] +
|
|
+ ["--append=%s" % karg for karg in append_kargs], return_err=True)
|
|
if rc != 0:
|
|
- log.error("Something went wrong with rpm-ostree kargs\n%s" % (err))
|
|
- return self._options_to_dict(out), None, None
|
|
- else:
|
|
- return kargs, appended, deleted
|
|
+ log.error("Error modifying rpm-ostree kargs: %s" % err)
|
|
+ return False
|
|
+ return True
|
|
|
|
def _get_effective_options(self, options):
|
|
"""Merge provided options with plugin default options and merge all cmdline.* options."""
|
|
@@ -368,18 +327,16 @@ def _remove_grub2_tuning(self):
|
|
log.info("removing initrd image '%s'" % self._initrd_dst_img_val)
|
|
self._cmd.unlink(self._initrd_dst_img_val)
|
|
|
|
- def _get_rpm_ostree_changes(self):
|
|
+ def _get_appended_rpm_ostree_kargs(self):
|
|
+ """Return the list of kernel arguments that were appended by this profile (in a rpm-ostree system)."""
|
|
f = self._cmd.read_file(consts.BOOT_CMDLINE_FILE)
|
|
appended = re.search(consts.BOOT_CMDLINE_TUNED_VAR + r"=\"(.*)\"", f, flags=re.MULTILINE)
|
|
- appended = appended[1] if appended else ""
|
|
- deleted = re.search(consts.BOOT_CMDLINE_KARGS_DELETED_VAR + r"=\"(.*)\"", f, flags=re.MULTILINE)
|
|
- deleted = deleted[1] if deleted else ""
|
|
- return appended, deleted
|
|
+ return appended[1].split() if appended else []
|
|
|
|
def _remove_rpm_ostree_tuning(self):
|
|
- appended, deleted = self._get_rpm_ostree_changes()
|
|
- self._rpm_ostree_kargs(append=self._options_to_dict(deleted), delete=self._options_to_dict(appended))
|
|
- self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR: "", consts.BOOT_CMDLINE_KARGS_DELETED_VAR: ""})
|
|
+ """Remove kernel parameter tuning in a rpm-ostree system."""
|
|
+ self._modify_rpm_ostree_kargs(delete_kargs=self._get_appended_rpm_ostree_kargs())
|
|
+ self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR: ""})
|
|
|
|
def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
|
|
if rollback == consts.ROLLBACK_FULL and not self._skip_grub_config_val:
|
|
@@ -489,14 +446,22 @@ def _grub2_cfg_patch(self, d):
|
|
return True
|
|
|
|
def _rpm_ostree_update(self):
|
|
- appended, _ = self._get_rpm_ostree_changes()
|
|
- _cmdline_dict = self._options_to_dict(self._cmdline_val, appended)
|
|
- if not _cmdline_dict:
|
|
- return None
|
|
- (_, _, d) = self._rpm_ostree_kargs(append=_cmdline_dict)
|
|
- if d is None:
|
|
+ """Apply kernel parameter tuning in a rpm-ostree system."""
|
|
+ if self._get_appended_rpm_ostree_kargs():
|
|
+ # The kargs are already set in /etc/tuned/bootcmldine,
|
|
+ # we are likely post-reboot and done.
|
|
+ return
|
|
+ profile_kargs = self._cmdline_val.split()
|
|
+ active_kargs = self._get_rpm_ostree_kargs()
|
|
+ if active_kargs is None:
|
|
+ log.error("Not updating kernel arguments, could not read the current ones.")
|
|
return
|
|
- self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR : self._cmdline_val, consts.BOOT_CMDLINE_KARGS_DELETED_VAR : self._dict_to_options(d)})
|
|
+ # Only append key=value pairs that do not yet appear in kernel parameters,
|
|
+ # otherwise we would not be able to restore the cmdline to the previous state
|
|
+ # via rpm-ostree kargs --delete.
|
|
+ kargs_to_append = [karg for karg in profile_kargs if karg not in active_kargs.split()]
|
|
+ if self._modify_rpm_ostree_kargs(append_kargs=kargs_to_append):
|
|
+ self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR : " ".join(kargs_to_append)})
|
|
|
|
def _grub2_update(self):
|
|
self._grub2_cfg_patch({consts.GRUB2_TUNED_VAR : self._cmdline_val, consts.GRUB2_TUNED_INITRD_VAR : self._initrd_val})
|
|
@@ -646,11 +611,10 @@ def _cmdline(self, enabling, value, verify, ignore_missing, instance):
|
|
v = self._variables.expand(self._cmd.unquote(value))
|
|
if verify:
|
|
if self._rpm_ostree:
|
|
- rpm_ostree_kargs = self._rpm_ostree_kargs()[0]
|
|
- cmdline = self._dict_to_options(rpm_ostree_kargs)
|
|
+ cmdline = self._get_rpm_ostree_kargs()
|
|
else:
|
|
cmdline = self._cmd.read_file("/proc/cmdline")
|
|
- if len(cmdline) == 0:
|
|
+ if cmdline is None or len(cmdline) == 0:
|
|
return None
|
|
cmdline_set = set(cmdline.split())
|
|
value_set = set(v.split())
|
|
|
|
From 3e05cb783ee10ea78efb113c54bd2ad7d73a0e2e Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pavol=20=C5=BD=C3=A1=C4=8Dik?= <zacik.pa@gmail.com>
|
|
Date: Fri, 16 May 2025 15:13:25 +0200
|
|
Subject: [PATCH 2/2] bootloader: Remove previously appended rpm-ostree kargs
|
|
|
|
If TuneD-appended kargs are present and do not match
|
|
the kargs to be appended, we should remove them. This
|
|
can happen if there was no profile rollback, e.g.,
|
|
when using the no-daemon mode.
|
|
|
|
Resolves: RHEL-86814
|
|
---
|
|
tuned/plugins/plugin_bootloader.py | 24 ++++++++++++++++--------
|
|
1 file changed, 16 insertions(+), 8 deletions(-)
|
|
|
|
diff --git a/tuned/plugins/plugin_bootloader.py b/tuned/plugins/plugin_bootloader.py
|
|
index 07a66d265..2711e116f 100644
|
|
--- a/tuned/plugins/plugin_bootloader.py
|
|
+++ b/tuned/plugins/plugin_bootloader.py
|
|
@@ -105,7 +105,7 @@ class BootloaderPlugin(base.Plugin):
|
|
----
|
|
[main]
|
|
include=profile_1
|
|
-
|
|
+
|
|
[bootloader]
|
|
cmdline_profile_2=-quiet
|
|
----
|
|
@@ -114,7 +114,7 @@ class BootloaderPlugin(base.Plugin):
|
|
----
|
|
[main]
|
|
include=profile_1
|
|
-
|
|
+
|
|
[bootloader]
|
|
cmdline_profile_1=-quiet
|
|
----
|
|
@@ -447,20 +447,28 @@ def _grub2_cfg_patch(self, d):
|
|
|
|
def _rpm_ostree_update(self):
|
|
"""Apply kernel parameter tuning in a rpm-ostree system."""
|
|
- if self._get_appended_rpm_ostree_kargs():
|
|
- # The kargs are already set in /etc/tuned/bootcmldine,
|
|
- # we are likely post-reboot and done.
|
|
- return
|
|
+ appended_kargs = self._get_appended_rpm_ostree_kargs()
|
|
profile_kargs = self._cmdline_val.split()
|
|
active_kargs = self._get_rpm_ostree_kargs()
|
|
if active_kargs is None:
|
|
log.error("Not updating kernel arguments, could not read the current ones.")
|
|
return
|
|
+ # Ignore kargs previously appended by TuneD, these will be removed later.
|
|
+ non_tuned_kargs = active_kargs.split()
|
|
+ for karg in appended_kargs:
|
|
+ non_tuned_kargs.remove(karg)
|
|
# Only append key=value pairs that do not yet appear in kernel parameters,
|
|
# otherwise we would not be able to restore the cmdline to the previous state
|
|
# via rpm-ostree kargs --delete.
|
|
- kargs_to_append = [karg for karg in profile_kargs if karg not in active_kargs.split()]
|
|
- if self._modify_rpm_ostree_kargs(append_kargs=kargs_to_append):
|
|
+ kargs_to_append = [karg for karg in profile_kargs if karg not in non_tuned_kargs]
|
|
+ if appended_kargs == kargs_to_append:
|
|
+ # The correct kargs are already set in /etc/tuned/bootcmldine,
|
|
+ # we are likely post-reboot and done.
|
|
+ log.info("Kernel arguments already set, not updating.")
|
|
+ return
|
|
+ # If there are kargs in /etc/bootcmdline and they do not match
|
|
+ # the requested ones, there was no rollback, so remove them now.
|
|
+ if self._modify_rpm_ostree_kargs(delete_kargs=appended_kargs, append_kargs=kargs_to_append):
|
|
self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR : " ".join(kargs_to_append)})
|
|
|
|
def _grub2_update(self):
|