You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

sysfs节点trace_marker写入异常:首次成功后后续失败(文件描述符失效)

sysfs节点trace_marker重复写入失败问题排查与解决

问题背景

向/sys/kernel/debug/tracing/trace_marker写入日志时,首次写入成功,但后续写入报错Errornum: Bad file descriptor,文件描述符被自动关闭。需求是仅打开一次文件,保持fd全程有效,避免每次写入都执行打开/关闭系统调用(写入频率极高,每10微秒2-3次)。

最初尝试两种方案均失败:

  • 类成员保存文件描述符,多线程加锁写入(已确认Logger对象未被销毁)
  • 全局文件描述符+函数调用写入

当前临时采用每次写入前打开、写入后关闭的方案,但存在额外系统调用开销。

最初实现代码

class Logger {

int mFileFd;

void logFromAnotherThread(std::string s) {
    std::unique_lock<std::mutex> ul(mLogMu);
    ...
    int count = write(mFileFd, s.c_str(), s.length());
    if (count > 0)
       std::cout << "Wrote n bytes: " << count << std::endl;
    else
       std::cout << "Errornum: " << strerror(errno) << std::endl;
    ...
}


Logger() {
   mFileFd = open(SYSFS_NODE_WRITE,  O_WRONLY);
   ....
}

}

当前临时方案代码

#define TRACE_MARKER_FILE "/sys/kernel/debug/tracing/trace_marker"

void logdata(pid_t tid, std::string mystring) {
    if(useLogger) {        
        std::stringstream ss;
        if (funcname.length() > 0) 
            ss << LOGTAG << mystring;

        int tempfd = open(TRACE_MARKER_FILE,  O_WRONLY);
        int count = write(tempfd, ss.str().c_str(), ss.str().length());
        if (count == 0) {
            std::cout << "Errornum: " << strerror(errno) <<std::endl;
        }
        close(tempfd);
    }
}

问题原因

trace_marker是ftrace的特殊内核节点,其文件描述符会被内核主动关闭,常见场景包括:

  • 手动执行echo > /sys/kernel/debug/tracing/trace清空trace日志
  • 内核trace buffer写满后自动轮转
  • 其他工具(如trace-cmd)操作ftrace配置触发buffer重置
    高频写入本身不会直接导致fd关闭,但上述内核层面的操作是主要诱因。

解决方案

方案1:检测fd有效性,失效时自动重开

在写入前验证fd是否可用,若无效则重新打开,兼顾性能与可靠性:

#include <fcntl.h>
#include <unistd.h>
#include <mutex>
#include <string>
#include <iostream>

class Logger {
    int mFileFd = -1;
    std::mutex mLogMu;
    const char* const TRACE_MARKER = "/sys/kernel/debug/tracing/trace_marker";

    void ensureFdValid() {
        // 验证fd是否有效,无效则重新打开
        if (mFileFd == -1 || fcntl(mFileFd, F_GETFD) == -1) {
            if (mFileFd != -1) {
                close(mFileFd);
            }
            mFileFd = open(TRACE_MARKER, O_WRONLY | O_APPEND);
        }
    }

public:
    Logger() {
        ensureFdValid();
    }

    ~Logger() {
        if (mFileFd != -1) {
            close(mFileFd);
        }
    }

    void log(std::string s) {
        std::unique_lock<std::mutex> ul(mLogMu);
        ensureFdValid();
        if (mFileFd == -1) {
            std::cout << "Failed to open trace_marker" << std::endl;
            return;
        }
        int count = write(mFileFd, s.c_str(), s.length());
        if (count < 0) {
            std::cout << "Errornum: " << strerror(errno) << std::endl;
            // 写入失败标记fd无效,下次重新打开
            mFileFd = -1;
        } else {
            std::cout << "Wrote n bytes: " << count << std::endl;
        }
    }
};

核心改进:

  • 用fcntl(F_GETFD)准确验证fd有效性,比单纯判断mFileFd != -1更可靠
  • 写入失败后主动标记fd无效,避免重复使用坏fd
  • 初始化时确保ftrace节点就绪后再打开文件

方案2:添加O_APPEND标志打开文件

部分内核版本中,不带O_APPEND打开trace_marker可能触发fd异常关闭,添加该标志符合ftrace的日志追加逻辑,能提升fd稳定性:

// 打开时添加O_APPEND
mFileFd = open(TRACE_MARKER, O_WRONLY | O_APPEND);

方案3:排查外部ftrace操作

检查系统中是否有其他脚本或工具在操作ftrace,比如定期清空日志的任务、trace-cmd或perf trace等工具,这些操作会导致已打开的trace_marker fd失效,需避免此类冲突。

内容的提问来源于stack exchange,提问作者Ishank Rawat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 15:50:25