Linux驱动遍历init子进程获取PID出现异常值的问题求助
问题分析与解决
核心错误点
链表成员匹配错误
父进程的children链表挂载的是子进程的sibling成员,而非子进程的children成员。你在调用list_first_entry/list_last_entry时,第三个参数传入了children,导致结构体指针偏移计算错误,访问到无效内存,从而得到异常PID值。缺少RCU保护
real_parent和进程链表都受RCU(Read-Copy-Update)机制保护(指针带有__rcu修饰),直接访问会引发并发安全问题,可能导致野指针或数据不一致。list_next_entry用法错误
该宏的第一个参数应为链表节点(struct list_head),而非task_struct结构体本身。
修正后的代码示例
#include <linux/sched.h> #include <linux/rcupdate.h> #include <linux/module.h> static int __init ps_module_init(void) { struct task_struct *p; struct task_struct *init_task = NULL; struct task_struct *child; rcu_read_lock(); p = current; pr_info("Current process name: %s\tPID: %d\n", p->comm, p->pid); // 回溯到init进程(PID=1) for (p = rcu_dereference(p->real_parent); ; p = rcu_dereference(p->real_parent)) { pr_info("Parent process name: %s\tPID: %d\n", p->comm, p->pid); if (p->pid == 1) { init_task = p; break; } } // 遍历init的所有子进程 pr_info("--- Init's children ---\n"); list_for_each_entry_rcu(child, &init_task->children, sibling) { pr_info("Child process name: %s\tPID: %d\n", child->comm, child->pid); } rcu_read_unlock(); return 0; } static void __exit ps_module_exit(void) { pr_info("PS module exited\n"); } module_init(ps_module_init); module_exit(ps_module_exit); MODULE_LICENSE("GPL");
更优实现方法
直接获取init进程
无需从current回溯,内核提供全局变量init_task(对应PID=1的进程结构体),可直接使用,减少冗余代码。安全遍历所有进程
若要打印系统所有进程,推荐使用for_each_process()宏(需包含<linux/sched/signal.h>),它会自动处理锁与遍历逻辑:
rcu_read_lock(); for_each_process(p) { pr_info("Process: %s\tPID: %d\n", p->comm, p->pid); } rcu_read_unlock();
注意:for_each_process()在新内核中依赖RCU保护,必须包裹在rcu_read_lock()/rcu_read_unlock()代码块中。
- 遵循内核编程规范
- 访问RCU保护的指针或链表时,必须持有RCU读锁;
- 避免手动计算结构体偏移,优先使用内核提供的
list_for_each_entry_rcu等宏,降低出错概率。
内容的提问来源于stack exchange,提问作者acevans
相关产品推荐
相关产品推荐

