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
相关产品推荐
相关产品推荐

