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()
```
This commit is contained in:
Ikki Zhu 2023-06-08 02:29:18 +08:00 committed by GitHub
parent 8a6d45227e
commit 9fcbd5ed1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 19 additions and 12 deletions

View File

@ -51,21 +51,13 @@ class Component(ComponentBase):
except Exception as e: except Exception as e:
return None 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): def __get_cpld_version(self):
# Retrieves the CPLD firmware version # Retrieves the CPLD firmware version
cpld_version = dict() cpld_version = dict()
for cpld_name in CPLD_ADDR_MAPPING: for cpld_name in CPLD_ADDR_MAPPING:
try: try:
cpld_addr = CPLD_ADDR_MAPPING[cpld_name] 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_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_raw[3], 16)) if cpld_version_raw is not None else 'None'
cpld_version[cpld_name] = cpld_version_str cpld_version[cpld_name] = cpld_version_str

View File

@ -1,3 +1,4 @@
import fcntl
import os import os
import struct import struct
import subprocess import subprocess
@ -74,9 +75,23 @@ class APIHelper():
return True return True
def get_cpld_reg_value(self, getreg_path, register): 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') file.write(register + '\n')
with open(getreg_path, 'r') as file: file.flush()
result = file.readline()
# 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 return result