From 09ed03a5ae96d1b58ae6f3bcb5a82dfcc3469d3e Mon Sep 17 00:00:00 2001 From: Sahithi Ravindranath Date: Wed, 11 Feb 2026 02:33:59 -0600 Subject: [PATCH 1/2] [spyre] validate the current ulimit against the config If the currently set ulimit value is higher than the configured 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 configured value, the check passes; otherwise, it fails. Signed-off-by: Sahithi Ravindranath --- servicereportpkg/validate/plugins/spyre.py | 38 +++++++++++++++++++--- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/servicereportpkg/validate/plugins/spyre.py b/servicereportpkg/validate/plugins/spyre.py index b4bc16c..12655f3 100644 --- a/servicereportpkg/validate/plugins/spyre.py +++ b/servicereportpkg/validate/plugins/spyre.py @@ -136,10 +136,36 @@ def check_udev_rule(self): conf_check.set_status(status) return conf_check + def verify_if_memlimit_config_is_valid(self, conf_check, + line, vfio_mem_conf): + """Verify if memlimit config rule valid""" + + # Patterns to parse sentient 1234, memlock ulimited, + # memlock 7890, sentient memlock unlimited + pattern = r'^(.+?)\s+(unlimited|\d+)$' + for conf in vfio_mem_conf[:]: + if line == conf: + conf_check.add_attribute(line, True, None, None) + vfio_mem_conf.remove(conf) + continue + 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))): + conf_check.add_attribute(line, True, None, None) + vfio_mem_conf.remove(conf) + 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__, @@ -150,9 +176,13 @@ def check_memlock_conf(self): 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) + if not line: + continue + # parses the vfio mem config and exiting config and + # validates the vfio mem config and the memlimit value + # against existing config. + self.verify_if_memlimit_config_is_valid(conf_check, + line, vfio_mem_conf) except FileNotFoundError: self.log.error("File not found : %s", config_file) From 4401e6af9c7dafc9dcf524af409887349021c569 Mon Sep 17 00:00:00 2001 From: Sahithi Ravindranath Date: Wed, 11 Feb 2026 10:10:12 -0600 Subject: [PATCH 2/2] [spyre] Update the ulimit for the sentient group multi-card spyre containers eventually runs out of locked memory and can cause the containers to exit. Updating the memlock config to the max value containers might consume based on the number of cards in the system would prevent the containers exiting due to locked memory exhaustion. Signed-off-by: Sahithi Ravindranath --- .../repair/plugins/spyre_repair.py | 20 ++++++++++++-- servicereportpkg/validate/plugins/spyre.py | 27 ++++++++++++++++++- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/servicereportpkg/repair/plugins/spyre_repair.py b/servicereportpkg/repair/plugins/spyre_repair.py index cbc4746..03360db 100644 --- a/servicereportpkg/repair/plugins/spyre_repair.py +++ b/servicereportpkg/repair/plugins/spyre_repair.py @@ -46,10 +46,26 @@ 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) + config_match = re.sub(r'\s(\d+|unlimited)$', '', 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 line.strip() and config_match not in line: + 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(): diff --git a/servicereportpkg/validate/plugins/spyre.py b/servicereportpkg/validate/plugins/spyre.py index 12655f3..a658350 100644 --- a/servicereportpkg/validate/plugins/spyre.py +++ b/servicereportpkg/validate/plugins/spyre.py @@ -59,6 +59,30 @@ def is_applicable(cls): return Spyre.is_spyre_card_exists() + @classmethod + 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"] + # Spyre device IDs + spyre_device_ids = ["0x06a7", "0x06a8"] + + for device in context.list_devices(subsystem='pci'): + vendor_id = device.attributes.get("vendor").decode("utf-8").strip() + if vendor_id not in spyre_vendor_ids: + continue + + device_id = device.attributes.get("device").decode("utf-8").strip() + if device_id not in spyre_device_ids: + continue + + number_of_cards+=1 + + return number_of_cards + def check_driver_config(self): """VFIO Driver configuration""" @@ -164,7 +188,8 @@ def verify_if_memlimit_config_is_valid(self, conf_check, 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"