尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Linux proc-modules文件格式与m_show回调

Linux proc-modules文件格式与m_show回调
📅 发布时间:2026/6/22 13:37:20

Linux /proc/modules文件格式与m_show回调

/proc/modules是Linux内核暴露已加载模块信息的传统procfs接口,其文件格式和输出由seq_file接口中的m_show()回调完全控制。尽管/sys/module提供了更丰富的sysfs接口,/proc/modules因其简洁的文本格式仍然是lsmod等用户空间工具的首选数据源。

/proc/modules的注册位于kernel/module/procfs.c中的__init proc_modules_init():

static int __init proc_modules_init(void)
{
proc_create_seq("modules", 0, NULL, &modules_op);
return 0;
}
module_init(proc_modules_init);

proc_create_seq()是内核提供的seq_file封装,它在procfs根目录下创建名为"modules"的文件,并将所有读写操作委托给modules_op中定义的seq_operations回调。

struct seq_operations modules_op的定义:

static const struct seq_operations modules_op = {
.start = m_start,
.next = m_next,
.stop = m_stop,
.show = m_show,
};

/proc/modules的典型输出格式如下:

module_name size used_by_count used_by_list
fbdev 24576 0
ext4 589824 2 crc16,mbcache
usb_storage 73728 0

每行包含四列:
(1) 模块名称:最左列,20字符以内左对齐。
(2) 模块大小:模块核心代码段占用内存的字节数,对应mod->core_layout.size,以十进制显示。
(3) 引用计数:当前使用该模块的内核组件数量,通过atomic_read(&mod->refcnt)读取。
(4) 依赖列表:逗号分隔的使用者列表,当引用计数为0时此列为空。

m_show()回调的完整实现:

static int m_show(struct seq_file *m, void *p)
{
struct module *mod = list_entry(p, struct module, list);
char buf[MODULE_FLAGS_BUF_SIZE];

if (p == SEQ_START_TOKEN) {
seq_puts(m, "Module Size Used by\n");
return 0;
}

/* 输出基础信息 */
seq_printf(m, "%-20s%8lu %u ",
mod->name,
mod->core_layout.size,
atomic_read(&mod->refcnt));

/* 输出taint标志 */
module_flags(mod, buf, false);
seq_printf(m, "%s\n", buf);

return 0;
}

seq_file接口的工作机制对于理解/proc/modules的读取行为至关重要。当一个用户空间程序(如lsmod或者cat /proc/modules)读取文件时,内核依次调用:

(1) m_start():加module_mutex锁,返回第一个要显示的模块。

static void *m_start(struct seq_file *m, loff_t *pos)
{
struct module *mod;
loff_t n = 0;

mutex_lock(&module_mutex);

if (!*pos) {
if (list_empty(&module_list))
return SEQ_START_TOKEN;
mod = list_first_entry(&module_list, struct module, list);
(*pos)++;
return mod;
}

list_for_each_entry_continue(mod, &module_list, list) {
if (n++ >= *pos)
return mod;
}
return NULL;
}

(2) m_show():格式化输出当前模块的信息。

(3) m_next():遍历到module_list中的下一个模块。

static void *m_next(struct seq_file *m, void *p, loff_t *pos)
{
struct module *mod;

if (p == SEQ_START_TOKEN)
mod = list_first_entry(&module_list, struct module, list);
else {
mod = list_entry(p, struct module, list);
if (list_is_last(&mod->list, &module_list))
mod = NULL;
else
mod = list_next_entry(mod, list);
}

(*pos)++;
return mod;
}

(4) m_stop():释放module_mutex锁。

static void m_stop(struct seq_file *m, void *p)
{
mutex_unlock(&module_mutex);
}

/proc/modules的读写性能考虑:当系统加载了大量模块(数千个)时,cat /proc/modules可能会因为module_mutex的持有时间较长而短暂阻塞模块加载和卸载操作。seq_file的缓冲区默认大小为PAGE_SIZE字节(通常4096),当输出数据超过单页大小时,内核自动调用m_start()和m_next()进行多次迭代。

输出格式中的"Used by"列通过module_flags()函数生成。该函数还负责输出模块的taint污染标志:

static void module_flags(struct module *mod, char *buf, bool show_state)
{
int bx = 0;

if (mod->taints) {
if (mod->taints & TAINT_PROPRIETARY_MODULE)
buf[bx++] = 'P';
if (mod->taints & TAINT_OOT_MODULE)
buf[bx++] = 'O';
if (mod->taints & TAINT_FORCED_MODULE)
buf[bx++] = 'F';
if (mod->taints & TAINT_CRAP)
buf[bx++] = 'C';
if (mod->taints & TAINT_UNSIGNED_MODULE)
buf[bx++] = 'E';
}

if (show_state) {
switch (mod->state) {
case MODULE_STATE_LIVE: break;
case MODULE_STATE_COMING: buf[bx++] = 'C'; break;
case MODULE_STATE_GOING: buf[bx++] = 'G'; break;
}
}

if (bx)
buf[bx++] = ' ';
buf[bx] = '\0';

/* 附加使用者的模块名称列表 */
if (!list_empty(&mod->source_list)) {
struct module_use *use;
list_for_each_entry(use, &mod->source_list, source_list) {
if (bx >= MODULE_FLAGS_BUF_SIZE - 1)
break;
bx += snprintf(buf + bx, MODULE_FLAGS_BUF_SIZE - bx,
"%s,", use->target->name);
}
if (bx > 0 && buf[bx-1] == ',')
buf[bx-1] = ' ';
}
}

内核自5.x系列以来逐步将模块子系统从kernel/module.c重构为kernel/module/目录下的多个文件,procfs.c独立管理/proc/modules的逻辑。seq_file接口的设计使得/proc/modules可以安全地在模块并发加载和卸载的环境下提供一致的视图,即使遍历期间模块列表发生变化,m_start/stop的锁机制也保证了数据一致性。

用户空间工具可以直接解析/proc/modules的文本行,无需依赖任何内核头文件,这也是该接口历经数十年仍被libkmod等现代工具库作为fallback选项的原因。其格式的稳定性和简洁性使其成为内核模块信息导出的经典设计。

相关新闻

  • 酒泉市金塔县2026年黄金回收本地靠谱门店 白银回收+铂金回收门店指南TOP5排行榜 优选门店汇总及电话地址推荐 - 大熊猫898989
  • Qwen3-VL架构深度解析:Interleaved-MRoPE与DeepStack技术原理
  • 终极B站视频解析指南:3分钟掌握免费获取高清视频地址的完整教程

最新新闻

  • JMeter插件实战指南:从核心插件选型到阶梯压测与性能监控
  • BilibiliDown:B站视频下载的终极解决方案,3分钟轻松搞定离线收藏
  • 2026年绍兴本地GEO工具推荐:企业选工具前先看这8个核心能力 - 科技快讯
  • 高阶时空建模:从图神经网络到单纯复形与时空随机游走
  • 一劳永逸!Visual C++运行库完整安装指南:告别DLL缺失错误
  • 2026年7月全国汽车窗膜车衣服务机构实力盘点:DuPont™杜邦™正规可信、专业技术过硬、售后完善 - 十大排行榜推荐

日新闻

  • 2026速览惠州叛逆青少年学校前十大排名名单出炉 - 武汉中职最新信息发布
  • 2026上饶白蚁消杀哪家好?15年本土2大权威白蚁防治公司推荐(金盾虫控/青蚁卫士) - 我叫一
  • 天龙八部单机版终极数据管理工具:5个技巧快速掌握游戏数据编辑

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号