From 9fcbd5ed1dd7efd368567025af942177e80c4324 Mon Sep 17 00:00:00 2001 From: Ikki Zhu <79439153+qnos@users.noreply.github.com> Date: Thu, 8 Jun 2023 02:29:18 +0800 Subject: [PATCH] fix possible cpld race access issue (#15371) Why I did it fix possible cpld race read issue between watchdog and reboot cause process How I did it Use fcntl.flock to limit parallel access to cpld sys file How to verify it It can be simulated and verified with following python script ``` python3 import fcntl import signal import threading exit_flag = False def get_cpld_reg_value(getreg_path, register): file = open(getreg_path, 'w+') # Acquire an exclusive lock on the file fcntl.flock(file, fcntl.LOCK_EX) try: file.write(register + '\n') file.flush() # Seek to the beginning of the file file.seek(0) # Read the content of the file result = file.readline().strip() finally: # Release the lock and close the file fcntl.flock(file, fcntl.LOCK_UN) file.close() return result def cpld_read(thread_num, cpld_reg, expect_val): while not exit_flag: val = get_cpld_reg_value("/sys/devices/platform/dx010_cpld/getreg", cpld_reg) #print(f"Thread {thread_num}: get cpld reg {cpld_reg}, value {val}") if val != expect_val: print(f"Thread {thread_num}: get cpld reg {cpld_reg}, value {val}, expect_val {expect_val}") def signal_handler(sig, frame): global exit_flag print("Ctrl+C detected. Quitting...") exit_flag = True if __name__ == '__main__': # Register the signal handler for Ctrl+C signal.signal(signal.SIGINT, signal_handler) t1 = threading.Thread(target=cpld_read, args=(1, '0x103', '0x11',)) t2 = threading.Thread(target=cpld_read, args=(2, '0x141', '0x00',)) t1.start() t2.start() t1.join() t2.join() ``` --- .../sonic_platform/component.py | 10 +-------- .../sonic_platform/helper.py | 21 ++++++++++++++++--- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py index 8b66e7c4b1..1a61431ace 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/component.py @@ -51,21 +51,13 @@ class Component(ComponentBase): except Exception as e: return None - def get_register_value(self, register): - # Retrieves the cpld register value - with open(GETREG_PATH, 'w') as file: - file.write(register + '\n') - with open(GETREG_PATH, 'r') as file: - raw_data = file.readline() - return raw_data.strip() - def __get_cpld_version(self): # Retrieves the CPLD firmware version cpld_version = dict() for cpld_name in CPLD_ADDR_MAPPING: try: cpld_addr = CPLD_ADDR_MAPPING[cpld_name] - cpld_version_raw = self.get_register_value(cpld_addr) + cpld_version_raw = self._api_helper.get_cpld_reg_value(GETREG_PATH, cpld_addr) cpld_version_str = "{}.{}".format(int(cpld_version_raw[2], 16), int( cpld_version_raw[3], 16)) if cpld_version_raw is not None else 'None' cpld_version[cpld_name] = cpld_version_str diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/helper.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/helper.py index a77d27837e..8372ab8989 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/helper.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/helper.py @@ -1,3 +1,4 @@ +import fcntl import os import struct import subprocess @@ -74,9 +75,23 @@ class APIHelper(): return True def get_cpld_reg_value(self, getreg_path, register): - with open(getreg_path, 'w') as file: + file = open(getreg_path, 'w+') + # Acquire an exclusive lock on the file + fcntl.flock(file, fcntl.LOCK_EX) + + try: file.write(register + '\n') - with open(getreg_path, 'r') as file: - result = file.readline() + file.flush() + + # Seek to the beginning of the file + file.seek(0) + + # Read the content of the file + result = file.readline().strip() + finally: + # Release the lock and close the file + fcntl.flock(file, fcntl.LOCK_UN) + file.close() + return result