From 3eac19165b2ac55a2dcae1f160c8fb295f4bd303 Mon Sep 17 00:00:00 2001 From: Sahithi Ravindranath Date: Tue, 17 Feb 2026 23:35:47 -0600 Subject: [PATCH 1/3] [spyre] Fix memlock limit config check If the currently set ulimit value is higher than the expected limit, it does not need to be reduced, as higher values are harmless. The validation parses the configuration and checks the memlimit value. If the currently set memlimit is greater than or equal to the expected value, the check passes; otherwise, it fails. Signed-off-by: Sahithi Ravindranath --- servicereportpkg/validate/plugins/spyre.py | 68 ++++++++++++++++++---- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/servicereportpkg/validate/plugins/spyre.py b/servicereportpkg/validate/plugins/spyre.py index b4bc16c..1abecdf 100644 --- a/servicereportpkg/validate/plugins/spyre.py +++ b/servicereportpkg/validate/plugins/spyre.py @@ -136,27 +136,71 @@ def check_udev_rule(self): conf_check.set_status(status) return conf_check + """ + is_mem_limit_config_valid(): Verify whether the current memlock + configuration satisfies or exceeds the expected VFIO memory configuration. + + Args: + config_file (str): File path to existing configuration + conf (str): Expected memlimit configuration + + Returns: + bool: True if current memlimit config is valid, False otherwise. + """ + def is_mem_limit_config_valid(self, config_file, conf): + + # Example strings matching the pattern: + # "@sentient 1234", "@sentient unlimited", "@sentient 7890", + # "@sentient -memlock unlimited" + pattern = r'^(@sentient.+)\s+(unlimited|\d+)$' + status = False + try: + with open(config_file, "r", encoding="utf-8") as file: + for line in file: + line = line.strip() + if not line: + continue + + if line == conf: + status = True + + line_match = re.match(pattern, line) + conf_match = re.match(pattern, conf) + if line_match and conf_match: + line_str = line_match.group(1) + line_value = line_match.group(2) + conf_str = conf_match.group(1) + conf_value = conf_match.group(2) + if line_str == conf_str: + if (line_value == "unlimited" + or (int(line_value) >= int(conf_value))): + status = True + + except FileNotFoundError: + self.log.error("File not found : %s", config_file) + status = False + + except ValueError as e: + self.log.error("Type casting error: %s", e) + status = False + + return status + def check_memlock_conf(self): """User memlock configuration""" - vfio_mem_conf = ["@sentient - memlock 134217728"] + memlimit = 134217728 + vfio_mem_conf = [f"@sentient - memlock {memlimit}"] config_file = "/etc/security/limits.d/memlock.conf" conf_check = ConfigurationFileCheck(self.check_memlock_conf.__doc__, config_file) status = True - try: - with open(config_file, "r", encoding="utf-8") as file: - for line in file: - line = line.strip() - if line in vfio_mem_conf: - conf_check.add_attribute(line, True, None, None) - vfio_mem_conf.remove(line) - - except FileNotFoundError: - self.log.error("File not found : %s", config_file) - status = False + for conf in vfio_mem_conf[:]: + if self.is_mem_limit_config_valid(config_file, conf): + conf_check.add_attribute(conf, True, None, None) + vfio_mem_conf.remove(conf) if vfio_mem_conf: status = False From 771df1c6ecfe41362a6979bee7d84730915cbc38 Mon Sep 17 00:00:00 2001 From: Sahithi Ravindranath Date: Fri, 20 Feb 2026 03:31:56 -0600 Subject: [PATCH 2/3] [spyre] Update memlock repair to replace outdated ulimit config If the repair function updates the existing memlock configuration, any redundant or outdated configuration entries must be removed. Only the updated configuration should remain, rather than appending a new entry alongside the old ones. The memlimit fix now parses the existing configuration, identifies matching entries, removes old or duplicate configurations, and adds only the updated configuration. Signed-off-by: Sahithi Ravindranath --- .../repair/plugins/spyre_repair.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/servicereportpkg/repair/plugins/spyre_repair.py b/servicereportpkg/repair/plugins/spyre_repair.py index cbc4746..635487d 100644 --- a/servicereportpkg/repair/plugins/spyre_repair.py +++ b/servicereportpkg/repair/plugins/spyre_repair.py @@ -46,10 +46,25 @@ def fix_vfio_drive_config(self, plugin_obj, vfio_drive_config_check): def fix_user_mem_conf(self, plugin_obj, user_mem_conf_check): """Fix memory configuration usergroup""" + updated_lines = [] for config, val in user_mem_conf_check.get_config_attributes().items(): if not val["status"]: - append_to_file(user_mem_conf_check.get_file_path(), - "\n"+config) + try: + with open(user_mem_conf_check.get_file_path(), "r", encoding="utf-8") as file: + lines = file.readlines() + for line in lines: + # if a user mem config rule is redundant incorrect or old rule will be + # removed + if not re.match(r'^@sentient', line.strip()): + updated_lines.append(line) + + except FileNotFoundError: + self.log.error("File not found : %s", user_mem_conf_check.get_file_path()) + + updated_lines.append("\n"+config) + updated_string = "".join(updated_lines) + add_to_file(user_mem_conf_check.get_file_path(), + updated_string) re_check = plugin_obj.check_memlock_conf() if re_check.get_status(): From 0efa9cbaec39ed562918e249e6b8d05c50a34873 Mon Sep 17 00:00:00 2001 From: Sahithi Ravindranath Date: Fri, 20 Feb 2026 03:33:03 -0600 Subject: [PATCH 3/3] [spyre] Update memlock ulimit for sentient group based on card count Multi-card Spyre containers can eventually exhaust locked memory, causing the containers to exit unexpectedly. Update the memlock configuration to scale based on the number of Spyre cards present in the system. This sets the memlock limit to the maximum value containers may consume, preventing exits due to locked memory exhaustion. The memlimit value was determined experimentally as: memlimit = (number_of_spyre_cards) * (128GB + 16MB) Signed-off-by: Sahithi Ravindranath --- servicereportpkg/validate/plugins/spyre.py | 24 ++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/servicereportpkg/validate/plugins/spyre.py b/servicereportpkg/validate/plugins/spyre.py index 1abecdf..c02492a 100644 --- a/servicereportpkg/validate/plugins/spyre.py +++ b/servicereportpkg/validate/plugins/spyre.py @@ -30,10 +30,21 @@ def __init__(self): self.name = Spyre.__name__ self.description = Spyre.__doc__ + """ + get_number_of_spyre_cards(): Get the number of spyre cards available in + the system. + + Args: + None + + Returns: + int: Number of spyre cards in the system. + """ @classmethod - def is_spyre_card_exists(cls): - """Return True if spyre exists in the system otherwise False""" + def get_number_of_spyre_cards(cls): + """Returns number of spyre cards in the device""" + number_of_cards = 0 context = pyudev.Context() # IBM vendor ID spyre_vendor_ids = ["0x1014"] @@ -49,15 +60,15 @@ def is_spyre_card_exists(cls): if device_id not in spyre_device_ids: continue - return True + number_of_cards += 1 - return False + return number_of_cards @classmethod def is_applicable(cls): """Returns True if plugin is applicable otherwise False""" - return Spyre.is_spyre_card_exists() + return Spyre.get_number_of_spyre_cards() > 0 def check_driver_config(self): """VFIO Driver configuration""" @@ -189,7 +200,8 @@ def is_mem_limit_config_valid(self, config_file, conf): def check_memlock_conf(self): """User memlock configuration""" - memlimit = 134217728 + num_cards = Spyre.get_number_of_spyre_cards() + memlimit = num_cards * 134234112 vfio_mem_conf = [f"@sentient - memlock {memlimit}"] config_file = "/etc/security/limits.d/memlock.conf"